Skip to content

Commit

Permalink
feat(clerk-js): Add tabs to VerifiedDomainPage (#1624)
Browse files Browse the repository at this point in the history
* feat(clerk-js): Add tabs to VerifiedDomainPage

* chore(clerk-js): Add changeset

* fix(clerk-js): Avoid littering all input props with groupSuffix
  • Loading branch information
panteliselef authored Aug 25, 2023
1 parent 5a723c8 commit e4e1df8
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 45 deletions.
2 changes: 2 additions & 0 deletions .changeset/forty-cobras-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const AddDomainPage = withCardStateProvider(() => {
return null;
}

const canSubmit = organization.name !== nameField.value;
const canSubmit = nameField.value.trim() !== '';

const onSubmit = (e: React.FormEvent) => {
nameField.setError(undefined);
Expand All @@ -35,7 +35,7 @@ export const AddDomainPage = withCardStateProvider(() => {
.createDomain(nameField.value)
.then(res => {
if (res.verification && res.verification.status === 'verified') {
return navigate(`../domain/${res.id}`);
return navigate(`../domain/${res.id}?mode=select`);
}
return navigate(`../domain/${res.id}/verify`);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const RemoveDomainPage = () => {
successMessage={localizationKeys('organizationProfile.removeDomainPage.successMessage', {
domain: ref.current?.name,
})}
deleteResource={() => domain?.delete().then((domains as any).unstable__mutate())}
deleteResource={() => domain?.delete().then(() => (domains as any).unstable__mutate())}
breadcrumbTitle={localizationKeys('organizationProfile.profilePage.domainSection.title')}
Breadcrumbs={OrganizationProfileBreadcrumbs}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@ import type { OrganizationEnrollmentMode } from '@clerk/types';

import { useCoreOrganization, useEnvironment } from '../../contexts';
import { Col, Flex, localizationKeys, Spinner } from '../../customizables';
import { ContentPage, Form, FormButtons, Header, useCardState, withCardStateProvider } from '../../elements';
import {
ContentPage,
Form,
FormButtons,
Header,
Tab,
TabPanel,
TabPanels,
Tabs,
TabsList,
useCardState,
withCardStateProvider,
} from '../../elements';
import { useFetch, useNavigateToFlowStart } from '../../hooks';
import { useRouter } from '../../router';
import { handleError, useFormControl } from '../../utils';
import { LinkButtonWithDescription } from '../UserProfile/LinkButtonWithDescription';
import { OrganizationProfileBreadcrumbs } from './OrganizationProfileNavbar';

export const VerifiedDomainPage = withCardStateProvider(() => {
Expand All @@ -19,7 +32,7 @@ export const VerifiedDomainPage = withCardStateProvider(() => {
});
const { navigateToFlowStart } = useNavigateToFlowStart();
const { params, navigate, queryParams } = useRouter();
const mode = (queryParams.mode ?? 'edit') as 'select' | 'edit';
const mode = (queryParams.mode || 'edit') as 'select' | 'edit';

const breadcrumbTitle = localizationKeys('organizationProfile.profilePage.domainSection.title');
const allowsEdit = mode === 'edit';
Expand Down Expand Up @@ -87,6 +100,10 @@ export const VerifiedDomainPage = withCardStateProvider(() => {
);

const isFormDirty = deletePending.checked || domain?.enrollmentMode !== enrollmentMode.value;
const subtitle = localizationKeys('organizationProfile.verifiedDomainPage.subtitle', {
domain: domain?.name,
});

const updateEnrollmentMode = async () => {
if (!domain || !organization) {
return;
Expand Down Expand Up @@ -134,39 +151,82 @@ export const VerifiedDomainPage = withCardStateProvider(() => {
}
return (
<ContentPage
headerTitle={domain?.name}
headerTitle={domain.name}
headerSubtitle={allowsEdit ? undefined : subtitle}
breadcrumbTitle={breadcrumbTitle}
gap={4}
Breadcrumbs={OrganizationProfileBreadcrumbs}
>
<Col gap={2}>
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.verifiedDomainPage.start.headerTitle__enrollment')}
textVariant='largeMedium'
/>
<Header.Subtitle
localizationKey={localizationKeys('organizationProfile.verifiedDomainPage.enrollmentTab.subtitle')}
variant='regularRegular'
/>
</Header.Root>

<Form.Root onSubmit={updateEnrollmentMode}>
<Form.ControlRow elementId={enrollmentMode.id}>
<Form.Control {...enrollmentMode.props} />
</Form.ControlRow>

{allowsEdit && (
<Form.ControlRow elementId={deletePending.id}>
<Form.Control {...deletePending.props} />
</Form.ControlRow>
)}

<FormButtons
localizationKey={localizationKeys('organizationProfile.verifiedDomainPage.enrollmentTab.formButton__save')}
isDisabled={domainStatus.isLoading || !domain || !isFormDirty}
/>
</Form.Root>
<Col gap={6}>
<Tabs>
<TabsList>
<Tab
localizationKey={localizationKeys('organizationProfile.verifiedDomainPage.start.headerTitle__enrollment')}
/>
{allowsEdit && (
<Tab
localizationKey={localizationKeys('organizationProfile.verifiedDomainPage.start.headerTitle__danger')}
/>
)}
</TabsList>
<TabPanels>
<TabPanel
sx={{ width: '100%' }}
direction={'col'}
gap={4}
>
<Header.Root>
<Header.Subtitle
localizationKey={localizationKeys('organizationProfile.verifiedDomainPage.enrollmentTab.subtitle')}
variant='regularRegular'
/>
</Header.Root>
<Form.Root
onSubmit={updateEnrollmentMode}
gap={6}
>
<Form.ControlRow elementId={enrollmentMode.id}>
<Form.Control {...enrollmentMode.props} />
</Form.ControlRow>

{allowsEdit && (
<Form.ControlRow elementId={deletePending.id}>
<Form.Control {...deletePending.props} />
</Form.ControlRow>
)}

<FormButtons
localizationKey={localizationKeys(
'organizationProfile.verifiedDomainPage.enrollmentTab.formButton__save',
)}
isDisabled={domainStatus.isLoading || !domain || !isFormDirty}
/>
</Form.Root>
</TabPanel>

{allowsEdit && (
<TabPanel
direction={'col'}
sx={[
{ width: '100%' },
t => ({
padding: `${t.space.$none} ${t.space.$4}`,
}),
]}
>
<LinkButtonWithDescription
title={localizationKeys('organizationProfile.verifiedDomainPage.dangerTab.removeDomainTitle')}
subtitle={localizationKeys('organizationProfile.verifiedDomainPage.dangerTab.removeDomainSubtitle')}
actionLabel={localizationKeys(
'organizationProfile.verifiedDomainPage.dangerTab.removeDomainActionLabel__remove',
)}
colorScheme='danger'
onClick={() => navigate(`../../domain/${domain.id}/remove`)}
/>
</TabPanel>
)}
</TabPanels>
</Tabs>
</Col>
</ContentPage>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
withCardStateProvider,
} from '../../elements';
import { CodeForm } from '../../elements/CodeForm';
import { useFetch, useLoadingStatus, useNavigateToFlowStart } from '../../hooks';
import { useFetch, useLoadingStatus } from '../../hooks';
import { useRouter } from '../../router';
import { handleError, sleep, useFormControl } from '../../utils';
import { OrganizationProfileBreadcrumbs } from './OrganizationProfileNavbar';
Expand All @@ -23,8 +23,7 @@ export const VerifyDomainPage = withCardStateProvider(() => {
const card = useCardState();
const { organizationSettings } = useEnvironment();
const { organization } = useCoreOrganization();
const { params } = useRouter();
const { navigateToFlowStart } = useNavigateToFlowStart();
const { params, navigate } = useRouter();

const [success, setSuccess] = React.useState(false);

Expand Down Expand Up @@ -72,7 +71,7 @@ export const VerifyDomainPage = withCardStateProvider(() => {
.then(async res => {
await resolve();
if (res.verification?.status === 'verified') {
return navigateToFlowStart();
return navigate(`../../../domain/${res.id}?mode=select`);
}
return;
})
Expand Down Expand Up @@ -105,16 +104,17 @@ export const VerifyDomainPage = withCardStateProvider(() => {

const dataChanged = organization.name !== emailField.value;
const canSubmit = dataChanged;
const emailDomainSuffix = `@${domain?.name}`;

const onSubmitPrepare = (e: React.FormEvent) => {
e.preventDefault();
if (!domain) {
return;
}
affiliationEmailAddressRef.current = `${emailField.value}@${domain.name}`;
affiliationEmailAddressRef.current = `${emailField.value}${emailDomainSuffix}`;
return domain
.prepareAffiliationVerification({
affiliationEmailAddress: `${emailField.value}@${domain.name}`,
affiliationEmailAddress: affiliationEmailAddressRef.current,
})
.then(wizard.nextStep)
.catch(err => {
Expand Down
2 changes: 0 additions & 2 deletions packages/clerk-js/src/ui/elements/FormControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,6 @@ export const FormControl = forwardRef<HTMLInputElement, PropsWithChildren<FormCo

const Input = (
<InputElement
groupPreffix={groupPreffix}
groupSuffix={groupSuffix}
elementDescriptor={descriptors.formFieldInput}
elementId={descriptors.formFieldInput.setId(id)}
hasError={!!errorMessage}
Expand Down
11 changes: 8 additions & 3 deletions packages/localizations/src/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const enUS: LocalizationResource = {
formFieldLabel__backupCode: 'Backup code',
formFieldLabel__organizationName: 'Organization name',
formFieldLabel__organizationSlug: 'Slug URL',
formFieldLabel__organizationDomain: 'Email domain',
formFieldLabel__organizationDomain: 'Domain',
formFieldLabel__organizationDomainEmailAddress: 'Verification email address',
formFieldLabel__organizationDomainEmailAddressDescription:
'Enter an email address under this domain to receive a code and verify this domain.',
Expand Down Expand Up @@ -587,9 +587,9 @@ export const enUS: LocalizationResource = {
},
},
createDomainPage: {
title: 'Add email domain',
title: 'Add domain',
subtitle:
'Add the email domain to verify. Users with email addresses at this domain can join the organization automatically or request to join.',
'Add the domain to verify. Users with email addresses at this domain can join the organization automatically or request to join.',
},
verifyDomainPage: {
title: 'Verify domain',
Expand Down Expand Up @@ -617,6 +617,11 @@ export const enUS: LocalizationResource = {
'Users receive a suggestion to request to join, but must be approved by an admin before they are able to join the organization.',
formButton__save: 'Save',
},
dangerTab: {
removeDomainTitle: 'Remove domain',
removeDomainSubtitle: 'Remove this domain from your verified domains',
removeDomainActionLabel__remove: 'Remove domain',
},
},
invitePage: {
title: 'Invite members',
Expand Down

0 comments on commit e4e1df8

Please sign in to comment.