| 1 | "use client"; |
| 2 | |
| 3 | import type { OrganizationAuthClient } from "@better-auth-ui/core/plugins/organization"; |
| 4 | import { useAuth, useAuthPlugin, useSession } from "@better-auth-ui/react"; |
| 5 | import { useListUserInvitations } from "@better-auth-ui/react/plugins/organization"; |
| 6 | import { Fragment } from "react"; |
| 7 | |
| 8 | import { Card, CardContent } from "@/components/ui/card"; |
| 9 | import { ItemGroup, ItemSeparator } from "@/components/ui/item"; |
| 10 | import { organizationPlugin } from "@/lib/auth/organization-plugin"; |
| 11 | import { UserInvitationRow } from "./user-invitation-row"; |
| 12 | import { UserInvitationRowSkeleton } from "./user-invitation-row-skeleton"; |
| 13 | import { UserInvitationsEmpty } from "./user-invitations-empty"; |
| 14 | |
| 15 | export type UserInvitationsProps = { |
| 16 | className?: string; |
| 17 | }; |
| 18 | |
| 19 | /** Organization invitations for the signed-in user. Always renders the section card; uses `UserInvitationsEmpty` when there are no pending invitations. */ |
| 20 | export function UserInvitations({ className }: UserInvitationsProps) { |
| 21 | const { authClient } = useAuth<OrganizationAuthClient>(); |
| 22 | const { localization: organizationLocalization } = |
| 23 | useAuthPlugin(organizationPlugin); |
| 24 | const session = useSession(authClient); |
| 25 | const emailVerified = session.data?.user.emailVerified === true; |
| 26 | |
| 27 | const { data: invitations, isPending } = useListUserInvitations(authClient, { |
| 28 | enabled: emailVerified, |
| 29 | }); |
| 30 | |
| 31 | return ( |
| 32 | <div className={className}> |
| 33 | <div className="flex flex-col gap-3"> |
| 34 | <h2 className="truncate text-sm font-semibold"> |
| 35 | {organizationLocalization.invitations} |
| 36 | </h2> |
| 37 | |
| 38 | <Card className="p-0"> |
| 39 | <CardContent className="p-0"> |
| 40 | {session.isPending || (emailVerified && isPending) ? ( |
| 41 | <ItemGroup> |
| 42 | <UserInvitationRowSkeleton /> |
| 43 | </ItemGroup> |
| 44 | ) : !invitations?.length ? ( |
| 45 | <UserInvitationsEmpty verificationRequired={!emailVerified} /> |
| 46 | ) : ( |
| 47 | <ItemGroup className="gap-0"> |
| 48 | {invitations.map((invitation, index) => ( |
| 49 | <Fragment key={invitation.id}> |
| 50 | {index > 0 && <ItemSeparator />} |
| 51 | <UserInvitationRow invitation={invitation} /> |
| 52 | </Fragment> |
| 53 | ))} |
| 54 | </ItemGroup> |
| 55 | )} |
| 56 | </CardContent> |
| 57 | </Card> |
| 58 | </div> |
| 59 | </div> |
| 60 | ); |
| 61 | } |