@streamoid/settings 0.6.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ __export(index_exports, {
32
32
  MemberListFrame: () => MemberListFrame,
33
33
  MemberListToolbar: () => MemberListToolbar,
34
34
  OrganizationContent: () => OrganizationContent,
35
- OrganizationInviteModal: () => OrganizationInviteModal,
35
+ OrganizationMemberModal: () => OrganizationMemberModal,
36
36
  OrganizationModal: () => OrganizationModal,
37
37
  ProfileAvatar: () => ProfileAvatar,
38
38
  ProfileTab: () => ProfileTab,
@@ -54,6 +54,7 @@ __export(index_exports, {
54
54
  WorkspaceGeneralTab: () => WorkspaceGeneralTab,
55
55
  WorkspaceListTab: () => WorkspaceListTab,
56
56
  WorkspaceModal: () => WorkspaceModal,
57
+ WorkspacePicker: () => WorkspacePicker,
57
58
  WorkspaceTab: () => WorkspaceTab,
58
59
  countLabel: () => countLabel,
59
60
  loadWorkspaceOrganization: () => loadWorkspaceOrganization,
@@ -431,8 +432,9 @@ function WorkspaceModal({
431
432
  let cancelled = false;
432
433
  organizationAdapter.list().then((orgs) => {
433
434
  if (cancelled) return;
434
- setAvailableOrgs(orgs);
435
- setSelectedOrgId((prev) => prev || orgs[0]?._id || "");
435
+ const joinable = orgs.filter((org) => org.role !== "guest");
436
+ setAvailableOrgs(joinable);
437
+ setSelectedOrgId((prev) => prev || joinable[0]?._id || "");
436
438
  }).catch(() => {
437
439
  if (!cancelled) setAvailableOrgs([]);
438
440
  });
@@ -547,7 +549,7 @@ function WorkspaceModal({
547
549
  async function handleLeaveOrganization() {
548
550
  if (orgActionSubmitting || !workspaceAdapter.leaveOrganization) return;
549
551
  const confirmed = window.confirm(
550
- "Leave this organization? Members of the organization will lose any implicit access to this workspace."
552
+ "Take this workspace out of the organization? It will no longer be listed in the workspace picker, and org admins will lose access unless they are members."
551
553
  );
552
554
  if (!confirmed) return;
553
555
  setOrgActionSubmitting(true);
@@ -892,7 +894,7 @@ function WorkspaceModal({
892
894
  color: active ? "#ffffff" : T.muted,
893
895
  textAlign: "center"
894
896
  },
895
- children: opt === "private" ? "Private" : "Visible to organization"
897
+ children: opt === "private" ? "Private" : "Listed in picker"
896
898
  }
897
899
  ) })
898
900
  },
@@ -1643,7 +1645,7 @@ var TAB_TO_URL = {
1643
1645
  workspaceList: "workspace/all",
1644
1646
  organization: "organization/people",
1645
1647
  organizationWorkspaces: "organization/workspaces",
1646
- organizationDomains: "organization/domains",
1648
+ organizationDomains: "organization/workspaces",
1647
1649
  referral: "referral",
1648
1650
  billing: "billing",
1649
1651
  apikey: "api-keys"
@@ -1655,7 +1657,8 @@ var URL_TO_TAB = {
1655
1657
  "workspace/all": "workspaceList",
1656
1658
  "organization/people": "organization",
1657
1659
  "organization/workspaces": "organizationWorkspaces",
1658
- "organization/domains": "organizationDomains",
1660
+ /* The Domains tab is gone; its join requests live under Workspaces. */
1661
+ "organization/domains": "organizationWorkspaces",
1659
1662
  /* Unscoped destinations. */
1660
1663
  account: "profile",
1661
1664
  referral: "referral",
@@ -1674,7 +1677,7 @@ var TAB_LABELS = {
1674
1677
  workspaceList: "My workspaces",
1675
1678
  organization: "People",
1676
1679
  organizationWorkspaces: "Workspaces",
1677
- organizationDomains: "Domains & requests",
1680
+ organizationDomains: "Workspaces",
1678
1681
  referral: "Referral",
1679
1682
  /* "Billing & usage", not "Billing". The tab has held usage history as well
1680
1683
  as the plan and invoices since the credits work, and hosts had started
@@ -1688,9 +1691,9 @@ var TAB_DESCRIPTIONS = {
1688
1691
  workspace: "Rename or re-brand this workspace, or leave and delete it",
1689
1692
  workspaceMembers: "Invite people to this workspace and control which apps they can use",
1690
1693
  workspaceList: "Switch between your workspaces, or start a new one",
1691
- organization: "Everyone in the organization, and the invites still waiting to be accepted",
1692
- organizationWorkspaces: "Every workspace that sits under this organization",
1693
- organizationDomains: "Auto-join by email domain, and workspaces asking to join the organization",
1694
+ organization: "Everyone in the organization and their role",
1695
+ organizationWorkspaces: "Every workspace in this organization, and workspaces asking to join it",
1696
+ organizationDomains: "Every workspace in this organization, and workspaces asking to join it",
1694
1697
  referral: "Invite friends to Streamoid and track the rewards you have earned",
1695
1698
  billing: "Workspace plan, credits, invoices and usage history",
1696
1699
  apikey: "Create and revoke keys for calling the Streamoid APIs"
@@ -2309,7 +2312,7 @@ function OrganizationAffiliationCard({
2309
2312
  style: { gap: T5.spMd, opacity: submitting ? 0.6 : 1 },
2310
2313
  children: [
2311
2314
  workspaceAdapter.setOrgVisibility && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-start w-full", style: { gap: T5.spXs }, children: [
2312
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldLabel, { children: "Who in the organization can see this workspace" }),
2315
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldLabel, { children: "List this workspace in the organization's workspace picker" }),
2313
2316
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2314
2317
  "div",
2315
2318
  {
@@ -2340,11 +2343,11 @@ function OrganizationAffiliationCard({
2340
2343
  if (active || !workspaceAdapter.setOrgVisibility) return;
2341
2344
  void run(
2342
2345
  () => workspaceAdapter.setOrgVisibility(opt),
2343
- opt === "private" ? "Workspace is now private" : "Workspace is now visible to the organization",
2346
+ opt === "private" ? "Workspace is now private" : "Workspace is now listed in the workspace picker",
2344
2347
  "Failed to change visibility"
2345
2348
  );
2346
2349
  },
2347
- children: opt === "private" ? "Only workspace members" : "Everyone in the organization"
2350
+ children: opt === "private" ? "Private (invite only)" : "Listed in the workspace picker"
2348
2351
  },
2349
2352
  opt
2350
2353
  );
@@ -2370,7 +2373,7 @@ function OrganizationAffiliationCard({
2370
2373
  },
2371
2374
  onClick: () => {
2372
2375
  const confirmed = window.confirm(
2373
- "Leave this organization? Members of the organization will lose any implicit access to this workspace."
2376
+ "Take this workspace out of the organization? It will no longer be listed in the workspace picker, and org admins will lose access unless they are members."
2374
2377
  );
2375
2378
  if (!confirmed || !workspaceAdapter.leaveOrganization) return;
2376
2379
  void run(
@@ -2763,12 +2766,13 @@ function InviteUpdateModal({
2763
2766
  organizationName,
2764
2767
  allowGuestStanding = true,
2765
2768
  initialOrganizationStanding = "guest",
2769
+ organizationDomain,
2766
2770
  onInvite
2767
2771
  }) {
2768
2772
  useOverlayOpen(open, onClose);
2769
2773
  const [emailValue, setEmailValue] = (0, import_react8.useState)("");
2770
2774
  const [hasChanges, setHasChanges] = (0, import_react8.useState)(false);
2771
- const [role, setRole] = (0, import_react8.useState)("admin");
2775
+ const [role, setRole] = (0, import_react8.useState)("member");
2772
2776
  const [orgStanding, setOrgStanding] = (0, import_react8.useState)(
2773
2777
  initialOrganizationStanding
2774
2778
  );
@@ -2807,7 +2811,7 @@ function InviteUpdateModal({
2807
2811
  if (!open) {
2808
2812
  setEmailValue("");
2809
2813
  setHasChanges(false);
2810
- setRole("admin");
2814
+ setRole("member");
2811
2815
  setOrgStanding(initialOrganizationStanding);
2812
2816
  setCanUseCredits(true);
2813
2817
  setCanInviteUser(true);
@@ -2819,6 +2823,14 @@ function InviteUpdateModal({
2819
2823
  setSelectedStores(/* @__PURE__ */ new Set());
2820
2824
  }
2821
2825
  }, [open, initialPermissions, hiddenKey, initialOrganizationStanding]);
2826
+ const orgDomain = (organizationDomain || "").trim().toLowerCase();
2827
+ const inviteeDomains = emailValue.split(/[\s,;]+/).map((email) => email.trim().toLowerCase().split("@")[1] || "").filter(Boolean);
2828
+ const inviteeIsGuest = mode === "invite" && inviteeDomains.some(
2829
+ (domain) => !(orgDomain && domain === orgDomain) && (showOrganizationStanding ? orgStanding === "guest" : !!orgDomain)
2830
+ );
2831
+ (0, import_react8.useEffect)(() => {
2832
+ if (inviteeIsGuest && role === "admin") setRole("member");
2833
+ }, [inviteeIsGuest, role]);
2822
2834
  if (!open) return null;
2823
2835
  const isInvite = mode === "invite";
2824
2836
  const hasEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue.trim());
@@ -3009,12 +3021,15 @@ function InviteUpdateModal({
3009
3021
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3010
3022
  "div",
3011
3023
  {
3012
- className: "flex-1 min-w-0 cursor-pointer",
3024
+ className: `flex-1 min-w-0 ${inviteeIsGuest ? "cursor-not-allowed" : "cursor-pointer"}`,
3025
+ "aria-disabled": inviteeIsGuest,
3013
3026
  style: {
3014
3027
  background: role === "admin" ? T6.neutral300 : "transparent",
3015
- borderRadius: T6.rMd
3028
+ borderRadius: T6.rMd,
3029
+ opacity: inviteeIsGuest ? 0.4 : 1
3016
3030
  },
3017
3031
  onClick: () => {
3032
+ if (inviteeIsGuest) return;
3018
3033
  setRole("admin");
3019
3034
  setCanUseCredits(true);
3020
3035
  setCanInviteUser(true);
@@ -3088,6 +3103,19 @@ function InviteUpdateModal({
3088
3103
  ) })
3089
3104
  ]
3090
3105
  }
3106
+ ),
3107
+ inviteeIsGuest && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3108
+ "span",
3109
+ {
3110
+ style: {
3111
+ fontFamily: T6.font,
3112
+ fontSize: T6.fsXs,
3113
+ fontWeight: 400,
3114
+ lineHeight: T6.lhXs,
3115
+ color: T6.tertiary
3116
+ },
3117
+ children: "Guests can only be Members."
3118
+ }
3091
3119
  )
3092
3120
  ]
3093
3121
  }
