@stackframe/stack 2.5.33 → 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 (148) hide show
  1. package/CHANGELOG.md +40 -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/elements/sidebar-layout.js +15 -7
  11. package/dist/components/elements/sidebar-layout.js.map +1 -1
  12. package/dist/components/elements/user-avatar.js +1 -1
  13. package/dist/components/elements/user-avatar.js.map +1 -1
  14. package/dist/components/magic-link-sign-in.js +11 -9
  15. package/dist/components/magic-link-sign-in.js.map +1 -1
  16. package/dist/components/message-cards/message-card.d.mts +2 -2
  17. package/dist/components/message-cards/message-card.d.ts +2 -2
  18. package/dist/components/oauth-button-group.js.map +1 -1
  19. package/dist/components/oauth-button.js +46 -2
  20. package/dist/components/oauth-button.js.map +1 -1
  21. package/dist/components/profile-image-editor.js +7 -5
  22. package/dist/components/profile-image-editor.js.map +1 -1
  23. package/dist/components/selected-team-switcher.js +7 -4
  24. package/dist/components/selected-team-switcher.js.map +1 -1
  25. package/dist/components/team-icon.js.map +1 -1
  26. package/dist/components/user-button.d.mts +2 -2
  27. package/dist/components/user-button.d.ts +2 -2
  28. package/dist/components/user-button.js +11 -11
  29. package/dist/components/user-button.js.map +1 -1
  30. package/dist/components-page/account-settings.d.mts +4 -2
  31. package/dist/components-page/account-settings.d.ts +4 -2
  32. package/dist/components-page/account-settings.js +406 -221
  33. package/dist/components-page/account-settings.js.map +1 -1
  34. package/dist/components-page/auth-page.js +11 -7
  35. package/dist/components-page/auth-page.js.map +1 -1
  36. package/dist/components-page/email-verification.js +4 -2
  37. package/dist/components-page/email-verification.js.map +1 -1
  38. package/dist/components-page/error-page.js +6 -4
  39. package/dist/components-page/error-page.js.map +1 -1
  40. package/dist/components-page/forgot-password.js +12 -8
  41. package/dist/components-page/forgot-password.js.map +1 -1
  42. package/dist/components-page/magic-link-callback.js +5 -3
  43. package/dist/components-page/magic-link-callback.js.map +1 -1
  44. package/dist/components-page/oauth-callback.js +6 -5
  45. package/dist/components-page/oauth-callback.js.map +1 -1
  46. package/dist/components-page/password-reset.js +25 -22
  47. package/dist/components-page/password-reset.js.map +1 -1
  48. package/dist/components-page/stack-handler.d.mts +1 -0
  49. package/dist/components-page/stack-handler.d.ts +1 -0
  50. package/dist/components-page/team-creation.js +9 -7
  51. package/dist/components-page/team-creation.js.map +1 -1
  52. package/dist/components-page/team-invitation.js +14 -11
  53. package/dist/components-page/team-invitation.js.map +1 -1
  54. package/dist/esm/components/credential-sign-in.js +14 -12
  55. package/dist/esm/components/credential-sign-in.js.map +1 -1
  56. package/dist/esm/components/credential-sign-up.js +17 -15
  57. package/dist/esm/components/credential-sign-up.js.map +1 -1
  58. package/dist/esm/components/elements/sidebar-layout.js +15 -7
  59. package/dist/esm/components/elements/sidebar-layout.js.map +1 -1
  60. package/dist/esm/components/elements/user-avatar.js +1 -1
  61. package/dist/esm/components/elements/user-avatar.js.map +1 -1
  62. package/dist/esm/components/magic-link-sign-in.js +11 -9
  63. package/dist/esm/components/magic-link-sign-in.js.map +1 -1
  64. package/dist/esm/components/oauth-button-group.js.map +1 -1
  65. package/dist/esm/components/oauth-button.js +46 -2
  66. package/dist/esm/components/oauth-button.js.map +1 -1
  67. package/dist/esm/components/profile-image-editor.js +7 -5
  68. package/dist/esm/components/profile-image-editor.js.map +1 -1
  69. package/dist/esm/components/selected-team-switcher.js +7 -4
  70. package/dist/esm/components/selected-team-switcher.js.map +1 -1
  71. package/dist/esm/components/team-icon.js.map +1 -1
  72. package/dist/esm/components/user-button.js +12 -15
  73. package/dist/esm/components/user-button.js.map +1 -1
  74. package/dist/esm/components-page/account-settings.js +406 -222
  75. package/dist/esm/components-page/account-settings.js.map +1 -1
  76. package/dist/esm/components-page/auth-page.js +11 -7
  77. package/dist/esm/components-page/auth-page.js.map +1 -1
  78. package/dist/esm/components-page/email-verification.js +4 -2
  79. package/dist/esm/components-page/email-verification.js.map +1 -1
  80. package/dist/esm/components-page/error-page.js +6 -4
  81. package/dist/esm/components-page/error-page.js.map +1 -1
  82. package/dist/esm/components-page/forgot-password.js +12 -8
  83. package/dist/esm/components-page/forgot-password.js.map +1 -1
  84. package/dist/esm/components-page/magic-link-callback.js +5 -3
  85. package/dist/esm/components-page/magic-link-callback.js.map +1 -1
  86. package/dist/esm/components-page/oauth-callback.js +6 -5
  87. package/dist/esm/components-page/oauth-callback.js.map +1 -1
  88. package/dist/esm/components-page/password-reset.js +25 -22
  89. package/dist/esm/components-page/password-reset.js.map +1 -1
  90. package/dist/esm/components-page/team-creation.js +9 -7
  91. package/dist/esm/components-page/team-creation.js.map +1 -1
  92. package/dist/esm/components-page/team-invitation.js +14 -11
  93. package/dist/esm/components-page/team-invitation.js.map +1 -1
  94. package/dist/esm/generated/global-css.js +1 -1
  95. package/dist/esm/generated/global-css.js.map +1 -1
  96. package/dist/esm/generated/quetzal-translations.js +1629 -0
  97. package/dist/esm/generated/quetzal-translations.js.map +1 -0
  98. package/dist/esm/lib/stack-app.js +8 -1
  99. package/dist/esm/lib/stack-app.js.map +1 -1
  100. package/dist/esm/lib/translations.js +20 -0
  101. package/dist/esm/lib/translations.js.map +1 -0
  102. package/dist/esm/providers/stack-provider.js +4 -2
  103. package/dist/esm/providers/stack-provider.js.map +1 -1
  104. package/dist/esm/providers/theme-provider.js.map +1 -1
  105. package/dist/esm/providers/translation-provider-client.js +18 -0
  106. package/dist/esm/providers/translation-provider-client.js.map +1 -0
  107. package/dist/esm/providers/translation-provider.js +12 -0
  108. package/dist/esm/providers/translation-provider.js.map +1 -0
  109. package/dist/esm/utils/browser-script.js +43 -8
  110. package/dist/esm/utils/browser-script.js.map +1 -1
  111. package/dist/generated/global-css.d.mts +1 -1
  112. package/dist/generated/global-css.d.ts +1 -1
  113. package/dist/generated/global-css.js +1 -1
  114. package/dist/generated/global-css.js.map +1 -1
  115. package/dist/generated/quetzal-translations.d.mts +4 -0
  116. package/dist/generated/quetzal-translations.d.ts +4 -0
  117. package/dist/generated/quetzal-translations.js +1655 -0
  118. package/dist/generated/quetzal-translations.js.map +1 -0
  119. package/dist/index.d.mts +2 -0
  120. package/dist/index.d.ts +2 -0
  121. package/dist/lib/stack-app.d.mts +4 -1
  122. package/dist/lib/stack-app.d.ts +4 -1
  123. package/dist/lib/stack-app.js +8 -1
  124. package/dist/lib/stack-app.js.map +1 -1
  125. package/dist/lib/translations.d.mts +5 -0
  126. package/dist/lib/translations.d.ts +5 -0
  127. package/dist/lib/translations.js +55 -0
  128. package/dist/lib/translations.js.map +1 -0
  129. package/dist/providers/stack-provider-client.d.mts +3 -3
  130. package/dist/providers/stack-provider-client.d.ts +3 -3
  131. package/dist/providers/stack-provider.d.mts +6 -3
  132. package/dist/providers/stack-provider.d.ts +6 -3
  133. package/dist/providers/stack-provider.js +4 -2
  134. package/dist/providers/stack-provider.js.map +1 -1
  135. package/dist/providers/theme-provider.d.mts +2 -2
  136. package/dist/providers/theme-provider.d.ts +2 -2
  137. package/dist/providers/theme-provider.js.map +1 -1
  138. package/dist/providers/translation-provider-client.d.mts +14 -0
  139. package/dist/providers/translation-provider-client.d.ts +14 -0
  140. package/dist/providers/translation-provider-client.js +43 -0
  141. package/dist/providers/translation-provider-client.js.map +1 -0
  142. package/dist/providers/translation-provider.d.mts +9 -0
  143. package/dist/providers/translation-provider.d.ts +9 -0
  144. package/dist/providers/translation-provider.js +37 -0
  145. package/dist/providers/translation-provider.js.map +1 -0
  146. package/dist/utils/browser-script.js +43 -8
  147. package/dist/utils/browser-script.js.map +1 -1
  148. package/package.json +20 -12
