From cd06a71a9e3e59d5a86a3a4d29beefdf9f95726a Mon Sep 17 00:00:00 2001 From: Hafid Nur <73023445+hafidnrzs@users.noreply.github.com> Date: Thu, 27 Nov 2025 15:42:18 +0700 Subject: [PATCH] feat(hackathon): change "edit profile" to modal dialog - Add "edit profile" modal dialog that can be triggered from dashboard - Update background overlay for dark mode - Update dark mode for auth callback --- apps/hackathon/src/app/auth/callback/page.tsx | 6 +- apps/hackathon/src/app/dashboard/page.tsx | 453 ++++++++++-------- apps/hackathon/src/app/page.tsx | 8 +- apps/hackathon/src/app/profile/page.tsx | 438 ++++++++--------- .../hackathon/src/app/teams/[teamId]/page.tsx | 2 +- 5 files changed, 479 insertions(+), 428 deletions(-) diff --git a/apps/hackathon/src/app/auth/callback/page.tsx b/apps/hackathon/src/app/auth/callback/page.tsx index 0453894..1144c72 100644 --- a/apps/hackathon/src/app/auth/callback/page.tsx +++ b/apps/hackathon/src/app/auth/callback/page.tsx @@ -176,13 +176,13 @@ const CallbackPage: FC = (): ReactElement => { } return ( -
+
-

+

Completing login...

-

Please wait

+

Please wait

); diff --git a/apps/hackathon/src/app/dashboard/page.tsx b/apps/hackathon/src/app/dashboard/page.tsx index a3cf454..f12d389 100644 --- a/apps/hackathon/src/app/dashboard/page.tsx +++ b/apps/hackathon/src/app/dashboard/page.tsx @@ -1,4 +1,4 @@ -import { FC, ReactElement } from 'react'; +import { FC, ReactElement, useEffect, useState } from 'react'; import { Link } from 'react-router'; import { useMyTeams, @@ -9,16 +9,49 @@ import { import { toast } from 'sonner'; import { Button } from '@imphnen-frontend-service/ui/atoms'; import { Icon } from '@iconify/react'; +import ProfilePage from '../profile/page'; + +type Invitation = { + id: string; + team: { + id?: string; + name?: string; + logo?: string; + banner?: string; + description?: string; + city?: string; + visibility?: string; + leader_id?: string; + }; + inviter: { + id?: string; + fullname?: string; + email?: string; + avatar?: string; + }; +}; const DashboardPage: FC = (): ReactElement => { const { session } = useAuthStore(); + const [showProfileModal, setShowProfileModal] = useState(false); + // Lock background scroll when profile modal is open + useEffect(() => { + if (showProfileModal) { + const originalOverflow = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + return () => { + document.body.style.overflow = originalOverflow || ''; + }; + } + }, [showProfileModal]); const { data: teamsData } = useMyTeams(); const { data: invitationsData } = useMyInvitations(); const { mutateAsync: respondToInvitation } = useRespondToInvitation(); const user = session?.user; const myTeams = teamsData?.data || []; - const invitations = invitationsData?.data || []; + const invitations: Invitation[] = (invitationsData?.data || + []) as Invitation[]; const handleAcceptInvitation = async (invitationId: string) => { try { @@ -41,225 +74,233 @@ const DashboardPage: FC = (): ReactElement => { }; return ( -
-
-

- Welcome, {user?.fullname || user?.email?.split('@')[0] || 'User'}! -

- {user?.location && ( -

- - {user.location} -

- )} -
- - {invitations.length > 0 && ( -
-

- Team Invitations ({invitations.length}) -

-
- {invitations.map((invitation) => ( -
-
-

- {invitation.team.name} -

-

- Invited by {invitation.inviter.fullname} -

-
-
- - -
-
- ))} -
+ <> +
+
+

+ Welcome, {user?.fullname || user?.email?.split('@')[0] || 'User'}! +

+ {user?.location && ( +

+ + {user.location} +

+ )}
- )} - {myTeams.length > 0 ? ( -
-

- My Team -

-
- {myTeams.map((team) => ( - - {team.banner && ( -
- {team.name} + {invitations.length > 0 && ( +
+

+ Team Invitations ({invitations.length}) +

+
+ {invitations.map((invitation) => ( +
+
+

+ {invitation.team?.name ?? 'Unnamed Team'} +

+

+ Invited by{' '} + {invitation.inviter?.fullname ?? 'Unknown User'} +

+
+
+ + +
+
+ ))} +
+
+ )} + + {myTeams.length > 0 ? ( +
+

+ My Team +

+
+ {myTeams.map((team) => ( + + {team.banner && ( +
+ {team.name} +
+ )} +
+
+ {team.logo && ( + {team.name} + )} +
+

+ {team.name} +

+

+ + {team.city} +

+
+
+

+ {team.description} +

+
+ + ))} +
+
+ ) : ( +
+
+
👋
+

+ You are not in a team yet +

+

+ Use the sidebar to browse teams or create your own +

+
+
+ )} + +
+
+
+
+
+ {user?.avatar ? ( + {user.fullname + ) : ( +
+ + U +
)} -
-
- {team.logo && ( - {team.name} - )} -
-

- {team.name} -

-

- - {team.city} -

-
-
-

- {team.description} -

-
- - ))} -
-
- ) : ( -
-
-
👋
-

- You are not in a team yet -

-

- Use the sidebar to browse teams or create your own -

-
-
- )} +
+

+ {user?.fullname || + user?.email?.split('@')[0] || + 'Unnamed User'} +

-
-
-
-
-
- {user?.avatar ? ( - {user.fullname - ) : ( -
- - U - + {user?.location ? ( +

+ + {user.location} +

+ ) : ( + + Complete your profile + + + )} +
+
+ {user?.location && ( + + )} +
+
+ {user?.bio && ( +
+

+ About +

+

+ {user.bio} +

)} -
-

- {user?.fullname || - user?.email?.split('@')[0] || - 'Unnamed User'} -

- - {user?.location ? ( -

- - {user.location} -

- ) : ( - - Complete your profile - - - )} -
-
- {user?.location && ( - - Edit Profile - - )} -
-
- {user?.bio && ( -
-

- About -

-

- {user.bio} -

-
- )} -
-

- Contact -

-
- - {user?.email} - -
-
- {user?.skills && user.skills.length > 0 && (

- Skills + Contact

-
- {user.skills.map((skill: string) => ( - - {skill} - - ))} +
+ + {user?.email} +
- )} + {user?.skills && user.skills.length > 0 && ( +
+

+ Skills +

+
+ {user.skills.map((skill: string) => ( + + {skill} + + ))} +
+
+ )} +
-
+ setShowProfileModal(false)} + /> + ); }; diff --git a/apps/hackathon/src/app/page.tsx b/apps/hackathon/src/app/page.tsx index ca496fe..69b4ac5 100644 --- a/apps/hackathon/src/app/page.tsx +++ b/apps/hackathon/src/app/page.tsx @@ -187,12 +187,12 @@ export default function HomePage() { ) : ( <> - navigate('/auth/login')} + className="ms-3 text-gray-600 dark:text-gray-200 hover:text-gray-900 dark:hover:text-white cursor-pointer" > Masuk - +
-

- Click the camera icon to change your photo -
- Format: JPG, PNG. Max 5MB +

+ Update your photo and name

- {/* Full Name */} - - - {/* City */} -
- - ( - - )} - /> -
- - {/* Role/Skills */} -
- - ( -
-
- {ROLE_OPTIONS.map((role) => ( - - ))} -
-
- )} - /> -
- - {/* Bio */} -
- - ( -
-