Files
site-builder/craft/src/editor/DirtyTracker.tsx
T
shadowdaoandClaude Sonnet 5.5 9418444916 fix(site-builder): honest save state (dirty tracking, status pill, beforeunload, error notice)
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>
2026-10-07 10:07:03 -07:00

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;
};