@@ -3277,7 +3305,7 @@ function InviteUpdateModal({
3277
3305
  lineHeight: T6.lhXs,
3278
3306
  color: T6.tertiary
3279
3307
  },
3280
- children: orgStanding === "colleague" ? `Joins ${organizationName || "the organization"} as a member \u2014 they'll also see its shared workspaces.` : `This workspace only. They see nothing else in ${organizationName || "the organization"}.`
3308
+ children: orgStanding === "colleague" ? `Joins ${organizationName || "the organization"} as a member \u2014 they can also join its shared workspaces.` : `This workspace only, as a member. They see nothing else in ${organizationName || "the organization"}.`
3281
3309
  }
3282
3310
  )
3283
3311
  ]
@@ -3972,7 +4000,19 @@ function MemberListToolbar({
3972
4000
  className: "flex flex-wrap items-center justify-between shrink-0 w-full",
3973
4001
  style: { gap: "var(--spacing-md)" },
3974
4002
  children: [
3975
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4003
+ pendingCount === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4004
+ "span",
4005
+ {
4006
+ style: {
4007
+ fontFamily: T7.font,
4008
+ fontSize: T7.fsSm,
4009
+ fontWeight: 500,
4010
+ lineHeight: T7.lhSm,
4011
+ color: T7.primary
4012
+ },
4013
+ children: withCount(activeLabel, activeCount)
4014
+ }
4015
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3976
4016
  import_ui4.ScTabSwitcher,
3977
4017
  {
3978
4018
  tabCount: "2",
@@ -4938,9 +4978,9 @@ function TeamsContent({
4938
4978
  lineHeight: "var(--line-height-line-height-xs)"
4939
4979
  },
4940
4980
  children: [
4941
- "This workspace is visible to everyone in ",
4981
+ "Anyone in ",
4942
4982
  organizationName,
4943
- ", and its admins keep access whether or not they are listed here. Change that under Workspace \u203A General."
4983
+ " can join this workspace as a member from the workspace picker, and its org admins keep access whether or not they are listed here. Change that under Workspace \u203A General."
4944
4984
  ]
4945
4985
  }
4946
4986
  ),
@@ -5022,6 +5062,7 @@ function TeamsContent({
5022
5062
  ),
5023
5063
  showOrganizationStanding: mayGrantOrgMembership,
5024
5064
  organizationName: organizationName ?? orgCurrent?.name,
5065
+ organizationDomain: workspaceOrgId && orgCurrent?.id === workspaceOrgId ? orgCurrent?.domain : void 0,
5025
5066
  onInvite: handleInvite
5026
5067
  }
5027
5068
  )
@@ -5092,7 +5133,7 @@ var import_react12 = require("react");
5092
5133
  var import_ui8 = require("@streamoid/ui");
5093
5134
  var import_icons8 = require("@streamoid/icons");
5094
5135
 
5095
- // src/organization-invite-modal.tsx
5136
+ // src/organization-member-modal.tsx
5096
5137
  var import_react10 = require("react");
5097
5138
  var import_ui7 = require("@streamoid/ui");
5098
5139
  var import_icons7 = require("@streamoid/icons");
@@ -5123,33 +5164,6 @@ var T9 = {
5123
5164
  r4xl: "var(--radius-4xl)",
5124
5165
  neutral300: "var(--primitives-neutral-300)"
5125
5166
  };
5126
- function CheckboxSvg2({ checked }) {
5127
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "relative shrink-0", style: { width: 24, height: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: checked ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
5128
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5129
- "rect",
5130
- {
5131
- x: "0.75",
5132
- y: "0.75",
5133
- width: "22.5",
5134
- height: "22.5",
5135
- rx: "5.65",
5136
- fill: T9.primary,
5137
- stroke: T9.primary,
5138
- strokeWidth: "1.5"
5139
- }
5140
- ),
5141
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5142
- "path",
5143
- {
5144
- d: "M7 12.5L10.5 16L17 8",
5145
- stroke: T9.inverse,
5146
- strokeWidth: "1.5",
5147
- strokeLinecap: "round",
5148
- strokeLinejoin: "round"
5149
- }
5150
- )
5151
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: svg_rodctpja6f_default.p4792500, fill: T9.muted }) }) });
5152
- }
5153
5167
  function FieldLabel3({ text }) {
5154
5168
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center shrink-0 w-full", style: { height: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5155
5169
  "div",
@@ -5225,69 +5239,29 @@ function SegmentedToggle({
5225
5239
  }
5226
5240
  );
5227
5241
  }
