diff --git a/.changeset/shy-readers-visit.md b/.changeset/shy-readers-visit.md new file mode 100644 index 0000000000..da1fb5ffb3 --- /dev/null +++ b/.changeset/shy-readers-visit.md @@ -0,0 +1,7 @@ +--- +'@clerk/localizations': patch +'@clerk/clerk-js': patch +'@clerk/types': patch +--- + +When updating enrollment mode of a domain uses can now delete any pending invitations or suggestions. diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/VerifiedDomainPage.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/VerifiedDomainPage.tsx index 8a9e95807d..90e89b8651 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/VerifiedDomainPage.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/VerifiedDomainPage.tsx @@ -1,29 +1,27 @@ import type { OrganizationEnrollmentMode } from '@clerk/types'; import { useCoreOrganization, useEnvironment } from '../../contexts'; -import { Col, descriptors, Flex, localizationKeys, Spinner } from '../../customizables'; -import { - BlockWithAction, - ContentPage, - Form, - FormButtons, - Header, - useCardState, - withCardStateProvider, -} from '../../elements'; -import { useFetch } from '../../hooks'; +import { Col, Flex, localizationKeys, Spinner } from '../../customizables'; +import { ContentPage, Form, FormButtons, Header, useCardState, withCardStateProvider } from '../../elements'; +import { useFetch, useNavigateToFlowStart } from '../../hooks'; import { useRouter } from '../../router'; import { handleError, useFormControl } from '../../utils'; -import { EnrollmentBadge } from './EnrollmentBadge'; import { OrganizationProfileBreadcrumbs } from './OrganizationProfileNavbar'; export const VerifiedDomainPage = withCardStateProvider(() => { const card = useCardState(); const { organizationSettings } = useEnvironment(); const { organization } = useCoreOrganization(); - const { params, navigate } = useRouter(); + const { domains } = useCoreOrganization({ + domains: { + infinite: true, + }, + }); + const { navigateToFlowStart } = useNavigateToFlowStart(); + const { params, navigate, queryParams } = useRouter(); + const mode = (queryParams.mode ?? 'edit') as 'select' | 'edit'; - const title = localizationKeys('organizationProfile.verifiedDomainPage.title'); + const allowsEdit = mode === 'edit'; const enrollmentMode = useFormControl('enrollmentMode', '', { type: 'radio', @@ -32,9 +30,11 @@ export const VerifiedDomainPage = withCardStateProvider(() => { ? [ { value: 'manual_invitation', - label: localizationKeys('organizationProfile.verifiedDomainPage.manualInvitationOption__label'), + label: localizationKeys( + 'organizationProfile.verifiedDomainPage.enrollmentTab.manualInvitationOption__label', + ), description: localizationKeys( - 'organizationProfile.verifiedDomainPage.manualInvitationOption__description', + 'organizationProfile.verifiedDomainPage.enrollmentTab.manualInvitationOption__description', ), }, ] @@ -43,9 +43,11 @@ export const VerifiedDomainPage = withCardStateProvider(() => { ? [ { value: 'automatic_invitation', - label: localizationKeys('organizationProfile.verifiedDomainPage.automaticInvitationOption__label'), + label: localizationKeys( + 'organizationProfile.verifiedDomainPage.enrollmentTab.automaticInvitationOption__label', + ), description: localizationKeys( - 'organizationProfile.verifiedDomainPage.automaticInvitationOption__description', + 'organizationProfile.verifiedDomainPage.enrollmentTab.automaticInvitationOption__description', ), }, ] @@ -54,9 +56,11 @@ export const VerifiedDomainPage = withCardStateProvider(() => { ? [ { value: 'automatic_suggestion', - label: localizationKeys('organizationProfile.verifiedDomainPage.automaticSuggestionOption__label'), + label: localizationKeys( + 'organizationProfile.verifiedDomainPage.enrollmentTab.automaticSuggestionOption__label', + ), description: localizationKeys( - 'organizationProfile.verifiedDomainPage.automaticSuggestionOption__description', + 'organizationProfile.verifiedDomainPage.enrollmentTab.automaticSuggestionOption__description', ), }, ] @@ -64,6 +68,11 @@ export const VerifiedDomainPage = withCardStateProvider(() => { ], }); + const deletePending = useFormControl('deleteExistingInvitationsSuggestions', '', { + label: localizationKeys('formFieldLabel__organizationDomainDeletePending'), + type: 'checkbox', + }); + const { data: domain, status: domainStatus } = useFetch( organization?.getDomain, { @@ -76,6 +85,7 @@ export const VerifiedDomainPage = withCardStateProvider(() => { }, ); + const isFormDirty = deletePending.checked || domain?.enrollmentMode !== enrollmentMode.value; const updateEnrollmentMode = async () => { if (!domain || !organization) { return; @@ -84,8 +94,11 @@ export const VerifiedDomainPage = withCardStateProvider(() => { try { await domain.updateEnrollmentMode({ enrollmentMode: enrollmentMode.value as OrganizationEnrollmentMode, + deletePending: deletePending.checked, }); + await (domains as any).unstable__mutate(); + await navigate('../../'); } catch (e) { handleError(e, [enrollmentMode], card.setError); @@ -115,36 +128,23 @@ export const VerifiedDomainPage = withCardStateProvider(() => { ); } + if (!(domain.verification && domain.verification.status === 'verified')) { + void navigateToFlowStart(); + } return ( - } - sx={t => ({ - backgroundColor: t.colors.$blackAlpha50, - padding: `${t.space.$3} ${t.space.$4}`, - minHeight: t.sizes.$10, - })} - actionSx={t => ({ - color: t.colors.$danger500, - })} - actionLabel={localizationKeys('organizationProfile.verifiedDomainPage.actionLabel__remove')} - onActionClick={() => navigate(`../../domain/${domain.id}/remove`)} - > - {domain.name} - - @@ -154,7 +154,16 @@ export const VerifiedDomainPage = withCardStateProvider(() => { - + {allowsEdit && ( + + + + )} + + diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/VerifyDomainPage.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/VerifyDomainPage.tsx index b08e5c6482..b6f0a577d6 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/VerifyDomainPage.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/VerifyDomainPage.tsx @@ -5,7 +5,6 @@ import { useCoreOrganization, useEnvironment } from '../../contexts'; import { Button, descriptors, Flex, localizationKeys, Spinner } from '../../customizables'; import type { VerificationCodeCardProps } from '../../elements'; import { - BlockWithAction, ContentPage, Form, FormButtonContainer, @@ -18,14 +17,13 @@ import { CodeForm } from '../../elements/CodeForm'; import { useFetch, useLoadingStatus, useNavigateToFlowStart } from '../../hooks'; import { useRouter } from '../../router'; import { handleError, sleep, useFormControl } from '../../utils'; -import { EnrollmentBadge } from './EnrollmentBadge'; import { OrganizationProfileBreadcrumbs } from './OrganizationProfileNavbar'; export const VerifyDomainPage = withCardStateProvider(() => { const card = useCardState(); const { organizationSettings } = useEnvironment(); const { organization } = useCoreOrganization(); - const { params, navigate } = useRouter(); + const { params } = useRouter(); const { navigateToFlowStart } = useNavigateToFlowStart(); const [success, setSuccess] = React.useState(false); @@ -134,23 +132,6 @@ export const VerifyDomainPage = withCardStateProvider(() => { headerSubtitle={subtitle} Breadcrumbs={OrganizationProfileBreadcrumbs} > - } - sx={t => ({ - backgroundColor: t.colors.$blackAlpha50, - padding: `${t.space.$3} ${t.space.$4}`, - minHeight: t.sizes.$10, - })} - actionLabel={localizationKeys('organizationProfile.verifyDomainPage.actionLabel__remove')} - onActionClick={() => navigate(`../../../domain/${domain.id}/remove`)} - actionSx={t => ({ - color: t.colors.$danger500, - })} - > - {domain.name} - - & { - actionSx?: ThemableCssProp; - badge?: React.ReactElement; - textElementDescriptor?: ElementDescriptor; - textElementId?: ElementId; - textLocalizationKey?: LocalizationKey; - actionLabel?: LocalizationKey; - onActionClick?: (e: MouseEvent) => void | Promise; -}; - -/** - * Similar to ArrowBlockButton but just a container - * - An action is expected instead of an icon - */ -export const BlockWithAction = (props: ArrowBlockButtonProps) => { - const { - actionSx, - isLoading, - children, - textElementDescriptor, - textElementId, - textLocalizationKey, - badge, - onActionClick, - actionLabel, - ...rest - } = props; - - return ( - [ - { - borderRadius: theme.radii.$md, - display: 'inline-flex', - alignItems: 'center', - gap: theme.space.$4, - position: 'relative', - justifyContent: 'flex-start', - borderColor: theme.colors.$blackAlpha200, - '--action-opacity': '0', - '--action-transform': `translateX(-${theme.space.$2});`, - '&:hover,&:focus ': { - '--action-opacity': '1', - '--action-transform': 'translateX(0px);', - }, - }, - props.sx, - ]} - > - - - {children} - - {badge} - -