@stackframe/stack 2.5.35 → 2.5.37

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/elements/sidebar-layout.js +15 -7
  3. package/dist/components/elements/sidebar-layout.js.map +1 -1
  4. package/dist/components/elements/user-avatar.js +1 -1
  5. package/dist/components/elements/user-avatar.js.map +1 -1
  6. package/dist/components/oauth-button.js +19 -21
  7. package/dist/components/oauth-button.js.map +1 -1
  8. package/dist/components/profile-image-editor.js +2 -2
  9. package/dist/components/profile-image-editor.js.map +1 -1
  10. package/dist/components/selected-team-switcher.js +1 -1
  11. package/dist/components/selected-team-switcher.js.map +1 -1
  12. package/dist/components-page/account-settings.d.mts +4 -2
  13. package/dist/components-page/account-settings.d.ts +4 -2
  14. package/dist/components-page/account-settings.js +356 -184
  15. package/dist/components-page/account-settings.js.map +1 -1
  16. package/dist/components-page/oauth-callback.js +1 -1
  17. package/dist/components-page/oauth-callback.js.map +1 -1
  18. package/dist/components-page/stack-handler.d.mts +1 -0
  19. package/dist/components-page/stack-handler.d.ts +1 -0
  20. package/dist/esm/components/elements/sidebar-layout.js +15 -7
  21. package/dist/esm/components/elements/sidebar-layout.js.map +1 -1
  22. package/dist/esm/components/elements/user-avatar.js +1 -1
  23. package/dist/esm/components/elements/user-avatar.js.map +1 -1
  24. package/dist/esm/components/oauth-button.js +19 -21
  25. package/dist/esm/components/oauth-button.js.map +1 -1
  26. package/dist/esm/components/profile-image-editor.js +2 -2
  27. package/dist/esm/components/profile-image-editor.js.map +1 -1
  28. package/dist/esm/components/selected-team-switcher.js +1 -1
  29. package/dist/esm/components/selected-team-switcher.js.map +1 -1
  30. package/dist/esm/components-page/account-settings.js +356 -185
  31. package/dist/esm/components-page/account-settings.js.map +1 -1
  32. package/dist/esm/components-page/oauth-callback.js +1 -1
  33. package/dist/esm/components-page/oauth-callback.js.map +1 -1
  34. package/dist/esm/generated/global-css.js +1 -1
  35. package/dist/esm/generated/global-css.js.map +1 -1
  36. package/dist/esm/generated/quetzal-translations.js +1555 -1351
  37. package/dist/esm/generated/quetzal-translations.js.map +1 -1
  38. package/dist/esm/lib/stack-app.js +8 -1
  39. package/dist/esm/lib/stack-app.js.map +1 -1
  40. package/dist/esm/utils/browser-script.js +10 -7
  41. package/dist/esm/utils/browser-script.js.map +1 -1
  42. package/dist/generated/global-css.d.mts +1 -1
  43. package/dist/generated/global-css.d.ts +1 -1
  44. package/dist/generated/global-css.js +1 -1
  45. package/dist/generated/global-css.js.map +1 -1
  46. package/dist/generated/quetzal-translations.d.mts +2 -2
  47. package/dist/generated/quetzal-translations.d.ts +2 -2
  48. package/dist/generated/quetzal-translations.js +1555 -1351
  49. package/dist/generated/quetzal-translations.js.map +1 -1
  50. package/dist/lib/stack-app.d.mts +4 -1
  51. package/dist/lib/stack-app.d.ts +4 -1
  52. package/dist/lib/stack-app.js +8 -1
  53. package/dist/lib/stack-app.js.map +1 -1
  54. package/dist/utils/browser-script.js +10 -7
  55. package/dist/utils/browser-script.js.map +1 -1
  56. package/package.json +4 -4
@@ -33,7 +33,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  var account_settings_exports = {};
34
34
  __export(account_settings_exports, {
35
35
  AccountSettings: () => AccountSettings,
36
- TeamCreation: () => TeamCreation
36
+ TeamCreation: () => TeamCreation,
37
+ useDeleteAccountSection: () => useDeleteAccountSection
37
38
  });
