fix: more helpful messaging on account deletion

This commit is contained in:
Face 2025-05-31 13:27:30 +03:00
parent 4479d878ce
commit 2c98047ec0
2 changed files with 50 additions and 38 deletions

View file

@ -21,19 +21,20 @@ export async function POST({ request }) {
throw error(400, 'Invalid confirmation text'); throw error(400, 'Invalid confirmation text');
} }
const scheduledDeletionAt = new Date(); try {
scheduledDeletionAt.setDate(scheduledDeletionAt.getDate() + 14); const existingRequest = await db.select()
await db.transaction(async (tx) => {
const existingRequest = await tx.select()
.from(accountDeletionRequest) .from(accountDeletionRequest)
.where(eq(accountDeletionRequest.userId, userId)) .where(eq(accountDeletionRequest.userId, userId))
.limit(1); .limit(1);
if (existingRequest.length > 0) { if (existingRequest.length > 0) {
throw new Error('Account deletion already requested'); throw error(409, 'Account deletion already requested');
} }
const scheduledDeletionAt = new Date();
scheduledDeletionAt.setDate(scheduledDeletionAt.getDate() + 14);
await db.transaction(async (tx) => {
await tx.insert(accountDeletionRequest).values({ await tx.insert(accountDeletionRequest).values({
userId, userId,
scheduledDeletionAt, scheduledDeletionAt,
@ -49,10 +50,16 @@ export async function POST({ request }) {
.where(eq(user.id, userId)); .where(eq(user.id, userId));
}); });
return json({ return json({
success: true, success: true,
message: `Account deletion has been scheduled for ${scheduledDeletionAt.toLocaleDateString()}. Your account has been temporarily suspended. You can cancel this request by contacting support before the scheduled date.`, message: `Account deletion has been scheduled for ${scheduledDeletionAt.toLocaleDateString()}. Your account has been temporarily suspended. You can cancel this request by contacting support before the scheduled date.`,
scheduledDeletionAt: scheduledDeletionAt.toISOString() scheduledDeletionAt: scheduledDeletionAt.toISOString()
}); });
} catch (e) {
if (e && typeof e === 'object' && 'status' in e) {
throw e;
}
console.error('Account deletion error:', e);
throw error(500, 'Internal server error');
}
} }

View file

@ -239,16 +239,21 @@
}) })
}); });
if (!response.ok) {
const result = await response.json(); const result = await response.json();
if (!response.ok) {
if (response.status === 409) {
toast.error('Account deletion already scheduled', {
description: 'You have already requested account deletion. Contact support to cancel.'
});
} else {
throw new Error(result.message || 'Failed to delete account'); throw new Error(result.message || 'Failed to delete account');
} }
} else {
toast.success('Account deleted successfully. You will be logged out shortly.'); toast.success('Account deletion scheduled successfully', {
description: result.message
setTimeout(() => { });
window.location.href = '/'; }
}, 2000);
} catch (error: any) { } catch (error: any) {
console.error('Delete account error:', error); console.error('Delete account error:', error);
toast.error('Failed to delete account: ' + error.message); toast.error('Failed to delete account: ' + error.message);
@ -427,8 +432,8 @@
<div class="space-y-1"> <div class="space-y-1">
<h4 class="text-destructive text-sm font-medium">Delete Account</h4> <h4 class="text-destructive text-sm font-medium">Delete Account</h4>
<p class="text-muted-foreground text-xs"> <p class="text-muted-foreground text-xs">
Permanently delete your account. This will anonymize your data while preserving Schedule your account for permanent deletion. This will anonymize your data while
transaction records for compliance. preserving transaction records for compliance.
</p> </p>
</div> </div>
<Button <Button
@ -452,8 +457,8 @@
<Dialog.Header> <Dialog.Header>
<Dialog.Title class="text-destructive">Delete Account</Dialog.Title> <Dialog.Title class="text-destructive">Delete Account</Dialog.Title>
<Dialog.Description> <Dialog.Description>
This action cannot be undone. Your account will be permanently deleted and your data will be This action cannot be undone. Your account will be scheduled for permanent deletion, after a
anonymized. grace period of <span class="font-semibold">14 days</span>. Your data will be anonymized.
</Dialog.Description> </Dialog.Description>
</Dialog.Header> </Dialog.Header>
<div class="space-y-4"> <div class="space-y-4">