@@ -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,18 +48,20 @@ 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");
61
+ var import_translations = require("../lib/translations");
60
62
  var import_jsx_runtime = require("react/jsx-runtime");
61
63
  function AccountSettings(props) {
64
+ const { t } = (0, import_translations.useTranslation)();
62
65
  const user = (0, import__.useUser)({ or: "redirect" });
63
66
  const teams = user.useTeams();
64
67
  const stackApp = (0, import__.useStackApp)();
@@ -68,29 +71,25 @@ function AccountSettings(props) {
68
71
  {
69
72
  items: [
70
73
  {
71
- title: "My Profile",
74
+ title: t("My Profile"),
72
75
  type: "item",
73
76
  subpath: "/profile",
74
77
  icon: import_lucide_react.Contact,
75
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfileSection, {})
78
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfilePage, {})
76
79
  },
77
80
  {
78
- title: "Security",
81
+ title: t("Security"),
79
82
  type: "item",
80
- icon: import_lucide_react.ShieldCheck,
81
83
  subpath: "/security",
82
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
83
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmailVerificationSection, {}),
84
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PasswordSection, {}),
85
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MfaSection, {})
86
- ] })
84
+ icon: import_lucide_react.ShieldCheck,
85
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SecurityPage, {})
87
86
  },
88
87
  {
89
- title: "Sign Out",
90
- subpath: "/sign-out",
88
+ title: t("Settings"),
91
89
  type: "item",
92
- icon: import_lucide_react.LogOut,
93
- 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, {})
94
93
  },