38
39
  module.exports = __toCommonJS(account_settings_exports);
39
40
  var import_yup = require("@hookform/resolvers/yup");
@@ -47,16 +48,16 @@ var import_stack_ui = require("@stackframe/stack-ui");
47
48
  var import_lucide_react = require("lucide-react");
48
49
  var import_otp = require("oslo/otp");
49
50
  var QRCode = __toESM(require("qrcode"));
50
- var import_react = require("react");
51
+ var import_react = __toESM(require("react"));
51
52
  var import_react_hook_form = require("react-hook-form");
52
53
  var yup = __toESM(require("yup"));
53
54
  var import__ = require("..");
54
55
  var import_form_warning = require("../components/elements/form-warning");
56
+ var import_maybe_full_page = require("../components/elements/maybe-full-page");
55
57
  var import_sidebar_layout = require("../components/elements/sidebar-layout");
56
58
  var import_user_avatar = require("../components/elements/user-avatar");
57
59
  var import_profile_image_editor = require("../components/profile-image-editor");
58
60
  var import_team_icon = require("../components/team-icon");
59
- var import_maybe_full_page = require("../components/elements/maybe-full-page");
60
61
  var import_translations = require("../lib/translations");
61
62
  var import_jsx_runtime = require("react/jsx-runtime");
62
63
  function AccountSettings(props) {
@@ -74,25 +75,21 @@ function AccountSettings(props) {
74
75
  type: "item",
75
76
  subpath: "/profile",
76
77
  icon: import_lucide_react.Contact,
77
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfileSection, {})
78
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfilePage, {})
78
79
  },
79
80
  {
80
81
  title: t("Security"),
81
82
  type: "item",
82
- icon: import_lucide_react.ShieldCheck,
83
83
  subpath: "/security",
84
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
85
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmailVerificationSection, {}),
86
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PasswordSection, {}),
87
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MfaSection, {})
88
- ] })
84
+ icon: import_lucide_react.ShieldCheck,
85
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SecurityPage, {})
89
86
  },
90
87
  {
91
- title: t("Sign Out"),
92
- subpath: "/sign-out",
88
+ title: t("Settings"),
93
89
  type: "item",
94
- icon: import_lucide_react.LogOut,
95
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SignOutSection, {})
90
+ subpath: "/settings",
91
+ icon: import_lucide_react.Settings,
92
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingsPage, {})
96
93
  },
97
94
  ...props.extraItems?.map((item) => ({
98
95
  title: item.title,
@@ -112,13 +109,7 @@ function AccountSettings(props) {
112
109
  ] }),
113
110
  type: "item",
114
111
  subpath: `/teams/${team.id}`,
115
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
116
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfileSettings, { team }),
117
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ManagementSettings, { team }),
118
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberInvitation, { team }),
119
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MembersSettings, { team }),
120
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserSettings, { team })
121
- ] })
112
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPage, { team })
122
113
  })),
123
114
  ...project.config.clientTeamCreationEnabled ? [{
124
115
  title: t("Create a team"),
@@ -133,42 +124,93 @@ function AccountSettings(props) {
133
124
  }
134
125
  ) }) });
135
126
  }
