Update App.tsx
This commit is contained in:
87
App.tsx
87
App.tsx
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { HashRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom';
|
import { HashRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom';
|
||||||
import { Layout } from './components/Layout';
|
import { Layout } from './components/Layout';
|
||||||
import { FamilyList } from './pages/FamilyList';
|
import { FamilyList } from './pages/FamilyList';
|
||||||
@@ -13,6 +13,49 @@ import { CondoFinancialsPage } from './pages/CondoFinancials.tsx';
|
|||||||
import { DocumentsPage } from './pages/Documents.tsx';
|
import { DocumentsPage } from './pages/Documents.tsx';
|
||||||
import { LoginPage } from './pages/Login';
|
import { LoginPage } from './pages/Login';
|
||||||
import { CondoService } from './services/mockDb';
|
import { CondoService } from './services/mockDb';
|
||||||
|
import { BrandingConfig } from './types';
|
||||||
|
|
||||||
|
// Palette predefinite basate su chiavi stringa
|
||||||
|
const COLOR_PALETTES: Record<string, any> = {
|
||||||
|
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 ProtectedRoute = ({ children }: { children?: React.ReactNode }) => {
|
||||||
const user = CondoService.getCurrentUser();
|
const user = CondoService.getCurrentUser();
|
||||||
@@ -25,27 +68,61 @@ const ProtectedRoute = ({ children }: { children?: React.ReactNode }) => {
|
|||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Route wrapper that checks for Admin/PowerUser
|
|
||||||
const AdminRoute = ({ children }: { children?: React.ReactNode }) => {
|
const AdminRoute = ({ children }: { children?: React.ReactNode }) => {
|
||||||
const user = CondoService.getCurrentUser();
|
const user = CondoService.getCurrentUser();
|
||||||
const isAdmin = user?.role === 'admin' || user?.role === 'poweruser';
|
const isAdmin = user?.role === 'admin' || user?.role === 'poweruser';
|
||||||
|
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
// Redirect regular users to their own view
|
|
||||||
return <ExtraordinaryUser />;
|
return <ExtraordinaryUser />;
|
||||||
}
|
}
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
|
const [branding, setBranding] = useState<BrandingConfig>({ appName: 'CondoPay', primaryColor: 'blue' });
|
||||||
|
|
||||||
|
const applyBranding = (config: BrandingConfig) => {
|
||||||
|
setBranding(config);
|
||||||
|
document.title = config.appName || 'CondoPay Manager';
|
||||||
|
|
||||||
|
let palette;
|
||||||
|
if (config.primaryColor.startsWith('#')) {
|
||||||
|
palette = generatePaletteFromHex(config.primaryColor);
|
||||||
|
} else {
|
||||||
|
palette = COLOR_PALETTES[config.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 (
|
return (
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Route path="/login" element={<LoginPage branding={branding} />} />
|
||||||
|
|
||||||
<Route path="/" element={
|
<Route path="/" element={
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
<Layout />
|
<Layout branding={branding} />
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}>
|
}>
|
||||||
<Route index element={<FamilyList />} />
|
<Route index element={<FamilyList />} />
|
||||||
|
|||||||
Reference in New Issue
Block a user