From 7a1099bbbeeaf20fe065ce6a52e320a7dccd9a0b Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Mon, 18 May 2026 17:08:01 -0400 Subject: [PATCH] feat(idaa): replace filter checkboxes/radios with toggle pill chips + update docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ae_idaa_comp__event_obj_qry.svelte: replace Location checkboxes and Type radio inputs with styled pill-chip buttons. Location chips (Virtual / In-Person) are independent toggles; Type chips (All / IDAA / Caduceus / Family Recovery) are mutually exclusive — clicking the active chip deselects back to All. Chips fire the reactive search $effect directly via store updates; no explicit trigger needed. Remote First dev toggle preserved in edit mode, now inline with filter chips. - CLIENT__IDAA_and_customized_mods.md: update Recovery Meetings filter/sort docs, add My Meetings / favorites section, correct idaa_loc and idaa_sess store schemas, bump Last Verified date. Co-Authored-By: Claude Sonnet 4.6 --- .../CLIENT__IDAA_and_customized_mods.md | 65 ++++++-- .../ae_idaa_comp__event_obj_qry.svelte | 141 ++++++++---------- 2 files changed, 112 insertions(+), 94 deletions(-) diff --git a/documentation/CLIENT__IDAA_and_customized_mods.md b/documentation/CLIENT__IDAA_and_customized_mods.md index 0960b247..03708a07 100644 --- a/documentation/CLIENT__IDAA_and_customized_mods.md +++ b/documentation/CLIENT__IDAA_and_customized_mods.md @@ -376,12 +376,19 @@ Recovery Meetings reuses the Aether Events object to represent AA recovery meeti ### Search Filters Members can filter meetings by: -- **Fulltext search** — name, location -- **Physical** — in-person meetings -- **Virtual** — online meetings (Zoom, Google Meet, etc.) -- **Meeting type** — specific meeting format categories +- **Fulltext search** — name, location, day of week, contacts (debounced 250ms; uses SWR pattern) +- **Virtual** — online meetings (Zoom, Jitsi, other) +- **In-person** — physical location meetings +- **Meeting type** — IDAA / Caduceus / Family Recovery +- **My Meetings** — star toggle; shows only meetings the member has starred (favorites) -Search is debounced (250ms) and uses the standard Aether SWR pattern. +**Sort options:** Last Updated (default), Meeting Name A–Z, Meeting Name Z–A. + +**Empty state behavior:** +- Zero results with active filters → "No meetings found for these filters" + "Clear all filters" button +- Zero results with no filters → bare message shown, then after 8s a "Refresh Meeting Cache" escape hatch appears (clears IDB and re-fetches from API — indicates a stale-cache problem, not a real empty set) + +Search uses the standard Aether SWR pattern (IDB cache returned immediately, then API refreshes in background). ### Search Architecture — What Is and Isn't Searched @@ -398,6 +405,22 @@ has not yet been added to the searchable fields whitelist in the API. - Frontend: add `contact_li_json_ext` as an OR condition in `search__event()`, and update the local IDB fast-path filter to parse `contact_li_json` for instant cache results +### My Meetings (Favorites) + +Members can star meetings to build a personal "My Meetings" list. The star toggle appears: +- On each card in the meeting list (`ae_idaa_comp__event_obj_li.svelte`) +- On the meeting detail page nav bar (`[event_id]/+page.svelte`) + +Favorites are stored in the `data_store` table (code: `idaa_meetings_favorites`, scoped to the +IDAA account). The record's `json` field holds `{ [novi_uuid]: [event_id, ...] }` — one shared +record per account containing all members' favorites. This means: +- Favorites persist across browsers and devices (server-side) +- Does **not** write to `ae_event` rows (avoiding the `ON UPDATE current_timestamp()` side effect) +- Known last-write-wins race condition if two members toggle simultaneously — acceptable for ~1000 members +- Pre-created DB records: ID 150 (`gaTKSVPagFj`, account_id=1, dev/demo), ID 151 (`knJh8zhyKT0`, account_id=13, live IDAA) + +The star button uses inline styles (not `.btn`) to avoid Bootstrap v3 box-model overrides in the iframe. + ### Edit Form — Sections and Key Fields The edit form (`ae_idaa_comp__event_obj_id_edit.svelte`) is organized into these sections. @@ -604,18 +627,36 @@ Stores Novi auth context and per-submodule query settings: novi_jitsi_mod_li: string[] // Jitsi moderator UUIDs archives: { enabled, hidden, limit, offset, edit__archive_obj, edit__archive_content_obj } - bb: { enabled, hidden, limit, offset, edit__post_obj, edit__post_comment_obj } - recovery_meetings: { qry__fulltext_str, qry__physical, qry__virtual, qry__type, qry__limit, edit__event_obj } + bb: { enabled, hidden, limit, offset, edit__post_obj, edit__post_comment_obj, + qry__enabled, qry__hidden, qry__limit, qry__offset, qry__order_by, qry__order_by_li } + recovery_meetings: { + qry__enabled, qry__hidden, qry__limit, qry__offset, + qry__fulltext_str, qry__physical, qry__virtual, qry__type, + qry__order_by, qry__order_by_li, + qry__favorites_only, // true = show only starred meetings (My Meetings filter) + edit__event_obj // null or event_id string when edit form is open + } } ``` -### `idaa_sess` (sessionStorage — cleared on tab close) +### `idaa_sess` (in-memory only — resets on page load) UI state per submodule: ```typescript { - archives: { qry__status, show__modal_edit__archive_id, show__modal_view__archive_id, obj_changed } - bb: { qry__status, show__modal_edit__post_id, show__modal_view__post_id, obj_changed } - recovery_meetings: { qry__status, show__modal_edit, show__modal_view, attend_platform, obj_changed } + archives: { qry__status, show__modal_edit__archive_id, show__modal_view__archive_id, + show__modal_edit__archive_content_id, show__modal_view__archive_content_id, obj_changed } + bb: { qry__status, edit__post_obj, show__inline_edit__post_obj, show__modal_edit__post_id, + show__modal_view__post_id, obj_changed } + recovery_meetings: { + qry__status, // null | 'loading' | 'done' | 'error' + qry__fulltext_str, // session-only copy (separate from persisted loc copy) + search_version, // incremented to trigger a new search cycle + edit__event_obj, // null | event_id — controls edit form visibility + show__modal_edit, show__modal_view, + show__modal_edit__event_id, show__modal_view__event_id, + attend_platform, // 'Zoom' | 'Jitsi' | null — platform selected in virtual attend section + obj_changed + } } ``` @@ -780,4 +821,4 @@ ae_loc.idaa_loc = { novi_uuid: 'test-uuid-value', ... }; --- **Document Status:** ✅ Current -**Last Verified:** 2026-05-06 — added Module 5: Jitsi Reports (grouped view, UUID exclusion, known-meeting whitelist, UUID-based unique counts); fixed route tree (`jitsi_reports/` is inside `(idaa)/`) +**Last Verified:** 2026-05-18 — Recovery Meetings: added My Meetings / favorites (data_store-backed, star button on list + detail page), guided empty state for filtered zero-results, corrected filter/sort descriptions; updated `idaa_loc` and `idaa_sess` store schemas to match actual fields diff --git a/src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_qry.svelte b/src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_qry.svelte index a769bece..2808bcc6 100644 --- a/src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_qry.svelte +++ b/src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_qry.svelte @@ -160,97 +160,74 @@ function prevent_default(fn: (event: T) => void) { +
- - Location? - - - - - -
+ class="border-surface-300-700 flex w-full max-w-xl flex-row flex-wrap items-center justify-start gap-x-4 gap-y-1 border-b p-1"> -
- Type? + +
+ Location: + + +
- - - - - - - + +
+ Type: + {#each [ + ['', 'All', 'Show all meeting types'], + ['IDAA', 'IDAA', 'Open to IDAA members only'], + ['Caduceus', 'Caduceus', 'Open to all healthcare workers including those who do not qualify for IDAA'], + ['Family Recovery', 'Family Recovery', 'Open to spouses, parents, and children of medical professionals in recovery'] + ] as [val, label, tip]} + {@const active = val === '' ? !$idaa_loc.recovery_meetings.qry__type : $idaa_loc.recovery_meetings.qry__type === val} + + {/each} +
{#if $ae_loc.edit_mode} {/if}