Revert feature-folder migration; keep classic src/components + src/hooks layout

Decision: the src/features/<feature>/ layout introduced as proposal #3
(pilot on doorbell in 8ec9d27) is not the convention the team wants. The
existing src/components/<area>/ + src/hooks/<area>/ split is the one
that stays.

What's reverted
- src/features/doorbell/ is removed entirely. The doorbell view and the
  two hooks move back under the classic paths:
    src/features/doorbell/views/DoorbellWidgetView.tsx
      -> src/components/room/widgets/doorbell/DoorbellWidgetView.tsx
    src/features/doorbell/hooks/useDoorbellState.ts
      -> src/hooks/rooms/widgets/useDoorbellState.ts
    src/features/doorbell/hooks/useDoorbellActions.ts
      -> src/hooks/rooms/widgets/useDoorbellActions.ts
- The compat shims that lived in those classic paths are dropped now
  that the real files are back.
- src/hooks/rooms/widgets/index.ts adds the two new hooks alongside the
  existing useDoorbellWidget shim (kept as a deprecated wrapper so any
  external consumer importing the old shape via the barrel keeps
  working).

What's preserved
- The split between data and actions (proposal #4) — useDoorbellState
  and useDoorbellActions remain two separate hooks. This was the actual
  improvement, and it's independent of where the files sit.
- The bug fixes from 8ec9d27 (close button race, optimistic-remove
  rollback) — both still present, just in the new path.
- src/state/createNitroStore.ts and src/api/nitro-query/createNitroQuery.ts
  are left where they are. They aren't feature folders; they're
  cross-cutting framework code (Zustand skeleton, React Query adapter
  prototype) that any feature can consume.

Doc
- docs/ARCHITECTURE.md section #3 is rewritten to record the decision
  rather than recommend the layout. It now describes the convention to
  follow:
    * views under src/components/<area>/<feature>/
    * hooks under src/hooks/<area>/<feature?>/ (siblings, not subfolders
      per widget)
    * sibling .types/.constants/.helpers files for view-specific code
      (e.g. WiredCreatorTools.*.ts)
- "What's already in place" and "Recently fixed" sections updated to
  point at the new paths.
- "How to pick the next refactor PR" no longer mentions feature-folder
  migration as an option.

Note: the five extra feature folders started this session (reconnect,
nitropedia, ads, hc-center, campaign) were never committed; they only
existed in the working tree and have been restored from HEAD.

Verification
- find src/features -type f -> 0 (directory removed).
- npx tsc --noEmit on all touched files: clean (only the project-wide
  pre-existing TS2307 about @nitrots/nitro-renderer not installed
  locally remains, same as before).
- npx eslint on all touched files: 0 errors, 0 warnings.

https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
This commit is contained in:
simoleo89
2026-05-11 16:31:53 +00:00
parent 81656e7b19
commit 0755285708
8 changed files with 101 additions and 123 deletions
@@ -1 +1,46 @@
export { DoorbellWidgetView } from '../../../../features/doorbell';
import { FC, useState } from 'react';
import { LocalizeText } from '../../../../api';
import { Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useDoorbellActions, useDoorbellState } from '../../../../hooks';
export const DoorbellWidgetView: FC = () =>
{
const users = useDoorbellState();
const { answer } = useDoorbellActions();
const [ dismissed, setDismissed ] = useState(false);
const isVisible = !dismissed && users.length > 0;
if(!isVisible) return null;
return (
<NitroCardView className="nitro-widget-doorbell" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('navigator.doorbell.title') } onCloseClick={ () => setDismissed(true) } />
<NitroCardContentView gap={ 0 } overflow="hidden">
<Column gap={ 2 }>
<Grid className="text-black font-bold border-bottom px-1 pb-1" gap={ 1 }>
<div className="col-span-6">{ LocalizeText('generic.username') }</div>
<div className="col-span-6" />
</Grid>
</Column>
<Column className="striped-children" gap={ 0 } overflow="auto">
{ users.map(userName => (
<Grid key={ userName } alignItems="center" className="text-black border-bottom p-1" gap={ 1 }>
<div className="col-span-6">{ userName }</div>
<div className="col-span-6">
<div className="flex items-center gap-1 justify-end">
<Button variant="success" onClick={ () => answer(userName, true) }>
{ LocalizeText('generic.accept') }
</Button>
<Button variant="danger" onClick={ () => answer(userName, false) }>
{ LocalizeText('generic.deny') }
</Button>
</div>
</div>
</Grid>
)) }
</Column>
</NitroCardContentView>
</NitroCardView>
);
};