136
- function ProfileSection() {
127
+ function Section(props) {
128
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex", children: [
129
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 flex flex-col justify-center", children: [
130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { className: "font-medium", children: props.title }),
131
+ props.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", type: "footnote", children: props.description })
132
+ ] }),
133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex-1 flex flex-col gap-2", children: props.children })
134
+ ] });
135
+ }
136
+ function PageLayout(props) {
137
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-6", children: [
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Separator, {}),
139
+ import_react.default.Children.map(props.children, (child) => child && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
140
+ child,
141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Separator, {})
142
+ ] }))
143
+ ] });
144
+ }
145
+ function ProfilePage() {
137
146
  const { t } = (0, import_translations.useTranslation)();
138
147
  const user = (0, import__.useUser)({ or: "redirect" });
139
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
140
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-start", children: [
141
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { className: "mb-2", children: t("Profile image") }),
142
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
143
- import_profile_image_editor.ProfileImageEditor,
144
- {
145
- user,
146
- onProfileImageUrlChange: async (profileImageUrl) => {
147
- await user.update({ profileImageUrl });
148
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
150
+ Section,
151
+ {
152
+ title: t("User name"),
153
+ description: t("This is a display name and is not used for authentication"),
154
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
155
+ import_stack_ui.EditableText,
156
+ {
157
+ value: user.displayName || "",
158
+ onSave: async (newDisplayName) => {
159
+ await user.update({ displayName: newDisplayName });
160
+ }
148
161
  }
149
- }
150
- )
151
- ] }),
152
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
153
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Display name") }),
154
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.EditableText, { value: user.displayName || "", onSave: async (newDisplayName) => {
155
- await user.update({ displayName: newDisplayName });
156
- } })
157
- ] })
162
+ )
163
+ }
164
+ ),
165
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
166
+ Section,
167
+ {
168
+ title: t("Profile image"),
169
+ description: t("Upload your own image as your avatar"),
170
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
171
+ import_profile_image_editor.ProfileImageEditor,
172
+ {
173
+ user,
174
+ onProfileImageUrlChange: async (profileImageUrl) => {
175
+ await user.update({ profileImageUrl });
176
+ }
177
+ }
178
+ )
179
+ }
180
+ )
158
181
  ] });
159
182
  }
160
- function EmailVerificationSection() {
183
+ function SecurityPage() {
184
+ const emailVerificationSection = useEmailVerificationSection();
185
+ const passwordSection = usePasswordSection();
186
+ const mfaSection = useMfaSection();
187
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
188
+ emailVerificationSection,
189
+ passwordSection,
190
+ mfaSection
191
+ ] });
192
+ }
193
+ function SettingsPage() {
194
+ const deleteAccountSection = useDeleteAccountSection();
195
+ const signOutSection = useSignOutSection();
196
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
197
+ deleteAccountSection,
198
+ signOutSection
199
+ ] });
200
+ }
201
+ function useEmailVerificationSection() {
161
202
  const { t } = (0, import_translations.useTranslation)();
162
203
  const user = (0, import__.useUser)({ or: "redirect" });
163
204
  const [emailSent, setEmailSent] = (0, import_react.useState)(false);
164
205
  if (!user.primaryEmail) {
165
206
  return null;
166
207
  }
167
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
168
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Email Verification") }),
169
- user.primaryEmailVerified ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: t("Your email has been verified.") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
170
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Your email has not been verified.") }),
171
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
208
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
209
+ Section,
210
+ {
211
+ title: t("Email Verification"),
212
+ description: t("Verify your email address to secure your account"),
213
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: user.primaryEmailVerified ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: t("Your email has been verified.") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
172
214
  import_stack_ui.Button,
173
215
  {
174
216
  disabled: emailSent,
@@ -178,11 +220,11 @@ function EmailVerificationSection() {
178
220
  },
179
221
  children: emailSent ? t("Email sent!") : t("Send Verification Email")
180
222
  }
181
- ) })
182
- ] })
183
- ] }) });
223
+ ) }) })
224
+ }
225
+ );
184
226
  }
185
- function PasswordSection() {
227
+ function usePasswordSection() {
186
228
  const { t } = (0, import_translations.useTranslation)();
187
229
  const passwordSchema = (0, import_schema_fields.yupObject)({
188
230
  oldPassword: (0, import_schema_fields.yupString)().required(t("Please enter your old password")),
@@ -287,7 +329,7 @@ function PasswordSection() {
287
329
  ) })
288
330
  ] });
289
331
  }
290
- function MfaSection() {
332
+ function useMfaSection() {
291
333
  const { t } = (0, import_translations.useTranslation)();
292
334
  const project = (0, import__.useStackApp)().useProject();
293
335
  const user = (0, import__.useUser)({ or: "throw" });
@@ -313,103 +355,165 @@ function MfaSection() {
313
355
  setIsMaybeWrong(true);
314
356
  });
315
357
  }, [mfaCode, generatedSecret, handleSubmit]);
