import type { Project, ProjectProgram, ProjectSector } from '@/types'; export type { Project, ProjectProgram, ProjectSector } from '@/types'; /** * Portfolio helpers. The projects themselves are managed in the admin panel * and arrive as a page prop, already sorted newest first. */ /** Different names used over the years for the same institution. */ const clientAliases: Record = { 'Kementerian Investasi / Badan Koordinasi Penanaman Modal (BKPM)': 'Badan Koordinasi Penanaman Modal (BKPM)', 'Departemen Perdagangan Republik Indonesia': 'Kementerian Perdagangan', }; const clientName = (project: Project) => clientAliases[project.client] ?? project.client; /** Distinct clients, most frequent first. */ export const rankClients = (items: Project[]) => { const counts = new Map(); items.forEach((project) => { const name = clientName(project); counts.set(name, (counts.get(name) ?? 0) + 1); }); return [...counts.entries()] .sort((a, b) => b[1] - a[1]) .map(([name]) => name); }; export const bySector = (items: Project[], sector: ProjectSector) => items.filter((project) => project.sector === sector); export const inProgram = (items: Project[], program: ProjectProgram) => items.filter((project) => project.program === program); /** e.g. "2006 – 2025", or a single year when all projects share it. */ export const yearRange = (items: Project[]) => { if (items.length === 0) { return '–'; } const years = items.map((project) => project.year); const first = Math.min(...years); const last = Math.max(...years); return first === last ? `${first}` : `${first} – ${last}`; }; /** All portfolio numbers and lists derived from one set of projects. */ export const portfolio = (projects: Project[]) => ({ projects, projectCount: projects.length, clientCount: rankClients(projects).length, projectsBySector: (sector: ProjectSector) => bySector(projects, sector), projectsInProgram: (program: ProjectProgram) => inProgram(projects, program), clientsInSector: (sector: ProjectSector) => rankClients(bySector(projects, sector)), topClients: (limit: number) => rankClients(projects).slice(0, limit), }); export type Portfolio = ReturnType; /** Fills `{projects}` and `{clients}` placeholders in content strings. */ export const withCounts = (text: string, stats: Portfolio) => text .replaceAll('{projects}', String(stats.projectCount)) .replaceAll('{clients}', String(stats.clientCount)); /** Applies `withCounts` to every string in a content object. */ export function fillCounts(value: T, stats: Portfolio): T { if (typeof value === 'string') { return withCounts(value, stats) as T; } if (Array.isArray(value)) { return value.map((item: unknown) => fillCounts(item, stats)) as T; } if (value && typeof value === 'object') { return Object.fromEntries( Object.entries(value).map(([key, item]) => [ key, fillCounts(item, stats), ]), ) as T; } return value; }