diff --git a/backlog/tasks/task-053 - Fix-user-identity-caching-on-logout-login.md b/backlog/tasks/task-053 - Fix-user-identity-caching-on-logout-login.md deleted file mode 100644 index 7683d0d..0000000 --- a/backlog/tasks/task-053 - Fix-user-identity-caching-on-logout-login.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -id: task-053 -title: Fix user identity caching on logout/login -status: Done -assignee: [] -created_date: '2025-12-15 23:40' -updated_date: '2025-12-15 23:40' -labels: - - bug-fix - - auth - - presence -dependencies: [] -priority: high ---- - -## Description - - -Fixed issues with user identity state not being properly cleared/restored during logout and login cycles, causing duplicate cursors and stale presence data in the social network graph. - - -## Acceptance Criteria - -- [x] #1 Crypto keys and tldraw user IDs persist across logout (account data) -- [x] #2 Session-specific data cleared on logout (permissions, graph cache) -- [x] #3 No duplicate cursors when logging out and back in -- [x] #4 Tools load properly after login from logged-out state -- [x] #5 CryptIDDropdown and NetworkGraph reset state on logout - - -## Implementation Notes - - -Implemented in commits df80a3f and related changes to Board.tsx. - -Key changes: -- sessionPersistence.ts: Added session-logged-in and session-cleared events, preserve tldraw user IDs and crypto keys on logout -- Board.tsx: Check localStorage directly for auth in onMount, listen for session events -- CryptIDDropdown.tsx: Clear connections state on logout -- useNetworkGraph.ts: Clear graph cache on logout - -The root cause was clearing tldraw-user-id-* keys on logout, which created new presence IDs on each login while old presence records persisted in Automerge. - diff --git a/src/components/StandardizedToolWrapper.tsx b/src/components/StandardizedToolWrapper.tsx index a62c9d3..8341c6e 100644 --- a/src/components/StandardizedToolWrapper.tsx +++ b/src/components/StandardizedToolWrapper.tsx @@ -64,8 +64,6 @@ export interface StandardizedToolWrapperProps { onTagsChange?: (tags: string[]) => void /** Whether tags can be edited */ tagsEditable?: boolean - /** Zoom level when the shape was pinned (for constant visual size) */ - pinnedAtZoom?: number } /** @@ -92,67 +90,13 @@ export const StandardizedToolWrapper: React.FC = ( tags = [], onTagsChange, tagsEditable = true, - pinnedAtZoom, }) => { const [isHoveringHeader, setIsHoveringHeader] = useState(false) const [isEditingTags, setIsEditingTags] = useState(false) const [editingTagInput, setEditingTagInput] = useState('') - const [zoomScale, setZoomScale] = useState(1) const tagInputRef = useRef(null) const isDarkMode = useIsDarkMode() - // Calculate zoom compensation scale when pinned - useEffect(() => { - if (!isPinnedToView || !editor) { - setZoomScale(1) - return - } - - // Get pinnedAtZoom from shape meta if not passed as prop - let originalZoom = pinnedAtZoom - if (!originalZoom && shapeId) { - const shape = editor.getShape(shapeId) - originalZoom = (shape?.meta as any)?.pinnedAtZoom - } - - if (!originalZoom) { - setZoomScale(1) - return - } - - const updateScale = () => { - const currentZoom = editor.getCamera().z - // Scale inversely to zoom to maintain constant visual size - const scale = originalZoom / currentZoom - setZoomScale(scale) - } - - // Initial scale calculation - updateScale() - - // Listen for camera changes - const handleChange = () => { - updateScale() - } - - // Use requestAnimationFrame for smooth updates - let rafId: number | null = null - const throttledUpdate = () => { - if (rafId) return - rafId = requestAnimationFrame(() => { - updateScale() - rafId = null - }) - } - - editor.on('change' as any, throttledUpdate) - - return () => { - editor.off('change' as any, throttledUpdate) - if (rafId) cancelAnimationFrame(rafId) - } - }, [isPinnedToView, editor, shapeId, pinnedAtZoom]) - // Handle Esc key to exit maximize mode useEffect(() => { if (!isMaximized || !onMaximize) return @@ -229,11 +173,6 @@ export const StandardizedToolWrapper: React.FC = ( ? `${primaryColor}15` // 15% opacity : `${primaryColor}10` // 10% opacity - // Calculate transform for pinned shapes - const pinnedTransform = isPinnedToView && zoomScale !== 1 - ? `scale(${zoomScale})` - : undefined - const wrapperStyle: React.CSSProperties = { width: typeof width === 'number' ? `${width}px` : width, height: isMinimized ? 40 : (typeof height === 'number' ? `${height}px` : height), // Minimized height is just the header @@ -251,9 +190,6 @@ export const StandardizedToolWrapper: React.FC = ( pointerEvents: 'auto', transition: isPinnedToView ? 'box-shadow 0.2s ease' : 'height 0.2s ease, box-shadow 0.2s ease', boxSizing: 'border-box', - // Apply zoom compensation transform for pinned shapes - transform: pinnedTransform, - transformOrigin: 'top left', } const headerStyle: React.CSSProperties = {