From 563d8645cc31b257e35f03b5c468b8ed587caefe Mon Sep 17 00:00:00 2001 From: ansan johny Date: Thu, 10 Oct 2024 21:12:04 +0530 Subject: [PATCH] feat:optimization --- .../Onboarding/UserInterest/UserInterest.tsx | 482 ++++++------------ 1 file changed, 160 insertions(+), 322 deletions(-) diff --git a/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx b/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx index df1807b75..68b821748 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx @@ -1,13 +1,15 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useCallback } from "react"; +import { useNavigate } from "react-router-dom"; +import toast from "react-hot-toast"; +import { TagsInput } from "react-tag-input-component"; + import OnboardingHeader from "../../../components/OnboardingHeader/OnboardingHeader"; import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; -import styles from "./UserInterest.module.css"; -import muBrand from "/src/modules/Common/Authentication/assets/µLearn.png"; -import { TagsInput } from "react-tag-input-component"; import { privateGateway, publicGateway } from "@/MuLearnServices/apiGateways"; import { onboardingRoutes } from "@/MuLearnServices/urls"; -import toast from "react-hot-toast"; -import { useNavigate } from "react-router-dom"; + +import styles from "./UserInterest.module.css"; +import muBrand from "/src/modules/Common/Authentication/assets/µLearn.png"; import creative from "/src/modules/Common/Authentication/assets/interests/creative.svg"; import maker from "/src/modules/Common/Authentication/assets/interests/makers.svg"; import management from "/src/modules/Common/Authentication/assets/interests/management.svg"; @@ -15,374 +17,210 @@ import software from "/src/modules/Common/Authentication/assets/interests/softwa import others from "/src/modules/Common/Authentication/assets/interests/others.svg"; const CheckMark = () => ( - - + + ); +const INITIAL_INTERESTS = [ + { title: "Software", value: "software", img: software, checked: false }, + { title: "Maker", value: "maker", img: maker, checked: false }, + { title: "Management", value: "management", img: management, checked: false }, + { title: "Creative", value: "creative", img: creative, checked: false }, + { title: "Others", value: "others", img: others, checked: false } +]; + +const INITIAL_ENDGOALS = [ + { title: "Job", value: "job", checked: false }, + { title: "Higher Education", value: "higher_education", checked: false }, + { title: "Entrepreneurship", value: "entrepreneurship", checked: false }, + { title: "Gig Works", value: "gig_work", checked: false }, + { title: "Others", value: "others", checked: false } +]; + +type InterestGroup = { + id: string; + name: string; + category: string; +}; + +type InterestGroups = { + [key: string]: InterestGroup[]; +}; + export default function UserInterest() { - const [interests, setInterests] = useState([ - { title: "Software", value: "software", img: software, checked: false }, - { title: "Maker", value: "maker", img: maker, checked: false }, - { - title: "Management", - value: "management", - img: management, - checked: false - }, - { title: "Creative", value: "creative", img: creative, checked: false }, - { title: "Others", value: "others", img: others, checked: false } - ]); - const [endgoals, setEndgoals] = useState([ - { title: "Job", value: "job", checked: false }, - { - title: "Higher Education", - value: "higher_education", - checked: false - }, - { - title: "Entrepreneurship", - value: "entrepreneurship", - checked: false - }, - { title: "Gig Works", value: "gig_work", checked: false }, - { title: "Others", value: "others", checked: false } - ]); + const [interests, setInterests] = useState(INITIAL_INTERESTS); + const [endgoals, setEndgoals] = useState(INITIAL_ENDGOALS); const [otherInterest, setOtherInterest] = useState([]); const [otherEndgoal, setOtherEndgoal] = useState([]); const [stepTwo, setStepTwo] = useState(false); - const [interestGroups, setInterestGroups] = useState<{}>({}); + const [interestGroups, setInterestGroups] = useState({}); const navigate = useNavigate(); useEffect(() => { - publicGateway - .get(onboardingRoutes.interestGroups) - .then(res => { - var data: [] = res.data?.response?.interestGroup ?? []; - var interestGroupsData = {}; - for (let interest of interests) { - (interestGroupsData as any)[interest.value] = data.filter( - (group: any) => group?.category == interest.value - ); - } + const fetchInterestGroups = async () => { + try { + const res = await publicGateway.get(onboardingRoutes.interestGroups); + const data: InterestGroup[] = res.data?.response?.interestGroup ?? []; + + const interestGroupsData = interests.reduce((acc, interest) => ({ + ...acc, + [interest.value]: data.filter(group => group.category === interest.value) + }), {}); + setInterestGroups(interestGroupsData); - }) - .catch(err => { - console.log(err); - }); - }, []); - - const handleInterestChange = (value: any) => { - if (value === "others") { - if ( - interests.filter(interest => interest.value === value)[0] - .checked - ) { - setOtherInterest([]); + } catch (err) { + console.error('Failed to fetch interest groups:', err); } - } - setInterests( - interests.map(interest => - interest.value === value - ? { ...interest, checked: !interest.checked } - : interest - ) - ); - }; + }; - const handleEndgoalChange = (value: any) => { - if (value === "others") { - if ( - endgoals.filter(endgoal => endgoal.value === value)[0].checked - ) { - setOtherEndgoal([]); - } - } - setEndgoals( - endgoals.map(endgoal => - endgoal.value === value - ? { ...endgoal, checked: !endgoal.checked } - : endgoal - ) - ); - }; + fetchInterestGroups(); + }, []); - const handleContinue = () => { - const selectedInterests = interests - .filter(interest => interest.checked) - .map(interest => interest); - if (selectedInterests.find(interest => interest.value === "others")) { - if (otherInterest.length === 0) { - return; + const handleChange = useCallback((value: string, isInterest: boolean) => { + const setter = isInterest ? setInterests : setEndgoals; + const otherSetter = isInterest ? setOtherInterest : setOtherEndgoal; + + + setter((prev:any) => { + const newItems = prev.map((item:any) => + item.value === value ? { ...item, checked: !item.checked } : item + ); + + if (value === "others" && newItems.find((item:any) => item.value === "others")?.checked === false) { + otherSetter([]); } + + return newItems; + }); + }, []); + + const handleContinue = useCallback(() => { + const selectedInterests = interests.filter(interest => interest.checked); + if (selectedInterests.some(i => i.value === "others") && otherInterest.length === 0) { + return; } if (selectedInterests.length > 0 || otherInterest.length > 0) { setStepTwo(true); } - }; + }, [interests, otherInterest]); - const handleSubmit = () => { - const selectedInterests = interests - .filter(interest => interest.checked) - .map(interest => interest); - const selectedEndgoals = endgoals - .filter(endgoal => endgoal.checked) - .map(endgoal => endgoal); + const handleSubmit = useCallback(async () => { + const selectedInterests = interests.filter(i => i.checked).map(i => i.value); + const selectedEndgoals = endgoals.filter(e => e.checked).map(e => e.value); + const data = { - choosen_interests: selectedInterests.map( - interest => interest.value - ), - choosen_endgoals: selectedEndgoals.map(endgoal => endgoal.value), + choosen_interests: selectedInterests, + choosen_endgoals: selectedEndgoals, other_interests: otherInterest, other_endgoals: otherEndgoal }; + try { - privateGateway - .post(onboardingRoutes.interests, data) - .then(res => { - toast.success(res.data?.message.general[0]); - navigate("/dashboard/connect-discord"); - }) - .catch(err => { - toast.error(err.response?.data.message.general[0]); - }); - } catch (err) { - toast.error("Unexpected Error occured"); + const res = await privateGateway.post(onboardingRoutes.interests, data); + toast.success(res.data?.message.general[0]); + navigate("/dashboard/connect-discord"); + } catch (err: any) { + toast.error(err.response?.data.message.general[0] || "Unexpected Error occurred"); } - }; + }, [interests, endgoals, otherInterest, otherEndgoal, navigate]); const isInterestSelected = interests.some(interest => interest.checked); const isEndgoalSelected = endgoals.some(endgoal => endgoal.checked); - return stepTwo ? ( - <> - -
-
- mulearn -

