Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import type { DetailTab } from '@/components/shared/detail-layout';
|
|
|
|
|
import { NotesList } from '@/components/shared/notes-list';
|
2026-04-24 14:36:34 +02:00
|
|
|
import { ClientYachtsTab } from '@/components/clients/client-yachts-tab';
|
|
|
|
|
import { ClientCompaniesTab } from '@/components/clients/client-companies-tab';
|
|
|
|
|
import { ClientReservationsTab } from '@/components/clients/client-reservations-tab';
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
|
|
|
|
|
interface ClientTabsOptions {
|
|
|
|
|
clientId: string;
|
|
|
|
|
currentUserId?: string;
|
|
|
|
|
client: {
|
|
|
|
|
fullName: string;
|
|
|
|
|
nationality?: string | null;
|
|
|
|
|
preferredContactMethod?: string | null;
|
|
|
|
|
preferredLanguage?: string | null;
|
|
|
|
|
timezone?: string | null;
|
|
|
|
|
source?: string | null;
|
|
|
|
|
sourceDetails?: string | null;
|
|
|
|
|
contacts?: Array<{
|
|
|
|
|
id: string;
|
|
|
|
|
channel: string;
|
|
|
|
|
value: string;
|
|
|
|
|
label?: string | null;
|
|
|
|
|
isPrimary: boolean;
|
|
|
|
|
}>;
|
2026-04-24 14:36:34 +02:00
|
|
|
yachts: Array<{
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
hullNumber: string | null;
|
|
|
|
|
registration: string | null;
|
|
|
|
|
lengthFt: string | null;
|
|
|
|
|
widthFt: string | null;
|
|
|
|
|
status: string;
|
|
|
|
|
}>;
|
|
|
|
|
companies: Array<{
|
|
|
|
|
membershipId: string;
|
|
|
|
|
role: string;
|
|
|
|
|
isPrimary: boolean;
|
|
|
|
|
startDate: string | Date;
|
|
|
|
|
company: {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
legalName: string | null;
|
|
|
|
|
status: string;
|
|
|
|
|
};
|
|
|
|
|
}>;
|
|
|
|
|
activeReservations: Array<{
|
|
|
|
|
id: string;
|
|
|
|
|
berthId: string;
|
|
|
|
|
yachtId: string;
|
|
|
|
|
startDate: string | Date;
|
|
|
|
|
tenureType: string;
|
|
|
|
|
status: string;
|
|
|
|
|
}>;
|
|
|
|
|
tags?: Array<{ id: string; name: string; color: string }>;
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function InfoRow({ label, value }: { label: string; value?: string | null }) {
|
|
|
|
|
if (!value) return null;
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex gap-2 py-1.5 border-b last:border-0">
|
|
|
|
|
<dt className="w-40 shrink-0 text-sm text-muted-foreground">{label}</dt>
|
|
|
|
|
<dd className="text-sm">{value}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function OverviewTab({ client }: { client: ClientTabsOptions['client'] }) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
|
|
|
{/* Personal Info */}
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<h3 className="text-sm font-medium mb-2">Personal Information</h3>
|
|
|
|
|
<dl>
|
|
|
|
|
<InfoRow label="Full Name" value={client.fullName} />
|
|
|
|
|
<InfoRow label="Nationality" value={client.nationality} />
|
|
|
|
|
<InfoRow label="Preferred Language" value={client.preferredLanguage} />
|
|
|
|
|
<InfoRow label="Timezone" value={client.timezone} />
|
2026-04-24 14:36:34 +02:00
|
|
|
<InfoRow label="Preferred Contact" value={client.preferredContactMethod} />
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
</dl>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Contacts */}
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<h3 className="text-sm font-medium mb-2">Contact Details</h3>
|
|
|
|
|
{client.contacts && client.contacts.length > 0 ? (
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
{client.contacts.map((c) => (
|
|
|
|
|
<div
|
|
|
|
|
key={c.id}
|
|
|
|
|
className="flex items-center gap-2 p-2 rounded-lg border bg-muted/30 text-sm"
|
|
|
|
|
>
|
2026-04-24 14:36:34 +02:00
|
|
|
<span className="capitalize text-muted-foreground w-20 shrink-0">{c.channel}</span>
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
<span className="flex-1">{c.value}</span>
|
|
|
|
|
{c.label && (
|
2026-04-24 14:36:34 +02:00
|
|
|
<span className="text-xs text-muted-foreground capitalize">{c.label}</span>
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
)}
|
2026-04-24 14:36:34 +02:00
|
|
|
{c.isPrimary && <span className="text-xs font-medium text-primary">Primary</span>}
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<p className="text-sm text-muted-foreground">No contacts added</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Source */}
|
|
|
|
|
{(client.source || client.sourceDetails) && (
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<h3 className="text-sm font-medium mb-2">Source</h3>
|
|
|
|
|
<dl>
|
|
|
|
|
<InfoRow label="Source" value={client.source} />
|
|
|
|
|
<InfoRow label="Source Details" value={client.sourceDetails} />
|
|
|
|
|
</dl>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-04-24 14:36:34 +02:00
|
|
|
{/* Tags */}
|
|
|
|
|
{client.tags && client.tags.length > 0 && (
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
<div className="space-y-1">
|
2026-04-24 14:36:34 +02:00
|
|
|
<h3 className="text-sm font-medium mb-2">Tags</h3>
|
|
|
|
|
<div className="flex flex-wrap gap-1">
|
|
|
|
|
{client.tags.map((tag) => (
|
|
|
|
|
<span
|
|
|
|
|
key={tag.id}
|
|
|
|
|
className="inline-block rounded-full px-2 py-0.5 text-xs font-medium"
|
|
|
|
|
style={{ backgroundColor: `${tag.color}20`, color: tag.color }}
|
|
|
|
|
>
|
|
|
|
|
{tag.name}
|
|
|
|
|
</span>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 14:36:34 +02:00
|
|
|
export function getClientTabs({ clientId, currentUserId, client }: ClientTabsOptions): DetailTab[] {
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
id: 'overview',
|
|
|
|
|
label: 'Overview',
|
|
|
|
|
content: <OverviewTab client={client} />,
|
|
|
|
|
},
|
2026-04-24 14:36:34 +02:00
|
|
|
{
|
|
|
|
|
id: 'yachts',
|
|
|
|
|
label: 'Yachts',
|
|
|
|
|
badge: client.yachts.length,
|
|
|
|
|
content: <ClientYachtsTab clientId={clientId} yachts={client.yachts} />,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'companies',
|
|
|
|
|
label: 'Companies',
|
|
|
|
|
badge: client.companies.length,
|
|
|
|
|
content: <ClientCompaniesTab clientId={clientId} companies={client.companies} />,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'reservations',
|
|
|
|
|
label: 'Reservations',
|
|
|
|
|
badge: client.activeReservations.length,
|
|
|
|
|
content: (
|
|
|
|
|
<ClientReservationsTab clientId={clientId} activeReservations={client.activeReservations} />
|
|
|
|
|
),
|
|
|
|
|
},
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
{
|
|
|
|
|
id: 'interests',
|
|
|
|
|
label: 'Interests',
|
|
|
|
|
content: (
|
|
|
|
|
<div className="text-center py-12 text-muted-foreground">
|
|
|
|
|
<p>Interests will appear here once created.</p>
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'notes',
|
|
|
|
|
label: 'Notes',
|
2026-04-24 14:36:34 +02:00
|
|
|
content: <NotesList entityType="clients" entityId={clientId} currentUserId={currentUserId} />,
|
Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM,
PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source
files covering clients, berths, interests/pipeline, documents/EOI,
expenses/invoices, email, notifications, dashboard, admin, and
client portal. CI/CD via Gitea Actions with Docker builds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:52:51 +01:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'files',
|
|
|
|
|
label: 'Files',
|
|
|
|
|
content: (
|
|
|
|
|
<div className="text-center py-12 text-muted-foreground">
|
|
|
|
|
<p>File attachments coming soon.</p>
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'activity',
|
|
|
|
|
label: 'Activity',
|
|
|
|
|
content: (
|
|
|
|
|
<div className="text-center py-12 text-muted-foreground">
|
|
|
|
|
<p>Activity log coming soon.</p>
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
}
|