fix(uat): prod UAT batch — reports, sidebar, search, berths, breakpoint

- financial report: drop Expenses KPI, Net Contribution, cash-flow chart,
  expense donut + ledger (expenses are business-trip costs, not net contribution)
- dashboard report PDF: pagination-safe tables (TableSection + per-row wrap)
  so long doc lists no longer overlap/crush
- clients PDF report: rename "Nationality" -> "Country"
- sidebar: hide a section header when all its items gate off (FINANCIAL orphan)
- topbar: move global search into the 1fr grid track so it can't overlap "New"
- clients card: show all linked berths (not just latest interest's primary)
- berths list: hide table-only toggles (ft/m, density, columns) in card mode
- lists: lower table/card breakpoint lg -> md so narrow desktops get tables
- alert-rules: stale floor created_at -> updated_at (survives created_at backfill)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 15:41:31 +02:00
parent 93c6554c95
commit 95724c8e3a
12 changed files with 282 additions and 461 deletions

View File

@@ -402,6 +402,20 @@ function SidebarContent({
if (section.requiresResidentialModule && !residentialModuleEnabled) return null;
if (section.umamiRequired && !umamiConfigured) return null;
// Resolve the items this section will actually render after
// per-item module/permission gating. If they all gate off
// (e.g. the Financial section once the Expenses module is
// disabled), skip the whole section so its header + separator
// don't linger as an orphaned label.
const visibleItems = section.items.filter((item) => {
const gated = item as NavItemGated;
if (gated.requiresTenanciesModule && !tenanciesModuleEnabled) return false;
if (gated.requiresExpensesModule && !expensesModuleEnabled) return false;
if (gated.umamiRequired && !umamiConfigured) return false;
return true;
});
if (visibleItems.length === 0) return null;
return (
<div key={section.title}>
{!collapsed && (
@@ -425,24 +439,15 @@ function SidebarContent({
)}
{(!section.adminRequired || adminExpanded || collapsed) && (
<ul className="space-y-0.5">
{section.items
.filter((item) => {
const gated = item as NavItemGated;
if (gated.requiresTenanciesModule && !tenanciesModuleEnabled)
return false;
if (gated.requiresExpensesModule && !expensesModuleEnabled) return false;
if (gated.umamiRequired && !umamiConfigured) return false;
return true;
})
.map((item) => (
<li key={item.href}>
<NavItemLink
item={item}
collapsed={collapsed}
active={isActive(item.href, item.exact)}
/>
</li>
))}
{visibleItems.map((item) => (
<li key={item.href}>
<NavItemLink
item={item}
collapsed={collapsed}
active={isActive(item.href, item.exact)}
/>
</li>
))}
</ul>
)}
<Separator className="mt-3 bg-slate-200" aria-hidden />