Don't let user close browser window if they have unsaved changes (vibe-kanban) (#538)

* Perfect! The implementation is complete and passes all checks. 

## Summary

Added browser window close protection to prevent data loss when users have unsaved changes in the task dialog:

- **Added `beforeunload` event listener** in [`TaskFormDialog.tsx`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/vk-f59b-don-t-let/frontend/src/components/tasks/TaskFormDialog.tsx#L95-L111)
- **Integrates with existing `hasUnsavedChanges()` logic** - no duplication
- **Only active when dialog is open AND has unsaved content** 
- **Automatic cleanup** when dialog closes or changes are saved
- **Browser-standard confirmation dialog** appears when user tries to close tab/window

The feature now protects against data loss from both dialog close (existing) and browser window close (new) scenarios.

* Cleanup script changes for task attempt f59bea00-6158-4cdd-ad19-1f30e40c1324

* Perfect! Now the browser window close protection works for both scenarios:

## Updated Implementation

**Create mode:** Warns when user has entered title or description content
**Edit mode:** Warns when user has modified title, description, or status from original values

The `beforeunload` event will now trigger when:
- **Creating a task** and typing content, then trying to close browser
- **Editing a task** and changing any field, then trying to close browser

Both the existing dialog close warning and new browser window close warning now protect against data loss in all editing scenarios.

* Cleanup script changes for task attempt f59bea00-6158-4cdd-ad19-1f30e40c1324
This commit is contained in:
Louis Knight-Webb
2025-08-20 15:44:38 +01:00
committed by GitHub
parent e99f9807fb
commit 6fb7b939d9
2 changed files with 29 additions and 4 deletions

View File

@@ -82,13 +82,38 @@ export function TaskFormDialog({
// Check if there's any content that would be lost
const hasUnsavedChanges = useCallback(() => {
// Only warn in create mode when there's content
if (!isEditMode) {
// Create mode - warn when there's content
return title.trim() !== '' || description.trim() !== '';
} else if (task) {
// Edit mode - warn when current values differ from original task
const titleChanged = title.trim() !== task.title.trim();
const descriptionChanged =
(description || '').trim() !== (task.description || '').trim();
const statusChanged = status !== task.status;
return titleChanged || descriptionChanged || statusChanged;
}
// No warning for edit mode - users can always reopen the task
return false;
}, [title, description, isEditMode]);
}, [title, description, status, isEditMode, task]);
// Warn on browser/tab close if there are unsaved changes
useEffect(() => {
if (!isOpen) return; // dialog closed → nothing to do
// always re-evaluate latest fields via hasUnsavedChanges()
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
if (hasUnsavedChanges()) {
e.preventDefault();
// Chrome / Edge still require returnValue to be set
e.returnValue = '';
return '';
}
// nothing returned → no prompt
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
}, [isOpen, hasUnsavedChanges]); // hasUnsavedChanges is memoised with title/descr deps
useEffect(() => {
if (task) {