feat(berths): inline spec-PDF preview, manual-pin badge, maintenance module toggle, under-offer popover
Post-cutover UAT batch #3: - #62 Spec tab renders the current berth spec PDF inline (lazy PdfViewer, toggleable, default-open) + explicit download. Interest Documents tab already previews/downloads linked deal docs inline (verified). - #57 Surface berths.status_override_mode through the interest-berths API; linked-berth rows show an amber "Pin overrides pitch" badge + corrected consequence copy when a berth is specifically-pitched but manually pinned (the soft-pin wins on the public map). - #63 New maintenance-module gate (maintenance_module_enabled, default on): registry + admin Settings toggle, maintenance-module.service, port-provider useMaintenanceModuleEnabled, layout wiring, buildBerthTabs hides the Maintenance tab when off, and both maintenance log routes assert the gate. - #66 BerthOccupancyChip: >1 competing interest opens a popover listing every deal (name + stage + in-EOI/primary + link); single stays a direct link. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,10 @@ interface PortContextValue {
|
||||
* Resolved server-side in the dashboard layout. Consumers read via
|
||||
* `useTenanciesModuleEnabled()`. */
|
||||
tenanciesModuleByPort: Record<string, boolean>;
|
||||
/** Per-port Maintenance-module flag. Resolved server-side in the
|
||||
* dashboard layout; consumers read via `useMaintenanceModuleEnabled()`.
|
||||
* Defaults to enabled (unset port => true). */
|
||||
maintenanceModuleByPort: Record<string, boolean>;
|
||||
}
|
||||
|
||||
const PortContext = createContext<PortContextValue>({
|
||||
@@ -24,6 +28,7 @@ const PortContext = createContext<PortContextValue>({
|
||||
currentPortId: null,
|
||||
currentPortSlug: null,
|
||||
tenanciesModuleByPort: {},
|
||||
maintenanceModuleByPort: {},
|
||||
});
|
||||
|
||||
interface PortProviderProps {
|
||||
@@ -31,6 +36,7 @@ interface PortProviderProps {
|
||||
ports: Port[];
|
||||
defaultPortId: string | null;
|
||||
tenanciesModuleByPort?: Record<string, boolean>;
|
||||
maintenanceModuleByPort?: Record<string, boolean>;
|
||||
}
|
||||
|
||||
export function PortProvider({
|
||||
@@ -38,6 +44,7 @@ export function PortProvider({
|
||||
ports,
|
||||
defaultPortId,
|
||||
tenanciesModuleByPort = {},
|
||||
maintenanceModuleByPort = {},
|
||||
}: PortProviderProps) {
|
||||
const params = useParams();
|
||||
const portSlugFromUrl = params?.portSlug as string | undefined;
|
||||
@@ -87,6 +94,7 @@ export function PortProvider({
|
||||
currentPortId: currentPort?.id ?? null,
|
||||
currentPortSlug: currentPort?.slug ?? null,
|
||||
tenanciesModuleByPort,
|
||||
maintenanceModuleByPort,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
@@ -106,3 +114,13 @@ export function useTenanciesModuleEnabled(): boolean {
|
||||
if (!currentPortId) return false;
|
||||
return tenanciesModuleByPort[currentPortId] ?? false;
|
||||
}
|
||||
|
||||
/** Read the maintenance-module-enabled flag for the currently-active port.
|
||||
* Defaults to ENABLED (true) when unset so the feature stays visible
|
||||
* unless an admin has explicitly turned it off. Server-side resolved in
|
||||
* the dashboard layout — synchronous read, no fetch latency/flicker. */
|
||||
export function useMaintenanceModuleEnabled(): boolean {
|
||||
const { currentPortId, maintenanceModuleByPort } = useContext(PortContext);
|
||||
if (!currentPortId) return true;
|
||||
return maintenanceModuleByPort[currentPortId] ?? true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user