From c4b903bc497c8b805635fa8d04112f2630681c4d Mon Sep 17 00:00:00 2001 From: estifanos Date: Fri, 28 Aug 2026 11:33:07 +0000 Subject: [PATCH] feat: implement deterministic color-coding for licence type badges and update default scope badge style --- .../components/PersonalDocumentsCard.tsx | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/backoffice/src/app/features/certificate-requirements/components/PersonalDocumentsCard.tsx b/apps/backoffice/src/app/features/certificate-requirements/components/PersonalDocumentsCard.tsx index dfaa16175..b15a46869 100644 --- a/apps/backoffice/src/app/features/certificate-requirements/components/PersonalDocumentsCard.tsx +++ b/apps/backoffice/src/app/features/certificate-requirements/components/PersonalDocumentsCard.tsx @@ -46,6 +46,37 @@ const GLOBAL_ONLY = 'GLOBAL'; const SEARCH_DEBOUNCE_MS = 300; +/** + * Badge colours for licence types. + * + * Red and yellow are left out on purpose: they read as a problem, and a + * licence type is not one. Green is out too — it means verified elsewhere in + * the backoffice. + */ +const SCOPE_COLORS = [ + 'grape', + 'violet', + 'indigo', + 'cyan', + 'teal', + 'pink', + 'orange', + 'blue', +]; + +/** + * The same licence type keeps the same colour on every row and every visit — + * derived from its id rather than its position, so a colour is something the + * eye can learn instead of a lottery per render. + */ +function scopeColor(licenseTypeId: string): string { + let hash = 0; + for (let i = 0; i < licenseTypeId.length; i += 1) { + hash = (hash * 31 + licenseTypeId.charCodeAt(i)) % 997; + } + return SCOPE_COLORS[hash % SCOPE_COLORS.length]; +} + /** `application/vnd.openxmlformats-…-document` is nobody's idea of a column. */ const MIME_LABELS: Record = { 'application/pdf': 'PDF', @@ -168,13 +199,15 @@ export function PersonalDocumentsCard() { label: t('certReq.doc.scope', 'Applies to'), cell: ({ row }) => row.original.scope.length === 0 ? ( - + // Filled, where a licence type is outlined: "every licence" is a + // different kind of answer, not one more item in the same list. + {t('certReq.doc.scopeAll', 'All licences')} ) : ( {row.original.scope.map((id) => ( - + {typeName(id)} ))}