diff --git a/src/components/privacy/PrivacyReleaseNotes.tsx b/src/components/privacy/PrivacyReleaseNotes.tsx new file mode 100644 index 00000000..98001017 --- /dev/null +++ b/src/components/privacy/PrivacyReleaseNotes.tsx @@ -0,0 +1,119 @@ +'use client'; + +import { useMemo, useState } from 'react'; + +export type ReleaseNoteKind = + | 'added' + | 'changed' + | 'fixed' + | 'security' + | 'deprecated'; + +export interface ReleaseNote { + kind: ReleaseNoteKind; + text: string; +} + +export interface PrivacyRelease { + version: string; + /** ISO date the release goes (or went) effective. */ + effectiveAt: string; + notes: ReleaseNote[]; +} + +const KIND_LABEL: Record = { + added: 'Added', + changed: 'Changed', + fixed: 'Fixed', + security: 'Security', + deprecated: 'Deprecated', +}; + +const KIND_COLOR: Record = { + added: 'bg-emerald-100 text-emerald-800', + changed: 'bg-blue-100 text-blue-800', + fixed: 'bg-amber-100 text-amber-800', + security: 'bg-rose-100 text-rose-800', + deprecated: 'bg-gray-200 text-gray-700', +}; + +export interface PrivacyReleaseNotesProps { + notes: PrivacyRelease[]; + /** Initial version expanded; defaults to the latest. */ + initialVersion?: string; +} + +function slug(version: string): string { + return version.replace(/[^a-z0-9]+/gi, '-').toLowerCase(); +} + +export default function PrivacyReleaseNotes({ + notes, + initialVersion, +}: PrivacyReleaseNotesProps) { + const sorted = useMemo( + () => [...notes].sort((a, b) => b.effectiveAt.localeCompare(a.effectiveAt)), + [notes], + ); + + const [openVersion, setOpenVersion] = useState( + initialVersion ?? sorted[0]?.version ?? null, + ); + + if (sorted.length === 0) { + return ( +

+ No privacy-policy release notes available. +

+ ); + } + + return ( +
+

Privacy Policy — Release Notes

+
    + {sorted.map((release) => { + const open = openVersion === release.version; + return ( +
  • + + {open ? ( +
      + {release.notes.map((n, idx) => ( +
    • + + {KIND_LABEL[n.kind]} + + {n.text} +
    • + ))} +
    + ) : null} +
  • + ); + })} +
+
+ ); +}