Berth surfaces - New compact mooring-chip header (colored plate + status pill, dock-label in tooltip) replaces the redundant "Berth B1 / Sold / B DOCK" stack - Berth list gains a "Latest deal stage" column showing the most-advanced pipeline stage of any active linked interest (server-aggregated, ranks by PIPELINE_STAGES index) - "Linked prospect" Select on the status-change dialog rebuilt as a Command combobox: search, recent-first sort, stage-coloured pills Pipeline UX - Reverting an interest to Open with linked berths now prompts: keep the links, unlink and reset, or cancel. Silent when no berths are linked - Activity feed + entity-activity feed normalise enum field values via STAGE_LABELS / formatSource: "deposit_10pct → contract_sent" reads as "10% Deposit → Contract Sent" EOI generate dialog - Inline-editable rows for client name, nationality (country combobox), and yacht name — pencil affordance saves directly via clients/yachts PATCH - Replaces the single "Edit on client's page" link with two contextual links framed by short copy explaining what's inline vs what needs the canonical page - Backend EoiContext now includes client.id + yacht.id so the dialog can PATCH without an extra round-trip Company form - New "Connections" section lets the rep attach members (clients) and yachts during create. Yacht attach uses the existing transfer endpoint so audit log + ownership history capture the change - Inline "+ New client" / "+ New yacht" buttons open the canonical forms stacked over the company sheet - After save, the form chains to a yacht pull-in prompt (if any attached client owns yachts not yet linked) and an optional "Create interest" step pre-filled with the first attached client Admin - /admin landing gains a searchable index — typed query flattens groups into a result list matching label + description + group title - "Documenso & EOI" card relabelled to "EOI signing service" (consistent with the user-facing language rename from round 1) Measurement units (migration 0053) - interests gains desired_*_m columns + desired_*_unit discriminators so the rep's literal entry (ft OR m) is preserved verbatim instead of being reconstructed from a single canonical column on every render - yachts + berths gain matching *_unit columns alongside their existing ft + m pairs; defaults to 'ft' so legacy rows still render normally - Interest form POST/PATCH now sends both ft + m + unit; computed m is derived from the ft canonical to keep the recommender SQL unchanged Misc - Active-deals tile + topbar type their Link href as `Route` instead of `any` - Unused REPORT_TYPE_LABELS const dropped from generate-report-form - Test fixtures (fill-eoi-form, documenso-payload, public-berths) updated to include the new id + unit fields on the EoiContext / Berth shapes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
275 lines
7.4 KiB
TypeScript
275 lines
7.4 KiB
TypeScript
import {
|
|
Bell,
|
|
BookOpen,
|
|
Briefcase,
|
|
Database,
|
|
FileText,
|
|
HardDrive,
|
|
Inbox,
|
|
Key,
|
|
LayoutDashboard,
|
|
Mail,
|
|
Palette,
|
|
ScrollText,
|
|
Settings,
|
|
Shield,
|
|
Sliders,
|
|
Tag,
|
|
Upload,
|
|
Users,
|
|
UsersRound,
|
|
Webhook,
|
|
Globe,
|
|
} from 'lucide-react';
|
|
|
|
import { PageHeader } from '@/components/shared/page-header';
|
|
import { AdminSectionsBrowser, type AdminGroup } from '@/components/admin/admin-sections-browser';
|
|
|
|
const GROUPS: AdminGroup[] = [
|
|
{
|
|
title: 'Access',
|
|
description: 'Who can sign in and what they can do once they do.',
|
|
sections: [
|
|
{
|
|
href: 'users',
|
|
label: 'Users',
|
|
description: 'CRM accounts, role assignments, and per-user residential access toggles.',
|
|
icon: Users,
|
|
},
|
|
{
|
|
href: 'invitations',
|
|
label: 'Invitations',
|
|
description: 'Send invitations, track pending invites, and resend or revoke them.',
|
|
icon: Mail,
|
|
},
|
|
{
|
|
href: 'roles',
|
|
label: 'Roles & Permissions',
|
|
description: 'Default permission sets and per-port role overrides.',
|
|
icon: Shield,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'Configuration',
|
|
description: 'Branding, integrations, and per-port settings.',
|
|
sections: [
|
|
{
|
|
href: 'email',
|
|
label: 'Email Settings',
|
|
description: 'From address, signatures, and per-port SMTP overrides.',
|
|
icon: Mail,
|
|
},
|
|
{
|
|
href: 'documenso',
|
|
label: 'EOI signing service',
|
|
description:
|
|
'API credentials, EOI template, and default in-app vs external signing pathway.',
|
|
icon: FileText,
|
|
},
|
|
{
|
|
href: 'reminders',
|
|
label: 'Reminders',
|
|
description: 'Default reminder behaviour and the daily-digest delivery window.',
|
|
icon: Bell,
|
|
},
|
|
{
|
|
href: 'branding',
|
|
label: 'Branding',
|
|
description: 'App name, logo, primary color, and email header/footer HTML.',
|
|
icon: Palette,
|
|
},
|
|
{
|
|
href: 'settings',
|
|
label: 'System Settings',
|
|
description: 'Generic key/value configuration store for advanced flags.',
|
|
icon: Settings,
|
|
},
|
|
{
|
|
href: 'webhooks',
|
|
label: 'Webhooks',
|
|
description: 'Outgoing webhook subscriptions, secrets, and delivery log.',
|
|
icon: Webhook,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'Content',
|
|
description: 'Forms, templates, and labels that users see.',
|
|
sections: [
|
|
{
|
|
href: 'forms',
|
|
label: 'Forms',
|
|
description: 'Form templates used by client-facing inquiry and intake flows.',
|
|
icon: Sliders,
|
|
},
|
|
{
|
|
href: 'templates',
|
|
label: 'Document Templates',
|
|
description: 'PDF + email templates with merge-field placeholders.',
|
|
icon: FileText,
|
|
},
|
|
{
|
|
href: 'email-templates',
|
|
label: 'Email Templates',
|
|
description: 'Customize subject lines for transactional emails (portal, inquiry, invite).',
|
|
icon: Mail,
|
|
},
|
|
{
|
|
href: 'tags',
|
|
label: 'Tags',
|
|
description: 'Color-coded tags applied to clients, yachts, companies, and interests.',
|
|
icon: Tag,
|
|
},
|
|
{
|
|
href: 'vocabularies',
|
|
label: 'Vocabularies',
|
|
description:
|
|
'Per-port pick lists used across the CRM: interest temperatures, status reasons, tenure types, expense categories, document types.',
|
|
icon: BookOpen,
|
|
},
|
|
{
|
|
href: 'custom-fields',
|
|
label: 'Custom Fields',
|
|
description: 'Tenant-defined fields for clients, yachts, and reservations.',
|
|
icon: Key,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'Data Quality',
|
|
description: 'Cleanup, imports, and the audit trail.',
|
|
sections: [
|
|
{
|
|
href: 'inquiries',
|
|
label: 'Inquiry Inbox',
|
|
description:
|
|
'Submissions captured from the public marketing site (berth, residence, contact).',
|
|
icon: Inbox,
|
|
},
|
|
{
|
|
href: 'sends',
|
|
label: 'Send Log',
|
|
description: 'Brochure and per-berth PDF sends, with delivery failures surfaced for retry.',
|
|
icon: Mail,
|
|
},
|
|
{
|
|
href: 'duplicates',
|
|
label: 'Duplicates',
|
|
description: 'Review queue of suspected duplicate clients flagged by the dedup engine.',
|
|
icon: UsersRound,
|
|
},
|
|
{
|
|
href: 'import',
|
|
label: 'Bulk Import',
|
|
description: 'CSV-driven imports for clients, yachts, and reservations.',
|
|
icon: Upload,
|
|
},
|
|
{
|
|
href: 'audit',
|
|
label: 'Audit Log',
|
|
description: 'Searchable log of every authenticated mutation in the system.',
|
|
icon: ScrollText,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'Operations',
|
|
description: 'Health checks and disaster recovery.',
|
|
sections: [
|
|
{
|
|
href: 'reports',
|
|
label: 'Reports',
|
|
description: 'Saved analytics views and ad-hoc query results.',
|
|
icon: LayoutDashboard,
|
|
},
|
|
{
|
|
href: 'monitoring',
|
|
label: 'Queue Monitoring',
|
|
description: 'BullMQ queue health, throughput, and retry diagnostics.',
|
|
icon: Database,
|
|
},
|
|
{
|
|
href: 'backup',
|
|
label: 'Backup & Restore',
|
|
description: 'Backup posture + retention policy (read-only).',
|
|
icon: HardDrive,
|
|
},
|
|
{
|
|
href: 'storage',
|
|
label: 'Storage Backend',
|
|
description:
|
|
'Choose between S3-compatible object store or local filesystem; migrate between them.',
|
|
icon: HardDrive,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'Tenancy',
|
|
description: 'Multi-port and multi-install scaffolding.',
|
|
sections: [
|
|
{
|
|
href: 'ports',
|
|
label: 'Ports',
|
|
description: 'Manage the marinas/ports this installation serves.',
|
|
icon: Briefcase,
|
|
},
|
|
{
|
|
href: 'onboarding',
|
|
label: 'Onboarding checklist',
|
|
description: 'Setup checklist for fresh ports (read-only references).',
|
|
icon: LayoutDashboard,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: 'Integrations',
|
|
description: 'Third-party providers wired into the app.',
|
|
sections: [
|
|
{
|
|
href: 'ai',
|
|
label: 'AI configuration',
|
|
description:
|
|
'Master switch + provider credentials shared by every AI surface (OCR, berth-PDF parser, future recommender embeddings).',
|
|
icon: ScrollText,
|
|
},
|
|
{
|
|
href: 'ocr',
|
|
label: 'Receipt OCR (per-feature)',
|
|
description: 'Provider, model, and confidence thresholds for the receipt scanner.',
|
|
icon: ScrollText,
|
|
},
|
|
{
|
|
href: 'website-analytics',
|
|
label: 'Website analytics (Umami)',
|
|
description: 'Per-port Umami URL, API token, and Website ID.',
|
|
icon: Globe,
|
|
},
|
|
{
|
|
href: 'residential-stages',
|
|
label: 'Residential pipeline stages',
|
|
description:
|
|
'Configure stages residential interests flow through. Removing a stage with active interests prompts for reassignment.',
|
|
icon: ScrollText,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
export default async function AdminLandingPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ portSlug: string }>;
|
|
}) {
|
|
const { portSlug } = await params;
|
|
return (
|
|
<div className="space-y-8">
|
|
<PageHeader
|
|
title="Administration"
|
|
description="Per-port configuration and system administration. Use the search to jump to a setting, or browse the grouped index below."
|
|
/>
|
|
<AdminSectionsBrowser portSlug={portSlug} groups={GROUPS} />
|
|
</div>
|
|
);
|
|
}
|