diff --git a/src/app/(admin)/admin/projects/[id]/page.tsx b/src/app/(admin)/admin/projects/[id]/page.tsx index 421ad62..5c74dd4 100644 --- a/src/app/(admin)/admin/projects/[id]/page.tsx +++ b/src/app/(admin)/admin/projects/[id]/page.tsx @@ -677,6 +677,13 @@ function ProjectDetailContent({ projectId }: { projectId: string }) { detectedLang: f.detectedLang, langConfidence: f.langConfidence, analyzedAt: f.analyzedAt ? String(f.analyzedAt) : null, + requirementId: f.requirementId, + requirement: f.requirement ? { + id: f.requirement.id, + name: f.requirement.name, + description: f.requirement.description, + isRequired: f.requirement.isRequired, + } : null, }))} /> diff --git a/src/app/(admin)/admin/rounds/[roundId]/page.tsx b/src/app/(admin)/admin/rounds/[roundId]/page.tsx index 23590cd..1797999 100644 --- a/src/app/(admin)/admin/rounds/[roundId]/page.tsx +++ b/src/app/(admin)/admin/rounds/[roundId]/page.tsx @@ -6,7 +6,6 @@ import Link from 'next/link' import type { Route } from 'next' import { trpc } from '@/lib/trpc/client' import { toast } from 'sonner' -import { useDebouncedCallback } from 'use-debounce' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -167,7 +166,6 @@ export default function RoundDetailPage() { const [config, setConfig] = useState>({}) const [autosaveStatus, setAutosaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle') - const pendingSaveRef = useRef(false) const [activeTab, setActiveTab] = useState('overview') const [previewSheetOpen, setPreviewSheetOpen] = useState(false) @@ -239,28 +237,29 @@ export default function RoundDetailPage() { { enabled: round?.roundType === 'FILTERING', refetchInterval: 5_000 }, ) - // Sync config from server when no pending save - if (round && !pendingSaveRef.current) { + // Initialize config from server once on load (or when round changes externally) + const serverConfig = useMemo(() => (round?.configJson as Record) ?? {}, [round?.configJson]) + const configInitialized = useRef(false) + if (round && !configInitialized.current) { const roundConfig = (round.configJson as Record) ?? {} - if (JSON.stringify(roundConfig) !== JSON.stringify(config)) { + if (Object.keys(config).length === 0 || JSON.stringify(roundConfig) !== JSON.stringify(config)) { setConfig(roundConfig) } + configInitialized.current = true } + const hasUnsavedConfig = useMemo( + () => configInitialized.current && JSON.stringify(config) !== JSON.stringify(serverConfig), + [config, serverConfig], + ) // ── Mutations ────────────────────────────────────────────────────────── const updateMutation = trpc.round.update.useMutation({ onSuccess: () => { utils.round.getById.invalidate({ id: roundId }) setAutosaveStatus('saved') - // Keep pendingSaveRef locked briefly so the sync block doesn't - // overwrite local config with stale cache before refetch completes - setTimeout(() => { - pendingSaveRef.current = false - }, 500) setTimeout(() => setAutosaveStatus('idle'), 2000) }, onError: (err) => { - pendingSaveRef.current = false setAutosaveStatus('error') toast.error(err.message) }, @@ -389,17 +388,14 @@ export default function RoundDetailPage() { const isTransitioning = activateMutation.isPending || closeMutation.isPending || reopenMutation.isPending || archiveMutation.isPending - const debouncedSave = useDebouncedCallback((newConfig: Record) => { - setAutosaveStatus('saving') - updateMutation.mutate({ id: roundId, configJson: newConfig }) - }, 1500) - const handleConfigChange = useCallback((newConfig: Record) => { setConfig(newConfig) - pendingSaveRef.current = true + }, []) + + const saveConfig = useCallback(() => { setAutosaveStatus('saving') - debouncedSave(newConfig) - }, [debouncedSave]) + updateMutation.mutate({ id: roundId, configJson: config }) + }, [config, roundId, updateMutation]) // ── Computed values ──────────────────────────────────────────────────── const projectCount = round?._count?.projectRoundStates ?? 0 @@ -603,24 +599,12 @@ export default function RoundDetailPage() { {/* Action buttons */}
- {autosaveStatus === 'saving' && ( - - - Saving... - - )} {autosaveStatus === 'saved' && ( Saved )} - {autosaveStatus === 'error' && ( - - - Save failed - - )} + +
+ + + )} ) } diff --git a/src/components/shared/file-viewer.tsx b/src/components/shared/file-viewer.tsx index 869403e..2935017 100644 --- a/src/components/shared/file-viewer.tsx +++ b/src/components/shared/file-viewer.tsx @@ -258,6 +258,11 @@ function FileItem({ file }: { file: ProjectFile }) {
+ {file.requirement && ( +

+ {file.requirement.name} +

+ )}

{file.fileName}

{file.version != null && file.version > 1 && (