Files
app/src/admin/components/PlanRangeChips.tsx
BOHA 519edce373 fix: 2026-06-09 full-codebase audit hardening
Validation: shared NaN-guarded Zod coercion helpers in schemas/common.ts replace
the raw number|string transform idiom across every schema (the root-cause NaN bug
class); emailOrEmpty + lenient isoDateString/timeString.

Security: roles privilege-escalation closed; refresh-token family revocation on
reuse; TOTP uses config params; read endpoints permission-guarded; received-invoices
gross VAT on all paths; orders-pdf custom-items authz.

Concurrency: $queryRaw SELECT...FOR UPDATE locks in ascending-id order (warehouse
confirm/cancel, attendance lockUserRow); uniqueness checks moved into create
transactions (TOCTOU -> 409); deterministic id tiebreak on second-precision
timestamp ordering (plan resolveCell/resolveGrid, warehouse FIFO).

Frontend: Rules-of-Hooks fixed across ~14 pages + PlanCellModal; UTC-date persisted
fields; dashboard invalidation gaps; stale-closure confirm bugs.

Tooling/tests: ESLint flat config (react-hooks/rules-of-hooks = error) + Prettier;
tsconfig.test.json so tsc -b type-checks the tests; removed 3 dead deps; npm audit
fix (8 -> 3). Suite 195 -> 247 (happy-path auth, FIFO oldest-first, flakiness fixes),
isolated on app_test via .env.test with a hard-throw setup guard.

Gates: tsc 0 | build 0 | vitest 247/247 | eslint 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 06:45:26 +02:00

44 lines
1.5 KiB
TypeScript

import { ResolvedCell, cellProjectLabel } from "../lib/queries/plan";
import type { Project } from "../lib/queries/projects";
interface Props {
cell: ResolvedCell | null;
project: Project | null;
categoryLabel: string;
}
// Purely presentational — renders the category/project chips and note for a
// single resolved plan cell. It has no interactive handlers of its own (the
// click target is the cell <button> in PlanGrid, which already applies the
// read-only styling/behaviour), so there is no read-only state to gate here.
export default function PlanRangeChips({
cell,
project,
categoryLabel,
}: Props) {
if (!cell) return null;
// Prefer the server-embedded project label (always present). Fall back to
// the looked-up `project` prop only if the cell predates the embed (stale
// cache).
const fallbackLabel = project
? project.project_number
? `${project.project_number}${project.name}`
: project.name
: null;
const projectLabel = cellProjectLabel(cell) ?? fallbackLabel;
const projectTitle = projectLabel ?? undefined;
return (
<div className="plan-chip-block">
<div className="plan-chip-line">
<span className="plan-chip">{categoryLabel}</span>
{projectLabel && (
<span className="plan-chip-project" title={projectTitle}>
{projectLabel}
</span>
)}
</div>
{cell.note && <div className="plan-cell-note">{cell.note}</div>}
</div>
);
}