@stackframe/stack 2.5.33 → 2.5.35

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 (126) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/credential-sign-in.js +14 -12
  3. package/dist/components/credential-sign-in.js.map +1 -1
  4. package/dist/components/credential-sign-up.js +17 -15
  5. package/dist/components/credential-sign-up.js.map +1 -1
  6. package/dist/components/elements/maybe-full-page.d.mts +2 -2
  7. package/dist/components/elements/maybe-full-page.d.ts +2 -2
  8. package/dist/components/elements/sidebar-layout.d.mts +5 -5
  9. package/dist/components/elements/sidebar-layout.d.ts +5 -5
  10. package/dist/components/magic-link-sign-in.js +11 -9
  11. package/dist/components/magic-link-sign-in.js.map +1 -1
  12. package/dist/components/message-cards/message-card.d.mts +2 -2
  13. package/dist/components/message-cards/message-card.d.ts +2 -2
  14. package/dist/components/oauth-button-group.js.map +1 -1
  15. package/dist/components/oauth-button.js +48 -2
  16. package/dist/components/oauth-button.js.map +1 -1
  17. package/dist/components/profile-image-editor.js +5 -3
  18. package/dist/components/profile-image-editor.js.map +1 -1
  19. package/dist/components/selected-team-switcher.js +8 -5
  20. package/dist/components/selected-team-switcher.js.map +1 -1
  21. package/dist/components/team-icon.js.map +1 -1
  22. package/dist/components/user-button.d.mts +2 -2
  23. package/dist/components/user-button.d.ts +2 -2
  24. package/dist/components/user-button.js +11 -11
  25. package/dist/components/user-button.js.map +1 -1
  26. package/dist/components-page/account-settings.js +79 -66
  27. package/dist/components-page/account-settings.js.map +1 -1
  28. package/dist/components-page/auth-page.js +11 -7
  29. package/dist/components-page/auth-page.js.map +1 -1
  30. package/dist/components-page/email-verification.js +4 -2
  31. package/dist/components-page/email-verification.js.map +1 -1
  32. package/dist/components-page/error-page.js +6 -4
  33. package/dist/components-page/error-page.js.map +1 -1
  34. package/dist/components-page/forgot-password.js +12 -8
  35. package/dist/components-page/forgot-password.js.map +1 -1
  36. package/dist/components-page/magic-link-callback.js +5 -3
  37. package/dist/components-page/magic-link-callback.js.map +1 -1
  38. package/dist/components-page/oauth-callback.js +6 -5
  39. package/dist/components-page/oauth-callback.js.map +1 -1
  40. package/dist/components-page/password-reset.js +25 -22
  41. package/dist/components-page/password-reset.js.map +1 -1
  42. package/dist/components-page/team-creation.js +9 -7
  43. package/dist/components-page/team-creation.js.map +1 -1
  44. package/dist/components-page/team-invitation.js +14 -11
  45. package/dist/components-page/team-invitation.js.map +1 -1
  46. package/dist/esm/components/credential-sign-in.js +14 -12
  47. package/dist/esm/components/credential-sign-in.js.map +1 -1
  48. package/dist/esm/components/credential-sign-up.js +17 -15
  49. package/dist/esm/components/credential-sign-up.js.map +1 -1
  50. package/dist/esm/components/magic-link-sign-in.js +11 -9
  51. package/dist/esm/components/magic-link-sign-in.js.map +1 -1
  52. package/dist/esm/components/oauth-button-group.js.map +1 -1
  53. package/dist/esm/components/oauth-button.js +48 -2
  54. package/dist/esm/components/oauth-button.js.map +1 -1
  55. package/dist/esm/components/profile-image-editor.js +5 -3
  56. package/dist/esm/components/profile-image-editor.js.map +1 -1
  57. package/dist/esm/components/selected-team-switcher.js +8 -5
  58. package/dist/esm/components/selected-team-switcher.js.map +1 -1
  59. package/dist/esm/components/team-icon.js.map +1 -1
  60. package/dist/esm/components/user-button.js +12 -15
  61. package/dist/esm/components/user-button.js.map +1 -1
  62. package/dist/esm/components-page/account-settings.js +79 -66
  63. package/dist/esm/components-page/account-settings.js.map +1 -1
  64. package/dist/esm/components-page/auth-page.js +11 -7
  65. package/dist/esm/components-page/auth-page.js.map +1 -1
  66. package/dist/esm/components-page/email-verification.js +4 -2
  67. package/dist/esm/components-page/email-verification.js.map +1 -1
  68. package/dist/esm/components-page/error-page.js +6 -4
  69. package/dist/esm/components-page/error-page.js.map +1 -1
  70. package/dist/esm/components-page/forgot-password.js +12 -8
  71. package/dist/esm/components-page/forgot-password.js.map +1 -1
  72. package/dist/esm/components-page/magic-link-callback.js +5 -3
  73. package/dist/esm/components-page/magic-link-callback.js.map +1 -1
  74. package/dist/esm/components-page/oauth-callback.js +6 -5
  75. package/dist/esm/components-page/oauth-callback.js.map +1 -1
  76. package/dist/esm/components-page/password-reset.js +25 -22
  77. package/dist/esm/components-page/password-reset.js.map +1 -1
  78. package/dist/esm/components-page/team-creation.js +9 -7
  79. package/dist/esm/components-page/team-creation.js.map +1 -1
  80. package/dist/esm/components-page/team-invitation.js +14 -11
  81. package/dist/esm/components-page/team-invitation.js.map +1 -1
  82. package/dist/esm/generated/quetzal-translations.js +1425 -0
  83. package/dist/esm/generated/quetzal-translations.js.map +1 -0
  84. package/dist/esm/lib/stack-app.js +1 -1
  85. package/dist/esm/lib/translations.js +20 -0
  86. package/dist/esm/lib/translations.js.map +1 -0
  87. package/dist/esm/providers/stack-provider.js +4 -2
  88. package/dist/esm/providers/stack-provider.js.map +1 -1
  89. package/dist/esm/providers/theme-provider.js.map +1 -1
  90. package/dist/esm/providers/translation-provider-client.js +18 -0
  91. package/dist/esm/providers/translation-provider-client.js.map +1 -0
  92. package/dist/esm/providers/translation-provider.js +12 -0
  93. package/dist/esm/providers/translation-provider.js.map +1 -0
  94. package/dist/esm/utils/browser-script.js +38 -6
  95. package/dist/esm/utils/browser-script.js.map +1 -1
  96. package/dist/generated/quetzal-translations.d.mts +4 -0
  97. package/dist/generated/quetzal-translations.d.ts +4 -0
  98. package/dist/generated/quetzal-translations.js +1451 -0
  99. package/dist/generated/quetzal-translations.js.map +1 -0
  100. package/dist/index.d.mts +2 -0
  101. package/dist/index.d.ts +2 -0
  102. package/dist/lib/stack-app.js +1 -1
  103. package/dist/lib/translations.d.mts +5 -0
  104. package/dist/lib/translations.d.ts +5 -0
  105. package/dist/lib/translations.js +55 -0
  106. package/dist/lib/translations.js.map +1 -0
  107. package/dist/providers/stack-provider-client.d.mts +3 -3
  108. package/dist/providers/stack-provider-client.d.ts +3 -3
  109. package/dist/providers/stack-provider.d.mts +6 -3
  110. package/dist/providers/stack-provider.d.ts +6 -3
  111. package/dist/providers/stack-provider.js +4 -2
  112. package/dist/providers/stack-provider.js.map +1 -1
  113. package/dist/providers/theme-provider.d.mts +2 -2
  114. package/dist/providers/theme-provider.d.ts +2 -2
  115. package/dist/providers/theme-provider.js.map +1 -1
  116. package/dist/providers/translation-provider-client.d.mts +14 -0
  117. package/dist/providers/translation-provider-client.d.ts +14 -0
  118. package/dist/providers/translation-provider-client.js +43 -0
  119. package/dist/providers/translation-provider-client.js.map +1 -0
  120. package/dist/providers/translation-provider.d.mts +9 -0
  121. package/dist/providers/translation-provider.d.ts +9 -0
  122. package/dist/providers/translation-provider.js +37 -0
  123. package/dist/providers/translation-provider.js.map +1 -0
  124. package/dist/utils/browser-script.js +38 -6
  125. package/dist/utils/browser-script.js.map +1 -1
  126. package/package.json +20 -12
