import { Badge } from '@/components/ui/badge';
import { Plus, Minus, Edit, Check } from 'lucide-react';
import { formatFieldValue } from '@/lib/submissionChangeDetection';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
interface ArrayFieldDiffProps {
fieldName: string;
oldArray: unknown[];
newArray: unknown[];
compact?: boolean;
}
interface ArrayDiffItem {
type: 'added' | 'removed' | 'modified' | 'unchanged';
oldValue?: unknown;
newValue?: unknown;
index: number;
}
export function ArrayFieldDiff({ fieldName, oldArray, newArray, compact = false }: ArrayFieldDiffProps) {
const [showUnchanged, setShowUnchanged] = useState(false);
// Compute array differences
const differences = computeArrayDiff(oldArray || [], newArray || []);
const changedItems = differences.filter(d => d.type !== 'unchanged');
const unchangedCount = differences.filter(d => d.type === 'unchanged').length;
const totalChanges = changedItems.length;
if (compact) {
return (
{fieldName} ({totalChanges} changes)
);
}
return (
{fieldName} ({differences.length} items, {totalChanges} changed)
{unchangedCount > 0 && (
)}
{differences.map((diff, idx) => {
if (diff.type === 'unchanged' && !showUnchanged) {
return null;
}
return (
);
})}
);
}
function ArrayDiffItemDisplay({ diff }: { diff: ArrayDiffItem }) {
const isObject = typeof diff.newValue === 'object' || typeof diff.oldValue === 'object';
switch (diff.type) {
case 'added':
return (
{isObject ? (
) : (
{formatFieldValue(diff.newValue)}
)}
);
case 'removed':
return (
{isObject ? (
) : (
{formatFieldValue(diff.oldValue)}
)}
);
case 'modified':
return (
{isObject ? (
) : (
formatFieldValue(diff.oldValue)
)}
{isObject ? (
) : (
formatFieldValue(diff.newValue)
)}
);
case 'unchanged':
return (
{isObject ? (
) : (
formatFieldValue(diff.newValue)
)}
);
}
}
function ObjectDisplay({ value, className = '' }: { value: unknown; className?: string }) {
if (!value || typeof value !== 'object') {
return {formatFieldValue(value)};
}
return (
{Object.entries(value).map(([key, val]) => (
{key.replace(/_/g, ' ')}:
{formatFieldValue(val)}
))}
);
}
/**
* Compute differences between two arrays
*/
function computeArrayDiff(oldArray: unknown[], newArray: unknown[]): ArrayDiffItem[] {
const results: ArrayDiffItem[] = [];
const maxLength = Math.max(oldArray.length, newArray.length);
// Simple position-based comparison
for (let i = 0; i < maxLength; i++) {
const oldValue = i < oldArray.length ? oldArray[i] : undefined;
const newValue = i < newArray.length ? newArray[i] : undefined;
if (oldValue === undefined && newValue !== undefined) {
// Added
results.push({ type: 'added', newValue, index: i });
} else if (oldValue !== undefined && newValue === undefined) {
// Removed
results.push({ type: 'removed', oldValue, index: i });
} else if (!isEqual(oldValue, newValue)) {
// Modified
results.push({ type: 'modified', oldValue, newValue, index: i });
} else {
// Unchanged
results.push({ type: 'unchanged', oldValue, newValue, index: i });
}
}
return results;
}
/**
* Deep equality check
*/
function isEqual(a: unknown, b: unknown): boolean {
if (a === b) return true;
if (a == null || b == null) return a === b;
if (typeof a !== typeof b) return false;
if (typeof a === 'object') {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
return a.every((item, i) => isEqual(item, b[i]));
}
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
return keysA.every(key => isEqual(a[key], b[key]));
}
return false;
}