316
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
317
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Multi-factor Authentication") }),
318
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
319
- isEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: t("Multi-factor authentication is currently enabled.") }) : generatedSecret ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4 items-center", children: [
320
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Scan this QR code with your authenticator app:") }),
321
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { width: 200, height: 200, src: qrCodeUrl ?? (0, import_errors.throwErr)("TOTP QR code failed to generate"), alt: t("TOTP multi-factor authentication QR code") }),
322
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Then, enter your six-digit MFA code:") }),
323
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
324
- import_stack_ui.Input,
358
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
359
+ Section,
360
+ {
361
+ title: t("Multi-factor Authentication"),
362
+ description: isEnabled ? t("Multi-factor authentication is currently enabled.") : t("Multi-factor authentication is currently disabled."),
363
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4", children: [
364
+ !isEnabled && generatedSecret && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
365
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Scan this QR code with your authenticator app:") }),
366
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { width: 200, height: 200, src: qrCodeUrl ?? (0, import_errors.throwErr)("TOTP QR code failed to generate"), alt: t("TOTP multi-factor authentication QR code") }),
367
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Then, enter your six-digit MFA code:") }),
368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
369
+ import_stack_ui.Input,
370
+ {
371
+ value: mfaCode,
372
+ onChange: (e) => {
373
+ setIsMaybeWrong(false);
374
+ setMfaCode(e.target.value);
375
+ },
376
+ placeholder: "123456",
377
+ maxLength: 6,
378
+ disabled: isLoading
379
+ }
380
+ ),
381
+ isMaybeWrong && mfaCode.length === 6 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Incorrect code. Please try again.") }),
382
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
383
+ import_stack_ui.Button,
384
+ {
385
+ variant: "secondary",
386
+ onClick: () => {
387
+ setGeneratedSecret(null);
388
+ setQrCodeUrl(null);
389
+ setMfaCode("");
390
+ },
391
+ children: t("Cancel")
392
+ }
393
+ ) })
394
+ ] }),
395
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-2", children: isEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
396
+ import_stack_ui.Button,
325
397
  {
326
- value: mfaCode,
327
- onChange: (e) => {
328
- setIsMaybeWrong(false);
329
- setMfaCode(e.target.value);
330
- },
331
- placeholder: "123456",
332
- maxLength: 6,
333
- disabled: isLoading
334
- }
335
- ),
336
- isMaybeWrong && mfaCode.length === 6 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Incorrect code. Please try again.") })
337
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Multi-factor authentication is currently disabled.") }),
338
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
339
- import_stack_ui.Button,
340
- {
341
- className: "mt-4",
342
- variant: isEnabled ? "secondary" : "default",
343
- onClick: async () => {
344
- if (isEnabled) {
398
+ variant: "secondary",
399
+ onClick: async () => {
345
400
  await user.update({
346
401
  totpMultiFactorSecret: null
347
402
  });
348
- } else if (!generatedSecret) {
403
+ },
404
+ children: t("Disable")
405
+ }
406
+ ) : !generatedSecret && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
407
+ import_stack_ui.Button,
408
+ {
409
+ variant: "default",
410
+ onClick: async () => {
349
411
  const secret = (0, import_crypto.generateRandomValues)(new Uint8Array(20));
350
412
  setQrCodeUrl(await generateTotpQrCode(project, user, secret));
351
413
  setGeneratedSecret(secret);
352
- } else {
353
- setGeneratedSecret(null);
354
- setQrCodeUrl(null);
355
- setMfaCode("");
356
- }
357
- },
358
- children: isEnabled ? t("Disable") : generatedSecret ? t("Cancel") : t("Enable")
359
- }
360
- )
361
- ] })
362
- ] }) });
414
+ },
415
+ children: t("Enable")
416
+ }
417
+ ) })
418
+ ] })
419
+ }
420
+ );
363
421
  }
364
422
  async function generateTotpQrCode(project, user, secret) {
365
423
  const uri = (0, import_otp.createTOTPKeyURI)(project.displayName, user.primaryEmail ?? user.id, secret);
366
424
  return await QRCode.toDataURL(uri);
367
425
  }
