Track dirty from Craft node changes and page/design/header/footer state, cleared only by a successful save. Persistent Unsaved/Saving/Saved/Published/Save failed pill, beforeunload prompt while dirty or saving, one persistent error notice, resp.ok/non-JSON handling for save and publish, and publish refuses to run after a failed save. Draft badge no longer flips on a no-op autosave. Refs #30 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
34 lines
1.1 KiB
TypeScript
34 lines
1.1 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { useEditorConfig } from '../state/EditorConfigContext';
|
|
import { useSaveGuard } from '../state/SaveGuardContext';
|
|
import { usePages } from '../state/PageContext';
|
|
import { useSiteDesign } from '../state/SiteDesignContext';
|
|
|
|
/**
|
|
* Marks the editor dirty when page, header/footer or design state changes
|
|
* after the site has loaded. Canvas edits arrive separately, through the
|
|
* `<Editor onNodesChange>` hook in App.tsx. Renders nothing.
|
|
*/
|
|
export const DirtyTracker: React.FC = () => {
|
|
const { isWHP } = useEditorConfig();
|
|
const { loadState, markDirty } = useSaveGuard();
|
|
const { pages, headerPage, footerPage } = usePages();
|
|
const { design } = useSiteDesign();
|
|
const armedRef = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (!isWHP || loadState !== 'loaded') {
|
|
armedRef.current = false;
|
|
return;
|
|
}
|
|
// The first pass after a load only records the loaded state as the baseline.
|
|
if (!armedRef.current) {
|
|
armedRef.current = true;
|
|
return;
|
|
}
|
|
markDirty();
|
|
}, [isWHP, loadState, pages, headerPage, footerPage, design, markDirty]);
|
|
|
|
return null;
|
|
};
|