Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/few-dingos-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@clerk/localizations': minor
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add a confirmation input as an additional check when doing destructive actions such as:
- delete an organization
- delete a user account
- leave an organization

Νew localization keys were introduced to support the above
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
withCardStateProvider,
} from '../../elements';
import { useRouter } from '../../router';
import { handleError } from '../../utils';
import { handleError, useFormControl } from '../../utils';
import { OrganizationProfileBreadcrumbs } from './OrganizationProfileNavbar';

export const LeaveOrganizationPage = () => {
Expand All @@ -30,9 +30,14 @@ export const LeaveOrganizationPage = () => {

return (
<ActionConfirmationPage
organizationName={organization?.name}
title={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.title')}
messageLine1={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.messageLine1')}
messageLine2={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.messageLine2')}
actionDescription={localizationKeys(
'organizationProfile.profilePage.dangerSection.leaveOrganization.actionDescription',
{ organizationName: organization?.name },
)}
submitLabel={localizationKeys('organizationProfile.profilePage.dangerSection.leaveOrganization.title')}
successMessage={localizationKeys(
'organizationProfile.profilePage.dangerSection.leaveOrganization.successMessage',
Expand All @@ -57,9 +62,14 @@ export const DeleteOrganizationPage = () => {

return (
<ActionConfirmationPage
organizationName={organization?.name}
title={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.title')}
messageLine1={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.messageLine1')}
messageLine2={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.messageLine2')}
actionDescription={localizationKeys(
'organizationProfile.profilePage.dangerSection.deleteOrganization.actionDescription',
{ organizationName: organization?.name },
)}
submitLabel={localizationKeys('organizationProfile.profilePage.dangerSection.deleteOrganization.title')}
successMessage={localizationKeys(
'organizationProfile.profilePage.dangerSection.deleteOrganization.successMessage',
Expand All @@ -73,6 +83,8 @@ type ActionConfirmationPageProps = {
title: LocalizationKey;
messageLine1: LocalizationKey;
messageLine2: LocalizationKey;
actionDescription?: LocalizationKey;
organizationName?: string;
successMessage: LocalizationKey;
submitLabel: LocalizationKey;
onConfirmation: () => Promise<any>;
Expand All @@ -84,6 +96,8 @@ const ActionConfirmationPage = withCardStateProvider((props: ActionConfirmationP
title,
messageLine1,
messageLine2,
actionDescription,
organizationName,
successMessage,
submitLabel,
onConfirmation,
Expand All @@ -93,6 +107,15 @@ const ActionConfirmationPage = withCardStateProvider((props: ActionConfirmationP
const card = useCardState();
const { navigate } = useRouter();

const confirmationField = useFormControl('deleteOrganizationConfirmation', '', {
type: 'text',
label: localizationKeys('formFieldLabel__confirmDeletion'),
isRequired: true,
placeholder: organizationName,
});

const canSubmit = actionDescription ? confirmationField.value === organizationName : true;

const handleSubmit = async () => {
try {
await onConfirmation().then(() => wizard.nextStep());
Expand All @@ -108,19 +131,24 @@ const ActionConfirmationPage = withCardStateProvider((props: ActionConfirmationP
Breadcrumbs={OrganizationProfileBreadcrumbs}
>
<Form.Root onSubmit={handleSubmit}>
<Text
localizationKey={messageLine1}
variant='regularRegular'
/>
<Text
localizationKey={messageLine2}
variant='regularRegular'
/>
<Text localizationKey={messageLine1} />
<Text localizationKey={messageLine2} />
Comment thread
raptisj marked this conversation as resolved.

<Text localizationKey={actionDescription} />

<Form.ControlRow elementId={confirmationField.id}>
<Form.Control
{...confirmationField.props}
required
/>
</Form.ControlRow>

<FormButtonContainer>
<Form.SubmitButton
block={false}
colorScheme={colorScheme}
localizationKey={submitLabel}
isDisabled={!canSubmit}
/>
<Form.ResetButton
localizationKey={localizationKeys('userProfile.formButtonReset')}
Expand Down
27 changes: 23 additions & 4 deletions packages/clerk-js/src/ui/components/UserProfile/DeletePage.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useEnvironment, useCoreUser, useCoreClerk } from '../../contexts';
import { useCoreClerk, useCoreUser, useEnvironment } from '../../contexts';
import { localizationKeys, Text } from '../../customizables';
import { ContentPage, Form, FormButtons, useCardState, withCardStateProvider } from '../../elements';
import { handleError } from '../../utils';
import { UserProfileBreadcrumbs } from './UserProfileNavbar';
import { useRouter } from '../../router';
import { handleError, useFormControl } from '../../utils';
import { UserProfileBreadcrumbs } from './UserProfileNavbar';

export const DeletePage = withCardStateProvider(() => {
const card = useCardState();
Expand All @@ -25,16 +25,35 @@ export const DeletePage = withCardStateProvider(() => {
}
};

const confirmationField = useFormControl('deleteConfirmation', '', {
type: 'text',
label: localizationKeys('formFieldLabel__confirmDeletion'),
isRequired: true,
placeholder: 'Delete account',
});

const canSubmit = confirmationField.value === 'Delete account';

return (
<ContentPage
headerTitle={localizationKeys('userProfile.deletePage.title')}
Breadcrumbs={UserProfileBreadcrumbs}
>
<Form.Root onSubmit={deleteUser}>
<Text localizationKey={localizationKeys('userProfile.deletePage.description')} />
<Text localizationKey={localizationKeys('userProfile.deletePage.messageLine1')} />
<Text localizationKey={localizationKeys('userProfile.deletePage.messageLine2')} />
<Text localizationKey={localizationKeys('userProfile.deletePage.actionDescription')} />

<Form.ControlRow elementId={confirmationField.id}>
<Form.Control
{...confirmationField.props}
required
/>
</Form.ControlRow>
<FormButtons
submitLabel={localizationKeys('userProfile.deletePage.confirm')}
colorScheme='danger'
isDisabled={!canSubmit}
/>
</Form.Root>
</ContentPage>
Expand Down
7 changes: 6 additions & 1 deletion packages/localizations/src/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const enUS: LocalizationResource = {
formFieldLabel__backupCode: 'Backup code',
formFieldLabel__organizationName: 'Organization name',
formFieldLabel__organizationSlug: 'Slug URL',
formFieldLabel__confirmDeletion: 'Confirmation',
formFieldLabel__role: 'Role',
formFieldInputPlaceholder__emailAddress: '',
formFieldInputPlaceholder__emailAddresses:
Expand Down Expand Up @@ -506,7 +507,9 @@ export const enUS: LocalizationResource = {
},
deletePage: {
title: 'Delete account',
description: 'Are you sure you want to delete your account? This action is permanent and irreversible.',
messageLine1: 'Are you sure you want to delete your account?',
messageLine2: 'This action is permanent and irreversible.',
actionDescription: 'Type Delete account below to continue.',
confirm: 'Delete account',
},
},
Expand Down Expand Up @@ -545,11 +548,13 @@ export const enUS: LocalizationResource = {
'Are you sure you want to leave this organization? You will lose access to this organization and its applications.',
messageLine2: 'This action is permanent and irreversible.',
successMessage: 'You have left the organization.',
actionDescription: 'Type {{organizationName}} below to continue.',
},
deleteOrganization: {
title: 'Delete organization',
messageLine1: 'Are you sure you want to delete this organization?',
messageLine2: 'This action is permanent and irreversible.',
actionDescription: 'Type {{organizationName}} below to continue.',
successMessage: 'You have deleted the organization.',
},
},
Expand Down
4 changes: 2 additions & 2 deletions packages/localizations/src/nb-NO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,8 +509,8 @@ export const nbNO: LocalizationResource = {
},
deletePage: {
title: 'Slett konto',
description:
'Er du sikker på at du vil slette kontoen din? Denne handlingen er permanent og kan ikke reverseres.',
messageLine1: 'Er du sikker på at du vil slette kontoen din?',
messageLine2: 'Denne handlingen er permanent og kan ikke reverseres.',
confirm: 'Slett konto',
},
},
Expand Down
4 changes: 2 additions & 2 deletions packages/localizations/src/vi-VN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ export const viVN: LocalizationResource = {
},
deletePage: {
title: 'Xóa tài khoản',
description:
'Bạn có chắc chắn muốn xóa tài khoản của mình không? Hành động này là vĩnh viễn và không thể hoàn tác.',
messageLine1: 'Bạn có chắc chắn muốn xóa tài khoản của mình không?',
messageLine2: 'Hành động này là vĩnh viễn và không thể hoàn tác.',
confirm: 'Xóa tài khoản',
},
},
Expand Down
4 changes: 3 additions & 1 deletion packages/types/src/appearance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ export type FieldId =
| 'identifier'
| 'username'
| 'code'
| 'role';
| 'role'
| 'deleteConfirmation'
| 'deleteOrganizationConfirmation';
export type ProfileSectionId =
| 'profile'
| 'username'
Expand Down
7 changes: 6 additions & 1 deletion packages/types/src/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type _LocalizationResource = {
formFieldLabel__backupCode: LocalizationValue;
formFieldLabel__organizationName: LocalizationValue;
formFieldLabel__organizationSlug: LocalizationValue;
formFieldLabel__confirmDeletion: LocalizationValue;
formFieldLabel__role: LocalizationValue;
formFieldInputPlaceholder__emailAddress: LocalizationValue;
formFieldInputPlaceholder__emailAddresses: LocalizationValue;
Expand Down Expand Up @@ -527,7 +528,9 @@ type _LocalizationResource = {
};
deletePage: {
title: LocalizationValue;
description: LocalizationValue;
messageLine1: LocalizationValue;
messageLine2: LocalizationValue;
actionDescription: LocalizationValue;
confirm: LocalizationValue;
};
};
Expand Down Expand Up @@ -564,12 +567,14 @@ type _LocalizationResource = {
title: LocalizationValue;
messageLine1: LocalizationValue;
messageLine2: LocalizationValue;
actionDescription: LocalizationValue;
successMessage: LocalizationValue;
};
deleteOrganization: {
title: LocalizationValue;
messageLine1: LocalizationValue;
messageLine2: LocalizationValue;
actionDescription: LocalizationValue;
successMessage: LocalizationValue;
};
};
Expand Down