@@ -57,8 +57,10 @@ var import_user_avatar = require("../components/elements/user-avatar");
57
57
  var import_profile_image_editor = require("../components/profile-image-editor");
58
58
  var import_team_icon = require("../components/team-icon");
59
59
  var import_maybe_full_page = require("../components/elements/maybe-full-page");
60
+ var import_translations = require("../lib/translations");
60
61
  var import_jsx_runtime = require("react/jsx-runtime");
61
62
  function AccountSettings(props) {
63
+ const { t } = (0, import_translations.useTranslation)();
62
64
  const user = (0, import__.useUser)({ or: "redirect" });
63
65
  const teams = user.useTeams();
64
66
  const stackApp = (0, import__.useStackApp)();
@@ -68,14 +70,14 @@ function AccountSettings(props) {
68
70
  {
69
71
  items: [
70
72
  {
71
- title: "My Profile",
73
+ title: t("My Profile"),
72
74
  type: "item",
73
75
  subpath: "/profile",
74
76
  icon: import_lucide_react.Contact,
75
77
  content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfileSection, {})
76
78
  },
77
79
  {
78
- title: "Security",
80
+ title: t("Security"),
79
81
  type: "item",
80
82
  icon: import_lucide_react.ShieldCheck,
81
83
  subpath: "/security",
@@ -86,7 +88,7 @@ function AccountSettings(props) {
86
88
  ] })
87
89
  },
88
90
  {
89
- title: "Sign Out",
91
+ title: t("Sign Out"),
90
92
  subpath: "/sign-out",
91
93
  type: "item",
92
94
  icon: import_lucide_react.LogOut,
@@ -100,7 +102,7 @@ function AccountSettings(props) {
100
102
  content: item.content
101
103
  })) || [],
102
104
  ...teams.length > 0 || project.config.clientTeamCreationEnabled ? [{
103
- title: "Teams",
105
+ title: t("Teams"),
104
106
  type: "divider"
105
107
  }] : [],
106
108
  ...teams.map((team) => ({
@@ -119,23 +121,24 @@ function AccountSettings(props) {
119
121
  ] })
120
122
  })),
121
123
  ...project.config.clientTeamCreationEnabled ? [{
122
- title: "Create a team",
124
+ title: t("Create a team"),
123
125
  icon: import_lucide_react.CirclePlus,
124
126
  type: "item",
125
127
  subpath: "/team-creation",
126
128
  content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreation, {})
127
129
  }] : []
128
130
  ].filter((p) => p.type === "divider" || p.content),
129
- title: "Account Settings",
131
+ title: t("Account Settings"),
130
132
  basePath: stackApp.urls.accountSettings
131
133
  }
