'use client'; import { useState, useEffect } from 'react'; import { Box, Typography, Grid, Paper, Button, Avatar, Chip, CircularProgress, Alert, IconButton, Divider, Snackbar, Container, List, ListItem, ListItemAvatar, ListItemText, Card, CardContent, } from '@mui/material'; import { PersonAdd, ContentCopy, People, Delete, GroupAdd } from '@mui/icons-material'; import { useAuth } from '@/lib/auth/AuthContext'; import { AppShell } from '@/components/layouts/AppShell/AppShell'; import { ProtectedRoute } from '@/components/common/ProtectedRoute'; import { familiesApi, Family, FamilyMember, InviteMemberData, JoinFamilyData } from '@/lib/api/families'; import { InviteMemberDialog } from '@/components/family/InviteMemberDialog'; import { JoinFamilyDialog } from '@/components/family/JoinFamilyDialog'; import { RemoveMemberDialog } from '@/components/family/RemoveMemberDialog'; import { motion } from 'framer-motion'; import { useTranslation } from '@/hooks/useTranslation'; export default function FamilyPage() { const { t } = useTranslation('family'); const { user, refreshUser } = useAuth(); const [family, setFamily] = useState(null); const [members, setMembers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [inviteDialogOpen, setInviteDialogOpen] = useState(false); const [joinDialogOpen, setJoinDialogOpen] = useState(false); const [removeDialogOpen, setRemoveDialogOpen] = useState(false); const [memberToRemove, setMemberToRemove] = useState(null); const [actionLoading, setActionLoading] = useState(false); const [snackbar, setSnackbar] = useState({ open: false, message: '' }); // Get familyId from user const familyId = user?.families?.[0]?.familyId; useEffect(() => { if (familyId) { fetchFamilyData(); } else { setLoading(false); setError(t('messages.noFamilyFound')); } }, [familyId]); const fetchFamilyData = async () => { if (!familyId) return; try { setLoading(true); setError(''); const [familyData, membersData] = await Promise.all([ familiesApi.getFamily(familyId), familiesApi.getFamilyMembers(familyId), ]); setFamily(familyData); setMembers(membersData); } catch (err: any) { console.error('Failed to fetch family data:', err); setError(err.response?.data?.message || t('messages.failedToLoad')); } finally { setLoading(false); } }; const handleCopyCode = async () => { if (!family?.shareCode) return; try { await navigator.clipboard.writeText(family.shareCode); setSnackbar({ open: true, message: t('messages.shareCodeCopied') }); } catch (err) { setSnackbar({ open: true, message: t('messages.shareCodeCopyFailed') }); } }; const handleInviteMember = async (data: InviteMemberData) => { if (!familyId) { throw new Error(t('messages.noFamilyId')); } try { setActionLoading(true); await familiesApi.inviteMember(familyId, data); setSnackbar({ open: true, message: t('messages.invitationSent') }); await fetchFamilyData(); setInviteDialogOpen(false); } catch (err: any) { console.error('Failed to invite member:', err); throw new Error(err.response?.data?.message || t('messages.failedToInvite')); } finally { setActionLoading(false); } }; const handleJoinFamily = async (data: JoinFamilyData) => { try { setActionLoading(true); await familiesApi.joinFamily(data); setSnackbar({ open: true, message: t('messages.joinedFamily') }); await refreshUser(); await fetchFamilyData(); setJoinDialogOpen(false); } catch (err: any) { console.error('Failed to join family:', err); throw new Error(err.response?.data?.message || t('messages.failedToJoin')); } finally { setActionLoading(false); } }; const handleRemoveClick = (member: FamilyMember) => { setMemberToRemove(member); setRemoveDialogOpen(true); }; const handleRemoveConfirm = async () => { if (!familyId || !memberToRemove) return; try { setActionLoading(true); await familiesApi.removeMember(familyId, memberToRemove.userId); setSnackbar({ open: true, message: t('messages.memberRemoved') }); await fetchFamilyData(); setRemoveDialogOpen(false); setMemberToRemove(null); } catch (err: any) { console.error('Failed to remove member:', err); setError(err.response?.data?.message || t('messages.failedToRemove')); } finally { setActionLoading(false); } }; const getRoleColor = (role: string): 'primary' | 'secondary' | 'default' | 'success' | 'warning' | 'info' => { switch (role) { case 'parent': return 'primary'; case 'caregiver': return 'secondary'; case 'viewer': return 'info'; default: return 'default'; } }; const isCurrentUser = (userId: string) => { return user?.id === userId; }; return ( {t('pageTitle')} {t('pageSubtitle')} {error && ( setError('')}> {error} )} {loading ? ( ) : ( {/* Family Share Code */} {family && ( {t('shareCode.title')} {t('shareCode.description')} )} {/* Family Members */} {t('members.title', { count: members.length })} {members.length === 0 ? ( {t('members.noMembers')} {t('members.noMembersDescription')} ) : ( {members.map((member, index) => { const memberName = member.user?.name || t('placeholders.unknownUser'); return ( {memberName[0]} {memberName} {isCurrentUser(member.userId) && ( )} } secondary={member.user?.email || t('placeholders.noEmail')} primaryTypographyProps={{ fontWeight: 500 }} /> {!isCurrentUser(member.userId) && ( handleRemoveClick(member)} color="error" aria-label={t('members.removeAriaLabel', { name: memberName })} > )} ); })} )} )} setInviteDialogOpen(false)} onSubmit={handleInviteMember} isLoading={actionLoading} /> setJoinDialogOpen(false)} onSubmit={handleJoinFamily} isLoading={actionLoading} /> setRemoveDialogOpen(false)} onConfirm={handleRemoveConfirm} memberName={memberToRemove?.user?.name || ''} isLoading={actionLoading} /> setSnackbar({ ...snackbar, open: false })} message={snackbar.message} /> ); }