From e99ae02693519922c5b2197bc1ecedfc27593acd Mon Sep 17 00:00:00 2001 From: Mohamed Ali Alkassas Date: Tue, 16 Sep 2025 20:10:49 +0300 Subject: [PATCH 1/2] update(web): update student settings page design --- .../components/Settings/StudentPublicInfo.tsx | 165 ++++++++++++++++++ .../components/StudentSettings/Content.tsx | 24 +-- .../src/components/StudentSettings/utils.ts | 2 +- packages/atlas/src/api/student.ts | 4 + packages/headless/src/student.ts | 20 ++- packages/types/src/student.ts | 10 ++ .../components/MultiSelect/MultiSelect.tsx | 2 +- packages/ui/src/components/Tabs/Tabs.tsx | 6 +- packages/ui/src/locales/ar-eg.json | 4 +- packages/utils/src/routes/route.ts | 4 +- 10 files changed, 218 insertions(+), 23 deletions(-) create mode 100644 apps/web/src/components/Settings/StudentPublicInfo.tsx diff --git a/apps/web/src/components/Settings/StudentPublicInfo.tsx b/apps/web/src/components/Settings/StudentPublicInfo.tsx new file mode 100644 index 000000000..4f86747e1 --- /dev/null +++ b/apps/web/src/components/Settings/StudentPublicInfo.tsx @@ -0,0 +1,165 @@ +import { languageLevels } from "@/constants/student"; +import { useOnError } from "@/hooks/error"; +import { useForm } from "@litespace/headless/form"; +import { + useFindStudentById, + useUpdateStudent, +} from "@litespace/headless/student"; +import { useInfiniteTopics } from "@litespace/headless/topic"; +import { IStudent, ITopic } from "@litespace/types"; +import { Button } from "@litespace/ui/Button"; +import { Form } from "@litespace/ui/Form"; +import { useFormatMessage } from "@litespace/ui/hooks/intl"; +import { useMakeValidators } from "@litespace/ui/hooks/validation"; +import { Input } from "@litespace/ui/Input"; +import { validateEnglishLevel } from "@litespace/ui/lib/validate"; +import { MultiSelect } from "@litespace/ui/MultiSelect"; +import { Select } from "@litespace/ui/Select"; +import { Textarea } from "@litespace/ui/Textarea"; +import { useToast } from "@litespace/ui/Toast"; +import { Typography } from "@litespace/ui/Typography"; +import React, { useCallback, useMemo } from "react"; + +type IForm = { + topics: ITopic.Self["name"]["ar"][]; + career: string; + level: IStudent.EnglishLevel; + aim: string; +}; + +export const StudentPublicInfo: React.FC<{ id: number }> = ({ id }) => { + const intl = useFormatMessage(); + const toast = useToast(); + + const { data } = useFindStudentById(id); + + const { list: allTopics } = useInfiniteTopics(); + + const onSuccess = useCallback(() => { + toast.success({ + title: intl("student-settings.updated-successfully"), + }); + }, [intl, toast]); + + const onError = useOnError({ + type: "mutation", + handler: ({ messageId }) => { + toast.error({ + title: intl("complete-profile.update.error"), + description: intl(messageId), + }); + }, + }); + + const updateStudent = useUpdateStudent({ onSuccess, onError }); + + const validators = useMakeValidators({ + career: { required: false }, + level: { required: false, validate: validateEnglishLevel }, + aim: { required: false }, + }); + + const form = useForm({ + defaults: { + topics: data?.topics.map((topic) => topic.name.ar) || [], + career: data?.career || intl("labels.jobs.student"), + level: data?.level || IStudent.EnglishLevel.Beginner, + aim: data?.aim || "", + }, + validators, + onSubmit(data) { + updateStudent.mutate({ + id, + payload: { + topics: data.topics, + career: data.career, + level: data.level, + aim: data.aim, + }, + }); + }, + }); + + const levels = useMemo( + () => + Object.entries(languageLevels).map(([key, value]) => ({ + label: intl(value), + value: Number(key), + })), + [intl] + ); + + return ( +
+
+
+ + {intl("student-settings.public-info.title")} + + ({ + label: topic.name.ar, + value: topic.name.ar, + })) || [] + } + placeholder={intl("complete-profile.topics.placeholder")} + values={form.state.topics} + setValues={(values) => form.set("topics", values)} + /> + + form.set("career", e.target.value)} + label={intl("labels.job")} + placeholder={intl("complete-profile.job.placeholder")} + state={form.errors.career ? "error" : undefined} + helper={form.errors.career} + /> + +