Commit Graph
23 Commits
Author SHA1 Message Date
Moheeb ZaraandClaude Opus 4.8 9100532bef refactor(members): decompose members-client + fix form-field focus bug (slice 8)
663-line members-client.tsx → a 255-line orchestrator + members/components/
{member-form-dialog,members-table,members-toolbar}.tsx + types.ts. The add/edit
form fields (previously defined INSIDE render, which remounted and lost input
focus every keystroke) are now a stable top-level component in member-form-dialog
— fixing that footgun. tsc 0, build ok.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-04 06:14:25 -07:00
Moheeb ZaraandClaude Opus 4.8 70b85a20fa fix(members): repair broken member-directory visibility gate
member_directory_visibility is the directory_visibility enum
(board_only|member_count_visible|members_visible|public_members_visible), but
the gate compared against 'board_visible'/'admin_only' — values from other
enums that never match — so every setting except members_visible silently
restricted the directory, including public_members_visible (meant to be the
most open). Map the gate to the real enum values.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-01 21:19:29 -07:00
Moheeb ZaraandClaude Opus 4.8 da11127ca4 fix(members): guard nullable display_name/email in the members list (M6)
Typing into the members search box called .toLowerCase() on display_name/email,
both of which are nullable (e.g. imported members) — a single null row threw a
TypeError and blanked the entire members page. Optional-chain the search match,
and handle nullable values when seeding the edit form and optimistic update.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-01 21:19:29 -07:00
Moheeb Zara 390046a96b feat(ux): bulk member select + Approve selected
New bulkApproveMembers server action (ADMIN_ROLES, Zod-validated ids,
one batched space-scoped update that only flips still-unverified rows,
audited). Members table + mobile cards get a selection checkbox (admin
only) with a header select-all; a sticky bar shows the count with
Approve selected / Clear. Optimistic local update + toast.
2026-05-17 02:00:58 -07:00
Moheeb Zara 9d419fe164 feat(ux): mobile card layouts for members & payments tables
The two dense tables were overflow-x-auto only; on phones the action
buttons sat off-screen. Table is now hidden md:block; under md a stacked
card list renders the same data + key actions reusing the existing
handlers/dialogs (members: approve/edit/certs/cards/forms/remove;
payments: link member). Desktop unchanged.
2026-05-17 01:54:14 -07:00
Moheeb Zara b8440e9c9e perf(ux): request-cached permission checks (dedupe RPC fan-out)
New React cache()-wrapped hasPermission(uid,sid,perm): identical checks
resolve once per server render, so the (app) layout's nav-permission
resolution and a page's checks for the same perm (door.manage,
forms.manage) no longer double-round-trip user_has_permission. Pure
dedupe -- semantics unchanged, permission logic stays in SQL/RLS.
Adopted in the layout + members page.
2026-05-17 01:36:54 -07:00
Moheeb Zara c87cb35d87 feat(ux): content-shaped route skeletons + disable Cancel during submit
Per-route loading.tsx for dashboard/members/payments (content-shaped
Skeletons instead of the single global full-page spinner) so heavy
server pages paint structure immediately. Add/Edit member + Log cash
modals now disable Cancel while the submit is in flight (was clickable
mid-insert).
2026-05-17 01:24:10 -07:00
Moheeb Zara 4feecdaad0 feat(ux): sortable members table (name/tier/joined/last payment/status)
Clickable column headers cycle asc -> desc -> none with a caret
indicator; pure client state over the already-filtered list. Lets a
100+-member space sort by last payment or join date (the core dues/
onboarding workflows).
2026-05-17 01:22:03 -07:00
Moheeb Zara ed8d629472 feat(forms): per-member 'Forms submitted' view on the members page
listMemberSubmissions (forms.manage, RLS-honoring, metadata only) + a
FORMS column/button -> MemberFormsDialog listing the member's
submissions (title, kind, version, date) with a link to the audited
forms results surface. Gated by forms.manage (matches existing
submission-read RLS; no new exposure).
2026-05-16 23:50:52 -07:00
Moheeb Zara a8892a2dc8 feat(door): P1 member access cards + door permissions
Migration 034 adds member_cards (RFID/NFC UID -> member). The card UID
is treated as a credential: door.manage-only RLS with no member SELECT
policy; the member's own "My access cards" view goes through a service
-client action that returns only count + last4 (never the raw UID).
New door.manage / door.operate permissions (group Access), seeded to
board and backfilled, introduced now for the whole Door epic. Pure
door-logic masking is unit-tested. A per-member "Cards" panel on
/members is gated to door.manage (independent of admin). No controller
calls and no anonymous path in this phase. Mirrored in schema.sql; types
and schema docs updated.
2026-05-16 20:13:22 -07:00
Moheeb Zara af503c3869 feat(certifications): per-member award/revoke panel on Members
A "Certs" column appears for anyone holding certifications.grant (the
Instructor capability), independent of admin/board, so a non-admin
instructor can reach it. The button opens a self-contained dialog that
loads the member's grants and the active cert catalog, and supports
award (with optional note + expiry override), soft revoke, and renew.
Status badges come from the shared certifications-logic. The members
server page resolves certifications.grant via the RPC and passes it in.
2026-05-16 18:59:44 -07:00
Moheeb Zara 04f1a31999 fix(members): surface invite-link UI on the members page
The first-run "Invite or add members" step links to /members, but
invite creation only lived in Customize, so the page dead-ended. Reuse
the existing InvitesPanel: the members server page loads invites + space
slug for admin/board and composes the panel into MembersClient via an
inviteSlot prop (MembersClient stays unaware of invites). First-run copy
updated to match.
2026-05-16 18:26:42 -07:00
Moheeb Zara 108c2a54cb feat(ux): convert all hand-rolled modals to accessible Radix Dialog
S3 (final Tier 1 item). ops (4 modals), members/tasks/projects/
payments/contacts add-edit modals, settings integration-credentials
modal, and the payments link-member modal now use components/ui/dialog
(focus trap, ESC, aria, scroll lock for free). Forms, fields, handlers,
validation and close/reset behavior preserved verbatim; onOpenChange
mirrors the old Cancel/X reset. Removed now-unused X imports; replaced
a stray em-dash with a middot in the link-member subtitle.
2026-05-16 14:02:32 -07:00
Moheeb Zara 075b274204 fix(ux): focus visibility, tap targets, form labels, surfaced errors
- S6: unlayered :focus-visible ring for form controls and links so
  keyboard focus is perceivable (was focus:outline-none + 1px border)
