Update Layout.tsx

This commit is contained in:
2026-01-09 23:36:44 +01:00
committed by GitHub
parent 92669b6925
commit 7f78a0d80a

View File

@@ -3,14 +3,17 @@ import React, { useEffect, useState } from 'react';
import { NavLink, Outlet } from 'react-router-dom';
import { Users, Settings, Building, LogOut, Menu, X, ChevronDown, Check, LayoutDashboard, Megaphone, Info, AlertTriangle, Hammer, Calendar, MessageSquareWarning, PieChart, Briefcase, ReceiptEuro, FileText } from 'lucide-react';
import { CondoService } from '../services/mockDb';
import { Condo, Notice, AppSettings } from '../types';
import { Condo, Notice, AppSettings, BrandingConfig } from '../types';
export const Layout: React.FC = () => {
interface LayoutProps {
branding?: BrandingConfig;
}
export const Layout: React.FC<LayoutProps> = ({ branding }) => {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const user = CondoService.getCurrentUser();
// Logic: "isPrivileged" includes Admin AND PowerUser.
// This allows PowerUsers to see Reports and other admin-like features.
const isPrivileged = user?.role === 'admin' || user?.role === 'poweruser';
const [condos, setCondos] = useState<Condo[]>([]);
@@ -26,7 +29,6 @@ export const Layout: React.FC = () => {
const [ticketBadgeCount, setTicketBadgeCount] = useState(0);
const fetchContext = async () => {
// Fetch global settings to check features
try {
const globalSettings = await CondoService.getSettings();
setSettings(globalSettings);
@@ -49,7 +51,7 @@ export const Layout: React.FC = () => {
// 1. Tickets Badge Logic
try {
if (settings?.features.tickets || true) { // Check features if available or default
if (settings?.features.tickets || true) {
const tickets = await CondoService.getTickets();
let count = 0;
@@ -59,7 +61,6 @@ export const Layout: React.FC = () => {
const isArchived = t.status === 'RESOLVED' || t.status === 'CLOSED';
if (isPrivileged) {
// Admin/PowerUser: Count new unarchived tickets OR tickets with new comments from users
if (isTicketNew && !isArchived) {
count++;
} else {
@@ -71,7 +72,6 @@ export const Layout: React.FC = () => {
}
}
} else {
// User: Count tickets with new comments from Admin (or others)
const updatedDate = new Date(t.updatedAt).getTime();
if (updatedDate > lastViewedTickets) {
const comments = await CondoService.getTicketComments(t.id);
@@ -85,21 +85,17 @@ export const Layout: React.FC = () => {
} catch(e) { console.error("Error calc ticket badges", e); }
// Check for notices & expenses for User (non-privileged mostly, but logic works for all if needed)
if (!isPrivileged && active && user) {
try {
// 2. Check Notices
const unread = await CondoService.getUnreadNoticesForUser(user.id, active.id);
if (unread.length > 0) {
setActiveNotice(unread[0]);
}
// 3. Check New Extraordinary Expenses
const myExpenses = await CondoService.getMyExpenses();
const lastViewed = localStorage.getItem('lastViewedExpensesTime');
const lastViewedTime = lastViewed ? parseInt(lastViewed) : 0;
// Count expenses created AFTER the last visit
const count = myExpenses.filter((e: any) => new Date(e.createdAt).getTime() > lastViewedTime).length;
setNewExpensesCount(count);
@@ -109,12 +105,10 @@ export const Layout: React.FC = () => {
useEffect(() => {
fetchContext();
// Listen for updates from Settings or Expense views
const handleUpdate = () => fetchContext();
window.addEventListener('condo-updated', handleUpdate);
window.addEventListener('expenses-viewed', handleUpdate);
window.addEventListener('tickets-viewed', handleUpdate); // Listen for ticket view
window.addEventListener('tickets-viewed', handleUpdate);
return () => {
window.removeEventListener('condo-updated', handleUpdate);
window.removeEventListener('expenses-viewed', handleUpdate);
@@ -134,8 +128,6 @@ export const Layout: React.FC = () => {
}
};
const closeNoticeModal = () => setActiveNotice(null);
const navClass = ({ isActive }: { isActive: boolean }) =>
`flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 ${
isActive
@@ -154,9 +146,12 @@ export const Layout: React.FC = () => {
}
};
// Check if notices are actually enabled before showing modal
const showNotice = activeNotice && settings?.features.notices;
// Use props passed from App.tsx directly
const appName = branding?.appName || 'CondoPay';
const logoUrl = branding?.logoUrl;
return (
<div className="flex h-screen bg-slate-50 overflow-hidden">
@@ -195,11 +190,15 @@ export const Layout: React.FC = () => {
{/* Mobile Header */}
<div className="lg:hidden fixed top-0 left-0 right-0 h-16 bg-white border-b border-slate-200 flex items-center justify-between px-4 z-40 shadow-sm">
<div className="flex items-center gap-2 overflow-hidden">
<div className="bg-blue-600 p-1.5 rounded-lg flex-shrink-0">
<Building className="text-white w-5 h-5" />
</div>
{logoUrl ? (
<img src={logoUrl} alt="Logo" className="w-8 h-8 object-contain rounded-lg" />
) : (
<div className="bg-blue-600 p-1.5 rounded-lg flex-shrink-0">
<Building className="text-white w-5 h-5" />
</div>
)}
<div className="flex flex-col min-w-0">
<h1 className="font-bold text-slate-800 leading-tight truncate">CondoPay</h1>
<h1 className="font-bold text-slate-800 leading-tight truncate">{appName}</h1>
{activeCondo && <p className="text-xs text-slate-500 truncate">{activeCondo.name}</p>}
</div>
</div>
@@ -221,10 +220,14 @@ export const Layout: React.FC = () => {
{/* Desktop Logo & Condo Switcher */}
<div className="p-6 hidden lg:flex flex-col gap-4 border-b border-slate-100">
<div className="flex items-center gap-3">
<div className="bg-blue-600 p-2 rounded-lg">
<Building className="text-white w-6 h-6" />
</div>
<h1 className="font-bold text-xl text-slate-800 tracking-tight">CondoPay</h1>
{logoUrl ? (
<img src={logoUrl} alt="Logo" className="w-10 h-10 object-contain rounded-xl" />
) : (
<div className="bg-blue-600 p-2 rounded-lg">
<Building className="text-white w-6 h-6" />
</div>
)}
<h1 className="font-bold text-xl text-slate-800 tracking-tight">{appName}</h1>
</div>
{/* Condo Switcher (Privileged Only & MultiCondo Enabled) */}