diff --git a/api/database/databaseSetup.go b/api/database/databaseSetup.go index 44497c7c9a614f136cdfe9f11c82d9eb200c2980..65874175edb2ee0ea9e0c6c2e83eb120f4d1ce0a 100644 --- a/api/database/databaseSetup.go +++ b/api/database/databaseSetup.go @@ -20,11 +20,9 @@ var Client *firestore.Client //Code taken from https://firebase.google.com/docs/firestore/quickstart#go func DatabaseConnection() { file, err := filepath.Abs("database/stillas-16563-firebase-adminsdk-wd82v-a9fe8919b7.json") - if err != nil { log.Fatal(err) } - // Creates instance of firebase Ctx = context.Background() sa := option.WithCredentialsFile(file) //Initializes database @@ -72,7 +70,6 @@ GetDocumentData inspired from https://firebase.google.com/docs/firestore/query-d The function will return a selected document from a selected collection. document is the path to the selected document. */ - func GetDocumentData(document *firestore.DocumentRef) (map[string]interface{}, error) { dsnap, err := document.Get(Ctx) if err != nil { diff --git a/api/endpoints/APIHandler.go b/api/endpoints/APIHandler.go index 9b11f6b9fd9ed97ffdb781de8d6833825d10f81d..c4e41adee3895d8aa4c25a500b4b45f2cd9a0da8 100644 --- a/api/endpoints/APIHandler.go +++ b/api/endpoints/APIHandler.go @@ -59,7 +59,6 @@ func Handle() { //Gateway POST request endpoint (Only used for registering tags) router.HandleFunc(baseURL+"/gateway/input", UpdatePosition) - http.Handle("/", router) InfoLogger.Println(http.ListenAndServe(getPort(), nil)) } diff --git a/api/endpoints/projects.go b/api/endpoints/projects.go index 91e3009d8ce71f1dffdc0116e2219d6eea5ce856..148ac30e6fa91f2a56db5a7b6c96d6b594ea1826 100644 --- a/api/endpoints/projects.go +++ b/api/endpoints/projects.go @@ -721,7 +721,7 @@ func addScaffolding(documentPath *firestore.DocumentRef, batch *firestore.WriteB scaffoldingTypeDocument := scaffoldingCollection.Doc(scaffoldingType) scaffoldingStruct := _struct.Scaffolding{ - Type: (scaffoldingType), + Type: scaffoldingType, Quantity: _struct.Quantity{ Expected: 0, Registered: 0, diff --git a/api/endpoints/scaffolding.go b/api/endpoints/scaffolding.go index be73ac79533899439a8dc01e191c6f931b75a38e..14e368cbcd0ab860bc1c5148de63551147162c51 100644 --- a/api/endpoints/scaffolding.go +++ b/api/endpoints/scaffolding.go @@ -80,13 +80,6 @@ func createPart(w http.ResponseWriter, r *http.Request) { return } - //Prints the amount of scaffolding parts added to the system - err = json.NewEncoder(w).Encode(strconv.Itoa(len(scaffoldList)) + " new scaffolding units added to the system the following units were added:") - if err != nil { - tool.HandleError(tool.ENCODINGERROR, w) - return - } - for i := range scaffoldList { //For loop iterates through the list of new scaffolding parts newPartPath := database.Client.Collection(constants.S_TrackingUnitCollection).Doc(constants.S_ScaffoldingParts).Collection(scaffoldList[i].Type).Doc(scaffoldList[i].Id) @@ -166,7 +159,6 @@ func deletePart(w http.ResponseWriter, r *http.Request) { tool.HandleError(tool.ENCODINGERROR, w) return } - } //getQuantity Function takes an object of scaffolding type in storage and returns the expected amount and registered quantity @@ -253,12 +245,10 @@ func getAllScaffoldingParts(w http.ResponseWriter) { if err == iterator.Done { break } - if err != nil { tool.HandleError(tool.COLLECTIONITERATORERROR, w) return } - document := database.Client.Collection(constants.S_TrackingUnitCollection).Doc(constants.S_ScaffoldingParts).Collection(scaffoldingType.ID).Documents(database.Ctx) for { partRef, err := document.Next() diff --git a/api/endpoints/trackingTools.go b/api/endpoints/trackingTools.go index 2e598d3671463e67494d52216f93c06b702ef7ee..8bf36de6e99f6c8739f5a8adeb7a50faccfe9c32 100644 --- a/api/endpoints/trackingTools.go +++ b/api/endpoints/trackingTools.go @@ -62,6 +62,7 @@ func UpdatePosition(w http.ResponseWriter, r *http.Request) { printList = append(printList, "\nTag id:"+idList[i]+" Battery voltage: "+battery+"\n") } + updateAmountProject(gatewayList[0].Gateway(), w, idList, batteryList) fmt.Printf("\n-----------------------------------------------------") fmt.Println("\nBeacon payload:") @@ -70,8 +71,6 @@ func UpdatePosition(w http.ResponseWriter, r *http.Request) { fmt.Printf("Amount of tags registered: %v \n", len(idList)) fmt.Printf("List of tags:\n %v", printList) fmt.Printf("\n-----------------------------------------------------\n") - - updateAmountProject(gatewayList[0].Gateway(), w, idList, batteryList) } func updateAmountProject(beaconID string, w http.ResponseWriter, idList []string, batteryList map[string]float32) { @@ -224,7 +223,6 @@ func getTagTypes(idList []string, projectName string, scaffoldingArray _struct.S resultList := make(map[string]int) var scaffoldingType string for i := range idList { - for j := range scaffoldingArray { scaffoldingType = scaffoldingArray[j].Type documentPath := database.Client.Collection(constants.S_TrackingUnitCollection).Doc(constants.S_ScaffoldingParts).Collection(scaffoldingType).Doc(idList[i]) diff --git a/dockerUpdates.txt b/dockerUpdates.txt index 78445f1a92ed565aa93354be92748f2bbb33cdba..3638c01d2f21d3555af9dda8784f610c0ae4b097 100644 --- a/dockerUpdates.txt +++ b/dockerUpdates.txt @@ -4,8 +4,7 @@ Nettverk brukernavn martiiv@stud.ntnu.no Nettverk passord samme som vanlig sudo docker build . -t scaffoldingtracker -sudo docker run -d --name scaffolding0.4 -p 8080:8080 scaffoldingtracker - +19 Krisetilfellet: package endpoints diff --git a/webstillas/src/App.js b/webstillas/src/App.js index 2086fe1746a1a218d08f6ec3cd14ca191d5be00c..b56cf1c58e154768e60b7cbeec3f63d502b850d5 100644 --- a/webstillas/src/App.js +++ b/webstillas/src/App.js @@ -1,23 +1,30 @@ import './App.css'; import React from "react"; -import { Routes, Route} from "react-router-dom"; +import {Routes, Route} from "react-router-dom"; import {Project} from "./components/projects/projects"; import {MapPage} from "./components/mapPage/mapPage"; import {Scaffolding} from "./components/scaffolding/scaffolding"; import TopBar from "./components/topBar/topBar"; import {PreView} from "./components/projects/elements/preView"; import Logistic from "./components/logistics/logistic"; -import { QueryClientProvider, QueryClient } from 'react-query' -import { ReactQueryDevtools } from 'react-query/devtools' +import {QueryClientProvider, QueryClient} from 'react-query' +import {ReactQueryDevtools} from 'react-query/devtools' import ProtectedRoute from "./components/ProtectedRoute"; import Login from "./components/Login"; import Signup from "./components/Signup"; -import {UserAuthContextProvider, useUserAuth} from "./context/UserAuthContext"; -import auth from "./firebase"; +import {UserAuthContextProvider} from "./context/UserAuthContext"; import AddProjectFunc from "./components/logistics/project/addProject"; import AddScaffolding from "./components/logistics/scaffold/addScaffolding"; import {UserInfo} from "./components/userinformation/userInfo"; - +import {NotFound} from "./components/error/error"; +import { + ADD_PROJECT_URL, ADD_SCAFFOLDING_URL, LOGIN, + LOGISTICS_URL, + MAP_URL, NOTFOUND, + PROJECT_URL, + PROJECT_URL_ID, + SCAFFOLDING_URL, SIGNUP, USERINFO_URL +} from "./components/constants"; const queryClient = new QueryClient() @@ -26,30 +33,28 @@ function App() { return ( //Authorisation of user <UserAuthContextProvider> - {//Caching provider client - } + {/*Caching provider client*/} <QueryClientProvider client={queryClient}> <TopBar/> {/*Topbar for the user to navigate throughout the webpage}*/} <Routes> {/*Router that creates the routes the user is able to navigate*/} - <Route path="/prosjekt/*" element={<ProtectedRoute> <Project/></ProtectedRoute>}/> - <Route path="/kart" element={<ProtectedRoute> <MapPage/></ProtectedRoute>}/> - <Route path="/stillas" element={<ProtectedRoute> <Scaffolding/></ProtectedRoute>}/> - <Route path="/project/:id" element={<ProtectedRoute> <PreView/></ProtectedRoute>}/> - <Route path="/logistics" element={<ProtectedRoute> <Logistic/></ProtectedRoute>}/> - <Route path="/" element={<Login/>}/> - <Route path="/signup" element={<Signup/>}/> - <Route path="/addproject/" element={<ProtectedRoute> <AddProjectFunc/></ProtectedRoute>}/> - <Route path="/addscaffolding/" element={<ProtectedRoute> <AddScaffolding/></ProtectedRoute>}/> - <Route path="/userinfo/" element={<ProtectedRoute> <UserInfo/></ProtectedRoute>}/> - - + <Route path={PROJECT_URL} exact={true} element={<ProtectedRoute> <Project/></ProtectedRoute>}/> + <Route path={MAP_URL} exact={true} element={<ProtectedRoute> <MapPage/></ProtectedRoute>}/> + <Route path={SCAFFOLDING_URL} exact={true} element={<ProtectedRoute> <Scaffolding/></ProtectedRoute>}/> + <Route path={PROJECT_URL_ID} exact={true} element={<ProtectedRoute> <PreView/></ProtectedRoute>}/> + <Route path={LOGIN} exact={true} element={<Login/>}/> + <Route path={SIGNUP} exact={true} element={<Signup/>}/> + <Route path={ADD_PROJECT_URL} exact={true} + element={<ProtectedRoute> <AddProjectFunc/></ProtectedRoute>}/> + <Route path={ADD_SCAFFOLDING_URL} exact={true} + element={<ProtectedRoute> <AddScaffolding/></ProtectedRoute>}/> + <Route path={USERINFO_URL} exact={true} element={<ProtectedRoute> <UserInfo/></ProtectedRoute>}/> + <Route path={NOTFOUND} element={<NotFound/>}/> </Routes> - <ReactQueryDevtools initialIsOpen={true} /> + <ReactQueryDevtools initialIsOpen={true}/> </QueryClientProvider> </UserAuthContextProvider> ); - } export default App; diff --git a/webstillas/src/components/Login.js b/webstillas/src/components/Login.js index 6524237795d0542b832bd7ce8a56958c09ef764d..1ed3ecdc591cc76f19b276f9ccdb778a774e40e4 100644 --- a/webstillas/src/components/Login.js +++ b/webstillas/src/components/Login.js @@ -3,6 +3,7 @@ import { Link, useNavigate } from "react-router-dom"; import { Form, Alert } from "react-bootstrap"; import { Button } from "react-bootstrap"; import { useUserAuth } from "../context/UserAuthContext"; +import {PROJECT_URL, SIGNUP} from "./constants"; const Login = () => { const [email, setEmail] = useState(""); @@ -16,7 +17,7 @@ const Login = () => { setError(""); try { await logIn(email, password); - navigate("/prosjekt"); + navigate(PROJECT_URL); } catch (err) { setError("Feil brukernavn eller passord. \nVennligst prøv igjen"); } @@ -47,14 +48,14 @@ const Login = () => { <div className="d-grid gap-2"> <Button variant="primary" type="Submit"> - Log In + Logg inn </Button> </div> </Form> <hr /> </div> <div className="p-4 box mt-3 text-center"> - Don't have an account? <Link to="/signup">Sign up</Link> + Har du ikke en bruker? <Link to={SIGNUP}>Registrer</Link> </div> </> ); diff --git a/webstillas/src/components/Signup.js b/webstillas/src/components/Signup.js index aa6bdcdda99638330bb16cd00e2bbc3b1b7718b3..0894b34690d3a5a484afcf5617dacee4435589aa 100644 --- a/webstillas/src/components/Signup.js +++ b/webstillas/src/components/Signup.js @@ -1,135 +1,132 @@ -import React, { useState } from "react"; -import { Link, useNavigate } from "react-router-dom"; -import { Form, Alert } from "react-bootstrap"; -import { Button } from "react-bootstrap"; -import { useUserAuth } from "../context/UserAuthContext"; +import React, {useState} from "react"; +import {Link, useNavigate} from "react-router-dom"; +import {Form, Alert} from "react-bootstrap"; +import {Button} from "react-bootstrap"; +import {useUserAuth} from "../context/UserAuthContext"; import postModel from "../modelData/postModel"; -import {formatDate, formatDateToString} from "./projects/projects"; +import { formatDateToString} from "./projects/projects"; const Signup = () => { - const [email, setEmail] = useState(""); - const [firstName, setFirstName] = useState(""); - const [lastName, setLastName] = useState(""); - const [role, setRole] = useState(""); - const [phone, setPhone] = useState(0); - const [admin, setAdmin] = useState(false); - const [birthDay, setBirthDay] = useState(""); - - const [error, setError] = useState(""); - const [password, setPassword] = useState(""); - const { signUp } = useUserAuth(); - - let navigate = useNavigate(); - - const handleSubmit = async (e) => { - e.preventDefault(); - setError(""); - try { - signUp(email, password).then(newUser => { - console.log(newUser.user.uid) - const user = - { - "employeeID": newUser.user.uid, - "name": { - "firstName": firstName, - "lastName": lastName - }, - "role": role, - "phone": phone, - "email": email, - "admin": admin, - "dateOfBirth": birthDay - } - console.log(JSON.stringify(user)) - postModel("user", user) - .then(() => navigate("/")) - .catch(e => console.log(e)) - }) - } catch (err) { - setError(err.message); - } - }; - - - - - - console.log(birthDay) - - return ( - <> - <div className="p-4 box"> - <h2 className="mb-3">Firebase Auth Signup</h2> - {error && <Alert variant="danger">{error}</Alert>} - <Form onSubmit={handleSubmit}> - <Form.Group className="mb-3" controlId="firstName"> - <Form.Control - type="text" - placeholder="First name" - onChange={(e) => setFirstName(e.target.value)} - /> - </Form.Group> - <Form.Group className="mb-3" controlId="lastName"> - <Form.Control - type="text" - placeholder="Last name" - onChange={(e) => setLastName(e.target.value)} - /> - </Form.Group> - - <Form.Group className="mb-3" controlId="lastName"> - <Form.Control - type="number" - placeholder="phone" - onChange={(e) => setPhone(Number(e.target.value))} - /> - </Form.Group> - - <Form.Group className="mb-3" controlId="admin"> - <Form.Select onChange={(e) => setAdmin(Boolean(e.target.value))}> - <option value={"false"}>False</option> - <option value={"true"}>True</option> - </Form.Select> - </Form.Group> - - <Form.Group className="mb-3" controlId="role"> - <Form.Select onChange={(e) => setRole(e.target.value)}> - <option value={"admin"}>Administrator</option> - <option value={"installer"}>Installatør</option> - <option value={"storage"}>Lagerarbeider</option> - - </Form.Select> - </Form.Group> - - <label htmlFor="startDate">Birthday</label> - <input type="date" onChange={(event) => setBirthDay(formatDateToString(event.target.value))}/> - - <Form.Group className="mb-3" controlId="formBasicEmail"> - <Form.Control - type="email" - placeholder="Email address" - onChange={(e) => setEmail(e.target.value)} - /> - </Form.Group> - <Form.Group className="mb-3" controlId="formBasicPassword"> - <Form.Control - type="password" - placeholder="Password" - onChange={(e) => setPassword(e.target.value)} - /> - </Form.Group> - <div className="d-grid gap-2"> - <Button variant="primary" type="Submit"> - Sign up - </Button> - </div> - </Form> - </div> - <div className="p-4 box mt-3 text-center"> - Already have an account? <Link to="/">Log In</Link> - </div> - </> - ); + const [email, setEmail] = useState(""); + const [firstName, setFirstName] = useState(""); + const [lastName, setLastName] = useState(""); + const [role, setRole] = useState(""); + const [phone, setPhone] = useState(0); + const [admin, setAdmin] = useState(false); + const [birthDay, setBirthDay] = useState(""); + + const [error, setError] = useState(""); + const [password, setPassword] = useState(""); + const {signUp} = useUserAuth(); + + let navigate = useNavigate(); + + const handleSubmit = async (e) => { + e.preventDefault(); + setError(""); + try { + signUp(email, password).then(newUser => { + const user = + { + "employeeID": newUser.user.uid, + "name": { + "firstName": firstName, + "lastName": lastName + }, + "role": role, + "phone": phone, + "email": email, + "admin": admin, + "dateOfBirth": birthDay + } + postModel("user", user) + .then(() => navigate("/")) + .catch(e => console.log(e)) + }).catch( + e => console.log(e) + ) + + } catch (err) { + setError(err.message); + } + }; + + + return ( + <> + <div className="p-4 box"> + <h2 className="mb-3">Firebase Auth Signup</h2> + {error && <Alert variant="danger">{error}</Alert>} + <Form onSubmit={handleSubmit}> + <Form.Group className="mb-3" controlId="firstName"> + <Form.Control + type="text" + placeholder="Fornavn" + onChange={(e) => setFirstName(e.target.value)} + /> + </Form.Group> + <Form.Group className="mb-3" controlId="lastName"> + <Form.Control + type="text" + placeholder="Etternavn" + onChange={(e) => setLastName(e.target.value)} + /> + </Form.Group> + + <Form.Group className="mb-3" controlId="lastName"> + <Form.Control + type="number" + placeholder="Telefonnummer" + onChange={(e) => setPhone(Number(e.target.value))} + /> + </Form.Group> + + <Form.Group className="mb-3" controlId="admin"> + <Form.Select onChange={(e) => setAdmin(Boolean(e.target.value))}> + <option value={"false"}>False</option> + <option value={"true"}>True</option> + </Form.Select> + </Form.Group> + + <Form.Group className="mb-3" controlId="role"> + <Form.Select onChange={(e) => setRole(e.target.value)}> + <option value={"admin"}>Administrator</option> + <option value={"installer"}>Installatør</option> + <option value={"storage"}>Lagerarbeider</option> + + </Form.Select> + </Form.Group> + + <label htmlFor="startDate">Fødselsdag</label> + <input type="date" onChange={(event) => setBirthDay(formatDateToString(event.target.value))}/> + + <Form.Group className="mb-3" controlId="formBasicEmail"> + <Form.Control + type="email" + placeholder="Email" + onChange={(e) => setEmail(e.target.value)} + /> + </Form.Group> + <Form.Group className="mb-3" controlId="formBasicPassword"> + <Form.Control + type="password" + placeholder="Passord" + onChange={(e) => setPassword(e.target.value)} + /> + </Form.Group> + <div className="d-grid gap-2"> + <Button variant="primary" type="Submit"> + Registrer + </Button> + </div> + </Form> + </div> + <div className="p-4 box mt-3 text-center"> + Har du allerede en bruker? <Link to="/">Logg inn</Link> + </div> + </> + ); }; + export default Signup; diff --git a/webstillas/src/components/Spinner.css b/webstillas/src/components/Spinner.css index d50fc6d702eadb923021b0d3e3d51cfcea4a5c73..00f0984a66739f2e72b6ebaeefa6021266ca555e 100644 --- a/webstillas/src/components/Spinner.css +++ b/webstillas/src/components/Spinner.css @@ -1,5 +1,5 @@ .spinner{ - display: flex; - justify-content: center; + margin-top: 20%; + margin-left: 47%; } diff --git a/webstillas/src/components/Spinner.js b/webstillas/src/components/Spinner.js index 59b2dec4b3205773ce66b5cad92ebc84955c2a85..57a870499519d291c8e8772437e8f97a057c69f4 100644 --- a/webstillas/src/components/Spinner.js +++ b/webstillas/src/components/Spinner.js @@ -1,5 +1,6 @@ import {Spinner} from "react-bootstrap"; import React from "react"; +import "./Spinner.css" export const SpinnerDefault = () =>{ return( diff --git a/webstillas/src/components/constants.js b/webstillas/src/components/constants.js new file mode 100644 index 0000000000000000000000000000000000000000..7ba12642b45fc92742cc3548bc985b82ffbc4290 --- /dev/null +++ b/webstillas/src/components/constants.js @@ -0,0 +1,16 @@ +export const PROJECT_URL = "/project" +export const MAP_URL = "/map" +export const SCAFFOLDING_URL = "/scaffolding" +export const PROJECT_URL_ID = "/project/:id" +export const ADD_PROJECT_URL = "/addproject" +export const ADD_SCAFFOLDING_URL = "/addscaffolding" +export const USERINFO_URL = "/userinfo" +export const NOTFOUND = "/*" +export const SIGNUP = "/signup" +export const LOGIN = "/" + + + + + + diff --git a/webstillas/src/components/error/error.js b/webstillas/src/components/error/error.js index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..47568b00833878c02bb42b4f32a1bad58d054ef8 100644 --- a/webstillas/src/components/error/error.js +++ b/webstillas/src/components/error/error.js @@ -0,0 +1,26 @@ +/* +Error function that will be displayed if the user requests an invalid url. + */ +export function NotFound() { + return ( + <h1> + 404 Page Not Found + </h1> + ) +} + +/* +Error function that will be displayed if a server error occurs. + */ +export function InternalServerError() { + return ( + <h1> + 500 Internal Server Error + </h1> + ) +} + + +export function AlertCatch(){ + window.alert("Something went wrong. Please try again later") +} diff --git a/webstillas/src/components/logistics/project/addProject.js b/webstillas/src/components/logistics/project/addProject.js index d795e484864e2a536dd4316e7b24331aa415c587..4c70678befab54d5b74f27b1671eb9cf39858cd6 100644 --- a/webstillas/src/components/logistics/project/addProject.js +++ b/webstillas/src/components/logistics/project/addProject.js @@ -4,25 +4,26 @@ import MapboxAutocomplete from "react-mapbox-autocomplete"; import 'mapbox-gl/dist/mapbox-gl.css' import "./addProject.css" import {Alert} from "react-bootstrap"; +import {MapBoxAPIKey} from "../../../firebaseConfig"; -export default function AddProjectFunc() { +/** + Function that will allow the user to add a new project to the system. + */ +export default function AddProjectFunc() { + //Access token to the mapbox api. const mapAccess = { // Thanks to SomeSoftwareTeam (https://github.com/SomeSoftwareTeam/some-react-app/blob/acd17860b8b1f51edefa4e18486cc1fb07afff70/src/components/SomeComponent.js) - mapboxApiAccessToken: - "pk.eyJ1IjoiZmFrZXVzZXJnaXRodWIiLCJhIjoiY2pwOGlneGI4MDNnaDN1c2J0eW5zb2ZiNyJ9.mALv0tCpbYUPtzT7YysA2g" + mapboxApiAccessToken: MapBoxAPIKey }; - + /* + Initialise variables the user must fill in order to add a new project. + */ const [address, setAddress] = useState({street: "", zipcode: 0, municipality: "", county: ""}) - - const [period, setPeriod] = useState({startDate: "", endDate: ""}) - const [customer, setCustomer] = useState({name: "", email: ""}) - const [customerNumber, setCustomerNumber] = useState({number: 0}) - const [projectDetails, setProjectDetails] = useState({ projectID: Math.round(Math.random() * 1000000), projectName: '', @@ -30,9 +31,11 @@ export default function AddProjectFunc() { longitude: 0, state: "Inactive" }) - const [size, setSize] = useState({size: 0}) + /* + Error messages that will be displayed to the user, if the user has entered invalid input. + */ const [errors, setErrors] = useState({ projectName: '', address: "", @@ -43,6 +46,9 @@ export default function AddProjectFunc() { date: "" }) + /* + Checks if the input is valid. + */ const [valid, setValid] = useState({ projectNameValid: false, streetValid: false, @@ -57,6 +63,11 @@ export default function AddProjectFunc() { }) + /** + * Function that will handle and check the user input + * + * @param e the input field name and value. + */ const handleUserInputProjectDetails = (e) => { const name = e.target.name; const value = e.target.value; @@ -69,6 +80,11 @@ export default function AddProjectFunc() { setProjectDetails({...projectDetails, [name]: value}); } + /** + * Function that will handle and check the user input + * + * @param e the input field name and value. + */ const handleUserInputCustomer = (e) => { const name = e.target.name; const value = e.target.value; @@ -80,43 +96,24 @@ export default function AddProjectFunc() { setCustomer(({...customer, [name]: value})); } - const handleUserInputAddress = (e) => { - const name = e.target.name; - const value = e.target.value; - validateFieldProjectAddress(name, value) - setAddress({...address, [name]: value}); - } - - + /** + * Function that will format input from "input date" to required API format + * + * @param date as "input date" format "mm-dd-yyyy" + * @returns {string} return to API format "dd-mm-yyyy" + */ const dateFormat = (date) => { const dateArray = date.split('-') return dateArray[2] + '-' + dateArray[1] + '-' + dateArray[0] } - const validateFieldProjectAddress = (field, value) => { - switch (field) { - case "street": - setValid({...valid, streetValid: value.length > 3}) - setErrors({...errors, street: (valid.streetValid ? '' : ' is too short')}) - break; - case "zipcode": - setValid({...valid, zipcodeValid: ((value.length) === 4)}) - setErrors({...errors, zipcode: (valid.zipcodeValid ? '' : ' needs to be of length 4')}); - break; - case 'municipality': - setValid({...valid, municipalityValid: (value !== undefined)}) - setErrors({...errors, municipalityErr: (valid.municipalityValid ? '' : 'Not a valid municipality')}); - - break; - case 'county': - setValid({...valid, countyValid: (value !== undefined)}) - setErrors({...errors, countyErr: (valid.countyValid ? '' : 'Not a valid county')}); - break; - default: - break; - } - } - + /** + * Function that will validate the customer input + * If input is not valid, then a predefined error message is set. + * + * @param fieldName is the object field that is going to be set + * @param value is the object value to be set. + */ const validateFieldProjectCustomer = (fieldName, value) => { switch (fieldName) { case 'name': @@ -140,6 +137,13 @@ export default function AddProjectFunc() { } } + /** + * Function to validate date format. + * If input is not valid, then a predefined error message is set. + * + * @param fieldName is the object field that is going to be set + * @param value is the object value to be set. + */ const validateFieldDate = (fieldName, value) => { switch (fieldName) { case 'startDate': @@ -155,6 +159,13 @@ export default function AddProjectFunc() { } } + /** + * Function to validate projectDetails + * If input is not valid, then a predefined error message is set. + * + * @param fieldName is the object field that is going to be set + * @param value is the object value to be set. + */ const validateFieldProjectDetails = (fieldName, value) => { switch (fieldName) { case 'projectName': @@ -171,6 +182,11 @@ export default function AddProjectFunc() { } + /** + * Function that will set period fields + * + * @param e is value and name of input fields. + */ const handleUserInputPeriod = (e) => { const name = e.target.name; const value = e.target.value; @@ -180,29 +196,29 @@ export default function AddProjectFunc() { } - const [mapPage, setMapPage] = useState(false) - - const nextPage = () => { - setMapPage(true) - - } + // Query that will only allow norwegian addresses const queryParams = { country: "no", place_type: "address" }; - const parseReverseGeo = async (geoData, lat, long) => { + /** + * Function that will fetch data of a spesific longitude and latitude, to set address/poi, postcode, county and municipality + * + * @param lat latitude of the place we would like to get information + * @param long longitude of the place we would like to get information + * @returns {Promise<void>} + */ + const parseReverseGeo = async (lat, long) => { let street, postcode, region, place await fetch("https://api.mapbox.com/geocoding/v5/mapbox.places/" + long + "," + lat + ".json?access_token=pk.eyJ1IjoiYWxla3NhYWIxIiwiYSI6ImNrbnFjbms1ODBkaWEyb3F3OTZiMWd6M2gifQ.vzOmLzHH3RXFlSsCRrxODQ") .then(res => res.json()) .then(res => { - let validStreet, validZip, validCounty, validMunicipality for (const re of res.features) { console.log((re.place_type[0])) switch (re.place_type[0]) { - case "address": { street = re.text if ((re.text.length > 3)) { @@ -247,6 +263,7 @@ export default function AddProjectFunc() { } + if (validStreet && validZip && validCounty && validMunicipality) { setValid({ ...valid, @@ -255,6 +272,8 @@ export default function AddProjectFunc() { zipcodeValid: validZip, streetValid: validStreet }) + + //If region is oslo the municipality is not set. if (region === "Oslo") { setAddress({ ...address, @@ -279,10 +298,22 @@ export default function AddProjectFunc() { })) } - const _suggestionSelect = async (result, lat, long, country) => { - await parseReverseGeo(result, lat, long) + /** + *Function that will redirect to parseReverseGeo + * + * @param lat latitude from the suggested input of user + * @param long longitude from the suggested input of user + * @returns {Promise<void>} + */ + const _suggestionSelect = async (_, lat, long) => { + await parseReverseGeo(lat, long) } + + /** + * Struct of adding project that will set the variables the user has set. + * + */ const finalProject = { projectID: projectDetails.projectID, projectName: projectDetails.projectName, @@ -309,6 +340,11 @@ export default function AddProjectFunc() { } + /** + * Checks if all the fields are valid. + * + * @type {boolean} is set true if all the fields are valid. + */ let formsValid = false if (valid.countyValid && valid.streetValid && valid.zipcodeValid && valid.municipalityValid && valid.dateValid && valid.sizeValid && valid.projectNameValid && valid.emailValid && valid.nameValid @@ -318,19 +354,19 @@ export default function AddProjectFunc() { } - -console.log(address) - + /** + * + * @returns {JSX.Element} with input that can set the customer information. + */ const contactInformation = () => { - - return( + return ( <div> <h3>Contact Information</h3> <hr/> <div className={"input-with-text"}> <p className={"input-field-text"}>Name</p> <input - className = {"form-control"} + className={"form-control"} type={"text"} required name={"name"} @@ -338,31 +374,32 @@ console.log(address) onChange={handleUserInputCustomer} /> <p className={"error-message"}> - {(errors.name === "" || valid.nameValid) ? null: <Alert variant="danger">{errors.name}</Alert> } + {(errors.name === "" || valid.nameValid) ? null : <Alert variant="danger">{errors.name}</Alert>} </p> </div> <div className={"input-with-text"}> <p className={"input-field-text"}>Number</p> <input - className = {"form-control"} + className={"form-control"} type={"number"} - min={0} - required - name={"number"} - placeholder={"Enter Customer Number"} - onChange={handleUserInputCustomer} + min={0} + required + name={"number"} + placeholder={"Enter Customer Number"} + onChange={handleUserInputCustomer} /> <p className={"error-message"}> - {(errors.number === "" || valid.numberValid) ? null: <Alert variant="danger">{errors.number}</Alert> } + {(errors.number === "" || valid.numberValid) ? null : + <Alert variant="danger">{errors.number}</Alert>} </p> </div> <div className={"input-with-email"}> <p className={"input-field-text"}>Email</p> <input - className = {"form-control"} + className={"form-control"} type={"email"} required name={"email"} @@ -370,7 +407,8 @@ console.log(address) onChange={handleUserInputCustomer} /> <p className={"error-message"}> - {(errors.email === "" || valid.emailValid) ? null: <Alert variant="danger">{errors.email}</Alert> } + {(errors.email === "" || valid.emailValid) ? null : + <Alert variant="danger">{errors.email}</Alert>} </p> </div> @@ -379,38 +417,31 @@ console.log(address) } - - - - - console.log(valid) - - - if (!mapPage) { - return ( - <div className={"add-card"}> - <article className={"information"}> - <h1>Add project</h1> + return ( + <div className={"add-card"}> + <article className={"information"}> + <h1>Legg til prosjekt</h1> <h2>Generelt</h2> <hr/> <div> <div className={"test"}> <div className={"address-name"}> - <div className={"input-with-text"}> - <p className={"input-field-text"}>Project Name </p> - <input - className = {"form-control name"} - type={"text"} - required - name={"projectName"} - placeholder={"Project Name"} - onChange={handleUserInputProjectDetails} - /> - <p className={"error-message"}> - {(errors.projectName === "" || valid.projectNameValid) ? null: <Alert variant="danger">{errors.projectName}</Alert> } - </p> + <div className={"input-with-text"}> + <p className={"input-field-text"}>Project Name </p> + <input + className={"form-control name"} + type={"text"} + required + name={"projectName"} + placeholder={"Project Name"} + onChange={handleUserInputProjectDetails} + /> + <p className={"error-message"}> + {(errors.projectName === "" || valid.projectNameValid) ? null : + <Alert variant="danger">{errors.projectName}</Alert>} + </p> - </div> + </div> <div className={"input-with-text"}> <p className={"input-field-text"}>Project size</p> @@ -419,10 +450,11 @@ console.log(address) required name={"size"} placeholder={"Size"} - className = {"form-control number"} + className={"form-control number"} onChange={handleUserInputProjectDetails}/> <p className={"error-message"}> - {(errors.size === "" || valid.sizeValid) ? null: <Alert variant="danger">{errors.size}</Alert> } + {(errors.size === "" || valid.sizeValid) ? null : + <Alert variant="danger">{errors.size}</Alert>} </p> </div> @@ -440,7 +472,8 @@ console.log(address) className={"input-text-add"} onChange={handleUserInputPeriod}/> <p className={"error-message"}> - {(errors.date === "" || valid.dateValid) ? null: <Alert variant="danger">{errors.date}</Alert> } + {(errors.date === "" || valid.dateValid) ? null : + <Alert variant="danger">{errors.date}</Alert>} </p> @@ -454,7 +487,8 @@ console.log(address) className={"input-text-add"} onChange={handleUserInputPeriod}/> <p className={"error-message"}> - {(errors.date === "" || valid.dateValid) ? null: <Alert variant="danger">{errors.date}</Alert> } + {(errors.date === "" || valid.dateValid) ? null : + <Alert variant="danger">{errors.date}</Alert>} </p> </div> @@ -467,15 +501,15 @@ console.log(address) inputClass='form-control address' publicKey={mapAccess.mapboxApiAccessToken} onSuggestionSelect={_suggestionSelect} - - country="no" resetSearch={false} + country = "no" placeholder="Search Address..." queryParams={queryParams} /> <p className={"error-message"}> - {(errors.address === "" || valid.streetValid) ? null: <Alert variant="danger">{errors.address}</Alert> } + {(errors.address === "" || valid.streetValid) ? null : + <Alert variant="danger">{errors.address}</Alert>} </p> </div> </div> @@ -483,14 +517,14 @@ console.log(address) </div> </div> - </article> - <MapClass props={finalProject} - valid ={formsValid} + </article> + <MapClass props={finalProject} + valid={formsValid} + + /> + </div> + ) - /> - </div> - ) - } } diff --git a/webstillas/src/components/logistics/project/map.js b/webstillas/src/components/logistics/project/map.js index 41825aeeea257dbac774864a8f410f1d1c23bad9..9599fae1091f505974d86310c2ef65a986e25cc2 100644 --- a/webstillas/src/components/logistics/project/map.js +++ b/webstillas/src/components/logistics/project/map.js @@ -3,41 +3,53 @@ import ReactMapboxGl, {ZoomControl} from "react-mapbox-gl"; import DrawControl from "react-mapbox-gl-draw"; import "@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css"; import postModel from "../../../modelData/postModel"; -import {PROJECTS_URL} from "../../../modelData/constantsFile"; +import {MAP_STYLE_V11, PROJECTS_URL} from "../../../modelData/constantsFile"; import {useQueryClient} from "react-query"; import polygon from "@mapbox/mapbox-gl-draw/src/feature_types/polygon"; import "./map.css" +import {MapBoxAPIKey} from "../../../firebaseConfig"; +import {AlertCatch} from "../../error/error"; const Map = ReactMapboxGl({ - accessToken: - "pk.eyJ1IjoiYWxla3NhYWIxIiwiYSI6ImNrbnFjbms1ODBkaWEyb3F3OTZiMWd6M2gifQ.vzOmLzHH3RXFlSsCRrxODQ" + accessToken: MapBoxAPIKey }); +/** + * Function that will display a map, and allow a user to draw a polygon. + * + * @param props variables sent from previous view. + * @returns {JSX.Element} Map with draw controllers. + */ export function MapClass(props) { + //Query client that will manage the caching. const queryClient = useQueryClient() + //Setting variables const [ok, setOk] = useState(false) - - console.log(props.props) const [mapInfo, setMapInfo] = useState([]) + /** + * Function that will validate the polygon the user has drawn. + * If the user has drawn a polygon more than 4 points, the user will get a warning. + * + * @param features is the return value from the polygon. + */ const onDrawCreate = ({features}) => { if (features[0].geometry.coordinates[0].length !== 5) { console.log("length is invalid") window.alert("Invalid geo format. Only valid is 4 points") - console.log(features) } else { - console.log(features) setMapInfo(features) setOk(true) - } - }; + + //Defines the geofence and project object let geofence = null let project = (props.props) for (const mapInfoElement of mapInfo) { + //if the user has added a valid polygon for the system. the geofence object is initialized. if ((mapInfoElement).hasOwnProperty('geometry')) { geofence = { "w-position": { @@ -58,29 +70,34 @@ export function MapClass(props) { }, } } - console.log(geofence) + //The geofence is added to project object. project = {...project, geofence} } + /** + * Function that will add the project to the API. + * + * @returns {Promise<void>} + * @constructor + */ const AddProjectRequest = async () => { try { console.log(JSON.stringify(project)) - await postModel(PROJECTS_URL, JSON.stringify(project)) await queryClient.refetchQueries("allProjects") - } catch (e) { - console.log(e) + AlertCatch() } - } + + return ( <div className="App"> <div className={"map"}> <Map - style="mapbox://styles/mapbox/streets-v9" // eslint-disable-line + style={MAP_STYLE_V11} containerStyle={{ height: "80vh", width: "50vw" @@ -99,9 +116,7 @@ export function MapClass(props) { uncombine_features: false }} default_mode={"polygon"} - clickBuffer={5} onDrawDelete={() => setOk(false)} - /> <ZoomControl position="bottom-right" @@ -111,8 +126,6 @@ export function MapClass(props) { <button className={"confirm-btn"} disabled={!ok || !props.valid} onClick={AddProjectRequest}>Add Project</button> </div> ); - - } diff --git a/webstillas/src/components/logistics/scaffold/addScaffolding.css b/webstillas/src/components/logistics/scaffold/addScaffolding.css index 0bea57a075d09bdb40abd2230762c3645a168d1a..bc9e9b8f1386e7e2bf46613ca41bfbe64db14210 100644 --- a/webstillas/src/components/logistics/scaffold/addScaffolding.css +++ b/webstillas/src/components/logistics/scaffold/addScaffolding.css @@ -12,7 +12,7 @@ .input-fields{ display: flow; - margin-left: 35%; + margin-left: 40%; margin-top: 10%; width: 500px; align-content: center; @@ -28,3 +28,7 @@ margin-left: 35%; margin-top: 7%; } + +.alert-success{ + width: 440px; +} diff --git a/webstillas/src/components/logistics/scaffold/addScaffolding.js b/webstillas/src/components/logistics/scaffold/addScaffolding.js index c062a8c959ac6a737c7de4cabd727b323c660cee..4b32aed45c07fa68139253ff2459024178025d28 100644 --- a/webstillas/src/components/logistics/scaffold/addScaffolding.js +++ b/webstillas/src/components/logistics/scaffold/addScaffolding.js @@ -1,92 +1,117 @@ -import React from 'react' +import React, {useState} from 'react' import postModel from "../../../modelData/postModel"; import {SCAFFOLDING_URL} from "../../../modelData/constantsFile"; import "./addScaffolding.css" +import {Alert} from "react-bootstrap"; -class AddScaffolding extends React.Component{ - constructor(props) { - super(props); - this.state = { - scaffolding : - { - id: 0, - type: "", - batteryLevel: 100, - location: null - }, - location: { - longitude: 0, - latitude: 0, - address: "" - } + +/** + * Function that will allow the user to add a new scaffolding unit + * @returns {JSX.Element} + */ +function AddScaffolding() { + + //Defining the json body to add a new unit + const [scaffolding, setScaffolding] = useState({ + id: "", + type: "", + batteryLevel: 100, + location: { + longitude: 0, + latitude: 0, + address: "" } - } + }) + const [postSucsess, setPostSucsess] = useState(null) + const [buttonPress, setButtonPress] = useState(false) + + - scaffoldingInformation(){ - return( + + + /** + * Returns card to write id scaffolding type. + * @returns {JSX.Element} + */ + const scaffoldingInformation = () => { + return ( <div className={"input-information"}> <div className={"input-fields-add"}> - <p className = {"input-sorting-text"}>Enter ID</p> + <p className={"input-sorting-text"}>Enter ID</p> + + <input type={"text"} className={"form-control scaffolding-input"} onChange={event => { + //Setting the id + setScaffolding({...scaffolding, id: event.target.value}) + }}/> - <input type={"text"} className={"form-control scaffolding-input"} onChange={event => - {const scaffolding = {...this.state.scaffolding}; - scaffolding.id = Number(event.target.value); - this.setState({scaffolding})}}/> </div> <div className={"input-fields-add"}> - <p className = {"input-sorting-text"}>Overfør til prosjekt:</p> - <select - className={"form-select scaffolding-input"} - value={"Test"} - onChange={(e) => - {const scaffolding = {...this.state.scaffolding}; - scaffolding.type = e.target.value; - this.setState({scaffolding})}}> - <option value={"Bunnskrue"}>Bunnskrue</option> - <option value={"Spire"}>Spir</option> - <option value={"Diagonalstang"}>Diagonalstang</option> - <option value={"Enrørsbjelke"}>Enrørsbjelke</option> - <option value={"Lengdebjeke"}>Lengdebjeke</option> - <option value={"Plank"}>Plank</option> - <option value={"Rekkverksramme"}>Rekkverksramme</option> - <option value={"Stillaslem"}>Stillaslem</option> - <option value={"Trapp"}>Trapp</option> - </select> + <p className={"input-sorting-text"}>Stillasdel:</p> + <select + className={"form-select scaffolding-input"} + value={"Test"} + onChange={(e) => { + //setting the type + setScaffolding({...scaffolding, type: e.target.value}) + }}> + <option value={"Bunnskrue"}>Bunnskrue</option> + <option value={"Spir"}>Spir</option> + <option value={"Diagonalstang"}>Diagonalstang</option> + <option value={"Enrørsbjelke"}>Enrørsbjelke</option> + <option value={"Lengdebjeke"}>Lengdebjeke</option> + <option value={"Plank"}>Plank</option> + <option value={"Gelender"}>Gelender</option> + <option value={"Rekkverksramme"}>Rekkverksramme</option> + <option value={"Stillaslem"}>Stillaslem</option> + <option value={"Trapp"}>Trapp</option> + </select> </div> </div> ) } - postRequest(){ - this.state.scaffolding.location = this.state.location + + const postRequest = async () => { + setButtonPress(true) const body = [ - this.state.scaffolding + scaffolding ] - try { - postModel(SCAFFOLDING_URL, JSON.stringify(body)) - }catch (e){ + //posting body + const promise = await postModel(SCAFFOLDING_URL, (body)) + setPostSucsess(promise.statusCode) + } catch (e) { console.log(e) } - } - render() { - return( - <div className={"main-add-scaffolding"}> - <div className={"info-card"}> - {this.scaffoldingInformation()} - <div className={"btn-add-scaffolding"}> - <button className={"btn"} onClick={() => this.postRequest()}>Legg til</button> - </div> - </div> - </div> + console.log(postSucsess, buttonPress) + return ( + <div className={"main-add-scaffolding"}> + {(postSucsess === 201) ? + (<Alert className={"alert-success"} + key={"success"} variant={"success"}> + Stillasdel har blitt registrert + </Alert>): null } + {(postSucsess !== 201 && buttonPress) ? + (<Alert className={"alert-success"} + key={"danger"} variant={"danger"}> + Stillasdel har ikke blitt registrert + </Alert>): null } + <div className={"info-card"}> + {scaffoldingInformation()} + <div className={"btn-add-scaffolding"}> + <button className={"btn"} onClick={() => postRequest()}>Legg til</button> + </div> + </div> + </div> ) - } + + } export default AddScaffolding diff --git a/webstillas/src/components/projects/elements/preView.js b/webstillas/src/components/projects/elements/preView.js index 2dc2af39d7c0704c8874d1a9220df2b69f807c90..f775abf22fb0069dbcc74e5f636804e01a05f46e 100644 --- a/webstillas/src/components/projects/elements/preView.js +++ b/webstillas/src/components/projects/elements/preView.js @@ -194,8 +194,6 @@ function contactInformation(project) { </ul> </div> </section> - - </div> ) diff --git a/webstillas/src/components/projects/projects.css b/webstillas/src/components/projects/projects.css index 0447e690ffb8c835d034dffbd83bc4c9907a5261..e4aa57269522176d72a892e3a6a6a50d0209a363 100644 --- a/webstillas/src/components/projects/projects.css +++ b/webstillas/src/components/projects/projects.css @@ -28,10 +28,13 @@ input[type=number]::-webkit-outer-spin-button { } +body{ + background-color: #9f9e9e; +} + .main-project-window { display: flex; - background-color: #f9f9f9; } diff --git a/webstillas/src/components/projects/projects.js b/webstillas/src/components/projects/projects.js index a0d5655325929eb808a6bb5cf1a419edb2b2f159..40e9d1db41b31e89d675fefd5e4495b342940c48 100644 --- a/webstillas/src/components/projects/projects.js +++ b/webstillas/src/components/projects/projects.js @@ -5,6 +5,9 @@ import {Route, Routes} from "react-router-dom"; import {PROJECTS_WITH_SCAFFOLDING_URL} from "../../modelData/constantsFile"; import {GetDummyData} from "../../modelData/addData"; import {SpinnerDefault} from "../Spinner"; +import DatePicker from "react-datepicker" +import {InternalServerError} from "../error/error"; + /** Class that will create an overview of the projects @@ -31,11 +34,16 @@ export function Project(){ - const {isLoading, data} = GetDummyData("allProjects", PROJECTS_WITH_SCAFFOLDING_URL) + const {isLoading, data, isError} = GetDummyData("allProjects", PROJECTS_WITH_SCAFFOLDING_URL) + + + if (isLoading) { return( <SpinnerDefault /> ) + } else if (isError){ + return <InternalServerError/> } else { return ( <div className={"main-project-window"}> @@ -53,7 +61,6 @@ export function Project(){ </div> <div className={"search-filter"}> <p className = {"input-sorting-text"}>Prosjekt navn: </p> - <input className={"form-control"} type="text" @@ -85,6 +92,24 @@ export function Project(){ /> </div> </div> + <div className={"date-filter"}> + <p className = {"input-sorting-text"}>Fra dato: </p> + <input + className={"form-control"} + type="date" + onChange={e => { + setStartDate(formatDateToString(e.target.value)) + }}/> + </div> + <div className={"search-filter"}> + <p className = {"input-sorting-text"}>Til dato: </p> + <input + className={"form-control"} + type="date" + onChange={e => { + setEndDate(formatDateToString(e.target.value)) + }}/> + </div> </div> <div> <div className={"projects-display"}> @@ -100,14 +125,14 @@ export function Project(){ .filter(data => { console.log(startDate) if (startDate !== null ) { - return formatDate(data.period.startDate) >= startDate._d + return formatDate(data.period.startDate) >= formatDate(startDate) } else { return true } }) .filter(data => { if (endDate !== null) { - return formatDate(data.period.endDate) <= endDate + return formatDate(data.period.endDate) <= formatDate(endDate) } else { return true } diff --git a/webstillas/src/components/scaffolding/scaffolding.css b/webstillas/src/components/scaffolding/scaffolding.css index 4519052cb16603d34b40b7a6c390de9a69a4142c..aee32c0588e3f6daec115e20c90e92b6da4da7a5 100644 --- a/webstillas/src/components/scaffolding/scaffolding.css +++ b/webstillas/src/components/scaffolding/scaffolding.css @@ -9,7 +9,6 @@ .input-sorting-text{ margin-bottom: 0; display: flex; - justify-content: center; font-weight: initial; font-size: 15px; } diff --git a/webstillas/src/components/topBar/topBar.css b/webstillas/src/components/topBar/topBar.css index 958384826df6fd9a9584bac5dda7c697677dc132..8e384981bf2b86d15d4c48a2e8f48367b75c5a92 100644 --- a/webstillas/src/components/topBar/topBar.css +++ b/webstillas/src/components/topBar/topBar.css @@ -17,3 +17,6 @@ position: fixed; } +.dropdown-button{ + text-decoration-color: rebeccapurple; +} diff --git a/webstillas/src/components/topBar/topBar.js b/webstillas/src/components/topBar/topBar.js index eb61859ea0942748d95b729e73e9d33ac205460a..c451cbfc3a0357ce50d4d1723a8544d867759158 100644 --- a/webstillas/src/components/topBar/topBar.js +++ b/webstillas/src/components/topBar/topBar.js @@ -3,81 +3,85 @@ import './topBar.css'; import { AppBar, Toolbar, Button } from '@material-ui/core'; -import {Link, NavLink} from "react-router-dom"; +import {Link} from "react-router-dom"; import {DropdownButton, NavDropdown} from "react-bootstrap"; import DropdownItem from "react-bootstrap/DropdownItem"; import {useUserAuth} from "../../context/UserAuthContext"; import {auth} from "../../firebase" -import {orange} from "@material-ui/core/colors"; +import {GetDummyData} from "../../modelData/addData"; +import {USER_URL} from "../../modelData/constantsFile"; +import {SpinnerDefault} from "../Spinner"; +import "bootstrap/dist/css/bootstrap.min.css"; +import {ADD_PROJECT_URL, ADD_SCAFFOLDING_URL, MAP_URL, PROJECT_URL, SCAFFOLDING_URL, USERINFO_URL} from "../constants"; /** - Class that will create a topbar for the application. + Component that will be used as a top bar for the user to navigate throughout the application. */ - -//Todo make list instead of toolbar - //se hva andre nettsider har gjort const TopBar = () => { - const {logOut} = useUserAuth(); - - - if (!auth.currentUser) { - return ( - <AppBar position="sticky"> - <Toolbar className="toolbar"> - - </Toolbar> - </AppBar> - ) - } else { - return ( - <AppBar position="sticky"> - <Toolbar className="toolbar"> - <Link className="link" to="/prosjekt"> - <Button className="button">Prosjekter</Button> - </Link> - <Link className="link" to="/stillas"> - <Button className="button">Stillasdeler</Button> - </Link> - - <Link className="link" to="/kart"> - <Button className="button">Kart</Button> - </Link> - {/* <Link className="link" to="/logistics"> - <Button className="button">Logistikk</Button> - </Link>*/} - - <NavDropdown id="basic-nav-dropdown1" - title={"Logistikk"} - size="sm" - menuVariant={"dark"} + const {logOut} = useUserAuth(); + let loading, userData - > - <DropdownItem> - <Link to={"/addproject/"}>Legg til prosjekt </Link> - </DropdownItem> - <DropdownItem> - <Link to={"/addscaffolding/"}>Legg til stillas</Link> - </DropdownItem> - </NavDropdown> - - - <DropdownButton id="dropdown-button" - title={"Bruker"} - size="sm" - - > - <DropdownItem> - <Link to={"/userinfo/"}>Bruker Informasjon</Link> - </DropdownItem> - - <DropdownItem onClick={logOut}>Logg ut</DropdownItem> - </DropdownButton> - </Toolbar> - </AppBar> - ); - } + /*Checking if the user is authenticated + * If so, fetch userdata + */ + if (auth.currentUser !== null) { + const {isLoading, data} = GetDummyData("user", USER_URL + auth.currentUser.uid) + loading = isLoading + userData = data + } + /* + If the user is not authenticated, the topbar will be empty. + */ + if (!auth.currentUser) { + return ( + <AppBar position="sticky"> + <Toolbar className="toolbar"> + </Toolbar> + </AppBar> + ) + } else if (loading) { + //If data is loading, the user will get a spinner displayed + return <SpinnerDefault/> + } else { + //Top bar with interactive buttons to navigate. + return ( + <AppBar position="sticky"> + <Toolbar className="toolbar"> + <Link className="link" to={PROJECT_URL}> + <Button className="button">Prosjekter</Button> + </Link> + <Link className="link" to={SCAFFOLDING_URL}> + <Button className="button">Stillasdeler</Button> + </Link> + <Link className="link" to={MAP_URL}> + <Button className="button">Kart</Button> + </Link> + <NavDropdown id="basic-nav-dropdown1" + title={"Logistikk"} + size="sm" + > + <DropdownItem> + <Link to={ADD_PROJECT_URL}>Legg til prosjekt </Link> + </DropdownItem> + <DropdownItem> + <Link to={ADD_SCAFFOLDING_URL}>Legg til stillas</Link> + </DropdownItem> + </NavDropdown> + <DropdownButton id="dropdown-button" + title={"userData.name.firstName"} + size="sm" + > + <DropdownItem> + <Link to={USERINFO_URL}>Bruker Informasjon</Link> + </DropdownItem> + <DropdownItem onClick={logOut}>Logg ut</DropdownItem> + </DropdownButton> + </Toolbar> + </AppBar> + ); } +} export default TopBar; diff --git a/webstillas/src/context/UserAuthContext.js b/webstillas/src/context/UserAuthContext.js index bf428001e92a30c4c502c0cbff96a072ff6b688c..fdbc08fa5d5125e9036fa01c20bd5d828fde9ac6 100644 --- a/webstillas/src/context/UserAuthContext.js +++ b/webstillas/src/context/UserAuthContext.js @@ -9,19 +9,53 @@ import { auth } from "../firebase"; const userAuthContext = createContext(); //Hentet fra https://github.com/WebDevSimplified/React-Firebase-Auth + + +/** + *Function that handles firebase log in and sign up. + * + * @param children + * @returns {JSX.Element} + */ export function UserAuthContextProvider({ children }) { const [user, setUser] = useState({}); + /** + * Function to handle login from firebase. + * + * @param email the registered email of the user + * @param password the corresponding password that matches the users email. + * @returns {Promise<UserCredential>} + */ function logIn(email, password) { return signInWithEmailAndPassword(auth, email, password); } + + /** + * Function to sign up a new user to firebase. + * + * @param email of the user that is to be registered. + * @param password of the user that is to be registered. + * @returns {Promise<UserCredential>} + */ function signUp(email, password) { return createUserWithEmailAndPassword(auth, email, password); } + + /** + * Function that will log a user out of the system. + * @returns {Promise<void>} + */ function logOut() { return signOut(auth); } + + /** + * + * + */ + //Todo kommenter useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (currentuser) => { console.log("Auth", currentuser); diff --git a/webstillas/src/firebase.js b/webstillas/src/firebase.js index ca330e81dae57f615c6413f244edf0264208861d..98165b259b27fdaa277e263bb92d62e4282e05e8 100644 --- a/webstillas/src/firebase.js +++ b/webstillas/src/firebase.js @@ -1,16 +1,24 @@ import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; +import { + FirbaseAPIKEY, FirbaseAppID, + FirbaseMessagingSenderId, + FirbaseprojectId, + FirbaseStorageBucket, + FirebaseAuthDomain +} from "./firebaseConfig"; +//Firebase configuration to database. const firebaseConfig = { - apiKey: "AIzaSyB5XxJ-AIC_Bm38oOH4TjdeIBA0eNLRl7w", - authDomain: "stillas-16563.firebaseapp.com", - projectId: "stillas-16563", - storageBucket: "stillas-16563.appspot.com", - messagingSenderId: "586975019426", - appId: "1:586975019426:web:83a11475b6ae32ffbc32fb" + apiKey: FirbaseAPIKEY, + authDomain: FirebaseAuthDomain, + projectId: FirbaseprojectId, + storageBucket: FirbaseStorageBucket, + messagingSenderId: FirbaseMessagingSenderId, + appId: FirbaseAppID }; -// Initialize Firebase +// Initialize Firebase. const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export default app; diff --git a/webstillas/src/modelData/addData.js b/webstillas/src/modelData/addData.js index 68e0bd095035564ef5d3b16205fb907e71e074a5..cd7c16716c6b7fdb207da0783594834039e92ca4 100644 --- a/webstillas/src/modelData/addData.js +++ b/webstillas/src/modelData/addData.js @@ -2,17 +2,19 @@ import React from 'react' import fetchModel from "./fetchData"; import { useQuery } from 'react-query' - +//Todo set timeout export const GetDummyData = (dataName, url) => { - const { isLoading, data} = useQuery(dataName, ()=>{ + const { isLoading, data, isError, isLoadingError} = useQuery(dataName, ()=>{ return fetchModel(url) }, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false + }) - return {isLoading, data} + return {isLoading, data, isError, isLoadingError} } + diff --git a/webstillas/src/modelData/constantsFile.js b/webstillas/src/modelData/constantsFile.js index 944117bb987e530e25fa1cb938f14dbed1b95c85..39706b9c2050a315b7197ea8e31f160a2eedcff0 100644 --- a/webstillas/src/modelData/constantsFile.js +++ b/webstillas/src/modelData/constantsFile.js @@ -1,4 +1,4 @@ -export const PROJECTS_WITH_SCAFFOLDING_URL = "project?scaffolding=true" +export const PROJECTS_WITH_SCAFFOLDING_URL = "projct?scaffolding=true" export const BASE_URL = "http://10.212.138.205:8080/stillastracking/v1/api/" export const SCAFFOLDING_URL = "unit" export const STORAGE_URL = "storage" diff --git a/webstillas/src/modelData/postModel.js b/webstillas/src/modelData/postModel.js index 48fb7b976507b8d68dd62641af4657131b94d92b..c0de311a2d8eac8db64c3a17eb68354afac02ef8 100644 --- a/webstillas/src/modelData/postModel.js +++ b/webstillas/src/modelData/postModel.js @@ -20,7 +20,11 @@ export default function postModel(url, body) { text: xhr.responseText }))); } else { - resolve((xhr.responseText)); + resolve({ + statusCode: xhr.status, + text: xhr.responseText + } + ); } });