import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Badge } from "@workspace/ui/components/badge"; import { Button } from "@workspace/ui/components/button"; import { ScrollArea } from "@workspace/ui/components/scroll-area"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, } from "@workspace/ui/components/sheet"; import { ConfirmButton } from "@workspace/ui/composed/confirm-button"; import { EnhancedInput } from "@workspace/ui/composed/enhanced-input"; import { dissolveFamily, getFamilyDetail, removeFamilyMember, updateFamilyMaxMembers, } from "@workspace/ui/services/admin/user"; import type { ReactNode } from "react"; import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { formatDate } from "@/utils/common"; import { getFamilyJoinSourceLabel, getFamilyMemberStatusLabel, getFamilyRoleLabel, getFamilyStatusLabel, isFamilyMemberStatusActive, isFamilyRoleOwner, isFamilyStatusActive, } from "./enums"; interface FamilyDetailSheetProps { familyId?: number; trigger: ReactNode; onChanged?: () => void; } export function FamilyDetailSheet({ familyId, trigger, onChanged, }: Readonly) { const { t } = useTranslation("user"); const [open, setOpen] = useState(false); const [maxMembersInput, setMaxMembersInput] = useState(""); const queryClient = useQueryClient(); const validFamilyId = Number(familyId || 0); const { data, isLoading, refetch } = useQuery({ enabled: open && validFamilyId > 0, queryKey: ["familyDetail", validFamilyId], queryFn: async () => { const { data } = await getFamilyDetail({ id: validFamilyId }); return data.data; }, }); useEffect(() => { if (!(open && data?.summary)) return; setMaxMembersInput(String(data.summary.max_members)); }, [data?.summary, open]); const invalidateAll = async () => { await Promise.all([ queryClient.invalidateQueries({ queryKey: ["familyList"] }), queryClient.invalidateQueries({ queryKey: ["familyDetail", validFamilyId], }), queryClient.invalidateQueries({ queryKey: ["getUserList"] }), ]); onChanged?.(); }; const updateMaxMutation = useMutation({ mutationFn: async (maxMembers: number) => updateFamilyMaxMembers({ family_id: validFamilyId, max_members: maxMembers, }), onSuccess: async () => { toast.success(t("updateSuccess", "Updated successfully")); await invalidateAll(); await refetch(); }, }); const removeMemberMutation = useMutation({ mutationFn: async (userId: number) => removeFamilyMember({ family_id: validFamilyId, user_id: userId }), onSuccess: async () => { toast.success(t("removeSuccess", "Removed successfully")); await invalidateAll(); await refetch(); }, }); const dissolveMutation = useMutation({ mutationFn: async () => dissolveFamily({ family_id: validFamilyId }), onSuccess: async () => { toast.success(t("familyDissolved", "Family dissolved")); await invalidateAll(); await refetch(); }, }); const canDissolve = isFamilyStatusActive(data?.summary.status); const summaryItems = useMemo(() => { if (!data?.summary) return []; return [ { label: t("familyId", "Family ID"), value: data.summary.family_id }, { label: t("owner", "Owner"), value: data.summary.owner_identifier }, { label: t("userId", "User ID"), value: data.summary.owner_user_id }, { label: t("familyStatus", "Family Status"), value: getFamilyStatusLabel(t, data.summary.status), }, { label: t("memberCount", "Member Count"), value: `${data.summary.active_member_count}/${data.summary.max_members}`, }, { label: t("createdAt", "Created At"), value: formatDate(data.summary.created_at), }, { label: t("updatedAt", "Updated At"), value: formatDate(data.summary.updated_at), }, ]; }, [data?.summary, t]); return ( {trigger} {t("familyDetail", "Family Detail")} {validFamilyId ? ` · ID: ${validFamilyId}` : ""} {isLoading ? (
{t("loading", "Loading...")}
) : data ? (

{t("familySummary", "Family Summary")}

{summaryItems.map((item) => (
{item.label} {item.value}
))}

{t("familyActions", "Family Actions")}

{ setMaxMembersInput(value); }} type="number" value={maxMembersInput} />
{ await dissolveMutation.mutateAsync(); }} title={t( "familyConfirmDissolve", "Confirm Dissolve Family" )} trigger={ } />

{t("familyMembers", "Family Members")}

{data.members?.length ? ( data.members.map((member) => { const canRemove = isFamilyStatusActive(data.summary.status) && !isFamilyRoleOwner(member.role_name) && isFamilyMemberStatusActive(member.status_name); return (
ID: {member.user_id} {member.auth_type ? ( {member.auth_type} ) : null} {member.device_no ? ( {member.device_no} ) : null} {member.device_type ? ( {member.device_type} ) : null} {member.auth_type === "device" ? member.device_no || member.identifier : member.identifier} {getFamilyRoleLabel(t, member.role_name)} {getFamilyMemberStatusLabel( t, member.status_name )}
{t("familyJoinSource", "Join Source")}:{" "} {getFamilyJoinSourceLabel(t, member.join_source)}{" "} · {t("familyJoinedAt", "Joined At")}:{" "} {member.joined_at ? formatDate(member.joined_at) : "--"}{" "} · {t("familyLeftAt", "Left At")}:{" "} {member.left_at ? formatDate(member.left_at) : "--"}
{canRemove ? ( { await removeMemberMutation.mutateAsync( member.user_id ); }} title={t( "familyConfirmRemoveMember", "Confirm Remove Member" )} trigger={ } /> ) : null}
); }) ) : (
{t("familyNoMembers", "No members")}
)}
) : (
{t("familyNoData", "No family data")}
)}
); }