Fix temporary annotation storage toast spam
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s
This commit is contained in:
parent
9aa98c892d
commit
e3d823d0b1
2 changed files with 43 additions and 9 deletions
|
|
@ -12,7 +12,10 @@ function markerLabel(index, marker, textContent) {
|
||||||
export function ImageAnnotationModule({ toolboxId, moduleId, context, editing, textExchangeOpen }) {
|
export function ImageAnnotationModule({ toolboxId, moduleId, context, editing, textExchangeOpen }) {
|
||||||
const data = context.normalizeImageAnnotationData(context.getModuleData(toolboxId, moduleId, { image: "", markers: [] }));
|
const data = context.normalizeImageAnnotationData(context.getModuleData(toolboxId, moduleId, { image: "", markers: [] }));
|
||||||
const textContent = context.moduleText?.imageAnnotation || {};
|
const textContent = context.moduleText?.imageAnnotation || {};
|
||||||
|
const notify = context.notify;
|
||||||
const previewMediaRef = useRef(null);
|
const previewMediaRef = useRef(null);
|
||||||
|
const temporaryDrawingsDirtyRef = useRef(false);
|
||||||
|
const sessionStorageFailureRef = useRef("");
|
||||||
const sessionKey = `sokkog:image-annotation-drawings:${toolboxId}:${moduleId}`;
|
const sessionKey = `sokkog:image-annotation-drawings:${toolboxId}:${moduleId}`;
|
||||||
const [dragOver, setDragOver] = useState(false);
|
const [dragOver, setDragOver] = useState(false);
|
||||||
const [drawingMode, setDrawingMode] = useState("permanent");
|
const [drawingMode, setDrawingMode] = useState("permanent");
|
||||||
|
|
@ -26,6 +29,8 @@ export function ImageAnnotationModule({ toolboxId, moduleId, context, editing, t
|
||||||
}), []);
|
}), []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
temporaryDrawingsDirtyRef.current = false;
|
||||||
|
sessionStorageFailureRef.current = "";
|
||||||
try {
|
try {
|
||||||
const stored = JSON.parse(sessionStorage.getItem(sessionKey) || "{\"strokes\":[]}");
|
const stored = JSON.parse(sessionStorage.getItem(sessionKey) || "{\"strokes\":[]}");
|
||||||
setTemporaryDrawings(stored?.strokes ? stored : { strokes: [] });
|
setTemporaryDrawings(stored?.strokes ? stored : { strokes: [] });
|
||||||
|
|
@ -36,12 +41,19 @@ export function ImageAnnotationModule({ toolboxId, moduleId, context, editing, t
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (drawingMode !== "temporary") return;
|
if (drawingMode !== "temporary") return;
|
||||||
|
if (!temporaryDrawingsDirtyRef.current) return;
|
||||||
|
const serializedDrawings = JSON.stringify(temporaryDrawings);
|
||||||
try {
|
try {
|
||||||
sessionStorage.setItem(sessionKey, JSON.stringify(temporaryDrawings));
|
sessionStorage.setItem(sessionKey, serializedDrawings);
|
||||||
|
temporaryDrawingsDirtyRef.current = false;
|
||||||
|
sessionStorageFailureRef.current = "";
|
||||||
} catch {
|
} catch {
|
||||||
context.notify?.(textContent.sessionStorageError || "Les annotations temporaires n'ont pas pu être sauvegardées.");
|
const failureKey = `${sessionKey}:${serializedDrawings}`;
|
||||||
|
if (sessionStorageFailureRef.current === failureKey) return;
|
||||||
|
sessionStorageFailureRef.current = failureKey;
|
||||||
|
notify?.(textContent.sessionStorageError || "Les annotations temporaires n'ont pas pu être sauvegardées.");
|
||||||
}
|
}
|
||||||
}, [context, drawingMode, sessionKey, temporaryDrawings, textContent.sessionStorageError]);
|
}, [drawingMode, notify, sessionKey, temporaryDrawings, textContent.sessionStorageError]);
|
||||||
|
|
||||||
function save(nextData) {
|
function save(nextData) {
|
||||||
context.setModuleData(toolboxId, moduleId, nextData);
|
context.setModuleData(toolboxId, moduleId, nextData);
|
||||||
|
|
@ -151,12 +163,18 @@ export function ImageAnnotationModule({ toolboxId, moduleId, context, editing, t
|
||||||
onChangeMarkers: (nextMarkers) => save({ ...data, markers: nextMarkers }),
|
onChangeMarkers: (nextMarkers) => save({ ...data, markers: nextMarkers }),
|
||||||
onChangeDrawings: (nextDrawings, nextMode = drawingMode) => {
|
onChangeDrawings: (nextDrawings, nextMode = drawingMode) => {
|
||||||
if (nextMode === "permanent") save({ ...data, drawings: nextDrawings });
|
if (nextMode === "permanent") save({ ...data, drawings: nextDrawings });
|
||||||
else setTemporaryDrawings(nextDrawings);
|
else {
|
||||||
|
temporaryDrawingsDirtyRef.current = true;
|
||||||
|
setTemporaryDrawings(nextDrawings);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onChangeDrawingMode: (nextMode, currentDrawings) => {
|
onChangeDrawingMode: (nextMode, currentDrawings) => {
|
||||||
setDrawingMode(nextMode);
|
setDrawingMode(nextMode);
|
||||||
if (nextMode === "permanent") save({ ...data, drawings: currentDrawings });
|
if (nextMode === "permanent") save({ ...data, drawings: currentDrawings });
|
||||||
else setTemporaryDrawings(currentDrawings);
|
else {
|
||||||
|
temporaryDrawingsDirtyRef.current = true;
|
||||||
|
setTemporaryDrawings(currentDrawings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
aria-label={textContent.previewAriaLabel || "Agrandir l'image annotée"}
|
aria-label={textContent.previewAriaLabel || "Agrandir l'image annotée"}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,15 @@ export function NotepadModule({ toolboxId, moduleId, context, textExchangeOpen }
|
||||||
const storedData = context.getModuleData(toolboxId, moduleId, { text: "" });
|
const storedData = context.getModuleData(toolboxId, moduleId, { text: "" });
|
||||||
const normalizedData = useMemo(() => context.normalizeNotepadData(storedData), [context, storedData]);
|
const normalizedData = useMemo(() => context.normalizeNotepadData(storedData), [context, storedData]);
|
||||||
const textContent = context.moduleText?.notepad || {};
|
const textContent = context.moduleText?.notepad || {};
|
||||||
|
const notify = context.notify;
|
||||||
const activePage = normalizedData.pages.find((page) => page.id === normalizedData.activePageId) || normalizedData.pages[0];
|
const activePage = normalizedData.pages.find((page) => page.id === normalizedData.activePageId) || normalizedData.pages[0];
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
const surfaceRef = useRef(null);
|
const surfaceRef = useRef(null);
|
||||||
const selectionOffsetRef = useRef(null);
|
const selectionOffsetRef = useRef(null);
|
||||||
const localSaveUpdatedAtRef = useRef("");
|
const localSaveUpdatedAtRef = useRef("");
|
||||||
const pageKeyRef = useRef(`${toolboxId}:${moduleId}:${activePage.id}`);
|
const pageKeyRef = useRef(`${toolboxId}:${moduleId}:${activePage.id}`);
|
||||||
|
const temporaryStrokesDirtyRef = useRef(false);
|
||||||
|
const sessionStorageFailureRef = useRef("");
|
||||||
const [html, setHtml] = useState(activePage.html);
|
const [html, setHtml] = useState(activePage.html);
|
||||||
const [text, setText] = useState(activePage.text);
|
const [text, setText] = useState(activePage.text);
|
||||||
const [updatedAt, setUpdatedAt] = useState(activePage.updatedAt);
|
const [updatedAt, setUpdatedAt] = useState(activePage.updatedAt);
|
||||||
|
|
@ -113,6 +116,8 @@ export function NotepadModule({ toolboxId, moduleId, context, textExchangeOpen }
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
temporaryStrokesDirtyRef.current = false;
|
||||||
|
sessionStorageFailureRef.current = "";
|
||||||
try {
|
try {
|
||||||
const stored = JSON.parse(sessionStorage.getItem(sessionKey) || "[]");
|
const stored = JSON.parse(sessionStorage.getItem(sessionKey) || "[]");
|
||||||
setTemporaryStrokes(Array.isArray(stored) ? stored : []);
|
setTemporaryStrokes(Array.isArray(stored) ? stored : []);
|
||||||
|
|
@ -123,12 +128,19 @@ export function NotepadModule({ toolboxId, moduleId, context, textExchangeOpen }
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (drawingMode !== "temporary") return;
|
if (drawingMode !== "temporary") return;
|
||||||
|
if (!temporaryStrokesDirtyRef.current) return;
|
||||||
|
const serializedStrokes = JSON.stringify(temporaryStrokes);
|
||||||
try {
|
try {
|
||||||
sessionStorage.setItem(sessionKey, JSON.stringify(temporaryStrokes));
|
sessionStorage.setItem(sessionKey, serializedStrokes);
|
||||||
|
temporaryStrokesDirtyRef.current = false;
|
||||||
|
sessionStorageFailureRef.current = "";
|
||||||
} catch {
|
} catch {
|
||||||
context.notify?.(textContent.sessionStorageError || "Les annotations temporaires n'ont pas pu être sauvegardées.");
|
const failureKey = `${sessionKey}:${serializedStrokes}`;
|
||||||
|
if (sessionStorageFailureRef.current === failureKey) return;
|
||||||
|
sessionStorageFailureRef.current = failureKey;
|
||||||
|
notify?.(textContent.sessionStorageError || "Les annotations temporaires n'ont pas pu être sauvegardées.");
|
||||||
}
|
}
|
||||||
}, [context, drawingMode, sessionKey, temporaryStrokes, textContent.sessionStorageError]);
|
}, [drawingMode, notify, sessionKey, temporaryStrokes, textContent.sessionStorageError]);
|
||||||
|
|
||||||
const activeStrokes = drawingMode === "permanent" ? activePage.drawings.strokes : temporaryStrokes;
|
const activeStrokes = drawingMode === "permanent" ? activePage.drawings.strokes : temporaryStrokes;
|
||||||
const formattedUpdatedAt = formatUpdatedAt(updatedAt);
|
const formattedUpdatedAt = formatUpdatedAt(updatedAt);
|
||||||
|
|
@ -160,7 +172,10 @@ export function NotepadModule({ toolboxId, moduleId, context, textExchangeOpen }
|
||||||
|
|
||||||
function saveDrawingMode(nextMode, nextStrokes) {
|
function saveDrawingMode(nextMode, nextStrokes) {
|
||||||
setDrawingMode(nextMode);
|
setDrawingMode(nextMode);
|
||||||
if (nextMode === "temporary") setTemporaryStrokes(nextStrokes);
|
if (nextMode === "temporary") {
|
||||||
|
temporaryStrokesDirtyRef.current = true;
|
||||||
|
setTemporaryStrokes(nextStrokes);
|
||||||
|
}
|
||||||
updateActivePage((page) => ({
|
updateActivePage((page) => ({
|
||||||
...page,
|
...page,
|
||||||
html,
|
html,
|
||||||
|
|
@ -182,6 +197,7 @@ export function NotepadModule({ toolboxId, moduleId, context, textExchangeOpen }
|
||||||
drawings: { strokes: nextStrokes }
|
drawings: { strokes: nextStrokes }
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
temporaryStrokesDirtyRef.current = true;
|
||||||
setTemporaryStrokes(nextStrokes);
|
setTemporaryStrokes(nextStrokes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue