Skip to content

Organisations

Organisation components serve three audiences: the public feed (OrganizationsInfiniteFeed, OrganizationCard), the signed-in user’s own memberships and invitations (OrganizationsTabs and the User*Card trio), and organisation admins (the members screens and the two forms). There are no barrel files; import each component from its file path. Client cards send fetch calls to /api/organizations/{orgId}/… and then call router.refresh(); invites are the exception and go through the inviteMember server action.

See also: Organisations feature

flowchart LR
  Page["settings page (server)<br/>fetches members / invites / requests"] --> Tab["AllMembersTab / InvitationsTab / RequestsTab"]
  Tab --> Card["MemberCard / InviteCard / JoinRequestCard"]
  Card -- "POST / PATCH / DELETE /api/organizations/{orgId}/…" --> API[(API route)]
  Card -- "router.refresh()" --> Page
  Header[OrgMembersHeader] --> Modal[InviteMemberModal]
  Modal -- "inviteMember(orgId, data)" --> Action[(server action)]

A paginated two-column grid of OrganizationCards, built on GenericInfiniteFeed with entity="organizations".

Source: src/components/organizations/OrganizationsInfiniteFeed.tsx

The underline NavTabs for “My Organisations”: Active Organisations, Invitations and Requests to join. OrganizationsTabs is async and adds pending counts to the Invitations and Requests tabs; OrganizationsTabsFallback renders the same tabs without counts and serves as the Suspense fallback. Count queries run in parallel; if one fails the error is logged and the tab renders without that count.

Source: src/components/organizations/OrganizationsTabs.tsx

A feed card showing the logo, name, mission, member/project/article counts, an optional role line, and a “View” affordance. The whole card links to /organizations/{slug} via an overlay <Link> with prefetch={false}; a count is shown only when it is greater than 0.

Source: src/components/organizations/cards/OrganizationCard.tsx

A collapsible admin card for one organisation member with a role select (Member/Admin) and removal behind a confirmation. Owners show a read-only “Owner” field and have no remove action.

Source: src/components/organizations/cards/MemberCard.tsx

A collapsible admin card for a pending invitation showing the invitee name and role. The card’s cancel action removes the invite immediately with no confirmation dialog.

Source: src/components/organizations/cards/InviteCard.tsx

A collapsible admin card for a user’s join request with Accept and Reject buttons. Both buttons are disabled while either request is in flight.

Source: src/components/organizations/cards/JoinRequestCard.tsx

A collapsible card for one of the signed-in user’s own memberships. Owners and admins see “Edit Organisation” (switches account then pushes /settings); other members see “Leave Organisation” behind a confirmation.

Source: src/components/organizations/cards/UserMembershipCard.tsx

A collapsible card for an invitation the signed-in user received, with Accept and Decline buttons. Decline requires a confirmation.

Source: src/components/organizations/cards/UserInviteCard.tsx

A collapsible card for a join request the signed-in user sent, with a “Cancel Request” button behind a confirmation.

Source: src/components/organizations/cards/UserJoinRequestCard.tsx

The create-organisation form with three FormSectionCards (Identity, Media, Links & Social Media), a FormSidebar section tracker, and a “Create Organisation” button. Form state and moderation handling come from useOrganizationForm(); on success it routes to /organizations/{slug}. The back button opens a “Discard Changes” confirmation.

Source: src/components/organizations/form/OrganizationForm.tsx

Name, slug, organisation type, mission, description, contact email, and location fields. The slug auto-syncs to slugify(name) until the user edits it directly.

Source: src/components/organizations/form/steps/IdentityStep.tsx

Logo and cover image upload fields using FormImageUpload. Removing an image sets its field to null.

Source: src/components/organizations/form/steps/MediaStep.tsx

Website and LinkedIn URL fields plus a repeatable custom_links list managed with useFieldArray.

Source: src/components/organizations/form/steps/LinksStep.tsx

The organisation settings page for an existing organisation, with Identity, About, Social Links, and (owners only) Danger Zone cards. Key behaviours:

  • Images and custom-link deletions commit immediately; undo and navigating away restore saved form values but do not revert those changes.
  • The slug re-syncs to slugify(name) only after the name field has been edited, so mounting never overwrites a stored slug.
  • A 422 response with a moderation body opens ModerationRejectedDialog; a 503 is treated as a moderation failure.
  • The Danger Zone is visible to owners only and deletes the organisation, switches the active account back to user, and redirects to /.

Source: src/components/organizations/form/OrganizationSettingsForm.tsx

The “Organisation Members” heading with an “Invite Member” button that opens InviteMemberModal. Calls router.refresh() after a successful invite.

Source: src/components/organizations/members/OrgMembersHeader.tsx

A dialog form for inviting a user, with a user search (InputSearchSelect against /api/users/search) and a role select (Member/Admin, default member). Submit calls the inviteMember(orgId, data) server action.

Source: src/components/organizations/members/InviteMemberModal.tsx

Shows pending join requests first, then pending invites, then members. Renders EmptyState when all three lists are empty.

Source: src/components/organizations/members/AllMembersTab.tsx

A list of pending invites rendered as InviteCards. Renders EmptyState (“No pending invitations”) when empty.

Source: src/components/organizations/members/InvitationsTab.tsx

A list of pending join requests rendered as JoinRequestCards. Renders EmptyState (“No pending requests”) when empty.

Source: src/components/organizations/members/RequestsTab.tsx