MFA: shuffled components to avoid re-rendering closing the setup dialog
This commit is contained in:
@@ -46,17 +46,25 @@ import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { MultiFactorAuthSetupDialog } from './multi-factor-auth-setup-dialog';
|
||||
|
||||
const MAX_FACTOR_COUNT = 10;
|
||||
|
||||
export function MultiFactorAuthFactorsList(props: { userId: string }) {
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<FactorsTableContainer userId={props.userId} />
|
||||
|
||||
<div>
|
||||
<MultiFactorAuthSetupDialog userId={props.userId} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FactorsTableContainer(props: { userId: string }) {
|
||||
const {
|
||||
data: factors,
|
||||
isLoading,
|
||||
isError,
|
||||
} = useFetchAuthFactors(props.userId);
|
||||
|
||||
const [unEnrolling, setUnenrolling] = useState<string>();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={'flex items-center space-x-4'}>
|
||||
@@ -103,37 +111,11 @@ export function MultiFactorAuthFactorsList(props: { userId: string }) {
|
||||
<Trans i18nKey={'account:multiFactorAuthDescription'} />
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<div>
|
||||
<MultiFactorAuthSetupDialog userId={props.userId} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const canAddNewFactors = allFactors.length < MAX_FACTOR_COUNT;
|
||||
|
||||
return (
|
||||
<div className={'flex flex-col space-y-4'}>
|
||||
<FactorsTable factors={allFactors} setUnenrolling={setUnenrolling} />
|
||||
|
||||
<If condition={canAddNewFactors}>
|
||||
<div>
|
||||
<MultiFactorAuthSetupDialog userId={props.userId} />
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<If condition={unEnrolling}>
|
||||
{(factorId) => (
|
||||
<ConfirmUnenrollFactorModal
|
||||
userId={props.userId}
|
||||
factorId={factorId}
|
||||
setIsModalOpen={() => setUnenrolling(undefined)}
|
||||
/>
|
||||
)}
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
return <FactorsTable factors={allFactors} userId={props.userId} />;
|
||||
}
|
||||
|
||||
function ConfirmUnenrollFactorModal(
|
||||
@@ -157,7 +139,7 @@ function ConfirmUnenrollFactorModal(
|
||||
const errorCode = response.data;
|
||||
|
||||
throw t(`auth:errors.${errorCode}`, {
|
||||
defaultValue: t(`account:unenrollFactorError`)
|
||||
defaultValue: t(`account:unenrollFactorError`),
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -205,75 +187,89 @@ function ConfirmUnenrollFactorModal(
|
||||
}
|
||||
|
||||
function FactorsTable({
|
||||
setUnenrolling,
|
||||
factors,
|
||||
userId,
|
||||
}: React.PropsWithChildren<{
|
||||
setUnenrolling: (factorId: string) => void;
|
||||
factors: Factor[];
|
||||
userId: string;
|
||||
}>) {
|
||||
const [unEnrolling, setUnenrolling] = useState<string>();
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
<Trans i18nKey={'account:factorName'} />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans i18nKey={'account:factorType'} />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans i18nKey={'account:factorStatus'} />
|
||||
</TableHead>
|
||||
<>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
<Trans i18nKey={'account:factorName'} />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans i18nKey={'account:factorType'} />
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
<Trans i18nKey={'account:factorStatus'} />
|
||||
</TableHead>
|
||||
|
||||
<TableHead />
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
||||
<TableBody>
|
||||
{factors.map((factor) => (
|
||||
<TableRow key={factor.id}>
|
||||
<TableCell>
|
||||
<span className={'block truncate'}>{factor.friendly_name}</span>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Badge variant={'info'} className={'inline-flex uppercase'}>
|
||||
{factor.factor_type}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
|
||||
<td>
|
||||
<Badge
|
||||
className={'inline-flex capitalize'}
|
||||
variant={factor.status === 'verified' ? 'success' : 'outline'}
|
||||
>
|
||||
{factor.status}
|
||||
</Badge>
|
||||
</td>
|
||||
|
||||
<td className={'flex justify-end'}>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
size={'icon'}
|
||||
onClick={() => setUnenrolling(factor.id)}
|
||||
>
|
||||
<X className={'h-4'} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent>
|
||||
<Trans i18nKey={'account:unenrollTooltip'} />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</td>
|
||||
<TableHead />
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableHeader>
|
||||
|
||||
<TableBody>
|
||||
{factors.map((factor) => (
|
||||
<TableRow key={factor.id}>
|
||||
<TableCell>
|
||||
<span className={'block truncate'}>{factor.friendly_name}</span>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Badge variant={'info'} className={'inline-flex uppercase'}>
|
||||
{factor.factor_type}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
|
||||
<td>
|
||||
<Badge
|
||||
className={'inline-flex capitalize'}
|
||||
variant={factor.status === 'verified' ? 'success' : 'outline'}
|
||||
>
|
||||
{factor.status}
|
||||
</Badge>
|
||||
</td>
|
||||
|
||||
<td className={'flex justify-end'}>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
size={'icon'}
|
||||
onClick={() => setUnenrolling(factor.id)}
|
||||
>
|
||||
<X className={'h-4'} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent>
|
||||
<Trans i18nKey={'account:unenrollTooltip'} />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</td>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<If condition={unEnrolling}>
|
||||
{(factorId) => (
|
||||
<ConfirmUnenrollFactorModal
|
||||
userId={userId}
|
||||
factorId={factorId}
|
||||
setIsModalOpen={() => setUnenrolling(undefined)}
|
||||
/>
|
||||
)}
|
||||
</If>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -291,13 +287,13 @@ function useUnenrollFactor(userId: string) {
|
||||
return {
|
||||
success: false as const,
|
||||
data: error.code as string,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true as const,
|
||||
data,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return useMutation({
|
||||
|
||||
@@ -53,7 +53,7 @@ export function MultiFactorAuthSetupDialog(props: { userId: string }) {
|
||||
const onEnrollSuccess = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
|
||||
return toast.success(t(`multiFactorSetupSuccess`));
|
||||
return toast.success(t(`account:multiFactorSetupSuccess`));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user