From 1ee04ada1447f370dd18c349b8f01feb771888d9 Mon Sep 17 00:00:00 2001 From: Maulana Sodiqin Date: Fri, 28 Nov 2025 19:30:43 +0700 Subject: [PATCH] feat: add destroy team feature --- .../hackathon/src/app/teams/[teamId]/page.tsx | 92 +++++++++++++++++++ libs/service/src/hooks/teams/index.ts | 21 +++++ 2 files changed, 113 insertions(+) diff --git a/apps/hackathon/src/app/teams/[teamId]/page.tsx b/apps/hackathon/src/app/teams/[teamId]/page.tsx index dec3e46..572f495 100644 --- a/apps/hackathon/src/app/teams/[teamId]/page.tsx +++ b/apps/hackathon/src/app/teams/[teamId]/page.tsx @@ -8,6 +8,7 @@ import { useTeamJoinRequests, useRespondToJoinRequest, useLeaveTeam, + useDeleteTeam, ETeamMemberRole, useAuthStore, } from '@imphnen-frontend-service/service'; @@ -54,6 +55,8 @@ const TeamDashboardPage: FC = (): ReactElement => { const [showInviteModal, setShowInviteModal] = useState(false); const [showJoinRequestsModal, setShowJoinRequestsModal] = useState(false); const [showLeaveModal, setShowLeaveModal] = useState(false); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [deleteConfirmText, setDeleteConfirmText] = useState(''); const [inviteEmail, setInviteEmail] = useState(''); const [imagesLoaded, setImagesLoaded] = useState(false); const [imageLoadCount, setImageLoadCount] = useState(0); @@ -104,6 +107,7 @@ const TeamDashboardPage: FC = (): ReactElement => { const { mutateAsync: respondToJoinRequest, isPending: isResponding } = useRespondToJoinRequest(teamId || ''); const { mutateAsync: leaveTeam, isPending: isLeaving } = useLeaveTeam(); + const { mutateAsync: deleteTeam, isPending: isDeleting } = useDeleteTeam(); const joinRequests = joinRequestsData?.data || []; const pendingJoinRequests = joinRequests.filter( @@ -157,6 +161,19 @@ const TeamDashboardPage: FC = (): ReactElement => { } }; + const handleDeleteTeam = async () => { + if (!teamId) return; + + try { + await deleteTeam(teamId); + toast.success('Team deleted successfully'); + navigate('/dashboard'); + } catch (error: any) { + console.error('Failed to delete team:', error); + toast.error(error?.message || 'Failed to delete team'); + } + }; + if (isLoadingTeam || isLoadingMembers) { return (
@@ -408,6 +425,21 @@ const TeamDashboardPage: FC = (): ReactElement => { Maximum team size reached ({MAX_TEAM_MEMBERS} members)

)} + {/* Danger Zone - Only show when leader is alone */} + {members.length === 1 && ( +
+

+ Danger Zone +

+ +
+ )}
)} @@ -767,6 +799,66 @@ const TeamDashboardPage: FC = (): ReactElement => { )} + + {/* Delete Team Confirmation Modal */} + {showDeleteModal && ( +
+
+
+
+ +
+

+ Delete Team? +

+

+ This action is permanent and cannot be undone. +

+
+
+

+ Warning: All team data, chat messages, and submissions will be permanently deleted. +

+
+
+ + setDeleteConfirmText(e.target.value)} + placeholder="Type team name here" + className="w-full px-4 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder:text-gray-400 dark:placeholder:text-gray-500" + autoComplete="off" + /> +
+
+ + +
+
+
+ )} ); }; diff --git a/libs/service/src/hooks/teams/index.ts b/libs/service/src/hooks/teams/index.ts index e593542..8c617aa 100644 --- a/libs/service/src/hooks/teams/index.ts +++ b/libs/service/src/hooks/teams/index.ts @@ -504,6 +504,27 @@ export const useLeaveTeam = () => { }); }; +// Delete Team Hook (Leader only) +export const useDeleteTeam = () => { + const queryClient = useQueryClient(); + const { session } = useAuthStore(); + + return useMutation({ + mutationFn: async (teamId: string) => { + if (!session?.user?.id) { + throw new Error('You must be logged in to delete a team'); + } + + await hackathonApi.delete(`/teams/${teamId}`); + return { success: true }; + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: teamKeys.myTeams() }); + queryClient.invalidateQueries({ queryKey: teamKeys.lists() }); + }, + }); +}; + // Get Teams by User ID - uses /users/{user_id}/teams export const useTeamsByUserId = (userId: string) => { return useQuery({