132
134
  ) }) });
133
135
  }
134
136
  function ProfileSection() {
137
+ const { t } = (0, import_translations.useTranslation)();
135
138
  const user = (0, import__.useUser)({ or: "redirect" });
136
139
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
137
140
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-start", children: [
138
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { className: "mb-2", children: "Profile image" }),
141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { className: "mb-2", children: t("Profile image") }),
139
142
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
140
143
  import_profile_image_editor.ProfileImageEditor,
141
144
  {
@@ -147,7 +150,7 @@ function ProfileSection() {
147
150
  )
148
151
  ] }),
149
152
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
150
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Display name" }),
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Display name") }),
151
154
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.EditableText, { value: user.displayName || "", onSave: async (newDisplayName) => {
152
155
  await user.update({ displayName: newDisplayName });
153
156
  } })
@@ -155,15 +158,16 @@ function ProfileSection() {
155
158
  ] });
156
159
  }
157
160
  function EmailVerificationSection() {
161
+ const { t } = (0, import_translations.useTranslation)();
158
162
  const user = (0, import__.useUser)({ or: "redirect" });
159
163
  const [emailSent, setEmailSent] = (0, import_react.useState)(false);
160
164
  if (!user.primaryEmail) {
161
165
  return null;
162
166
  }
163
167
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
164
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Email Verification" }),
165
- user.primaryEmailVerified ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: "Your email has been verified." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
166
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: "Your email has not been verified." }),
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.") }),
167
171
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
168
172
  import_stack_ui.Button,
169
173
  {
@@ -172,28 +176,29 @@ function EmailVerificationSection() {
172
176
  await user.sendVerificationEmail();
173
177
  setEmailSent(true);
174
178
  },
175
- children: emailSent ? "Email sent!" : "Send Verification Email"
179
+ children: emailSent ? t("Email sent!") : t("Send Verification Email")
176
180
  }
177
181
  ) })
178
182
  ] })
179
183
  ] }) });
180
184
  }
181
- var passwordSchema = (0, import_schema_fields.yupObject)({
182
- oldPassword: (0, import_schema_fields.yupString)().required("Please enter your old password"),
183
- newPassword: (0, import_schema_fields.yupString)().required("Please enter your password").test({
184
- name: "is-valid-password",
185
- test: (value, ctx) => {
186
- const error = (0, import_password.getPasswordError)(value);
187
- if (error) {
188
- return ctx.createError({ message: error.message });
189
- } else {
190
- return true;
191
- }
192
- }
193
- }),
194
- newPasswordRepeat: (0, import_schema_fields.yupString)().nullable().oneOf([yup.ref("newPassword"), "", null], "Passwords do not match").required("Please repeat your password")
195
- });
196
185
  function PasswordSection() {
186
+ const { t } = (0, import_translations.useTranslation)();
187
+ const passwordSchema = (0, import_schema_fields.yupObject)({
188
+ oldPassword: (0, import_schema_fields.yupString)().required(t("Please enter your old password")),
189
+ newPassword: (0, import_schema_fields.yupString)().required(t("Please enter your password")).test({
190
+ name: "is-valid-password",
191
+ test: (value, ctx) => {
192
+ const error = (0, import_password.getPasswordError)(value);
193
+ if (error) {
194
+ return ctx.createError({ message: error.message });
195
+ } else {
196
+ return true;
197
+ }
198
+ }
199
+ }),
200
+ newPasswordRepeat: (0, import_schema_fields.yupString)().nullable().oneOf([yup.ref("newPassword"), "", null], t("Passwords do not match")).required(t("Please repeat your password"))
201
+ });
197
202
  const user = (0, import__.useUser)({ or: "throw" });
198
203
  const [changingPassword, setChangingPassword] = (0, import_react.useState)(false);
199
204
  const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = (0, import_react_hook_form.useForm)({
@@ -207,7 +212,7 @@ function PasswordSection() {
207
212
  const { oldPassword, newPassword } = data;
208
213
  const error = await user.updatePassword({ oldPassword, newPassword });
209
214
  if (error) {
210
- setError("oldPassword", { type: "manual", message: "Incorrect password" });
215
+ setError("oldPassword", { type: "manual", message: t("Incorrect password") });
211
216
  } else {
212
217
  reset();
213
218
  setAlreadyReset(true);
@@ -222,15 +227,15 @@ function PasswordSection() {
222
227
  return null;
223
228
  }
224
229
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
225
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Change password" }),
226
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: alreadyReset ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: "Password changed successfully!" }) : !changingPassword ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Change password") }),
231
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: alreadyReset ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: t("Password changed successfully!") }) : !changingPassword ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
227
232
  import_stack_ui.Button,
228
233
  {
229
234
  variant: "secondary",
230
235
  onClick: async () => {
231
236
  setChangingPassword(true);
232
237
  },
233
- children: "Change Password"
238
+ children: t("Change Password")
234
239
  }
235
240
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
236
241
  "form",
@@ -238,7 +243,7 @@ function PasswordSection() {
238
243
  onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
239
244
  noValidate: true,
240
245
  children: [
241
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "old-password", className: "mb-1", children: "Old password" }),
246
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "old-password", className: "mb-1", children: t("Old password") }),
242
247
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
243
248
  import_stack_ui.Input,
244
249
  {
@@ -248,7 +253,7 @@ function PasswordSection() {
248
253
  }
249
254
  ),
250
255
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.oldPassword?.message?.toString() }),
251
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "new-password", className: "mt-4 mb-1", children: "Password" }),
256
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "new-password", className: "mt-4 mb-1", children: t("Password") }),
252
257
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
253
258
  import_stack_ui.PasswordInput,