95
94
  ...props.extraItems?.map((item) => ({
96
95
  title: item.title,
@@ -100,7 +99,7 @@ function AccountSettings(props) {
100
99
  content: item.content
101
100
  })) || [],
102
101
  ...teams.length > 0 || project.config.clientTeamCreationEnabled ? [{
103
- title: "Teams",
102
+ title: t("Teams"),
104
103
  type: "divider"
105
104
  }] : [],
106
105
  ...teams.map((team) => ({
@@ -110,61 +109,108 @@ function AccountSettings(props) {
110
109
  ] }),
111
110
  type: "item",
112
111
  subpath: `/teams/${team.id}`,
113
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
114
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProfileSettings, { team }),
115
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ManagementSettings, { team }),
116
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberInvitation, { team }),
117
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MembersSettings, { team }),
118
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserSettings, { team })
119
- ] })
112
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPage, { team })
120
113
  })),
121
114
  ...project.config.clientTeamCreationEnabled ? [{
122
- title: "Create a team",
115
+ title: t("Create a team"),
123
116
  icon: import_lucide_react.CirclePlus,
124
117
  type: "item",
125
118
  subpath: "/team-creation",
126
119
  content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreation, {})
127
120
  }] : []
128
121
  ].filter((p) => p.type === "divider" || p.content),
