/** * What a client is shown for a shot. * * `Shot.clientCode` is the naming alias some productions supply — their own * code for the same shot. It already drives slates, overlay burn-ins and * delivered file names (RenderPipeline2 §11.2); internal paths, comp names and * every DB lookup stay on `shotCode`. * * The client portal is the other place the client's own naming belongs, and * that includes task titles: they follow the house convention * `UNG_102_019_010_cmp_TT_v004`, so the internal code is embedded in the * string the client reads and copies. * * Apply these at the API boundary rather than at each render site, so nothing * downstream has to remember which code it is holding. */ export interface ShotCodeFields { shotCode: string; clientCode?: string | null; } /** The shot's code as the client knows it; their alias if set, ours otherwise. */ export function clientShotCode(shot: ShotCodeFields): string { return shot.clientCode?.trim() || shot.shotCode; } /** * A task title with the internal shot code swapped for the client's alias. * * Titles are built from the shot code by convention, so this is a substring * swap rather than a rename — a title that does not contain the code (a * hand-edited one, say) is returned untouched rather than guessed at. */ export function clientTaskTitle(title: string, shot: ShotCodeFields): string { const alias = shot.clientCode?.trim(); if (!alias || !title || alias === shot.shotCode) return title; // split/join rather than a regex: shot codes are user-supplied and would // otherwise need escaping. return title.split(shot.shotCode).join(alias); }