From 4137e570467ff02dd84670f764a3d856fa503c61 Mon Sep 17 00:00:00 2001 From: frakarr Date: Thu, 11 Dec 2025 22:30:33 +0100 Subject: [PATCH] Update FamilyList.tsx --- pages/FamilyList.tsx | 167 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 142 insertions(+), 25 deletions(-) diff --git a/pages/FamilyList.tsx b/pages/FamilyList.tsx index 63a9af8..5c6ea89 100644 --- a/pages/FamilyList.tsx +++ b/pages/FamilyList.tsx @@ -1,11 +1,12 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; +import React, { useEffect, useState, useMemo } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; import { CondoService } from '../services/mockDb'; -import { Family, Condo, Notice, AppSettings } from '../types'; -import { Search, ChevronRight, UserCircle, Building, Bell, AlertTriangle, Hammer, Calendar, Info, Link as LinkIcon, Check } from 'lucide-react'; +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(''); @@ -13,7 +14,15 @@ export const FamilyList: React.FC = () => { 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 [myRegularDebt, setMyRegularDebt] = useState(0); + const [myFamily, setMyFamily] = useState(null); + const currentUser = CondoService.getCurrentUser(); + const isPrivileged = currentUser?.role === 'admin' || currentUser?.role === 'poweruser'; useEffect(() => { const fetchData = async () => { @@ -29,28 +38,50 @@ export const FamilyList: React.FC = () => { setActiveCondo(condo); setSettings(appSettings); - if (condo && currentUser && appSettings.features.notices) { - // Filter notices logic: - // 1. Must belong to current condo and be active - // 2. If Admin/PowerUser -> See everything - // 3. If standard User -> See Public notices (no target) OR Targeted notices containing their familyId - const isPrivileged = currentUser.role === 'admin' || currentUser.role === 'poweruser'; + // --- 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 Debt (Current Year) + const payments = await CondoService.getPaymentsByFamily(currentUser.familyId); + const currentYear = appSettings.currentYear; + const now = new Date(); + const currentMonth = now.getFullYear() === currentYear ? now.getMonth() + 1 : (now.getFullYear() > currentYear ? 12 : 0); + + let debt = 0; + const quota = me?.customMonthlyQuota ?? condo.defaultMonthlyQuota; + + for (let m = 1; m <= currentMonth; m++) { + const isPaid = payments.some(p => p.forMonth === m && p.forYear === currentYear); + if (!isPaid) debt += quota; + } + setMyRegularDebt(debt); + } + + // --- NOTICE LOGIC --- + if (condo && currentUser && appSettings.features.notices) { const condoNotices = allNotices.filter(n => { if (n.condoId !== condo.id || !n.active) return false; - if (isPrivileged) return true; - - // Check targeting const hasTargets = n.targetFamilyIds && n.targetFamilyIds.length > 0; - if (!hasTargets) return true; // Public to all - + if (!hasTargets) return true; return currentUser.familyId && n.targetFamilyIds?.includes(currentUser.familyId); }); setNotices(condoNotices); - // Check which ones are read const readStatuses = await Promise.all(condoNotices.map(n => CondoService.getNoticeReadStatus(n.id))); const readIds: string[] = []; readStatuses.forEach((reads, idx) => { @@ -68,7 +99,7 @@ export const FamilyList: React.FC = () => { } }; fetchData(); - }, []); + }, [currentUser?.id, isPrivileged]); // Dependencies const filteredFamilies = families.filter(f => f.name.toLowerCase().includes(searchTerm.toLowerCase()) || @@ -84,6 +115,10 @@ export const FamilyList: React.FC = () => { } }; + // Dashboard Calculations + 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...
; } @@ -99,11 +134,11 @@ export const FamilyList: React.FC = () => { } return ( -
+
- {/* Notices Section - Dashboard effect */} + {/* 1. NOTICES (Bacheca) - High Priority */} {settings?.features.notices && notices.length > 0 && ( -
+

Bacheca Avvisi

@@ -138,10 +173,92 @@ export const FamilyList: React.FC = () => {
)} - {/* Responsive Header */} -
+ {/* 2. USER DASHBOARD (Widgets) - Only for Regular Users with a linked Family */} + {!isPrivileged && myFamily && ( +
+

+ La Tua Situazione +

+
+ + {/* Regular Payments Widget */} +
0 ? 'bg-white border-red-200' : 'bg-white border-slate-200'}`}> +
+
+
0 ? 'bg-red-50 text-red-600' : 'bg-green-50 text-green-600'}`}> + +
+ {myRegularDebt > 0 && Insoluto} +
+

Rate Condominiali {settings?.currentYear}

+

0 ? 'text-red-600' : 'text-slate-800'}`}> + {myRegularDebt > 0 ? `€ -${myRegularDebt.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 */} +
-

Elenco Condomini

+

Rubrica Condominiale

{activeCondo.name} @@ -155,14 +272,14 @@ export const FamilyList: React.FC = () => { setSearchTerm(e.target.value)} />

- {/* List */} + {/* 4. LIST */}
    {filteredFamilies.length === 0 ? (