Commit Graph

143 Commits

Author SHA1 Message Date
simoleo89 bf84a0c2a6 useNitroQuery: add accept() predicate; migrate two mod-tools chatlog views
Many composer/parser pairs on the Nitro wire are correlation-key based:
the request carries a key (roomId, issueId, etc.) and the response shows
up on the globally-shared event bus, where other components may be
listening for the same parser type with a different key. The previous
useNitroQuery resolved on the FIRST matching parser event regardless of
key — useless for that pattern, which is why two obvious migration
targets (ModToolsChatlogView, CfhChatlogView) were skipped earlier.

Adapter change
- New optional `accept?: (event) => boolean` on NitroQueryConfig.
- In awaitNitroResponse, events for which accept returns false are
  IGNORED rather than resolving the promise. The listener stays
  registered, the timeout still applies. This lets callers do:
    accept: e => e.getParser()?.data.roomId === roomId

Migrations
- src/components/mod-tools/views/room/ModToolsChatlogView.tsx
  - Was: useState<ChatRecordData>(null) + useMessageEvent with
    `if (parser.data.roomId !== roomId) return; setRoomChatlog(...)` +
    a mount-only useEffect dispatching the composer.
  - Now: a single useNitroQuery call keyed on roomId; accept filters
    by roomId; the query is enabled only when roomId is set.
    The composer is no longer re-dispatched on remount within
    staleTime; switching to a different room still triggers a fresh
    fetch because the queryKey changes.
- src/components/mod-tools/views/tickets/CfhChatlogView.tsx
  - Same pattern, keyed on issueId.

Both migrations drop ~15 lines per file (no more local state + manual
listener + manual send) while gaining cache/dedup/loading/error
handling from TanStack Query.

Verification
- yarn eslint on the four files: 1 pre-existing error (the
  IMessageEvent "redundant union" false positive in createNitroQuery
  that we already documented — local sandbox doesn't have the
  renderer SDK installed, so its types resolve as `any`).
- yarn test: 49/49 passing.
- yarn tsc on the four files: clean.
2026-05-11 17:00:06 +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 48d62c5c6b Architecture refactor: docs + 5 pilot implementations + error boundary
This is the structural plan promised in the previous session, with concrete
pilots for all five proposals + the bonus error-boundary work.

== docs/ARCHITECTURE.md (new, ~370 lines)

Living document describing:
- where the project stands today (event-bus pattern friction with React 19,
  god-hooks, oversized files);
- the five proposed structural improvements with the why/how/status of each;
- what's already in place across this branch;
- recommended order for the next refactor PRs.

This is the deliverable the rest of this commit references.

== Proposal #3 + #4 pilots: src/features/doorbell/ (new)

Concrete feature-folder migration on the doorbell widget (chosen because
it's small enough to migrate end-to-end in one commit).

  src/features/doorbell/
    index.ts                    public API
    views/DoorbellWidgetView.tsx
    hooks/useDoorbellState.ts   reduces 3 events into a users array (data only)
    hooks/useDoorbellActions.ts answer(name, flag) (imperative actions only)

The split (data vs actions) is the pattern proposal #4 wants applied to
useCatalog/useChat/useWiredTools later. The original useDoorbellWidget had
both concerns + a buggy `useEffect(() => setIsVisible(!!users.length), [users])`
derive-state-in-effect. The new view computes visibility in render.

Compat shims kept so existing imports keep working:
- src/components/room/widgets/doorbell/DoorbellWidgetView.tsx -> 1-line re-export
- src/hooks/rooms/widgets/useDoorbellWidget.ts -> deprecated wrapper around
  the two new hooks, returning the same { users, answer } shape.

== Proposal #2 prototype: src/api/nitro-query/ (new)

Adapter outline for wrapping composer/parser request-response pairs in
TanStack Query. Not yet enabled because @tanstack/react-query is not in
package.json. The file documents the activation steps:

  yarn add @tanstack/react-query @tanstack/react-query-devtools
  + mount QueryClientProvider in src/index.tsx

awaitNitroResponse() throws with a helpful pointer to the doc section if
called before activation, so accidental adoption fails loudly.

== Proposal #5 skeleton: src/state/createNitroStore.ts (new)

Same pattern: skeleton + activation instructions. Not yet enabled because
zustand is not in package.json.

  yarn add zustand
  + replace the throw with `import { create } from 'zustand'; export const createNitroStore = create;`

The doc inside the file shows the recommended slice shape and points to
the suggested first migration target (the let isCreatingRoom singleton in
NavigatorRoomCreatorView).

== Bonus: WidgetErrorBoundary

src/common/error-boundary/WidgetErrorBoundary.tsx wraps react-error-boundary
with a sensible default (silent fallback, NitroLogger.error). Re-exported
from src/common/index.ts.

Applied as the umbrella around RoomWidgetsView's children — a widget
crash in a room (e.g. malformed pet data) now degrades gracefully
instead of unmounting the whole UI.

== Verification

- yarn eslint on all new + modified files: 0 errors / 0 warnings introduced.
  RoomWidgetsView still has its 1 pre-existing FC<{}> error (1 before, 1 after).
- yarn tsc on all new files: clean (only project-wide pre-existing
  TS2307 about @nitrots/nitro-renderer not installed locally remains).
- No regressions: existing imports of DoorbellWidgetView and
  useDoorbellWidget keep resolving via the compat shims.

== What's NOT in this commit (intentionally)

- Mass adoption of the new patterns elsewhere — left as follow-up PRs in
  the order documented in ARCHITECTURE.md "How to pick the next refactor PR".
- Installation of @tanstack/react-query / zustand — explicit team decision,
  not the LLM's to make.
- Test infrastructure (Vitest setup) — listed as the #1 missing piece in
  the doc, but a separate PR.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:52 +00:00
simoleo89 d382635597 Phase A: clear all react-hooks/exhaustive-deps warnings via useEffectEvent or hoisting
Eliminate the four remaining missing-dependency warnings reported by
react-hooks v7. Each one was a real stale-closure or re-trigger hazard;
the fix matches the intent rather than just silencing the linter.

- src/App.tsx (line 448): wrap showSessionExpired with useEffectEvent
  (onSessionExpired) so the prepare effect doesn't re-run on every
  showSessionExpired identity change but still calls the latest
  callback. Replace the two in-effect call sites.
- src/components/furni-editor/views/FurniEditorSearchView.tsx: wrap
  the on-mount onSearch('', '', 1) call with useEffectEvent so the
  callback prop isn't a missing dependency.
- src/components/notification-center/views/bubble-layouts/
  NotificationBadgeReceivedBubbleView.tsx: wrap the
  "fetch badges only if empty on mount" check with useEffectEvent
  so badgeCodes.length isn't required as a dep (and won't re-fetch
  every count change).