254
259
  {
@@ -262,7 +267,7 @@ function PasswordSection() {
262
267
  }
263
268
  ),
264
269
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.newPassword?.message?.toString() }),
265
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "repeat-password", className: "mt-4 mb-1", children: "Repeat password" }),
270
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "repeat-password", className: "mt-4 mb-1", children: t("Repeat password") }),
266
271
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
267
272
  import_stack_ui.PasswordInput,
268
273
  {
@@ -276,13 +281,14 @@ function PasswordSection() {
276
281
  }
277
282
  ),
278
283
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.newPasswordRepeat?.message?.toString() }),
279
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", className: "mt-6", loading, children: "Change Password" })
284
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", className: "mt-6", loading, children: t("Change Password") })
280
285
  ]
281
286
  }
282
287
  ) })
283
288
  ] });
284
289
  }
285
290
  function MfaSection() {
291
+ const { t } = (0, import_translations.useTranslation)();
286
292
  const project = (0, import__.useStackApp)().useProject();
287
293
  const user = (0, import__.useUser)({ or: "throw" });
288
294
  const [generatedSecret, setGeneratedSecret] = (0, import_react.useState)(null);
@@ -308,12 +314,12 @@ function MfaSection() {
308
314
  });
309
315
  }, [mfaCode, generatedSecret, handleSubmit]);
310
316
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
311
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Multi-factor Authentication" }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Multi-factor Authentication") }),
312
318
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
313
- isEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "success", children: "Multi-factor authentication is currently enabled." }) : generatedSecret ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4 items-center", children: [
314
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: "Scan this QR code with your authenticator app:" }),
315
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { width: 200, height: 200, src: qrCodeUrl ?? (0, import_errors.throwErr)("TOTP QR code failed to generate"), alt: "TOTP multi-factor authentication QR code" }),
316
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: "Then, enter your six-digit MFA code:" }),
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:") }),
317
323
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
318
324
  import_stack_ui.Input,
319
325
  {
@@ -327,8 +333,8 @@ function MfaSection() {
327
333
  disabled: isLoading
328
334
  }
329
335
  ),
330
- isMaybeWrong && mfaCode.length === 6 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: "Incorrect code. Please try again." })
331
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: "Multi-factor authentication is currently disabled." }),
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.") }),
332
338
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
333
339
  import_stack_ui.Button,
334
340
  {
@@ -349,7 +355,7 @@ function MfaSection() {
349
355
  setMfaCode("");
350
356
  }
351
357
  },
352
- children: isEnabled ? "Disable" : generatedSecret ? "Cancel" : "Enable"
358
+ children: isEnabled ? t("Disable") : generatedSecret ? t("Cancel") : t("Enable")
353
359
  }
354
360
  )
355
361
  ] })
@@ -360,17 +366,19 @@ async function generateTotpQrCode(project, user, secret) {
360
366
  return await QRCode.toDataURL(uri);
361
367
  }
362
368
  function SignOutSection() {
369
+ const { t } = (0, import_translations.useTranslation)();
363
370
  const user = (0, import__.useUser)({ or: "throw" });
364
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)(
365
372
  import_stack_ui.Button,
366
373
  {
367
374
  variant: "secondary",
368
375
  onClick: () => user.signOut(),
369
- children: "Sign Out"
376
+ children: t("Sign Out")
370
377
  }
371
378
  ) }) });
372
379
  }
373
380
  function UserSettings(props) {
381
+ const { t } = (0, import_translations.useTranslation)();
374
382
  const user = (0, import__.useUser)({ or: "redirect" });
375
383
  const [leaving, setLeaving] = (0, import_react.useState)(false);
376
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)(
@@ -378,20 +386,21 @@ function UserSettings(props) {
378
386
  {
379
387
  variant: "secondary",
380
388
  onClick: async () => setLeaving(true),
381
- children: "Leave team"
389
+ children: t("Leave team")
382
390
  }
383
391
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "", children: [
384
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: "Are you sure you want to leave the team?" }),
392
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("Are you sure you want to leave the team?") }),
385
393
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
386
394
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "destructive", onClick: async () => {
387
395
  await user.leaveTeam(props.team);
388
396
  window.location.reload();
389
- }, children: "Leave" }),
390
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "secondary", onClick: () => setLeaving(false), children: "Cancel" })
397
+ }, children: t("Leave") }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "secondary", onClick: () => setLeaving(false), children: t("Cancel") })
391
399
  ] })
392
400
  ] }) }) });
393
401
  }
394
402
  function ManagementSettings(props) {
403
+ const { t } = (0, import_translations.useTranslation)();
395
404
  const user = (0, import__.useUser)({ or: "redirect" });
396
405
  const updateTeamPermission = user.usePermission(props.team, "$update_team");
397
406
  if (!updateTeamPermission) {
@@ -399,7 +408,7 @@ function ManagementSettings(props) {
399
408
  }
400
409
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
401
410
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
402
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Team display name" }),
411
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Team display name") }),
403
412
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
404
413
  import_profile_image_editor.ProfileImageEditor,
405
414
  {
@@ -411,7 +420,7 @@ function ManagementSettings(props) {
411
420
  )
412
421
  ] }),
413
422
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
414
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Team display name" }),
423
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Team display name") }),
415
424
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
416
425
  import_stack_ui.EditableText,
417
426
  {
@@ -423,11 +432,12 @@ function ManagementSettings(props) {
423
432
  ] });
424
433
  }
