@workos-inc/widgets 1.17.2-next.1788288181219 → 1.17.2
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 +2 -2
- package/dist/cjs/api/client-graphql/generated.cjs.map +1 -1
- package/dist/cjs/api/client-graphql/generated.d.cts +97 -1
- package/dist/cjs/api/endpoint.cjs +113 -0
- package/dist/cjs/api/endpoint.cjs.map +1 -1
- package/dist/cjs/api/endpoint.d.cts +161 -11
- package/dist/cjs/experimental/api/fetch.cjs +68 -0
- package/dist/cjs/experimental/api/fetch.cjs.map +1 -1
- package/dist/cjs/experimental/api/fetch.d.cts +169 -11
- package/dist/cjs/experimental/api/react-query.cjs +132 -0
- package/dist/cjs/experimental/api/react-query.cjs.map +1 -1
- package/dist/cjs/experimental/api/react-query.d.cts +237 -11
- package/dist/cjs/experimental/api/swr.cjs +144 -0
- package/dist/cjs/experimental/api/swr.cjs.map +1 -1
- package/dist/cjs/experimental/api/swr.d.cts +221 -11
- package/dist/cjs/lib/change-email-dialog.cjs +3 -3
- package/dist/cjs/lib/change-email-dialog.cjs.map +1 -1
- package/dist/cjs/lib/save-button.cjs +6 -2
- package/dist/cjs/lib/save-button.cjs.map +1 -1
- package/dist/esm/api/client-graphql/generated.d.ts +97 -1
- package/dist/esm/api/client-graphql/generated.js.map +1 -1
- package/dist/esm/api/endpoint.d.ts +161 -11
- package/dist/esm/api/endpoint.js +103 -0
- package/dist/esm/api/endpoint.js.map +1 -1
- package/dist/esm/experimental/api/fetch.d.ts +169 -11
- package/dist/esm/experimental/api/fetch.js +62 -0
- package/dist/esm/experimental/api/fetch.js.map +1 -1
- package/dist/esm/experimental/api/react-query.d.ts +237 -11
- package/dist/esm/experimental/api/react-query.js +119 -0
- package/dist/esm/experimental/api/react-query.js.map +1 -1
- package/dist/esm/experimental/api/swr.d.ts +221 -11
- package/dist/esm/experimental/api/swr.js +130 -0
- package/dist/esm/experimental/api/swr.js.map +1 -1
- package/dist/esm/lib/change-email-dialog.js +3 -3
- package/dist/esm/lib/change-email-dialog.js.map +1 -1
- package/dist/esm/lib/save-button.js +6 -2
- package/dist/esm/lib/save-button.js.map +1 -1
- package/package.json +1 -1
|
@@ -181,7 +181,7 @@ function VerifyEmailChangeForm({
|
|
|
181
181
|
const { setElevatedAccess } = useElevatedAccessToken();
|
|
182
182
|
const verifyEmailChange = useVerifyEmailChange({
|
|
183
183
|
mutation: {
|
|
184
|
-
onSuccess:
|
|
184
|
+
onSuccess: (response) => {
|
|
185
185
|
setElevatedAccess({
|
|
186
186
|
token: response.elevatedAccessToken,
|
|
187
187
|
expiresAt: response.expiresAt
|
|
@@ -190,7 +190,7 @@ function VerifyEmailChangeForm({
|
|
|
190
190
|
getMeQueryKey(),
|
|
191
191
|
(old) => old ? { ...old, ...response.user } : response.user
|
|
192
192
|
);
|
|
193
|
-
|
|
193
|
+
void client.invalidateQueries({ queryKey: getMeQueryKey() });
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
});
|
|
@@ -280,7 +280,7 @@ function VerifyEmailChangeForm({
|
|
|
280
280
|
SaveButton,
|
|
281
281
|
{
|
|
282
282
|
type: "submit",
|
|
283
|
-
loading:
|
|
283
|
+
loading: verifyEmailChange.isPending,
|
|
284
284
|
done: verifyEmailChange.isSuccess,
|
|
285
285
|
onDone: onSuccess,
|
|
286
286
|
children: /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/change-email-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as Form from \"./form.js\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport {\n getMeQueryKey,\n Me,\n useAuthenticationInformation,\n useSendEmailChange,\n useVerifyEmailChange,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport { Button, Dialog, Label, TextField } from \"./elements.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport * as Otp from \"./otp-input.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { SetPasswordForm } from \"./set-password-dialog.js\";\n\ninterface ChangeEmailDialogProps {\n user: Me;\n children?: ReactNode;\n}\n\nexport function ChangeEmailDialog({ children, user }: ChangeEmailDialogProps) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n\n <Dialog.Content maxWidth=\"480px\">\n <ElevatedAccess>\n <Content user={user} onClose={handleClose} />\n </ElevatedAccess>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n user: Me;\n onClose: () => void;\n}\n\ntype Step =\n | { name: \"send\" }\n | { name: \"verify\"; newEmail: string }\n | { name: \"set-password\"; newEmail: string };\n\nfunction Content({ user, onClose }: ContentProps) {\n const [step, setStep] = React.useState<Step>({ name: \"send\" });\n const authInfo = useAuthenticationInformation();\n\n const passwordIsSetUp =\n authInfo.data?.data.verificationMethods.Password?.isSetUp;\n\n const handleVerified = React.useCallback(\n (newEmail: string) => {\n if (passwordIsSetUp === false) {\n setStep({ name: \"set-password\", newEmail });\n } else {\n onClose();\n }\n },\n [passwordIsSetUp, onClose],\n );\n\n switch (step.name) {\n case \"send\":\n return (\n <SendEmailChangeForm\n user={user}\n onSuccess={(newEmail) => setStep({ name: \"verify\", newEmail })}\n />\n );\n case \"verify\":\n return (\n <VerifyEmailChangeForm\n newEmail={step.newEmail}\n onBack={() => setStep({ name: \"send\" })}\n onSuccess={() => handleVerified(step.newEmail)}\n />\n );\n case \"set-password\":\n return <SetPasswordStep newEmail={step.newEmail} onDone={onClose} />;\n }\n}\n\ninterface SendEmailChangeFormProps {\n user: Me;\n onSuccess: (newEmail: string) => void;\n}\n\nfunction SendEmailChangeForm({ user, onSuccess }: SendEmailChangeFormProps) {\n const translate = useTranslation();\n const [newEmail, setNewEmail] = React.useState(\"\");\n const sendEmailChange = useSendEmailChange({\n mutation: {\n onSuccess: (_response, variables) => {\n onSuccess(variables.data.newEmail);\n },\n },\n });\n\n return (\n <>\n <Dialog.Title mb=\"2\">\n <Translation\n defaultMessage=\"Change email address\"\n id=\"KdUdX9\"\n description=\"Dialog title for changing the user's email address\"\n />\n </Dialog.Title>\n\n <Dialog.Description mb=\"5\">\n <Translation\n defaultMessage=\"We'll send a verification code to your new email address to confirm the change. Your current email is {email}.\"\n id=\"K6x8v6\"\n description=\"Description explaining that a verification code will be sent to the new email, including the user's current email\"\n values={{\n email: (\n <Text weight=\"bold\" highContrast>\n {user.email}\n </Text>\n ),\n }}\n />\n </Dialog.Description>\n\n {sendEmailChange.error ? (\n <Callout.Root color=\"red\" mt=\"-2\" mb=\"0\">\n <Callout.Text>\n {getMutationErrorMessage(sendEmailChange.error)}\n </Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Form.Root\n onSubmit={(event) => {\n event.preventDefault();\n const trimmed = newEmail.trim();\n if (!trimmed) return;\n sendEmailChange.mutate({ data: { newEmail: trimmed } });\n }}\n >\n <Flex my=\"5\" direction=\"column\" gap=\"4\">\n <Form.Field name=\"newEmail\" asChild>\n <Flex direction=\"column\" gap=\"1\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"New email address\"\n id=\"dbgchn\"\n description=\"Label for the new email input\"\n />\n </Label>\n </Form.Label>\n <Form.Control asChild>\n <TextField\n type=\"email\"\n autoComplete=\"email\"\n autoFocus\n required\n value={newEmail}\n onChange={(event) => setNewEmail(event.target.value)}\n placeholder={translate({\n defaultMessage: \"name@example.com\",\n id: \"QyYabV\",\n description: \"Placeholder for the new email input\",\n })}\n disabled={sendEmailChange.isPending}\n />\n </Form.Control>\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 type=\"button\"\n disabled={sendEmailChange.isPending}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n loading={sendEmailChange.isPending}\n disabled={!newEmail.trim()}\n >\n <Translation\n defaultMessage=\"Send verification code\"\n id=\"1bX9l4\"\n description=\"Button text to send the email change verification code\"\n />\n </Button>\n </Flex>\n </Form.Root>\n </>\n );\n}\n\ninterface VerifyEmailChangeFormProps {\n newEmail: string;\n onBack: () => void;\n onSuccess: () => void;\n}\n\nfunction VerifyEmailChangeForm({\n newEmail,\n onBack,\n onSuccess,\n}: VerifyEmailChangeFormProps) {\n const [otpValue, setOtpValue] = React.useState<string>(\"\");\n const client = useQueryClient();\n const { setElevatedAccess } = useElevatedAccessToken();\n const verifyEmailChange = useVerifyEmailChange({\n mutation: {\n onSuccess: async (response) => {\n setElevatedAccess({\n token: response.elevatedAccessToken,\n expiresAt: response.expiresAt,\n });\n client.setQueryData<Me>(getMeQueryKey(), (old) =>\n old ? { ...old, ...response.user } : response.user,\n );\n await client.invalidateQueries({ queryKey: getMeQueryKey() });\n },\n },\n });\n\n const isSubmitting =\n verifyEmailChange.isPending || verifyEmailChange.isSuccess;\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (verifyEmailChange.isPending || verifyEmailChange.isSuccess) return;\n const formData = new FormData(event.currentTarget);\n const code = formData.get(\"otp-code\")?.toString() ?? \"\";\n if (!code) return;\n verifyEmailChange.mutate({ data: { code } });\n };\n\n return (\n <Form.Root onSubmit={handleSubmit}>\n <Dialog.Title mb=\"2\">\n <Translation\n defaultMessage=\"Enter verification code\"\n id=\"upvyOt\"\n description=\"Dialog title for entering the email change verification code\"\n />\n </Dialog.Title>\n\n <Dialog.Description>\n <Translation\n defaultMessage=\"A verification code was sent to {email}. Please enter it below.\"\n id=\"9OH/qs\"\n description=\"Description explaining where the email change code was sent\"\n values={{\n email: (\n <Text weight=\"bold\" highContrast>\n {newEmail}\n </Text>\n ),\n }}\n />\n </Dialog.Description>\n\n <Flex direction=\"column\" gap=\"2\" mt=\"5\" mx=\"auto\" width=\"fit-content\">\n <Otp.Root\n autoSubmit\n gap=\"2\"\n justify=\"center\"\n columns=\"repeat(6, 48px)\"\n width=\"fit-content\"\n rows=\"48px\"\n name=\"otp-code\"\n readOnly={isSubmitting}\n value={otpValue}\n onValueChange={setOtpValue}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {verifyEmailChange.error ? (\n <Text color=\"red\" size=\"2\" as=\"p\">\n {getMutationErrorMessage(verifyEmailChange.error)}\n </Text>\n ) : null}\n </Flex>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"between\" align=\"center\">\n <Button\n variant=\"secondary\"\n type=\"button\"\n onClick={onBack}\n disabled={isSubmitting}\n >\n <Translation\n defaultMessage=\"Use a different email\"\n id=\"HVuco9\"\n description=\"Button text to go back and change the new email address\"\n />\n </Button>\n <Flex gap=\"3\">\n <Dialog.Close>\n <Button variant=\"secondary\" type=\"button\" disabled={isSubmitting}>\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <SaveButton\n type=\"submit\"\n loading={isSubmitting}\n done={verifyEmailChange.isSuccess}\n onDone={onSuccess}\n >\n <Translation\n defaultMessage=\"Confirm\"\n id=\"EmYENK\"\n description=\"Confirm button text for verification\"\n />\n </SaveButton>\n </Flex>\n </Flex>\n\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {verifyEmailChange.error\n ? getMutationErrorMessage(verifyEmailChange.error)\n : null}\n </section>\n </VisuallyHidden>\n </Form.Root>\n );\n}\n\ninterface SetPasswordStepProps {\n newEmail: string;\n onDone: () => void;\n}\n\nfunction SetPasswordStep({ newEmail, onDone }: SetPasswordStepProps) {\n return (\n <SetPasswordForm\n description={\n <Dialog.Description>\n <Translation\n defaultMessage=\"Your email has been successfully updated to {email}. You can also set a password now if you'd like to be able to sign in with email and password.\"\n id=\"U7k/vL\"\n description=\"Description for the set-password step after a successful email change\"\n values={{\n email: (\n <Text weight=\"bold\" highContrast>\n {newEmail}\n </Text>\n ),\n }}\n />\n </Dialog.Description>\n }\n onSuccess={onDone}\n cancel={\n <Button variant=\"secondary\" type=\"button\" onClick={onDone}>\n <Translation\n defaultMessage=\"Not now\"\n id=\"/7/PVX\"\n description=\"Button to dismiss the set-password step and close the dialog\"\n />\n </Button>\n }\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=\"Dn/G2O\"\n description=\"Generic error message for email change failure\"\n />\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/change-email-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport * as Form from \"./form.js\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport {\n getMeQueryKey,\n Me,\n useAuthenticationInformation,\n useSendEmailChange,\n useVerifyEmailChange,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport { Button, Dialog, Label, TextField } from \"./elements.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport * as Otp from \"./otp-input.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { SetPasswordForm } from \"./set-password-dialog.js\";\n\ninterface ChangeEmailDialogProps {\n user: Me;\n children?: ReactNode;\n}\n\nexport function ChangeEmailDialog({ children, user }: ChangeEmailDialogProps) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n\n <Dialog.Content maxWidth=\"480px\">\n <ElevatedAccess>\n <Content user={user} onClose={handleClose} />\n </ElevatedAccess>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n user: Me;\n onClose: () => void;\n}\n\ntype Step =\n | { name: \"send\" }\n | { name: \"verify\"; newEmail: string }\n | { name: \"set-password\"; newEmail: string };\n\nfunction Content({ user, onClose }: ContentProps) {\n const [step, setStep] = React.useState<Step>({ name: \"send\" });\n const authInfo = useAuthenticationInformation();\n\n const passwordIsSetUp =\n authInfo.data?.data.verificationMethods.Password?.isSetUp;\n\n const handleVerified = React.useCallback(\n (newEmail: string) => {\n if (passwordIsSetUp === false) {\n setStep({ name: \"set-password\", newEmail });\n } else {\n onClose();\n }\n },\n [passwordIsSetUp, onClose],\n );\n\n switch (step.name) {\n case \"send\":\n return (\n <SendEmailChangeForm\n user={user}\n onSuccess={(newEmail) => setStep({ name: \"verify\", newEmail })}\n />\n );\n case \"verify\":\n return (\n <VerifyEmailChangeForm\n newEmail={step.newEmail}\n onBack={() => setStep({ name: \"send\" })}\n onSuccess={() => handleVerified(step.newEmail)}\n />\n );\n case \"set-password\":\n return <SetPasswordStep newEmail={step.newEmail} onDone={onClose} />;\n }\n}\n\ninterface SendEmailChangeFormProps {\n user: Me;\n onSuccess: (newEmail: string) => void;\n}\n\nfunction SendEmailChangeForm({ user, onSuccess }: SendEmailChangeFormProps) {\n const translate = useTranslation();\n const [newEmail, setNewEmail] = React.useState(\"\");\n const sendEmailChange = useSendEmailChange({\n mutation: {\n onSuccess: (_response, variables) => {\n onSuccess(variables.data.newEmail);\n },\n },\n });\n\n return (\n <>\n <Dialog.Title mb=\"2\">\n <Translation\n defaultMessage=\"Change email address\"\n id=\"KdUdX9\"\n description=\"Dialog title for changing the user's email address\"\n />\n </Dialog.Title>\n\n <Dialog.Description mb=\"5\">\n <Translation\n defaultMessage=\"We'll send a verification code to your new email address to confirm the change. Your current email is {email}.\"\n id=\"K6x8v6\"\n description=\"Description explaining that a verification code will be sent to the new email, including the user's current email\"\n values={{\n email: (\n <Text weight=\"bold\" highContrast>\n {user.email}\n </Text>\n ),\n }}\n />\n </Dialog.Description>\n\n {sendEmailChange.error ? (\n <Callout.Root color=\"red\" mt=\"-2\" mb=\"0\">\n <Callout.Text>\n {getMutationErrorMessage(sendEmailChange.error)}\n </Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Form.Root\n onSubmit={(event) => {\n event.preventDefault();\n const trimmed = newEmail.trim();\n if (!trimmed) return;\n sendEmailChange.mutate({ data: { newEmail: trimmed } });\n }}\n >\n <Flex my=\"5\" direction=\"column\" gap=\"4\">\n <Form.Field name=\"newEmail\" asChild>\n <Flex direction=\"column\" gap=\"1\">\n <Form.Label asChild>\n <Label>\n <Translation\n defaultMessage=\"New email address\"\n id=\"dbgchn\"\n description=\"Label for the new email input\"\n />\n </Label>\n </Form.Label>\n <Form.Control asChild>\n <TextField\n type=\"email\"\n autoComplete=\"email\"\n autoFocus\n required\n value={newEmail}\n onChange={(event) => setNewEmail(event.target.value)}\n placeholder={translate({\n defaultMessage: \"name@example.com\",\n id: \"QyYabV\",\n description: \"Placeholder for the new email input\",\n })}\n disabled={sendEmailChange.isPending}\n />\n </Form.Control>\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 type=\"button\"\n disabled={sendEmailChange.isPending}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n loading={sendEmailChange.isPending}\n disabled={!newEmail.trim()}\n >\n <Translation\n defaultMessage=\"Send verification code\"\n id=\"1bX9l4\"\n description=\"Button text to send the email change verification code\"\n />\n </Button>\n </Flex>\n </Form.Root>\n </>\n );\n}\n\ninterface VerifyEmailChangeFormProps {\n newEmail: string;\n onBack: () => void;\n onSuccess: () => void;\n}\n\nfunction VerifyEmailChangeForm({\n newEmail,\n onBack,\n onSuccess,\n}: VerifyEmailChangeFormProps) {\n const [otpValue, setOtpValue] = React.useState<string>(\"\");\n const client = useQueryClient();\n const { setElevatedAccess } = useElevatedAccessToken();\n const verifyEmailChange = useVerifyEmailChange({\n mutation: {\n onSuccess: (response) => {\n setElevatedAccess({\n token: response.elevatedAccessToken,\n expiresAt: response.expiresAt,\n });\n client.setQueryData<Me>(getMeQueryKey(), (old) =>\n old ? { ...old, ...response.user } : response.user,\n );\n void client.invalidateQueries({ queryKey: getMeQueryKey() });\n },\n },\n });\n\n const isSubmitting =\n verifyEmailChange.isPending || verifyEmailChange.isSuccess;\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (verifyEmailChange.isPending || verifyEmailChange.isSuccess) return;\n const formData = new FormData(event.currentTarget);\n const code = formData.get(\"otp-code\")?.toString() ?? \"\";\n if (!code) return;\n verifyEmailChange.mutate({ data: { code } });\n };\n\n return (\n <Form.Root onSubmit={handleSubmit}>\n <Dialog.Title mb=\"2\">\n <Translation\n defaultMessage=\"Enter verification code\"\n id=\"upvyOt\"\n description=\"Dialog title for entering the email change verification code\"\n />\n </Dialog.Title>\n\n <Dialog.Description>\n <Translation\n defaultMessage=\"A verification code was sent to {email}. Please enter it below.\"\n id=\"9OH/qs\"\n description=\"Description explaining where the email change code was sent\"\n values={{\n email: (\n <Text weight=\"bold\" highContrast>\n {newEmail}\n </Text>\n ),\n }}\n />\n </Dialog.Description>\n\n <Flex direction=\"column\" gap=\"2\" mt=\"5\" mx=\"auto\" width=\"fit-content\">\n <Otp.Root\n autoSubmit\n gap=\"2\"\n justify=\"center\"\n columns=\"repeat(6, 48px)\"\n width=\"fit-content\"\n rows=\"48px\"\n name=\"otp-code\"\n readOnly={isSubmitting}\n value={otpValue}\n onValueChange={setOtpValue}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {verifyEmailChange.error ? (\n <Text color=\"red\" size=\"2\" as=\"p\">\n {getMutationErrorMessage(verifyEmailChange.error)}\n </Text>\n ) : null}\n </Flex>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"between\" align=\"center\">\n <Button\n variant=\"secondary\"\n type=\"button\"\n onClick={onBack}\n disabled={isSubmitting}\n >\n <Translation\n defaultMessage=\"Use a different email\"\n id=\"HVuco9\"\n description=\"Button text to go back and change the new email address\"\n />\n </Button>\n <Flex gap=\"3\">\n <Dialog.Close>\n <Button variant=\"secondary\" type=\"button\" disabled={isSubmitting}>\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <SaveButton\n type=\"submit\"\n loading={verifyEmailChange.isPending}\n done={verifyEmailChange.isSuccess}\n onDone={onSuccess}\n >\n <Translation\n defaultMessage=\"Confirm\"\n id=\"EmYENK\"\n description=\"Confirm button text for verification\"\n />\n </SaveButton>\n </Flex>\n </Flex>\n\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {verifyEmailChange.error\n ? getMutationErrorMessage(verifyEmailChange.error)\n : null}\n </section>\n </VisuallyHidden>\n </Form.Root>\n );\n}\n\ninterface SetPasswordStepProps {\n newEmail: string;\n onDone: () => void;\n}\n\nfunction SetPasswordStep({ newEmail, onDone }: SetPasswordStepProps) {\n return (\n <SetPasswordForm\n description={\n <Dialog.Description>\n <Translation\n defaultMessage=\"Your email has been successfully updated to {email}. You can also set a password now if you'd like to be able to sign in with email and password.\"\n id=\"U7k/vL\"\n description=\"Description for the set-password step after a successful email change\"\n values={{\n email: (\n <Text weight=\"bold\" highContrast>\n {newEmail}\n </Text>\n ),\n }}\n />\n </Dialog.Description>\n }\n onSuccess={onDone}\n cancel={\n <Button variant=\"secondary\" type=\"button\" onClick={onDone}>\n <Translation\n defaultMessage=\"Not now\"\n id=\"/7/PVX\"\n description=\"Button to dismiss the set-password step and close the dialog\"\n />\n </Button>\n }\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=\"Dn/G2O\"\n description=\"Generic error message for email change failure\"\n />\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -19,7 +19,11 @@ function SaveButton({
|
|
|
19
19
|
loading ? "loading" : done ? "done" : "idle"
|
|
20
20
|
);
|
|
21
21
|
const loadingStartTime = useRef(null);
|
|
22
|
+
const onDoneRef = useRef(onDone);
|
|
22
23
|
const ButtonComponent = asChild ? Slot : Button;
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
onDoneRef.current = onDone;
|
|
26
|
+
}, [onDone]);
|
|
23
27
|
useEffect(() => {
|
|
24
28
|
if (loading) {
|
|
25
29
|
setState("loading");
|
|
@@ -32,7 +36,7 @@ function SaveButton({
|
|
|
32
36
|
const savedTimer = window.setTimeout(() => {
|
|
33
37
|
setState("done");
|
|
34
38
|
doneTimer = window.setTimeout(() => {
|
|
35
|
-
|
|
39
|
+
onDoneRef.current?.();
|
|
36
40
|
}, DONE_TIMEOUT_MS);
|
|
37
41
|
}, remainingDelay);
|
|
38
42
|
return () => {
|
|
@@ -44,7 +48,7 @@ function SaveButton({
|
|
|
44
48
|
} else if (!loading && !done) {
|
|
45
49
|
setState("idle");
|
|
46
50
|
}
|
|
47
|
-
}, [loading, done
|
|
51
|
+
}, [loading, done]);
|
|
48
52
|
return /* @__PURE__ */ jsxs(
|
|
49
53
|
ButtonComponent,
|
|
50
54
|
{
|
|
@@ -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\";\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
|
|
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 onDoneRef = useRef(onDone);\n const ButtonComponent = asChild ? Slot : Button;\n\n useEffect(() => {\n onDoneRef.current = onDone;\n }, [onDone]);\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 onDoneRef.current?.();\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]);\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":"AA8EM,cAcE,YAdF;AA9EN,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,YAAY,OAAO,MAAM;AAC/B,QAAM,kBAAkB,UAAU,OAAO;AAEzC,YAAU,MAAM;AACd,cAAU,UAAU;AAAA,EACtB,GAAG,CAAC,MAAM,CAAC;AAEX,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,oBAAU,UAAU;AAAA,QACtB,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,IAAI,CAAC;AAElB,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":[]}
|