5228
- function OrganizationInviteModal({
5242
+ function OrganizationMemberModal({
5229
5243
  open,
5230
- mode,
5231
5244
  userEmail = "email@domain.in",
5232
5245
  initialRole,
5233
5246
  lockRole,
5234
- canClaimDomain = true,
5235
- claimableDomain,
5236
5247
  lockedRoleLabel,
5237
- initialInviteAccess,
5238
- allowSubmitWithoutChanges = false,
5239
5248
  canRemove = true,
5240
5249
  onClose,
5241
- onInviteEmail,
5242
- onInviteDomain,
5243
5250
  onUpdate,
5244
5251
  onRemove
5245
5252
  }) {
5246
5253
  useOverlayOpen(open, onClose);
5247
- const [inviteMode, setInviteMode] = (0, import_react10.useState)("email");
5248
- const [emailValue, setEmailValue] = (0, import_react10.useState)("");
5249
- const [domainValue, setDomainValue] = (0, import_react10.useState)(claimableDomain ?? "");
5250
5254
  const [hasChanges, setHasChanges] = (0, import_react10.useState)(false);
5251
- const [role, setRole] = (0, import_react10.useState)("admin");
5252
- const [inviteAccess, setInviteAccess] = (0, import_react10.useState)(false);
5255
+ const [role, setRole] = (0, import_react10.useState)("member");
5253
5256
  (0, import_react10.useEffect)(() => {
5254
- if (open && mode === "update") {
5257
+ if (open) {
5255
5258
  setRole(initialRole ?? "member");
5256
- setInviteAccess(initialInviteAccess ?? false);
5257
- }
5258
- if (!open) {
5259
- setInviteMode("email");
5260
- setEmailValue("");
5261
- setDomainValue(claimableDomain ?? "");
5259
+ } else {
5262
5260
  setHasChanges(false);
5263
- setRole("admin");
5264
- setInviteAccess(true);
5265
5261
  }
5266
- }, [open, mode, initialRole, initialInviteAccess, claimableDomain]);
5262
+ }, [open, initialRole]);
5267
5263
  if (!open) return null;
5268
- const isInvite = mode === "invite";
5269
- const isEmailInvite = isInvite && inviteMode === "email";
5270
- const isDomainInvite = isInvite && inviteMode === "domain";
5271
- const hasEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue.trim());
5272
- const hasDomain = /^[^\s@]+\.[^\s@]+$/.test(domainValue.trim());
5273
- const isSubmitDisabled = isEmailInvite ? !hasEmail : isDomainInvite ? !hasDomain : (
5274
- // A locked role has nothing this modal can legitimately submit.
5275
- lockRole || !(allowSubmitWithoutChanges || hasChanges)
5276
- );
5277
- function markChanged() {
5278
- setHasChanges(true);
5279
- }
5280
- function handleSubmit() {
5281
- if (isEmailInvite) {
5282
- onInviteEmail?.({ email: emailValue.trim(), role, inviteAccess });
5283
- return;
5284
- }
5285
- if (isDomainInvite) {
5286
- onInviteDomain?.({ domain: domainValue.trim(), autoJoinRole: role });
5287
- return;
5288
- }
5289
- onUpdate?.({ role, inviteAccess });
5290
- }
5264
+ const isSubmitDisabled = lockRole || !hasChanges;
5291
5265
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5292
5266
  "div",
5293
5267
  {
@@ -5305,6 +5279,7 @@ function OrganizationInviteModal({
5305
5279
  borderRadius: T9.r4xl,
5306
5280
  border: `1px solid ${T9.borderSubtle}`,
5307
5281
  width: 480,
5282
+ maxWidth: "calc(100vw - 32px)",
5308
5283
  maxHeight: "85vh"
5309
5284
  },
5310
5285
  children: [
@@ -5334,7 +5309,7 @@ function OrganizationInviteModal({
5334
5309
  fontWeight: 600,
5335
5310
  lineHeight: T9.lhLg
5336
5311
  },
5337
- children: isInvite ? "Invite to organization" : "Update member"
5312
+ children: "Update member"
5338
5313
  }
5339
5314
  ),
5340
5315
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "shrink-0 cursor-pointer", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons7.SiconClose, { className: "w-6 h-6", color: T9.primary }) })
@@ -5348,116 +5323,41 @@ function OrganizationInviteModal({
5348
5323
  className: "flex flex-col items-start w-full",
5349
5324
  style: { padding: `${T9.sp3xl} ${T9.sp6xl}`, gap: T9.sp3xl },
5350
5325
  children: [
5351
- isInvite && canClaimDomain && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5352
- "div",
5353
- {
5354
- className: "flex flex-col items-start justify-center shrink-0 w-full",
5355
- style: { gap: T9.spXs },
5356
- children: [
5357
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(FieldLabel3, { text: "Invite by" }),
5358
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5359
- SegmentedToggle,
5360
- {
5361
- options: [
5362
- { value: "email", label: "Email" },
5363
- { value: "domain", label: "Domain" }
5364
- ],
5365
- value: inviteMode,
5366
- onChange: setInviteMode
5367
- }
5368
- )
5369
- ]
5370
- }
5371
- ),
5372
5326
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5373
5327
  "div",
5374
5328
  {
5375
5329
  className: "flex flex-col items-start justify-center shrink-0 w-full",
5376
5330
  style: { gap: T9.spXs },
5377
5331
  children: [
5378
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5379
- FieldLabel3,
5380
- {
5381
- text: isDomainInvite ? "Domain" : isEmailInvite ? "Email ID" : "Email ID"
5382
- }
5383
- ),
5332
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(FieldLabel3, { text: "Email ID" }),
5384
5333
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5385
5334
  "div",
5386
5335
  {
5387
5336
  className: "shrink-0 w-full",
5388
5337
  style: { background: T9.fillPlus, height: 48, borderRadius: T9.r3xl },
5389
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5338
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5390
5339
  "div",
5391
5340
  {
5392
5341
  className: "flex items-center relative size-full",
5393
5342
  style: { padding: `${T9.spXl} ${T9.sp3xl}` },
5394
- children: [
5395
- isEmailInvite && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5396
- "input",
5397
- {
5398
- className: "flex-1 min-w-0 bg-transparent border-none outline-none",
5399
- style: {
5400
- fontFamily: T9.font,
5401
- fontSize: T9.fsSm,
5402
- fontWeight: 400,
5403
- lineHeight: T9.lhSm,
5404
- color: T9.primary
5405
- },
5406
- placeholder: "email@domain.in",
5407
- value: emailValue,
5408
- onChange: (e) => setEmailValue(e.target.value)
5409
- }
5410
- ),
5411
- isDomainInvite && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5412
- "span",
5413
- {
5414
- className: "flex-1 min-w-0 truncate",
5415
- style: {
5416
- fontFamily: T9.font,
5417
- fontSize: T9.fsSm,
5418
- fontWeight: 400,
5419
- lineHeight: T9.lhSm,
5420
- color: T9.primary
5421
- },
5422
- children: domainValue
5423
- }
5424
- ),
5425
- !isInvite && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5426
- "div",
5427
- {
5428
- className: "flex-1 flex flex-col justify-center",
5429
- style: {
5430
- fontFamily: T9.font,
5431
- fontSize: T9.fsSm,
5432
- fontWeight: 400,
5433
- lineHeight: T9.lhSm,
5434
- color: T9.muted,
5435
- opacity: 0.6
5436
- },
5437
- children: userEmail
5438
- }
5439
- )
5440
- ]
5343
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5344
+ "div",
5345
+ {
5346
+ className: "flex-1 flex flex-col justify-center truncate",
5347
+ style: {
5348
+ fontFamily: T9.font,
5349
+ fontSize: T9.fsSm,
5350
+ fontWeight: 400,
5351
+ lineHeight: T9.lhSm,
5352
+ color: T9.muted,
5353
+ opacity: 0.6
5354
+ },
5355
+ children: userEmail
5356
+ }
5357
+ )
5441
5358
  }
5442
5359
  ) })
5443
5360
  }
5444
- ),
5445
- isDomainInvite && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5446
- "span",
5447
- {
5448
- style: {
5449
- fontFamily: T9.font,
5450
- fontSize: T9.fsSm,
5451
- fontWeight: 400,
5452
- color: T9.muted
5453
- },
5454
- children: [
5455
- "Anyone who signs up or logs in with an @",
5456
- domainValue.trim(),
5457
- " ",
5458
- "address will automatically join this organization from now on."
5459
- ]
5460
- }
5461
5361
  )
5462
5362
  ]
5463
5363
  }
@@ -5468,7 +5368,7 @@ function OrganizationInviteModal({
5468
5368
  className: "flex flex-col items-start justify-center shrink-0 w-full",
5469
5369
  style: { gap: T9.spXs },
5470
5370
  children: [
5471
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(FieldLabel3, { text: isDomainInvite ? "Auto-join role" : "Role" }),
5371
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(FieldLabel3, { text: "Role" }),
5472
5372
  lockRole ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5473
5373
  "span",
5474
5374
  {
@@ -5480,49 +5380,33 @@ function OrganizationInviteModal({
5480
5380
  },
5481
5381
  children: [
5482
5382
  lockedRoleLabel || "Guest",
5483
- " \u2014 invited to specific workspaces only, with no access to the rest of the organization. Remove them to end that access."
5383
+ " \u2014 invited to specific workspaces only, with no access to the rest of the organization. Guests can't be made members or admins. Remove them to end that access."
5484
5384
  ]
5485
5385
  }
5486
5386
  ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5487
5387
  SegmentedToggle,
5488
5388
  {
5489
5389
  options: [
5490
- { value: "admin", label: "Admin" },
5390
+ { value: "admin", label: "Org admin" },
5491
5391
  { value: "member", label: "Member" }
5492
5392
  ],
5493
5393
  value: role,
5494
5394
  onChange: (v) => {
5495
5395
  setRole(v);
5496
- if (v === "admin") setInviteAccess(true);
5497
- markChanged();
5396
+ setHasChanges(v !== (initialRole ?? "member"));
5498
5397
  }
5499
5398
  }
5500
- )
5501
- ]
5502
- }
5503
- ),
5504
- !isDomainInvite && !lockRole && role === "member" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5505
- "div",
5506
- {
5507
- className: "flex items-center shrink-0 w-full cursor-pointer",
5508
- style: { gap: T9.spMd },
5509
- onClick: () => {
5510
- setInviteAccess(!inviteAccess);
5511
- markChanged();
5512
- },
5513
- children: [
5514
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CheckboxSvg2, { checked: inviteAccess }),
5515
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5399
+ ),
5400
+ !lockRole && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5516
5401
  "span",
5517
5402
  {
5518
5403
  style: {
5519
5404
  fontFamily: T9.font,
5520
5405
  fontSize: T9.fsSm,
5521
- fontWeight: 400,
5522
5406
  lineHeight: T9.lhSm,
5523
- color: T9.primary
5407
+ color: T9.muted
5524
5408
  },
5525
- children: "Can invite members"
5409
+ children: "Org admins can see and manage every workspace in the organization."
5526
5410
  }
5527
5411
  )
5528
5412
  ]