425
434
  function ProfileSettings(props) {
435
+ const { t } = (0, import_translations.useTranslation)();
426
436
  const user = (0, import__.useUser)({ or: "redirect" });
427
437
  const profile = user.useTeamProfile(props.team);
428
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: [
429
439
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Label, { className: "flex gap-2", children: [
430
- "User display name ",
440
+ t("User display name"),
431
441
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SimpleTooltip, { tooltip: "This overwrites your user display name in the account setting", type: "info" })
432
442
  ] }),
433
443
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -441,10 +451,11 @@ function ProfileSettings(props) {
441
451
  )
442
452
  ] }) });
443
453
  }
444
- var invitationSchema = (0, import_schema_fields.yupObject)({
445
- email: (0, import_schema_fields.yupString)().email().required("Please enter an email address")
446
- });
447
454
  function MemberInvitation(props) {
455
+ const { t } = (0, import_translations.useTranslation)();
456
+ const invitationSchema = (0, import_schema_fields.yupObject)({
457
+ email: (0, import_schema_fields.yupString)().email().required(t("Please enter an email address"))
458
+ });
448
459
  const user = (0, import__.useUser)({ or: "redirect" });
449
460
  const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
450
461
  if (!inviteMemberPermission) {
@@ -468,7 +479,7 @@ function MemberInvitation(props) {
468
479
  setInvitedEmail(null);
469
480
  }, [watch("email")]);
470
481
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
471
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Invite a user to team" }),
482
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Invite a user to team") }),
472
483
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
473
484
  "form",
474
485
  {
@@ -479,11 +490,11 @@ function MemberInvitation(props) {
479
490
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
480
491
  import_stack_ui.Input,
481
492
  {
482
- placeholder: "Email",
493
+ placeholder: t("Email"),
483
494
  ...register("email")
484
495
  }
485
496
  ) }),
486
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: "Invite User" })
497
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Invite User") })
487
498
  ] }),
488
499
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.email?.message?.toString() }),
489
500
  invitedEmail && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { type: "label", variant: "secondary", children: [
@@ -496,6 +507,7 @@ function MemberInvitation(props) {
496
507
  ] });
497
508
  }
498
509
  function MembersSettings(props) {
510
+ const { t } = (0, import_translations.useTranslation)();
499
511
  const user = (0, import__.useUser)({ or: "redirect" });
500
512
  const readMemberPermission = user.usePermission(props.team, "$read_members");
501
513
  const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
@@ -507,11 +519,11 @@ function MembersSettings(props) {
507
519
  return null;
508
520
  }
509
521
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
510
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Members" }),
522
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Members") }),
511
523
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Table, { children: [
512
524
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
513
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[100px]", children: "User" }),
514
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[200px]", children: "Name" })
525
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[100px]", children: t("User") }),
526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[200px]", children: t("Name") })
515
527
  ] }) }),
516
528
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableBody, { children: users.map(({ id, teamProfile }, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
517
529
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_user_avatar.UserAvatar, { user: teamProfile }) }),
@@ -520,10 +532,11 @@ function MembersSettings(props) {
520
532
  ] })
521
533
  ] });
522
534
  }
523
- var teamCreationSchema = (0, import_schema_fields.yupObject)({
524
- displayName: (0, import_schema_fields.yupString)().required("Please enter a team name")
525
- });
526
535
  function TeamCreation() {
536
+ const { t } = (0, import_translations.useTranslation)();
537
+ const teamCreationSchema = (0, import_schema_fields.yupObject)({
538
+ displayName: (0, import_schema_fields.yupString)().required(t("Please enter a team name"))
539
+ });
527
540
  const { register, handleSubmit, formState: { errors } } = (0, import_react_hook_form.useForm)({
528
541
  resolver: (0, import_yup.yupResolver)(teamCreationSchema)
529
542
  });
@@ -532,7 +545,7 @@ function TeamCreation() {
532
545
  const user = (0, import__.useUser)({ or: "redirect" });
533
546
  const [loading, setLoading] = (0, import_react.useState)(false);
534
547
  if (!project.config.clientTeamCreationEnabled) {
535
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import__.MessageCard, { title: "Team creation is not enabled" });
548
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import__.MessageCard, { title: t("Team creation is not enabled") });
536
549
  }
537
550
  const onSubmit = async (data) => {
538
551
  setLoading(true);
@@ -550,7 +563,7 @@ function TeamCreation() {
550
563
  noValidate: true,
551
564
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-end gap-4", children: [
552
565
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
553
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "email", className: "mb-1", children: "Display name" }),
566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "email", className: "mb-1", children: t("Display name") }),
554
567
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
555
568
  import_stack_ui.Input,
556
569
  {
@@ -561,7 +574,7 @@ function TeamCreation() {
561
574
  )
562
575
  ] }),
563
576
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.displayName?.message?.toString() }),
564
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", className: "mt-6", loading, children: "Create" })
577
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", className: "mt-6", loading, children: t("Create") })
565
578
  ] })
566
579
  }
