@workos-inc/widgets 1.7.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/cjs/api/endpoint.cjs +1 -0
- package/dist/cjs/api/endpoint.cjs.map +1 -1
- package/dist/cjs/api/endpoint.d.cts +1 -0
- package/dist/cjs/index.cjs +5 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/lib/add-mfa-dialog.cjs +133 -61
- package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-domain-verification.cjs +41 -5
- package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-sso-connection.cjs +121 -44
- package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-key-details-card.cjs +25 -3
- package/dist/cjs/lib/api-keys/api-key-details-card.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-key-details-dialog.cjs +25 -3
- package/dist/cjs/lib/api-keys/api-key-details-dialog.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys-search.cjs +13 -4
- package/dist/cjs/lib/api-keys/api-keys-search.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys-table.cjs +94 -12
- package/dist/cjs/lib/api-keys/api-keys-table.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/api-keys.cjs +16 -2
- package/dist/cjs/lib/api-keys/api-keys.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/create-api-key.cjs +172 -20
- package/dist/cjs/lib/api-keys/create-api-key.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/relative-time.cjs +12 -2
- package/dist/cjs/lib/api-keys/relative-time.cjs.map +1 -1
- package/dist/cjs/lib/api-keys/revoke-api-key-dialog.cjs +49 -7
- package/dist/cjs/lib/api-keys/revoke-api-key-dialog.cjs.map +1 -1
- package/dist/cjs/lib/change-password-dialog.cjs +122 -16
- package/dist/cjs/lib/change-password-dialog.cjs.map +1 -1
- package/dist/cjs/lib/copy-button.cjs +14 -2
- package/dist/cjs/lib/copy-button.cjs.map +1 -1
- package/dist/cjs/lib/copy-button.d.cts +2 -1
- package/dist/cjs/lib/delete-domain-dialog.cjs +52 -19
- package/dist/cjs/lib/delete-domain-dialog.cjs.map +1 -1
- package/dist/cjs/lib/delete-user-dialog.cjs +46 -11
- package/dist/cjs/lib/delete-user-dialog.cjs.map +1 -1
- package/dist/cjs/lib/delete-user-dialog.d.cts +2 -2
- package/dist/cjs/lib/domain-actions.cjs +51 -7
- package/dist/cjs/lib/domain-actions.cjs.map +1 -1
- package/dist/cjs/lib/domain-item.cjs +42 -8
- package/dist/cjs/lib/domain-item.cjs.map +1 -1
- package/dist/cjs/lib/edit-user-profile-dialog.cjs +62 -11
- package/dist/cjs/lib/edit-user-profile-dialog.cjs.map +1 -1
- package/dist/cjs/lib/edit-user-role-dialog.cjs +90 -17
- package/dist/cjs/lib/edit-user-role-dialog.cjs.map +1 -1
- package/dist/cjs/lib/elements.cjs +14 -3
- package/dist/cjs/lib/elements.cjs.map +1 -1
- package/dist/cjs/lib/elements.d.cts +5 -2
- package/dist/cjs/lib/elevated-access.cjs +78 -18
- package/dist/cjs/lib/elevated-access.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.cjs +53 -11
- package/dist/cjs/lib/generic-error.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.d.cts +5 -1
- package/dist/cjs/lib/i18n/intl-context.cjs +47 -0
- package/dist/cjs/lib/i18n/intl-context.cjs.map +1 -0
- package/dist/cjs/lib/i18n/intl-context.d.cts +29 -0
- package/dist/cjs/lib/i18n/translation.cjs +67 -0
- package/dist/cjs/lib/i18n/translation.cjs.map +1 -0
- package/dist/cjs/lib/i18n/translation.d.cts +16 -0
- package/dist/cjs/lib/i18n/use-locale.cjs +33 -0
- package/dist/cjs/lib/i18n/use-locale.cjs.map +1 -0
- package/dist/cjs/lib/i18n/use-locale.d.cts +7 -0
- package/dist/cjs/lib/i18n/use-translation.cjs +47 -0
- package/dist/cjs/lib/i18n/use-translation.cjs.map +1 -0
- package/dist/cjs/lib/i18n/use-translation.d.cts +15 -0
- package/dist/cjs/lib/identity-providers.d.cts +1 -1
- package/dist/cjs/lib/invite-user-dialog.cjs +69 -14
- package/dist/cjs/lib/invite-user-dialog.cjs.map +1 -1
- package/dist/cjs/lib/logout-all-sessions-dialog.cjs +33 -4
- package/dist/cjs/lib/logout-all-sessions-dialog.cjs.map +1 -1
- package/dist/cjs/lib/logout-dialog.cjs +34 -10
- package/dist/cjs/lib/logout-dialog.cjs.map +1 -1
- package/dist/cjs/lib/organization-switcher.cjs +12 -2
- package/dist/cjs/lib/organization-switcher.cjs.map +1 -1
- package/dist/cjs/lib/pipes.cjs +175 -36
- package/dist/cjs/lib/pipes.cjs.map +1 -1
- package/dist/cjs/lib/resend-invite-dialog.cjs +67 -17
- package/dist/cjs/lib/resend-invite-dialog.cjs.map +1 -1
- package/dist/cjs/lib/reset-mfa-dialog.cjs +50 -7
- package/dist/cjs/lib/reset-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/revoke-invite-dialog.cjs +42 -10
- package/dist/cjs/lib/revoke-invite-dialog.cjs.map +1 -1
- package/dist/cjs/lib/save-button.cjs +9 -1
- package/dist/cjs/lib/save-button.cjs.map +1 -1
- package/dist/cjs/lib/set-password-dialog.cjs +101 -13
- package/dist/cjs/lib/set-password-dialog.cjs.map +1 -1
- package/dist/cjs/lib/user-actions-dropdown.cjs +54 -6
- package/dist/cjs/lib/user-actions-dropdown.cjs.map +1 -1
- package/dist/cjs/lib/user-profile.cjs +81 -10
- package/dist/cjs/lib/user-profile.cjs.map +1 -1
- package/dist/cjs/lib/user-security.cjs +127 -25
- package/dist/cjs/lib/user-security.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.cjs +74 -15
- package/dist/cjs/lib/user-sessions.cjs.map +1 -1
- package/dist/cjs/lib/users-management.cjs +265 -49
- package/dist/cjs/lib/users-management.cjs.map +1 -1
- package/dist/cjs/lib/users-search.cjs +18 -4
- package/dist/cjs/lib/users-search.cjs.map +1 -1
- package/dist/cjs/lib/utils.cjs +10 -7
- package/dist/cjs/lib/utils.cjs.map +1 -1
- package/dist/cjs/lib/utils.d.cts +2 -1
- package/dist/cjs/lib/view-dns-record-dialog.cjs +89 -18
- package/dist/cjs/lib/view-dns-record-dialog.cjs.map +1 -1
- package/dist/cjs/workos-widgets.client.cjs +2 -2
- package/dist/cjs/workos-widgets.client.cjs.map +1 -1
- package/dist/esm/api/endpoint.d.ts +1 -0
- package/dist/esm/api/endpoint.js +1 -0
- package/dist/esm/api/endpoint.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/add-mfa-dialog.js +133 -61
- package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/admin-portal-domain-verification.js +41 -5
- package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
- package/dist/esm/lib/admin-portal-sso-connection.js +121 -44
- package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
- package/dist/esm/lib/api-keys/api-key-details-card.js +25 -3
- package/dist/esm/lib/api-keys/api-key-details-card.js.map +1 -1
- package/dist/esm/lib/api-keys/api-key-details-dialog.js +25 -3
- package/dist/esm/lib/api-keys/api-key-details-dialog.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys-search.js +13 -4
- package/dist/esm/lib/api-keys/api-keys-search.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys-table.js +94 -12
- package/dist/esm/lib/api-keys/api-keys-table.js.map +1 -1
- package/dist/esm/lib/api-keys/api-keys.js +16 -2
- package/dist/esm/lib/api-keys/api-keys.js.map +1 -1
- package/dist/esm/lib/api-keys/create-api-key.js +172 -20
- package/dist/esm/lib/api-keys/create-api-key.js.map +1 -1
- package/dist/esm/lib/api-keys/relative-time.js +12 -2
- package/dist/esm/lib/api-keys/relative-time.js.map +1 -1
- package/dist/esm/lib/api-keys/revoke-api-key-dialog.js +49 -7
- package/dist/esm/lib/api-keys/revoke-api-key-dialog.js.map +1 -1
- package/dist/esm/lib/change-password-dialog.js +122 -16
- package/dist/esm/lib/change-password-dialog.js.map +1 -1
- package/dist/esm/lib/copy-button.d.ts +2 -1
- package/dist/esm/lib/copy-button.js +14 -2
- package/dist/esm/lib/copy-button.js.map +1 -1
- package/dist/esm/lib/delete-domain-dialog.js +52 -19
- package/dist/esm/lib/delete-domain-dialog.js.map +1 -1
- package/dist/esm/lib/delete-user-dialog.d.ts +2 -2
- package/dist/esm/lib/delete-user-dialog.js +36 -11
- package/dist/esm/lib/delete-user-dialog.js.map +1 -1
- package/dist/esm/lib/domain-actions.js +41 -7
- package/dist/esm/lib/domain-actions.js.map +1 -1
- package/dist/esm/lib/domain-item.js +42 -8
- package/dist/esm/lib/domain-item.js.map +1 -1
- package/dist/esm/lib/edit-user-profile-dialog.js +62 -11
- package/dist/esm/lib/edit-user-profile-dialog.js.map +1 -1
- package/dist/esm/lib/edit-user-role-dialog.js +90 -17
- package/dist/esm/lib/edit-user-role-dialog.js.map +1 -1
- package/dist/esm/lib/elements.d.ts +5 -2
- package/dist/esm/lib/elements.js +14 -3
- package/dist/esm/lib/elements.js.map +1 -1
- package/dist/esm/lib/elevated-access.js +78 -18
- package/dist/esm/lib/elevated-access.js.map +1 -1
- package/dist/esm/lib/generic-error.d.ts +5 -1
- package/dist/esm/lib/generic-error.js +53 -11
- package/dist/esm/lib/generic-error.js.map +1 -1
- package/dist/esm/lib/i18n/intl-context.d.ts +29 -0
- package/dist/esm/lib/i18n/intl-context.js +12 -0
- package/dist/esm/lib/i18n/intl-context.js.map +1 -0
- package/dist/esm/lib/i18n/translation.d.ts +16 -0
- package/dist/esm/lib/i18n/translation.js +45 -0
- package/dist/esm/lib/i18n/translation.js.map +1 -0
- package/dist/esm/lib/i18n/use-locale.d.ts +7 -0
- package/dist/esm/lib/i18n/use-locale.js +9 -0
- package/dist/esm/lib/i18n/use-locale.js.map +1 -0
- package/dist/esm/lib/i18n/use-translation.d.ts +15 -0
- package/dist/esm/lib/i18n/use-translation.js +23 -0
- package/dist/esm/lib/i18n/use-translation.js.map +1 -0
- package/dist/esm/lib/identity-providers.d.ts +1 -1
- package/dist/esm/lib/invite-user-dialog.js +70 -15
- package/dist/esm/lib/invite-user-dialog.js.map +1 -1
- package/dist/esm/lib/logout-all-sessions-dialog.js +33 -4
- package/dist/esm/lib/logout-all-sessions-dialog.js.map +1 -1
- package/dist/esm/lib/logout-dialog.js +34 -10
- package/dist/esm/lib/logout-dialog.js.map +1 -1
- package/dist/esm/lib/organization-switcher.js +12 -2
- package/dist/esm/lib/organization-switcher.js.map +1 -1
- package/dist/esm/lib/pipes.js +175 -36
- package/dist/esm/lib/pipes.js.map +1 -1
- package/dist/esm/lib/resend-invite-dialog.js +67 -17
- package/dist/esm/lib/resend-invite-dialog.js.map +1 -1
- package/dist/esm/lib/reset-mfa-dialog.js +50 -7
- package/dist/esm/lib/reset-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/revoke-invite-dialog.js +42 -10
- package/dist/esm/lib/revoke-invite-dialog.js.map +1 -1
- package/dist/esm/lib/save-button.js +9 -1
- package/dist/esm/lib/save-button.js.map +1 -1
- package/dist/esm/lib/set-password-dialog.js +101 -13
- package/dist/esm/lib/set-password-dialog.js.map +1 -1
- package/dist/esm/lib/user-actions-dropdown.js +54 -6
- package/dist/esm/lib/user-actions-dropdown.js.map +1 -1
- package/dist/esm/lib/user-profile.js +81 -10
- package/dist/esm/lib/user-profile.js.map +1 -1
- package/dist/esm/lib/user-security.js +127 -25
- package/dist/esm/lib/user-security.js.map +1 -1
- package/dist/esm/lib/user-sessions.js +74 -15
- package/dist/esm/lib/user-sessions.js.map +1 -1
- package/dist/esm/lib/users-management.js +266 -51
- package/dist/esm/lib/users-management.js.map +1 -1
- package/dist/esm/lib/users-search.js +18 -4
- package/dist/esm/lib/users-search.js.map +1 -1
- package/dist/esm/lib/utils.d.ts +2 -1
- package/dist/esm/lib/utils.js +10 -7
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/lib/view-dns-record-dialog.js +89 -18
- package/dist/esm/lib/view-dns-record-dialog.js.map +1 -1
- package/dist/esm/workos-widgets.client.js +2 -2
- package/dist/esm/workos-widgets.client.js.map +1 -1
- package/package.json +11 -2
|
@@ -8,6 +8,7 @@ import { useSecuritySettings } from "./use-security-settings.js";
|
|
|
8
8
|
import { ElevatedAccess } from "./elevated-access.js";
|
|
9
9
|
import { SaveButton } from "./save-button.js";
|
|
10
10
|
import { useDialogClose } from "./use-dialog-close.js";
|
|
11
|
+
import { Translation } from "./i18n/translation.js";
|
|
11
12
|
function ResetMfaDialog({
|
|
12
13
|
children,
|
|
13
14
|
isPasswordSet,
|
|
@@ -35,11 +36,38 @@ function Content({
|
|
|
35
36
|
securitySettings.update("Mfa", false);
|
|
36
37
|
});
|
|
37
38
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38
|
-
/* @__PURE__ */ jsx(AlertDialog.Title, { children:
|
|
39
|
+
/* @__PURE__ */ jsx(AlertDialog.Title, { children: /* @__PURE__ */ jsx(
|
|
40
|
+
Translation,
|
|
41
|
+
{
|
|
42
|
+
defaultMessage: "Disable multi-factor authentication?",
|
|
43
|
+
id: "a4wDlZ",
|
|
44
|
+
description: "Dialog title asking to confirm disabling MFA"
|
|
45
|
+
}
|
|
46
|
+
) }),
|
|
39
47
|
/* @__PURE__ */ jsxs(AlertDialog.Description, { children: [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
/* @__PURE__ */ jsx(
|
|
49
|
+
Translation,
|
|
50
|
+
{
|
|
51
|
+
defaultMessage: "Turning off MFA will remove the additional layer of security on your account.",
|
|
52
|
+
id: "24huc/",
|
|
53
|
+
description: "Warning that disabling MFA reduces security"
|
|
54
|
+
}
|
|
55
|
+
),
|
|
56
|
+
isPasswordSet ? /* @__PURE__ */ jsx(
|
|
57
|
+
Translation,
|
|
58
|
+
{
|
|
59
|
+
defaultMessage: "We will only ask for your password during sign-in.",
|
|
60
|
+
id: "Z6coCJ",
|
|
61
|
+
description: "Explanation when password is set but MFA will be disabled"
|
|
62
|
+
}
|
|
63
|
+
) : /* @__PURE__ */ jsx(
|
|
64
|
+
Translation,
|
|
65
|
+
{
|
|
66
|
+
defaultMessage: "We will not ask for additional verification during sign-in.",
|
|
67
|
+
id: "4SH+qg",
|
|
68
|
+
description: "Explanation when no password set and MFA will be disabled"
|
|
69
|
+
}
|
|
70
|
+
)
|
|
43
71
|
] }),
|
|
44
72
|
/* @__PURE__ */ jsx(Flex, { gap: "3", justify: "end", mt: "5", asChild: true, children: /* @__PURE__ */ jsxs(
|
|
45
73
|
"form",
|
|
@@ -54,17 +82,32 @@ function Content({
|
|
|
54
82
|
{
|
|
55
83
|
variant: "secondary",
|
|
56
84
|
disabled: resetMfa.isPending || resetMfa.isSuccess,
|
|
57
|
-
children:
|
|
85
|
+
children: /* @__PURE__ */ jsx(
|
|
86
|
+
Translation,
|
|
87
|
+
{
|
|
88
|
+
defaultMessage: "Cancel",
|
|
89
|
+
id: "OdCEs1",
|
|
90
|
+
description: "Button to cancel disabling MFA"
|
|
91
|
+
}
|
|
92
|
+
)
|
|
58
93
|
}
|
|
59
94
|
) }),
|
|
60
95
|
/* @__PURE__ */ jsx(
|
|
61
96
|
SaveButton,
|
|
62
97
|
{
|
|
63
|
-
|
|
98
|
+
type: "submit",
|
|
64
99
|
loading: resetMfa.isPending,
|
|
65
100
|
done: resetMfa.isSuccess,
|
|
66
101
|
onDone: onClose,
|
|
67
|
-
|
|
102
|
+
variant: "destructive",
|
|
103
|
+
children: /* @__PURE__ */ jsx(
|
|
104
|
+
Translation,
|
|
105
|
+
{
|
|
106
|
+
defaultMessage: "Disable",
|
|
107
|
+
id: "uvxVJM",
|
|
108
|
+
description: "Button to confirm disabling MFA"
|
|
109
|
+
}
|
|
110
|
+
)
|
|
68
111
|
}
|
|
69
112
|
)
|
|
70
113
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/reset-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { useDeleteTotpFactors } from \"../api/endpoint.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface ResetMfaDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n isPasswordSet: boolean;\n}\n\nexport function ResetMfaDialog({\n children,\n isPasswordSet,\n ...props\n}: ResetMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <AlertDialog.Root {...props} open={open} onOpenChange={setOpen}>\n <AlertDialog.Trigger>{children}</AlertDialog.Trigger>\n\n <AlertDialog.Content maxWidth=\"480px\">\n <ElevatedAccess type=\"alert\">\n <Content onClose={handleClose} isPasswordSet={isPasswordSet} />\n </ElevatedAccess>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n\nfunction Content({\n onClose,\n isPasswordSet,\n}: {\n onClose: () => void;\n isPasswordSet: boolean;\n}) {\n const securitySettings = useSecuritySettings();\n const resetMfa = useDeleteTotpFactors();\n\n const onSubmitForm = () => {\n resetMfa.mutate();\n };\n\n useDialogClose(resetMfa.isSuccess, () => {\n securitySettings.update(\"Mfa\", false);\n });\n\n return (\n <>\n <AlertDialog.Title>\n Disable multi-factor authentication?\n </AlertDialog.Title>\n <AlertDialog.Description>\n Turning off MFA will remove the additional layer of security on your\n
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/reset-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { useDeleteTotpFactors } from \"../api/endpoint.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\nimport { Translation } from \"./i18n/translation.js\";\n\ninterface ResetMfaDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n isPasswordSet: boolean;\n}\n\nexport function ResetMfaDialog({\n children,\n isPasswordSet,\n ...props\n}: ResetMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <AlertDialog.Root {...props} open={open} onOpenChange={setOpen}>\n <AlertDialog.Trigger>{children}</AlertDialog.Trigger>\n\n <AlertDialog.Content maxWidth=\"480px\">\n <ElevatedAccess type=\"alert\">\n <Content onClose={handleClose} isPasswordSet={isPasswordSet} />\n </ElevatedAccess>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n\nfunction Content({\n onClose,\n isPasswordSet,\n}: {\n onClose: () => void;\n isPasswordSet: boolean;\n}) {\n const securitySettings = useSecuritySettings();\n const resetMfa = useDeleteTotpFactors();\n\n const onSubmitForm = () => {\n resetMfa.mutate();\n };\n\n useDialogClose(resetMfa.isSuccess, () => {\n securitySettings.update(\"Mfa\", false);\n });\n\n return (\n <>\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Disable multi-factor authentication?\"\n id=\"a4wDlZ\"\n description=\"Dialog title asking to confirm disabling MFA\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"Turning off MFA will remove the additional layer of security on your account.\"\n id=\"24huc/\"\n description=\"Warning that disabling MFA reduces security\"\n />\n {isPasswordSet ? (\n <Translation\n defaultMessage=\"We will only ask for your password during sign-in.\"\n id=\"Z6coCJ\"\n description=\"Explanation when password is set but MFA will be disabled\"\n />\n ) : (\n <Translation\n defaultMessage=\"We will not ask for additional verification during sign-in.\"\n id=\"4SH+qg\"\n description=\"Explanation when no password set and MFA will be disabled\"\n />\n )}\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={resetMfa.isPending || resetMfa.isSuccess}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"OdCEs1\"\n description=\"Button to cancel disabling MFA\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n type=\"submit\"\n loading={resetMfa.isPending}\n done={resetMfa.isSuccess}\n onDone={onClose}\n variant=\"destructive\"\n >\n <Translation\n defaultMessage=\"Disable\"\n id=\"uvxVJM\"\n description=\"Button to confirm disabling MFA\"\n />\n </SaveButton>\n </form>\n </Flex>\n </>\n );\n}\n"],"mappings":";AA8BI,SA+BA,UA9BE,KADF;AA5BJ,YAAY,WAAW;AACvB,SAAS,YAAY;AAErB,SAAS,aAAa,cAAc;AACpC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAOrB,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAwB;AACtB,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAE5C,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,YAAQ,KAAK;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,SACE,qBAAC,YAAY,MAAZ,EAAkB,GAAG,OAAO,MAAY,cAAc,SACrD;AAAA,wBAAC,YAAY,SAAZ,EAAqB,UAAS;AAAA,IAE/B,oBAAC,YAAY,SAAZ,EAAoB,UAAS,SAC5B,8BAAC,kBAAe,MAAK,SACnB,8BAAC,WAAQ,SAAS,aAAa,eAA8B,GAC/D,GACF;AAAA,KACF;AAEJ;AAEA,SAAS,QAAQ;AAAA,EACf;AAAA,EACA;AACF,GAGG;AACD,QAAM,mBAAmB,oBAAoB;AAC7C,QAAM,WAAW,qBAAqB;AAEtC,QAAM,eAAe,MAAM;AACzB,aAAS,OAAO;AAAA,EAClB;AAEA,iBAAe,SAAS,WAAW,MAAM;AACvC,qBAAiB,OAAO,OAAO,KAAK;AAAA,EACtC,CAAC;AAED,SACE,iCACE;AAAA,wBAAC,YAAY,OAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACA,qBAAC,YAAY,aAAZ,EACC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,MACC,gBACC;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,IAEA;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd;AAAA,OAEJ;AAAA,IAEA,oBAAC,QAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,8BAAC,YAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UAAU,SAAS,aAAa,SAAS;AAAA,cAEzC;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd;AAAA;AAAA,UACF,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,SAAS;AAAA,cAClB,MAAM,SAAS;AAAA,cACf,QAAQ;AAAA,cACR,SAAQ;AAAA,cAER;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -4,6 +4,7 @@ import { Callout, Flex, Text, VisuallyHidden } from "@radix-ui/themes";
|
|
|
4
4
|
import { useRef } from "react";
|
|
5
5
|
import { useRevokeUserInvite } from "./api/user.js";
|
|
6
6
|
import { AlertDialog, Button } from "./elements.js";
|
|
7
|
+
import { Translation } from "./i18n/translation.js";
|
|
7
8
|
function RevokeInviteDialog({
|
|
8
9
|
children,
|
|
9
10
|
user,
|
|
@@ -33,13 +34,23 @@ function RevokeInviteDialog({
|
|
|
33
34
|
});
|
|
34
35
|
},
|
|
35
36
|
children: [
|
|
36
|
-
/* @__PURE__ */ jsx(AlertDialog.Title, { children:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
/* @__PURE__ */ jsx(AlertDialog.Title, { children: /* @__PURE__ */ jsx(
|
|
38
|
+
Translation,
|
|
39
|
+
{
|
|
40
|
+
defaultMessage: "Revoke invite?",
|
|
41
|
+
id: "/fEPAD",
|
|
42
|
+
description: "Dialog title asking to confirm revoking an invitation"
|
|
43
|
+
}
|
|
44
|
+
) }),
|
|
45
|
+
/* @__PURE__ */ jsx(Flex, { mb: "4", direction: "column", gap: "3", children: /* @__PURE__ */ jsx(AlertDialog.Description, { children: /* @__PURE__ */ jsx(
|
|
46
|
+
Translation,
|
|
47
|
+
{
|
|
48
|
+
defaultMessage: "Are you sure you want to revoke the invite to {email}? This action is immediate and cannot be undone.",
|
|
49
|
+
id: "wt2qe9",
|
|
50
|
+
description: "Warning message about revoking invite to specific email",
|
|
51
|
+
values: { email: /* @__PURE__ */ jsx(Text, { weight: "bold", children: user.email }) }
|
|
52
|
+
}
|
|
53
|
+
) }) }),
|
|
43
54
|
revokeInvite.error ? /* @__PURE__ */ jsx(Callout.Root, { color: "red", mt: "4", mb: "-2", children: /* @__PURE__ */ jsx(Callout.Text, { children: getMutationErrorMessage(revokeInvite.error) }) }) : null,
|
|
44
55
|
/* @__PURE__ */ jsx(Flex, { gap: "3", justify: "end", mt: "5", asChild: true, children: /* @__PURE__ */ jsxs(
|
|
45
56
|
"form",
|
|
@@ -55,7 +66,14 @@ function RevokeInviteDialog({
|
|
|
55
66
|
variant: "secondary",
|
|
56
67
|
ref: cancelButtonRef,
|
|
57
68
|
disabled: revokeInvite.isPending,
|
|
58
|
-
children:
|
|
69
|
+
children: /* @__PURE__ */ jsx(
|
|
70
|
+
Translation,
|
|
71
|
+
{
|
|
72
|
+
defaultMessage: "Cancel",
|
|
73
|
+
id: "+p4qwy",
|
|
74
|
+
description: "Button to cancel revoking invite"
|
|
75
|
+
}
|
|
76
|
+
)
|
|
59
77
|
}
|
|
60
78
|
) }),
|
|
61
79
|
/* @__PURE__ */ jsx(
|
|
@@ -64,7 +82,14 @@ function RevokeInviteDialog({
|
|
|
64
82
|
variant: "destructive",
|
|
65
83
|
type: "submit",
|
|
66
84
|
loading: revokeInvite.isPending,
|
|
67
|
-
children:
|
|
85
|
+
children: /* @__PURE__ */ jsx(
|
|
86
|
+
Translation,
|
|
87
|
+
{
|
|
88
|
+
defaultMessage: "Revoke",
|
|
89
|
+
id: "Nkz6Xi",
|
|
90
|
+
description: "Button to confirm revoking the invitation"
|
|
91
|
+
}
|
|
92
|
+
)
|
|
68
93
|
}
|
|
69
94
|
)
|
|
70
95
|
]
|
|
@@ -80,7 +105,14 @@ function getMutationErrorMessage(error) {
|
|
|
80
105
|
if (!error) {
|
|
81
106
|
return null;
|
|
82
107
|
}
|
|
83
|
-
return
|
|
108
|
+
return /* @__PURE__ */ jsx(
|
|
109
|
+
Translation,
|
|
110
|
+
{
|
|
111
|
+
defaultMessage: "There was an error revoking the invite. Please try again.",
|
|
112
|
+
id: "zG7XDc",
|
|
113
|
+
description: "Error message shown when revoking invite fails"
|
|
114
|
+
}
|
|
115
|
+
);
|
|
84
116
|
}
|
|
85
117
|
export {
|
|
86
118
|
RevokeInviteDialog
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/revoke-invite-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport { type ReactNode, useRef } from \"react\";\nimport { useRevokeUserInvite } from \"./api/user.js\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { Member } from \"../api/endpoint.js\";\n\ninterface RevokeInviteDialogProps extends AlertDialog.RootProps {\n user: Member;\n children?: ReactNode;\n}\n\nexport function RevokeInviteDialog({\n children,\n user,\n ...props\n}: RevokeInviteDialogProps) {\n const revokeInvite = useRevokeUserInvite();\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n\n const onSubmitForm = () => {\n revokeInvite.mutate(\n { userId: user.id },\n {\n onSuccess: () => {\n props.onOpenChange?.(false);\n },\n },\n );\n };\n\n return (\n <AlertDialog.Root {...props}>\n {children && <AlertDialog.Trigger>{children}</AlertDialog.Trigger>}\n\n <AlertDialog.Content\n maxWidth=\"480px\"\n onOpenAutoFocus={() => {\n requestAnimationFrame(() => {\n cancelButtonRef.current?.focus();\n });\n }}\n >\n <AlertDialog.Title
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/revoke-invite-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport { type ReactNode, useRef } from \"react\";\nimport { useRevokeUserInvite } from \"./api/user.js\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { Member } from \"../api/endpoint.js\";\nimport { Translation } from \"./i18n/translation.js\";\n\ninterface RevokeInviteDialogProps extends AlertDialog.RootProps {\n user: Member;\n children?: ReactNode;\n}\n\nexport function RevokeInviteDialog({\n children,\n user,\n ...props\n}: RevokeInviteDialogProps) {\n const revokeInvite = useRevokeUserInvite();\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n\n const onSubmitForm = () => {\n revokeInvite.mutate(\n { userId: user.id },\n {\n onSuccess: () => {\n props.onOpenChange?.(false);\n },\n },\n );\n };\n\n return (\n <AlertDialog.Root {...props}>\n {children && <AlertDialog.Trigger>{children}</AlertDialog.Trigger>}\n\n <AlertDialog.Content\n maxWidth=\"480px\"\n onOpenAutoFocus={() => {\n requestAnimationFrame(() => {\n cancelButtonRef.current?.focus();\n });\n }}\n >\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Revoke invite?\"\n id=\"/fEPAD\"\n description=\"Dialog title asking to confirm revoking an invitation\"\n />\n </AlertDialog.Title>\n <Flex mb=\"4\" direction=\"column\" gap=\"3\">\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"Are you sure you want to revoke the invite to {email}? This action is immediate and cannot be undone.\"\n id=\"wt2qe9\"\n description=\"Warning message about revoking invite to specific email\"\n values={{ email: <Text weight=\"bold\">{user.email}</Text> }}\n />\n </AlertDialog.Description>\n </Flex>\n\n {revokeInvite.error ? (\n <Callout.Root color=\"red\" mt=\"4\" mb=\"-2\">\n <Callout.Text>\n {getMutationErrorMessage(revokeInvite.error)}\n </Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n ref={cancelButtonRef}\n disabled={revokeInvite.isPending}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"+p4qwy\"\n description=\"Button to cancel revoking invite\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <Button\n variant=\"destructive\"\n type=\"submit\"\n loading={revokeInvite.isPending}\n >\n <Translation\n defaultMessage=\"Revoke\"\n id=\"Nkz6Xi\"\n description=\"Button to confirm revoking the invitation\"\n />\n </Button>\n </form>\n </Flex>\n </AlertDialog.Content>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(revokeInvite.error)}\n </section>\n </VisuallyHidden>\n </AlertDialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n if (!error) {\n return null;\n }\n // TODO Handle server errors\n return (\n <Translation\n defaultMessage=\"There was an error revoking the invite. Please try again.\"\n id=\"zG7XDc\"\n description=\"Error message shown when revoking invite fails\"\n />\n );\n}\n"],"mappings":";AAmCmB,cAqCT,YArCS;AAjCnB,SAAS,SAAS,MAAM,MAAM,sBAAsB;AACpD,SAAyB,cAAc;AACvC,SAAS,2BAA2B;AACpC,SAAS,aAAa,cAAc;AAEpC,SAAS,mBAAmB;AAOrB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA4B;AAC1B,QAAM,eAAe,oBAAoB;AACzC,QAAM,kBAAkB,OAA0B,IAAI;AAEtD,QAAM,eAAe,MAAM;AACzB,iBAAa;AAAA,MACX,EAAE,QAAQ,KAAK,GAAG;AAAA,MAClB;AAAA,QACE,WAAW,MAAM;AACf,gBAAM,eAAe,KAAK;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SACE,qBAAC,YAAY,MAAZ,EAAkB,GAAG,OACnB;AAAA,gBAAY,oBAAC,YAAY,SAAZ,EAAqB,UAAS;AAAA,IAE5C;AAAA,MAAC,YAAY;AAAA,MAAZ;AAAA,QACC,UAAS;AAAA,QACT,iBAAiB,MAAM;AACrB,gCAAsB,MAAM;AAC1B,4BAAgB,SAAS,MAAM;AAAA,UACjC,CAAC;AAAA,QACH;AAAA,QAEA;AAAA,8BAAC,YAAY,OAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd,GACF;AAAA,UACA,oBAAC,QAAK,IAAG,KAAI,WAAU,UAAS,KAAI,KAClC,8BAAC,YAAY,aAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA,cACZ,QAAQ,EAAE,OAAO,oBAAC,QAAK,QAAO,QAAQ,eAAK,OAAM,EAAQ;AAAA;AAAA,UAC3D,GACF,GACF;AAAA,UAEC,aAAa,QACZ,oBAAC,QAAQ,MAAR,EAAa,OAAM,OAAM,IAAG,KAAI,IAAG,MAClC,8BAAC,QAAQ,MAAR,EACE,kCAAwB,aAAa,KAAK,GAC7C,GACF,IACE;AAAA,UAEJ,oBAAC,QAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,YAAC;AAAA;AAAA,cACC,UAAU,CAAC,UAAU;AACnB,sBAAM,eAAe;AACrB,6BAAa;AAAA,cACf;AAAA,cAEA;AAAA,oCAAC,YAAY,QAAZ,EACC;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,KAAK;AAAA,oBACL,UAAU,aAAa;AAAA,oBAEvB;AAAA,sBAAC;AAAA;AAAA,wBACC,gBAAe;AAAA,wBACf,IAAG;AAAA,wBACH,aAAY;AAAA;AAAA,oBACd;AAAA;AAAA,gBACF,GACF;AAAA,gBAEA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,SAAS,aAAa;AAAA,oBAEtB;AAAA,sBAAC;AAAA;AAAA,wBACC,gBAAe;AAAA,wBACf,IAAG;AAAA,wBACH,aAAY;AAAA;AAAA,oBACd;AAAA;AAAA,gBACF;AAAA;AAAA;AAAA,UACF,GACF;AAAA;AAAA;AAAA,IACF;AAAA,IAGA,oBAAC,kBAAe,SAAO,MACrB,8BAAC,aAAQ,aAAU,UAChB,kCAAwB,aAAa,KAAK,GAC7C,GACF;AAAA,KACF;AAEJ;AAEA,SAAS,wBAAwB,OAAgB;AAC/C,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd;AAEJ;","names":[]}
|
|
@@ -4,6 +4,7 @@ import { CheckIcon } from "@radix-ui/react-icons";
|
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import { namespaceClassNames } from "./utils.js";
|
|
6
6
|
import { Button } from "./elements.js";
|
|
7
|
+
import { Translation } from "./i18n/translation.js";
|
|
7
8
|
const DONE_TIMEOUT_MS = 1500;
|
|
8
9
|
const SAVING_TIMEOUT_MS = 600;
|
|
9
10
|
function SaveButton({
|
|
@@ -82,7 +83,14 @@ function SaveButton({
|
|
|
82
83
|
className: namespaceClassNames("save-button__done-icon")
|
|
83
84
|
}
|
|
84
85
|
),
|
|
85
|
-
/* @__PURE__ */ jsx(Text, { className: namespaceClassNames("save-button__done-text"), children:
|
|
86
|
+
/* @__PURE__ */ jsx(Text, { className: namespaceClassNames("save-button__done-text"), children: /* @__PURE__ */ jsx(
|
|
87
|
+
Translation,
|
|
88
|
+
{
|
|
89
|
+
defaultMessage: "Done",
|
|
90
|
+
id: "wjt0K3",
|
|
91
|
+
description: "Button label indicating an action has completed successfully"
|
|
92
|
+
}
|
|
93
|
+
) })
|
|
86
94
|
]
|
|
87
95
|
}
|
|
88
96
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/save-button.tsx"],"sourcesContent":["import { Flex, Slot, Slottable, Spinner, Text } from \"@radix-ui/themes\";\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { namespaceClassNames } from \"./utils.js\";\nimport { Button, type ButtonProps } from \"./elements.js\";\n\nconst DONE_TIMEOUT_MS = 1500;\nconst SAVING_TIMEOUT_MS = 600;\n\ninterface SaveButtonProps extends ButtonProps {\n asChild?: boolean;\n children: React.ReactNode;\n loading?: boolean;\n done?: boolean;\n onDone?: () => void;\n}\n\nexport function SaveButton({\n asChild = false,\n children,\n loading,\n done,\n onDone,\n ...props\n}: SaveButtonProps) {\n const [state, setState] = useState<\"idle\" | \"loading\" | \"done\">(\n loading ? \"loading\" : done ? \"done\" : \"idle\",\n );\n const loadingStartTime = useRef<number | null>(null);\n const ButtonComponent = asChild ? Slot : Button;\n\n useEffect(() => {\n if (loading) {\n // FIXME: This should be refactored\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setState(\"loading\");\n loadingStartTime.current = Date.now();\n } else if (done) {\n const currentTime = Date.now();\n const loadingDuration = loadingStartTime.current\n ? currentTime - loadingStartTime.current\n : 0;\n\n // If loading lasted less than 500 ms, wait for the remaining time\n const remainingDelay = Math.max(0, SAVING_TIMEOUT_MS - loadingDuration);\n\n let doneTimer: number | null = null;\n const savedTimer = window.setTimeout(() => {\n setState(\"done\");\n\n doneTimer = window.setTimeout(() => {\n onDone?.();\n }, DONE_TIMEOUT_MS);\n }, remainingDelay);\n\n return () => {\n window.clearTimeout(savedTimer);\n if (doneTimer !== null) {\n window.clearTimeout(doneTimer);\n }\n };\n } else if (!loading && !done) {\n setState(\"idle\");\n }\n }, [loading, done, onDone]);\n\n return (\n <ButtonComponent\n {...props}\n className={namespaceClassNames(\"save-button\")}\n data-save-state={state}\n >\n <Slottable>{children}</Slottable>\n {state === \"loading\" && (\n <Flex\n as=\"span\"\n align=\"center\"\n justify=\"center\"\n position=\"absolute\"\n inset=\"0\"\n >\n <Spinner size=\"1\" />\n </Flex>\n )}\n\n {state === \"done\" && (\n <Flex\n as=\"span\"\n align=\"center\"\n justify=\"center\"\n position=\"absolute\"\n inset=\"0\"\n gap=\"1\"\n >\n <CheckIcon\n width=\"18px\"\n height=\"18px\"\n style={{ marginLeft: \"-4px\" }}\n className={namespaceClassNames(\"save-button__done-icon\")}\n />\n <Text className={namespaceClassNames(\"save-button__done-text\")}>\n Done\n </Text>\n </Flex>\n )}\n </ButtonComponent>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/save-button.tsx"],"sourcesContent":["import { Flex, Slot, Slottable, Spinner, Text } from \"@radix-ui/themes\";\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { namespaceClassNames } from \"./utils.js\";\nimport { Button, type ButtonProps } from \"./elements.js\";\nimport { Translation } from \"./i18n/translation.js\";\n\nconst DONE_TIMEOUT_MS = 1500;\nconst SAVING_TIMEOUT_MS = 600;\n\ninterface SaveButtonProps extends ButtonProps {\n asChild?: boolean;\n children: React.ReactNode;\n loading?: boolean;\n done?: boolean;\n onDone?: () => void;\n}\n\nexport function SaveButton({\n asChild = false,\n children,\n loading,\n done,\n onDone,\n ...props\n}: SaveButtonProps) {\n const [state, setState] = useState<\"idle\" | \"loading\" | \"done\">(\n loading ? \"loading\" : done ? \"done\" : \"idle\",\n );\n const loadingStartTime = useRef<number | null>(null);\n const ButtonComponent = asChild ? Slot : Button;\n\n useEffect(() => {\n if (loading) {\n // FIXME: This should be refactored\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setState(\"loading\");\n loadingStartTime.current = Date.now();\n } else if (done) {\n const currentTime = Date.now();\n const loadingDuration = loadingStartTime.current\n ? currentTime - loadingStartTime.current\n : 0;\n\n // If loading lasted less than 500 ms, wait for the remaining time\n const remainingDelay = Math.max(0, SAVING_TIMEOUT_MS - loadingDuration);\n\n let doneTimer: number | null = null;\n const savedTimer = window.setTimeout(() => {\n setState(\"done\");\n\n doneTimer = window.setTimeout(() => {\n onDone?.();\n }, DONE_TIMEOUT_MS);\n }, remainingDelay);\n\n return () => {\n window.clearTimeout(savedTimer);\n if (doneTimer !== null) {\n window.clearTimeout(doneTimer);\n }\n };\n } else if (!loading && !done) {\n setState(\"idle\");\n }\n }, [loading, done, onDone]);\n\n return (\n <ButtonComponent\n {...props}\n className={namespaceClassNames(\"save-button\")}\n data-save-state={state}\n >\n <Slottable>{children}</Slottable>\n {state === \"loading\" && (\n <Flex\n as=\"span\"\n align=\"center\"\n justify=\"center\"\n position=\"absolute\"\n inset=\"0\"\n >\n <Spinner size=\"1\" />\n </Flex>\n )}\n\n {state === \"done\" && (\n <Flex\n as=\"span\"\n align=\"center\"\n justify=\"center\"\n position=\"absolute\"\n inset=\"0\"\n gap=\"1\"\n >\n <CheckIcon\n width=\"18px\"\n height=\"18px\"\n style={{ marginLeft: \"-4px\" }}\n className={namespaceClassNames(\"save-button__done-icon\")}\n />\n <Text className={namespaceClassNames(\"save-button__done-text\")}>\n <Translation\n defaultMessage=\"Done\"\n id=\"wjt0K3\"\n description=\"Button label indicating an action has completed successfully\"\n />\n </Text>\n </Flex>\n )}\n </ButtonComponent>\n );\n}\n"],"mappings":"AAyEM,cAcE,YAdF;AAzEN,SAAS,MAAM,MAAM,WAAW,SAAS,YAAY;AACrD,SAAS,iBAAiB;AAC1B,SAAS,WAAW,QAAQ,gBAAgB;AAC5C,SAAS,2BAA2B;AACpC,SAAS,cAAgC;AACzC,SAAS,mBAAmB;AAE5B,MAAM,kBAAkB;AACxB,MAAM,oBAAoB;AAUnB,SAAS,WAAW;AAAA,EACzB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,QAAM,CAAC,OAAO,QAAQ,IAAI;AAAA,IACxB,UAAU,YAAY,OAAO,SAAS;AAAA,EACxC;AACA,QAAM,mBAAmB,OAAsB,IAAI;AACnD,QAAM,kBAAkB,UAAU,OAAO;AAEzC,YAAU,MAAM;AACd,QAAI,SAAS;AAGX,eAAS,SAAS;AAClB,uBAAiB,UAAU,KAAK,IAAI;AAAA,IACtC,WAAW,MAAM;AACf,YAAM,cAAc,KAAK,IAAI;AAC7B,YAAM,kBAAkB,iBAAiB,UACrC,cAAc,iBAAiB,UAC/B;AAGJ,YAAM,iBAAiB,KAAK,IAAI,GAAG,oBAAoB,eAAe;AAEtE,UAAI,YAA2B;AAC/B,YAAM,aAAa,OAAO,WAAW,MAAM;AACzC,iBAAS,MAAM;AAEf,oBAAY,OAAO,WAAW,MAAM;AAClC,mBAAS;AAAA,QACX,GAAG,eAAe;AAAA,MACpB,GAAG,cAAc;AAEjB,aAAO,MAAM;AACX,eAAO,aAAa,UAAU;AAC9B,YAAI,cAAc,MAAM;AACtB,iBAAO,aAAa,SAAS;AAAA,QAC/B;AAAA,MACF;AAAA,IACF,WAAW,CAAC,WAAW,CAAC,MAAM;AAC5B,eAAS,MAAM;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,SAAS,MAAM,MAAM,CAAC;AAE1B,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,WAAW,oBAAoB,aAAa;AAAA,MAC5C,mBAAiB;AAAA,MAEjB;AAAA,4BAAC,aAAW,UAAS;AAAA,QACpB,UAAU,aACT;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,UAAS;AAAA,YACT,OAAM;AAAA,YAEN,8BAAC,WAAQ,MAAK,KAAI;AAAA;AAAA,QACpB;AAAA,QAGD,UAAU,UACT;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,UAAS;AAAA,YACT,OAAM;AAAA,YACN,KAAI;AAAA,YAEJ;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBACN,QAAO;AAAA,kBACP,OAAO,EAAE,YAAY,OAAO;AAAA,kBAC5B,WAAW,oBAAoB,wBAAwB;AAAA;AAAA,cACzD;AAAA,cACA,oBAAC,QAAK,WAAW,oBAAoB,wBAAwB,GAC3D;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd,GACF;AAAA;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -9,6 +9,8 @@ import { useSecuritySettings } from "./use-security-settings.js";
|
|
|
9
9
|
import { ElevatedAccess } from "./elevated-access.js";
|
|
10
10
|
import { SaveButton } from "./save-button.js";
|
|
11
11
|
import { useDialogClose } from "./use-dialog-close.js";
|
|
12
|
+
import { Translation } from "./i18n/translation.js";
|
|
13
|
+
import { useTranslation } from "./i18n/use-translation.js";
|
|
12
14
|
function SetPasswordDialog({
|
|
13
15
|
children,
|
|
14
16
|
...props
|
|
@@ -23,6 +25,7 @@ function SetPasswordDialog({
|
|
|
23
25
|
] });
|
|
24
26
|
}
|
|
25
27
|
function Content({ onClose }) {
|
|
28
|
+
const translate = useTranslation();
|
|
26
29
|
const setPassword = useCreatePassword();
|
|
27
30
|
const securitySettings = useSecuritySettings();
|
|
28
31
|
const [disableSubmit, setDisableSubmit] = React.useState(true);
|
|
@@ -39,8 +42,22 @@ function Content({ onClose }) {
|
|
|
39
42
|
securitySettings.update("Password", true);
|
|
40
43
|
});
|
|
41
44
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42
|
-
/* @__PURE__ */ jsx(Dialog.Title, { mb: "5", children:
|
|
43
|
-
|
|
45
|
+
/* @__PURE__ */ jsx(Dialog.Title, { mb: "5", children: /* @__PURE__ */ jsx(
|
|
46
|
+
Translation,
|
|
47
|
+
{
|
|
48
|
+
defaultMessage: "Set New Password",
|
|
49
|
+
id: "4ymFUc",
|
|
50
|
+
description: "Dialog title for setting a new password"
|
|
51
|
+
}
|
|
52
|
+
) }),
|
|
53
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(Dialog.Description, { children: /* @__PURE__ */ jsx(
|
|
54
|
+
Translation,
|
|
55
|
+
{
|
|
56
|
+
defaultMessage: "Set a new password for your account",
|
|
57
|
+
id: "KYv5vS",
|
|
58
|
+
description: "Screen reader description for set password dialog"
|
|
59
|
+
}
|
|
60
|
+
) }) }),
|
|
44
61
|
setPassword.error ? /* @__PURE__ */ jsx(Callout.Root, { color: "red", my: "-2", children: /* @__PURE__ */ jsx(Callout.Text, { children: getMutationErrorMessage(setPassword.error) }) }) : null,
|
|
45
62
|
/* @__PURE__ */ jsxs(
|
|
46
63
|
Form.Root,
|
|
@@ -55,38 +72,88 @@ function Content({ onClose }) {
|
|
|
55
72
|
children: [
|
|
56
73
|
/* @__PURE__ */ jsxs(Flex, { mt: "5", direction: "column", gap: "4", children: [
|
|
57
74
|
/* @__PURE__ */ jsx(Form.Field, { name: "password", asChild: true, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
|
|
58
|
-
/* @__PURE__ */ jsx(Form.Label, { asChild: true, children: /* @__PURE__ */ jsx(Label, { children:
|
|
75
|
+
/* @__PURE__ */ jsx(Form.Label, { asChild: true, children: /* @__PURE__ */ jsx(Label, { children: /* @__PURE__ */ jsx(
|
|
76
|
+
Translation,
|
|
77
|
+
{
|
|
78
|
+
defaultMessage: "Enter a new password",
|
|
79
|
+
id: "OHDxyL",
|
|
80
|
+
description: "Label for password input field"
|
|
81
|
+
}
|
|
82
|
+
) }) }),
|
|
59
83
|
/* @__PURE__ */ jsx(Form.Control, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
60
84
|
PasswordField,
|
|
61
85
|
{
|
|
62
86
|
autoFocus: true,
|
|
63
87
|
required: true,
|
|
64
88
|
autoComplete: "new-password",
|
|
65
|
-
placeholder:
|
|
89
|
+
placeholder: translate({
|
|
90
|
+
defaultMessage: "New password",
|
|
91
|
+
id: "ABfT4E",
|
|
92
|
+
description: "Placeholder for password input"
|
|
93
|
+
}),
|
|
66
94
|
disabled: setPassword.isPending || setPassword.isSuccess
|
|
67
95
|
}
|
|
68
96
|
) }),
|
|
69
|
-
/* @__PURE__ */ jsx(Form.Message, { match: "valueMissing", asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children:
|
|
70
|
-
|
|
97
|
+
/* @__PURE__ */ jsx(Form.Message, { match: "valueMissing", asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children: /* @__PURE__ */ jsx(
|
|
98
|
+
Translation,
|
|
99
|
+
{
|
|
100
|
+
defaultMessage: "Please enter a new password",
|
|
101
|
+
id: "+2kQs5",
|
|
102
|
+
description: "Error message when password field is empty"
|
|
103
|
+
}
|
|
104
|
+
) }) }),
|
|
105
|
+
/* @__PURE__ */ jsx(Form.Message, { match: (value) => value.length < 8, asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children: /* @__PURE__ */ jsx(
|
|
106
|
+
Translation,
|
|
107
|
+
{
|
|
108
|
+
defaultMessage: "Password must be at least 8 characters",
|
|
109
|
+
id: "WRjyrh",
|
|
110
|
+
description: "Error message when password is too short"
|
|
111
|
+
}
|
|
112
|
+
) }) })
|
|
71
113
|
] }) }),
|
|
72
114
|
/* @__PURE__ */ jsx(Form.Field, { name: "confirmPassword", asChild: true, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", children: [
|
|
73
|
-
/* @__PURE__ */ jsx(Form.Label, { asChild: true, children: /* @__PURE__ */ jsx(Label, { children:
|
|
115
|
+
/* @__PURE__ */ jsx(Form.Label, { asChild: true, children: /* @__PURE__ */ jsx(Label, { children: /* @__PURE__ */ jsx(
|
|
116
|
+
Translation,
|
|
117
|
+
{
|
|
118
|
+
defaultMessage: "Confirm your new password",
|
|
119
|
+
id: "K83lBn",
|
|
120
|
+
description: "Label for password confirmation field"
|
|
121
|
+
}
|
|
122
|
+
) }) }),
|
|
74
123
|
/* @__PURE__ */ jsx(Form.Control, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
75
124
|
PasswordField,
|
|
76
125
|
{
|
|
77
126
|
required: true,
|
|
78
127
|
autoComplete: "new-password",
|
|
79
|
-
placeholder:
|
|
128
|
+
placeholder: translate({
|
|
129
|
+
defaultMessage: "Confirm new password",
|
|
130
|
+
id: "O79vjp",
|
|
131
|
+
description: "Placeholder for password confirmation input"
|
|
132
|
+
}),
|
|
80
133
|
disabled: setPassword.isPending || setPassword.isSuccess
|
|
81
134
|
}
|
|
82
135
|
) }),
|
|
83
|
-
/* @__PURE__ */ jsx(Form.Message, { match: "valueMissing", asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children:
|
|
136
|
+
/* @__PURE__ */ jsx(Form.Message, { match: "valueMissing", asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children: /* @__PURE__ */ jsx(
|
|
137
|
+
Translation,
|
|
138
|
+
{
|
|
139
|
+
defaultMessage: "Please confirm your new password",
|
|
140
|
+
id: "vfwqWf",
|
|
141
|
+
description: "Error message when password confirmation is empty"
|
|
142
|
+
}
|
|
143
|
+
) }) }),
|
|
84
144
|
/* @__PURE__ */ jsx(
|
|
85
145
|
Form.Message,
|
|
86
146
|
{
|
|
87
147
|
match: (value, formData) => value !== formData.get("password"),
|
|
88
148
|
asChild: true,
|
|
89
|
-
children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children:
|
|
149
|
+
children: /* @__PURE__ */ jsx(Text, { size: "2", color: "red", children: /* @__PURE__ */ jsx(
|
|
150
|
+
Translation,
|
|
151
|
+
{
|
|
152
|
+
defaultMessage: "The passwords you entered don't match.",
|
|
153
|
+
id: "ayYwQx",
|
|
154
|
+
description: "Error message when passwords don't match"
|
|
155
|
+
}
|
|
156
|
+
) })
|
|
90
157
|
}
|
|
91
158
|
)
|
|
92
159
|
] }) })
|
|
@@ -97,7 +164,14 @@ function Content({ onClose }) {
|
|
|
97
164
|
{
|
|
98
165
|
variant: "secondary",
|
|
99
166
|
disabled: setPassword.isPending || setPassword.isSuccess,
|
|
100
|
-
children:
|
|
167
|
+
children: /* @__PURE__ */ jsx(
|
|
168
|
+
Translation,
|
|
169
|
+
{
|
|
170
|
+
defaultMessage: "Cancel",
|
|
171
|
+
id: "VJVs4m",
|
|
172
|
+
description: "Button to cancel setting password"
|
|
173
|
+
}
|
|
174
|
+
)
|
|
101
175
|
}
|
|
102
176
|
) }),
|
|
103
177
|
/* @__PURE__ */ jsx(
|
|
@@ -108,7 +182,14 @@ function Content({ onClose }) {
|
|
|
108
182
|
onDone: onClose,
|
|
109
183
|
type: "submit",
|
|
110
184
|
disabled: disableSubmit || void 0,
|
|
111
|
-
children:
|
|
185
|
+
children: /* @__PURE__ */ jsx(
|
|
186
|
+
Translation,
|
|
187
|
+
{
|
|
188
|
+
defaultMessage: "Set password",
|
|
189
|
+
id: "jSfqX/",
|
|
190
|
+
description: "Button to confirm setting new password"
|
|
191
|
+
}
|
|
192
|
+
)
|
|
112
193
|
}
|
|
113
194
|
)
|
|
114
195
|
] }),
|
|
@@ -125,7 +206,14 @@ function getMutationErrorMessage(error) {
|
|
|
125
206
|
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
126
207
|
return error.message;
|
|
127
208
|
}
|
|
128
|
-
return
|
|
209
|
+
return /* @__PURE__ */ jsx(
|
|
210
|
+
Translation,
|
|
211
|
+
{
|
|
212
|
+
defaultMessage: "Something went wrong. Please try again.",
|
|
213
|
+
id: "jLzoYu",
|
|
214
|
+
description: "Generic error message for password setting failure"
|
|
215
|
+
}
|
|
216
|
+
);
|
|
129
217
|
}
|
|
130
218
|
export {
|
|
131
219
|
SetPasswordDialog
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/set-password-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport { Dialog, Label, PasswordField, Button } from \"./elements.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { useCreatePassword } from \"../api/endpoint.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface SetPasswordDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n}\n\nexport function SetPasswordDialog({\n children,\n ...props\n}: SetPasswordDialogProps) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root {...props} open={open} onOpenChange={setOpen}>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n\n <Dialog.Content maxWidth=\"480px\">\n <ElevatedAccess>\n <Content onClose={handleClose} />\n </ElevatedAccess>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n onClose: () => void;\n}\n\nfunction Content({ onClose }: ContentProps) {\n const setPassword = useCreatePassword();\n const securitySettings = useSecuritySettings();\n const [disableSubmit, setDisableSubmit] = React.useState(true);\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n const formData = new FormData(event.currentTarget);\n const password = formData.get(\"password\")?.toString();\n\n if (!password) {\n return;\n }\n\n setPassword.mutate({ data: { password } });\n };\n\n useDialogClose(setPassword.isSuccess, () => {\n securitySettings.update(\"Password\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set New Password</Dialog.Title>\n <VisuallyHidden>\n <Dialog.Description>\n Set a new password for your account\n </Dialog.Description>\n </VisuallyHidden>\n\n {setPassword.error ? (\n <Callout.Root color=\"red\" my=\"-2\">\n <Callout.Text>\n {getMutationErrorMessage(setPassword.error)}\n </Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Form.Root\n onSubmit={handleSubmit}\n onChange={(event) => {\n const formData = new FormData(event.currentTarget);\n const password = formData.get(\"password\")?.toString();\n const confirmPassword = formData.get(\"confirmPassword\")?.toString();\n setDisableSubmit(password === \"\" || confirmPassword === \"\");\n }}\n >\n <Flex mt=\"5\" direction=\"column\" gap=\"4\">\n <Form.Field name=\"password\" asChild>\n <Flex direction=\"column\" gap=\"2\">\n <Form.Label asChild>\n <Label>Enter a new password</Label>\n </Form.Label>\n <Form.Control asChild>\n <PasswordField\n autoFocus\n required\n autoComplete=\"new-password\"\n placeholder=\"New password\"\n disabled={setPassword.isPending || setPassword.isSuccess}\n />\n </Form.Control>\n <Form.Message match=\"valueMissing\" asChild>\n <Text size=\"2\" color=\"red\">\n Please enter a new password\n </Text>\n </Form.Message>\n <Form.Message match={(value) => value.length < 8} asChild>\n <Text size=\"2\" color=\"red\">\n Password must be at least 8 characters\n </Text>\n </Form.Message>\n </Flex>\n </Form.Field>\n\n <Form.Field name=\"confirmPassword\" asChild>\n <Flex direction=\"column\" gap=\"2\">\n <Form.Label asChild>\n <Label>Confirm your new password</Label>\n </Form.Label>\n <Form.Control asChild>\n <PasswordField\n required\n autoComplete=\"new-password\"\n placeholder=\"Confirm new password\"\n disabled={setPassword.isPending || setPassword.isSuccess}\n />\n </Form.Control>\n <Form.Message match=\"valueMissing\" asChild>\n <Text size=\"2\" color=\"red\">\n Please confirm your new password\n </Text>\n </Form.Message>\n <Form.Message\n match={(value, formData) => value !== formData.get(\"password\")}\n asChild\n >\n <Text size=\"2\" color=\"red\">\n The passwords you entered don’t match.\n </Text>\n </Form.Message>\n </Flex>\n </Form.Field>\n </Flex>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <Button\n variant=\"secondary\"\n disabled={setPassword.isPending || setPassword.isSuccess}\n >\n Cancel\n </Button>\n </Dialog.Close>\n\n <SaveButton\n loading={setPassword.isPending}\n done={setPassword.isSuccess}\n onDone={onClose}\n type=\"submit\"\n disabled={disableSubmit || undefined}\n >\n Set password\n </SaveButton>\n </Flex>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(setPassword.error)}\n </section>\n </VisuallyHidden>\n </Form.Root>\n </>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n if (error instanceof Error) {\n return error.message;\n }\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n\n return \"Something went wrong. Please try again.\";\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/set-password-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport { Dialog, Label, PasswordField, Button } from \"./elements.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { useCreatePassword } from \"../api/endpoint.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\n\ninterface SetPasswordDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n}\n\nexport function SetPasswordDialog({\n children,\n ...props\n}: SetPasswordDialogProps) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root {...props} open={open} onOpenChange={setOpen}>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n\n <Dialog.Content maxWidth=\"480px\">\n <ElevatedAccess>\n <Content onClose={handleClose} />\n </ElevatedAccess>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n onClose: () => void;\n}\n\nfunction Content({ onClose }: ContentProps) {\n const translate = useTranslation();\n const setPassword = useCreatePassword();\n const securitySettings = useSecuritySettings();\n const [disableSubmit, setDisableSubmit] = React.useState(true);\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n const formData = new FormData(event.currentTarget);\n const password = formData.get(\"password\")?.toString();\n\n if (!password) {\n return;\n }\n\n setPassword.mutate({ data: { password } });\n };\n\n useDialogClose(setPassword.isSuccess, () => {\n securitySettings.update(\"Password\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">\n <Translation\n defaultMessage=\"Set New Password\"\n id=\"4ymFUc\"\n description=\"Dialog title for setting a new password\"\n />\n </Dialog.Title>\n <VisuallyHidden>\n <Dialog.Description>\n <Translation\n defaultMessage=\"Set a new password for your account\"\n id=\"KYv5vS\"\n description=\"Screen reader description for set password dialog\"\n />\n </Dialog.Description>\n </VisuallyHidden>\n\n {setPassword.error ? (\n <Callout.Root color=\"red\" my=\"-2\">\n <Callout.Text>\n {getMutationErrorMessage(setPassword.error)}\n </Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Form.Root\n onSubmit={handleSubmit}\n onChange={(event) => {\n const formData = new FormData(event.currentTarget);\n const password = formData.get(\"password\")?.toString();\n const confirmPassword = formData.get(\"confirmPassword\")?.toString();\n setDisableSubmit(password === \"\" || confirmPassword === \"\");\n }}\n >\n <Flex mt=\"5\" direction=\"column\" gap=\"4\">\n <Form.Field name=\"password\" asChild>\n <Flex direction=\"column\" gap=\"2\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"Enter a new password\"\n id=\"OHDxyL\"\n description=\"Label for password input field\"\n />\n </Label>\n </Form.Label>\n <Form.Control asChild>\n <PasswordField\n autoFocus\n required\n autoComplete=\"new-password\"\n placeholder={translate({\n defaultMessage: \"New password\",\n id: \"ABfT4E\",\n description: \"Placeholder for password input\",\n })}\n disabled={setPassword.isPending || setPassword.isSuccess}\n />\n </Form.Control>\n <Form.Message match=\"valueMissing\" asChild>\n <Text size=\"2\" color=\"red\">\n <Translation\n defaultMessage=\"Please enter a new password\"\n id=\"+2kQs5\"\n description=\"Error message when password field is empty\"\n />\n </Text>\n </Form.Message>\n <Form.Message match={(value) => value.length < 8} asChild>\n <Text size=\"2\" color=\"red\">\n <Translation\n defaultMessage=\"Password must be at least 8 characters\"\n id=\"WRjyrh\"\n description=\"Error message when password is too short\"\n />\n </Text>\n </Form.Message>\n </Flex>\n </Form.Field>\n\n <Form.Field name=\"confirmPassword\" asChild>\n <Flex direction=\"column\" gap=\"2\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"Confirm your new password\"\n id=\"K83lBn\"\n description=\"Label for password confirmation field\"\n />\n </Label>\n </Form.Label>\n <Form.Control asChild>\n <PasswordField\n required\n autoComplete=\"new-password\"\n placeholder={translate({\n defaultMessage: \"Confirm new password\",\n id: \"O79vjp\",\n description: \"Placeholder for password confirmation input\",\n })}\n disabled={setPassword.isPending || setPassword.isSuccess}\n />\n </Form.Control>\n <Form.Message match=\"valueMissing\" asChild>\n <Text size=\"2\" color=\"red\">\n <Translation\n defaultMessage=\"Please confirm your new password\"\n id=\"vfwqWf\"\n description=\"Error message when password confirmation is empty\"\n />\n </Text>\n </Form.Message>\n <Form.Message\n match={(value, formData) => value !== formData.get(\"password\")}\n asChild\n >\n <Text size=\"2\" color=\"red\">\n <Translation\n defaultMessage=\"The passwords you entered don't match.\"\n id=\"ayYwQx\"\n description=\"Error message when passwords don't match\"\n />\n </Text>\n </Form.Message>\n </Flex>\n </Form.Field>\n </Flex>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <Button\n variant=\"secondary\"\n disabled={setPassword.isPending || setPassword.isSuccess}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"VJVs4m\"\n description=\"Button to cancel setting password\"\n />\n </Button>\n </Dialog.Close>\n\n <SaveButton\n loading={setPassword.isPending}\n done={setPassword.isSuccess}\n onDone={onClose}\n type=\"submit\"\n disabled={disableSubmit || undefined}\n >\n <Translation\n defaultMessage=\"Set password\"\n id=\"jSfqX/\"\n description=\"Button to confirm setting new password\"\n />\n </SaveButton>\n </Flex>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(setPassword.error)}\n </section>\n </VisuallyHidden>\n </Form.Root>\n </>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n if (error instanceof Error) {\n return error.message;\n }\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n\n return (\n <Translation\n defaultMessage=\"Something went wrong. Please try again.\"\n id=\"jLzoYu\"\n description=\"Generic error message for password setting failure\"\n />\n );\n}\n"],"mappings":"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","names":[]}
|