Skip to content

Commit

Permalink
feat(clerk-js): Retheme UsernameSection and EmailsSection
Browse files Browse the repository at this point in the history
  • Loading branch information
desiprisg committed Dec 14, 2023
1 parent dad8829 commit feccba8
Show file tree
Hide file tree
Showing 31 changed files with 420 additions and 359 deletions.
2 changes: 2 additions & 0 deletions .changeset/smart-ways-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
15 changes: 8 additions & 7 deletions packages/clerk-js/src/ui/common/RemoveResourcePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';

import { Text } from '../customizables';
import { Form, FormButtons, FormContent, SuccessPage, useCardState, withCardStateProvider } from '../elements';
import { useActionContext } from '../elements/Action/ActionRoot';
import type { LocalizationKey } from '../localization';
import { handleError } from '../utils';
import { useWizard, Wizard } from './Wizard';
Expand All @@ -17,9 +18,10 @@ type RemovePageProps = {
};

export const RemoveResourcePage = withCardStateProvider((props: RemovePageProps) => {
const { title, messageLine1, messageLine2, breadcrumbTitle, successMessage, deleteResource } = props;
const { title, messageLine1, messageLine2, successMessage, deleteResource } = props;
const wizard = useWizard();
const card = useCardState();
const { close } = useActionContext();

const handleSubmit = async () => {
try {
Expand All @@ -31,15 +33,14 @@ export const RemoveResourcePage = withCardStateProvider((props: RemovePageProps)

return (
<Wizard {...wizard.props}>
<FormContent
headerTitle={title}
breadcrumbTitle={breadcrumbTitle}
Breadcrumbs={props.Breadcrumbs}
>
<FormContent headerTitle={title}>
<Form.Root onSubmit={handleSubmit}>
<Text localizationKey={messageLine1} />
<Text localizationKey={messageLine2} />
<FormButtons variant='primaryDanger' />
<FormButtons
variant='primaryDanger'
onReset={close}
/>
</Form.Root>
</FormContent>
<SuccessPage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Col, descriptors, localizationKeys } from '../../customizables';
import { Card, Header, useCardState, withCardStateProvider } from '../../elements';
import { NavbarMenuButtonRow } from '../../elements/Navbar';
import { ConnectedAccountsSection } from './ConnectedAccountsSection';
import { EmailsSection } from './EmailSection';
import { EmailsSection } from './EmailsSection';
import { EnterpriseAccountsSection } from './EnterpriseAccountsSection';
import { PhoneSection } from './PhoneSection';
import { UsernameSection } from './UsernameSection';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@ import { useWizard, Wizard } from '../../common';
import { useEnvironment } from '../../contexts';
import { localizationKeys, Text } from '../../customizables';
import { Form, FormButtons, FormContent, SuccessPage, useCardState, withCardStateProvider } from '../../elements';
import { useRouter } from '../../router';
import { useActionContext } from '../../elements/Action/ActionRoot';
import { handleError, useFormControl } from '../../utils';
import { UserProfileBreadcrumbs } from './UserProfileNavbar';
import { emailLinksEnabledForInstance } from './utils';
import { VerifyWithCode } from './VerifyWithCode';
import { VerifyWithLink } from './VerifyWithLink';

export const EmailPage = withCardStateProvider(() => {
type EmailFormProps = {
emailId?: string;
};
export const EmailForm = withCardStateProvider((props: EmailFormProps) => {
const { emailId: id } = props;
const title = localizationKeys('userProfile.emailAddressPage.title');
const card = useCardState();
const { user } = useUser();
const { close } = useActionContext();
const environment = useEnvironment();
const preferEmailLinks = emailLinksEnabledForInstance(environment);

const { params } = useRouter();
const { id } = params || {};

const emailAddressRef = React.useRef<EmailAddressResource | undefined>(user?.emailAddresses.find(a => a.id === id));
const wizard = useWizard({
defaultStep: emailAddressRef.current ? 1 : 0,
Expand Down Expand Up @@ -69,7 +71,10 @@ export const EmailPage = withCardStateProvider(() => {
: localizationKeys('userProfile.emailAddressPage.emailCode.formHint')
}
/>
<FormButtons isDisabled={!canSubmit} />
<FormButtons
isDisabled={!canSubmit}
onReset={close}
/>
</Form.Root>
</FormContent>

Expand All @@ -81,13 +86,15 @@ export const EmailPage = withCardStateProvider(() => {
<VerifyWithLink
nextStep={wizard.nextStep}
email={emailAddressRef.current as any}
onReset={close}
/>
) : (
<VerifyWithCode
nextStep={wizard.nextStep}
identification={emailAddressRef.current}
identifier={emailAddressRef.current?.emailAddress}
prepareVerification={() => emailAddressRef.current?.prepareVerification({ strategy: 'email_code' })}
onReset={close}
/>
)}
</FormContent>
Expand All @@ -103,6 +110,7 @@ export const EmailPage = withCardStateProvider(() => {
identifier: emailAddressRef.current?.emailAddress || '',
})
}
onFinish={close}
/>
</Wizard>
);
Expand Down
104 changes: 0 additions & 104 deletions packages/clerk-js/src/ui/components/UserProfile/EmailSection.tsx

This file was deleted.

123 changes: 123 additions & 0 deletions packages/clerk-js/src/ui/components/UserProfile/EmailsSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { useUser } from '@clerk/shared/react';
import type { EmailAddressResource } from '@clerk/types';

import { Badge, Button, Col, Flex, localizationKeys, Text } from '../../customizables';
import { ProfileSection, ThreeDotsMenu, useCardState } from '../../elements';
import { Action } from '../../elements/Action';
import { useActionContext } from '../../elements/Action/ActionRoot';
import type { PropsOfComponent } from '../../styledSystem';
import { handleError } from '../../utils';
import { EmailForm } from './EmailForm';
import { RemoveEmailForm } from './RemoveResourcePage';
import { primaryIdentificationFirst } from './utils';

export const EmailsSection = () => {
const { user } = useUser();

return (
<ProfileSection
title={localizationKeys('userProfile.start.emailAddressesSection.title')}
id='emailAddresses'
>
<Action.Root>
<Col>
{user?.emailAddresses.sort(primaryIdentificationFirst(user.primaryEmailAddressId)).map(email => (
<Action.Root key={email.emailAddress}>
<Action.Closed value=''>
<Flex sx={t => ({ justifyContent: 'space-between', padding: `${t.space.$1} ${t.space.$4}` })}>
<Text>
{email.emailAddress}{' '}
{user?.primaryEmailAddressId === email.id && (
<Badge localizationKey={localizationKeys('badge__primary')} />
)}
{email.verification.status !== 'verified' && (
<Badge localizationKey={localizationKeys('badge__unverified')} />
)}
</Text>

<EmailMenu
key={email.id}
email={email}
/>
</Flex>
</Action.Closed>

<Action.Open value='remove'>
<Action.Card>
<RemoveEmailForm emailId={email.id} />
</Action.Card>
</Action.Open>

<Action.Open value='verify'>
<Action.Card>
<EmailForm emailId={email.id} />
</Action.Card>
</Action.Open>
</Action.Root>
))}

<Action.Trigger value='add'>
<Button
id='emailAddresses'
variant='ghost'
sx={t => ({ justifyContent: 'start', padding: `${t.space.$1} ${t.space.$4}` })}
localizationKey={localizationKeys('userProfile.start.emailAddressesSection.primaryButton')}
/>
</Action.Trigger>
</Col>

<Action.Open value='add'>
<Action.Card>
<EmailForm />
</Action.Card>
</Action.Open>
</Action.Root>
</ProfileSection>
);
};

const EmailMenu = ({ email }: { email: EmailAddressResource }) => {
const card = useCardState();
const { user } = useUser();
const { open } = useActionContext();
const isPrimary = user?.primaryEmailAddressId === email.id;
const isVerified = email.verification.status === 'verified';
const setPrimary = () => {
return user!.update({ primaryEmailAddressId: email.id }).catch(e => handleError(e, [], card.setError));
};

const actions = (
[
isPrimary && !isVerified
? {
label: localizationKeys('userProfile.start.emailAddressesSection.detailsAction__primary'),
onClick: () => open('verify'),
}
: null,
!isPrimary && isVerified
? {
label: localizationKeys('userProfile.start.emailAddressesSection.detailsAction__nonPrimary'),
onClick: setPrimary,
}
: null,
!isPrimary && !isVerified
? {
label: localizationKeys('userProfile.start.emailAddressesSection.detailsAction__unverified'),
onClick: () => open('verify'),
}
: null,
{
label: localizationKeys('userProfile.start.emailAddressesSection.destructiveAction'),
isDestructive: true,
onClick: () => open('remove'),
},
] satisfies (PropsOfComponent<typeof ThreeDotsMenu>['actions'][0] | null)[]
).filter(a => a !== null) as PropsOfComponent<typeof ThreeDotsMenu>['actions'];

return (
<ThreeDotsMenu
actions={actions}
elementId={'member'}
/>
);
};
3 changes: 3 additions & 0 deletions packages/clerk-js/src/ui/components/UserProfile/PhonePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useWizard, Wizard } from '../../common';
import type { LocalizationKey } from '../../customizables';
import { localizationKeys, Text } from '../../customizables';
import { Form, FormButtons, FormContent, SuccessPage, useCardState, withCardStateProvider } from '../../elements';
import { useActionContext } from '../../elements/Action/ActionRoot';
import { useRouter } from '../../router';
import { handleError, useFormControl } from '../../utils';
import { UserProfileBreadcrumbs } from './UserProfileNavbar';
Expand Down Expand Up @@ -97,6 +98,7 @@ export const AddPhone = (props: AddPhoneProps) => {

export const VerifyPhone = (props: AddPhoneProps) => {
const { title, onSuccess, resourceRef } = props;
const { close } = useActionContext();

return (
<FormContent
Expand All @@ -108,6 +110,7 @@ export const VerifyPhone = (props: AddPhoneProps) => {
identification={resourceRef.current}
identifier={resourceRef.current?.phoneNumber}
prepareVerification={resourceRef.current?.prepareVerification}
onReset={close}
/>
</FormContent>
);
Expand Down
Loading

0 comments on commit feccba8

Please sign in to comment.