diff --git a/CLAUDE.md b/CLAUDE.md index 982ba69..e9ab4ca 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -260,7 +260,7 @@ into `configurePreviewServer` so `yarn preview` keeps working. | Zustand | `NavigatorRoomCreatorView` (`useRoomCreatorStore`) | | God-hook split (state + actions + shim) | `doorbell`, `poll`, `furni-chooser`, `user-chooser`, `friend-request`, `chat-input` | | God-hook split (`useBetween` singleton + state filter + actions filter + shim) | `wired-tools`, `translation`, `notification`, `friends`, `catalog` (three-way: `useCatalogData` / `useCatalogUiState` / `useCatalogActions` — all 48 consumers migrated, deprecated `useCatalog` shim removed) | -| `WidgetErrorBoundary` | `RoomWidgetsView` umbrella | +| `WidgetErrorBoundary` | `RoomWidgetsView` umbrella + per-widget wrap on all 13 room widgets and all 20 furniture widgets (so a crash in one widget no longer takes down its siblings) | | Vitest | 162/162 cases — pure helpers + Zustand store + 2 component-/hook-level pilots (WidgetErrorBoundary, useDoorbellState) on top of the renderer-SDK mock at `tests/mocks/renderer-mock.ts`, 34 cases on the catalog pure helpers, 4 contract cases on the catalog filters | | Form Actions | Login / Register / Forgot (LoginView.tsx) | | Cherry-picked from `duckietm` PR #126 | `UserAccountSettingsView` (reset password / email / username under user settings), plus the wear-badge popup `canShowWearButton` gating | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 18193a8..a305cea 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -302,12 +302,12 @@ takes down the whole UI. Implementation lives at `src/common/error-boundary/WidgetErrorBoundary.tsx`. **Status.** Implemented + applied to `RoomWidgetsView` as the umbrella for -all in-room widgets. A widget crash now degrades gracefully (the offending -widget disappears) instead of unmounting the room. - -A more granular pass could wrap each individual widget for finer-grained -fallbacks, but the umbrella alone already prevents the worst class of -failures. +all in-room widgets, **plus** a per-widget pass that wraps each of the 13 +direct children of `RoomWidgetsView` and each of the 20 sub-widgets in +`FurnitureWidgetsView`. A crash in any single widget now silently logs +through `NitroLogger` and renders `null` for that widget only — its +siblings keep rendering. Each boundary carries a `name` prop matching +the widget so the log line identifies the culprit. --- @@ -729,20 +729,11 @@ Remaining order of value/risk for the next contributor: siblings under `src/hooks/catalog/`). Only after step 1 — React Query removes ~60% of the file's responsibility, Zustand can absorb the UI state slice. -3. **Per-widget `WidgetErrorBoundary` wrapping** inside `RoomWidgetsView`. - The umbrella is in place; granular wrapping means a crash in one - widget (e.g. `ChatWidgetView`) doesn't take down the rest of the - room overlay. Mechanical and safe. -4. **Hoist `WiredCreatorToolsView`'s shared state to a Zustand slice.** +3. **Hoist `WiredCreatorToolsView`'s shared state to a Zustand slice.** The 4-tab split is done but the parent still passes ~25 props to each tab. A slice at `src/components/wired-tools/wiredToolsStore.ts` would make each tab subscribe to the keys it needs. -5. **Address the two open logic bugs** (see the "Known logic bugs" - section above): the `MainView` CREATED/ENDED race needs a session - token; the `LayoutFurniImageView` / `LayoutAvatarImageView` async - fetch race needs a request-id ref (or is solved by migrating the - image fetch to `useNitroQuery` keyed on props). -6. **Widen the component/hook Vitest coverage.** The renderer-SDK +4. **Widen the component/hook Vitest coverage.** The renderer-SDK mock layer is in place (`tests/mocks/renderer-mock.ts`) and the first two pilots — `WidgetErrorBoundary` and `useDoorbellState` — pass. Good follow-up targets: other `*State` hooks built on event diff --git a/src/components/room/widgets/RoomWidgetsView.tsx b/src/components/room/widgets/RoomWidgetsView.tsx index 66745c2..0d86075 100644 --- a/src/components/room/widgets/RoomWidgetsView.tsx +++ b/src/components/room/widgets/RoomWidgetsView.tsx @@ -161,20 +161,20 @@ export const RoomWidgetsView: FC<{}> = props => return (
- +
- - - - - - - - - - - - + + + + + + + + + + + +
); }; diff --git a/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx index 443a883..f4ca400 100644 --- a/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx +++ b/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -1,4 +1,5 @@ import { FC } from 'react'; +import { WidgetErrorBoundary } from '../../../../common'; import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView'; import { FurnitureAreaHideView } from './FurnitureAreaHideView'; import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView'; @@ -24,26 +25,26 @@ export const FurnitureWidgetsView: FC<{}> = props => { return ( <> - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + ); };