- S5: >=44px touch targets at the named hotspots (dashboard actions,
  list-row buttons, ops pills/icons, customize number inputs); dense
  rows use a 44px hit area without growing row height
- S8: 28 form fields associated via id/htmlFor; search inputs get
  aria-label
- S7: claim/complete/delete/link handlers now surface result.error via
  toast and stop instead of failing silently
2026-05-16 00:00:23 -07:00
Moheeb Zara 1db9434930 feat(ux): accessible confirm dialog replaces window.confirm
- new components/ui/confirm.tsx: ConfirmProvider + useConfirm() built
  on the existing Radix alert-dialog (focus trap, ESC, aria for free)
- wired once into the app layout
- all 13 native window.confirm() delete/remove guards now use the
  styled, accessible confirm with a destructive action button
2026-05-15 22:18:15 -07:00
Moheeb Zara f885ac73d3 feat(ux): adopt shared Empty primitive across all empty states
- one Empty/EmptyHeader/EmptyMedia/EmptyTitle/EmptyDescription
  component replaces ~18 ad-hoc empty states
- projects gains a real empty state (was four bare columns) with a
  create CTA wired to the existing handler
- governance/ops/customize/comms/comments empty states unified;
  existing CTAs and conditions preserved (presentational only)
2026-05-15 22:12:52 -07:00
Moheeb Zara 92ba6fb390 feat(ux): shared PageTitle/SectionTitle primitive, adopt app-wide
- new components/ui/page-title.tsx (PageHeader/PageTitle/SectionTitle)
- every page heading routed through PageTitle (one source of truth
  for the page-title style; identical render)
