mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 19:01:02 +01:00
feat(unsaved-changes): implement utility for detecting and handling unsaved changes
This commit is contained in:
31
src/lib/client/ui/modal/UnsavedChangesModal.svelte
Normal file
31
src/lib/client/ui/modal/UnsavedChangesModal.svelte
Normal file
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { beforeNavigate, goto } from '$app/navigation';
|
||||
import Modal from './Modal.svelte';
|
||||
import { useUnsavedChanges } from '$lib/client/utils/unsavedChanges.svelte';
|
||||
|
||||
const unsavedChanges = useUnsavedChanges();
|
||||
let pendingNavigationUrl: string | null = null;
|
||||
|
||||
beforeNavigate(async (navigation) => {
|
||||
if (unsavedChanges.isDirty) {
|
||||
navigation.cancel();
|
||||
pendingNavigationUrl = navigation.to?.url.pathname || null;
|
||||
const shouldNavigate = await unsavedChanges.confirmNavigation();
|
||||
if (shouldNavigate && pendingNavigationUrl) {
|
||||
goto(pendingNavigationUrl);
|
||||
}
|
||||
pendingNavigationUrl = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
open={unsavedChanges.showModal}
|
||||
header="Unsaved Changes"
|
||||
bodyMessage="You have unsaved changes. Are you sure you want to leave this page? Your changes will be lost."
|
||||
confirmText="Discard Changes"
|
||||
cancelText="Stay on Page"
|
||||
confirmDanger={true}
|
||||
on:confirm={() => unsavedChanges.confirmDiscard()}
|
||||
on:cancel={() => unsavedChanges.cancelDiscard()}
|
||||
/>
|
||||
78
src/lib/client/utils/unsavedChanges.svelte.ts
Normal file
78
src/lib/client/utils/unsavedChanges.svelte.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Utility for detecting and handling unsaved changes
|
||||
*/
|
||||
|
||||
let hasUnsavedChanges = $state(false);
|
||||
let showWarningModal = $state(false);
|
||||
let resolveNavigation: ((value: boolean) => void) | null = null;
|
||||
|
||||
export function useUnsavedChanges() {
|
||||
return {
|
||||
/**
|
||||
* Mark the page as having unsaved changes
|
||||
*/
|
||||
markDirty() {
|
||||
hasUnsavedChanges = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark the page as clean (changes saved)
|
||||
*/
|
||||
markClean() {
|
||||
hasUnsavedChanges = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if there are unsaved changes
|
||||
*/
|
||||
get isDirty() {
|
||||
return hasUnsavedChanges;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get modal state
|
||||
*/
|
||||
get showModal() {
|
||||
return showWarningModal;
|
||||
},
|
||||
|
||||
/**
|
||||
* Request navigation confirmation
|
||||
* Returns a promise that resolves to true if navigation should proceed
|
||||
*/
|
||||
confirmNavigation(): Promise<boolean> {
|
||||
if (!hasUnsavedChanges) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
showWarningModal = true;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
resolveNavigation = resolve;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* User confirmed navigation (discard changes)
|
||||
*/
|
||||
confirmDiscard() {
|
||||
showWarningModal = false;
|
||||
hasUnsavedChanges = false;
|
||||
if (resolveNavigation) {
|
||||
resolveNavigation(true);
|
||||
resolveNavigation = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* User cancelled navigation (stay on page)
|
||||
*/
|
||||
cancelDiscard() {
|
||||
showWarningModal = false;
|
||||
if (resolveNavigation) {
|
||||
resolveNavigation(false);
|
||||
resolveNavigation = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user