@streamoid/settings 0.6.6 → 0.7.1

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.mjs CHANGED
@@ -188,10 +188,10 @@ import {
188
188
  SiconBilling,
189
189
  SiconBookOpen,
190
190
  SiconExternalLink as SiconExternalLink2,
191
- SiconSettings,
191
+ SiconSettings as SiconSettings2,
192
192
  SiconRight as SiconRight2,
193
193
  SiconLeft as SiconLeft3,
194
- SiconUserAdd as SiconUserAdd3,
194
+ SiconUserAdd as SiconUserAdd2,
195
195
  SiconLock,
196
196
  SiconDown,
197
197
  SiconGlobe as SiconGlobe3,
@@ -395,8 +395,9 @@ function WorkspaceModal({
395
395
  let cancelled = false;
396
396
  organizationAdapter.list().then((orgs) => {
397
397
  if (cancelled) return;
398
- setAvailableOrgs(orgs);
399
- setSelectedOrgId((prev) => prev || orgs[0]?._id || "");
398
+ const joinable = orgs.filter((org) => org.role !== "guest");
399
+ setAvailableOrgs(joinable);
400
+ setSelectedOrgId((prev) => prev || joinable[0]?._id || "");
400
401
  }).catch(() => {
401
402
  if (!cancelled) setAvailableOrgs([]);
402
403
  });
@@ -511,7 +512,7 @@ function WorkspaceModal({
511
512
  async function handleLeaveOrganization() {
512
513
  if (orgActionSubmitting || !workspaceAdapter.leaveOrganization) return;
513
514
  const confirmed = window.confirm(
514
- "Leave this organization? Members of the organization will lose any implicit access to this workspace."
515
+ "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."
515
516
  );
516
517
  if (!confirmed) return;
517
518
  setOrgActionSubmitting(true);
@@ -856,7 +857,7 @@ function WorkspaceModal({
856
857
  color: active ? "#ffffff" : T.muted,
857
858
  textAlign: "center"
858
859
  },
859
- children: opt === "private" ? "Private" : "Visible to organization"
860
+ children: opt === "private" ? "Private" : "Listed in picker"
860
861
  }
861
862
  ) })
862
863
  },
@@ -1607,7 +1608,7 @@ var TAB_TO_URL = {
1607
1608
  workspaceList: "workspace/all",
1608
1609
  organization: "organization/people",
1609
1610
  organizationWorkspaces: "organization/workspaces",
1610
- organizationDomains: "organization/domains",
1611
+ organizationDomains: "organization/workspaces",
1611
1612
  referral: "referral",
1612
1613
  billing: "billing",
1613
1614
  apikey: "api-keys"
@@ -1619,7 +1620,8 @@ var URL_TO_TAB = {
1619
1620
  "workspace/all": "workspaceList",
1620
1621
  "organization/people": "organization",
1621
1622
  "organization/workspaces": "organizationWorkspaces",
1622
- "organization/domains": "organizationDomains",
1623
+ /* The Domains tab is gone; its join requests live under Workspaces. */
1624
+ "organization/domains": "organizationWorkspaces",
1623
1625
  /* Unscoped destinations. */
1624
1626
  account: "profile",
1625
1627
  referral: "referral",
@@ -1638,7 +1640,7 @@ var TAB_LABELS = {
1638
1640
  workspaceList: "My workspaces",
1639
1641
  organization: "People",
1640
1642
  organizationWorkspaces: "Workspaces",
1641
- organizationDomains: "Domains & requests",
1643
+ organizationDomains: "Workspaces",
1642
1644
  referral: "Referral",
1643
1645
  /* "Billing & usage", not "Billing". The tab has held usage history as well
1644
1646
  as the plan and invoices since the credits work, and hosts had started
@@ -1652,9 +1654,9 @@ var TAB_DESCRIPTIONS = {
1652
1654
  workspace: "Rename or re-brand this workspace, or leave and delete it",
1653
1655
  workspaceMembers: "Invite people to this workspace and control which apps they can use",
1654
1656
  workspaceList: "Switch between your workspaces, or start a new one",
1655
- organization: "Everyone in the organization, and the invites still waiting to be accepted",
1656
- organizationWorkspaces: "Every workspace that sits under this organization",
1657
- organizationDomains: "Auto-join by email domain, and workspaces asking to join the organization",
1657
+ organization: "Everyone in the organization and their role",
1658
+ organizationWorkspaces: "Every workspace in this organization, and workspaces asking to join it",
1659
+ organizationDomains: "Every workspace in this organization, and workspaces asking to join it",
1658
1660
  referral: "Invite friends to Streamoid and track the rewards you have earned",
1659
1661
  billing: "Workspace plan, credits, invoices and usage history",
1660
1662
  apikey: "Create and revoke keys for calling the Streamoid APIs"
@@ -2273,7 +2275,7 @@ function OrganizationAffiliationCard({
2273
2275
  style: { gap: T5.spMd, opacity: submitting ? 0.6 : 1 },
2274
2276
  children: [
2275
2277
  workspaceAdapter.setOrgVisibility && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-start w-full", style: { gap: T5.spXs }, children: [
2276
- /* @__PURE__ */ jsx10(FieldLabel, { children: "Who in the organization can see this workspace" }),
2278
+ /* @__PURE__ */ jsx10(FieldLabel, { children: "List this workspace in the organization's workspace picker" }),
2277
2279
  /* @__PURE__ */ jsx10(
2278
2280
  "div",
2279
2281
  {
@@ -2304,11 +2306,11 @@ function OrganizationAffiliationCard({
2304
2306
  if (active || !workspaceAdapter.setOrgVisibility) return;
2305
2307
  void run(
2306
2308
  () => workspaceAdapter.setOrgVisibility(opt),
2307
- opt === "private" ? "Workspace is now private" : "Workspace is now visible to the organization",
2309
+ opt === "private" ? "Workspace is now private" : "Workspace is now listed in the workspace picker",
2308
2310
  "Failed to change visibility"
2309
2311
  );
2310
2312
  },
2311
- children: opt === "private" ? "Only workspace members" : "Everyone in the organization"
2313
+ children: opt === "private" ? "Private (invite only)" : "Listed in the workspace picker"
2312
2314
  },
2313
2315
  opt
2314
2316
  );
@@ -2334,7 +2336,7 @@ function OrganizationAffiliationCard({
2334
2336
  },
2335
2337
  onClick: () => {
2336
2338
  const confirmed = window.confirm(
2337
- "Leave this organization? Members of the organization will lose any implicit access to this workspace."
2339
+ "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."
2338
2340
  );
2339
2341
  if (!confirmed || !workspaceAdapter.leaveOrganization) return;
2340
2342
  void run(
@@ -2741,12 +2743,13 @@ function InviteUpdateModal({
2741
2743
  organizationName,
2742
2744
  allowGuestStanding = true,
2743
2745
  initialOrganizationStanding = "guest",
2746
+ organizationDomain,
2744
2747
  onInvite
2745
2748
  }) {
2746
2749
  useOverlayOpen(open, onClose);
2747
2750
  const [emailValue, setEmailValue] = useState6("");
2748
2751
  const [hasChanges, setHasChanges] = useState6(false);
2749
- const [role, setRole] = useState6("admin");
2752
+ const [role, setRole] = useState6("member");
2750
2753
  const [orgStanding, setOrgStanding] = useState6(
2751
2754
  initialOrganizationStanding
2752
2755
  );
@@ -2785,7 +2788,7 @@ function InviteUpdateModal({
2785
2788
  if (!open) {
2786
2789
  setEmailValue("");
2787
2790
  setHasChanges(false);
2788
- setRole("admin");
2791
+ setRole("member");
2789
2792
  setOrgStanding(initialOrganizationStanding);
2790
2793
  setCanUseCredits(true);
2791
2794
  setCanInviteUser(true);
@@ -2797,6 +2800,14 @@ function InviteUpdateModal({
2797
2800
  setSelectedStores(/* @__PURE__ */ new Set());
2798
2801
  }
2799
2802
  }, [open, initialPermissions, hiddenKey, initialOrganizationStanding]);
2803
+ const orgDomain = (organizationDomain || "").trim().toLowerCase();
2804
+ const inviteeDomains = emailValue.split(/[\s,;]+/).map((email) => email.trim().toLowerCase().split("@")[1] || "").filter(Boolean);
2805
+ const inviteeIsGuest = mode === "invite" && inviteeDomains.some(
2806
+ (domain) => !(orgDomain && domain === orgDomain) && (showOrganizationStanding ? orgStanding === "guest" : !!orgDomain)
2807
+ );
2808
+ useEffect6(() => {
2809
+ if (inviteeIsGuest && role === "admin") setRole("member");
2810
+ }, [inviteeIsGuest, role]);
2800
2811
  if (!open) return null;
2801
2812
  const isInvite = mode === "invite";
2802
2813
  const hasEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue.trim());
@@ -2987,12 +2998,15 @@ function InviteUpdateModal({
2987
2998
  /* @__PURE__ */ jsx12(
2988
2999
  "div",
2989
3000
  {
2990
- className: "flex-1 min-w-0 cursor-pointer",
3001
+ className: `flex-1 min-w-0 ${inviteeIsGuest ? "cursor-not-allowed" : "cursor-pointer"}`,
3002
+ "aria-disabled": inviteeIsGuest,
2991
3003
  style: {
2992
3004
  background: role === "admin" ? T6.neutral300 : "transparent",
2993
- borderRadius: T6.rMd
3005
+ borderRadius: T6.rMd,
3006
+ opacity: inviteeIsGuest ? 0.4 : 1
2994
3007
  },
2995
3008
  onClick: () => {
3009
+ if (inviteeIsGuest) return;
2996
3010
  setRole("admin");
2997
3011
  setCanUseCredits(true);
2998
3012
  setCanInviteUser(true);
@@ -3066,6 +3080,19 @@ function InviteUpdateModal({
3066
3080
  ) })
3067
3081
  ]
3068
3082
  }
3083
+ ),
3084
+ inviteeIsGuest && /* @__PURE__ */ jsx12(
3085
+ "span",
3086
+ {
3087
+ style: {
3088
+ fontFamily: T6.font,
3089
+ fontSize: T6.fsXs,
3090
+ fontWeight: 400,
3091
+ lineHeight: T6.lhXs,
3092
+ color: T6.tertiary
3093
+ },
3094
+ children: "Guests can only be Members."
3095
+ }
3069
3096
  )
3070
3097
  ]
3071
3098
  }
@@ -3255,7 +3282,7 @@ function InviteUpdateModal({
3255
3282
  lineHeight: T6.lhXs,
3256
3283
  color: T6.tertiary
3257
3284
  },
3258
- 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"}.`
3285
+ 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"}.`
3259
3286
  }
3260
3287
  )
3261
3288
  ]
@@ -3950,7 +3977,19 @@ function MemberListToolbar({
3950
3977
  className: "flex flex-wrap items-center justify-between shrink-0 w-full",
3951
3978
  style: { gap: "var(--spacing-md)" },
3952
3979
  children: [
3953
- /* @__PURE__ */ jsx13(
3980
+ pendingCount === void 0 ? /* @__PURE__ */ jsx13(
3981
+ "span",
3982
+ {
3983
+ style: {
3984
+ fontFamily: T7.font,
3985
+ fontSize: T7.fsSm,
3986
+ fontWeight: 500,
3987
+ lineHeight: T7.lhSm,
3988
+ color: T7.primary
3989
+ },
3990
+ children: withCount(activeLabel, activeCount)
3991
+ }
3992
+ ) : /* @__PURE__ */ jsx13(
3954
3993
  ScTabSwitcher,
3955
3994
  {
3956
3995
  tabCount: "2",
@@ -4916,9 +4955,9 @@ function TeamsContent({
4916
4955
  lineHeight: "var(--line-height-line-height-xs)"
4917
4956
  },
4918
4957
  children: [
4919
- "This workspace is visible to everyone in ",
4958
+ "Anyone in ",
4920
4959
  organizationName,
4921
- ", and its admins keep access whether or not they are listed here. Change that under Workspace \u203A General."
4960
+ " 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."
4922
4961
  ]
4923
4962
  }
4924
4963
  ),
@@ -5000,6 +5039,7 @@ function TeamsContent({
5000
5039
  ),
5001
5040
  showOrganizationStanding: mayGrantOrgMembership,
5002
5041
  organizationName: organizationName ?? orgCurrent?.name,
5042
+ organizationDomain: workspaceOrgId && orgCurrent?.id === workspaceOrgId ? orgCurrent?.domain : void 0,
5003
5043
  onInvite: handleInvite
5004
5044
  }
5005
5045
  )
@@ -5068,13 +5108,13 @@ function TeamsContent({
5068
5108
  // src/organization-content.tsx
5069
5109
  import { useCallback as useCallback3, useEffect as useEffect10, useState as useState10 } from "react";
5070
5110
  import { ScButton as ScButton5 } from "@streamoid/ui";
5071
- import { SiconUserAdd as SiconUserAdd2, SiconGlobe as SiconGlobe2 } from "@streamoid/icons";
5111
+ import { SiconCheck, SiconCopy, SiconGlobe as SiconGlobe2, SiconSettings } from "@streamoid/icons";
5072
5112
 
5073
- // src/organization-invite-modal.tsx
5113
+ // src/organization-member-modal.tsx
5074
5114
  import { useEffect as useEffect8, useState as useState8 } from "react";
5075
5115
  import { ScButton as ScButton4 } from "@streamoid/ui";
5076
5116
  import { SiconClose as SiconClose3 } from "@streamoid/icons";
5077
- import { Fragment as Fragment7, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
5117
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
5078
5118
  var T9 = {
5079
5119
  primary: "var(--alias-text---icons-primary)",
5080
5120
  tertiary: "var(--alias-text---icons-tertiary)",
@@ -5101,33 +5141,6 @@ var T9 = {
5101
5141
  r4xl: "var(--radius-4xl)",
5102
5142
  neutral300: "var(--primitives-neutral-300)"
5103
5143
  };
5104
- function CheckboxSvg2({ checked }) {
5105
- return /* @__PURE__ */ jsx15("div", { className: "relative shrink-0", style: { width: 24, height: 24 }, children: /* @__PURE__ */ jsx15("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: checked ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
5106
- /* @__PURE__ */ jsx15(
5107
- "rect",
5108
- {
5109
- x: "0.75",
5110
- y: "0.75",
5111
- width: "22.5",
5112
- height: "22.5",
5113
- rx: "5.65",
5114
- fill: T9.primary,
5115
- stroke: T9.primary,
5116
- strokeWidth: "1.5"
5117
- }
5118
- ),
5119
- /* @__PURE__ */ jsx15(
5120
- "path",
5121
- {
5122
- d: "M7 12.5L10.5 16L17 8",
5123
- stroke: T9.inverse,
5124
- strokeWidth: "1.5",
5125
- strokeLinecap: "round",
5126
- strokeLinejoin: "round"
5127
- }
5128
- )
5129
- ] }) : /* @__PURE__ */ jsx15("path", { d: svg_rodctpja6f_default.p4792500, fill: T9.muted }) }) });
5130
- }
5131
5144
  function FieldLabel3({ text }) {
5132
5145
  return /* @__PURE__ */ jsx15("div", { className: "flex items-center shrink-0 w-full", style: { height: 24 }, children: /* @__PURE__ */ jsx15(
5133
5146
  "div",
@@ -5203,69 +5216,29 @@ function SegmentedToggle({
5203
5216
  }
5204
5217
  );
5205
5218
  }
5206
- function OrganizationInviteModal({
5219
+ function OrganizationMemberModal({
5207
5220
  open,
5208
- mode,
5209
5221
  userEmail = "email@domain.in",
5210
5222
  initialRole,
5211
5223
  lockRole,
5212
- canClaimDomain = true,
5213
- claimableDomain,
5214
5224
  lockedRoleLabel,
5215
- initialInviteAccess,
5216
- allowSubmitWithoutChanges = false,
5217
5225
  canRemove = true,
5218
5226
  onClose,
5219
- onInviteEmail,
5220
- onInviteDomain,
5221
5227
  onUpdate,
5222
5228
  onRemove
5223
5229
  }) {
5224
5230
  useOverlayOpen(open, onClose);
5225
- const [inviteMode, setInviteMode] = useState8("email");
5226
- const [emailValue, setEmailValue] = useState8("");
5227
- const [domainValue, setDomainValue] = useState8(claimableDomain ?? "");
5228
5231
  const [hasChanges, setHasChanges] = useState8(false);
5229
- const [role, setRole] = useState8("admin");
5230
- const [inviteAccess, setInviteAccess] = useState8(false);
5232
+ const [role, setRole] = useState8("member");
5231
5233
  useEffect8(() => {
5232
- if (open && mode === "update") {
5234
+ if (open) {
5233
5235
  setRole(initialRole ?? "member");
5234
- setInviteAccess(initialInviteAccess ?? false);
5235
- }
5236
- if (!open) {
5237
- setInviteMode("email");
5238
- setEmailValue("");
5239
- setDomainValue(claimableDomain ?? "");
5236
+ } else {
5240
5237
  setHasChanges(false);
5241
- setRole("admin");
5242
- setInviteAccess(true);
5243
5238
  }
5244
- }, [open, mode, initialRole, initialInviteAccess, claimableDomain]);
5239
+ }, [open, initialRole]);
5245
5240
  if (!open) return null;
5246
- const isInvite = mode === "invite";
5247
- const isEmailInvite = isInvite && inviteMode === "email";
5248
- const isDomainInvite = isInvite && inviteMode === "domain";
5249
- const hasEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue.trim());
5250
- const hasDomain = /^[^\s@]+\.[^\s@]+$/.test(domainValue.trim());
5251
- const isSubmitDisabled = isEmailInvite ? !hasEmail : isDomainInvite ? !hasDomain : (
5252
- // A locked role has nothing this modal can legitimately submit.
5253
- lockRole || !(allowSubmitWithoutChanges || hasChanges)
5254
- );
5255
- function markChanged() {
5256
- setHasChanges(true);
5257
- }
5258
- function handleSubmit() {
5259
- if (isEmailInvite) {
5260
- onInviteEmail?.({ email: emailValue.trim(), role, inviteAccess });
5261
- return;
5262
- }
5263
- if (isDomainInvite) {
5264
- onInviteDomain?.({ domain: domainValue.trim(), autoJoinRole: role });
5265
- return;
5266
- }
5267
- onUpdate?.({ role, inviteAccess });
5268
- }
5241
+ const isSubmitDisabled = lockRole || !hasChanges;
5269
5242
  return /* @__PURE__ */ jsx15(
5270
5243
  "div",
5271
5244
  {
@@ -5283,6 +5256,7 @@ function OrganizationInviteModal({
5283
5256
  borderRadius: T9.r4xl,
5284
5257
  border: `1px solid ${T9.borderSubtle}`,
5285
5258
  width: 480,
5259
+ maxWidth: "calc(100vw - 32px)",
5286
5260
  maxHeight: "85vh"
5287
5261
  },
5288
5262
  children: [
@@ -5312,7 +5286,7 @@ function OrganizationInviteModal({
5312
5286
  fontWeight: 600,
5313
5287
  lineHeight: T9.lhLg
5314
5288
  },
5315
- children: isInvite ? "Invite to organization" : "Update member"
5289
+ children: "Update member"
5316
5290
  }
5317
5291
  ),
5318
5292
  /* @__PURE__ */ jsx15("div", { className: "shrink-0 cursor-pointer", onClick: onClose, children: /* @__PURE__ */ jsx15(SiconClose3, { className: "w-6 h-6", color: T9.primary }) })
@@ -5326,116 +5300,41 @@ function OrganizationInviteModal({
5326
5300
  className: "flex flex-col items-start w-full",
5327
5301
  style: { padding: `${T9.sp3xl} ${T9.sp6xl}`, gap: T9.sp3xl },
5328
5302
  children: [
5329
- isInvite && canClaimDomain && /* @__PURE__ */ jsxs12(
5330
- "div",
5331
- {
5332
- className: "flex flex-col items-start justify-center shrink-0 w-full",
5333
- style: { gap: T9.spXs },
5334
- children: [
5335
- /* @__PURE__ */ jsx15(FieldLabel3, { text: "Invite by" }),
5336
- /* @__PURE__ */ jsx15(
5337
- SegmentedToggle,
5338
- {
5339
- options: [
5340
- { value: "email", label: "Email" },
5341
- { value: "domain", label: "Domain" }
5342
- ],
5343
- value: inviteMode,
5344
- onChange: setInviteMode
5345
- }
5346
- )
5347
- ]
5348
- }
5349
- ),
5350
5303
  /* @__PURE__ */ jsxs12(
5351
5304
  "div",
5352
5305
  {
5353
5306
  className: "flex flex-col items-start justify-center shrink-0 w-full",
5354
5307
  style: { gap: T9.spXs },
5355
5308
  children: [
5356
- /* @__PURE__ */ jsx15(
5357
- FieldLabel3,
5358
- {
5359
- text: isDomainInvite ? "Domain" : isEmailInvite ? "Email ID" : "Email ID"
5360
- }
5361
- ),
5309
+ /* @__PURE__ */ jsx15(FieldLabel3, { text: "Email ID" }),
5362
5310
  /* @__PURE__ */ jsx15(
5363
5311
  "div",
5364
5312
  {
5365
5313
  className: "shrink-0 w-full",
5366
5314
  style: { background: T9.fillPlus, height: 48, borderRadius: T9.r3xl },
5367
- children: /* @__PURE__ */ jsx15("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsxs12(
5315
+ children: /* @__PURE__ */ jsx15("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsx15(
5368
5316
  "div",
5369
5317
  {
5370
5318
  className: "flex items-center relative size-full",
5371
5319
  style: { padding: `${T9.spXl} ${T9.sp3xl}` },
5372
- children: [
5373
- isEmailInvite && /* @__PURE__ */ jsx15(
5374
- "input",
5375
- {
5376
- className: "flex-1 min-w-0 bg-transparent border-none outline-none",
5377
- style: {
5378
- fontFamily: T9.font,
5379
- fontSize: T9.fsSm,
5380
- fontWeight: 400,
5381
- lineHeight: T9.lhSm,
5382
- color: T9.primary
5383
- },
5384
- placeholder: "email@domain.in",
5385
- value: emailValue,
5386
- onChange: (e) => setEmailValue(e.target.value)
5387
- }
5388
- ),
5389
- isDomainInvite && /* @__PURE__ */ jsx15(
5390
- "span",
5391
- {
5392
- className: "flex-1 min-w-0 truncate",
5393
- style: {
5394
- fontFamily: T9.font,
5395
- fontSize: T9.fsSm,
5396
- fontWeight: 400,
5397
- lineHeight: T9.lhSm,
5398
- color: T9.primary
5399
- },
5400
- children: domainValue
5401
- }
5402
- ),
5403
- !isInvite && /* @__PURE__ */ jsx15(
5404
- "div",
5405
- {
5406
- className: "flex-1 flex flex-col justify-center",
5407
- style: {
5408
- fontFamily: T9.font,
5409
- fontSize: T9.fsSm,
5410
- fontWeight: 400,
5411
- lineHeight: T9.lhSm,
5412
- color: T9.muted,
5413
- opacity: 0.6
5414
- },
5415
- children: userEmail
5416
- }
5417
- )
5418
- ]
5320
+ children: /* @__PURE__ */ jsx15(
5321
+ "div",
5322
+ {
5323
+ className: "flex-1 flex flex-col justify-center truncate",
5324
+ style: {
5325
+ fontFamily: T9.font,
5326
+ fontSize: T9.fsSm,
5327
+ fontWeight: 400,
5328
+ lineHeight: T9.lhSm,
5329
+ color: T9.muted,
5330
+ opacity: 0.6
5331
+ },
5332
+ children: userEmail
5333
+ }
5334
+ )
5419
5335
  }
5420
5336
  ) })
5421
5337
  }
5422
- ),
5423
- isDomainInvite && /* @__PURE__ */ jsxs12(
5424
- "span",
5425
- {
5426
- style: {
5427
- fontFamily: T9.font,
5428
- fontSize: T9.fsSm,
5429
- fontWeight: 400,
5430
- color: T9.muted
5431
- },
5432
- children: [
5433
- "Anyone who signs up or logs in with an @",
5434
- domainValue.trim(),
5435
- " ",
5436
- "address will automatically join this organization from now on."
5437
- ]
5438
- }
5439
5338
  )
5440
5339
  ]
5441
5340
  }
@@ -5446,7 +5345,7 @@ function OrganizationInviteModal({
5446
5345
  className: "flex flex-col items-start justify-center shrink-0 w-full",
5447
5346
  style: { gap: T9.spXs },
5448
5347
  children: [
5449
- /* @__PURE__ */ jsx15(FieldLabel3, { text: isDomainInvite ? "Auto-join role" : "Role" }),
5348
+ /* @__PURE__ */ jsx15(FieldLabel3, { text: "Role" }),
5450
5349
  lockRole ? /* @__PURE__ */ jsxs12(
5451
5350
  "span",
5452
5351
  {
@@ -5458,49 +5357,33 @@ function OrganizationInviteModal({
5458
5357
  },
5459
5358
  children: [
5460
5359
  lockedRoleLabel || "Guest",
5461
- " \u2014 invited to specific workspaces only, with no access to the rest of the organization. Remove them to end that access."
5360
+ " \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."
5462
5361
  ]
5463
5362
  }
5464
5363
  ) : /* @__PURE__ */ jsx15(
5465
5364
  SegmentedToggle,
5466
5365
  {
5467
5366
  options: [
5468
- { value: "admin", label: "Admin" },
5367
+ { value: "admin", label: "Org admin" },
5469
5368
  { value: "member", label: "Member" }
5470
5369
  ],
5471
5370
  value: role,
5472
5371
  onChange: (v) => {
5473
5372
  setRole(v);
5474
- if (v === "admin") setInviteAccess(true);
5475
- markChanged();
5373
+ setHasChanges(v !== (initialRole ?? "member"));
5476
5374
  }
5477
5375
  }
5478
- )
5479
- ]
5480
- }
5481
- ),
5482
- !isDomainInvite && !lockRole && role === "member" && /* @__PURE__ */ jsxs12(
5483
- "div",
5484
- {
5485
- className: "flex items-center shrink-0 w-full cursor-pointer",
5486
- style: { gap: T9.spMd },
5487
- onClick: () => {
5488
- setInviteAccess(!inviteAccess);
5489
- markChanged();
5490
- },
5491
- children: [
5492
- /* @__PURE__ */ jsx15(CheckboxSvg2, { checked: inviteAccess }),
5493
- /* @__PURE__ */ jsx15(
5376
+ ),
5377
+ !lockRole && /* @__PURE__ */ jsx15(
5494
5378
  "span",
5495
5379
  {
5496
5380
  style: {
5497
5381
  fontFamily: T9.font,
5498
5382
  fontSize: T9.fsSm,
5499
- fontWeight: 400,
5500
5383
  lineHeight: T9.lhSm,
5501
- color: T9.primary
5384
+ color: T9.muted
5502
5385
  },
5503
- children: "Can invite members"
5386
+ children: "Org admins can see and manage every workspace in the organization."
5504
5387
  }
5505
5388
  )
5506
5389
  ]
@@ -5521,10 +5404,10 @@ function OrganizationInviteModal({
5521
5404
  /* @__PURE__ */ jsx15("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsxs12(
5522
5405
  "div",
5523
5406
  {
5524
- className: `flex items-center w-full ${isInvite ? "justify-end" : "justify-between"}`,
5407
+ className: "flex items-center w-full justify-between",
5525
5408
  style: { padding: `${T9.sp3xl} ${T9.sp6xl}` },
5526
5409
  children: [
5527
- !isInvite && /* @__PURE__ */ jsx15(
5410
+ /* @__PURE__ */ jsx15(
5528
5411
  ScButton4,
5529
5412
  {
5530
5413
  text: "Remove member",
@@ -5537,11 +5420,11 @@ function OrganizationInviteModal({
5537
5420
  /* @__PURE__ */ jsx15(
5538
5421
  ScButton4,
5539
5422
  {
5540
- text: isEmailInvite ? "Send invite" : isDomainInvite ? "Add domain" : allowSubmitWithoutChanges ? "Resend invite" : "Save changes",
5423
+ text: "Save changes",
5541
5424
  variant: "primary",
5542
5425
  size: "md",
5543
5426
  state: isSubmitDisabled ? "disabled" : "default",
5544
- onClick: !isSubmitDisabled ? handleSubmit : void 0
5427
+ onClick: !isSubmitDisabled ? () => onUpdate?.({ role }) : void 0
5545
5428
  }
5546
5429
  )
5547
5430
  ]
@@ -5557,7 +5440,7 @@ function OrganizationInviteModal({
5557
5440
 
5558
5441
  // src/organization-modal.tsx
5559
5442
  import { useState as useState9, useRef as useRef5, useEffect as useEffect9 } from "react";
5560
- import { Fragment as Fragment8, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
5443
+ import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
5561
5444
  var T10 = {
5562
5445
  primary: "var(--alias-text---icons-primary)",
5563
5446
  muted: "var(--alias-text---icons-muted)",
@@ -5851,7 +5734,7 @@ function OrganizationModal({
5851
5734
  height: 120
5852
5735
  },
5853
5736
  onClick: () => !hasImage && fileInputRef.current?.click(),
5854
- children: /* @__PURE__ */ jsx16("div", { className: "flex items-center justify-center size-full", style: { padding: `var(--spacing-lg) ${T10.spXl}`, gap: T10.spMd }, children: hasImage ? /* @__PURE__ */ jsxs13(Fragment8, { children: [
5737
+ children: /* @__PURE__ */ jsx16("div", { className: "flex items-center justify-center size-full", style: { padding: `var(--spacing-lg) ${T10.spXl}`, gap: T10.spMd }, children: hasImage ? /* @__PURE__ */ jsxs13(Fragment7, { children: [
5855
5738
  /* @__PURE__ */ jsx16(
5856
5739
  "div",
5857
5740
  {
@@ -5886,7 +5769,7 @@ function OrganizationModal({
5886
5769
  e.stopPropagation();
5887
5770
  handleRemoveImage();
5888
5771
  }, children: /* @__PURE__ */ jsx16(CloseIcon4, { color: "var(--primitives-error-500)" }) })
5889
- ] }) : /* @__PURE__ */ jsxs13(Fragment8, { children: [
5772
+ ] }) : /* @__PURE__ */ jsxs13(Fragment7, { children: [
5890
5773
  /* @__PURE__ */ jsx16(UploadIcon2, {}),
5891
5774
  /* @__PURE__ */ jsx16(
5892
5775
  "span",
@@ -5992,7 +5875,7 @@ function OrganizationModal({
5992
5875
  }
5993
5876
 
5994
5877
  // src/organization-content.tsx
5995
- import { Fragment as Fragment9, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
5878
+ import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
5996
5879
  function orgRoleLabel(role) {
5997
5880
  if (role === "admin") return "Org admin";
5998
5881
  if (role === "member") return "Member";
@@ -6035,20 +5918,6 @@ function formatDate(iso) {
6035
5918
  return iso;
6036
5919
  }
6037
5920
  }
6038
- function toDisplayText2(value, fallback = "\u2013") {
6039
- if (typeof value === "string") {
6040
- const trimmed = value.trim();
6041
- return trimmed.length > 0 ? trimmed : fallback;
6042
- }
6043
- if (value && typeof value === "object") {
6044
- const record = value;
6045
- const name = typeof record.name === "string" ? record.name.trim() : "";
6046
- if (name) return name;
6047
- const email = typeof record.email === "string" ? record.email.trim() : "";
6048
- if (email) return email;
6049
- }
6050
- return fallback;
6051
- }
6052
5921
  function VisibilityBadge({ visibility }) {
6053
5922
  const isShared = visibility === "shared";
6054
5923
  return /* @__PURE__ */ jsx17(
@@ -6069,10 +5938,46 @@ function VisibilityBadge({ visibility }) {
6069
5938
  }
6070
5939
  );
6071
5940
  }
5941
+ function RowIconButton({
5942
+ label,
5943
+ onClick,
5944
+ children,
5945
+ visible = true
5946
+ }) {
5947
+ return /* @__PURE__ */ jsx17(
5948
+ "button",
5949
+ {
5950
+ type: "button",
5951
+ "aria-label": label,
5952
+ title: label,
5953
+ className: "flex items-center justify-center shrink-0 cursor-pointer border-none",
5954
+ style: {
5955
+ width: 32,
5956
+ height: 32,
5957
+ borderRadius: T11.rLg,
5958
+ background: "transparent",
5959
+ opacity: visible ? 1 : 0,
5960
+ transition: "opacity 120ms ease"
5961
+ },
5962
+ onMouseEnter: (e) => {
5963
+ e.currentTarget.style.background = T11.fillPlus;
5964
+ },
5965
+ onMouseLeave: (e) => {
5966
+ e.currentTarget.style.background = "transparent";
5967
+ },
5968
+ onClick,
5969
+ children
5970
+ }
5971
+ );
5972
+ }
6072
5973
  function MemberRow({
6073
5974
  member,
6074
- onClick
5975
+ onEdit,
5976
+ onCopyEmail
6075
5977
  }) {
5978
+ const [copied, setCopied] = useState10(false);
5979
+ const [active, setActive] = useState10(false);
5980
+ const noHover = typeof window !== "undefined" && window.matchMedia?.("(hover: none)").matches === true;
6076
5981
  const name = member.user.name?.trim();
6077
5982
  const email = member.user.email || "";
6078
5983
  const displayIdent = name || email.split("@")[0] || "user";
@@ -6084,18 +5989,20 @@ function MemberRow({
6084
5989
  return /* @__PURE__ */ jsxs14(
6085
5990
  "div",
6086
5991
  {
6087
- className: `flex items-center self-stretch shrink-0 ${onClick ? "cursor-pointer" : "cursor-default"}`,
5992
+ className: "flex items-center self-stretch shrink-0 cursor-default",
6088
5993
  style: {
6089
5994
  borderBottom: `1px solid ${T11.borderSubtle}`,
6090
5995
  padding: `${T11.sp5xl} ${T11.sp3xl}`,
6091
- gap: T11.sp6xl
6092
- },
6093
- onClick,
6094
- onMouseEnter: (e) => {
6095
- if (onClick) e.currentTarget.style.background = T11.fillPlus;
5996
+ gap: T11.sp6xl,
5997
+ background: active && onEdit ? T11.fillPlus : "transparent"
6096
5998
  },
6097
- onMouseLeave: (e) => {
6098
- e.currentTarget.style.background = "transparent";
5999
+ onMouseEnter: () => setActive(true),
6000
+ onMouseLeave: () => setActive(false),
6001
+ onFocus: () => setActive(true),
6002
+ onBlur: (e) => {
6003
+ if (!e.currentTarget.contains(e.relatedTarget)) {
6004
+ setActive(false);
6005
+ }
6099
6006
  },
6100
6007
  children: [
6101
6008
  /* @__PURE__ */ jsxs14(
@@ -6174,112 +6081,29 @@ function MemberRow({
6174
6081
  },
6175
6082
  children: formatDate(member.createdAt || member.user.createdAt)
6176
6083
  }
6177
- )
6178
- ]
6179
- }
6180
- );
6181
- }
6182
- function InviteRow({
6183
- invite,
6184
- onCancel,
6185
- onResend
6186
- }) {
6187
- const isDomain = invite.kind === "domain";
6188
- const invitedByText = (() => {
6189
- if (!invite.invitedBy) return "\u2013";
6190
- if (typeof invite.invitedBy === "string") return invite.invitedBy;
6191
- return invite.invitedBy.name || invite.invitedBy.email || "\u2013";
6192
- })();
6193
- const role = isDomain ? invite.autoJoinRole : invite.role;
6194
- return /* @__PURE__ */ jsxs14(
6195
- "div",
6196
- {
6197
- className: "flex items-center self-stretch shrink-0",
6198
- style: {
6199
- borderBottom: `1px solid ${T11.borderSubtle}`,
6200
- padding: `${T11.sp5xl} ${T11.sp3xl}`,
6201
- gap: T11.sp6xl
6202
- },
6203
- children: [
6204
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center min-w-0", style: { flex: 1, gap: T11.spMd }, children: [
6205
- isDomain ? /* @__PURE__ */ jsx17(
6206
- "div",
6207
- {
6208
- className: "shrink-0 flex items-center justify-center",
6209
- style: {
6210
- width: 32,
6211
- height: 32,
6212
- borderRadius: T11.rXl,
6213
- background: T11.fillNeutral
6214
- },
6215
- children: /* @__PURE__ */ jsx17(SiconGlobe2, { className: "w-4 h-4", color: T11.primary })
6216
- }
6217
- ) : /* @__PURE__ */ jsx17(ProfileAvatar, { name: invite.email || "invite", size: 32 }),
6218
- /* @__PURE__ */ jsxs14("div", { className: "flex flex-col min-w-0", children: [
6219
- /* @__PURE__ */ jsx17(
6220
- "span",
6221
- {
6222
- className: "truncate",
6223
- style: {
6224
- fontFamily: T11.font,
6225
- fontSize: T11.fsSm,
6226
- fontWeight: 500,
6227
- lineHeight: T11.lhSm,
6228
- color: T11.primary
6229
- },
6230
- children: isDomain ? `Domain: ${invite.domain}` : toDisplayText2(invite.email, "")
6231
- }
6232
- ),
6233
- /* @__PURE__ */ jsx17(
6234
- "span",
6235
- {
6236
- className: "truncate",
6237
- style: {
6238
- fontFamily: T11.font,
6239
- fontSize: T11.fsXs,
6240
- fontWeight: 400,
6241
- lineHeight: T11.lhXs,
6242
- color: T11.muted
6243
- },
6244
- children: isDomain ? "Auto-join by verified domain" : "Email invite"
6245
- }
6246
- )
6247
- ] })
6248
- ] }),
6249
- /* @__PURE__ */ jsx17(
6250
- RoleLabel,
6084
+ ),
6085
+ /* @__PURE__ */ jsx17("div", { className: "flex items-center justify-end shrink-0", style: { width: 32 }, children: onEdit ? /* @__PURE__ */ jsx17(
6086
+ RowIconButton,
6251
6087
  {
6252
- role: role === "admin" ? "admin" : "member",
6253
- label: orgRoleLabel(role)
6088
+ label: `Manage ${email || "member"}`,
6089
+ onClick: onEdit,
6090
+ visible: active || noHover,
6091
+ children: /* @__PURE__ */ jsx17(SiconSettings, { className: "w-4 h-4", color: T11.primary })
6254
6092
  }
6255
- ),
6256
- /* @__PURE__ */ jsx17(
6257
- "div",
6093
+ ) : email && /* @__PURE__ */ jsx17(
6094
+ RowIconButton,
6258
6095
  {
6259
- className: "truncate shrink-0",
6260
- style: {
6261
- width: "7.5rem",
6262
- fontFamily: T11.font,
6263
- fontSize: T11.fsSm,
6264
- fontWeight: 400,
6265
- lineHeight: T11.lhSm,
6266
- color: T11.primary
6096
+ label: copied ? "Copied" : `Copy ${email}`,
6097
+ onClick: () => {
6098
+ void onCopyEmail().then((ok) => {
6099
+ if (!ok) return;
6100
+ setCopied(true);
6101
+ setTimeout(() => setCopied(false), 2e3);
6102
+ });
6267
6103
  },
6268
- children: invitedByText
6104
+ children: copied ? /* @__PURE__ */ jsx17(SiconCheck, { className: "w-4 h-4", color: T11.primary }) : /* @__PURE__ */ jsx17(SiconCopy, { className: "w-4 h-4", color: T11.primary })
6269
6105
  }
6270
- ),
6271
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center shrink-0", style: { gap: T11.spMd }, children: [
6272
- !isDomain && onResend && /* @__PURE__ */ jsx17(ScButton5, { text: "Resend", variant: "tertiary", size: "sm", onClick: onResend }),
6273
- /* @__PURE__ */ jsx17(
6274
- ScButton5,
6275
- {
6276
- text: isDomain ? "Revoke" : "Cancel",
6277
- variant: "error",
6278
- size: "sm",
6279
- onClick: onCancel
6280
- }
6281
- )
6282
- ] })
6106
+ ) })
6283
6107
  ]
6284
6108
  }
6285
6109
  );
@@ -6386,7 +6210,7 @@ function JoinRequestRow({
6386
6210
  )
6387
6211
  ] })
6388
6212
  ] }),
6389
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center shrink-0", style: { gap: T11.spMd }, children: [
6213
+ onApprove && onReject && /* @__PURE__ */ jsxs14("div", { className: "flex items-center shrink-0", style: { gap: T11.spMd }, children: [
6390
6214
  /* @__PURE__ */ jsx17(ScButton5, { text: "Reject", variant: "error", size: "sm", onClick: onReject }),
6391
6215
  /* @__PURE__ */ jsx17(ScButton5, { text: "Approve", variant: "primary", size: "sm", onClick: onApprove })
6392
6216
  ] })
@@ -6442,42 +6266,29 @@ function Section({
6442
6266
  }
6443
6267
  function OrganizationContent({
6444
6268
  embedded = false,
6445
- view = "people",
6446
- onInviteOpen,
6447
- onInviteOpenChange
6269
+ view = "people"
6448
6270
  } = {}) {
6449
6271
  const { organization, toast } = useSettingsAdapters();
6450
6272
  const current = organization.current;
6451
- const [activeTab, setActiveTab] = useState10("active");
6452
6273
  const [members, setMembers] = useState10([]);
6453
- const [invites, setInvites] = useState10([]);
6454
6274
  const [workspaces, setWorkspaces] = useState10([]);
6455
6275
  const [joinRequests, setJoinRequests] = useState10([]);
6456
6276
  const [highestRole, setHighestRole] = useState10("guest");
6457
- const [emailDomain, setEmailDomain] = useState10(null);
6458
- const [canClaimEmailDomain, setCanClaimEmailDomain] = useState10(true);
6459
6277
  const [searchQuery, setSearchQuery] = useState10("");
6460
6278
  const [loadingData, setLoadingData] = useState10(false);
6461
- const [modal, setModal] = useState10({ open: false, mode: "invite" });
6279
+ const [modal, setModal] = useState10({ open: false });
6462
6280
  const fetchData = useCallback3(async () => {
6281
+ if (!organization.current) return;
6463
6282
  setLoadingData(true);
6464
6283
  try {
6465
- const [membersRes, invitesRes, workspacesRes, joinRequestsRes, highestRoleRes] = await Promise.all([
6284
+ const [membersRes, workspacesRes, joinRequestsRes, highestRoleRes] = await Promise.all([
6466
6285
  organization.fetchMembers().catch(() => null),
6467
- organization.fetchInvites().catch(() => null),
6468
6286
  organization.fetchWorkspaces().catch(() => null),
6469
6287
  organization.fetchJoinRequests().catch(() => null),
6470
6288
  organization.getHighestRole?.().catch(() => null) ?? Promise.resolve(null)
6471
6289
  ]);
6472
6290
  if (highestRoleRes?.role) setHighestRole(highestRoleRes.role);
6473
- if (highestRoleRes?.emailDomain !== void 0) {
6474
- setEmailDomain(highestRoleRes.emailDomain ?? null);
6475
- }
6476
- if (highestRoleRes?.canClaimEmailDomain !== void 0) {
6477
- setCanClaimEmailDomain(highestRoleRes.canClaimEmailDomain);
6478
- }
6479
6291
  if (membersRes) setMembers(membersRes.filter((m) => m?.user));
6480
- if (invitesRes) setInvites(invitesRes);
6481
6292
  if (workspacesRes) setWorkspaces(workspacesRes);
6482
6293
  if (joinRequestsRes) setJoinRequests(joinRequestsRes);
6483
6294
  } catch {
@@ -6488,51 +6299,6 @@ function OrganizationContent({
6488
6299
  useEffect10(() => {
6489
6300
  fetchData();
6490
6301
  }, [fetchData]);
6491
- const [domainMatch, setDomainMatch] = useState10(null);
6492
- const [checkingDomainMatch, setCheckingDomainMatch] = useState10(false);
6493
- const [joiningByDomain, setJoiningByDomain] = useState10(false);
6494
- const [createModalOpen, setCreateModalOpen] = useState10(false);
6495
- useEffect10(() => {
6496
- if (current) return;
6497
- let cancelled = false;
6498
- setCheckingDomainMatch(true);
6499
- organization.checkDomainMatch().then((match) => {
6500
- if (!cancelled) setDomainMatch(match);
6501
- }).catch(() => {
6502
- if (!cancelled) setDomainMatch(null);
6503
- }).finally(() => {
6504
- if (!cancelled) setCheckingDomainMatch(false);
6505
- });
6506
- return () => {
6507
- cancelled = true;
6508
- };
6509
- }, [current, organization]);
6510
- const handleJoinByDomain = async () => {
6511
- if (!domainMatch) return;
6512
- setJoiningByDomain(true);
6513
- try {
6514
- await organization.joinByDomain();
6515
- await organization.switch(domainMatch.organizationId);
6516
- toast.success(`Joined ${domainMatch.organizationName}`);
6517
- } catch (err) {
6518
- toast.error(err instanceof Error ? err.message : "Failed to join organization");
6519
- } finally {
6520
- setJoiningByDomain(false);
6521
- }
6522
- };
6523
- const handleCreateOrganization = async (name, imageFile) => {
6524
- try {
6525
- const result = await organization.create({ name, imageFile });
6526
- if (result && "id" in result && result.id) {
6527
- await organization.switch(result.id);
6528
- }
6529
- toast.success("Organization created");
6530
- return true;
6531
- } catch (err) {
6532
- toast.error(err instanceof Error ? err.message : "Failed to create organization");
6533
- return false;
6534
- }
6535
- };
6536
6302
  const [manageModalOpen, setManageModalOpen] = useState10(false);
6537
6303
  const handleUpdateOrganization = async (name, imageFile) => {
6538
6304
  if (!current) return false;
@@ -6556,45 +6322,9 @@ function OrganizationContent({
6556
6322
  return false;
6557
6323
  }
6558
6324
  };
6559
- const openInviteModal = () => setModal({ open: true, mode: "invite" });
6560
- useEffect10(() => {
6561
- if (onInviteOpen) {
6562
- openInviteModal();
6563
- onInviteOpenChange?.(false);
6564
- }
6565
- }, [onInviteOpen]);
6566
- const openUpdateModal = (member) => setModal({ open: true, mode: "update", target: member });
6567
- const closeModal = () => setModal({ open: false, mode: "invite" });
6568
- const handleInviteEmail = async (input) => {
6569
- if (highestRole !== "admin") {
6570
- toast.error("You do not have permission to invite members");
6571
- closeModal();
6572
- return;
6573
- }
6574
- try {
6575
- await organization.inviteMemberByEmail(input);
6576
- toast.success(`Invitation sent to ${input.email}`);
6577
- await fetchData();
6578
- closeModal();
6579
- } catch (err) {
6580
- toast.error(err instanceof Error ? err.message : "Failed to send invite");
6581
- }
6582
- };
6583
- const handleInviteDomain = async (input) => {
6584
- if (highestRole !== "admin") {
6585
- toast.error("You do not have permission to invite members");
6586
- closeModal();
6587
- return;
6588
- }
6589
- try {
6590
- await organization.inviteDomain(input);
6591
- toast.success(`Domain ${input.domain} added`);
6592
- await fetchData();
6593
- closeModal();
6594
- } catch (err) {
6595
- toast.error(err instanceof Error ? err.message : "Failed to add domain");
6596
- }
6597
- };
6325
+ const openUpdateModal = (member) => setModal({ open: true, target: member });
6326
+ const closeModal = () => setModal({ open: false });
6327
+ const adminCount = members.filter((m) => m.role === "admin").length;
6598
6328
  const handleUpdateMember = async (input) => {
6599
6329
  const target = modal.target;
6600
6330
  if (!target) {
@@ -6606,20 +6336,16 @@ function OrganizationContent({
6606
6336
  closeModal();
6607
6337
  return;
6608
6338
  }
6609
- if (target.role === "admin" && input.role === "member") {
6610
- const adminCount = members.filter((m) => m.role === "admin").length;
6611
- if (adminCount <= 1) {
6612
- toast.error(
6613
- "You're the only admin. Promote another member to admin before changing your role."
6614
- );
6615
- return;
6616
- }
6339
+ if (target.role === "admin" && input.role === "member" && adminCount <= 1) {
6340
+ toast.error(
6341
+ "This is the only org admin. Make someone else an org admin first."
6342
+ );
6343
+ return;
6617
6344
  }
6618
6345
  try {
6619
6346
  await organization.updateMemberRole({
6620
6347
  userId: target.user._id,
6621
- role: input.role,
6622
- inviteAccess: input.inviteAccess
6348
+ role: input.role
6623
6349
  });
6624
6350
  toast.success("Member updated");
6625
6351
  await fetchData();
@@ -6639,8 +6365,14 @@ function OrganizationContent({
6639
6365
  closeModal();
6640
6366
  return;
6641
6367
  }
6368
+ if (target.role === "admin" && adminCount <= 1) {
6369
+ toast.error(
6370
+ "This is the only org admin. Make someone else an org admin first."
6371
+ );
6372
+ return;
6373
+ }
6642
6374
  const confirmed = window.confirm(
6643
- `Remove ${target.user.email} from this organization?`
6375
+ `Remove ${target.user.email} from this organization? They'll also be removed from every workspace in it.`
6644
6376
  );
6645
6377
  if (!confirmed) return;
6646
6378
  try {
@@ -6652,44 +6384,6 @@ function OrganizationContent({
6652
6384
  }
6653
6385
  closeModal();
6654
6386
  };
6655
- const handleCancelInvite = async (invite) => {
6656
- if (highestRole !== "admin") {
6657
- toast.error("You do not have permission to manage invites");
6658
- return;
6659
- }
6660
- const label = invite.kind === "domain" ? invite.domain : invite.email;
6661
- const confirmed = window.confirm(
6662
- invite.kind === "domain" ? `Revoke domain invite for ${label}? Members who already joined will keep their access.` : `Cancel invitation for ${label}?`
6663
- );
6664
- if (!confirmed) return;
6665
- try {
6666
- if (invite.kind === "domain") {
6667
- await organization.revokeDomainInvite(invite._id);
6668
- } else if (invite.token) {
6669
- await organization.cancelInvite(invite.token);
6670
- } else {
6671
- await organization.removeMember({ invitationIds: [invite._id] });
6672
- }
6673
- toast.success(invite.kind === "domain" ? "Domain invite revoked" : "Invitation removed");
6674
- await fetchData();
6675
- } catch (err) {
6676
- toast.error(err instanceof Error ? err.message : "Failed to update invite");
6677
- }
6678
- };
6679
- const handleResendInvite = async (invite) => {
6680
- if (invite.kind !== "email") return;
6681
- if (highestRole !== "admin") {
6682
- toast.error("You do not have permission to invite members");
6683
- return;
6684
- }
6685
- try {
6686
- await organization.resendInvite(invite._id);
6687
- toast.success("Invitation resent");
6688
- await fetchData();
6689
- } catch (err) {
6690
- toast.error(err instanceof Error ? err.message : "Failed to resend invitation");
6691
- }
6692
- };
6693
6387
  const handleApproveJoinRequest = async (request) => {
6694
6388
  try {
6695
6389
  await organization.approveJoinRequest(request._id);
@@ -6711,101 +6405,29 @@ function OrganizationContent({
6711
6405
  }
6712
6406
  };
6713
6407
  if (!current) {
6714
- return /* @__PURE__ */ jsxs14(Fragment9, { children: [
6715
- /* @__PURE__ */ jsxs14(
6716
- "div",
6717
- {
6718
- className: "flex flex-col flex-1 min-w-0 min-h-0 w-full items-center justify-center",
6719
- style: { gap: T11.spXl, padding: T11.sp6xl },
6720
- children: [
6721
- /* @__PURE__ */ jsx17(SiconGlobe2, { className: "w-10 h-10", color: T11.muted }),
6722
- domainMatch ? /* @__PURE__ */ jsxs14(Fragment9, { children: [
6723
- /* @__PURE__ */ jsxs14(
6724
- "p",
6725
- {
6726
- className: "text-center",
6727
- style: { color: T11.primary, fontFamily: T11.font, fontSize: T11.fsMd, fontWeight: 600 },
6728
- children: [
6729
- "An organization already exists for ",
6730
- domainMatch.domain
6731
- ]
6732
- }
6733
- ),
6734
- /* @__PURE__ */ jsxs14(
6735
- "p",
6736
- {
6737
- className: "text-center",
6738
- style: { color: T11.muted, fontFamily: T11.font, fontSize: T11.fsSm },
6739
- children: [
6740
- domainMatch.organizationName,
6741
- " \u2014 join it instead of creating a new one and fragmenting your company across multiple orgs."
6742
- ]
6743
- }
6744
- ),
6745
- /* @__PURE__ */ jsx17(
6746
- ScButton5,
6747
- {
6748
- text: joiningByDomain ? "Joining\u2026" : `Join ${domainMatch.organizationName}`,
6749
- variant: "primary",
6750
- size: "md",
6751
- state: joiningByDomain ? "disabled" : "default",
6752
- onClick: handleJoinByDomain
6753
- }
6754
- )
6755
- ] }) : /* @__PURE__ */ jsxs14(Fragment9, { children: [
6756
- /* @__PURE__ */ jsx17(
6757
- "p",
6758
- {
6759
- className: "text-center",
6760
- style: { color: T11.primary, fontFamily: T11.font, fontSize: T11.fsMd, fontWeight: 600 },
6761
- children: "You're not part of an organization yet"
6762
- }
6763
- ),
6764
- /* @__PURE__ */ jsx17(
6765
- "p",
6766
- {
6767
- className: "text-center",
6768
- style: { color: T11.muted, fontFamily: T11.font, fontSize: T11.fsSm },
6769
- children: "Create one to invite your team and manage workspaces together."
6770
- }
6771
- ),
6772
- /* @__PURE__ */ jsx17(
6773
- ScButton5,
6774
- {
6775
- text: "Create organization",
6776
- variant: "primary",
6777
- size: "md",
6778
- styleVariant: "icon-left",
6779
- icon: /* @__PURE__ */ jsx17(SiconUserAdd2, { className: "w-5 h-5", color: T11.inverse }),
6780
- state: checkingDomainMatch ? "disabled" : "default",
6781
- onClick: () => setCreateModalOpen(true)
6782
- }
6783
- )
6784
- ] })
6785
- ]
6786
- }
6787
- ),
6788
- /* @__PURE__ */ jsx17(
6789
- OrganizationModal,
6790
- {
6791
- open: createModalOpen,
6792
- mode: "create",
6793
- onClose: () => setCreateModalOpen(false),
6794
- onCreate: handleCreateOrganization
6795
- }
6796
- )
6797
- ] });
6408
+ return /* @__PURE__ */ jsxs14(
6409
+ "div",
6410
+ {
6411
+ className: "flex flex-col flex-1 min-w-0 min-h-0 w-full items-center justify-center",
6412
+ style: { gap: T11.spXl, padding: T11.sp6xl },
6413
+ children: [
6414
+ /* @__PURE__ */ jsx17(SiconGlobe2, { className: "w-10 h-10", color: T11.muted }),
6415
+ /* @__PURE__ */ jsx17(
6416
+ "p",
6417
+ {
6418
+ className: "text-center",
6419
+ style: { color: T11.primary, fontFamily: T11.font, fontSize: T11.fsMd, fontWeight: 600 },
6420
+ children: "Your workspace isn't part of an organization"
6421
+ }
6422
+ )
6423
+ ]
6424
+ }
6425
+ );
6798
6426
  }
6799
6427
  const q = searchQuery.toLowerCase();
6800
6428
  const filteredMembers = members.filter(
6801
6429
  (m) => (m.user.email || "").toLowerCase().includes(q) || (m.user.name || "").toLowerCase().includes(q) || m.role.toLowerCase().includes(q)
6802
6430
  );
6803
- const filteredInvites = invites.filter((inv) => {
6804
- const label = inv.kind === "domain" ? inv.domain ?? "" : inv.email ?? "";
6805
- return label.toLowerCase().includes(q);
6806
- });
6807
- const emailInvites = filteredInvites.filter((inv) => inv.kind !== "domain");
6808
- const domainInvites = invites.filter((inv) => inv.kind === "domain");
6809
6431
  const scopeHeader = /* @__PURE__ */ jsx17(
6810
6432
  ScopeHeader,
6811
6433
  {
@@ -6854,15 +6476,26 @@ function OrganizationContent({
6854
6476
  )
6855
6477
  }
6856
6478
  );
6857
- const peopleView = /* @__PURE__ */ jsxs14(Fragment9, { children: [
6479
+ const isOrgAdmin = highestRole === "admin";
6480
+ const copyEmail = async (email) => {
6481
+ try {
6482
+ await navigator.clipboard.writeText(email);
6483
+ toast.success("Email copied");
6484
+ return true;
6485
+ } catch {
6486
+ toast.error("Couldn't copy the email");
6487
+ return false;
6488
+ }
6489
+ };
6490
+ const peopleView = /* @__PURE__ */ jsxs14(Fragment8, { children: [
6858
6491
  /* @__PURE__ */ jsx17(
6859
6492
  MemberListToolbar,
6860
6493
  {
6861
- activeTab,
6862
- onTabChange: setActiveTab,
6494
+ activeTab: "active",
6495
+ onTabChange: () => {
6496
+ },
6863
6497
  activeLabel: "Members",
6864
6498
  activeCount: filteredMembers.length,
6865
- pendingCount: emailInvites.length,
6866
6499
  searchQuery,
6867
6500
  onSearchChange: setSearchQuery
6868
6501
  }
@@ -6870,47 +6503,31 @@ function OrganizationContent({
6870
6503
  /* @__PURE__ */ jsx17(
6871
6504
  MemberListFrame,
6872
6505
  {
6873
- isEmpty: activeTab === "active" ? filteredMembers.length === 0 : emailInvites.length === 0,
6874
- emptyText: activeTab === "active" ? "No members yet" : "No pending invites",
6506
+ isEmpty: filteredMembers.length === 0,
6507
+ emptyText: "No members yet",
6875
6508
  grow: "fill",
6876
- children: activeTab === "active" ? filteredMembers.map((m) => /* @__PURE__ */ jsx17(MemberRow, { member: m, onClick: () => openUpdateModal(m) }, m._id)) : emailInvites.map((inv) => /* @__PURE__ */ jsx17(
6877
- InviteRow,
6509
+ children: filteredMembers.map((m) => /* @__PURE__ */ jsx17(
6510
+ MemberRow,
6878
6511
  {
6879
- invite: inv,
6880
- onCancel: () => void handleCancelInvite(inv),
6881
- onResend: () => void handleResendInvite(inv)
6512
+ member: m,
6513
+ onEdit: isOrgAdmin ? () => openUpdateModal(m) : void 0,
6514
+ onCopyEmail: () => copyEmail(m.user.email)
6882
6515
  },
6883
- inv._id
6516
+ m._id
6884
6517
  ))
6885
6518
  }
6886
6519
  )
6887
6520
  ] });
6888
- const workspacesView = /* @__PURE__ */ jsx17(
6889
- Section,
6890
- {
6891
- title: "Workspaces in this organization",
6892
- empty: workspaces.length === 0,
6893
- children: workspaces.map((ws) => /* @__PURE__ */ jsx17(WorkspaceRow, { workspace: ws }, ws._id))
6894
- }
6895
- );
6896
- const domainsView = /* @__PURE__ */ jsxs14(Fragment9, { children: [
6521
+ const workspacesView = /* @__PURE__ */ jsxs14(Fragment8, { children: [
6897
6522
  /* @__PURE__ */ jsx17(
6898
6523
  Section,
6899
6524
  {
6900
- title: "Auto-join by email domain",
6901
- empty: domainInvites.length === 0,
6902
- 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.`,
6903
- children: domainInvites.map((inv) => /* @__PURE__ */ jsx17(
6904
- InviteRow,
6905
- {
6906
- invite: inv,
6907
- onCancel: () => void handleCancelInvite(inv)
6908
- },
6909
- inv._id
6910
- ))
6525
+ title: "Workspaces in this organization",
6526
+ empty: workspaces.length === 0,
6527
+ children: workspaces.map((ws) => /* @__PURE__ */ jsx17(WorkspaceRow, { workspace: ws }, ws._id))
6911
6528
  }
6912
6529
  ),
6913
- /* @__PURE__ */ jsx17(
6530
+ (isOrgAdmin || joinRequests.length > 0) && /* @__PURE__ */ jsx17(
6914
6531
  Section,
6915
6532
  {
6916
6533
  title: "Workspaces asking to join",
@@ -6919,37 +6536,29 @@ function OrganizationContent({
6919
6536
  JoinRequestRow,
6920
6537
  {
6921
6538
  request: req,
6922
- onApprove: () => void handleApproveJoinRequest(req),
6923
- onReject: () => void handleRejectJoinRequest(req)
6539
+ onApprove: isOrgAdmin ? () => void handleApproveJoinRequest(req) : void 0,
6540
+ onReject: isOrgAdmin ? () => void handleRejectJoinRequest(req) : void 0
6924
6541
  },
6925
6542
  req._id
6926
6543
  ))
6927
6544
  }
6928
6545
  )
6929
6546
  ] });
6930
- const innerContent = /* @__PURE__ */ jsxs14(Fragment9, { children: [
6547
+ const innerContent = /* @__PURE__ */ jsxs14(Fragment8, { children: [
6931
6548
  scopeHeader,
6932
6549
  loadingData && loadingBlock,
6933
6550
  !loadingData && view === "people" && peopleView,
6934
- !loadingData && view === "workspaces" && workspacesView,
6935
- !loadingData && view === "domains" && domainsView,
6551
+ !loadingData && view !== "people" && workspacesView,
6936
6552
  /* @__PURE__ */ jsx17(
6937
- OrganizationInviteModal,
6553
+ OrganizationMemberModal,
6938
6554
  {
6939
6555
  open: modal.open,
6940
- mode: modal.mode,
6941
6556
  userEmail: modal.target?.user.email,
6942
6557
  initialRole: modal.target?.role === "admin" || modal.target?.role === "member" ? modal.target.role : void 0,
6943
- initialInviteAccess: modal.target?.inviteAccess,
6944
- allowSubmitWithoutChanges: false,
6945
6558
  lockRole: modal.target?.role === "guest",
6946
6559
  lockedRoleLabel: orgRoleLabel(modal.target?.role),
6947
6560
  canRemove: highestRole === "admin",
6948
- canClaimDomain: canClaimEmailDomain,
6949
- claimableDomain: emailDomain,
6950
6561
  onClose: closeModal,
6951
- onInviteEmail: handleInviteEmail,
6952
- onInviteDomain: handleInviteDomain,
6953
6562
  onUpdate: handleUpdateMember,
6954
6563
  onRemove: handleRemoveMember
6955
6564
  }
@@ -6994,34 +6603,20 @@ function OrganizationContent({
6994
6603
  backgroundSize: "24px 24px"
6995
6604
  },
6996
6605
  children: [
6997
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between shrink-0 w-full", children: [
6998
- /* @__PURE__ */ jsx17(
6999
- "p",
7000
- {
7001
- className: "flex-1 min-w-0 truncate",
7002
- style: {
7003
- color: T11.primary,
7004
- fontFamily: T11.font,
7005
- fontSize: "var(--font-size-font-size-xxl)",
7006
- fontWeight: 600,
7007
- lineHeight: "var(--line-height-line-height-xxl)"
7008
- },
7009
- children: current?.name ? `${current.name} \u2014 Organization` : "Organization"
7010
- }
7011
- ),
7012
- /* @__PURE__ */ jsx17(
7013
- ScButton5,
7014
- {
7015
- text: "Invite",
7016
- variant: "primary",
7017
- size: "md",
7018
- styleVariant: "icon-left",
7019
- state: highestRole !== "admin" ? "disabled" : "default",
7020
- icon: /* @__PURE__ */ jsx17(SiconUserAdd2, { className: "w-5 h-5", color: "var(--alias-text---icons-inverse)" }),
7021
- onClick: openInviteModal
7022
- }
7023
- )
7024
- ] }),
6606
+ /* @__PURE__ */ jsx17("div", { className: "flex items-center justify-between shrink-0 w-full", children: /* @__PURE__ */ jsx17(
6607
+ "p",
6608
+ {
6609
+ className: "flex-1 min-w-0 truncate",
6610
+ style: {
6611
+ color: T11.primary,
6612
+ fontFamily: T11.font,
6613
+ fontSize: "var(--font-size-font-size-xxl)",
6614
+ fontWeight: 600,
6615
+ lineHeight: "var(--line-height-line-height-xxl)"
6616
+ },
6617
+ children: current?.name ? `${current.name} \u2014 Organization` : "Organization"
6618
+ }
6619
+ ) }),
7025
6620
  innerContent
7026
6621
  ]
7027
6622
  }
@@ -7955,7 +7550,7 @@ function BuyCreditsModal({
7955
7550
  }
7956
7551
 
7957
7552
  // src/billing-content.tsx
7958
- import { Fragment as Fragment10, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
7553
+ import { Fragment as Fragment9, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
7959
7554
  var DEFAULT_TOPUP_SERVICE = "catalogix";
7960
7555
  var PRIMARY_COLOR2 = "var(--alias-text---icons-primary)";
7961
7556
  var MUTED_COLOR = "var(--alias-text---icons-muted)";
@@ -9519,7 +9114,7 @@ function BillingContent({
9519
9114
  if (embedded) return plansView;
9520
9115
  return /* @__PURE__ */ jsx20("div", { className: "flex-1 h-full min-h-0 min-w-0 relative", children: plansView });
9521
9116
  }
9522
- const billingInnerContent = /* @__PURE__ */ jsxs17(Fragment10, { children: [
9117
+ const billingInnerContent = /* @__PURE__ */ jsxs17(Fragment9, { children: [
9523
9118
  /* @__PURE__ */ jsxs17(
9524
9119
  "div",
9525
9120
  {
@@ -9718,7 +9313,7 @@ import {
9718
9313
  SiconPlus as SiconPlus2,
9719
9314
  SiconClose as SiconClose7
9720
9315
  } from "@streamoid/icons";
9721
- import { Fragment as Fragment11, jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
9316
+ import { Fragment as Fragment10, jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
9722
9317
  var EXPIRY_OPTIONS = [
9723
9318
  { label: "30 days", value: "30d" },
9724
9319
  { label: "60 days", value: "60d" },
@@ -10150,7 +9745,7 @@ function TokensContent({
10150
9745
  setCreatedToken(token);
10151
9746
  fetchTokens();
10152
9747
  }
10153
- const tokensInnerContent = /* @__PURE__ */ jsxs18(Fragment11, { children: [
9748
+ const tokensInnerContent = /* @__PURE__ */ jsxs18(Fragment10, { children: [
10154
9749
  !embedded && /* @__PURE__ */ jsxs18(
10155
9750
  "div",
10156
9751
  {
@@ -10502,7 +10097,7 @@ function TokenTable({ tokens, deletingId, onRevoke, onDelete }) {
10502
10097
  }
10503
10098
 
10504
10099
  // src/settings-content.tsx
10505
- import { Fragment as Fragment12, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
10100
+ import { Fragment as Fragment11, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
10506
10101
  function deriveInitials(name) {
10507
10102
  return name.split(/\s+/).slice(0, 2).map((part) => part[0]?.toUpperCase() ?? "").join("") || "WS";
10508
10103
  }
@@ -10608,20 +10203,19 @@ function SettingsNav({
10608
10203
  /* @__PURE__ */ jsx22(ScHDivider, {}),
10609
10204
  /* @__PURE__ */ jsxs19("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: [
10610
10205
  /* @__PURE__ */ jsx22("div", { title: workspaceName ?? void 0, style: { padding: "4px 12px", fontSize: 11, fontWeight: 500, color: MUTED_COLOR2, textTransform: "uppercase", letterSpacing: "0.08em" }, children: "Workspace" }),
10611
- item("workspace", (color) => /* @__PURE__ */ jsx22(SiconSettings, { className: "w-5 h-5", color })),
10206
+ item("workspace", (color) => /* @__PURE__ */ jsx22(SiconSettings2, { className: "w-5 h-5", color })),
10612
10207
  item("workspaceMembers", (color) => /* @__PURE__ */ jsx22(SiconTeam, { className: "w-5 h-5", color })),
10613
- isWorkspaceAdmin && /* @__PURE__ */ jsxs19(Fragment12, { children: [
10208
+ isWorkspaceAdmin && /* @__PURE__ */ jsxs19(Fragment11, { children: [
10614
10209
  item("billing", (color) => /* @__PURE__ */ jsx22(SiconBilling, { className: "w-5 h-5", color })),
10615
10210
  item("apikey", (color) => /* @__PURE__ */ jsx22(SiconKey_default, { className: "w-5 h-5", color }))
10616
10211
  ] }),
10617
10212
  !isWorkspaceAdmin && /* @__PURE__ */ jsx22("p", { style: { margin: "4px 12px", fontSize: 12, lineHeight: "18px", color: MUTED_COLOR2 }, children: "Contact your workspace admin for credit top-ups and billing history." })
10618
10213
  ] }),
10619
10214
  /* @__PURE__ */ jsx22(ScHDivider, {}),
10620
- /* @__PURE__ */ jsx22("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: hasOrganization ? /* @__PURE__ */ jsxs19(Fragment12, { children: [
10215
+ /* @__PURE__ */ jsx22("div", { className: "flex flex-col w-full", style: { gap: "var(--spacing-md)" }, children: hasOrganization ? /* @__PURE__ */ jsxs19(Fragment11, { children: [
10621
10216
  /* @__PURE__ */ jsx22("div", { style: { padding: "4px 12px", fontSize: 11, fontWeight: 500, color: MUTED_COLOR2, textTransform: "uppercase", letterSpacing: "0.08em" }, children: "Organization" }),
10622
10217
  item("organization", (color) => /* @__PURE__ */ jsx22(SiconTeam, { className: "w-5 h-5", color })),
10623
- item("organizationWorkspaces", (color) => /* @__PURE__ */ jsx22(SiconWorkspace2, { className: "w-5 h-5", color })),
10624
- item("organizationDomains", (color) => /* @__PURE__ */ jsx22(SiconLock, { className: "w-5 h-5", color }))
10218
+ item("organizationWorkspaces", (color) => /* @__PURE__ */ jsx22(SiconWorkspace2, { className: "w-5 h-5", color }))
10625
10219
  ] }) : /* @__PURE__ */ jsx22(
10626
10220
  SettingsNavItem,
10627
10221
  {
@@ -10916,7 +10510,7 @@ function LanguageDropdown({
10916
10510
  ScMenuOptions,
10917
10511
  {
10918
10512
  text: lang.label,
10919
- icon: /* @__PURE__ */ jsx22(Fragment12, {}),
10513
+ icon: /* @__PURE__ */ jsx22(Fragment11, {}),
10920
10514
  hover: isActive ? "true" : "false",
10921
10515
  variant: "default",
10922
10516
  role: "option",
@@ -11306,16 +10900,49 @@ function ProfileTab() {
11306
10900
  }
11307
10901
  );
11308
10902
  }
10903
+ var WORKSPACE_LIST_PAGE_SIZE = 10;
11309
10904
  function WorkspaceListTab({
11310
10905
  workspaces,
11311
10906
  loading,
11312
10907
  onCreateClick: _onCreateClick,
11313
10908
  onEditClick,
11314
10909
  onSwitchClick,
11315
- onLeaveClick
10910
+ onLeaveClick,
10911
+ fetchPlans,
10912
+ pageSize = WORKSPACE_LIST_PAGE_SIZE
11316
10913
  }) {
11317
10914
  const currentWorkspace = workspaces.find((ws) => ws.isCurrent);
11318
10915
  const otherWorkspaces = workspaces.filter((ws) => !ws.isCurrent);
10916
+ const pageCount = Math.max(1, Math.ceil(otherWorkspaces.length / pageSize));
10917
+ const [page, setPage] = useState15(0);
10918
+ const safePage = Math.min(page, pageCount - 1);
10919
+ const pageStart = safePage * pageSize;
10920
+ const pageWorkspaces = otherWorkspaces.slice(pageStart, pageStart + pageSize);
10921
+ const [plans, setPlans] = useState15({});
10922
+ const requestedPlans = useRef7(/* @__PURE__ */ new Set());
10923
+ const visibleIds = [
10924
+ ...currentWorkspace ? [currentWorkspace._id] : [],
10925
+ ...pageWorkspaces.map((ws) => ws._id)
10926
+ ];
10927
+ const visibleKey = visibleIds.join(",");
10928
+ const mounted = useRef7(true);
10929
+ useEffect13(() => {
10930
+ mounted.current = true;
10931
+ return () => {
10932
+ mounted.current = false;
10933
+ };
10934
+ }, []);
10935
+ useEffect13(() => {
10936
+ if (!fetchPlans || loading) return;
10937
+ const missing = visibleKey.split(",").filter((id) => id && !requestedPlans.current.has(id));
10938
+ if (!missing.length) return;
10939
+ missing.forEach((id) => requestedPlans.current.add(id));
10940
+ fetchPlans(missing).then((found) => {
10941
+ if (mounted.current) setPlans((prev) => ({ ...prev, ...found }));
10942
+ }).catch(() => {
10943
+ });
10944
+ }, [fetchPlans, loading, visibleKey]);
10945
+ const planOf = (ws) => fetchPlans ? plans[ws._id] ?? "" : ws.plan ?? "";
11319
10946
  return /* @__PURE__ */ jsxs19(
11320
10947
  "div",
11321
10948
  {
@@ -11373,7 +11000,7 @@ function WorkspaceListTab({
11373
11000
  initials: currentWorkspace.initials,
11374
11001
  imageUrl: currentWorkspace.imageUrl,
11375
11002
  role: currentWorkspace.role,
11376
- plan: currentWorkspace.plan,
11003
+ plan: planOf(currentWorkspace),
11377
11004
  ownerId: currentWorkspace.ownerEmail,
11378
11005
  type: "currentWS",
11379
11006
  onSettings: () => onEditClick(currentWorkspace),
@@ -11418,14 +11045,14 @@ function WorkspaceListTab({
11418
11045
  {
11419
11046
  className: "flex flex-col items-start w-full",
11420
11047
  style: { gap: 16 },
11421
- children: otherWorkspaces.map((ws) => /* @__PURE__ */ jsx22(
11048
+ children: pageWorkspaces.map((ws) => /* @__PURE__ */ jsx22(
11422
11049
  ScWorkspaceSwitchCard,
11423
11050
  {
11424
11051
  wsName: ws.name,
11425
11052
  initials: ws.initials,
11426
11053
  imageUrl: ws.imageUrl,
11427
11054
  role: ws.role,
11428
- plan: ws.plan,
11055
+ plan: planOf(ws),
11429
11056
  ownerId: ws.ownerEmail,
11430
11057
  type: "otherWS",
11431
11058
  onSwitch: () => onSwitchClick(ws),
@@ -11435,6 +11062,56 @@ function WorkspaceListTab({
11435
11062
  ws._id
11436
11063
  ))
11437
11064
  }
11065
+ ),
11066
+ pageCount > 1 && /* @__PURE__ */ jsxs19(
11067
+ "div",
11068
+ {
11069
+ className: "flex items-center justify-between shrink-0 w-full",
11070
+ style: { gap: "var(--spacing-md)" },
11071
+ children: [
11072
+ /* @__PURE__ */ jsxs19(
11073
+ "span",
11074
+ {
11075
+ style: {
11076
+ color: "var(--alias-text---icons-muted)",
11077
+ fontFamily: "var(--font-family-font-family-body)",
11078
+ fontSize: "var(--font-size-font-size-sm)",
11079
+ lineHeight: "var(--line-height-line-height-sm)"
11080
+ },
11081
+ children: [
11082
+ pageStart + 1,
11083
+ "\u2013",
11084
+ pageStart + pageWorkspaces.length,
11085
+ " of",
11086
+ " ",
11087
+ otherWorkspaces.length
11088
+ ]
11089
+ }
11090
+ ),
11091
+ /* @__PURE__ */ jsxs19("div", { className: "flex items-center", style: { gap: "var(--spacing-md)" }, children: [
11092
+ /* @__PURE__ */ jsx22(
11093
+ ScButton7,
11094
+ {
11095
+ text: "Previous",
11096
+ variant: "tertiary",
11097
+ size: "sm",
11098
+ state: safePage === 0 ? "disabled" : "default",
11099
+ onClick: safePage === 0 ? void 0 : () => setPage(safePage - 1)
11100
+ }
11101
+ ),
11102
+ /* @__PURE__ */ jsx22(
11103
+ ScButton7,
11104
+ {
11105
+ text: "Next",
11106
+ variant: "tertiary",
11107
+ size: "sm",
11108
+ state: safePage >= pageCount - 1 ? "disabled" : "default",
11109
+ onClick: safePage >= pageCount - 1 ? void 0 : () => setPage(safePage + 1)
11110
+ }
11111
+ )
11112
+ ] })
11113
+ ]
11114
+ }
11438
11115
  )
11439
11116
  ]
11440
11117
  }
@@ -11593,7 +11270,6 @@ function SettingsContentInner({
11593
11270
  const [creatingWorkspace, setCreatingWorkspace] = useState15(false);
11594
11271
  const [updatingWorkspace, setUpdatingWorkspace] = useState15(false);
11595
11272
  const [teamInviteOpen, setTeamInviteOpen] = useState15(false);
11596
- const [organizationInviteOpen, setOrganizationInviteOpen] = useState15(false);
11597
11273
  const [tokenShowRevoked, setTokenShowRevoked] = useState15(false);
11598
11274
  const [tokenCreateOpen, setTokenCreateOpen] = useState15(false);
11599
11275
  const [billingShowPlans, setBillingShowPlans] = useState15(false);
@@ -11955,7 +11631,7 @@ function SettingsContentInner({
11955
11631
  },
11956
11632
  children: [
11957
11633
  /* @__PURE__ */ jsxs19("div", { className: "flex items-center flex-1 min-w-0", style: { gap: 8, paddingLeft: 20 }, children: [
11958
- /* @__PURE__ */ jsx22(SiconSettings, { className: "w-6 h-6 shrink-0", color: "var(--alias-text---icons-primary)" }),
11634
+ /* @__PURE__ */ jsx22(SiconSettings2, { className: "w-6 h-6 shrink-0", color: "var(--alias-text---icons-primary)" }),
11959
11635
  /* @__PURE__ */ jsx22(
11960
11636
  "span",
11961
11637
  {
@@ -11969,7 +11645,7 @@ function SettingsContentInner({
11969
11645
  children: "Settings"
11970
11646
  }
11971
11647
  ),
11972
- scopeCrumb && /* @__PURE__ */ jsxs19(Fragment12, { children: [
11648
+ scopeCrumb && /* @__PURE__ */ jsxs19(Fragment11, { children: [
11973
11649
  /* @__PURE__ */ jsx22(SiconRight2, { className: "w-6 h-6 shrink-0", color: "var(--alias-text---icons-primary)" }),
11974
11650
  /* @__PURE__ */ jsx22(
11975
11651
  "span",
@@ -12002,7 +11678,7 @@ function SettingsContentInner({
12002
11678
  children: leafLabel
12003
11679
  }
12004
11680
  ),
12005
- isBillingPlans && /* @__PURE__ */ jsxs19(Fragment12, { children: [
11681
+ isBillingPlans && /* @__PURE__ */ jsxs19(Fragment11, { children: [
12006
11682
  /* @__PURE__ */ jsx22(SiconRight2, { className: "w-6 h-6 shrink-0", color: "var(--alias-text---icons-primary)" }),
12007
11683
  /* @__PURE__ */ jsx22(
12008
11684
  "span",
@@ -12089,7 +11765,7 @@ function SettingsContentInner({
12089
11765
  size: "md",
12090
11766
  styleVariant: "icon-left",
12091
11767
  icon: /* @__PURE__ */ jsx22(
12092
- SiconUserAdd3,
11768
+ SiconUserAdd2,
12093
11769
  {
12094
11770
  className: "w-5 h-5",
12095
11771
  color: "var(--alias-text---icons-inverse)"
@@ -12100,31 +11776,6 @@ function SettingsContentInner({
12100
11776
  )
12101
11777
  }
12102
11778
  ),
12103
- activeTab === "organization" && hasOrganization && /* @__PURE__ */ jsx22(
12104
- SettingsTooltip,
12105
- {
12106
- content: "Invite someone into your organization",
12107
- placement: "bottom",
12108
- inline: true,
12109
- children: /* @__PURE__ */ jsx22(
12110
- ScButton7,
12111
- {
12112
- text: "Invite",
12113
- variant: "secondary",
12114
- size: "md",
12115
- styleVariant: "icon-left",
12116
- icon: /* @__PURE__ */ jsx22(
12117
- SiconUserAdd3,
12118
- {
12119
- className: "w-5 h-5",
12120
- color: "var(--alias-text---icons-inverse)"
12121
- }
12122
- ),
12123
- onClick: () => setOrganizationInviteOpen(true)
12124
- }
12125
- )
12126
- }
12127
- ),
12128
11779
  activeTab === "apikey" && isWorkspaceAdmin && /* @__PURE__ */ jsxs19("div", { className: "flex items-center shrink-0", style: { gap: "var(--spacing-md)" }, children: [
12129
11780
  /* @__PURE__ */ jsx22(
12130
11781
  SettingsTooltip,
@@ -12254,6 +11905,7 @@ function SettingsContentInner({
12254
11905
  {
12255
11906
  workspaces: displayWorkspaces,
12256
11907
  loading: workspaceListLoading && workspaceList.length === 0,
11908
+ fetchPlans: workspace.fetchPlans,
12257
11909
  onCreateClick: handleCreateClick,
12258
11910
  onEditClick: handleEditClick,
12259
11911
  onSwitchClick: async (ws) => {
@@ -12283,9 +11935,7 @@ function SettingsContentInner({
12283
11935
  OrganizationContent,
12284
11936
  {
12285
11937
  embedded: true,
12286
- view: activeTab === "organizationWorkspaces" ? "workspaces" : activeTab === "organizationDomains" ? "domains" : "people",
12287
- onInviteOpen: organizationInviteOpen,
12288
- onInviteOpenChange: setOrganizationInviteOpen
11938
+ view: activeTab === "organizationWorkspaces" || activeTab === "organizationDomains" ? "workspaces" : "people"
12289
11939
  }
12290
11940
  ) }),
12291
11941
  activeTab === "billing" && isWorkspaceAdmin && /* @__PURE__ */ jsx22("div", { className: "flex flex-col flex-1 min-w-0 min-h-0 h-full", children: /* @__PURE__ */ jsx22(
@@ -12423,6 +12073,249 @@ function SettingsContentInner({
12423
12073
  }
12424
12074
  );
12425
12075
  }
12076
+
12077
+ // src/workspace-picker.tsx
12078
+ import { useState as useState16 } from "react";
12079
+ import { ScButton as ScButton8, ScCheckbox } from "@streamoid/ui";
12080
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
12081
+ var T13 = {
12082
+ primary: "var(--alias-text---icons-primary)",
12083
+ muted: "var(--alias-text---icons-muted)",
12084
+ tertiary: "var(--alias-text---icons-tertiary)",
12085
+ surface: "var(--alias-surface-base)",
12086
+ fillPlus: "var(--alias-fill-neutral-neutralplus)",
12087
+ borderSubtle: "var(--alias-border-subtle)",
12088
+ font: "var(--font-family-font-family-body)",
12089
+ fsXs: "var(--font-size-font-size-xs)",
12090
+ fsSm: "var(--font-size-font-size-sm)",
12091
+ fsXl: "var(--font-size-font-size-xl)",
12092
+ lhXs: "var(--line-height-line-height-xs)",
12093
+ lhSm: "var(--line-height-line-height-sm)",
12094
+ lhXl: "var(--line-height-line-height-xl)",
12095
+ spXs: "var(--spacing-xs)",
12096
+ spMd: "var(--spacing-md)",
12097
+ spXl: "var(--spacing-xl)",
12098
+ sp3xl: "var(--spacing-3xl)",
12099
+ sp5xl: "var(--spacing-5xl)",
12100
+ sp6xl: "var(--spacing-6xl)",
12101
+ rLg: "var(--radius-lg)",
12102
+ r3xl: "var(--radius-3xl)"
12103
+ };
12104
+ function WorkspacePicker({
12105
+ organizationName,
12106
+ workspaces,
12107
+ loading = false,
12108
+ onJoin,
12109
+ onCreate
12110
+ }) {
12111
+ const [selected, setSelected] = useState16(/* @__PURE__ */ new Set());
12112
+ const [creating, setCreating] = useState16(false);
12113
+ const [name, setName] = useState16("");
12114
+ const [busy, setBusy] = useState16(false);
12115
+ const hasWorkspaces = workspaces.length > 0;
12116
+ const showCreate = creating || !loading && !hasWorkspaces;
12117
+ const orgLabel = organizationName || "your organization";
12118
+ const toggle = (id) => setSelected((prev) => {
12119
+ const next = new Set(prev);
12120
+ if (next.has(id)) next.delete(id);
12121
+ else next.add(id);
12122
+ return next;
12123
+ });
12124
+ const run = async (action) => {
12125
+ setBusy(true);
12126
+ try {
12127
+ await action();
12128
+ } catch {
12129
+ } finally {
12130
+ setBusy(false);
12131
+ }
12132
+ };
12133
+ return /* @__PURE__ */ jsxs20(
12134
+ "div",
12135
+ {
12136
+ className: "flex flex-col w-full",
12137
+ style: { maxWidth: 520, gap: T13.sp5xl, fontFamily: T13.font },
12138
+ children: [
12139
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col", style: { gap: T13.spMd }, children: [
12140
+ /* @__PURE__ */ jsx23(
12141
+ "p",
12142
+ {
12143
+ style: {
12144
+ color: T13.primary,
12145
+ fontSize: T13.fsXl,
12146
+ fontWeight: 600,
12147
+ lineHeight: T13.lhXl,
12148
+ margin: 0
12149
+ },
12150
+ children: "Choose your workspaces"
12151
+ }
12152
+ ),
12153
+ /* @__PURE__ */ jsx23("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.` })
12154
+ ] }),
12155
+ (loading || hasWorkspaces) && /* @__PURE__ */ jsx23(
12156
+ "div",
12157
+ {
12158
+ className: "flex flex-col w-full overflow-y-auto",
12159
+ style: {
12160
+ maxHeight: 360,
12161
+ background: T13.surface,
12162
+ border: `1px solid ${T13.borderSubtle}`,
12163
+ borderRadius: T13.r3xl
12164
+ },
12165
+ children: loading ? /* @__PURE__ */ jsx23(
12166
+ "div",
12167
+ {
12168
+ className: "flex items-center justify-center",
12169
+ style: { padding: T13.sp6xl, color: T13.muted, fontSize: T13.fsSm },
12170
+ children: "Loading workspaces\u2026"
12171
+ }
12172
+ ) : workspaces.map((workspace, index) => {
12173
+ const checked = selected.has(workspace._id);
12174
+ return /* @__PURE__ */ jsxs20(
12175
+ "div",
12176
+ {
12177
+ role: "checkbox",
12178
+ "aria-checked": checked,
12179
+ tabIndex: 0,
12180
+ className: "flex items-center cursor-pointer",
12181
+ style: {
12182
+ gap: T13.spXl,
12183
+ padding: `${T13.spXl} ${T13.sp3xl}`,
12184
+ borderTop: index ? `1px solid ${T13.borderSubtle}` : "none"
12185
+ },
12186
+ onClick: () => toggle(workspace._id),
12187
+ onKeyDown: (e) => {
12188
+ if (e.key === " " || e.key === "Enter") {
12189
+ e.preventDefault();
12190
+ toggle(workspace._id);
12191
+ }
12192
+ },
12193
+ children: [
12194
+ /* @__PURE__ */ jsx23(ScCheckbox, { checked }),
12195
+ /* @__PURE__ */ jsx23(
12196
+ ProfileAvatar,
12197
+ {
12198
+ name: workspace.name,
12199
+ profileImage: workspace.imageUrl,
12200
+ size: 32,
12201
+ borderRadius: T13.rLg
12202
+ }
12203
+ ),
12204
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-col min-w-0", children: [
12205
+ /* @__PURE__ */ jsx23(
12206
+ "span",
12207
+ {
12208
+ className: "truncate",
12209
+ style: {
12210
+ color: T13.primary,
12211
+ fontSize: T13.fsSm,
12212
+ fontWeight: 500,
12213
+ lineHeight: T13.lhSm
12214
+ },
12215
+ children: workspace.name
12216
+ }
12217
+ ),
12218
+ workspace.ownerName && /* @__PURE__ */ jsxs20(
12219
+ "span",
12220
+ {
12221
+ className: "truncate",
12222
+ style: { color: T13.muted, fontSize: T13.fsXs, lineHeight: T13.lhXs },
12223
+ children: [
12224
+ "Created by ",
12225
+ workspace.ownerName
12226
+ ]
12227
+ }
12228
+ )
12229
+ ] })
12230
+ ]
12231
+ },
12232
+ workspace._id
12233
+ );
12234
+ })
12235
+ }
12236
+ ),
12237
+ showCreate ? /* @__PURE__ */ jsxs20("div", { className: "flex flex-col w-full", style: { gap: T13.spMd }, children: [
12238
+ /* @__PURE__ */ jsx23(
12239
+ "label",
12240
+ {
12241
+ htmlFor: "workspace-picker-name",
12242
+ style: { color: T13.tertiary, fontSize: T13.fsSm, lineHeight: T13.lhSm },
12243
+ children: "New workspace name"
12244
+ }
12245
+ ),
12246
+ /* @__PURE__ */ jsx23(
12247
+ "input",
12248
+ {
12249
+ id: "workspace-picker-name",
12250
+ autoFocus: true,
12251
+ value: name,
12252
+ onChange: (e) => setName(e.target.value),
12253
+ onKeyDown: (e) => {
12254
+ if (e.key === "Enter" && name.trim() && !busy) {
12255
+ void run(() => onCreate(name.trim()));
12256
+ }
12257
+ },
12258
+ placeholder: "e.g. Marketing",
12259
+ style: {
12260
+ height: 48,
12261
+ padding: `0 ${T13.sp3xl}`,
12262
+ background: T13.fillPlus,
12263
+ border: "none",
12264
+ outline: "none",
12265
+ borderRadius: T13.r3xl,
12266
+ color: T13.primary,
12267
+ fontFamily: T13.font,
12268
+ fontSize: T13.fsSm
12269
+ }
12270
+ }
12271
+ ),
12272
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-end w-full", style: { gap: T13.spMd }, children: [
12273
+ hasWorkspaces && /* @__PURE__ */ jsx23(
12274
+ ScButton8,
12275
+ {
12276
+ text: "Back",
12277
+ variant: "tertiary",
12278
+ size: "md",
12279
+ onClick: () => setCreating(false)
12280
+ }
12281
+ ),
12282
+ /* @__PURE__ */ jsx23(
12283
+ ScButton8,
12284
+ {
12285
+ text: busy ? "Creating\u2026" : "Create workspace",
12286
+ variant: "primary",
12287
+ size: "md",
12288
+ state: !name.trim() || busy ? "disabled" : "default",
12289
+ onClick: name.trim() && !busy ? () => void run(() => onCreate(name.trim())) : void 0
12290
+ }
12291
+ )
12292
+ ] })
12293
+ ] }) : /* @__PURE__ */ jsxs20("div", { className: "flex flex-wrap items-center justify-between w-full", style: { gap: T13.spMd }, children: [
12294
+ /* @__PURE__ */ jsx23(
12295
+ ScButton8,
12296
+ {
12297
+ text: "Create a workspace",
12298
+ variant: "tertiary",
12299
+ size: "md",
12300
+ state: loading || busy ? "disabled" : "default",
12301
+ onClick: loading || busy ? void 0 : () => setCreating(true)
12302
+ }
12303
+ ),
12304
+ /* @__PURE__ */ jsx23(
12305
+ ScButton8,
12306
+ {
12307
+ text: busy ? "Joining\u2026" : selected.size > 1 ? `Join ${selected.size} workspaces` : "Join workspace",
12308
+ variant: "primary",
12309
+ size: "md",
12310
+ state: !selected.size || busy ? "disabled" : "default",
12311
+ onClick: selected.size && !busy ? () => void run(() => onJoin([...selected])) : void 0
12312
+ }
12313
+ )
12314
+ ] })
12315
+ ]
12316
+ }
12317
+ );
12318
+ }
12426
12319
  export {
12427
12320
  APP_KEYS,
12428
12321
  BillingContent,
@@ -12436,7 +12329,7 @@ export {
12436
12329
  MemberListFrame,
12437
12330
  MemberListToolbar,
12438
12331
  OrganizationContent,
12439
- OrganizationInviteModal,
12332
+ OrganizationMemberModal,
12440
12333
  OrganizationModal,
12441
12334
  ProfileAvatar,
12442
12335
  ProfileTab,
@@ -12455,9 +12348,11 @@ export {
12455
12348
  TokensContent,
12456
12349
  URL_TO_TAB,
12457
12350
  USER_LANGUAGES,
12351
+ WORKSPACE_LIST_PAGE_SIZE,
12458
12352
  WorkspaceGeneralTab,
12459
12353
  WorkspaceListTab,
12460
12354
  WorkspaceModal,
12355
+ WorkspacePicker,
12461
12356
  WorkspaceTab,
12462
12357
  countLabel,
12463
12358
  loadWorkspaceOrganization,