What describes you the most!

-

- Choose one or goals you expect from µLearn. -

-
- {endgoals.map(endgoal => { - let classname = `${styles.itemsCard} ${ - endgoal.checked && styles.checked - }`; - return ( -
- handleEndgoalChange(endgoal.value) - } - > - {endgoal.checked && } -

{endgoal.title}

+ const renderItems = useCallback((items: typeof interests | typeof endgoals, isInterest: boolean) => ( +
+ {items.map(item => { + const isOthers = item.value === "others"; + const isChecked = item.checked; + const otherItems = isInterest ? otherInterest : otherEndgoal; + const setOtherItems = isInterest ? setOtherInterest : setOtherEndgoal; - {endgoal.value == "others" ? ( - endgoals.find( - endgoal => - endgoal.value === "others" - )?.checked && ( -
{ - e.stopPropagation(); - }} - > - { - if ( - e.target.value - .length > 0 - ) { - setOtherEndgoal([ - ...otherEndgoal, - e.target.value - ]); - e.target.value = ""; - } - }} - onChange={setOtherEndgoal} - name="other_endgoals" - placeHolder="Specify your endgoals" - /> -
- ) - ) : ( - <> - )} + return ( +
handleChange(item.value, isInterest)} + > + {isChecked && } + {isInterest ? ( +
+ +

{item.title}

+
+ ) : ( +

{item.title}

+ )} + {isInterest && ( + <> +
e.stopPropagation()}> + + + + +
+
+

This category includes:

+
    + {interestGroups[item.value]?.map((group: InterestGroup) => ( +
  • {group.name}
  • + ))} +
- ); - })} + + )} + {isOthers && isChecked && ( +
e.stopPropagation()}> + { + if (e.target.value.length > 0) { + setOtherItems([...otherItems, e.target.value]); + e.target.value = ""; + } + }} + onChange={setOtherItems} + name={`other_${isInterest ? 'interests' : 'endgoals'}`} + placeHolder={`Specify your ${isInterest ? 'interest' : 'endgoal'}`} + separators={isInterest ? [","] : undefined} + /> +
+ )}
+ ); + })} +
+ ), [handleChange, interestGroups, otherInterest, otherEndgoal]); - {isEndgoalSelected && ( - - Submit - - )} -
-
- - ) : ( + return ( <>
mulearn -

Your dynamic area of interest!

+

{stepTwo ? "What describes you the most!" : "Your dynamic area of interest!"}

- Please select your interested area + {stepTwo ? "Choose one or goals you expect from µLearn." : "Please select your interested area"}

-
- {interests.map(interest => { - let classname = `${styles.itemsCard} ${ - interest.checked && styles.active - }`; - return ( -
- handleInterestChange(interest.value) - } - > - {interest.checked && } -
- -

- {interest.title} -

-
-
{ - e.stopPropagation(); - }} - > - - - - -
-
-

This category includes:

-
    - {(interestGroups as any)[ - interest.value - ]?.map((group: any) => ( -
  • - {group.name} -
  • - ))} -
-
- {interest.value == "others" ? ( - interests.find( - interest => - interest.value === "others" - )?.checked && ( - <> -
{ - e.stopPropagation(); - }} - > - { - if ( - e.target.value - .length > 0 - ) { - setOtherInterest( - [ - ...otherInterest, - e.target - .value - ] - ); - e.target.value = - ""; - } - }} - separators={[","]} - onChange={ - setOtherInterest - } - name="other_interests" - placeHolder="Specify your interest" - /> -
- - ) - ) : ( - <> - )} -
- ); - })} -
+ + {stepTwo ? renderItems(endgoals, false) : renderItems(interests, true)} - {isInterestSelected && ( + {(stepTwo ? isEndgoalSelected : isInterestSelected) && ( - Continue + {stepTwo ? "Submit" : "Continue"} )}
); -} +} \ No newline at end of file