fix(annotations): address code review findings (1-8, 10)

1. toggleVote wrapped in transaction (race condition fix)
2. FeedbackPanel fetch calls now surface errors via onError/toast
3. Extracted resolveBoard/hasCollectionRole to shared board-access.js
4. AnnotationStore uses monotonic version counter for snapshots
5. PinOverlay uses object pool instead of destroy/recreate on refresh
6. canvasObjects prop memoized with useMemo
7. PinOverlay store subscription cleaned up on unmount
8. Comment content capped at 5000 chars (backend validation)
10. anchor_type validated to 'object' or 'point'
This commit is contained in:
Hiren Kangad
2026-03-10 21:16:08 +05:30
parent 303124f518
commit f7a39a1726
9 changed files with 176 additions and 133 deletions
+10 -4
View File
@@ -355,13 +355,18 @@ export function useCanvasSetup(deps: CanvasSetupDeps) {
pinOverlayRef.current = pinOverlay;
// Refresh overlay on viewport move
viewport.on('moved', () => {
const onViewportMoved = () => {
if (pinOverlay.visible) pinOverlay.refresh();
});
// Refresh on store change
annotationStoreRef.current!.subscribe(() => {
};
viewport.on('moved', onViewportMoved);
// Refresh on store change (save unsub for cleanup)
const unsubPinOverlay = annotationStoreRef.current!.subscribe(() => {
if (pinOverlay.visible) pinOverlay.refresh();
});
(pinOverlay as any)._cleanup = () => {
viewport.off('moved', onViewportMoved);
unsubPinOverlay();
};
}
// Setup drag/drop and paste
@@ -394,6 +399,7 @@ export function useCanvasSetup(deps: CanvasSetupDeps) {
dropCleanupRef.current?.();
pasteCleanupRef.current?.();
if (pinOverlayRef.current) {
(pinOverlayRef.current as any)._cleanup?.();
pinOverlayRef.current.destroy();
pinOverlayRef.current = null;
}