import React, { useEffect, useState } from 'react'; import { HashRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom'; import { Layout } from './components/Layout'; import { FamilyList } from './pages/FamilyList'; import { FamilyDetail } from './pages/FamilyDetail'; import { SettingsPage } from './pages/Settings'; import { TicketsPage } from './pages/Tickets'; import { ReportsPage } from './pages/Reports'; import { ExtraordinaryAdmin } from './pages/ExtraordinaryAdmin'; import { ExtraordinaryUser } from './pages/ExtraordinaryUser'; import { CondoFinancialsPage } from './pages/CondoFinancials.tsx'; import { DocumentsPage } from './pages/Documents.tsx'; import { LoginPage } from './pages/Login'; import { CondoService } from './services/mockDb'; import { BrandingConfig } from './types'; // Palette predefinite basate su chiavi stringa const COLOR_PALETTES: Record = { blue: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', 950: '#172554' }, purple: { 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87', 950: '#3b0764' }, green: { 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d', 950: '#052e16' }, red: { 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5', 400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c', 800: '#991b1b', 900: '#7f1d1d', 950: '#450a0a' }, orange: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', 950: '#431407' }, slate: { 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617' } }; /** * Genera una palette completa Tailwind (50-950) partendo da un singolo colore HEX. */ function generatePaletteFromHex(hex: string) { // Rimuoviamo eventuale # se presente const cleanHex = hex.replace('#', ''); const r = parseInt(cleanHex.slice(0, 2), 16); const g = parseInt(cleanHex.slice(2, 4), 16); const b = parseInt(cleanHex.slice(4, 6), 16); const adjust = (color: number, amount: number) => { return Math.max(0, Math.min(255, Math.round(color + (amount * (amount > 0 ? 255 - color : color))))); }; const toHex = (c: number) => c.toString(16).padStart(2, '0'); const getHex = (amt: number) => `#${toHex(adjust(r, amt))}${toHex(adjust(g, amt))}${toHex(adjust(b, amt))}`; return { 50: getHex(0.95), 100: getHex(0.85), 200: getHex(0.7), 300: getHex(0.5), 400: getHex(0.3), 500: `#${cleanHex}`, 600: getHex(-0.1), 700: getHex(-0.25), 800: getHex(-0.45), 900: getHex(-0.6), 950: getHex(-0.8) }; } const ProtectedRoute = ({ children }: { children?: React.ReactNode }) => { const user = CondoService.getCurrentUser(); const location = useLocation(); if (!user) { return ; } return <>{children}; }; const AdminRoute = ({ children }: { children?: React.ReactNode }) => { const user = CondoService.getCurrentUser(); const isAdmin = user?.role === 'admin' || user?.role === 'poweruser'; if (!isAdmin) { return ; } return <>{children}; }; const App: React.FC = () => { const [branding, setBranding] = useState({ appName: 'CondoPay', primaryColor: 'blue', logoUrl: '', loginBackgroundUrl: '' }); const applyBranding = (config: BrandingConfig) => { // Merge with defaults ensures properties like logoUrl aren't undefined if API returns partial object const mergedConfig = { appName: 'CondoPay', primaryColor: 'blue', logoUrl: '', loginBackgroundUrl: '', ...config }; setBranding(mergedConfig); document.title = mergedConfig.appName || 'CondoPay Manager'; let palette; if (mergedConfig.primaryColor && mergedConfig.primaryColor.startsWith('#')) { palette = generatePaletteFromHex(mergedConfig.primaryColor); } else { palette = COLOR_PALETTES[mergedConfig.primaryColor] || COLOR_PALETTES['blue']; } const root = document.documentElement; Object.keys(palette).forEach(key => { root.style.setProperty(`--color-primary-${key}`, palette[key]); }); }; useEffect(() => { const loadBranding = async () => { try { const config = await CondoService.getPublicBranding(); if (config) { applyBranding(config); } } catch(e) { console.error("Error loading branding", e); } }; loadBranding(); // Listen for branding updates from settings without full reload const handleUpdate = () => loadBranding(); window.addEventListener('branding-updated', handleUpdate); return () => window.removeEventListener('branding-updated', handleUpdate); }, []); return ( } /> }> } /> } /> } /> } /> } /> } /> } /> } /> } /> ); }; export default App;