@@ -5543,10 +5427,10 @@ function OrganizationInviteModal({
5543
5427
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5544
5428
  "div",
5545
5429
  {
5546
- className: `flex items-center w-full ${isInvite ? "justify-end" : "justify-between"}`,
5430
+ className: "flex items-center w-full justify-between",
5547
5431
  style: { padding: `${T9.sp3xl} ${T9.sp6xl}` },
5548
5432
  children: [
5549
- !isInvite && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5433
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5550
5434
  import_ui7.ScButton,
5551
5435
  {
5552
5436
  text: "Remove member",
@@ -5559,11 +5443,11 @@ function OrganizationInviteModal({
5559
5443
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5560
5444
  import_ui7.ScButton,
5561
5445
  {
5562
- text: isEmailInvite ? "Send invite" : isDomainInvite ? "Add domain" : allowSubmitWithoutChanges ? "Resend invite" : "Save changes",
5446
+ text: "Save changes",
5563
5447
  variant: "primary",
5564
5448
  size: "md",
5565
5449
  state: isSubmitDisabled ? "disabled" : "default",
5566
- onClick: !isSubmitDisabled ? handleSubmit : void 0
5450
+ onClick: !isSubmitDisabled ? () => onUpdate?.({ role }) : void 0
5567
5451
  }
5568
5452
  )
5569
5453
  ]
@@ -6057,20 +5941,6 @@ function formatDate(iso) {
6057
5941
  return iso;
6058
5942
  }
6059
5943
  }
6060
- function toDisplayText2(value, fallback = "\u2013") {
6061
- if (typeof value === "string") {
6062
- const trimmed = value.trim();
6063
- return trimmed.length > 0 ? trimmed : fallback;
6064
- }
6065
- if (value && typeof value === "object") {
6066
- const record = value;
6067
- const name = typeof record.name === "string" ? record.name.trim() : "";
6068
- if (name) return name;
6069
- const email = typeof record.email === "string" ? record.email.trim() : "";
6070
- if (email) return email;
6071
- }
6072
- return fallback;
6073
- }
6074
5944
  function VisibilityBadge({ visibility }) {
6075
5945
  const isShared = visibility === "shared";
6076
5946
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
@@ -6091,10 +5961,46 @@ function VisibilityBadge({ visibility }) {
6091
5961
  }
6092
5962
  );
6093
5963
  }
5964
+ function RowIconButton({
5965
+ label,
5966
+ onClick,
5967
+ children,
5968
+ visible = true
5969
+ }) {
5970
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5971
+ "button",
5972
+ {
5973
+ type: "button",
5974
+ "aria-label": label,
5975
+ title: label,
5976
+ className: "flex items-center justify-center shrink-0 cursor-pointer border-none",
5977
+ style: {
5978
+ width: 32,
5979
+ height: 32,
5980
+ borderRadius: T11.rLg,
5981
+ background: "transparent",
5982
+ opacity: visible ? 1 : 0,
5983
+ transition: "opacity 120ms ease"
5984
+ },
5985
+ onMouseEnter: (e) => {
5986
+ e.currentTarget.style.background = T11.fillPlus;
5987
+ },
5988
+ onMouseLeave: (e) => {
5989
+ e.currentTarget.style.background = "transparent";
5990
+ },
5991
+ onClick,
5992
+ children
5993
+ }
5994
+ );
5995
+ }
6094
5996
  function MemberRow({
6095
5997
  member,
6096
- onClick
5998
+ onEdit,
5999
+ onCopyEmail
6097
6000
  }) {
6001
+ const [copied, setCopied] = (0, import_react12.useState)(false);
6002
+ const [active, setActive] = (0, import_react12.useState)(false);
6003
+ const noHover = typeof window !== "undefined" && window.matchMedia?.("(hover: none)").matches === true;
6098
6004
  const name = member.user.name?.trim();
6099
6005
  const email = member.user.email || "";
6100
6006
  const displayIdent = name || email.split("@")[0] || "user";
@@ -6106,18 +6012,20 @@ function MemberRow({
6106
6012
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6107
6013
  "div",
6108
6014
  {
6109
- className: `flex items-center self-stretch shrink-0 ${onClick ? "cursor-pointer" : "cursor-default"}`,
6015
+ className: "flex items-center self-stretch shrink-0 cursor-default",
6110
6016
  style: {
6111
6017
  borderBottom: `1px solid ${T11.borderSubtle}`,
6112
6018
  padding: `${T11.sp5xl} ${T11.sp3xl}`,
6113
- gap: T11.sp6xl
6114
- },
6115
- onClick,
6116
- onMouseEnter: (e) => {
6117
- if (onClick) e.currentTarget.style.background = T11.fillPlus;
6019
+ gap: T11.sp6xl,
6020
+ background: active && onEdit ? T11.fillPlus : "transparent"
6118
6021
  },
6119
- onMouseLeave: (e) => {
6120
- e.currentTarget.style.background = "transparent";
6022
+ onMouseEnter: () => setActive(true),
6023
+ onMouseLeave: () => setActive(false),
6024
+ onFocus: () => setActive(true),
6025
+ onBlur: (e) => {
6026
+ if (!e.currentTarget.contains(e.relatedTarget)) {
6027
+ setActive(false);
6028
+ }
6121
6029
  },
6122
6030
  children: [
6123
6031
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
@@ -6196,112 +6104,29 @@ function MemberRow({
6196
6104
  },
6197
6105
  children: formatDate(member.createdAt || member.user.createdAt)
6198
6106
  }
6199
- )
6200
- ]
6201
- }
6202
- );
6203
- }
6204
- function InviteRow({
6205
- invite,
6206
- onCancel,
6207
- onResend
6208
- }) {
6209
- const isDomain = invite.kind === "domain";
6210
- const invitedByText = (() => {
6211
- if (!invite.invitedBy) return "\u2013";
6212
- if (typeof invite.invitedBy === "string") return invite.invitedBy;
6213
- return invite.invitedBy.name || invite.invitedBy.email || "\u2013";
6214
- })();
6215
- const role = isDomain ? invite.autoJoinRole : invite.role;
6216
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6217
- "div",
6218
- {
6219
- className: "flex items-center self-stretch shrink-0",
6220
- style: {
6221
- borderBottom: `1px solid ${T11.borderSubtle}`,
6222
- padding: `${T11.sp5xl} ${T11.sp3xl}`,
6223
- gap: T11.sp6xl
6224
- },
6225
- children: [
6226
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center min-w-0", style: { flex: 1, gap: T11.spMd }, children: [
6227
- isDomain ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6228
- "div",
6229
- {
6230
- className: "shrink-0 flex items-center justify-center",
6231
- style: {
6232
- width: 32,
6233
- height: 32,
6234
- borderRadius: T11.rXl,
6235
- background: T11.fillNeutral
6236
- },
6237
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconGlobe, { className: "w-4 h-4", color: T11.primary })
6238
- }
6239
- ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ProfileAvatar, { name: invite.email || "invite", size: 32 }),
6240
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col min-w-0", children: [
6241
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6242
- "span",
6243
- {
6244
- className: "truncate",
6245
- style: {
6246
- fontFamily: T11.font,
6247
- fontSize: T11.fsSm,
6248
- fontWeight: 500,
6249
- lineHeight: T11.lhSm,
6250
- color: T11.primary
6251
- },
6252
- children: isDomain ? `Domain: ${invite.domain}` : toDisplayText2(invite.email, "")
6253
- }
6254
- ),
6255
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6256
- "span",
6257
- {
6258
- className: "truncate",
6259
- style: {
6260
- fontFamily: T11.font,
6261
- fontSize: T11.fsXs,
6262
- fontWeight: 400,
6263
- lineHeight: T11.lhXs,
6264
- color: T11.muted
6265
- },
6266
- children: isDomain ? "Auto-join by verified domain" : "Email invite"
6267
- }
6268
- )
6269
- ] })
6270
- ] }),
6271
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6272
- RoleLabel,
6107
+ ),
6108
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex items-center justify-end shrink-0", style: { width: 32 }, children: onEdit ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6109
+ RowIconButton,
6273
6110
  {
6274
- role: role === "admin" ? "admin" : "member",
6275
- label: orgRoleLabel(role)
6111
+ label: `Manage ${email || "member"}`,
6112
+ onClick: onEdit,
6113
+ visible: active || noHover,
6114
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconSettings, { className: "w-4 h-4", color: T11.primary })
6276
6115
  }
6277
- ),
6278
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6279
- "div",
6116
+ ) : email && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6117
+ RowIconButton,
6280
6118
  {
6281
- className: "truncate shrink-0",
6282
- style: {
6283
- width: "7.5rem",
6284
- fontFamily: T11.font,
6285
- fontSize: T11.fsSm,
6286
- fontWeight: 400,
6287
- lineHeight: T11.lhSm,
6288
- color: T11.primary
6119
+ label: copied ? "Copied" : `Copy ${email}`,
6120
+ onClick: () => {
6121
+ void onCopyEmail().then((ok) => {
6122
+ if (!ok) return;
6123
+ setCopied(true);
6124
+ setTimeout(() => setCopied(false), 2e3);
6125
+ });
6289
6126
  },
6290
- children: invitedByText
6127
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconCheck, { className: "w-4 h-4", color: T11.primary }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconCopy, { className: "w-4 h-4", color: T11.primary })
6291
6128
  }
6292
- ),
6293
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center shrink-0", style: { gap: T11.spMd }, children: [
6294
- !isDomain && onResend && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ui8.ScButton, { text: "Resend", variant: "tertiary", size: "sm", onClick: onResend }),
6295
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6296
- import_ui8.ScButton,
6297
- {
6298
- text: isDomain ? "Revoke" : "Cancel",
6299
- variant: "error",
6300
- size: "sm",
6301
- onClick: onCancel
6302
- }
6303
- )
6304
- ] })
6129
+ ) })
6305
6130
  ]
6306
6131
  }
6307
6132
  );
@@ -6408,7 +6233,7 @@ function JoinRequestRow({
6408
6233
  )
6409
6234
  ] })
