Skip to content

Commit 0388a7d

Browse files
refactor(mosaic): require a controller for email reverification
1 parent 940e1fe commit 0388a7d

4 files changed

Lines changed: 41 additions & 13 deletions

File tree

‎packages/mosaic/src/features/user-profile/user-profile-email-section/__tests__/user-profile-add-email.dialog.test.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { MosaicProvider } from '../../../../mosaic-provider';
77
import type { UserProfileAddEmailDialogProps } from '../user-profile-add-email.dialog';
88
import { UserProfileAddEmailDialog } from '../user-profile-add-email.dialog';
99

10-
function renderView(overrides: Partial<UserProfileAddEmailDialogProps> = {}) {
10+
function renderView(overrides: Partial<Exclude<UserProfileAddEmailDialogProps, { step: 'reverify' }>> = {}) {
1111
const props: UserProfileAddEmailDialogProps = {
1212
open: true,
1313
onOpenChange: vi.fn(),

‎packages/mosaic/src/features/user-profile/user-profile-email-section/user-profile-add-email.controller.ts‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ export interface UserProfileAddEmailControllerOptions {
2626
reverification?: ReverificationController;
2727
}
2828

29-
export interface UserProfileAddEmailController extends UserProfileAddEmailDialogProps {
29+
export type UserProfileAddEmailController = UserProfileAddEmailDialogProps & {
3030
handle: DialogHandle<unknown>;
3131
verifyingId: string | undefined;
3232
onVerifyEmail: (email: Pick<UserProfileEmail, 'id' | 'value'>, verifier: UserProfileEmailVerifier) => void;
33-
}
33+
};
3434

3535
interface Context {
3636
verifyingId: string | undefined;
@@ -202,8 +202,7 @@ export function useUserProfileAddEmailController({
202202
return () => clearTimeout(timer);
203203
}, [open, resendSeconds, send]);
204204

205-
const isReverifying = emailForm.isSubmitting && Boolean(reverification?.visible);
206-
const step = isReverifying ? 'reverify' : toStep(state, verification);
205+
const isReverifying = emailForm.isSubmitting && reverification?.visible;
207206
const form = state === 'email' ? emailForm : codeForm;
208207
const formError = state === 'email' ? emailForm.fields.emailAddress.feedback : codeForm.fields.code.feedback;
209208
const machineError = error?.global ? errorText(error.global) : undefined;
@@ -213,8 +212,9 @@ export function useUserProfileAddEmailController({
213212
resendSeconds,
214213
isResending: state === 'sending',
215214
open,
216-
step,
217-
reverification,
215+
...(isReverifying
216+
? { step: 'reverify' as const, reverification }
217+
: { step: toStep(state, verification), reverification }),
218218
emailAddress: state === 'email' ? emailForm.values.emailAddress : snapshot.context.emailAddress,
219219
canSubmitEmail: emailForm.canSubmit || emailForm.isSubmitting,
220220
code: codeForm.values.code,
@@ -266,7 +266,7 @@ export function useUserProfileAddEmailController({
266266
function toStep(
267267
state: string,
268268
verification: UserProfileEmailVerification | undefined,
269-
): UserProfileAddEmailDialogProps['step'] {
269+
): Exclude<UserProfileAddEmailDialogProps['step'], 'reverify'> {
270270
if (state === 'email') {
271271
return 'email';
272272
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { describe, expectTypeOf, test } from 'vitest';
2+
3+
import type { ReverificationController } from '../../reverification';
4+
import type { UserProfileAddEmailDialogProps } from './user-profile-add-email.dialog';
5+
6+
type BaseProps = Omit<UserProfileAddEmailDialogProps, 'step' | 'reverification'>;
7+
8+
describe('UserProfileAddEmailDialogProps', () => {
9+
test('requires a controller for the reverification step', () => {
10+
expectTypeOf<BaseProps & { step: 'reverify' }>().not.toExtend<UserProfileAddEmailDialogProps>();
11+
expectTypeOf<
12+
BaseProps & { step: 'reverify'; reverification: undefined }
13+
>().not.toExtend<UserProfileAddEmailDialogProps>();
14+
});
15+
16+
test('accepts a controller for the reverification step', () => {
17+
expectTypeOf<
18+
BaseProps & { step: 'reverify'; reverification: ReverificationController }
19+
>().toExtend<UserProfileAddEmailDialogProps>();
20+
});
21+
22+
test('allows the other steps without a controller', () => {
23+
expectTypeOf<
24+
BaseProps & { step: 'email' | 'verify' | 'link' | 'sso' }
25+
>().toExtend<UserProfileAddEmailDialogProps>();
26+
});
27+
});

‎packages/mosaic/src/features/user-profile/user-profile-email-section/user-profile-add-email.dialog.tsx‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,11 @@ const styles = stylex.create({
2525
},
2626
});
2727

28-
export interface UserProfileAddEmailDialogProps {
28+
export type UserProfileAddEmailDialogProps = {
2929
open: boolean;
3030
onOpenChange: (open: boolean) => void;
3131
handle?: DialogHandle<unknown>;
3232
finalFocus?: DialogFocusTarget;
33-
step: 'email' | 'reverify' | 'verify' | 'link' | 'sso';
34-
reverification?: ReverificationController;
3533
emailAddress: string;
3634
onEmailAddressChange: (value: string) => void;
3735
canSubmitEmail?: boolean;
@@ -44,7 +42,10 @@ export interface UserProfileAddEmailDialogProps {
4442
errorMessage?: string;
4543
isResending?: boolean;
4644
resendSeconds?: number;
47-
}
45+
} & (
46+
| { step: 'reverify'; reverification: ReverificationController }
47+
| { step: 'email' | 'verify' | 'link' | 'sso'; reverification?: ReverificationController }
48+
);
4849

4950
export function UserProfileAddEmailDialog(props: UserProfileAddEmailDialogProps) {
5051
const emailRef = useRef<HTMLInputElement>(null);
@@ -85,7 +86,7 @@ export function UserProfileAddEmailDialog(props: UserProfileAddEmailDialogProps)
8586
/>
8687
</Flow.Step>
8788
<Flow.Step ids={['reverify']}>
88-
{current.reverification ? (
89+
{current.step === 'reverify' ? (
8990
<ReverifyStep
9091
controller={current.reverification}
9192
onClose={() => current.onOpenChange(false)}

0 commit comments

Comments
 (0)