'use client'; import { useState, useEffect } from 'react'; import { Box, Paper, Typography, Button, Chip, IconButton, Tooltip, TextField, Dialog, DialogTitle, DialogContent, DialogActions, Alert, CircularProgress, Accordion, AccordionSummary, AccordionDetails, Stack, } from '@mui/material'; import { ContentCopy, Refresh, Delete, Email, ExpandMore, Info, } from '@mui/icons-material'; import { familiesApi } from '@/lib/api/families'; interface RoleInvitesSectionProps { familyId: string; onSuccess?: (message: string) => void; onError?: (message: string) => void; } interface RoleCode { code: string; expiresAt: Date; } interface RoleCodes { parent?: RoleCode; caregiver?: RoleCode; viewer?: RoleCode; } const roleInfo = { parent: { icon: '👨‍👩‍👧', label: 'Parent', description: 'Full access - manage children, log activities, view reports, and invite others', color: 'primary' as const, }, caregiver: { icon: '🤝', label: 'Caregiver', description: 'Can edit children, log activities, and view reports (cannot add children or invite others)', color: 'secondary' as const, }, viewer: { icon: '👁️', label: 'Viewer', description: 'View-only access - can view reports but cannot log activities', color: 'info' as const, }, }; export function RoleInvitesSection({ familyId, onSuccess, onError }: RoleInvitesSectionProps) { const [roleCodes, setRoleCodes] = useState({}); const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState(null); const [emailDialogOpen, setEmailDialogOpen] = useState(false); const [selectedRole, setSelectedRole] = useState<'parent' | 'caregiver' | 'viewer' | null>(null); const [recipientEmail, setRecipientEmail] = useState(''); const [emailSending, setEmailSending] = useState(false); useEffect(() => { fetchRoleCodes(); }, [familyId]); const fetchRoleCodes = async () => { try { setLoading(true); const codes = await familiesApi.getRoleInviteCodes(familyId); setRoleCodes(codes); } catch (err: any) { console.error('Failed to fetch role codes:', err); onError?.('Failed to load invite codes'); } finally { setLoading(false); } }; const handleGenerateCode = async (role: 'parent' | 'caregiver' | 'viewer') => { try { setActionLoading(role); const result = await familiesApi.generateRoleInviteCode(familyId, role, 7); setRoleCodes(prev => ({ ...prev, [role]: { code: result.code, expiresAt: result.expiresAt }, })); onSuccess?.(`${roleInfo[role].label} invite code generated`); } catch (err: any) { console.error('Failed to generate code:', err); onError?.('Failed to generate invite code'); } finally { setActionLoading(null); } }; const handleCopyCode = async (code: string, role: string) => { try { await navigator.clipboard.writeText(code); onSuccess?.(`${roleInfo[role as keyof typeof roleInfo].label} code copied to clipboard`); } catch (err) { onError?.('Failed to copy code'); } }; const handleRevokeCode = async (role: 'parent' | 'caregiver' | 'viewer') => { try { setActionLoading(role); await familiesApi.revokeRoleInviteCode(familyId, role); setRoleCodes(prev => { const updated = { ...prev }; delete updated[role]; return updated; }); onSuccess?.(`${roleInfo[role].label} invite code revoked`); } catch (err: any) { console.error('Failed to revoke code:', err); onError?.('Failed to revoke invite code'); } finally { setActionLoading(null); } }; const handleOpenEmailDialog = (role: 'parent' | 'caregiver' | 'viewer') => { setSelectedRole(role); setRecipientEmail(''); setEmailDialogOpen(true); }; const handleSendEmailInvite = async () => { if (!selectedRole || !recipientEmail) return; try { setEmailSending(true); const result = await familiesApi.sendEmailInvite(familyId, recipientEmail, selectedRole); // Update the codes setRoleCodes(prev => ({ ...prev, [selectedRole]: { code: result.code, expiresAt: result.expiresAt }, })); if (result.emailSent) { onSuccess?.(`Invite email sent to ${recipientEmail}`); } else { onSuccess?.('Invite code generated, but email could not be sent'); } setEmailDialogOpen(false); setRecipientEmail(''); setSelectedRole(null); } catch (err: any) { console.error('Failed to send email invite:', err); onError?.(err.response?.data?.message || 'Failed to send email invite'); } finally { setEmailSending(false); } }; const formatExpiryDate = (expiresAt: Date) => { const date = new Date(expiresAt); const now = new Date(); const diffMs = date.getTime() - now.getTime(); const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24)); if (diffDays < 0) return 'Expired'; if (diffDays === 0) return 'Expires today'; if (diffDays === 1) return 'Expires tomorrow'; return `Expires in ${diffDays} days`; }; const renderRoleCodeCard = (role: 'parent' | 'caregiver' | 'viewer') => { const info = roleInfo[role]; const codeData = roleCodes[role]; const isLoading = actionLoading === role; return ( } sx={{ borderRadius: 2, '&.Mui-expanded': { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }, }} > {info.icon} {info.label} {codeData ? formatExpiryDate(codeData.expiresAt) : 'No active code'} {codeData && ( )} {info.description} {codeData ? ( handleRevokeCode(role)} disabled={isLoading} > ) : ( )} ); }; if (loading) { return ( ); } return ( <> Role-Based Invites Create role-specific invite codes that automatically assign permissions when used. {renderRoleCodeCard('parent')} {renderRoleCodeCard('caregiver')} {renderRoleCodeCard('viewer')} {/* Email Invite Dialog */} setEmailDialogOpen(false)} maxWidth="sm" fullWidth > Send {selectedRole && roleInfo[selectedRole].icon} {selectedRole && roleInfo[selectedRole].label} Invite via Email Send an invitation email with the {selectedRole} invite code setRecipientEmail(e.target.value)} placeholder="name@example.com" autoFocus sx={{ mt: 1 }} /> ); }