"use client"; import { useState } from "react"; import { Button } from "../../ui/button"; import { useToast } from "../../ui/use-toast"; import type { Account } from "@/lib/db"; import { User } from "revolt-api"; import { cancelAccountDeletion, changeAccountEmail, deleteMFARecoveryCodes, disableAccount, disableMFA, queueAccountDeletion, restoreAccount, verifyAccountEmail, } from "@/lib/actions"; import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "../../ui/alert-dialog"; import { AlertDialogDescription } from "@radix-ui/react-alert-dialog"; import { Input } from "@/components/ui/input"; dayjs.extend(relativeTime); export function AccountActions({ account, user, }: { account: Account; user?: User; }) { const { toast } = useToast(); const [accountDraft, setAccountDraft] = useState(account); const [emailDraft, setEmailDraft] = useState(""); return (
Update account email setEmailDraft(e.currentTarget.value)} value={emailDraft} /> Cancel { try { await changeAccountEmail(account._id, emailDraft); setEmailDraft(""); toast({ title: "Updated email" }); window.location.reload(); } catch (err) { toast({ title: "Failed to execute action", description: String(err), variant: "destructive", }); } }} > Change Mark Email as verified Verification status is currently {accountDraft.verification.status}. Cancel { try { await verifyAccountEmail(account._id); toast({ title: "Verified email" }); setAccountDraft({ ...accountDraft, verification: { status: "Verified" } }); } catch(e) { toast({ title: "Failed to verify", description: String(e), variant: "destructive", }) } }} > Mark verified { navigator.clipboard.writeText(`https://app.revolt.chat/login/verify/${(accountDraft.verification as any).token}`); toast({ title: "Copied verification link" }) }} > Copy link Manage MFA MFA is currently { accountDraft.mfa?.totp_token?.status == "Pending" ? "pending setup" : (accountDraft.mfa?.totp_token?.status.toLowerCase() || "disabled") }.
The account has {accountDraft.mfa?.recovery_codes ?? "no"} recovery codes.
{ try { await deleteMFARecoveryCodes(account._id); toast({ title: "MFA recovery codes cleared", }); accountDraft.mfa!.recovery_codes = undefined; } catch(e) { toast({ title: "Failed to clear recovery codes", description: String(e), variant: "destructive", }) } }} > Clear recovery codes { try { await disableMFA(account._id); toast({ title: "MFA disabled", }); accountDraft.mfa!.totp_token = undefined; } catch(e) { toast({ title: " Failed to disable MFA", description: String(e), variant: "destructive", }) } }} > Disable MFA Close
Are you sure you want to{" "} {accountDraft.disabled ? "restore" : "disable"} this account? Cancel { try { if (accountDraft.disabled) { await restoreAccount(account._id); setAccountDraft((account) => ({ ...account!, disabled: false, })); toast({ title: "Restored account", }); } else { await disableAccount(account._id); setAccountDraft((account) => ({ ...account!, disabled: true, })); toast({ title: "Disabled account", }); } } catch (err) { toast({ title: "Failed to execute action", description: String(err), variant: "destructive", }); } }} > {accountDraft.disabled ? "Restore" : "Disable"} Are you sure you want to{" "} {accountDraft.deletion?.status === "Scheduled" ? "cancel deletion of" : "queue deletion for"}{" "} this account? Cancel { try { if (accountDraft.deletion?.status === "Scheduled") { await cancelAccountDeletion(account._id); setAccountDraft((account) => ({ ...account, deletion: null, })); toast({ title: "Cancelled account deletion", }); } else { const $set = await queueAccountDeletion(account._id); setAccountDraft((account) => ({ ...account!, ...$set })); toast({ title: "Queued account for deletion", }); } } catch (err) { toast({ title: "Failed to execute action", description: String(err), variant: "destructive", }); } }} > {accountDraft.deletion?.status === "Scheduled" ? "Unqueue" : "Queue"}
); }