Commit Graph

3 Commits

Author SHA1 Message Date
fef186c1cb feat(fase-16): integrate Spinner at the 5 loading sites + E2E coverage
Fase 16.2 + 16.3 — replace the bare `m.loading()` text at every
pre-existing async-loading site with `<Spinner size=...> + <span>`.
Text is kept (visual fallback + tooltip / SR redundancy). No new
loading semantics — only existing flags get a visual indicator.

Sites:
- (app)/+layout.svelte: auth splash gets `size="lg"` centred under the
  loading label.
- (app)/search/+page.svelte: inline `size="sm"` next to the search-in-flight
  copy.
- (app)/notes/archive/+page.svelte: inline `size="sm"` next to the
  archive-load copy.
- lib/components/CreateCollectiveModal.svelte: inline `size="sm"` inside
  the disabled Save button while the create RPC is in flight.
- (app)/collective/manage/+page.svelte: three sites — members-list load,
  invitation-generate button, and add-common-item Save button.

E2E (tests/e2e/spinner.test.ts):
- SP-E-01 throttles search_in_collective RPC by 500ms and asserts the
  spinner is visible in the loading paragraph.
- SP-E-02 throttles set_item_frequency_weight RPC and asserts the spinner
  is scoped inside the Save button.
- SP-E-03 seeds an expired `sb-192-auth-token` so GoTrue is forced to
  call /auth/v1/token, then hangs that endpoint indefinitely and
  asserts the splash spinner is visible. Storage key derivation matches
  Supabase's `sb-${hostname.split('.')[0]}-auth-token` default; we
  populate both the LAN-IP variant and a loopback fallback for
  resilience.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 13:54:26 +02:00
59c425f6f6 feat(fase-12): features store + integration coverage
Adds the client mirror of section_enabled():

  * SectionKey / FeatureFlags types + SECTION_KEYS constant in
    @colectivo/types so the SQL and TS sides share the same vocabulary.
  * apps/web/src/lib/stores/features.ts:
      - currentUserFeatures      writable, loaded by root layout
      - enabledSections          derived map { section → boolean }
      - enabledSectionList       ordered SectionKey[] visible to UI;
                                 forces 'lists' if every layer says OFF
      - setUserFeature           per-user toggle (optimistic + rollback)
      - setCollectiveFeature     admin toggle (rolls back on RLS deny)
      - realtime subscriptions   one channel for the user's row, one
                                 for the active collective; rebuilt
                                 whenever those targets change

Wired into the root layout: loadCurrentUserFeatures runs from inside
the existing setTimeout-deferred onAuthStateChange callback (the
documented gotcha), and currentCollective.subscribe drives
subscribeCollectiveFeatures so collective switches re-target the
realtime filter without an extra auth event.

loadUserCollectives + every other place that fabricates a Collective
object now carries feature_flags (defaulting to {} for freshly created
collectives) so the Collective interface stays sound.

Integration spec (6 tests, SV-01..SV-06) covers default-ON, user-only,
collective-beats-user, RLS writes (user_update_own + collectives_update),
and per-collective isolation for a user in two collectives.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 03:53:54 +02:00
10415bfca8 feat(fase-10): sidebar "+ New collective" entry + modal (10.6)
Adds a new "+ New collective" entry at the bottom of the sidebar
collective-switcher dropdown (and the mobile drawer for parity).
Clicking it opens a CreateCollectiveModal that reuses the same
onboarding form — name + emoji grid — and calls the existing
create_collective() RPC (migration 012). On success, the new
collective is appended to $userCollectives, set active in
$currentCollective, persisted to localStorage, and the user is sent
to /lists.

Side effects:
- Switcher now opens even with a single collective (previously gated
  on >1) so the entry is always reachable; the chevron is always
  shown.
- DesktopSidebar gets a data-testid on the switcher button so the
  Playwright suite can target it without text matching.

O-04 (rescued from Fase 7): Eva creates her first collective via
onboarding, then opens the switcher and creates a second one without
leaving /lists; both collectives end up in the switcher and the DB.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 02:25:11 +02:00