diff --git a/src/components/companies/company-columns.tsx b/src/components/companies/company-columns.tsx index 869041b..61a7099 100644 --- a/src/components/companies/company-columns.tsx +++ b/src/components/companies/company-columns.tsx @@ -4,6 +4,7 @@ import Link from 'next/link'; import { MoreHorizontal, Pencil, Archive, Eye } from 'lucide-react'; import type { ColumnDef } from '@tanstack/react-table'; +import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { DropdownMenu, @@ -12,7 +13,6 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; -// TODO: add member/yacht counts once the list endpoint returns them via a join. export interface CompanyRow { id: string; name: string; @@ -27,6 +27,8 @@ export interface CompanyRow { archivedAt: string | null; createdAt: string; updatedAt: string; + memberCount?: number; + yachtCount?: number; } const STATUS_COLORS: Record = { @@ -88,6 +90,28 @@ export function getCompanyColumns({ return {value}; }, }, + { + id: 'memberCount', + header: 'Members', + enableSorting: false, + size: 88, + cell: ({ row }) => { + const n = row.original.memberCount ?? 0; + if (n === 0) return ; + return {n}; + }, + }, + { + id: 'yachtCount', + header: 'Yachts', + enableSorting: false, + size: 88, + cell: ({ row }) => { + const n = row.original.yachtCount ?? 0; + if (n === 0) return ; + return {n}; + }, + }, { id: 'status', accessorKey: 'status', diff --git a/src/lib/services/companies.service.ts b/src/lib/services/companies.service.ts index f902f7f..d2ec681 100644 --- a/src/lib/services/companies.service.ts +++ b/src/lib/services/companies.service.ts @@ -1,7 +1,8 @@ -import { and, eq, ilike, or, sql } from 'drizzle-orm'; +import { and, count, eq, ilike, inArray, isNull, or, sql } from 'drizzle-orm'; import { db } from '@/lib/db'; -import { companies, companyTags } from '@/lib/db/schema/companies'; +import { companies, companyMemberships, companyTags } from '@/lib/db/schema/companies'; import type { Company } from '@/lib/db/schema/companies'; +import { yachts } from '@/lib/db/schema/yachts'; import { withTransaction } from '@/lib/db/utils'; import { buildListQuery } from '@/lib/db/query-builder'; import { createAuditLog } from '@/lib/audit'; @@ -238,7 +239,41 @@ export async function listCompanies(portId: string, query: ListCompaniesInput) { archivedAtColumn: companies.archivedAt, }); - return result; + if (result.data.length === 0) return result; + + const ids = result.data.map((r) => r.id); + + const [memberCounts, yachtCounts] = await Promise.all([ + db + .select({ companyId: companyMemberships.companyId, count: count() }) + .from(companyMemberships) + .where(and(inArray(companyMemberships.companyId, ids), isNull(companyMemberships.endDate))) + .groupBy(companyMemberships.companyId), + db + .select({ ownerId: yachts.currentOwnerId, count: count() }) + .from(yachts) + .where( + and( + eq(yachts.portId, portId), + eq(yachts.currentOwnerType, 'company'), + inArray(yachts.currentOwnerId, ids), + isNull(yachts.archivedAt), + ), + ) + .groupBy(yachts.currentOwnerId), + ]); + + const memberCountMap = new Map(memberCounts.map((r) => [r.companyId, r.count])); + const yachtCountMap = new Map(yachtCounts.map((r) => [r.ownerId, r.count])); + + return { + ...result, + data: result.data.map((row) => ({ + ...row, + memberCount: memberCountMap.get(row.id) ?? 0, + yachtCount: yachtCountMap.get(row.id) ?? 0, + })), + }; } // ─── Autocomplete ────────────────────────────────────────────────────────────