diff --git a/app/(dashboard)/dashboard/page.tsx b/app/(dashboard)/dashboard/page.tsx index 60475a8587..83dfb217a1 100644 --- a/app/(dashboard)/dashboard/page.tsx +++ b/app/(dashboard)/dashboard/page.tsx @@ -10,8 +10,8 @@ import { CardFooter } from '@/components/ui/card'; import { customerPortalAction } from '@/lib/payments/actions'; -import { useActionState } from 'react'; -import { TeamDataWithMembers, User } from '@/lib/db/schema'; +import { useActionState, useState } from 'react'; +import { TeamDataWithMembers, TeamMemberWithUser, User } from '@/lib/db/schema'; import { removeTeamMember, inviteTeamMember } from '@/app/(login)/actions'; import useSWR from 'swr'; import { Suspense } from 'react'; @@ -95,14 +95,6 @@ function TeamMembersSkeleton() { function TeamMembers() { const { data: teamData } = useSWR('/api/team', fetcher); - const [removeState, removeAction, isRemovePending] = useActionState< - ActionState, - FormData - >(removeTeamMember, {}); - - const getUserDisplayName = (user: Pick) => { - return user.name || user.email || 'Unknown User'; - }; if (!teamData?.teamMembers?.length) { return ( @@ -125,58 +117,90 @@ function TeamMembers() {
    {teamData.teamMembers.map((member, index) => ( -
  • -
    - - {/* - This app doesn't save profile images, but here - is how you'd show them: - - - */} - - {getUserDisplayName(member.user) - .split(' ') - .map((n) => n[0]) - .join('')} - - -
    -

    - {getUserDisplayName(member.user)} -

    -

    - {member.role} -

    -
    -
    - {index > 1 ? ( -
    - - -
    - ) : null} -
  • + ))}
- {removeState?.error && ( -

{removeState.error}

- )}
); } +function TeamMemberRow({ + member, + index, +}: { + member: TeamMemberWithUser; + index: number; +}) { + const [visible, setVisible] = useState(true); + const [removeState, removeAction, isRemovePending] = useActionState< + ActionState, + FormData + >(async (actionState,formData) => { + const result = await removeTeamMember(actionState,formData); + if ('success' in result && typeof result.success !== 'undefined') { + setVisible(false); + } + return result; + }, {}); + + const getUserDisplayName = (user: Pick) => { + return user.name || user.email || "Unknown User"; + }; + + if (!visible) return null; + + return ( +
  • +
    + + {/* + This app doesn't save profile images, but here + is how you'd show them: + + + */} + + {getUserDisplayName(member.user) + .split(' ') + .map((n) => n[0]) + .join('')} + + +
    +

    + {getUserDisplayName(member.user)} +

    +

    + {member.role} +

    +
    +
    + {index > 0 && ( +
    +
    + + +
    + {removeState?.error && ( +

    {removeState.error}

    + )} +
    + )} +
  • + ); +} + function InviteTeamMemberSkeleton() { return ( diff --git a/app/(login)/actions.ts b/app/(login)/actions.ts index 532adc0ef4..1791a6a2e5 100644 --- a/app/(login)/actions.ts +++ b/app/(login)/actions.ts @@ -359,7 +359,7 @@ export const updateAccount = validatedActionWithUser( ); const removeTeamMemberSchema = z.object({ - memberId: z.number() + memberId: z.string().transform((val) => Number(val)), }); export const removeTeamMember = validatedActionWithUser( diff --git a/lib/db/schema.ts b/lib/db/schema.ts index 1d047ce661..25162b91af 100644 --- a/lib/db/schema.ts +++ b/lib/db/schema.ts @@ -122,10 +122,11 @@ export type ActivityLog = typeof activityLogs.$inferSelect; export type NewActivityLog = typeof activityLogs.$inferInsert; export type Invitation = typeof invitations.$inferSelect; export type NewInvitation = typeof invitations.$inferInsert; +export type TeamMemberWithUser = TeamMember & { + user: Pick; +}; export type TeamDataWithMembers = Team & { - teamMembers: (TeamMember & { - user: Pick; - })[]; + teamMembers: TeamMemberWithUser[]; }; export enum ActivityType {