From 848e3b8f026c1c8ebe3036039a94b7574de26c9c Mon Sep 17 00:00:00 2001 From: Vy Ngo Chi Date: Wed, 26 Aug 2026 16:06:04 +0700 Subject: [PATCH] feat: implement tutor profile editor system and add messages screen UI --- apps/sale/app/tutor/profile/edit/loading.tsx | 5 + .../messages/components/ChatSidebar.tsx | 2 +- .../messages/components/MessagesScreen.tsx | 7 +- .../components/TutorApprovedPreview.tsx | 6 +- .../components/tutor-approved.ui.tsx | 139 ++---------- .../components/AvailabilityListField.tsx | 68 ++++++ .../components/EditableProfileBlock.tsx | 39 ++++ .../components/ProfileBlockDialog.tsx | 80 +++++++ .../components/ProfileEditModalRouter.tsx | 52 +++++ .../components/ProfileEditorSkeleton.tsx | 31 +++ .../components/ProfileEditorToolbar.tsx | 37 ++++ .../components/ProfileField.tsx | 113 ++++++++++ .../components/RepeaterPrimitives.tsx | 86 ++++++++ .../components/SimpleListField.tsx | 75 +++++++ .../components/TeachingMethodListField.tsx | 59 +++++ .../components/TutorEvidenceEditorPreview.tsx | 45 ++++ .../components/TutorProfileEditorScreen.tsx | 77 +++++++ .../components/TutorProfileSidebarPreview.tsx | 21 ++ .../components/TutorVideoEditorPreview.tsx | 19 ++ .../modals/AcademicProfileEditDialog.tsx | 84 ++++++++ .../components/modals/BasicInfoEditDialog.tsx | 135 ++++++++++++ .../components/modals/EvidenceEditDialog.tsx | 203 ++++++++++++++++++ .../modals/ExperienceEditDialog.tsx | 95 ++++++++ .../modals/IntroductionEditDialog.tsx | 17 ++ .../modals/TeachingMethodsEditDialog.tsx | 17 ++ .../components/modals/VideoEditDialog.tsx | 108 ++++++++++ .../constants/profile-editor.fixture.ts | 44 ++++ .../constants/profile-editor.options.ts | 21 ++ .../hooks/useTutorProfileInlineEditor.ts | 68 ++++++ .../features/tutor-profile-editor/index.ts | 2 + .../schemas/profile-editor.schema.ts | 84 ++++++++ .../services/profile-editor.service.ts | 25 +++ .../types/profile-editor.types.ts | 12 ++ .../utils/file-preview.ts | 21 ++ .../utils/profile-editor.mapper.ts | 47 ++++ .../tutor-profile/components/TutorHero.tsx | 8 +- .../components/TutorOwnProfileScreen.tsx | 91 ++++++++ .../tutor-profile/types/mockTutorProfile.ts | 15 +- .../features/auth/components/AuthLayout.tsx | 16 -- packages/core/configs/navigation.ts | 8 +- packages/ui/components/layout/Header.tsx | 17 +- 41 files changed, 1941 insertions(+), 158 deletions(-) create mode 100644 apps/sale/app/tutor/profile/edit/loading.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/AvailabilityListField.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/EditableProfileBlock.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/ProfileBlockDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/ProfileEditModalRouter.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/ProfileEditorSkeleton.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/ProfileEditorToolbar.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/ProfileField.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/RepeaterPrimitives.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/SimpleListField.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/TeachingMethodListField.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/TutorEvidenceEditorPreview.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/TutorProfileEditorScreen.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/TutorProfileSidebarPreview.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/TutorVideoEditorPreview.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/AcademicProfileEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/BasicInfoEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/EvidenceEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/ExperienceEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/IntroductionEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/TeachingMethodsEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/components/modals/VideoEditDialog.tsx create mode 100644 apps/sale/features/tutor-profile-editor/constants/profile-editor.fixture.ts create mode 100644 apps/sale/features/tutor-profile-editor/constants/profile-editor.options.ts create mode 100644 apps/sale/features/tutor-profile-editor/hooks/useTutorProfileInlineEditor.ts create mode 100644 apps/sale/features/tutor-profile-editor/index.ts create mode 100644 apps/sale/features/tutor-profile-editor/schemas/profile-editor.schema.ts create mode 100644 apps/sale/features/tutor-profile-editor/services/profile-editor.service.ts create mode 100644 apps/sale/features/tutor-profile-editor/types/profile-editor.types.ts create mode 100644 apps/sale/features/tutor-profile-editor/utils/file-preview.ts create mode 100644 apps/sale/features/tutor-profile-editor/utils/profile-editor.mapper.ts create mode 100644 apps/sale/features/tutor-profile/components/TutorOwnProfileScreen.tsx diff --git a/apps/sale/app/tutor/profile/edit/loading.tsx b/apps/sale/app/tutor/profile/edit/loading.tsx new file mode 100644 index 0000000..b475b4b --- /dev/null +++ b/apps/sale/app/tutor/profile/edit/loading.tsx @@ -0,0 +1,5 @@ +import { ProfileEditorSkeleton } from "@/features/tutor-profile-editor"; + +export default function Loading() { + return ; +} diff --git a/apps/sale/features/messages/components/ChatSidebar.tsx b/apps/sale/features/messages/components/ChatSidebar.tsx index 640796e..1c3593d 100644 --- a/apps/sale/features/messages/components/ChatSidebar.tsx +++ b/apps/sale/features/messages/components/ChatSidebar.tsx @@ -126,7 +126,7 @@ export function ChatSidebar() { className="text-sm tracking-tight text-[#280f91]" style={{ fontFamily: "var(--font-nunito-family)", fontWeight: 800 }} > - CỘNG ĐỒNG GIA SƯ + CỘNG ĐỒNG GIA SƯ BEEWISE diff --git a/apps/sale/features/messages/components/MessagesScreen.tsx b/apps/sale/features/messages/components/MessagesScreen.tsx index 8db88fb..a494977 100644 --- a/apps/sale/features/messages/components/MessagesScreen.tsx +++ b/apps/sale/features/messages/components/MessagesScreen.tsx @@ -22,9 +22,12 @@ export function MessagesScreen() { - CỘNG ĐỒNG GIA SƯ + CỘNG ĐỒNG GIA SƯ BEEWISE

diff --git a/apps/sale/features/tutor-approved/components/TutorApprovedPreview.tsx b/apps/sale/features/tutor-approved/components/TutorApprovedPreview.tsx index c977977..13b34c3 100644 --- a/apps/sale/features/tutor-approved/components/TutorApprovedPreview.tsx +++ b/apps/sale/features/tutor-approved/components/TutorApprovedPreview.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/navigation"; import { TutorApprovedProvider } from "./TutorApprovedProvider"; import { TutorApprovedScreenView, TutorApprovedShell } from "./tutor-approved.ui"; -import { resolveTutorApprovedScenario, parseTutorApprovedScenario } from "../schemas/tutor-approved.resolver"; +import { parseTutorApprovedScenario } from "../schemas/tutor-approved.resolver"; import { tutorApprovedScenarios, type TutorApprovedScenario, type TutorApprovedScreen } from "../types"; const previewUser = { @@ -31,6 +31,7 @@ function scenarioScreen(scenario: TutorApprovedScenario): TutorApprovedScreen { export function TutorApprovedPreview({ scenario, capture }: { scenario?: string | null; capture: boolean }) { const parsed = parseTutorApprovedScenario(scenario); + const screen = scenarioScreen(parsed); const router = useRouter(); const navigate = (next: TutorApprovedScenario, nextCapture = capture) => { const params = new URLSearchParams({ scenario: next }); @@ -40,11 +41,12 @@ export function TutorApprovedPreview({ scenario, capture }: { scenario?: string return ( PREVIEW : null} > - + ); diff --git a/apps/sale/features/tutor-approved/components/tutor-approved.ui.tsx b/apps/sale/features/tutor-approved/components/tutor-approved.ui.tsx index 1cd578a..c34d618 100644 --- a/apps/sale/features/tutor-approved/components/tutor-approved.ui.tsx +++ b/apps/sale/features/tutor-approved/components/tutor-approved.ui.tsx @@ -26,6 +26,8 @@ import { TUTOR_LMS_URL } from "@workspace/core/constants/tutor-links"; import { useTutorApproved } from "./TutorApprovedProvider"; import type { TutorApprovedScreen } from "../types"; import { ChatSummary, MessagesScreen, ChatRoomScreen } from "../../messages"; +import { TutorProfileEditorScreen } from "../../tutor-profile-editor"; +import { TutorOwnProfileScreen } from "../../tutor-profile/components/TutorOwnProfileScreen"; const card = "rounded-2xl border border-[#dce7f7] bg-white p-5 shadow-[0_12px_32px_rgba(40,15,145,0.07)]"; @@ -46,6 +48,15 @@ export function TutorApprovedShell({ screen?: TutorApprovedScreen; }) { const isChat = screen === "messages" || screen === "chat-room"; + const isProfileEdit = screen === "profile-edit"; + + if (isProfileEdit) { + return ( +
+ {children} +
+ ); + } if (isChat) { return ( @@ -84,8 +95,8 @@ export function TutorApprovedScreenView({ screen?: TutorApprovedScreen; chatRoomId?: string; }) { - if (screen === "profile" || screen === "profile-edit") - return ; + if (screen === "profile-edit") return ; + if (screen === "profile") return ; if (screen === "messages") return ; if (screen === "chat-room") return ; if (screen === "notifications") return ; @@ -476,130 +487,6 @@ function RecentActivity() { ); } -function ProfileScreen({ edit }: { edit: boolean }) { - const { state, dispatch } = useTutorApproved(); - const p = edit ? state.draftProfile : state.profile; - const fields: - | [[keyof typeof p, string, boolean]] - | Array<[keyof typeof p, string, boolean]> = [ - ["title", "Tiêu đề hồ sơ", true], - ["introduction", "Giới thiệu ngắn", true], - ["description", "Mô tả", true], - ["teachingMethod", "Phương pháp giảng dạy", false], - ["experience", "Kinh nghiệm", false], - ["rate", "Học phí dự kiến", true], - ]; - return ( -
-
-

Hồ sơ gia sư

-

- {edit ? "Chỉnh sửa hồ sơ" : "Hồ sơ của tôi"} -

-

- Thông tin ngân hàng và giấy tờ xác thực không xuất hiện trong hồ sơ - công khai. -

-
- {state.profileSubmitted && ( -
- Thay đổi đã được gửi. Hồ sơ công khai hiện tại vẫn được giữ cho đến - khi Consultant phê duyệt nội dung mới. -
- )} -
-
-
- MA -
-
-

{p.fullName}

- - Đã xác thực - -
-
- {edit ? ( -
{ - e.preventDefault(); - dispatch({ type: "submit-profile" }); - }} - className="space-y-4" - > - {fields.map(([field, label, review]) => ( -