Commit Graph

23 Commits

Author SHA1 Message Date
simoleo89 6793de2106 Set up Vitest + 22 smoke tests on pure modules (proposal #6)
Phase 3 of the refactor plan in docs/ARCHITECTURE.md — the foundation
that unblocks every safe refactor below.

Install
- yarn add -D vitest@3 jsdom @testing-library/dom @testing-library/react
  @testing-library/jest-dom

Note: pinned to vitest@3 (not the latest 4.x) because yarn 1's peer
resolution breaks on vitest@4's peer link to vite. With vitest@3 the
existing Vite 8 install resolves cleanly.

Configuration
- vitest.config.mts (new): separate from vite.config.mjs because the
  dev/build config wires up renderer SDK aliases that point at sibling
  working trees (../renderer, ../Nitro_Render_V3). Tests are written
  against pure modules that don't pull in the renderer, so the test
  runner uses a smaller alias set.
- tests/setup.ts (new): imports @testing-library/jest-dom/vitest so
  custom matchers (toBeInTheDocument, etc.) are available without
  per-file imports.
- tsconfig.json: include "tests" so eslint stops complaining about
  unparseable files; also makes the IDE see the test files.
- package.json scripts: "test" (one-shot) and "test:watch".

Tests
- tests/WiredCreatorTools.helpers.test.ts (18 cases): covers the pure
  helpers extracted in 3c68d97 — createEmptyMonitorSnapshot,
  formatMonitorLatestOccurrence (5 time-bucket branches),
  formatMonitorHistoryOccurrence, formatVariableTimestamp,
  formatMonitorSource (4 branches), normalizeMonitorReason. These are
  the most boring-but-easy-to-break functions; locking them down first
  is high value, near-zero risk.
- tests/navigatorRoomCreatorStore.test.ts (4 cases): exercises the
  Zustand store added in the previous commit — initial state, latch
  semantics, 5s auto-reset (with fake timers), and the
  "second beginCreate restarts the lockout" invariant. Validates that
  the store-based replacement of the let-singleton has the same
  observable behavior, plus the new invariant that wasn't possible
  before (timer composition under StrictMode double-mount).

Side effect: two non-test source files were converted to `import type`
to keep the test bundle from accidentally pulling in the renderer SDK
transitively:
- src/components/wired-tools/WiredCreatorTools.types.ts
  (`import type { AvatarInfoFurni }`)
- src/components/wired-tools/WiredCreatorTools.helpers.ts
  (`import type { HotelDateTimeParts, MonitorSnapshot }`)
This is harmless — TypeScript already treated them as type-only —
and improves tree-shaking on build as a side benefit.

Verification
- yarn test -> 2 files, 22 tests passing in ~1.0s.
- yarn eslint on tests/ + the two type-only-import files: 0 errors,
  0 warnings.

Migration path
- Next adoption targets: cover useDoorbellState reducer (data hook
  split), the new useNitroQuery adapter (timeout/cleanup behavior),
  and the smaller pure formatters under src/api/.
- React component tests (via @testing-library/react) deferred until
  there's a small mock layer for the renderer SDK. The
  @testing-library/* deps are already installed so that PR is
  unblocked.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:53 +00:00
simoleo89 fd1835ca5d Enable Zustand (proposal #5) + convert isCreatingRoom singleton
Phase 2 of the refactor plan in docs/ARCHITECTURE.md.

Install
- yarn add zustand (^5, matches React 19 peer requirement).

Wiring
- src/state/createNitroStore.ts: replaces the previous prototype
  (which threw on call) with a re-export of zustand's `create` under
  the project-local name `createNitroStore`. Comments document the
  convention (one store per domain, subscribe to slices not the whole
  store).

First migration target
- src/components/navigator/views/navigatorRoomCreatorStore.ts (new):
  a Zustand store with `isCreating: boolean` and `beginCreate()` —
  the latter latches the flag to true, dispatches an internal
  setTimeout to auto-reset after 5s, and replaces any in-flight timer
  on re-entry. The timer handle lives in the store's closure, so a
  remount of the view doesn't reset the lockout and StrictMode's
  double-mount no longer schedules two pending timers.
- src/components/navigator/views/NavigatorRoomCreatorView.tsx:
  removes the two module-level `let` variables that the React Compiler
  was flagging ("Writing to a variable defined outside a component is
  not allowed"). The component now reads `isCreating` via a slice
  subscription and calls `beginCreate()` from the click handler. The
  imperative guard (`if (isCreating) return`) uses
  `useRoomCreatorStore.getState()` so it reads the latest value
  synchronously without being a stale closure.
- Also cleans up `FC<{}>` -> `FC` while touching the file.

Verification
- yarn eslint on the three touched files: 1 pre-existing error
  (the `setCategory(categories[0].id)` set-state-in-effect on the
  categories hook, deliberately left as-is in Phase C — it's the
  "init from late-arriving async data" pattern; baseline matches).
- yarn tsc: clean.

Migration path (per docs/ARCHITECTURE.md)
- This is the smallest possible Zustand pilot (~30 lines), chosen
  because the let-singleton anti-pattern was the most obvious quick
  win and the React Compiler was already complaining about it.
- Next adoption targets (cross-feature UI state): the toolbar's
  active-window state (currently inside scattered Contexts), the
  notification center's open-state, the catalog's currentPage/selection
  state (after the god-hook split).

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:53 +00:00
simoleo89 34b1b56788 Enable React Query (proposal #2) + first real-data pilot on OfferView
Phase 1 of the refactor plan in docs/ARCHITECTURE.md.

Install
- yarn add @tanstack/react-query@5 @tanstack/react-query-devtools@5
- Both pinned to ^5 (matches React 19 peer requirement).

Wiring
- src/index.tsx: mounts QueryClientProvider above ErrorBoundary +
  Suspense. Default config: staleTime=30s, retry=1,
  refetchOnWindowFocus=false (chat client, not a data dashboard).

Adapter
- src/api/nitro-query/createNitroQuery.ts: replaces the previous
  prototype that just threw. Exposes:
    * useNitroQuery({ key, request, parser, select, timeoutMs })
      — wraps TanStack's useQuery; queryFn awaits the parser response.
    * awaitNitroResponse(...) — lower-level helper for imperative use
      via queryClient.fetchQuery.
  The Promise:
    1. registers the parser via GetCommunication().registerMessageEvent
    2. dispatches the composer via SendMessageComposer
    3. resolves with select(event) on the first matching parser
    4. rejects after timeoutMs (default 15s)
    5. always cleans up the listener + timeout (cancel-safe).

Pilot
- src/components/catalog/views/targeted-offer/OfferView.tsx:
  the previous useMessageEventState + manual useEffect-send pattern
  becomes a single useNitroQuery call. staleTime:Infinity because the
  targeted offer doesn't change during a session. Subsequent OfferView
  remounts (e.g. opening/closing the dialog) now reuse the cached
  payload — the GetTargetedOfferComposer is no longer re-sent each
  time.

Verification
- yarn eslint on the four touched files: 1 pre-existing
  no-redundant-type-constituents error (IMessageEvent resolves as `any`
  in the local sandbox without the renderer SDK installed; matches the
  12 other pre-existing instances of the same false positive).
- yarn tsc on the four touched files: clean (modulo the
  project-wide TS2307 about @nitrots/nitro-renderer).
- The original prototype's "throw" guard is gone — useNitroQuery is now
  callable.

Migration path (per docs/ARCHITECTURE.md)
- Next adoption targets (read-only fetches first): useCatalog's page
  data, useInventoryFurni's bot listing, Navigator search results,
  Marketplace listings.
- Push messages (server-pushed events the client doesn't request)
  keep using useNitroEventState / useMessageEventState — they're
  subscriptions, not requests.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:53 +00:00
simoleo89 f18c917fc4 Add TypeScript 7 (tsgo) as fast type-checker alongside TS 6
TypeScript 7 is the Go-native rewrite of tsc, ~10x faster but only
distributed as @typescript/native-preview daily builds at the time
of writing (npm typescript@latest is still 6.0.3). Add it as a
non-disruptive type-check tool: yarn typecheck → tsgo --noEmit.

Vite still uses esbuild for transpilation, ESLint still uses TS 6
through @typescript-eslint v8, IDEs continue using their bundled TS.
This commit only adds a type-check tool — nothing replaces.

Required tsconfig.json adjustments for TS 7 compatibility (still
valid for TS 6):

- Drop baseUrl: "./src" (removed in TS 7). The codebase has no
  bare/non-relative imports that depended on it; all imports are
  relative or aliased.
- Drop downlevelIteration: true (removed in TS 7; target es2022
  doesn't need it).
- moduleResolution: "node" → "bundler" (TS 7 dropped node10; bundler
  is the right mode for Vite anyway).
- paths "@layout/*" entries now use leading "./" (TS 7 disallows
  non-relative path mappings). Add "@/*" → "./src/*" to match the
  Vite alias used in some components.

Other TS 7 adjustments:

- src/react-app-env.d.ts: add module declarations for *.css/.scss/.sass
  side-effect imports (TS 7 with bundler resolution requires them) +
  Window.NitroConfig / Window.NitroSecureApiUrl globals which were
  used in App.tsx without a declaration.
- src/common/Popover.tsx: explicit `import { JSX } from 'react'`
  because TS 7 dropped the implicit global JSX namespace.

Verification:
- yarn eslint still passes (TS 6 / @typescript-eslint v8 happy with
  the migrated config).
- yarn typecheck (tsgo) runs and reports only cascading errors
  rooted in the missing @nitrots/nitro-renderer sibling repo
  (environmental, not introduced here).

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:51 +00:00
simoleo89 13dc483938 Bump ecosystem dependencies (minor/patch)
- @radix-ui/react-popover: ^1.1.6 → ^1.1.15
- @radix-ui/react-slider:  ^1.2.4 → ^1.3.6
- react-icons:             ^5.5.0 → ^5.6.0
- dompurify:               ^3.4.1 → ^3.4.2
- @tanstack/react-virtual: pin → ^3.13.24 (loosen to caret; no version change)

framer-motion (12.38.0), @tanstack/react-virtual (3.13.24), emoji-mart
(5.6.0), and @emoji-mart/* are already at latest. react-player was
intentionally not bumped (3.x is a major release).

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:51 +00:00
simoleo89 a1bee1d825 React 19 modernization: forwardRef removal, Compiler, ErrorBoundary, Suspense, native <script>
Adopt React 19 idioms across the codebase. The runtime was already on
react@19.2.5 but no React 19 APIs were in use.

- forwardRef -> ref-as-prop in 7 layout/component files
  (NitroInput/Button/ItemCountBadge/Card×5/InfiniteGridItem,
  ToolbarItemView, AvatarEditorIcon)
- <Ctx.Provider> -> <Ctx> in 6 contexts (CatalogAdmin, FloorplanEditor,
  UiSettings, GridContext, NitroCardContext, NitroCardAccordionContext)
- Native <script> hoisting for Turnstile, ExternalPluginLoader, GoogleAdsView
  (React 19 dedupes by src; removes manual document.head.appendChild +
  module-level promise caches)
- React Compiler enabled at build time via babel-plugin-react-compiler
  in vite.config.mjs (target: '19'), plus eslint-plugin-react-compiler
  in lint mode
- Global <ErrorBoundary> + <Suspense> in src/index.tsx using
  react-error-boundary, with LoadingView as fallback
- BackgroundsView migrated to use(promise) as a demonstrator pattern
  for Suspense-driven config loading
- ESLint react setting bumped 18.3.1 -> 19.2; legacy
  @typescript-eslint/ban-types replaced with no-restricted-types
  (the old rule was removed in @typescript-eslint v8)
- Refresh public/configuration/{asset-loader,bootstrap}.js to match
  current write-asset-loader.mjs output

Phase 3 (login forms -> useActionState/useFormStatus) deferred:
LoginView is 1623 lines with lockout + Turnstile + heartbeat
interleaving; safer as its own PR.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:50 +00:00
Lorenzune 71171dc205 Merge remote-tracking branch 'duckie/main' into merge-duckie-main-2026-05-06
# Conflicts:
#	index.html
#	public/UITexts.example
#	public/renderer-config.example
#	src/App.tsx
#	src/components/login/LoginView.tsx
#	src/components/room/widgets/avatar-info/infostand/InfoStandWidgetUserView.tsx
#	src/components/toolbar/ToolbarView.tsx
#	src/components/user-profile/UserContainerView.tsx
2026-05-06 04:23:15 +02:00
DuckieTM 92e9bb19cd 🆙 Updates thanks to Life
react-slider → @radix-ui/react-slider
react-tiny-popover → @radix-ui/react-popover
react-youtube → react-player (more formats, better maintained)
2026-05-03 17:54:10 +02:00
DuckieTM 99aceefb9e 🆙 Updates thanks to Life
react-bootstrap → migrate to shadcn/ui + Tailwind (or HeroUI)
Legacy, ~250KB bundle, dated API, inconsistent with CMS stack

react-transition-group → use framer-motion (already installed!)
De-facto deprecated, duplicate animation lib
2026-05-03 16:05:23 +02:00
duckietm 5234ba5662 ㊙️ Updates for the packages
please remove the node_modules dir and do yarn install
2026-04-28 09:43:00 +02:00
Lorenzune 237c523f9a checkpoint: secure assets and login flow baseline 2026-04-23 07:01:09 +02:00
duckietm 2ac7ed492f 🆙 Updated all css to be used for vite 8.0 2026-04-10 10:15:58 +02:00
duckietm 19fd0e0809 Revert "Merge pull request #45 from simoleo89/interface-color-pr"
This reverts commit d911196ccb, reversing
changes made to 8dccc509c4.
2026-03-23 13:31:15 +01:00
Life 9c2dccaad6 feat: UI color theming system with live preview, presets and server sync
- RGBA color picker with live preview (debounce 50ms)
- 30 preset colors + 12 theme presets (Ocean, Forest, Sunset, Royal, etc.)
- Header image selection from configurable image library
- Export/Import theme as JSON via clipboard
- CSS variable theming across all UI elements: NitroCard headers/tabs,
  context menus, buttons (primary/dark/gray), InfoStand, toolbar,
  room tools, purse, progress bars, sliders
- All elements use var(--name, fallback) for zero visual change when default
- Smooth 0.3s CSS transitions on theme change
- Server-side persistence via WebSocket (packets 10047/10048)
- Integrated Color/Image tabs into BackgroundsView panel
- All strings use LocalizeText() for i18n support
- Settings persisted in localStorage + server sync with 1s debounce
- Added react-colorful dependency
2026-03-22 21:48:07 +01:00
duckietm 194e8cf3a8 Revert "Merge pull request #16 from simoleo89/feature/ui-customization"
This reverts commit d1a5996268, reversing
changes made to ae4ecc42f0.
2026-03-19 10:39:56 +01:00
medievalshell ea35f19940 Add UI Customization Panel with full color theming
- New "Interfaccia" panel with color picker (HSV + hex/RGB/alpha + 30 presets)
- Profile background customization tab
- Accent color propagates via CSS variables to: card headers/tabs,
  context menus, Button dark/primary/gray variants, InfoStand panels,
  toolbar, room tools, purse, .btn-primary/.btn-dark CSS classes
- All elements use var(--name, fallback) for zero visual change when default
- Settings persisted in localStorage
- Added react-colorful dependency
- Added ui-config.json with header images config keys
2026-03-18 20:12:00 +01:00
DuckieTM a38a52fa5d 🆙 Release RC-1 2026-02-27 22:49:33 +01:00
duckietm faadd0cf31 🆙 Better way to load the slider 2026-02-25 11:51:03 +01:00
duckietm 32cf466fb4 🆙 Added emoji to the chat 2026-02-25 11:03:29 +01:00
duckietm f2446d232b 🆙 Upgrade to tailwind css 4.2.0 2026-02-20 08:17:17 +01:00
duckietm eef3841c87 🆙 start update package to latest versions 2026-02-20 07:34:30 +01:00
duckietm 515b282888 🆙 update to the latest react 2026-02-19 17:05:24 +01:00
DuckieTM 7feb10ab15 🆙 Init V3 2026-01-31 09:10:52 +01:00