diff --git a/frontend/front/src/api/apiSlice.js b/frontend/front/src/api/apiSlice.js index c785f56f..518146b0 100644 --- a/frontend/front/src/api/apiSlice.js +++ b/frontend/front/src/api/apiSlice.js @@ -1,6 +1,7 @@ import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { AUTHORIZATION_HEADER } from "../features/login/loginUtils"; +import { transformSurveyorKeys } from "../features/surveyor/surveyorUtils"; const baseUrl = process.env.REACT_APP_API_URL || "http://localhost:3000"; @@ -98,6 +99,7 @@ export const apiSlice = createApi({ // }), getSurveyor: builder.query({ query: (id) => `/surveyors/${id}`, + transformResponse: (result) => result && transformSurveyorKeys(result), providesTags: (result, error, arg) => [{ type: "Surveyor", id: arg }], }), createSurveyor: builder.mutation({ @@ -114,6 +116,7 @@ export const apiSlice = createApi({ method: "PUT", body: surveyor, }), + transformResponse: (result) => result && transformSurveyorKeys(result), invalidatesTags: (result, error, arg) => [ { type: "Surveyor", id: arg.id }, ], diff --git a/frontend/front/src/features/login/loginUtils.js b/frontend/front/src/features/login/loginUtils.js index 663ccff0..a6e9398a 100644 --- a/frontend/front/src/features/login/loginUtils.js +++ b/frontend/front/src/features/login/loginUtils.js @@ -43,8 +43,8 @@ export const useLocallyStoredJWT = () => { export const decodeJwt = (token) => { // "sub" = "subject", aka the user id - const { sub, email, role } = jwt_decode(token); - return { id: sub, email, role }; + const { surveyorId, sub, email, role } = jwt_decode(token); + return { id: surveyorId, userId: sub, email, role }; }; export const generatePassword = () => diff --git a/frontend/front/src/features/surveyor/surveyorUtils.js b/frontend/front/src/features/surveyor/surveyorUtils.js new file mode 100644 index 00000000..d1cafc97 --- /dev/null +++ b/frontend/front/src/features/surveyor/surveyorUtils.js @@ -0,0 +1,15 @@ +/* + * Transform backend surveyor keys to match surveyor form name fields + */ +export const transformSurveyorKeys = (data) => { + if (!data) return null; + + const { firstname, lastname, street_address, zipcode, ...rest } = data; + return { + ...rest, + firstName: firstname, + lastName: lastname, + streetAddress: street_address, + zipCode: zipcode, + }; +}; diff --git a/frontend/front/src/pages/Admin/user/UserProfile.js b/frontend/front/src/pages/Admin/user/UserProfile.js index 04dd7354..977b5198 100644 --- a/frontend/front/src/pages/Admin/user/UserProfile.js +++ b/frontend/front/src/pages/Admin/user/UserProfile.js @@ -41,7 +41,6 @@ const UserProfile = () => { defaultValues: { firstName: "", lastName: "", - email: "", phone: "", streetAddress: "", city: "", @@ -57,10 +56,10 @@ const UserProfile = () => { ...surveyorData, firstname: data.firstName, lastname: data.lastName, - email: data.email, phone: data.phone, - street_address: data.street_address, + street_address: data.streetAddress, city: data.city, + zipcode: data.zipCode, }; updateSurveyor(newSurveyorData) .unwrap() @@ -127,13 +126,12 @@ const UserProfile = () => { useEffect(() => { if (surveyorData) { reset({ - firstName: surveyorData.firstname, - lastName: surveyorData.lastname, - email: surveyorData.email, + firstName: surveyorData.firstName, + lastName: surveyorData.lastName, phone: surveyorData.phone, - streetAddress: surveyorData.street_address, + streetAddress: surveyorData.streetAddress, city: surveyorData.city, - zipCode: surveyorData.zipcode, + zipCode: surveyorData.zipCode, state: surveyorData.state, }); } @@ -226,9 +224,11 @@ const UserProfile = () => { title="Confirm Deactivation" message="Please confirm to deactivate this user." /> - - - User Profile: {uid} + + + + User Profile: {surveyorData.email} + Status: {surveyorData.status} @@ -247,7 +247,7 @@ const UserProfile = () => { value={value} label="First Name" variant="standard" - sx={{ width: "95%", mx: 2, mt: 3 }} + sx={{ width: "95%", mx: 1, mt: 3 }} /> )} /> @@ -261,21 +261,7 @@ const UserProfile = () => { value={value} label="Last Name" variant="standard" - sx={{ width: "95%", mx: 2, mt: 3 }} - /> - )} - /> - ( - )} /> @@ -286,10 +272,10 @@ const UserProfile = () => { )} /> @@ -303,7 +289,7 @@ const UserProfile = () => { value={value} label="Street Address" variant="standard" - sx={{ width: "95%", mx: 2, mt: 3 }} + sx={{ width: "95%", mx: 1, mt: 3 }} /> )} /> @@ -317,35 +303,35 @@ const UserProfile = () => { value={value} label="City" variant="standard" - sx={{ width: "95%", mx: 2, mt: 3 }} + sx={{ width: "95%", mx: 1, mt: 3 }} /> )} /> ( )} /> ( )} /> diff --git a/frontend/front/src/pages/Surveyor/Components/EditAccount.js b/frontend/front/src/pages/Surveyor/Components/EditAccount.js new file mode 100644 index 00000000..a1c0f3e5 --- /dev/null +++ b/frontend/front/src/pages/Surveyor/Components/EditAccount.js @@ -0,0 +1,254 @@ +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { Box, Button, Grid, Paper, TextField } from "@mui/material"; +import CustomSnackbar from "../../../components/CustomSnackbar"; +import { SURVEYOR_DASHBOARD_ROUTE } from "../../../routing/routes"; +import { useUpdateSurveyorMutation } from "../../../api/apiSlice"; +import { + validatePhoneNumber, + validateZipCode, +} from "../../../util/stringUtils"; + +const EditAccount = ({ surveyorData }) => { + const { firstName, lastName, phone, streetAddress, city, zipCode, state } = + surveyorData; + const navigate = useNavigate(); + const { + register, + handleSubmit, + formState: { errors, isDirty }, + reset, + } = useForm({ + defaultValues: { + firstName, + lastName, + phone, + streetAddress, + city, + zipCode, + state, + }, + }); + + const paperStyle = { + padding: 40, + display: "flex", + flexDirection: "column", + width: 280, + margin: "20px auto", + }; + + const btnstyle = { margin: "10px 0" }; + + const [ + updateSurveyor, + { + isLoading: updateSurveyorProg, + isSuccess: updateSurveyorSuccess, + isError: updateSurveyorError, + }, + ] = useUpdateSurveyorMutation(); + + async function EditAccountForms(values) { + if (!values) return; + const newSurveyorData = { + ...surveyorData, + firstname: values.firstName, + lastname: values.lastName, + phone: values.phone, + street_address: values.streetAddress, + city: values.city, + zipcode: values.zipCode, + }; + const updatedSurveyorData = await updateSurveyor(newSurveyorData).unwrap(); + if (updatedSurveyorData) { + reset({ + firstName: updatedSurveyorData.firstName, + lastName: updatedSurveyorData.lastName, + phone: updatedSurveyorData.phone, + streetAddress: updatedSurveyorData.streetAddress, + city: updatedSurveyorData.city, + zipCode: updatedSurveyorData.zipCode, + state: updatedSurveyorData.state, + }); + } + } + return ( + + + +

Update Account Details?

+
+ +
+ + + + + + + + + + {updateSurveyorSuccess && ( + + )} + {updateSurveyorError && ( + + )} +
+
+ ); +}; + +export default EditAccount; diff --git a/frontend/front/src/pages/Surveyor/SurveyorContainer.js b/frontend/front/src/pages/Surveyor/SurveyorContainer.js index 22f4cdfd..eaebe7d6 100644 --- a/frontend/front/src/pages/Surveyor/SurveyorContainer.js +++ b/frontend/front/src/pages/Surveyor/SurveyorContainer.js @@ -11,7 +11,6 @@ import { import { ProtectedInactive } from "../../routing/ProtectedInactive"; import InactiveSurveyor from "./Components/InactiveSurveyor"; import Account from "./account/Account"; -import EditAccount from "./account/edit/EditAccount"; import Dashboard from "./dashboard/Dashboard"; import HouseProfile from "./houseProfile/HouseProfile"; import Nav from "./nav/Nav"; @@ -32,7 +31,6 @@ const SurveyorContainer = () => { > }> }> - }> }> { - const { firstName, lastName, email, address, phoneNumber } = useSelector( - (state) => state.account - ); + const currentUser = useSelector(selectCurrentUser); + const { + data: surveyorData, + isLoading: isSurveyorDataLoading, + isError: isSurveyorError, + } = useGetSurveyorQuery(currentUser.id); + return ( <> - - - - - - - - - - - - - - {/* - - - - --Feature will not implemented on backend - - - */} - - + {isSurveyorDataLoading ? ( + + ) : !surveyorData || isSurveyorError ? ( + + ) : ( + + )} ); }; diff --git a/frontend/front/src/pages/Surveyor/account/edit/EditAccount.js b/frontend/front/src/pages/Surveyor/account/edit/EditAccount.js deleted file mode 100644 index 8834b592..00000000 --- a/frontend/front/src/pages/Surveyor/account/edit/EditAccount.js +++ /dev/null @@ -1,207 +0,0 @@ -import React from "react"; -import Button from "@mui/material/Button"; -import { Grid, Paper, TextField, Box } from "@mui/material"; -import { useForm } from "react-hook-form"; -import { useDispatch, useSelector } from "react-redux"; -import { setAccount } from "../../../../features/account/accountSlice"; -import { useNavigate, Link } from "react-router-dom"; - -const EditAccount = () => { - const dispatch = useDispatch(); - const navigate = useNavigate(); - - const { - register, - handleSubmit, - formState: { errors }, - reset, - } = useForm(); - - const { firstName, lastName, email, address, phoneNumber } = useSelector( - (state) => state.account - ); - - const paperStyle = { - padding: 40, - - display: "flex", - flexDirection: "column", - width: 280, - margin: "20px auto", - }; - - const btnstyle = { margin: "10px 0" }; - - const errorStyles = { - color: "rgb(239 68 68 / 1)", - fontSize: "0.875rem", - lineHeight: "1.25rem", - }; - - async function EditAccountForms(values) { - if (!values) return; - - dispatch( - setAccount({ - firstName: values.firstName, - lastName: values.lastName, - email: values.email, - address: values.address, - phoneNumber: values.phoneNumber, - }) - ); - - reset(); - - navigate("../account"); - } - - return ( - - - -

Update Account Details?

-
- -
- - {errors?.firstName?.message} - - {errors?.lastName?.message} - ()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, - message: "Please enter a valid email", - }, - })} - /> - {errors?.email?.message} - - {errors?.address?.message} - - {errors?.phoneNumber?.message} - - - - -
-
- ); -}; - -export default EditAccount; diff --git a/frontend/front/src/util/stringUtils.js b/frontend/front/src/util/stringUtils.js index 545360f6..d76f9b05 100644 --- a/frontend/front/src/util/stringUtils.js +++ b/frontend/front/src/util/stringUtils.js @@ -28,3 +28,26 @@ export const isPasswordValid = (password) => { }; } }; + +export const validatePhoneNumber = (value) => { + const digitsOnly = value.replace(/\D/g, ""); + if ( + (digitsOnly.length === 11 && digitsOnly.startsWith("1")) || + digitsOnly.length === 10 + ) { + const validCharacters = /^[0-9()\-\s]+$/; + if (validCharacters.test(value)) { + return true; + } + } + + return "Invalid phone number format"; +}; + +export const validateZipCode = (value) => { + const zipPattern = /^\d{5}(-\d{4})?$/; + if (!zipPattern.test(value)) { + return "Invalid zip code format"; + } + return true; +};