6410
6235
  ] }),
6411
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center shrink-0", style: { gap: T11.spMd }, children: [
6236
+ onApprove && onReject && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center shrink-0", style: { gap: T11.spMd }, children: [
6412
6237
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ui8.ScButton, { text: "Reject", variant: "error", size: "sm", onClick: onReject }),
6413
6238
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ui8.ScButton, { text: "Approve", variant: "primary", size: "sm", onClick: onApprove })
6414
6239
  ] })
@@ -6464,42 +6289,29 @@ function Section({
6464
6289
  }
6465
6290
  function OrganizationContent({
6466
6291
  embedded = false,
6467
- view = "people",
6468
- onInviteOpen,
6469
- onInviteOpenChange
6292
+ view = "people"
6470
6293
  } = {}) {
6471
6294
  const { organization, toast } = useSettingsAdapters();
6472
6295
  const current = organization.current;
6473
- const [activeTab, setActiveTab] = (0, import_react12.useState)("active");
6474
6296
  const [members, setMembers] = (0, import_react12.useState)([]);
6475
- const [invites, setInvites] = (0, import_react12.useState)([]);
6476
6297
  const [workspaces, setWorkspaces] = (0, import_react12.useState)([]);
6477
6298
  const [joinRequests, setJoinRequests] = (0, import_react12.useState)([]);
6478
6299
  const [highestRole, setHighestRole] = (0, import_react12.useState)("guest");
6479
- const [emailDomain, setEmailDomain] = (0, import_react12.useState)(null);
6480
- const [canClaimEmailDomain, setCanClaimEmailDomain] = (0, import_react12.useState)(true);
6481
6300
  const [searchQuery, setSearchQuery] = (0, import_react12.useState)("");
6482
6301
  const [loadingData, setLoadingData] = (0, import_react12.useState)(false);
6483
- const [modal, setModal] = (0, import_react12.useState)({ open: false, mode: "invite" });
6302
+ const [modal, setModal] = (0, import_react12.useState)({ open: false });
6484
6303
  const fetchData = (0, import_react12.useCallback)(async () => {
6304
+ if (!organization.current) return;
6485
6305
  setLoadingData(true);
6486
6306
  try {
6487
- const [membersRes, invitesRes, workspacesRes, joinRequestsRes, highestRoleRes] = await Promise.all([
6307
+ const [membersRes, workspacesRes, joinRequestsRes, highestRoleRes] = await Promise.all([
6488
6308
  organization.fetchMembers().catch(() => null),
6489
- organization.fetchInvites().catch(() => null),
6490
6309
  organization.fetchWorkspaces().catch(() => null),
6491
6310
  organization.fetchJoinRequests().catch(() => null),
6492
6311
  organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null)
6493
6312
  ]);
6494
6313
  if (highestRoleRes?.role) setHighestRole(highestRoleRes.role);
6495
- if (highestRoleRes?.emailDomain !== void 0) {
6496
- setEmailDomain(highestRoleRes.emailDomain ?? null);
6497
- }
6498
- if (highestRoleRes?.canClaimEmailDomain !== void 0) {
6499
- setCanClaimEmailDomain(highestRoleRes.canClaimEmailDomain);
6500
- }
6501
6314
  if (membersRes) setMembers(membersRes.filter((m) => m?.user));
6502
- if (invitesRes) setInvites(invitesRes);
6503
6315
  if (workspacesRes) setWorkspaces(workspacesRes);
6504
6316
  if (joinRequestsRes) setJoinRequests(joinRequestsRes);
6505
6317
  } catch {
@@ -6510,51 +6322,6 @@ function OrganizationContent({
6510
6322
  (0, import_react12.useEffect)(() => {
6511
6323
  fetchData();
6512
6324
  }, [fetchData]);
6513
- const [domainMatch, setDomainMatch] = (0, import_react12.useState)(null);
6514
- const [checkingDomainMatch, setCheckingDomainMatch] = (0, import_react12.useState)(false);
6515
- const [joiningByDomain, setJoiningByDomain] = (0, import_react12.useState)(false);
6516
- const [createModalOpen, setCreateModalOpen] = (0, import_react12.useState)(false);
6517
- (0, import_react12.useEffect)(() => {
6518
- if (current) return;
6519
- let cancelled = false;
6520
- setCheckingDomainMatch(true);
6521
- organization.checkDomainMatch().then((match) => {
6522
- if (!cancelled) setDomainMatch(match);
6523
- }).catch(() => {
6524
- if (!cancelled) setDomainMatch(null);
6525
- }).finally(() => {
6526
- if (!cancelled) setCheckingDomainMatch(false);
6527
- });
6528
- return () => {
6529
- cancelled = true;
6530
- };
6531
- }, [current, organization]);
6532
- const handleJoinByDomain = async () => {
6533
- if (!domainMatch) return;
6534
- setJoiningByDomain(true);
6535
- try {
6536
- await organization.joinByDomain();
6537
- await organization.switch(domainMatch.organizationId);
6538
- toast.success(`Joined ${domainMatch.organizationName}`);
6539
- } catch (err) {
6540
- toast.error(err instanceof Error ? err.message : "Failed to join organization");
6541
- } finally {
6542
- setJoiningByDomain(false);
6543
- }
6544
- };
6545
- const handleCreateOrganization = async (name, imageFile) => {
6546
- try {
6547
- const result = await organization.create({ name, imageFile });
6548
- if (result && "id" in result && result.id) {
6549
- await organization.switch(result.id);
6550
- }
6551
- toast.success("Organization created");
6552
- return true;
6553
- } catch (err) {
6554
- toast.error(err instanceof Error ? err.message : "Failed to create organization");
6555
- return false;
6556
- }
6557
- };
6558
6325
  const [manageModalOpen, setManageModalOpen] = (0, import_react12.useState)(false);
6559
6326
  const handleUpdateOrganization = async (name, imageFile) => {
6560
6327
  if (!current) return false;
@@ -6578,45 +6345,9 @@ function OrganizationContent({
6578
6345
  return false;
6579
6346
  }
6580
6347
  };
6581
- const openInviteModal = () => setModal({ open: true, mode: "invite" });
6582
- (0, import_react12.useEffect)(() => {
6583
- if (onInviteOpen) {
6584
- openInviteModal();
6585
- onInviteOpenChange?.(false);
6586
- }
6587
- }, [onInviteOpen]);
6588
- const openUpdateModal = (member) => setModal({ open: true, mode: "update", target: member });
6589
- const closeModal = () => setModal({ open: false, mode: "invite" });
6590
- const handleInviteEmail = async (input) => {
6591
- if (highestRole !== "admin") {
6592
- toast.error("You do not have permission to invite members");
6593
- closeModal();
6594
- return;
6595
- }
6596
- try {
6597
- await organization.inviteMemberByEmail(input);
6598
- toast.success(`Invitation sent to ${input.email}`);
6599
- await fetchData();
6600
- closeModal();
6601
- } catch (err) {
6602
- toast.error(err instanceof Error ? err.message : "Failed to send invite");
6603
- }
6604
- };
6605
- const handleInviteDomain = async (input) => {
6606
- if (highestRole !== "admin") {
6607
- toast.error("You do not have permission to invite members");
6608
- closeModal();
6609
- return;
6610
- }
6611
- try {
6612
- await organization.inviteDomain(input);
6613
- toast.success(`Domain ${input.domain} added`);
6614
- await fetchData();
6615
- closeModal();
6616
- } catch (err) {
6617
- toast.error(err instanceof Error ? err.message : "Failed to add domain");
6618
- }
6619
- };
6348
+ const openUpdateModal = (member) => setModal({ open: true, target: member });
6349
+ const closeModal = () => setModal({ open: false });
6350
+ const adminCount = members.filter((m) => m.role === "admin").length;
6620
6351
  const handleUpdateMember = async (input) => {
6621
6352
  const target = modal.target;
6622
6353
  if (!target) {
@@ -6628,20 +6359,16 @@ function OrganizationContent({
6628
6359
  closeModal();
6629
6360
  return;
6630
6361
  }
6631
- if (target.role === "admin" && input.role === "member") {
6632
- const adminCount = members.filter((m) => m.role === "admin").length;
6633
- if (adminCount <= 1) {
6634
- toast.error(
6635
- "You're the only admin. Promote another member to admin before changing your role."
6636
- );
6637
- return;
6638
- }
6362
+ if (target.role === "admin" && input.role === "member" && adminCount <= 1) {
6363
+ toast.error(
6364
+ "This is the only org admin. Make someone else an org admin first."
6365
+ );
6366
+ return;
6639
6367
  }
6640
6368
  try {
6641
6369
  await organization.updateMemberRole({
6642
6370
  userId: target.user._id,
6643
- role: input.role,
6644
- inviteAccess: input.inviteAccess
6371
+ role: input.role
6645
6372
  });
6646
6373
  toast.success("Member updated");
6647
6374
  await fetchData();
@@ -6661,8 +6388,14 @@ function OrganizationContent({
6661
6388
  closeModal();
6662
6389
  return;
6663
6390
  }
6391
+ if (target.role === "admin" && adminCount <= 1) {
6392
+ toast.error(
6393
+ "This is the only org admin. Make someone else an org admin first."
6394
+ );
6395
+ return;
6396
+ }
6664
6397
  const confirmed = window.confirm(
6665
- `Remove ${target.user.email} from this organization?`
6398
+ `Remove ${target.user.email} from this organization? They'll also be removed from every workspace in it.`
6666
6399
  );
6667
6400
  if (!confirmed) return;
6668
6401
  try {
@@ -6674,44 +6407,6 @@ function OrganizationContent({
6674
6407
  }
6675
6408
  closeModal();
6676
6409
  };
6677
- const handleCancelInvite = async (invite) => {
6678
- if (highestRole !== "admin") {
6679
- toast.error("You do not have permission to manage invites");
6680
- return;
6681
- }
6682
- const label = invite.kind === "domain" ? invite.domain : invite.email;
6683
- const confirmed = window.confirm(
6684
- invite.kind === "domain" ? `Revoke domain invite for ${label}? Members who already joined will keep their access.` : `Cancel invitation for ${label}?`
6685
- );
6686
- if (!confirmed) return;
6687
- try {
6688
- if (invite.kind === "domain") {
6689
- await organization.revokeDomainInvite(invite._id);
6690
- } else if (invite.token) {
6691
- await organization.cancelInvite(invite.token);
6692
- } else {
6693
- await organization.removeMember({ invitationIds: [invite._id] });
6694
- }
6695
- toast.success(invite.kind === "domain" ? "Domain invite revoked" : "Invitation removed");
6696
- await fetchData();
6697
- } catch (err) {
6698
- toast.error(err instanceof Error ? err.message : "Failed to update invite");
6699
- }
6700
- };
6701
- const handleResendInvite = async (invite) => {
6702
- if (invite.kind !== "email") return;
6703
- if (highestRole !== "admin") {
6704
- toast.error("You do not have permission to invite members");
6705
- return;
6706
- }
6707
- try {
6708
- await organization.resendInvite(invite._id);
6709
- toast.success("Invitation resent");
6710
- await fetchData();
6711
- } catch (err) {
6712
- toast.error(err instanceof Error ? err.message : "Failed to resend invitation");
6713
- }
6714
- };
6715
6410
  const handleApproveJoinRequest = async (request) => {
6716
6411
  try {
6717
6412
  await organization.approveJoinRequest(request._id);
@@ -6733,101 +6428,29 @@ function OrganizationContent({
6733
6428
  }
6734
6429
  };
6735
6430
  if (!current) {
6736
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6737
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6738
- "div",
6739
- {
6740
- className: "flex flex-col flex-1 min-w-0 min-h-0 w-full items-center justify-center",
6741
- style: { gap: T11.spXl, padding: T11.sp6xl },
6742
- children: [
6743
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconGlobe, { className: "w-10 h-10", color: T11.muted }),
6744
- domainMatch ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6745
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6746
- "p",
6747
- {
6748
- className: "text-center",
6749
- style: { color: T11.primary, fontFamily: T11.font, fontSize: T11.fsMd, fontWeight: 600 },
6750
- children: [
6751
- "An organization already exists for ",
6752
- domainMatch.domain
6753
- ]
6754
- }
6755
- ),
6756
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6757
- "p",
6758
- {
6759
- className: "text-center",
6760
- style: { color: T11.muted, fontFamily: T11.font, fontSize: T11.fsSm },
6761
- children: [
6762
- domainMatch.organizationName,
6763
- " \u2014 join it instead of creating a new one and fragmenting your company across multiple orgs."
6764
- ]
6765
- }
6766
- ),
6767
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6768
- import_ui8.ScButton,
6769
- {
6770
- text: joiningByDomain ? "Joining\u2026" : `Join ${domainMatch.organizationName}`,
6771
- variant: "primary",
6772
- size: "md",
6773
- state: joiningByDomain ? "disabled" : "default",
6774
- onClick: handleJoinByDomain
6775
- }
6776
- )
6777
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6778
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6779
- "p",
6780
- {
6781
- className: "text-center",
6782
- style: { color: T11.primary, fontFamily: T11.font, fontSize: T11.fsMd, fontWeight: 600 },
6783
- children: "You're not part of an organization yet"
6784
- }
6785
- ),
6786
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6787
- "p",
6788
- {
6789
- className: "text-center",
6790
- style: { color: T11.muted, fontFamily: T11.font, fontSize: T11.fsSm },
6791
- children: "Create one to invite your team and manage workspaces together."
6792
- }
6793
- ),
6794
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6795
- import_ui8.ScButton,
6796
- {
6797
- text: "Create organization",
6798
- variant: "primary",
6799
- size: "md",
6800
- styleVariant: "icon-left",
6801
- icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconUserAdd, { className: "w-5 h-5", color: T11.inverse }),
6802
- state: checkingDomainMatch ? "disabled" : "default",
6803
- onClick: () => setCreateModalOpen(true)
6804
- }
6805
- )
6806
- ] })
6807
- ]
6808
- }
6809
- ),
6810
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6811
- OrganizationModal,
6812
- {
6813
- open: createModalOpen,
6814
- mode: "create",
6815
- onClose: () => setCreateModalOpen(false),
6816
- onCreate: handleCreateOrganization
6817
- }
6818
- )
6819
- ] });
6431
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
6432
+ "div",
6433
+ {
6434
+ className: "flex flex-col flex-1 min-w-0 min-h-0 w-full items-center justify-center",
6435
+ style: { gap: T11.spXl, padding: T11.sp6xl },
6436
+ children: [
6437
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconGlobe, { className: "w-10 h-10", color: T11.muted }),
6438
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6439
+ "p",
6440
+ {
6441
+ className: "text-center",
6442
+ style: { color: T11.primary, fontFamily: T11.font, fontSize: T11.fsMd, fontWeight: 600 },
6443
+ children: "Your workspace isn't part of an organization"
6444
+ }
6445
+ )
6446
+ ]
6447
+ }
6448
+ );
6820
6449
  }