567
580
  ) }) });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Button, EditableText, Input, Label, PasswordInput, SimpleTooltip, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, LogOut, ShieldCheck, LucideIcon } from 'lucide-react';\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { ProfileImageEditor } from \"../components/profile-image-editor\";\nimport { TeamIcon } from '../components/team-icon';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\n\n\nexport function AccountSettings(props: {\n fullPage?: boolean,\n extraItems?: {\n title: string,\n icon: LucideIcon,\n content: React.ReactNode,\n subpath: string,\n }[],\n}) {\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const stackApp = useStackApp();\n const project = stackApp.useProject();\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div style={{ alignSelf: 'stretch', flexGrow: 1 }}>\n <SidebarLayout\n items={([\n {\n title: 'My Profile',\n type: 'item',\n subpath: '/profile',\n icon: Contact,\n content: <ProfileSection/>,\n },\n {\n title: 'Security',\n type: 'item',\n icon: ShieldCheck,\n subpath: '/security',\n content: (\n <div className='flex flex-col gap-8'>\n <EmailVerificationSection />\n <PasswordSection />\n <MfaSection />\n </div>\n ),\n },\n {\n title: 'Sign Out',\n subpath: '/sign-out',\n type: 'item',\n icon: LogOut,\n content: <SignOutSection />,\n },\n ...(props.extraItems?.map(item => ({\n title: item.title,\n type: 'item',\n subpath: item.subpath,\n icon: item.icon,\n content: item.content,\n } as const)) || []),\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: 'Teams',\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center'>\n <TeamIcon team={team}/>\n {team.displayName}\n </div>,\n type: 'item',\n subpath: `/teams/${team.id}`,\n content: (\n <div className=\"flex flex-col gap-8\">\n <ProfileSettings team={team}/>\n <ManagementSettings team={team}/>\n <MemberInvitation team={team}/>\n <MembersSettings team={team}/>\n <UserSettings team={team}/>\n </div>\n ),\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: 'Create a team',\n icon: CirclePlus,\n type: 'item',\n subpath: '/team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title='Account Settings'\n basePath={stackApp.urls.accountSettings}\n />\n </div>\n </MaybeFullPage>\n );\n}\n\nfunction ProfileSection() {\n const user = useUser({ or: 'redirect' });\n\n return (\n <div className='flex flex-col gap-8'>\n <div className='flex flex-col items-start'>\n <Label className=\"mb-2\">Profile image</Label>\n <ProfileImageEditor\n user={user}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await user.update({ profileImageUrl });\n }}\n />\n </div>\n <div className='flex flex-col'>\n <Label>Display name</Label>\n <EditableText value={user.displayName || ''} onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction EmailVerificationSection() {\n const user = useUser({ or: 'redirect' });\n const [emailSent, setEmailSent] = useState(false);\n\n if (!user.primaryEmail) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Email Verification</Label>\n {user.primaryEmailVerified ? (\n <Typography variant='success'>Your email has been verified.</Typography>\n ) : (\n <>\n <Typography variant='destructive'>Your email has not been verified.</Typography>\n <div className='flex mt-4'>\n <Button\n disabled={emailSent}\n onClick={async () => {\n await user.sendVerificationEmail();\n setEmailSent(true);\n }}\n >\n {emailSent ? 'Email sent!' : 'Send Verification Email'}\n </Button>\n </div>\n </>\n )}\n\n </div>\n </>\n );\n}\n\nconst passwordSchema = yupObject({\n oldPassword: yupString().required('Please enter your old password'),\n newPassword: yupString().required('Please enter your password').test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], 'Passwords do not match').required('Please repeat your password')\n});\n\nfunction PasswordSection() {\n const user = useUser({ or: \"throw\" });\n const [changingPassword, setChangingPassword] = useState(false);\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n const [alreadyReset, setAlreadyReset] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = await user.updatePassword({ oldPassword, newPassword });\n if (error) {\n setError('oldPassword', { type: 'manual', message: 'Incorrect password' });\n } else {\n reset();\n setAlreadyReset(true);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n if (!user.hasPassword) {\n return null;\n }\n\n return (\n <div>\n <Label>Change password</Label>\n <div>\n {\n alreadyReset ?\n <Typography variant='success'>Password changed successfully!</Typography> :\n !changingPassword ?\n <Button\n variant='secondary'\n onClick={async () => {\n setChangingPassword(true);\n }}\n >\n Change Password\n </Button> :\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"old-password\" className=\"mb-1\">Old password</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n {...register('oldPassword')}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">Password</Label>\n <PasswordInput\n id=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">Repeat password</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Change Password\n </Button>\n </form>\n }\n </div>\n </div>\n );\n}\n\nfunction MfaSection() {\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <div>\n <div>\n <Label>Multi-factor Authentication</Label>\n\n <div>\n {isEnabled ? (\n <Typography variant=\"success\">Multi-factor authentication is currently enabled.</Typography>\n ) : (\n generatedSecret ? (\n <div className='flex flex-col gap-4 items-center'>\n <Typography>Scan this QR code with your authenticator app:</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt=\"TOTP multi-factor authentication QR code\" />\n <Typography>Then, enter your six-digit MFA code:</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">Incorrect code. Please try again.</Typography>\n )}\n </div>\n ) : (\n <Typography variant=\"destructive\">Multi-factor authentication is currently disabled.</Typography>\n )\n )}\n\n <Button\n className=\"mt-4\"\n variant={isEnabled ? 'secondary' : 'default'}\n onClick={async () => {\n if (isEnabled) {\n await user.update({\n totpMultiFactorSecret: null,\n });\n } else if (!generatedSecret) {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n } else {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }\n }}\n >\n {isEnabled ? 'Disable' : (generatedSecret ? 'Cancel' : 'Enable')}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction SignOutSection() {\n const user = useUser({ or: \"throw\" });\n return (\n <div className='flex flex-col gap-2'>\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n Sign Out\n </Button>\n </div>\n </div>\n );\n}\n\nfunction UserSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <div className='flex flex-col gap-2'>\n <div>\n { !leaving ?\n <Button\n variant='secondary'\n onClick={async () => setLeaving(true)}\n >\n Leave team\n </Button> :\n <div className=''>\n <Typography variant='destructive'>Are you sure you want to leave the team?</Typography>\n <div className='flex gap-2'>\n <Button variant='destructive' onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}>\n Leave\n </Button>\n <Button variant='secondary' onClick={() => setLeaving(false)}>\n Cancel\n </Button>\n </div>\n </div>}\n </div>\n </div>\n );\n}\n\nfunction ManagementSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <>\n <div className='flex flex-col'>\n <Label>Team display name</Label>\n <ProfileImageEditor\n user={props.team}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await props.team.update({ profileImageUrl });\n }}\n />\n </div>\n\n <div className='flex flex-col'>\n <Label>Team display name</Label>\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </div>\n </>\n );\n}\n\nfunction ProfileSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <Label className=\"flex gap-2\">User display name <SimpleTooltip tooltip=\"This overwrites your user display name in the account setting\" type='info'/></Label>\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nconst invitationSchema = yupObject({\n email: yupString().email().required('Please enter an email address'),\n});\n\nfunction MemberInvitation(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!inviteMemberPermission) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <div>\n <Label>Invite a user to team</Label>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex flex-col gap-4 md:flex-row\">\n <div>\n <Input\n placeholder=\"Email\"\n {...register('email')}\n />\n </div>\n <Button type=\"submit\" loading={loading}>\n Invite User\n </Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </div>\n );\n}\n\n\nfunction MembersSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Label>Members</Label>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">User</TableHead>\n <TableHead className=\"w-[200px]\">Name</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n}\n\nconst teamCreationSchema = yupObject({\n displayName: yupString().required('Please enter a team name'),\n});\n\nexport function TeamCreation() {\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title='Team creation is not enabled' />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n try {\n const team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className='stack-scope flex flex-col items-stretch'>\n <div className=\"mb-6\">\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex items-end gap-4\">\n <div>\n <Label htmlFor=\"email\" className=\"mb-1\">Display name</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('displayName')}\n />\n </div>\n <FormWarningText text={errors.displayName?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Create\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Button, EditableText, Input, Label, PasswordInput, SimpleTooltip, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, LogOut, ShieldCheck, LucideIcon } from 'lucide-react';\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { ProfileImageEditor } from \"../components/profile-image-editor\";\nimport { TeamIcon } from '../components/team-icon';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { useTranslation } from \"../lib/translations\";\n\n\nexport function AccountSettings(props: {\n fullPage?: boolean,\n extraItems?: {\n title: string,\n icon: LucideIcon,\n content: React.ReactNode,\n subpath: string,\n }[],\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const stackApp = useStackApp();\n const project = stackApp.useProject();\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div style={{ alignSelf: 'stretch', flexGrow: 1 }}>\n <SidebarLayout\n items={([\n {\n title: t('My Profile'),\n type: 'item',\n subpath: '/profile',\n icon: Contact,\n content: <ProfileSection/>,\n },\n {\n title: t('Security'),\n type: 'item',\n icon: ShieldCheck,\n subpath: '/security',\n content: (\n <div className='flex flex-col gap-8'>\n <EmailVerificationSection />\n <PasswordSection />\n <MfaSection />\n </div>\n ),\n },\n {\n title: t('Sign Out'),\n subpath: '/sign-out',\n type: 'item',\n icon: LogOut,\n content: <SignOutSection />,\n },\n ...(props.extraItems?.map(item => ({\n title: item.title,\n type: 'item',\n subpath: item.subpath,\n icon: item.icon,\n content: item.content,\n } as const)) || []),\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: t('Teams'),\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center'>\n <TeamIcon team={team}/>\n {team.displayName}\n </div>,\n type: 'item',\n subpath: `/teams/${team.id}`,\n content: (\n <div className=\"flex flex-col gap-8\">\n <ProfileSettings team={team}/>\n <ManagementSettings team={team}/>\n <MemberInvitation team={team}/>\n <MembersSettings team={team}/>\n <UserSettings team={team}/>\n </div>\n ),\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: t('Create a team'),\n icon: CirclePlus,\n type: 'item',\n subpath: '/team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title={t(\"Account Settings\")}\n basePath={stackApp.urls.accountSettings}\n />\n </div>\n </MaybeFullPage>\n );\n}\n\nfunction ProfileSection() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n\n return (\n <div className='flex flex-col gap-8'>\n <div className='flex flex-col items-start'>\n <Label className=\"mb-2\">{t(\"Profile image\")}</Label>\n <ProfileImageEditor\n user={user}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await user.update({ profileImageUrl });\n }}\n />\n </div>\n <div className='flex flex-col'>\n <Label>{t(\"Display name\")}</Label>\n <EditableText value={user.displayName || ''} onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction EmailVerificationSection() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const [emailSent, setEmailSent] = useState(false);\n\n if (!user.primaryEmail) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>{t(\"Email Verification\")}</Label>\n {user.primaryEmailVerified ? (\n <Typography variant='success'>{t(\"Your email has been verified.\")}</Typography>\n ) : (\n <>\n <Typography variant='destructive'>{t(\"Your email has not been verified.\")}</Typography>\n <div className='flex mt-4'>\n <Button\n disabled={emailSent}\n onClick={async () => {\n await user.sendVerificationEmail();\n setEmailSent(true);\n }}\n >\n {emailSent ? t(\"Email sent!\") : t(\"Send Verification Email\")}\n </Button>\n </div>\n </>\n )}\n\n </div>\n </>\n );\n}\n\nfunction PasswordSection() {\n const { t } = useTranslation();\n\n const passwordSchema = yupObject({\n oldPassword: yupString().required(t('Please enter your old password')),\n newPassword: yupString().required(t('Please enter your password')).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], t('Passwords do not match')).required(t('Please repeat your password'))\n });\n\n const user = useUser({ or: \"throw\" });\n const [changingPassword, setChangingPassword] = useState(false);\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n const [alreadyReset, setAlreadyReset] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = await user.updatePassword({ oldPassword, newPassword });\n if (error) {\n setError('oldPassword', { type: 'manual', message: t('Incorrect password') });\n } else {\n reset();\n setAlreadyReset(true);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n if (!user.hasPassword) {\n return null;\n }\n\n return (\n <div>\n <Label>{t(\"Change password\")}</Label>\n <div>\n {\n alreadyReset ?\n <Typography variant='success'>{t(\"Password changed successfully!\")}</Typography> :\n !changingPassword ?\n <Button\n variant='secondary'\n onClick={async () => {\n setChangingPassword(true);\n }}\n >{t(\"Change Password\")}</Button> :\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"old-password\" className=\"mb-1\">{t(\"Old password\")}</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n {...register(\"oldPassword\")}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">{t(\"Password\")}</Label>\n <PasswordInput\n id=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t(\"Repeat password\")}</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>{t(\"Change Password\")}</Button>\n </form>\n }\n </div>\n </div>\n );\n}\n\nfunction MfaSection() {\n const { t } = useTranslation();\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <div>\n <div>\n <Label>{t(\"Multi-factor Authentication\")}</Label>\n\n <div>\n {isEnabled ? (\n <Typography variant=\"success\">{t(\"Multi-factor authentication is currently enabled.\")}</Typography>\n ) : (\n generatedSecret ? (\n <div className='flex flex-col gap-4 items-center'>\n <Typography>{t(\"Scan this QR code with your authenticator app:\")}</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt={t(\"TOTP multi-factor authentication QR code\")} />\n <Typography>{t(\"Then, enter your six-digit MFA code:\")}</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">{t(\"Incorrect code. Please try again.\")}</Typography>\n )}\n </div>\n ) : (\n <Typography variant=\"destructive\">{t(\"Multi-factor authentication is currently disabled.\")}</Typography>\n )\n )}\n\n <Button\n className=\"mt-4\"\n variant={isEnabled ? 'secondary' : 'default'}\n onClick={async () => {\n if (isEnabled) {\n await user.update({\n totpMultiFactorSecret: null,\n });\n } else if (!generatedSecret) {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n } else {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }\n }}\n >\n {isEnabled ? t(\"Disable\") : (generatedSecret ? t(\"Cancel\") : t(\"Enable\"))}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction SignOutSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n return (\n <div className='flex flex-col gap-2'>\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >{t(\"Sign Out\")}</Button>\n </div>\n </div>\n );\n}\n\nfunction UserSettings(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <div className='flex flex-col gap-2'>\n <div>\n { !leaving ?\n <Button\n variant='secondary'\n onClick={async () => setLeaving(true)}\n >{t(\"Leave team\")}</Button> :\n <div className=''>\n <Typography variant='destructive'>{t(\"Are you sure you want to leave the team?\")}</Typography>\n <div className='flex gap-2'>\n <Button variant='destructive' onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}>{t(\"Leave\")}</Button>\n <Button variant='secondary' onClick={() => setLeaving(false)}>{t(\"Cancel\")}</Button>\n </div>\n </div>}\n </div>\n </div>\n );\n}\n\nfunction ManagementSettings(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <>\n <div className='flex flex-col'>\n <Label>{t(\"Team display name\")}</Label>\n <ProfileImageEditor\n user={props.team}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await props.team.update({ profileImageUrl });\n }}\n />\n </div>\n\n <div className='flex flex-col'>\n <Label>{t(\"Team display name\")}</Label>\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </div>\n </>\n );\n}\n\nfunction ProfileSettings(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <Label className=\"flex gap-2\">{t(\"User display name\")}<SimpleTooltip tooltip=\"This overwrites your user display name in the account setting\" type='info'/></Label>\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction MemberInvitation(props: { team: Team }) {\n const { t } = useTranslation();\n\n const invitationSchema = yupObject({\n email: yupString().email().required(t('Please enter an email address')),\n });\n\n const user = useUser({ or: 'redirect' });\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!inviteMemberPermission) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <div>\n <Label>{t(\"Invite a user to team\")}</Label>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex flex-col gap-4 md:flex-row\">\n <div>\n <Input\n placeholder={t(\"Email\")}\n {...register(\"email\")}\n />\n </div>\n <Button type=\"submit\" loading={loading}>{t(\"Invite User\")}</Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </div>\n );\n}\n\n\nfunction MembersSettings(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Label>{t(\"Members\")}</Label>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">{t(\"User\")}</TableHead>\n <TableHead className=\"w-[200px]\">{t(\"Name\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n}\n\nexport function TeamCreation() {\n const { t } = useTranslation();\n\n const teamCreationSchema = yupObject({\n displayName: yupString().required(t(\"Please enter a team name\")),\n });\n\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title={t(\"Team creation is not enabled\")} />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n try {\n const team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className='stack-scope flex flex-col items-stretch'>\n <div className=\"mb-6\">\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex items-end gap-4\">\n <div>\n <Label htmlFor=\"email\" className=\"mb-1\">{t(\"Display name\")}</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register(\"displayName\")}\n />\n </div>\n <FormWarningText text={errors.displayName?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>{t(\"Create\")}</Button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}