- members restricted-directory screen now uses the standard
  PageHeader bar instead of an off-style mono heading
2026-05-15 22:12:52 -07:00
Moheeb Zara 4c9b55147b chore: clear audit backlog (types sync, email norm, docs, members shortcut)
Finishes all remaining tracked work from the full-app audit.

- types/database.ts synced: added the 8 missing tables (forum_threads,
  comments, space_tiers, space_invites, space_onboarding_steps,
  space_role_labels, space_custom_roles, space_member_custom_roles),
  the comment_entity_type enum (type + Constants), and the missing
  columns (space_members.tier_id/onboarding_completed_at/
  onboarding_progress, secrets.encrypted_value/encryption_version,
  knowledge_base.render_markdown).
- Email canonicalization: new emailField() helper (trim+lowercase)
  applied to signIn/signUp/addMember/updateMember/createContact and
  the import path; prevents case-variant duplicates and sign-in
  mismatches.
- Members directory: per-row "make area lead" picker (admin/board)
  assigns a member to any area-lead role; mirrors Customize.
- Docs refreshed and re-dated: DATABASE_SCHEMA.md (migrations 014-024
  summary), DB_SCHEMA_MAP.md (new-table quick map), API_REFERENCE.md
  (all server actions from migrations 016-024). schema.sql named as
  source of truth.

Backlog is now empty. 271/271 tests pass, build clean. No migration.
2026-05-15 19:01:52 -07:00
Moheeb Zara 8ad1ca44b7 feat: open-source release prep, audit fixes, and deploy hardening
Production deploy completed (DigitalOcean Droplet, self-hosted Supabase,
Caddy + Let's Encrypt, GitHub Actions auto-deploy on push to main, daily
pg_dumpall backups). This commit lands the work that came out of the
deep audit pass and the open-source release prep.

Audit fixes:
- Webhook signing secret is now displayed in the settings UI with
  show/hide and copy-to-clipboard; the broken external docs.hackerspace.sh
  link is replaced with a link to the new local docs.
- Settings updateSpaceSettings parameter type now includes
  mission_statement so the field persists.
- members page enforces member_directory_visibility for non-admin viewers
  (admin_only, board_visible, members_visible).
- Mobile responsiveness pass: Projects Kanban grid, Members + Payments
  tables (column hiding on small screens), Proposal tally + voting
  buttons (2-col on mobile).

Open-source release scaffolding:
- LICENSE (MIT).
- CONTRIBUTING.md with dev setup, conventions, PR flow.
- SECURITY.md with disclosure policy.
- CHANGELOG.md.
- docs/WEBHOOKS.md with Node and Python signature verification examples.
- README.md rewritten for an open-source audience.

Removed v0/Vercel references:
- @vercel/analytics dependency removed.
- app/layout.tsx no longer imports Analytics, drops generator: 'v0.app'.
- Canonical deployment docs (docs/DEPLOYMENT.md, docs/README.md,
  docs/ARCHITECTURE.md, DATABASE.md, CLAUDE.md, README.md) now describe
  the self-hosted Droplet target only.
- e2e console-error check no longer filters [v0] noise.

Landing page:
- GitHub icon link to the public repo in the nav and footer.
2026-05-14 16:28:16 -07:00
v0andMoheeb Zara 2e136b5f55 refactor: generate and use Supabase TypeScript types
Co-authored-by: Moheeb Zara <[email protected]>
2026-03-11 08:12:39 +00:00
v0andMoheeb Zara 8cdb9dbb87 fix: resolve member status check bugs
Fix '.eq('status', 'current')' in all actions and page-level files.

Co-authored-by: Moheeb Zara <[email protected]>
2026-03-11 07:49:53 +00:00
v0andMoheeb Zara 1036e1ff5e feat: make app fully mobile-responsive
Update layout, headers, tables, kanban, comms, forms, and modals for mobile.

Co-authored-by: Moheeb Zara <[email protected]>
2026-03-11 07:20:17 +00:00
v0 296c5dd78d Initial commit from v0 2026-03-11 04:44:48 +00:00