diff --git a/artifacts/cra-app/src/pages/timesheet-detail.tsx b/artifacts/cra-app/src/pages/timesheet-detail.tsx index 192f2ae..956b0cc 100644 --- a/artifacts/cra-app/src/pages/timesheet-detail.tsx +++ b/artifacts/cra-app/src/pages/timesheet-detail.tsx @@ -58,10 +58,10 @@ export default function TimesheetDetailPage() { const deleteLine = useDeleteTimesheetLine(); const upsertEntries = useUpsertTimeEntries(); - // Local state for optimistic updates const [localEntries, setLocalEntries] = useState>({}); const [isAddingLine, setIsAddingLine] = useState(false); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); + const dirtyKeysRef = useRef>(new Set()); const { data: projects } = useListProjects({ query: { queryKey: getListProjectsQueryKey() } }); @@ -78,6 +78,7 @@ export default function TimesheetDetailPage() { }); setLocalEntries(initial); setHasUnsavedChanges(false); + dirtyKeysRef.current.clear(); } }, [timesheet]); @@ -114,10 +115,11 @@ export default function TimesheetDetailPage() { const entries = localEntriesRef.current; const entriesToSave: LocalEntry[] = []; + const dirty = dirtyKeysRef.current; Object.entries(entries).forEach(([key, hours]) => { const lineIdStr = key.split("-")[0]; const fullDate = key.substring(lineIdStr.length + 1); - if (hours > 0) { + if (hours > 0 || dirty.has(key)) { entriesToSave.push({ timesheetLineId: parseInt(lineIdStr), date: fullDate, @@ -134,6 +136,7 @@ export default function TimesheetDetailPage() { onSuccess: () => { setSaveStatus("saved"); setHasUnsavedChanges(false); + dirtyKeysRef.current.clear(); queryClient.invalidateQueries({ queryKey: getGetTimesheetQueryKey(timesheetId) }); setTimeout(() => setSaveStatus("idle"), 2000); }, @@ -148,6 +151,7 @@ export default function TimesheetDetailPage() { const key = `${lineId}-${dateStr}`; setLocalEntries(prev => ({ ...prev, [key]: hours })); setHasUnsavedChanges(true); + dirtyKeysRef.current.add(key); if (saveTimerRef.current) clearTimeout(saveTimerRef.current); saveTimerRef.current = setTimeout(() => doSave(), 800); @@ -181,11 +185,12 @@ export default function TimesheetDetailPage() { if (hasUnsavedChanges) { const entries = localEntriesRef.current; + const dirty = dirtyKeysRef.current; const entriesToSave: LocalEntry[] = []; Object.entries(entries).forEach(([key, hours]) => { const lineIdStr = key.split("-")[0]; const fullDate = key.substring(lineIdStr.length + 1); - if (hours > 0) { + if (hours > 0 || dirty.has(key)) { entriesToSave.push({ timesheetLineId: parseInt(lineIdStr), date: fullDate, hours }); } }); diff --git a/attached_assets/image_1776156391873.png b/attached_assets/image_1776156391873.png new file mode 100644 index 0000000..7d5b294 Binary files /dev/null and b/attached_assets/image_1776156391873.png differ