Update Layout.tsx
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
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 } from 'lucide-react';
|
||||
import { CondoService } from '../services/mockDb';
|
||||
import { CondoService } from '../services/api';
|
||||
import { Condo, Notice, AppSettings } from '../types';
|
||||
|
||||
export const Layout: React.FC = () => {
|
||||
@@ -19,6 +19,9 @@ export const Layout: React.FC = () => {
|
||||
const [activeNotice, setActiveNotice] = useState<Notice | null>(null);
|
||||
const [hasNewExpenses, setHasNewExpenses] = useState(false);
|
||||
|
||||
// Ticket Badges
|
||||
const [ticketBadgeCount, setTicketBadgeCount] = useState(0);
|
||||
|
||||
const fetchContext = async () => {
|
||||
// Fetch global settings to check features
|
||||
try {
|
||||
@@ -37,16 +40,63 @@ export const Layout: React.FC = () => {
|
||||
const active = await CondoService.getActiveCondo();
|
||||
setActiveCondo(active);
|
||||
|
||||
// --- NOTIFICATION LOGIC ---
|
||||
const lastViewedTicketsStr = localStorage.getItem('lastViewedTickets');
|
||||
const lastViewedTickets = lastViewedTicketsStr ? parseInt(lastViewedTicketsStr) : 0;
|
||||
|
||||
// 1. Tickets Badge Logic
|
||||
try {
|
||||
if (settings?.features.tickets || true) { // Check features if available or default
|
||||
const tickets = await CondoService.getTickets();
|
||||
let count = 0;
|
||||
|
||||
for (const t of tickets) {
|
||||
const ticketDate = new Date(t.createdAt).getTime();
|
||||
const isTicketNew = ticketDate > lastViewedTickets;
|
||||
const isArchived = t.status === 'RESOLVED' || t.status === 'CLOSED';
|
||||
|
||||
if (isAdmin) {
|
||||
// Admin: Count new unarchived tickets OR tickets with new comments from users
|
||||
if (isTicketNew && !isArchived) {
|
||||
count++;
|
||||
} else {
|
||||
// Check for new comments from users
|
||||
// Optimization: In a real app we'd need a lighter query.
|
||||
// Here we iterate because we have the data or fetch lightly.
|
||||
// Assuming getTickets includes basic info or we need to check updatedAt
|
||||
const updatedDate = new Date(t.updatedAt).getTime();
|
||||
if (updatedDate > lastViewedTickets) {
|
||||
// Deep check: fetch comments only if recently updated
|
||||
const comments = await CondoService.getTicketComments(t.id);
|
||||
const hasNewUserReply = comments.some(c => new Date(c.createdAt).getTime() > lastViewedTickets && c.userId !== user?.id);
|
||||
if (hasNewUserReply) count++;
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
const hasNewReply = comments.some(c => new Date(c.createdAt).getTime() > lastViewedTickets && c.userId !== user?.id);
|
||||
if (hasNewReply) count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
setTicketBadgeCount(count);
|
||||
}
|
||||
} catch(e) { console.error("Error calc ticket badges", e); }
|
||||
|
||||
|
||||
// Check for notices & expenses for User
|
||||
if (!isAdmin && active && user) {
|
||||
try {
|
||||
// 1. Check Notices
|
||||
// 2. Check Notices
|
||||
const unread = await CondoService.getUnreadNoticesForUser(user.id, active.id);
|
||||
if (unread.length > 0) {
|
||||
setActiveNotice(unread[0]);
|
||||
}
|
||||
|
||||
// 2. Check New Extraordinary Expenses
|
||||
// 3. Check New Extraordinary Expenses
|
||||
const myExpenses = await CondoService.getMyExpenses();
|
||||
const lastViewed = localStorage.getItem('lastViewedExpensesTime');
|
||||
const lastViewedTime = lastViewed ? parseInt(lastViewed) : 0;
|
||||
@@ -65,10 +115,12 @@ export const Layout: React.FC = () => {
|
||||
// Listen for updates from Settings or Expense views
|
||||
const handleUpdate = () => fetchContext();
|
||||
window.addEventListener('condo-updated', handleUpdate);
|
||||
window.addEventListener('expenses-viewed', handleUpdate); // Listen for manual trigger when user views page
|
||||
window.addEventListener('expenses-viewed', handleUpdate);
|
||||
window.addEventListener('tickets-viewed', handleUpdate); // Listen for ticket view
|
||||
return () => {
|
||||
window.removeEventListener('condo-updated', handleUpdate);
|
||||
window.removeEventListener('expenses-viewed', handleUpdate);
|
||||
window.removeEventListener('tickets-viewed', handleUpdate);
|
||||
};
|
||||
}, [isAdmin]);
|
||||
|
||||
@@ -276,8 +328,17 @@ export const Layout: React.FC = () => {
|
||||
{/* Hide Tickets if disabled */}
|
||||
{settings?.features.tickets && (
|
||||
<NavLink to="/tickets" className={navClass} onClick={closeMenu}>
|
||||
<MessageSquareWarning className="w-5 h-5" />
|
||||
<span className="font-medium">Segnalazioni</span>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="flex items-center gap-3">
|
||||
<MessageSquareWarning className="w-5 h-5" />
|
||||
<span className="font-medium">Segnalazioni</span>
|
||||
</div>
|
||||
{ticketBadgeCount > 0 && (
|
||||
<span className="bg-red-500 text-white text-[10px] font-bold px-1.5 h-5 min-w-[20px] rounded-full flex items-center justify-center shadow-sm">
|
||||
{ticketBadgeCount > 99 ? '99+' : ticketBadgeCount}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user