129
- title: "Account Settings",
122
+ title: t("Account Settings"),
130
123
  basePath: stackApp.urls.accountSettings
131
124
  }
132
125
  ) }) });
133
126
  }
134
- 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() {
146
+ const { t } = (0, import_translations.useTranslation)();
135
147
  const user = (0, import__.useUser)({ or: "redirect" });
136
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-8", children: [
137
- /* @__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" }),
139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
140
- import_profile_image_editor.ProfileImageEditor,
141
- {
142
- user,
143
- onProfileImageUrlChange: async (profileImageUrl) => {
144
- 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
+ }
145
161
  }
146
- }
147
- )
148
- ] }),
149
- /* @__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" }),
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.EditableText, { value: user.displayName || "", onSave: async (newDisplayName) => {
152
- await user.update({ displayName: newDisplayName });
153
- } })
154
- ] })
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
+ )
155
181
  ] });
156
182
  }
157
- 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() {
202
+ const { t } = (0, import_translations.useTranslation)();
158
203
  const user = (0, import__.useUser)({ or: "redirect" });
159
204
  const [emailSent, setEmailSent] = (0, import_react.useState)(false);
160
205
  if (!user.primaryEmail) {
161
206
  return null;
162
207
  }
163
- 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." }),
167
- /* @__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)(
168
214
  import_stack_ui.Button,
169
215
  {
170
216
  disabled: emailSent,
@@ -172,28 +218,29 @@ function EmailVerificationSection() {
172
218
  await user.sendVerificationEmail();
173
219
  setEmailSent(true);
174
220
  },
175
- children: emailSent ? "Email sent!" : "Send Verification Email"
221
+ children: emailSent ? t("Email sent!") : t("Send Verification Email")
176
222
  }
177
- ) })
178
- ] })
179
- ] }) });
223
+ ) }) })
224
+ }
225
+ );
180
226
  }
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;
227
+ function usePasswordSection() {
228
+ const { t } = (0, import_translations.useTranslation)();
229
+ const passwordSchema = (0, import_schema_fields.yupObject)({
230
+ oldPassword: (0, import_schema_fields.yupString)().required(t("Please enter your old password")),
231
+ newPassword: (0, import_schema_fields.yupString)().required(t("Please enter your password")).test({
232
+ name: "is-valid-password",
233
+ test: (value, ctx) => {
234
+ const error = (0, import_password.getPasswordError)(value);
235
+ if (error) {
236
+ return ctx.createError({ message: error.message });
237
+ } else {
238
+ return true;
239
+ }
191
240
  }
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
- function PasswordSection() {
241
+ }),
242
+ newPasswordRepeat: (0, import_schema_fields.yupString)().nullable().oneOf([yup.ref("newPassword"), "", null], t("Passwords do not match")).required(t("Please repeat your password"))
243
+ });
197
244
  const user = (0, import__.useUser)({ or: "throw" });
198
245
  const [changingPassword, setChangingPassword] = (0, import_react.useState)(false);
199
246
  const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = (0, import_react_hook_form.useForm)({
@@ -207,7 +254,7 @@ function PasswordSection() {
207
254
  const { oldPassword, newPassword } = data;
208
255
  const error = await user.updatePassword({ oldPassword, newPassword });
209
256
  if (error) {
210
- setError("oldPassword", { type: "manual", message: "Incorrect password" });
257
+ setError("oldPassword", { type: "manual", message: t("Incorrect password") });
211
258
  } else {
212
259
  reset();
213
260
  setAlreadyReset(true);
@@ -222,15 +269,15 @@ function PasswordSection() {
222
269
  return null;
223
270
  }
224
271
  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)(
272
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: t("Change password") }),
273
+ /* @__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
274
  import_stack_ui.Button,
228
275
  {
229
276
  variant: "secondary",
230
277
  onClick: async () => {
231
278
  setChangingPassword(true);
232
279
  },
233
- children: "Change Password"
280
+ children: t("Change Password")
234
281
  }
235
282
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
236
283
  "form",
@@ -238,7 +285,7 @@ function PasswordSection() {
238
285
  onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
239
286
  noValidate: true,
240
287
  children: [
241
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "old-password", className: "mb-1", children: "Old password" }),
288
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "old-password", className: "mb-1", children: t("Old password") }),
242
289
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
243
290
  import_stack_ui.Input,
244
291
  {
@@ -248,7 +295,7 @@ function PasswordSection() {
248
295
  }
249
296
  ),
250
297
  /* @__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" }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "new-password", className: "mt-4 mb-1", children: t("Password") }),
252
299
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
253
300
  import_stack_ui.PasswordInput,
254
301
  {
@@ -262,7 +309,7 @@ function PasswordSection() {
262
309
  }
263
310
  ),
264
311
  /* @__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" }),
312
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "repeat-password", className: "mt-4 mb-1", children: t("Repeat password") }),
266
313
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
267
314
  import_stack_ui.PasswordInput,
268
315
  {
@@ -276,13 +323,14 @@ function PasswordSection() {
276
323
  }
277
324
  ),
278
325
  /* @__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" })
326
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", className: "mt-6", loading, children: t("Change Password") })
280
327
  ]
281
328
  }
282
329
  ) })
283
330
  ] });
284
331
  }
285
- function MfaSection() {
332
+ function useMfaSection() {
333
+ const { t } = (0, import_translations.useTranslation)();
286
334
  const project = (0, import__.useStackApp)().useProject();
287
335
  const user = (0, import__.useUser)({ or: "throw" });
288
336
  const [generatedSecret, setGeneratedSecret] = (0, import_react.useState)(null);
@@ -307,100 +355,165 @@ function MfaSection() {
307
355
  setIsMaybeWrong(true);
308
356
  });
309
357
  }, [mfaCode, generatedSecret, handleSubmit]);
310
- 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" }),
312
- /* @__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:" }),
317
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
318
- 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,
319
397
  {
320
- value: mfaCode,
321
- onChange: (e) => {
322
- setIsMaybeWrong(false);
323
- setMfaCode(e.target.value);
324
- },
325
- placeholder: "123456",
326
- maxLength: 6,
327
- disabled: isLoading
328
- }
329
- ),
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." }),
332
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
333
- import_stack_ui.Button,
334
- {
335
- className: "mt-4",
336
- variant: isEnabled ? "secondary" : "default",
337
- onClick: async () => {
338
- if (isEnabled) {
398
+ variant: "secondary",
399
+ onClick: async () => {
339
400
  await user.update({
340
401
  totpMultiFactorSecret: null
341
402
  });
342
- } 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 () => {
343
411
  const secret = (0, import_crypto.generateRandomValues)(new Uint8Array(20));
344
412
  setQrCodeUrl(await generateTotpQrCode(project, user, secret));
345
413
  setGeneratedSecret(secret);
346
- } else {
347
- setGeneratedSecret(null);
348
- setQrCodeUrl(null);
349
- setMfaCode("");
350
- }
351
- },
352
- children: isEnabled ? "Disable" : generatedSecret ? "Cancel" : "Enable"
353
- }
354
- )
355
- ] })
356
- ] }) });
414
+ },
415
+ children: t("Enable")
416
+ }
417
+ ) })
418
+ ] })
419
+ }
420
+ );
357
421
  }
358
422
  async function generateTotpQrCode(project, user, secret) {
359
423
  const uri = (0, import_otp.createTOTPKeyURI)(project.displayName, user.primaryEmail ?? user.id, secret);
360
424
  return await QRCode.toDataURL(uri);
361
425
  }
362
- function SignOutSection() {
426
+ function useSignOutSection() {
427
+ const { t } = (0, import_translations.useTranslation)();
363
428
  const user = (0, import__.useUser)({ or: "throw" });
364
- 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
- import_stack_ui.Button,
429
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
430
+ Section,
366
431
  {
367
- variant: "secondary",
368
- onClick: () => user.signOut(),
369
- children: "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
+ ) })
370
442
  }
371
- ) }) });
443
+ );
444
+ }
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
+ ] });
372
460
  }
373
- function UserSettings(props) {
461
+ function useLeaveTeamSection(props) {
462
+ const { t } = (0, import_translations.useTranslation)();
374
463
  const user = (0, import__.useUser)({ or: "redirect" });
375
464
  const [leaving, setLeaving] = (0, import_react.useState)(false);
376
- 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)(
377
- import_stack_ui.Button,
465
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
466
+ Section,
378
467
  {
379
- variant: "secondary",
380
- onClick: async () => setLeaving(true),
381
- children: "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
+ ] })
382
501
  }
383
- ) : /* @__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?" }),
385
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
386
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "destructive", onClick: async () => {
387
- await user.leaveTeam(props.team);
388
- window.location.reload();
389
- }, children: "Leave" }),
390
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "secondary", onClick: () => setLeaving(false), children: "Cancel" })
391
- ] })
392
- ] }) }) });
502
+ );
393
503
  }
394
- function ManagementSettings(props) {
504
+ function useTeamProfileImageSection(props) {
505
+ const { t } = (0, import_translations.useTranslation)();
395
506
  const user = (0, import__.useUser)({ or: "redirect" });
396
507
  const updateTeamPermission = user.usePermission(props.team, "$update_team");
397
508
  if (!updateTeamPermission) {
398
509
  return null;
399
510
  }
400
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
401
- /* @__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" }),
403
- /* @__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)(
404
517
  import_profile_image_editor.ProfileImageEditor,
405
518
  {
406
519
  user: props.team,
@@ -409,42 +522,57 @@ function ManagementSettings(props) {
409
522
  }
410
523
  }
411
524
  )
412
- ] }),
413
- /* @__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" }),
415
- /* @__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)(
416
541
  import_stack_ui.EditableText,
417
542
  {
418
543
  value: props.team.displayName,
419
544
  onSave: async (newDisplayName) => await props.team.update({ displayName: newDisplayName })
420
545
  }
421
546
  )
422
- ] })
423
- ] });
547
+ }
548
+ );
424
549
  }
425
- function ProfileSettings(props) {
550
+ function useTeamUserProfileSection(props) {
551
+ const { t } = (0, import_translations.useTranslation)();
426
552
  const user = (0, import__.useUser)({ or: "redirect" });
427
553
  const profile = user.useTeamProfile(props.team);
428
- 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
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Label, { className: "flex gap-2", children: [
430
- "User display name ",
431
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SimpleTooltip, { tooltip: "This overwrites your user display name in the account setting", type: "info" })
432
- ] }),
433
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
434
- import_stack_ui.EditableText,
435
- {
436
- value: profile.displayName || "",
437
- onSave: async (newDisplayName) => {
438
- 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
+ }
439
566
  }
440
- }
441
- )
442
- ] }) });
567
+ )
568
+ }
569
+ );
443
570
  }
444
- var invitationSchema = (0, import_schema_fields.yupObject)({
445
- email: (0, import_schema_fields.yupString)().email().required("Please enter an email address")
446
- });
447
- function MemberInvitation(props) {
571
+ function useMemberInvitationSection(props) {
572
+ const { t } = (0, import_translations.useTranslation)();
573
+ const invitationSchema = (0, import_schema_fields.yupObject)({
574
+ email: (0, import_schema_fields.yupString)().email().required(t("Please enter an email address"))
575
+ });
448
576
  const user = (0, import__.useUser)({ or: "redirect" });
449
577
  const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
450
578
  if (!inviteMemberPermission) {
@@ -467,35 +595,40 @@ function MemberInvitation(props) {
467
595
  (0, import_react.useEffect)(() => {
468
596
  setInvitedEmail(null);
469
597
  }, [watch("email")]);
470
- 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" }),
472
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
473
- "form",
474
- {
475
- onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
476
- noValidate: true,
477
- children: [
478
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4 md:flex-row", children: [
479
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
480
- import_stack_ui.Input,
481
- {
482
- placeholder: "Email",
483
- ...register("email")
484
- }
485
- ) }),
486
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: "Invite User" })
487
- ] }),
488
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.email?.message?.toString() }),
489
- invitedEmail && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { type: "label", variant: "secondary", children: [
490
- "Invited ",
491
- invitedEmail
492
- ] })
493
- ]
494
- }
495
- )
496
- ] });
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
+ );
497
629
  }
498
- function MembersSettings(props) {
630
+ function useMemberListSection(props) {
631
+ const { t } = (0, import_translations.useTranslation)();
499
632
  const user = (0, import__.useUser)({ or: "redirect" });
500
633
  const readMemberPermission = user.usePermission(props.team, "$read_members");
501
634
  const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
@@ -507,23 +640,24 @@ function MembersSettings(props) {
507
640
  return null;
508
641
  }
509
642
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
510
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { children: "Members" }),
511
- /* @__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: [
512
645
  /* @__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" })
646
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[100px]", children: t("User") }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[200px]", children: t("Name") })
515
648
  ] }) }),
516
649
  /* @__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
650
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_user_avatar.UserAvatar, { user: teamProfile }) }),
518
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 }) })
519
652
  ] }, id)) })
520
- ] })
653
+ ] }) })
521
654
  ] });
522
655
  }
523
- var teamCreationSchema = (0, import_schema_fields.yupObject)({
524
- displayName: (0, import_schema_fields.yupString)().required("Please enter a team name")
525
- });
526
656
  function TeamCreation() {
657
+ const { t } = (0, import_translations.useTranslation)();
658
+ const teamCreationSchema = (0, import_schema_fields.yupObject)({
659
+ displayName: (0, import_schema_fields.yupString)().required(t("Please enter a team name"))
660
+ });
527
661
  const { register, handleSubmit, formState: { errors } } = (0, import_react_hook_form.useForm)({
528
662
  resolver: (0, import_yup.yupResolver)(teamCreationSchema)
529
663
  });
@@ -532,7 +666,7 @@ function TeamCreation() {
532
666
  const user = (0, import__.useUser)({ or: "redirect" });
533
667
  const [loading, setLoading] = (0, import_react.useState)(false);
534
668
  if (!project.config.clientTeamCreationEnabled) {
535
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import__.MessageCard, { title: "Team creation is not enabled" });
669
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import__.MessageCard, { title: t("Team creation is not enabled") });
536
670
  }
537
671
  const onSubmit = async (data) => {
538
672
  setLoading(true);
@@ -542,33 +676,84 @@ function TeamCreation() {
542
676
  setLoading(false);
543
677
  }
544
678
  };
545
- 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)(
546
680
  "form",
547
681
  {
548
- className: "flex flex-col items-stretch stack-scope",
549
682
  onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
550
683
  noValidate: true,
551
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-end gap-4", children: [
552
- /* @__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" }),
684
+ className: "flex gap-2",
685
+ children: [
686
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col flex-1", children: [
554
687
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
555
688
  import_stack_ui.Input,
556
689
  {
557
- id: "email",
558
- type: "email",
690
+ id: "displayName",
691
+ type: "text",
559
692
  ...register("displayName")
560
693
  }
561
- )
694
+ ),
695
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.displayName?.message?.toString() })
562
696
  ] }),
563
- /* @__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" })
565
- ] })
697
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Create") })
698
+ ]
566
699
  }
567
700
  ) }) });
568
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
+ }
569
753
  // Annotate the CommonJS export names for ESM import in node:
570
754
  0 && (module.exports = {
571
755
  AccountSettings,
572
- TeamCreation
756
+ TeamCreation,
757
+ useDeleteAccountSection
573
758
  });
574
759
  //# sourceMappingURL=account-settings.js.map