368
- function SignOutSection() {
426
+ function useSignOutSection() {
369
427
  const { t } = (0, import_translations.useTranslation)();
370
428
  const user = (0, import__.useUser)({ or: "throw" });
371
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
372
- import_stack_ui.Button,
429
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
430
+ Section,
373
431
  {
374
- variant: "secondary",
375
- onClick: () => user.signOut(),
376
- children: t("Sign Out")
432
+ title: t("Sign out"),
433
+ description: t("End your current session"),
434
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
435
+ import_stack_ui.Button,
436
+ {
437
+ variant: "secondary",
438
+ onClick: () => user.signOut(),
439
+ children: t("Sign out")
440
+ }
441
+ ) })
377
442
  }
378
- ) }) });
443
+ );
379
444
  }
380
- function UserSettings(props) {
445
+ function TeamPage(props) {
446
+ const teamUserProfileSection = useTeamUserProfileSection(props);
447
+ const teamProfileImageSection = useTeamProfileImageSection(props);
448
+ const teamDisplayNameSection = useTeamDisplayNameSection(props);
449
+ const leaveTeamSection = useLeaveTeamSection(props);
450
+ const memberInvitationSection = useMemberInvitationSection(props);
451
+ const memberListSection = useMemberListSection(props);
452
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
453
+ teamUserProfileSection,
454
+ memberInvitationSection,
455
+ memberListSection,
456
+ teamProfileImageSection,
457
+ teamDisplayNameSection,
458
+ leaveTeamSection
459
+ ] });
460
+ }
461
+ function useLeaveTeamSection(props) {
381
462
  const { t } = (0, import_translations.useTranslation)();
382
463
  const user = (0, import__.useUser)({ or: "redirect" });
383
464
  const [leaving, setLeaving] = (0, import_react.useState)(false);
384
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: !leaving ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
385
- import_stack_ui.Button,
465
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
466
+ Section,
386
467
  {
387
- variant: "secondary",
388
- onClick: async () => setLeaving(true),
389
- children: t("Leave team")
468
+ title: t("Leave Team"),
469
+ description: t("leave this team and remove your team profile"),
470
+ children: !leaving ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
471
+ import_stack_ui.Button,
472
+ {
473
+ variant: "secondary",
474
+ onClick: () => setLeaving(true),
475
+ children: t("Leave team")
476
+ }
477
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-2", children: [
478
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Are you sure you want to leave the team?") }),
479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
481
+ import_stack_ui.Button,
482
+ {
483
+ variant: "destructive",
484
+ onClick: async () => {
485
+ await user.leaveTeam(props.team);
486
+ window.location.reload();
487
+ },
488
+ children: t("Leave")
489
+ }
490
+ ),
491
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
492
+ import_stack_ui.Button,
493
+ {
494
+ variant: "secondary",
495
+ onClick: () => setLeaving(false),
496
+ children: t("Cancel")
497
+ }
498
+ )
499
+ ] })
500
+ ] })
390
501
  }
391
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "", children: [
392
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Are you sure you want to leave the team?") }),
393
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
394
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "destructive", onClick: async () => {
395
- await user.leaveTeam(props.team);
396
- window.location.reload();
397
- }, children: t("Leave") }),
398
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "secondary", onClick: () => setLeaving(false), children: t("Cancel") })
399
- ] })
400
- ] }) }) });
502
+ );
401
503
  }
402
- function ManagementSettings(props) {
504
+ function useTeamProfileImageSection(props) {
403
505
  const { t } = (0, import_translations.useTranslation)();
404
506
  const user = (0, import__.useUser)({ or: "redirect" });
405
507
  const updateTeamPermission = user.usePermission(props.team, "$update_team");
406
508
  if (!updateTeamPermission) {
407
509
  return null;
408
510
  }
409
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
410
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
411
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Team display name") }),
412
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
511
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
512
+ Section,
513
+ {
514
+ title: t("Team profile image"),
515
+ description: t("Upload an image for your team"),
516
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
413
517
  import_profile_image_editor.ProfileImageEditor,
414
518
  {
415
519
  user: props.team,
@@ -418,40 +522,53 @@ function ManagementSettings(props) {
418
522
  }
419
523
  }
420
524
  )
421
- ] }),
422
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
423
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Team display name") }),
424
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
525
+ }
526
+ );
527
+ }
528
+ function useTeamDisplayNameSection(props) {
529
+ const { t } = (0, import_translations.useTranslation)();
530
+ const user = (0, import__.useUser)({ or: "redirect" });
531
+ const updateTeamPermission = user.usePermission(props.team, "$update_team");
532
+ if (!updateTeamPermission) {
533
+ return null;
534
+ }
535
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
536
+ Section,
537
+ {
538
+ title: t("Team display name"),
539
+ description: t("Change the display name of your team"),
540
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
425
541
  import_stack_ui.EditableText,
426
542
  {
427
543
  value: props.team.displayName,
428
544
  onSave: async (newDisplayName) => await props.team.update({ displayName: newDisplayName })
429
545
  }
430
546
  )
431
- ] })
432
- ] });
547
+ }
548
+ );
433
549
  }
