feat: add Reset MFA action for team members

Adds a Reset MFA button in the Actions column and an inline confirmation
card (with warning Alert) that calls useResetTeamMemberMfa on confirm.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-26 14:06:20 +02:00
parent 7e7407b137
commit d52084a081

View File

@@ -19,6 +19,7 @@ import {
useInviteTeamMember,
useRemoveTeamMember,
useResetTeamMemberPassword,
useResetTeamMemberMfa,
} from '../../api/tenant-hooks';
import styles from '../../styles/platform.module.css';
@@ -59,6 +60,7 @@ export function TeamPage() {
const inviteMember = useInviteTeamMember();
const removeMember = useRemoveTeamMember();
const resetPassword = useResetTeamMemberPassword();
const resetMfa = useResetTeamMemberMfa();
const { toast } = useToast();
const [showInvite, setShowInvite] = useState(false);
@@ -68,6 +70,7 @@ export function TeamPage() {
const [removeTarget, setRemoveTarget] = useState<TeamMember | null>(null);
const [pwTarget, setPwTarget] = useState<TeamMember | null>(null);
const [pwValue, setPwValue] = useState('');
const [mfaResetTarget, setMfaResetTarget] = useState<TeamMember | null>(null);
const team: TeamMember[] = (rawTeam ?? []).map(toMember).filter((m) => m.id !== '');
@@ -100,6 +103,13 @@ export function TeamPage() {
>
Reset Password
</Button>
<Button
variant="secondary"
size="small"
onClick={() => setMfaResetTarget(row)}
>
Reset MFA
</Button>
<Button
variant="danger"
onClick={(e) => { e.stopPropagation(); setRemoveTarget(row); }}
@@ -244,6 +254,33 @@ export function TeamPage() {
loading={removeMember.isPending}
/>
{/* Reset MFA inline form */}
{mfaResetTarget && (
<Card title={`Reset MFA for ${mfaResetTarget.name || mfaResetTarget.email}`} style={{ marginTop: 16 }}>
<Alert variant="warning">
This will remove all MFA factors for this user. They will need to re-enroll if MFA is required.
</Alert>
<div style={{ display: 'flex', gap: 8, marginTop: 16 }}>
<Button
variant="danger"
onClick={async () => {
try {
await resetMfa.mutateAsync(mfaResetTarget.id);
toast({ title: `MFA reset for ${mfaResetTarget.name || mfaResetTarget.email}`, variant: 'success' });
setMfaResetTarget(null);
} catch (err) {
toast({ title: 'Failed to reset MFA', description: String(err), variant: 'error' });
}
}}
loading={resetMfa.isPending}
>
Confirm Reset MFA
</Button>
<Button variant="secondary" onClick={() => setMfaResetTarget(null)}>Cancel</Button>
</div>
</Card>
)}
{/* Reset password inline form */}
{pwTarget && (
<Card title={`Reset password for ${pwTarget.name}`}>