Skip to content

Commit 6f2c70b

Browse files
refactor(mosaic): use shared clock for OTP countdown
1 parent b5722b9 commit 6f2c70b

1 file changed

Lines changed: 3 additions & 16 deletions

File tree

‎packages/mosaic/src/features/reverification/reverification.controller.ts‎

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { isClerkRuntimeError } from '@clerk/shared/error';
2-
import { useEffect, useMemo, useState } from 'react';
2+
import { useEffect, useMemo } from 'react';
33

44
import type { FlowDirection } from '../../components/flow';
5+
import { useNow } from '../../hooks/use-now';
56
import type { ErrorDescription } from '../../localization';
67
import { useErrorText, useMessages } from '../../localization';
78
import { setup } from '../../machine/setup';
@@ -538,19 +539,11 @@ function useReverificationState(model: ReverificationModel): ReverificationContr
538539
: undefined,
539540
);
540541

541-
const [now, setNow] = useState(() => Date.now());
542542
const resendAvailableAt = snapshot.context.resendAvailableAt;
543+
const now = useNow({ updateInterval: resendAvailableAt === undefined ? undefined : 1000 }).getTime();
543544
const canResend = resendAvailableAt === undefined || now >= resendAvailableAt;
544545
const countingDown = !canResend;
545546

546-
useEffect(() => {
547-
if (!countingDown) {
548-
return;
549-
}
550-
const id = window.setInterval(() => setNow(Date.now()), 1000);
551-
return () => window.clearInterval(id);
552-
}, [countingDown, resendAvailableAt]);
553-
554547
const cancelModel =
555548
(model.status === 'loading' || model.status === 'active') && snapshot.value !== 'retrying'
556549
? model.cancel
@@ -622,12 +615,6 @@ function useReverificationState(model: ReverificationModel): ReverificationContr
622615
otpChannel: activeMethod ? otpChannelFor(activeMethod.strategy) : undefined,
623616
onResend: () => send({ type: 'RESEND' }),
624617
canResend,
625-
// We clamp this to 30s because the first render after locking resend
626-
// will have the old `now` state set, which would result in a value above
627-
// 30s. There are other solutions like reading Date.now() in render and
628-
// letting the interval only retrigger render, but that makes the render
629-
// impure which is something the React compiler would warn about.
630-
// useSyncExternalStore feels unnecessarily complex here
631618
resendRemainingSeconds:
632619
countingDown && resendAvailableAt
633620
? Math.min(RESEND_COOLDOWN_MS / 1000, Math.max(0, Math.ceil((resendAvailableAt - now) / 1000)))

0 commit comments

Comments
 (0)