diff --git a/src/components/shared/profileCompletion/ProfileCompletion.jsx b/src/components/shared/profileCompletion/ProfileCompletion.jsx index bb554703..3160e9d6 100644 --- a/src/components/shared/profileCompletion/ProfileCompletion.jsx +++ b/src/components/shared/profileCompletion/ProfileCompletion.jsx @@ -2,10 +2,12 @@ import Cookies from "js-cookie"; import React, { useEffect, useState } from "react"; import { IoMdCloseCircleOutline } from "react-icons/io"; import { useDispatch, useSelector } from "react-redux"; -import { ProfileCompletionDetails } from "../../../constants"; + +import { ProfileElements } from "../../../constants"; import { updateUserData } from "../../../redux/slice/userSlice"; import { UpdateUser } from "../../../service/MilanApi"; import { showErrorToast, showSuccessToast } from "../../../utils/Toasts"; +import getProfileFields from "../../../utils/getProfileFields"; import Button from "../buttons/globalbutton/Button"; import "./ProfileCompletion.scss"; @@ -14,96 +16,34 @@ const ProfileCompletion = ({ editProfile, seteditProfile, }) => { - const [missingElements, setMissingElements] = useState([]); - const [currentStep, setcurrentStep] = useState(0); + const [currentStep, setcurrentStep] = useState(2); + const [currentIndex, setcurrentIndex] = useState(0); const [formData, setFormData] = useState({}); const [errors, setErrors] = useState({}); const info = useSelector((state) => state.user); const dispatch = useDispatch(); useEffect(() => { - calculateMissingElements(); if (editProfile) { setFormData(info); } - }, [info]); - - const calculateMissingElements = () => { - const missing = []; - if (!info.tagLine) missing.push("tagLine"); - if (!info.description) missing.push("description"); - if (!info.city) missing.push("city"); - if (!info.state) missing.push("state"); - if (!info.address) missing.push("address"); - if (!info.country) missing.push("country"); - if (!info.pincode) missing.push("pincode"); - - setMissingElements(missing); - }; - - const editProfileFields = [ - "name", - "tagLine", - "description", - "city", - "state", - "address", - "country", - "pincode", - ]; - - const calculateTotalSteps = () => { - if (editProfile) { - if (editProfileFields.length % 2 === 0) { - return Math.ceil(editProfileFields.length / 2); - } else { - return Math.ceil(editProfileFields.length / 2) + 1; - } - } else { - if (missingElements.length % 2 === 0) { - return Math.ceil(missingElements.length / 2); - } else { - return Math.ceil(missingElements.length / 2) + 1; - } - } - }; - - const validateFields = () => { - let stepErrors = {}; + }, []); - const currentMissingElements = missingElements.slice( - currentStep, - currentStep + 2, - ); - - const formElementstoBeValidated = ProfileCompletionDetails.elements.filter( - (element) => currentMissingElements.includes(element.id), - ); - - formElementstoBeValidated.forEach((element) => { - if ( - !formData[element.id] || - element.minimumLength > formData[element.id]?.length - ) { - stepErrors[element.id] = element.errorMessage; - } - }); - - setErrors(stepErrors); - return Object.keys(stepErrors).length === 0; - }; + const fields = getProfileFields(info, editProfile); + const totalfields = fields.length; const handleIncrementStep = () => { - if (editProfile) { - if (currentStep < calculateTotalSteps()) setcurrentStep(currentStep + 2); - } else { - if (validateFields() && currentStep < calculateTotalSteps()) - setcurrentStep(currentStep + 2); + if (currentStep + 2 <= totalfields) { + setcurrentIndex(currentIndex + 2); + setcurrentStep(currentStep + 2); } }; const handleDecrementStep = () => { - if (currentStep - 2 >= 0) setcurrentStep(currentStep - 2); + if (currentStep - 2 >= 2) { + setcurrentIndex(currentIndex - 2); + setcurrentStep(currentStep - 2); + } }; const handleChange = (e) => { @@ -113,24 +53,18 @@ const ProfileCompletion = ({ const handleSubmit = async (e) => { e.preventDefault(); - if (validateFields()) { - const response = await UpdateUser(formData); - if (response?.status !== 200) { - showErrorToast(response?.data?.message); - } else { - dispatch(updateUserData(formData)); - setFormData({}); - setShowProfileModal(false); - seteditProfile(false); - showSuccessToast(response?.data?.message); - } + const response = await UpdateUser(formData); + if (response?.status !== 200) { + showErrorToast(response?.data?.message); + } else { + dispatch(updateUserData(formData)); + setFormData({}); + setShowProfileModal(false); + seteditProfile(false); + showSuccessToast(response?.data?.message); } }; - const maxSteps = editProfile - ? editProfileFields.length - : missingElements.length; - return (
@@ -154,73 +88,36 @@ const ProfileCompletion = ({
- {editProfile - ? editProfileFields - .slice(currentStep, currentStep + 2) - .map((elId) => { - const formElement = ProfileCompletionDetails.elements.find( - (element) => element.id === elId, - ); - console.log("🚀 ~ .map ~ formElement:", formElement); - - return ( -
- - - {errors[formElement?.id] && ( -

{errors[formElement?.id]}

- )} -
- ); - }) - : missingElements - .slice(currentStep, currentStep + 2) - .map((elId) => { - const formElement = ProfileCompletionDetails.elements.find( - (element) => element.id === elId, - ); - - return ( -
- - - {errors[formElement?.id] && ( -

{errors[formElement?.id]}

- )} -
- ); - })} + {fields.slice(currentIndex, currentIndex + 2).map((elId) => { + const formElement = ProfileElements.find( + (element) => element.id === elId, + ); + + return ( +
+ + +
+ ); + })}
- {currentStep + 2 >= maxSteps ? ( + {currentStep == totalfields ? ( diff --git a/src/constants/ProfileCompletionDetails.js b/src/constants/ProfileCompletionDetails.js deleted file mode 100644 index efac46bf..00000000 --- a/src/constants/ProfileCompletionDetails.js +++ /dev/null @@ -1,93 +0,0 @@ -import { z } from "zod"; - -const ProfileCompletionDetails = { - elements: [ - { - id: "name", - label: "Name", - placeholder: "Your organization's name", - minimumLength: 5, - errorMessage: "Name must be at least 5 characters long", - type: "text", - }, - { - id: "tagLine", - label: "Tagline", - placeholder: "A small and attractive tagline", - minimumLength: 20, - errorMessage: "Tagline must be at least 20 characters long", - type: "text", - }, - { - id: "description", - label: "Bio", - placeholder: "A detailed bio about your organization", - minimumLength: 100, - errorMessage: "Bio must be at least 100 characters long", - type: "textarea", - }, - { - id: "city", - label: "City", - placeholder: "The city where your organization is located", - minimumLength: 3, - errorMessage: "City must be at least 3 characters long", - type: "text", - }, - { - id: "state", - label: "State", - placeholder: "The state where your organization is located", - minimumLength: 3, - errorMessage: "State must be at least 3 characters long", - type: "text", - }, - { - id: "address", - label: "Address", - placeholder: "The address of your organization", - minimumLength: 10, - errorMessage: "Address must be at least 10 characters long", - type: "text", - }, - { - id: "country", - label: "Country", - placeholder: "The country where your organization is located", - minimumLength: 3, - errorMessage: "Country must be at least 3 characters long", - type: "text", - }, - { - id: "pincode", - label: "Pincode", - placeholder: "The pincode of your organization", - minimumLength: 6, - errorMessage: "Pincode must be at least 6 characters long", - type: "text", - }, - ], - - schema: z.object({ - tagLine: z.string().min(20, { - message: "Tagline must be at least 20 characters long.", - }), - description: z.string().min(50, { - message: "Description must be at least 50 characters long.", - }), - city: z.string().min(5, { - message: "City must be at least 2 characters long.", - }), - state: z.string().min(5, { - message: "State must be at least 5 characters long.", - }), - address: z.string().min(5, { - message: "Address must be at least 5 characters long.", - }), - pincode: z.number().min(6, { - message: "Pincode must be at least 6 characters long.", - }), - }), -}; - -export default ProfileCompletionDetails; diff --git a/src/constants/ProfileElements.js b/src/constants/ProfileElements.js new file mode 100644 index 00000000..4dc2c203 --- /dev/null +++ b/src/constants/ProfileElements.js @@ -0,0 +1,84 @@ +const ProfileElements = [ + { + id: "name", + label: "Name", + placeholder: "Your organization's name", + minimumLength: 5, + errorMessage: "Name must be at least 5 characters long", + type: "text", + }, + { + id: "firstname", + label: "First Name", + placeholder: "Your first name", + minimumLength: 5, + errorMessage: "First Name must be at least 5 characters long", + type: "text", + }, + { + id: "lastname", + label: "Last Name", + placeholder: "Your last name", + minimumLength: 5, + errorMessage: "Last name must be at least 5 characters long", + type: "text", + }, + { + id: "tagLine", + label: "Tagline", + placeholder: "A small and attractive tagline", + minimumLength: 20, + errorMessage: "Tagline must be at least 20 characters long", + type: "text", + }, + { + id: "description", + label: "Bio", + placeholder: "A detailed bio about your organization", + minimumLength: 100, + errorMessage: "Bio must be at least 100 characters long", + type: "textarea", + }, + { + id: "city", + label: "City", + placeholder: "The city where your organization is located", + minimumLength: 3, + errorMessage: "City must be at least 3 characters long", + type: "text", + }, + { + id: "state", + label: "State", + placeholder: "The state where your organization is located", + minimumLength: 3, + errorMessage: "State must be at least 3 characters long", + type: "text", + }, + { + id: "address", + label: "Address", + placeholder: "The address of your organization", + minimumLength: 10, + errorMessage: "Address must be at least 10 characters long", + type: "text", + }, + { + id: "country", + label: "Country", + placeholder: "The country where your organization is located", + minimumLength: 3, + errorMessage: "Country must be at least 3 characters long", + type: "text", + }, + { + id: "pincode", + label: "Pincode", + placeholder: "The pincode of your organization", + minimumLength: 6, + errorMessage: "Pincode must be at least 6 characters long", + type: "text", + }, +]; + +export default ProfileElements; diff --git a/src/constants/index.js b/src/constants/index.js index 82416982..51c0d018 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -1,2 +1,2 @@ export { default as AuthSchema } from "./AuthSchema"; -export { default as ProfileCompletionDetails } from "./ProfileCompletionDetails"; +export { default as ProfileElements } from "./ProfileElements"; diff --git a/src/pages/auth/SignUp.jsx b/src/pages/auth/SignUp.jsx index a58333e7..7a37a22e 100644 --- a/src/pages/auth/SignUp.jsx +++ b/src/pages/auth/SignUp.jsx @@ -1,5 +1,5 @@ import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useState } from "react"; +import React from "react"; import { Helmet } from "react-helmet-async"; import { useForm } from "react-hook-form"; import { FaChevronDown } from "react-icons/fa"; @@ -9,8 +9,10 @@ import { ToastContainer } from "react-toastify"; import rightabstract from "../../assets/pictures/authpages/authbanner.png"; import { Button } from "../../components/shared"; +import { useDispatch, useSelector } from "react-redux"; import { AuthSchema } from "../../constants"; import { useAuth } from "../../hooks/useAuth"; +import { setAuthType } from "../../redux/slice/authSlice"; import { GoogleAuth } from "../../service/MilanApi"; import "./index.css"; @@ -32,12 +34,10 @@ const SignUp = () => { }); const navigate = useNavigate(); + const dispatch = useDispatch(); - const authTypeOptions = [ - { value: "individual", label: "Individual (Person)" }, - { value: "club", label: "Organization (Charity/Club/NGO)" }, - ]; - const [authType, setauthType] = useState("individual"); + const authTypeOptions = useSelector((state) => state.auth.authTypeOptions); + const authType = useSelector((state) => state.auth.authType); const handleGoogle = async () => { const response = await GoogleAuth(); @@ -86,8 +86,8 @@ const SignUp = () => { {...iregister("usertype")} onChange={() => { authType === "individual" - ? setauthType("club") - : setauthType("individual"); + ? dispatch(setAuthType("club")) + : dispatch(setAuthType("individual")); }} > {authTypeOptions.map((option) => ( @@ -222,8 +222,8 @@ const SignUp = () => { {...cregister("usertype")} onChange={() => { authType === "individual" - ? setauthType("club") - : setauthType("individual"); + ? dispatch(setAuthType("club")) + : dispatch(setAuthType("individual")); }} > {authTypeOptions.map((option) => ( diff --git a/src/pages/profile/Profile.jsx b/src/pages/profile/Profile.jsx index 8457ca01..d5653f07 100644 --- a/src/pages/profile/Profile.jsx +++ b/src/pages/profile/Profile.jsx @@ -73,10 +73,18 @@ const Profile = () => { />
-
-

{info?.name}

-

{info?.tagLine}

-
+ {info?.usertype === "club" ? ( +
+

{info?.name}

+

{info?.tagLine}

+
+ ) : ( +
+

+ {info?.firstname} {info?.lastname}{" "} +

+
+ )}
{params.username === Cookies.get("username") ? ( @@ -238,18 +246,20 @@ const Profile = () => {
)} -
-

Find us here

- -
+ {info?.usertype === "club" && ( +
+

Find us here

+ +
+ )}
diff --git a/src/redux/slice/authSlice.js b/src/redux/slice/authSlice.js new file mode 100644 index 00000000..cdbb5382 --- /dev/null +++ b/src/redux/slice/authSlice.js @@ -0,0 +1,22 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + authTypeOptions: [ + { value: "individual", label: "Individual (Person)" }, + { value: "club", label: "Organization (Charity/Club/NGO)" }, + ], + authType: "individual", +}; + +const authSlice = createSlice({ + name: "auth", + initialState, + reducers: { + setAuthType: (state, action) => { + state.authType = action.payload; + }, + }, +}); + +export const { setAuthType } = authSlice.actions; +export default authSlice.reducer; diff --git a/src/redux/store.js b/src/redux/store.js index d444510e..bbb0599b 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -1,10 +1,12 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit"; import { persistReducer, persistStore } from "redux-persist"; import storage from "redux-persist/lib/storage"; +import authReducer from "./slice/authSlice"; import userReducer from "./slice/userSlice"; const rootReducer = combineReducers({ user: userReducer, + auth: authReducer, }); const persistConfig = { diff --git a/src/utils/getProfileFields.js b/src/utils/getProfileFields.js new file mode 100644 index 00000000..3e353810 --- /dev/null +++ b/src/utils/getProfileFields.js @@ -0,0 +1,48 @@ +function getMissingElements(info) { + const missing = []; + + if (info?.usertype === "club") { + if (!info.name) missing.push("name"); + if (!info.tagLine) missing.push("tagLine"); + } else { + if (!info.firstname) missing.push("firstname"); + if (!info.lastname) missing.push("lastname"); + } + + if (!info.description) missing.push("description"); + if (!info.city) missing.push("city"); + if (!info.state) missing.push("state"); + if (!info.address) missing.push("address"); + if (!info.country) missing.push("country"); + if (!info.pincode) missing.push("pincode"); + + return missing; +} + +function getEditableFields(info) { + return info?.usertype === "club" + ? [ + "name", + "tagLine", + "description", + "city", + "state", + "address", + "country", + "pincode", + ] + : [ + "firstname", + "lastname", + "description", + "city", + "state", + "address", + "country", + "pincode", + ]; +} + +export default function getProfileFields(info, isEdit) { + return isEdit ? getEditableFields(info) : getMissingElements(info); +} diff --git a/src/utils/routesConfig.jsx b/src/utils/routesConfig.jsx index a83f2c3e..eaa6d5f9 100644 --- a/src/utils/routesConfig.jsx +++ b/src/utils/routesConfig.jsx @@ -8,14 +8,13 @@ import { Shop, SignIn, SignUp, - UserProfile, } from "../pages/route"; const routesConfig = [ { path: "/", element: }, { path: "/auth/signup", element: }, { path: "/auth/login", element: }, - { path: "/user/:username", element: }, + { path: "/user/:username", element: }, { path: "/clubs", element: }, { path: "/club/:username", element: }, { path: "/events", element: },