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';
|
import { MultiFactorAuthSetupDialog } from './multi-factor-auth-setup-dialog';
|
||||||
|
|
||||||
const MAX_FACTOR_COUNT = 10;
|
|
||||||
|
|
||||||
export function MultiFactorAuthFactorsList(props: { userId: string }) {
|
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 {
|
const {
|
||||||
data: factors,
|
data: factors,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
} = useFetchAuthFactors(props.userId);
|
} = useFetchAuthFactors(props.userId);
|
||||||
|
|
||||||
const [unEnrolling, setUnenrolling] = useState<string>();
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className={'flex items-center space-x-4'}>
|
<div className={'flex items-center space-x-4'}>
|
||||||
@@ -103,37 +111,11 @@ export function MultiFactorAuthFactorsList(props: { userId: string }) {
|
|||||||
<Trans i18nKey={'account:multiFactorAuthDescription'} />
|
<Trans i18nKey={'account:multiFactorAuthDescription'} />
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
<div>
|
|
||||||
<MultiFactorAuthSetupDialog userId={props.userId} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const canAddNewFactors = allFactors.length < MAX_FACTOR_COUNT;
|
return <FactorsTable factors={allFactors} userId={props.userId} />;
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConfirmUnenrollFactorModal(
|
function ConfirmUnenrollFactorModal(
|
||||||
@@ -157,7 +139,7 @@ function ConfirmUnenrollFactorModal(
|
|||||||
const errorCode = response.data;
|
const errorCode = response.data;
|
||||||
|
|
||||||
throw t(`auth:errors.${errorCode}`, {
|
throw t(`auth:errors.${errorCode}`, {
|
||||||
defaultValue: t(`account:unenrollFactorError`)
|
defaultValue: t(`account:unenrollFactorError`),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -205,75 +187,89 @@ function ConfirmUnenrollFactorModal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function FactorsTable({
|
function FactorsTable({
|
||||||
setUnenrolling,
|
|
||||||
factors,
|
factors,
|
||||||
|
userId,
|
||||||
}: React.PropsWithChildren<{
|
}: React.PropsWithChildren<{
|
||||||
setUnenrolling: (factorId: string) => void;
|
|
||||||
factors: Factor[];
|
factors: Factor[];
|
||||||
|
userId: string;
|
||||||
}>) {
|
}>) {
|
||||||
|
const [unEnrolling, setUnenrolling] = useState<string>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table>
|
<>
|
||||||
<TableHeader>
|
<Table>
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>
|
<TableRow>
|
||||||
<Trans i18nKey={'account:factorName'} />
|
<TableHead>
|
||||||
</TableHead>
|
<Trans i18nKey={'account:factorName'} />
|
||||||
<TableHead>
|
</TableHead>
|
||||||
<Trans i18nKey={'account:factorType'} />
|
<TableHead>
|
||||||
</TableHead>
|
<Trans i18nKey={'account:factorType'} />
|
||||||
<TableHead>
|
</TableHead>
|
||||||
<Trans i18nKey={'account:factorStatus'} />
|
<TableHead>
|
||||||
</TableHead>
|
<Trans i18nKey={'account:factorStatus'} />
|
||||||
|
</TableHead>
|
||||||
|
|
||||||
<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>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
</TableHeader>
|
||||||
</TableBody>
|
|
||||||
</Table>
|
<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 {
|
return {
|
||||||
success: false as const,
|
success: false as const,
|
||||||
data: error.code as string,
|
data: error.code as string,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true as const,
|
success: true as const,
|
||||||
data,
|
data,
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function MultiFactorAuthSetupDialog(props: { userId: string }) {
|
|||||||
const onEnrollSuccess = useCallback(() => {
|
const onEnrollSuccess = useCallback(() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
|
|
||||||
return toast.success(t(`multiFactorSetupSuccess`));
|
return toast.success(t(`account:multiFactorSetupSuccess`));
|
||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user