434
- function ProfileSettings(props) {
550
+ function useTeamUserProfileSection(props) {
435
551
  const { t } = (0, import_translations.useTranslation)();
436
552
  const user = (0, import__.useUser)({ or: "redirect" });
437
553
  const profile = user.useTeamProfile(props.team);
438
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
439
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Label, { className: "flex gap-2", children: [
440
- t("User display name"),
441
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SimpleTooltip, { tooltip: "This overwrites your user display name in the account setting", type: "info" })
442
- ] }),
443
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
444
- import_stack_ui.EditableText,
445
- {
446
- value: profile.displayName || "",
447
- onSave: async (newDisplayName) => {
448
- await profile.update({ displayName: newDisplayName });
554
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
555
+ Section,
556
+ {
557
+ title: t("Team user name"),
558
+ description: t("Overwrite your user display name in this team"),
559
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
560
+ import_stack_ui.EditableText,
561
+ {
562
+ value: profile.displayName || "",
563
+ onSave: async (newDisplayName) => {
564
+ await profile.update({ displayName: newDisplayName });
565
+ }
449
566
  }
450
- }
451
- )
452
- ] }) });
567
+ )
568
+ }
569
+ );
453
570
  }
454
- function MemberInvitation(props) {
571
+ function useMemberInvitationSection(props) {
455
572
  const { t } = (0, import_translations.useTranslation)();
456
573
  const invitationSchema = (0, import_schema_fields.yupObject)({
457
574
  email: (0, import_schema_fields.yupString)().email().required(t("Please enter an email address"))
@@ -478,35 +595,39 @@ function MemberInvitation(props) {
478
595
  (0, import_react.useEffect)(() => {
479
596
  setInvitedEmail(null);
480
597
  }, [watch("email")]);
481
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
482
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Invite a user to team") }),
483
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
484
- "form",
485
- {
486
- onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
487
- noValidate: true,
488
- children: [
489
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4 md:flex-row", children: [
490
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
491
- import_stack_ui.Input,
492
- {
493
- placeholder: t("Email"),
494
- ...register("email")
495
- }
496
- ) }),
497
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Invite User") })
498
- ] }),
499
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.email?.message?.toString() }),
500
- invitedEmail && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { type: "label", variant: "secondary", children: [
501
- "Invited ",
502
- invitedEmail
503
- ] })
504
- ]
505
- }
506
- )
507
- ] });
598
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
599
+ Section,
600
+ {
601
+ title: t("Invite member"),
602
+ description: t("Invite a user to your team through email"),
603
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
604
+ "form",
605
+ {
606
+ onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
607
+ noValidate: true,
608
+ children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4 md:flex-row", children: [
610
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
611
+ import_stack_ui.Input,
612
+ {
613
+ placeholder: t("Email"),
614
+ ...register("email")
615
+ }
616
+ ),
617
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Invite User") })
618
+ ] }),
619
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.email?.message?.toString() }),
620
+ invitedEmail && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { type: "label", variant: "secondary", children: [
621
+ "Invited ",
622
+ invitedEmail
623
+ ] })
624
+ ]
625
+ }
626
+ )
627
+ }
628
+ );
508
629
  }