6821
6450
  const q = searchQuery.toLowerCase();
6822
6451
  const filteredMembers = members.filter(
6823
6452
  (m) => (m.user.email || "").toLowerCase().includes(q) || (m.user.name || "").toLowerCase().includes(q) || m.role.toLowerCase().includes(q)
6824
6453
  );
6825
- const filteredInvites = invites.filter((inv) => {
6826
- const label = inv.kind === "domain" ? inv.domain ?? "" : inv.email ?? "";
6827
- return label.toLowerCase().includes(q);
6828
- });
6829
- const emailInvites = filteredInvites.filter((inv) => inv.kind !== "domain");
6830
- const domainInvites = invites.filter((inv) => inv.kind === "domain");
6831
6454
  const scopeHeader = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6832
6455
  ScopeHeader,
6833
6456
  {
@@ -6876,15 +6499,26 @@ function OrganizationContent({
6876
6499
  )
6877
6500
  }
6878
6501
  );
6502
+ const isOrgAdmin = highestRole === "admin";
6503
+ const copyEmail = async (email) => {
6504
+ try {
6505
+ await navigator.clipboard.writeText(email);
6506
+ toast.success("Email copied");
6507
+ return true;
6508
+ } catch {
6509
+ toast.error("Couldn't copy the email");
6510
+ return false;
6511
+ }
6512
+ };
6879
6513
  const peopleView = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6880
6514
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6881
6515
  MemberListToolbar,
6882
6516
  {
6883
- activeTab,
6884
- onTabChange: setActiveTab,
6517
+ activeTab: "active",
6518
+ onTabChange: () => {
6519
+ },
6885
6520
  activeLabel: "Members",
6886
6521
  activeCount: filteredMembers.length,
6887
- pendingCount: emailInvites.length,
6888
6522
  searchQuery,
6889
6523
  onSearchChange: setSearchQuery
6890
6524
  }
@@ -6892,47 +6526,31 @@ function OrganizationContent({
6892
6526
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6893
6527
  MemberListFrame,
6894
6528
  {
6895
- isEmpty: activeTab === "active" ? filteredMembers.length === 0 : emailInvites.length === 0,
6896
- emptyText: activeTab === "active" ? "No members yet" : "No pending invites",
6529
+ isEmpty: filteredMembers.length === 0,
6530
+ emptyText: "No members yet",
6897
6531
  grow: "fill",
6898
- children: activeTab === "active" ? filteredMembers.map((m) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MemberRow, { member: m, onClick: () => openUpdateModal(m) }, m._id)) : emailInvites.map((inv) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6899
- InviteRow,
6532
+ children: filteredMembers.map((m) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6533
+ MemberRow,
6900
6534
  {
6901
- invite: inv,
6902
- onCancel: () => void handleCancelInvite(inv),
6903
- onResend: () => void handleResendInvite(inv)
6535
+ member: m,
6536
+ onEdit: isOrgAdmin ? () => openUpdateModal(m) : void 0,
6537
+ onCopyEmail: () => copyEmail(m.user.email)
6904
6538
  },
6905
- inv._id
6539
+ m._id
6906
6540
  ))
6907
6541
  }
6908
6542
  )
6909
6543
  ] });