- src/components/navigator/views/room-settings/
  NavigatorRoomSettingsRightsTabView.tsx: switch deps from
  roomData?.roomId to roomData (the body uses roomData.roomId after
  an early return; the linter wanted the whole object).
- src/api/ui-settings/UiSettingsContext.tsx: hoist ALL_CSS_VARS
  outside the component (it's a static constant).

After this, yarn eslint reports zero exhaustive-deps warnings across
the whole src/.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:51 +00:00
simoleo89 535fa71020 ESLint --fix: auto-fix brace-style, indent, semi, no-trailing-spaces
Run eslint --fix across src/ to clear ~1900 mechanical lint errors
surfaced by the @typescript-eslint v8 + react-hooks v7 + react-compiler
upgrade in the React 19 modernization PR.

Issues fixed automatically:
- brace-style (Allman): try/catch one-liners reformatted to multi-line
- indent: tab-vs-space and depth corrections
- semi: missing trailing semicolons
- no-trailing-spaces

No semantic changes. Remaining 701 errors are real-code issues
(set-state-in-effect, rules-of-hooks, no-unsafe-* type checks) that
need manual per-file review.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
2026-05-11 16:31:50 +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
DuckieTM 71725b7f67 Merge branch 'Dev' into merge-duckie-main-2026-05-06 2026-05-08 07:45:17 +02:00
Lorenzune 57b83c1097 Refine mobile avatar widgets and login flow 2026-05-07 21:19:15 +02:00
DuckieTM 83ee05957d 🆙 Fix font colors in chat 2026-05-07 20:49:50 +02:00
duckietm a243640741 🆙 News windows in UI login update 2026-05-06 08:48:17 +02: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
simoleo89 72bc4da3c0 feat(profile): add full-box card background tab and rendering
Adds a "Cards" tab to the Profile Background picker (BackgroundsView)
that selects a pattern applied to the entire user info card and the
extended profile container, in addition to the existing avatar-pad
background/stand/overlay layers.

- AvatarInfoUser/Utilities: propagate cardBackgroundId from RoomUserData.
- InfoStandWidgetUserView: stateful cardBackgroundId, applied as
  .profile-card-background.card-background-{id} on the outer Column
  with bg-color suppressed when active.
- UserContainerView: same class on the wrapper of the extended profile.
- BackgroundsView: 4th tab "cards" backed by cards.data config
  (falls back to backgrounds.data); sends 4-id message via the
  extended sendBackgroundMessage signature.
- ui-config.example: cards.data dataset (15 entries).
- BackgroundsView.css: 188 .card-background-{N} rules cloned from
  background-{N} (repeat-tiled) plus 15 CSS-pattern overrides for the
  provisional dataset (gradients, stripes, dots, grid, checker).
2026-05-03 22:09:12 +02:00
duckietm 506a29c9a0 🆕 Create Custom Bage & Security update 2026-05-01 16:02:56 +02:00
duckietm eb0bf80dfa 🆙 Fix the avatar-editor faces 2026-04-29 15:44:17 +02:00
Lorenzune b4fab3f6b9 Merge duckie main into live merge branch 2026-04-25 13:52:11 +02:00
Lorenzune 541d3045f1 Update secure login flow and login view 2026-04-23 16:26:32 +02:00
Lorenzune 726d1cc5c8 Merge latest duckie main with login UI 2026-04-21 11:53:30 +02:00
Lorenzune 58e0ed30f6 Merge remote-tracking branch 'duckie-temp/main' into duckie-merge-2026-04-21
# Conflicts:
#	src/components/room/widgets/chat-input/ChatInputView.tsx
#	src/components/toolbar/ToolbarView.tsx
#	src/css/chat/Chats.css
#	src/css/nitrocard/NitroCardView.css
#	src/css/purse/PurseView.css
#	src/css/room/RoomWidgets.css
2026-04-21 11:19:59 +02:00
Lorenzune 9b36513def WIP preserve local changes before duckie merge 2026-04-21 11:13:32 +02:00
Lorenzune e0174e450c Align wired chat limits and formatting help UI 2026-04-21 08:54:02 +02:00
duckietm d3e6743fdf 🆙 Do not make have_offer static 2026-04-17 14:23:26 +02:00
duckietm 88117d937f 🆙 Fix Catalog editor 2026-04-17 13:51:46 +02:00
duckietm b0967d7eaf 🆕 New Misc clothing 2026-04-16 13:34:53 +02:00
duckietm 9dbe360448 🆙 Fixed Buddy Pets showing in catalogue 2026-04-15 13:09:27 +02:00
DuckieTM bae6f58b10 Merge branch 'Dev' into feat/wired-fixes-apr08 2026-04-13 16:58:14 +02:00
duckietm bef58bc929 🆙 Cleanup old youtube link in chat, now broadcasting is working 2026-04-10 16:32:14 +02:00
duckietm e7cf7809bc 🆙 Memory usage fixes 2026-04-10 11:40:39 +02:00
duckietm 4afdfd8f33 🆕 YoutubeTV Broadcasting in rooms ! 2026-04-10 09:26:50 +02:00
Lorenzune 5e9e3e1e4c Polish wired editor UI and variable handling 2026-04-08 16:18:16 +02:00
duckietm 5bff312b3b 🆙 Fixed some minor bugs 2026-04-08 14:06:25 +02:00
Lorenzune 954e477e47 feat: add builders club catalog ui flow 2026-04-07 14:40:51 +02:00
Lorenzune 60f0355a13 Merge remote-tracking branch 'upstream/main' 2026-04-03 12:04:39 +02:00
duckietm 19b7d7d9d9 🆙 more optimization mem. 2026-04-03 10:48:34 +02:00
Lorenzune 21193daebb Merge upstream/main into feature/checkpoint-20260403 2026-04-03 05:26:19 +02:00
Lorenzune 36c0221a54 chore: checkpoint current work 2026-04-03 05:22:26 +02:00
Lorenzune 83540ff329 feat: add advanced wired variable tools UI 2026-04-02 04:44:04 +02:00
duckietm 6ad9a0c7b9 🆙 Fix the catalog search in some cases it will give a black screen 2026-04-01 17:12:09 +02:00
duckietm aa10cb54db 🆙 Small update 2026-04-01 10:23:00 +02:00
Lorenzune 0a23bfaee4 Merge remote-tracking branch 'upstream/main' into feature/pr-20260327
# Conflicts:
#	public/UITexts.example
2026-03-31 09:14:35 +02:00
Lorenzune b003191165 Merge branch 'Dev' into feature/pr-20260327 2026-03-31 08:53:19 +02:00
DuckieTM 522219cbee 🆕 Groups Forum
- please add the text in the UITexts
2026-03-29 14:58:56 +02:00
duckietm bbe71e9753 🆙 Cleanup Furni-Edit & Fix the avatar-editor 2026-03-27 13:38:03 +01:00
Lorenzune 31e51297e7 Add wired creator tools monitor and inspection UI
- add the new :wired inspection/monitor panel with furni, user and global tabs

- add live variables, previews, inline editing and keep-selected behavior

- add global room diagnostics placeholders, monitor artwork and server/client timezone display

- add editor support for wf_xtra_text_output_furni_name and related UI texts/assets
2026-03-27 09:37:13 +01:00
Lorenzune 3b3e91f6d9 Add NFT avatar tab and wired extras UI 2026-03-26 05:24:53 +01:00
duckietm 303b75d378 🆕 🐶 have you favorite pet as your best pall next to you 2026-03-25 14:11:53 +01:00
Lorenzune 56a0be64d9 Polish wired editor UI and source selection flows 2026-03-25 03:26:27 +01:00
duckietm df1437c488 🆙 Cleanup 2026-03-24 11:56:51 +01:00
DuckieTM 47e07a5714 Merge pull request #43 from simoleo89/chat-prefix
feat: custom chat prefix system
2026-03-24 10:57:39 +01:00
DuckieTM 4aef7d5f94 Merge branch 'main' into chat-prefix 2026-03-24 10:54:42 +01:00
Lorenzune eca7cd9350 Merge branch 'Dev' into feature/wired-followups-20260324 2026-03-24 02:18:56 +01:00