509
- function MembersSettings(props) {
630
+ function useMemberListSection(props) {
510
631
  const { t } = (0, import_translations.useTranslation)();
511
632
  const user = (0, import__.useUser)({ or: "redirect" });
512
633
  const readMemberPermission = user.usePermission(props.team, "$read_members");
@@ -519,8 +640,8 @@ function MembersSettings(props) {
519
640
  return null;
520
641
  }
521
642
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
522
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Members") }),
523
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Table, { children: [
643
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { className: "font-medium mb-2", children: t("Members") }),
644
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border rounded-md", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Table, { children: [
524
645
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
525
646
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[100px]", children: t("User") }),
526
647
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[200px]", children: t("Name") })
@@ -529,7 +650,7 @@ function MembersSettings(props) {
529
650
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_user_avatar.UserAvatar, { user: teamProfile }) }),
530
651
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: teamProfile.displayName }) })
531
652
  ] }, id)) })
532
- ] })
653
+ ] }) })
533
654
  ] });
534
655
  }
535
656
  function TeamCreation() {
@@ -555,33 +676,84 @@ function TeamCreation() {
555
676
  setLoading(false);
556
677
  }
557
678
  };
558
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "stack-scope flex flex-col items-stretch", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mb-6", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
679
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageLayout, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, { title: t("Create a Team"), description: t("Enter a display name for your new team"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
559
680
  "form",
560
681
  {
561
- className: "flex flex-col items-stretch stack-scope",
562
682
  onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
563
683
  noValidate: true,
564
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-end gap-4", children: [
565
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
566
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "email", className: "mb-1", children: t("Display name") }),
684
+ className: "flex gap-2",
685
+ children: [
686
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col flex-1", children: [
567
687
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
568
688
  import_stack_ui.Input,
569
689
  {
570
- id: "email",
571
- type: "email",
690
+ id: "displayName",
691
+ type: "text",
572
692
  ...register("displayName")
573
693
  }
574
- )
694
+ ),
695
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.displayName?.message?.toString() })
575
696
  ] }),
576
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.displayName?.message?.toString() }),
577
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", className: "mt-6", loading, children: t("Create") })
578
- ] })
697
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Create") })
698
+ ]
579
699
  }
580
700
  ) }) });
581
701
  }
702
+ function useDeleteAccountSection() {
703
+ const { t } = (0, import_translations.useTranslation)();
704
+ const user = (0, import__.useUser)({ or: "redirect" });
705
+ const app = (0, import__.useStackApp)();
706
+ const project = app.useProject();
707
+ const [deleting, setDeleting] = (0, import_react.useState)(false);
708
+ if (!project.config.clientUserDeletionEnabled) {
709
+ return null;
710
+ }
711
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
712
+ Section,
713
+ {
714
+ title: t("Delete Account"),
715
+ description: t("Permanently remove your account and all associated data"),
716
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "stack-scope flex flex-col items-stretch", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.AccordionItem, { value: "item-1", children: [
717
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.AccordionTrigger, { children: t("Danger zone") }),
718
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.AccordionContent, { children: !deleting ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
719
+ import_stack_ui.Button,
720
+ {
721
+ variant: "destructive",
722
+ onClick: () => setDeleting(true),
723
+ children: t("Delete account")
724
+ }
725
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-2", children: [
726
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Are you sure you want to delete your account? This action is IRREVERSIBLE and will delete ALL associated data.") }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
728
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
729
+ import_stack_ui.Button,
730
+ {
731
+ variant: "destructive",
732
+ onClick: async () => {
733
+ await user.delete();
734
+ await app.redirectToHome();
735
+ },
736
+ children: t("Delete Account")
737
+ }
738
+ ),
739
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
740
+ import_stack_ui.Button,
741
+ {
742
+ variant: "secondary",
743
+ onClick: () => setDeleting(false),
744
+ children: t("Cancel")
745
+ }
746
+ )
747
+ ] })
748
+ ] }) })
749
+ ] }) }) })
750
+ }
751
+ );
752
+ }
582
753
  // Annotate the CommonJS export names for ESM import in node:
583
754
  0 && (module.exports = {
584
755
  AccountSettings,
585
- TeamCreation
756
+ TeamCreation,
757
+ useDeleteAccountSection
586
758
  });
587
759
  //# sourceMappingURL=account-settings.js.map