6910
- const workspacesView = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6911
- Section,
6912
- {
6913
- title: "Workspaces in this organization",
6914
- empty: workspaces.length === 0,
6915
- children: workspaces.map((ws) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(WorkspaceRow, { workspace: ws }, ws._id))
6916
- }
6917
- );
6918
- const domainsView = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6544
+ const workspacesView = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
6919
6545
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6920
6546
  Section,
6921
6547
  {
6922
- title: "Auto-join by email domain",
6923
- empty: domainInvites.length === 0,
6924
- emptyText: canClaimEmailDomain ? void 0 : `Auto-join needs a company email domain.${emailDomain ? ` ${emailDomain} is a public email provider, so it` : " A public email provider"} can't be claimed \u2014 invite people by email instead.`,
6925
- children: domainInvites.map((inv) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6926
- InviteRow,
6927
- {
6928
- invite: inv,
6929
- onCancel: () => void handleCancelInvite(inv)
6930
- },
6931
- inv._id
6932
- ))
6548
+ title: "Workspaces in this organization",
6549
+ empty: workspaces.length === 0,
6550
+ children: workspaces.map((ws) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(WorkspaceRow, { workspace: ws }, ws._id))
6933
6551
  }
6934
6552
  ),
6935
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6553
+ (isOrgAdmin || joinRequests.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6936
6554
  Section,
6937
6555
  {
6938
6556
  title: "Workspaces asking to join",
@@ -6941,8 +6559,8 @@ function OrganizationContent({
6941
6559
  JoinRequestRow,
6942
6560
  {
6943
6561
  request: req,
6944
- onApprove: () => void handleApproveJoinRequest(req),
6945
- onReject: () => void handleRejectJoinRequest(req)
6562
+ onApprove: isOrgAdmin ? () => void handleApproveJoinRequest(req) : void 0,
6563
+ onReject: isOrgAdmin ? () => void handleRejectJoinRequest(req) : void 0
6946
6564
  },
6947
6565
  req._id
6948
6566
  ))
@@ -6953,25 +6571,17 @@ function OrganizationContent({
6953
6571
  scopeHeader,
6954
6572
  loadingData && loadingBlock,
6955
6573
  !loadingData && view === "people" && peopleView,
6956
- !loadingData && view === "workspaces" && workspacesView,
6957
- !loadingData && view === "domains" && domainsView,
6574
+ !loadingData && view !== "people" && workspacesView,
6958
6575
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6959
- OrganizationInviteModal,
6576
+ OrganizationMemberModal,
6960
6577
  {
6961
6578
  open: modal.open,
6962
- mode: modal.mode,
6963
6579
  userEmail: modal.target?.user.email,
6964
6580
  initialRole: modal.target?.role === "admin" || modal.target?.role === "member" ? modal.target.role : void 0,
6965
- initialInviteAccess: modal.target?.inviteAccess,
6966
- allowSubmitWithoutChanges: false,
6967
6581
  lockRole: modal.target?.role === "guest",
6968
6582
  lockedRoleLabel: orgRoleLabel(modal.target?.role),
6969
6583
  canRemove: highestRole === "admin",
6970
- canClaimDomain: canClaimEmailDomain,
6971
- claimableDomain: emailDomain,
6972
6584
  onClose: closeModal,
6973
- onInviteEmail: handleInviteEmail,
6974
- onInviteDomain: handleInviteDomain,
6975
6585
  onUpdate: handleUpdateMember,
6976
6586
  onRemove: handleRemoveMember
6977
6587
  }
@@ -7016,34 +6626,20 @@ function OrganizationContent({
7016
6626
  backgroundSize: "24px 24px"
7017
6627
  },
7018
6628
  children: [
7019
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between shrink-0 w-full", children: [
7020
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7021
- "p",
7022
- {
7023
- className: "flex-1 min-w-0 truncate",
7024
- style: {
7025
- color: T11.primary,
7026
- fontFamily: T11.font,
7027
- fontSize: "var(--font-size-font-size-xxl)",
7028
- fontWeight: 600,
7029
- lineHeight: "var(--line-height-line-height-xxl)"
7030
- },
7031
- children: current?.name ? `${current.name} \u2014 Organization` : "Organization"
7032
- }
7033
- ),
7034
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7035
- import_ui8.ScButton,
7036
- {
7037
- text: "Invite",
7038
- variant: "primary",
7039
- size: "md",
7040
- styleVariant: "icon-left",
7041
- state: highestRole !== "admin" ? "disabled" : "default",
7042
- icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_icons8.SiconUserAdd, { className: "w-5 h-5", color: "var(--alias-text---icons-inverse)" }),
7043
- onClick: openInviteModal
7044
- }
7045
- )
7046
- ] }),
6629
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex items-center justify-between shrink-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
6630
+ "p",
6631
+ {
6632
+ className: "flex-1 min-w-0 truncate",
6633
+ style: {
6634
+ color: T11.primary,
6635
+ fontFamily: T11.font,
6636
+ fontSize: "var(--font-size-font-size-xxl)",
6637
+ fontWeight: 600,
6638
+ lineHeight: "var(--line-height-line-height-xxl)"
6639
+ },
6640
+ children: current?.name ? `${current.name} \u2014 Organization` : "Organization"
6641
+ }
6642
+ ) }),
7047
6643
  innerContent
7048
6644
  ]
7049
6645
  }
@@ -10615,8 +10211,7 @@ function SettingsNav({
10615
10211
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: hasOrganization ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
10616
10212
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { padding: "4px 12px", fontSize: 11, fontWeight: 500, color: MUTED_COLOR2, textTransform: "uppercase", letterSpacing: "0.08em" }, children: "Organization" }),
10617
10213
  item("organization", (color) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_icons13.SiconTeam, { className: "w-5 h-5", color })),
10618
- item("organizationWorkspaces", (color) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_icons13.SiconWorkspace, { className: "w-5 h-5", color })),
10619
- item("organizationDomains", (color) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_icons13.SiconLock, { className: "w-5 h-5", color }))
10214
+ item("organizationWorkspaces", (color) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_icons13.SiconWorkspace, { className: "w-5 h-5", color }))
10620
10215
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
10621
10216
  SettingsNavItem,
10622
10217
  {
@@ -11588,7 +11183,6 @@ function SettingsContentInner({
11588
11183
  const [creatingWorkspace, setCreatingWorkspace] = (0, import_react17.useState)(false);
11589
11184
  const [updatingWorkspace, setUpdatingWorkspace] = (0, import_react17.useState)(false);
11590
11185
  const [teamInviteOpen, setTeamInviteOpen] = (0, import_react17.useState)(false);
11591
- const [organizationInviteOpen, setOrganizationInviteOpen] = (0, import_react17.useState)(false);
11592
11186
  const [tokenShowRevoked, setTokenShowRevoked] = (0, import_react17.useState)(false);
11593
11187
  const [tokenCreateOpen, setTokenCreateOpen] = (0, import_react17.useState)(false);
11594
11188
  const [billingShowPlans, setBillingShowPlans] = (0, import_react17.useState)(false);
@@ -12095,31 +11689,6 @@ function SettingsContentInner({
12095
11689
  )
12096
11690
  }
12097
11691
  ),
12098
- activeTab === "organization" && hasOrganization && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12099
- SettingsTooltip,
12100
- {
12101
- content: "Invite someone into your organization",
12102
- placement: "bottom",
12103
- inline: true,
12104
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12105
- import_ui13.ScButton,
12106
- {
12107
- text: "Invite",
12108
- variant: "secondary",
12109
- size: "md",
12110
- styleVariant: "icon-left",
12111
- icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12112
- import_icons13.SiconUserAdd,
12113
- {
12114
- className: "w-5 h-5",
12115
- color: "var(--alias-text---icons-inverse)"
12116
- }
12117
- ),
12118
- onClick: () => setOrganizationInviteOpen(true)
12119
- }
12120
- )
12121
- }
12122
- ),
12123
11692
  activeTab === "apikey" && isWorkspaceAdmin && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center shrink-0", style: { gap: "var(--spacing-md)" }, children: [
12124
11693
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12125
11694
  SettingsTooltip,
@@ -12278,9 +11847,7 @@ function SettingsContentInner({
12278
11847
  OrganizationContent,
12279
11848
  {
12280
11849
  embedded: true,
12281
- view: activeTab === "organizationWorkspaces" ? "workspaces" : activeTab === "organizationDomains" ? "domains" : "people",
12282
- onInviteOpen: organizationInviteOpen,
12283
- onInviteOpenChange: setOrganizationInviteOpen
11850
+ view: activeTab === "organizationWorkspaces" || activeTab === "organizationDomains" ? "workspaces" : "people"
12284
11851
  }
12285
11852
  ) }),
12286
11853
  activeTab === "billing" && isWorkspaceAdmin && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-col flex-1 min-w-0 min-h-0 h-full", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
@@ -12418,3 +11985,246 @@ function SettingsContentInner({
12418
11985
  }
12419
11986
  );
12420
11987
  }
