+
+ {/* Header */}
+
+
+
+
+
+ {hasInvites ? "You have an invitation!" : "Set up your organisation"}
+
+
+ {hasInvites
+ ? "Join an existing organisation or create your own."
+ : "Create your organisation to get started. You'll be set as the Owner."}
+
+
+
+ {/* Loading skeleton while fetching invites */}
+ {invitesLoading ? (
+
+
+
+ ) : (
+ <>
+
+ {/* ── Pending invitations ────────────────────────────────────────────── */}
+ {hasInvites && (
+
+
+
+ Invitation{pendingInvites.length > 1 ? "s" : ""} for your email
+
+
+ {joinError &&
}
+
+ {pendingInvites.map((invite) => (
+
+
+
+ {invite.organization.name}
+
+
+ You were invited as{" "}
+ {invite.role}
+
+
+
handleJoinOrg(invite)}
+ data-testid="join-org-btn"
+ >
+ {joiningToken === invite.token ? (
+
+ ) : (
+ "Join"
+ )}
+
+
+ ))}
+
+ )}
+
+ {/* ── Divider ───────────────────────────────────────────────────────── */}
+ {hasInvites && (
+
+ )}
+
+ {/* ── Create organisation (collapsible when invites are present) ─────── */}
+ {hasInvites ? (
+
+ {/* Toggle header */}
+
setCreateOpen((o) => !o)}
+ data-testid="create-org-toggle"
+ >
+
+
+ Create a new organisation
+
+ {createOpen
+ ?
+ :
+ }
+
+
+ {/* Collapsible form */}
+ {createOpen && (
+
+
+
+ )}
+
+ ) : (
+ /* No invites — show the form directly */
+
+ )}
+ >
+ )}
+
+ );
+}
+
+// ── Reusable create-org form ─────────────────────────────────────────────────
+interface CreateOrgFormProps {
+ orgName: string;
+ orgSlug: string;
+ isCreating: boolean;
+ createError: string | null;
+ onNameChange: (v: string) => void;
+ onSlugChange: (v: string) => void;
+ onSubmit: (e: React.FormEvent) => void;
+}
+
+function CreateOrgForm({
+ orgName, orgSlug, isCreating, createError,
+ onNameChange, onSlugChange, onSubmit,
+}: CreateOrgFormProps) {
+ return (
+
-
-
-
-
-
- Check your email
-
-
- We've sent a verification link to {email} .
- Click the link to verify your account and get started.
-
-
-
-
-
- Continue to sign in
-
-
-
-
-
-
- Didn't receive the email?{" "}
- setState("form")}
- className="text-accent hover:underline font-medium"
- >
- Try again
-
-
-
- );
- }
-
// Registration form
return (
diff --git a/src/pages/org/MembersPage.tsx b/src/pages/org/MembersPage.tsx
index 0326575..eb716df 100644
--- a/src/pages/org/MembersPage.tsx
+++ b/src/pages/org/MembersPage.tsx
@@ -186,7 +186,7 @@ export default function MembersPage() {
if (!orgId || !changeRoleMember) return;
setIsChangingRole(true);
try {
- const updated = await api.organizations.updateMemberRole(orgId, changeRoleMember.user_id, newRole.toUpperCase());
+ const updated = await api.organizations.updateMemberRole(orgId, changeRoleMember.user_id, newRole.toLowerCase());
setMembers((prev) =>
prev.map((m) => (m.id === changeRoleMember.id ? { ...m, role: updated.member.role } : m))
);
@@ -331,7 +331,7 @@ export default function MembersPage() {
-
+
Pending invitations
{isInvitesLoading ? 'Loading...' : `${invites.length}`}
@@ -374,9 +374,11 @@ export default function MembersPage() {
-
-
-
Send an invitation
+
+
+
+
Send an invitation
+