import React, { useEffect, useState, useMemo } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { CondoService } from '../services/mockDb'; import { Family, Condo, Notice, AppSettings, Ticket, TicketStatus } from '../types'; import { Search, ChevronRight, UserCircle, Building, Bell, AlertTriangle, Hammer, Calendar, Info, Link as LinkIcon, Check, Wallet, Briefcase, MessageSquareWarning, ArrowRight, AlertCircle, CheckCircle2 } from 'lucide-react'; export const FamilyList: React.FC = () => { const navigate = useNavigate(); const [families, setFamilies] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [activeCondo, setActiveCondo] = useState(undefined); const [notices, setNotices] = useState([]); const [userReadIds, setUserReadIds] = useState([]); const [settings, setSettings] = useState(null); // User Dashboard Data const [myTickets, setMyTickets] = useState([]); const [myExtraExpenses, setMyExtraExpenses] = useState([]); const [myFamily, setMyFamily] = useState(null); // Payment Status State const [regularPaymentStatus, setRegularPaymentStatus] = useState<'OK' | 'PENDING' | 'OVERDUE'>('OK'); const [regularDebtAmount, setRegularDebtAmount] = useState(0); const currentUser = CondoService.getCurrentUser(); const isPrivileged = currentUser?.role === 'admin' || currentUser?.role === 'poweruser'; useEffect(() => { const fetchData = async () => { try { CondoService.seedPayments(); const [fams, condo, allNotices, appSettings] = await Promise.all([ CondoService.getFamilies(), CondoService.getActiveCondo(), CondoService.getNotices(), CondoService.getSettings() ]); setFamilies(fams); setActiveCondo(condo); setSettings(appSettings); // --- USER SPECIFIC DASHBOARD DATA --- if (currentUser && !isPrivileged && currentUser.familyId && condo) { // 1. Find My Family const me = fams.find(f => f.id === currentUser.familyId) || null; setMyFamily(me); // 2. Fetch Tickets const tickets = await CondoService.getTickets(); // Backend filters for user setMyTickets(tickets); // 3. Fetch Extra Expenses if (appSettings.features.extraordinaryExpenses) { const extra = await CondoService.getMyExpenses(); setMyExtraExpenses(extra); } // 4. Calculate Regular Payment Status (Logic Update) const payments = await CondoService.getPaymentsByFamily(currentUser.familyId); const currentYear = appSettings.currentYear; const now = new Date(); const currentRealYear = now.getFullYear(); const currentRealMonth = now.getMonth() + 1; // 1-12 const currentDay = now.getDate(); const dueDay = condo.dueDay || 10; const quota = me?.customMonthlyQuota ?? condo.defaultMonthlyQuota; let totalDebt = 0; let status: 'OK' | 'PENDING' | 'OVERDUE' = 'OK'; // Check previous months first (Always Overdue if unpaid) for (let m = 1; m < currentRealMonth; m++) { // Simplified: assuming user only cares about current active year for dashboard alert // In a real app, check past years too. const isPaid = payments.some(p => p.forMonth === m && p.forYear === currentYear); if (!isPaid) { totalDebt += quota; status = 'OVERDUE'; } } // Check current month const isCurrentMonthPaid = payments.some(p => p.forMonth === currentRealMonth && p.forYear === currentYear); if (!isCurrentMonthPaid) { // If today > dueDay -> Overdue if (currentDay > dueDay) { totalDebt += quota; status = 'OVERDUE'; } // If today is within 10 days before dueDay -> Pending else if (currentDay >= (dueDay - 10)) { totalDebt += quota; // It's due soon, so we count it if (status !== 'OVERDUE') status = 'PENDING'; } } setRegularDebtAmount(totalDebt); setRegularPaymentStatus(status); } // --- NOTICE LOGIC --- // Ensure notices are loaded even if user has no family yet (but belongs to condo) if (condo && currentUser && appSettings.features.notices) { const condoNotices = allNotices.filter(n => { if (n.condoId !== condo.id || !n.active) return false; // Admin sees all active if (isPrivileged) return true; // Public notices (targetFamilyIds is null/empty) if (!n.targetFamilyIds || n.targetFamilyIds.length === 0) return true; // Targeted notices return currentUser.familyId && n.targetFamilyIds.includes(currentUser.familyId); }); setNotices(condoNotices); // Check read status const readStatuses = await Promise.all(condoNotices.map(n => CondoService.getNoticeReadStatus(n.id))); const readIds: string[] = []; readStatuses.forEach((reads, idx) => { if (reads.find(r => r.userId === currentUser.id)) { readIds.push(condoNotices[idx].id); } }); setUserReadIds(readIds); } } catch (e) { console.error("Error fetching data", e); } finally { setLoading(false); } }; fetchData(); }, [currentUser?.id, isPrivileged]); const filteredFamilies = families.filter(f => f.name.toLowerCase().includes(searchTerm.toLowerCase()) || f.unitNumber.toLowerCase().includes(searchTerm.toLowerCase()) ); const NoticeIcon = ({type}: {type: string}) => { switch(type) { case 'warning': return ; case 'maintenance': return ; case 'event': return ; default: return ; } }; const activeTicketsCount = myTickets.filter(t => t.status !== TicketStatus.RESOLVED && t.status !== TicketStatus.CLOSED).length; const extraDebt = myExtraExpenses.reduce((acc, exp) => acc + Math.max(0, exp.myShare.amountDue - exp.myShare.amountPaid), 0); if (loading) { return
Caricamento in corso...
; } if (!activeCondo) { return (

Nessun Condominio Selezionato

Seleziona o crea un condominio dalle impostazioni.

); } return (
{/* 1. NOTICES (Bacheca) - ALWAYS VISIBLE IF ENABLED */} {settings?.features.notices && notices.length > 0 && (

Bacheca Avvisi

{notices.map(notice => { const isRead = userReadIds.includes(notice.id); return (

{notice.title}

{isRead && Letto} {!isRead && Nuovo}

{new Date(notice.date).toLocaleDateString()}

{notice.content}

{notice.link && ( Apri Link )}
); })}
)} {/* 2. USER DASHBOARD (Widgets) - Only for Regular Users with a linked Family */} {!isPrivileged && myFamily && (

La Tua Situazione

{/* Regular Payments Widget */}
{regularPaymentStatus === 'OVERDUE' && Insoluto} {regularPaymentStatus === 'PENDING' && In Scadenza}

Rate Condominiali {settings?.currentYear}

{regularDebtAmount > 0 ? `€ -${regularDebtAmount.toFixed(2)}` : 'In Regola'}

{/* Extra Expenses Widget */} {settings?.features.extraordinaryExpenses && (
0 ? 'bg-white border-orange-200' : 'bg-white border-slate-200'}`}>
0 ? 'bg-orange-50 text-orange-600' : 'bg-slate-100 text-slate-500'}`}>
{extraDebt > 0 && Da Saldare}

Spese Straordinarie

0 ? 'text-orange-600' : 'text-slate-800'}`}> {extraDebt > 0 ? `€ -${extraDebt.toFixed(2)}` : 'Nessuna'}

)} {/* Tickets Widget */} {settings?.features.tickets && (
0 ? 'bg-blue-50 text-blue-600' : 'bg-slate-100 text-slate-500'}`}>
{activeTicketsCount > 0 && {activeTicketsCount} Attive}

Le tue Segnalazioni

{activeTicketsCount > 0 ? `${activeTicketsCount} in corso` : 'Tutto OK'}

)}
)} {/* 3. DIRECTORY HEADER */}

Rubrica Condominiale

{activeCondo.name}

setSearchTerm(e.target.value)} />
{/* 4. LIST */}
    {filteredFamilies.length === 0 ? (
  • Nessuna famiglia trovata in questo condominio.
  • ) : ( filteredFamilies.map((family) => (
  • {family.name}

    Interno: {family.unitNumber}

  • )) )}
); };