11988
+
11989
+ // src/workspace-picker.tsx
11990
+ var import_react18 = require("react");
11991
+ var import_ui15 = require("@streamoid/ui");
11992
+ var import_jsx_runtime23 = require("react/jsx-runtime");
11993
+ var T13 = {
11994
+ primary: "var(--alias-text---icons-primary)",
11995
+ muted: "var(--alias-text---icons-muted)",
11996
+ tertiary: "var(--alias-text---icons-tertiary)",
11997
+ surface: "var(--alias-surface-base)",
11998
+ fillPlus: "var(--alias-fill-neutral-neutralplus)",
11999
+ borderSubtle: "var(--alias-border-subtle)",
12000
+ font: "var(--font-family-font-family-body)",
12001
+ fsXs: "var(--font-size-font-size-xs)",
12002
+ fsSm: "var(--font-size-font-size-sm)",
12003
+ fsXl: "var(--font-size-font-size-xl)",
12004
+ lhXs: "var(--line-height-line-height-xs)",
12005
+ lhSm: "var(--line-height-line-height-sm)",
12006
+ lhXl: "var(--line-height-line-height-xl)",
12007
+ spXs: "var(--spacing-xs)",
12008
+ spMd: "var(--spacing-md)",
12009
+ spXl: "var(--spacing-xl)",
12010
+ sp3xl: "var(--spacing-3xl)",
12011
+ sp5xl: "var(--spacing-5xl)",
12012
+ sp6xl: "var(--spacing-6xl)",
12013
+ rLg: "var(--radius-lg)",
12014
+ r3xl: "var(--radius-3xl)"
12015
+ };
12016
+ function WorkspacePicker({
12017
+ organizationName,
12018
+ workspaces,
12019
+ loading = false,
12020
+ onJoin,
12021
+ onCreate
12022
+ }) {
12023
+ const [selected, setSelected] = (0, import_react18.useState)(/* @__PURE__ */ new Set());
12024
+ const [creating, setCreating] = (0, import_react18.useState)(false);
12025
+ const [name, setName] = (0, import_react18.useState)("");
12026
+ const [busy, setBusy] = (0, import_react18.useState)(false);
12027
+ const hasWorkspaces = workspaces.length > 0;
12028
+ const showCreate = creating || !loading && !hasWorkspaces;
12029
+ const orgLabel = organizationName || "your organization";
12030
+ const toggle = (id) => setSelected((prev) => {
12031
+ const next = new Set(prev);
12032
+ if (next.has(id)) next.delete(id);
12033
+ else next.add(id);
12034
+ return next;
12035
+ });
12036
+ const run = async (action) => {
12037
+ setBusy(true);
12038
+ try {
12039
+ await action();
12040
+ } catch {
12041
+ } finally {
12042
+ setBusy(false);
12043
+ }
12044
+ };
12045
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
12046
+ "div",
12047
+ {
12048
+ className: "flex flex-col w-full",
12049
+ style: { maxWidth: 520, gap: T13.sp5xl, fontFamily: T13.font },
12050
+ children: [
12051
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col", style: { gap: T13.spMd }, children: [
12052
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12053
+ "p",
12054
+ {
12055
+ style: {
12056
+ color: T13.primary,
12057
+ fontSize: T13.fsXl,
12058
+ fontWeight: 600,
12059
+ lineHeight: T13.lhXl,
12060
+ margin: 0
12061
+ },
12062
+ children: "Choose your workspaces"
12063
+ }
12064
+ ),
12065
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { color: T13.muted, fontSize: T13.fsSm, lineHeight: T13.lhSm, margin: 0 }, children: hasWorkspaces || loading ? `Join one or more workspaces in ${orgLabel} as a member, or create your own.` : `There are no workspaces to join in ${orgLabel} yet. Create one to get started.` })
12066
+ ] }),
12067
+ (loading || hasWorkspaces) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12068
+ "div",
12069
+ {
12070
+ className: "flex flex-col w-full overflow-y-auto",
12071
+ style: {
12072
+ maxHeight: 360,
12073
+ background: T13.surface,
12074
+ border: `1px solid ${T13.borderSubtle}`,
12075
+ borderRadius: T13.r3xl
12076
+ },
12077
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12078
+ "div",
12079
+ {
12080
+ className: "flex items-center justify-center",
12081
+ style: { padding: T13.sp6xl, color: T13.muted, fontSize: T13.fsSm },
12082
+ children: "Loading workspaces\u2026"
12083
+ }
12084
+ ) : workspaces.map((workspace, index) => {
12085
+ const checked = selected.has(workspace._id);
12086
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
12087
+ "div",
12088
+ {
12089
+ role: "checkbox",
12090
+ "aria-checked": checked,
12091
+ tabIndex: 0,
12092
+ className: "flex items-center cursor-pointer",
12093
+ style: {
12094
+ gap: T13.spXl,
12095
+ padding: `${T13.spXl} ${T13.sp3xl}`,
12096
+ borderTop: index ? `1px solid ${T13.borderSubtle}` : "none"
12097
+ },
12098
+ onClick: () => toggle(workspace._id),
12099
+ onKeyDown: (e) => {
12100
+ if (e.key === " " || e.key === "Enter") {
12101
+ e.preventDefault();
12102
+ toggle(workspace._id);
12103
+ }
12104
+ },
12105
+ children: [
12106
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ui15.ScCheckbox, { checked }),
12107
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12108
+ ProfileAvatar,
12109
+ {
12110
+ name: workspace.name,
12111
+ profileImage: workspace.imageUrl,
12112
+ size: 32,
12113
+ borderRadius: T13.rLg
12114
+ }
12115
+ ),
12116
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col min-w-0", children: [
12117
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12118
+ "span",
12119
+ {
12120
+ className: "truncate",
12121
+ style: {
12122
+ color: T13.primary,
12123
+ fontSize: T13.fsSm,
12124
+ fontWeight: 500,
12125
+ lineHeight: T13.lhSm
12126
+ },
12127
+ children: workspace.name
12128
+ }
12129
+ ),
12130
+ workspace.ownerName && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
12131
+ "span",
12132
+ {
12133
+ className: "truncate",
12134
+ style: { color: T13.muted, fontSize: T13.fsXs, lineHeight: T13.lhXs },
12135
+ children: [
12136
+ "Created by ",
12137
+ workspace.ownerName
12138
+ ]
12139
+ }
12140
+ )
12141
+ ] })
12142
+ ]
12143
+ },
12144
+ workspace._id
12145
+ );
12146
+ })
12147
+ }
12148
+ ),
12149
+ showCreate ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col w-full", style: { gap: T13.spMd }, children: [
12150
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12151
+ "label",
12152
+ {
12153
+ htmlFor: "workspace-picker-name",
12154
+ style: { color: T13.tertiary, fontSize: T13.fsSm, lineHeight: T13.lhSm },
12155
+ children: "New workspace name"
12156
+ }
12157
+ ),
12158
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12159
+ "input",
12160
+ {
12161
+ id: "workspace-picker-name",
12162
+ autoFocus: true,
12163
+ value: name,
12164
+ onChange: (e) => setName(e.target.value),
12165
+ onKeyDown: (e) => {
12166
+ if (e.key === "Enter" && name.trim() && !busy) {
12167
+ void run(() => onCreate(name.trim()));
12168
+ }
12169
+ },
12170
+ placeholder: "e.g. Marketing",
12171
+ style: {
12172
+ height: 48,
12173
+ padding: `0 ${T13.sp3xl}`,
12174
+ background: T13.fillPlus,
12175
+ border: "none",
12176
+ outline: "none",
12177
+ borderRadius: T13.r3xl,
12178
+ color: T13.primary,
12179
+ fontFamily: T13.font,
12180
+ fontSize: T13.fsSm
12181
+ }
12182
+ }
12183
+ ),
12184
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-end w-full", style: { gap: T13.spMd }, children: [
12185
+ hasWorkspaces && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12186
+ import_ui15.ScButton,
12187
+ {
12188
+ text: "Back",
12189
+ variant: "tertiary",
12190
+ size: "md",
12191
+ onClick: () => setCreating(false)
12192
+ }
12193
+ ),
12194
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12195
+ import_ui15.ScButton,
12196
+ {
12197
+ text: busy ? "Creating\u2026" : "Create workspace",
12198
+ variant: "primary",
12199
+ size: "md",
12200
+ state: !name.trim() || busy ? "disabled" : "default",
12201
+ onClick: name.trim() && !busy ? () => void run(() => onCreate(name.trim())) : void 0
12202
+ }
12203
+ )
12204
+ ] })
12205
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap items-center justify-between w-full", style: { gap: T13.spMd }, children: [
12206
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12207
+ import_ui15.ScButton,
12208
+ {
12209
+ text: "Create a workspace",
12210
+ variant: "tertiary",
12211
+ size: "md",
12212
+ state: loading || busy ? "disabled" : "default",
12213
+ onClick: loading || busy ? void 0 : () => setCreating(true)
12214
+ }
12215
+ ),
12216
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
12217
+ import_ui15.ScButton,
12218
+ {
12219
+ text: busy ? "Joining\u2026" : selected.size > 1 ? `Join ${selected.size} workspaces` : "Join workspace",
12220
+ variant: "primary",
12221
+ size: "md",
12222
+ state: !selected.size || busy ? "disabled" : "default",
12223
+ onClick: selected.size && !busy ? () => void run(() => onJoin([...selected])) : void 0
12224
+ }
12225
+ )
12226
+ ] })
12227
+ ]
12228
+ }
12229
+ );
12230
+ }