'use client' /** * This Source Code is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright (c) Infonomic Company Limited */ import { useEffect, useState } from 'react' import { useTranslation } from '@byline/i18n/react' import { CloseIcon, IconButton, LoaderRing, Modal } from '@byline/ui/react' import cx from 'clsx' import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer-continued' import styles from './diff-modal.module.css' // Keys that are per-version metadata rather than content — strip before diffing // so the diff focuses on meaningful content changes. ClientDocument-shape // metadata keys after the Phase 7 admin migration. const STRIP_KEYS = new Set([ 'id', 'versionId', 'path', 'status', 'createdAt', 'updatedAt', 'hasPublishedVersion', '_publishedVersion', ]) function stripMeta(doc: Record): Record { // With the nested document shape, extract just the fields for diffing. if (doc.fields && typeof doc.fields === 'object') { return doc.fields as Record } return Object.fromEntries(Object.entries(doc).filter(([k]) => !STRIP_KEYS.has(k))) } export interface DiffModalProps { isOpen: boolean onDismiss: () => void collection: string documentId: string /** The `versionId` of the historical version to compare. */ versionId: string /** A human-readable label for the historical version (e.g. a date string). */ versionLabel: string /** The already-loaded current (latest) version of the document. */ currentDocument: Record /** Content locale to compare — undefined / 'all' shows all locales. */ locale?: string /** * Host-provided loader for a historical document version. The diff * modal is framework-neutral; callers wire this to whatever transport * they use (e.g. `BylineAdminServices.getCollectionDocumentVersion` in * the admin shell). */ loadHistoricalVersion: ( collection: string, documentId: string, versionId: string, locale: string | undefined ) => Promise> } export function DiffModal({ isOpen, onDismiss, collection, documentId, versionId, versionLabel, currentDocument, locale, loadHistoricalVersion, }: DiffModalProps) { const { t } = useTranslation('byline-admin') const [historicalDoc, setHistoricalDoc] = useState | null>(null) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) useEffect(() => { if (!isOpen || !versionId) return let cancelled = false setLoading(true) setError(null) setHistoricalDoc(null) loadHistoricalVersion(collection, documentId, versionId, locale) .then((doc) => { if (cancelled) return setHistoricalDoc(doc) }) .catch((err) => { if (cancelled) return setError(err instanceof Error ? err.message : t('diffModal.loadFailed')) }) .finally(() => { if (!cancelled) setLoading(false) }) return () => { cancelled = true } }, [isOpen, collection, documentId, versionId, locale, loadHistoricalVersion, t]) const currentStr = currentDocument ? JSON.stringify(stripMeta(currentDocument), null, 2) : '' const historicalStr = historicalDoc ? JSON.stringify(stripMeta(historicalDoc), null, 2) : '' return (

{t('diffModal.title')}

{t('diffModal.subtitleBefore')}{' '} {versionLabel} {' '} {t('diffModal.subtitleAfter')}

{loading && (
{t('diffModal.loading')}
)} {error && (
{error}
)} {!loading && !error && historicalDoc && (
)}
) }