Skip to content
181 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)1import { useState } from "react";
2import { Form, Link, useNavigation } from "react-router";
3
4import { ACCOUNT_RESTORE_DAYS, type AccountDeletion } from "@g1t/contracts";
5
6import { DangerAction } from "./danger-zone";
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.7import { ErrorText } from "./ui";
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)8import {
9 AlertDialog,
10 AlertDialogCancel,
11 AlertDialogContent,
12 AlertDialogDescription,
13 AlertDialogFooter,
14 AlertDialogHeader,
15 AlertDialogTitle,
16} from "./ui/alert-dialog";
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.17import { Button } from "./ui/button";
18import { Card } from "./ui/card";
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)19import { FieldDescription, FieldLabel, Field as FormField } from "./ui/field";
20import { Input as TextInput } from "./ui/input";
21import { accountDeletionRefusal, confirmsUsername, whatAccountDeletionTakes } from "../lib/account-deletion";
22
23/**
24 * Deleting your account, in one step, typed out to confirm, with your
25 * password unless you signed in within the last few minutes. Kept for
26 * `ACCOUNT_RESTORE_DAYS`, when support can restore it. Workspaces you own
27 * alone are listed instead of the button until they have another owner or
28 * are deleted.
29 */
30export function DeleteAccountAction({
31 username,
32 deletion,
33 hasPassword,
34 error,
35 defaultOpen = false,
36}: {
37 username: string;
38 deletion: AccountDeletion | null;
39 hasPassword: boolean;
40 error?: string;
41 /** Open on first render: for previews of the dialog. */
42 defaultOpen?: boolean;
43}) {
44 const [open, setOpen] = useState(Boolean(error) || defaultOpen);
45 const [confirm, setConfirm] = useState("");
46 const navigation = useNavigation();
47 const deleting = navigation.state !== "idle" && navigation.formData?.get("intent") === "delete-account";
48 const refusal = accountDeletionRefusal(deletion);
49 const goes = deletion ? whatAccountDeletionTakes(deletion) : [];
50 if (deletion?.protected) {
51 return (
52 <DangerAction title="Delete your account" action={null}>
53 <span role="status">{refusal}</span>
54 </DangerAction>
55 );
56 }
57 return (
58 <DangerAction
59 title="Delete your account"
60 action={
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.61 <Button type="button" variant="destructive" disabled={Boolean(refusal)} onClick={() => setOpen(true)}>
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)62 Delete account
63 </Button>
64 }
65 >
66 {refusal ? (
67 <>
68 <span role="status">{refusal}</span>
69 <ul className="mt-3 space-y-2">
70 {deletion?.sole_owner_of.map((workspace) => (
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.71 <Card asChild key={workspace.slug} radius="lg" className="px-3 py-2">
72 <li>
73 <p className="text-fg">
74 <span className="font-medium">{workspace.name}</span>{" "}
75 <span className="font-mono text-xs text-faint">{workspace.slug}</span>
76 </p>
77 <p className="mt-1 flex flex-wrap gap-x-3 gap-y-1 text-xs">
78 {workspace.members > 1 ? (
79 <Link to={`/${workspace.slug}/-/members`} className="text-accent underline-offset-4 hover:underline">
80 Make someone else an owner
81 </Link>
82 ) : null}
83 <Link to={`/${workspace.slug}/-/settings`} className="text-accent underline-offset-4 hover:underline">
84 Delete the workspace
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)85 </Link>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.86 </p>
87 {workspace.billing ? <p className="mt-1 text-xs text-warn">{workspace.billing}</p> : null}
88 </li>
89 </Card>
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)90 ))}
91 </ul>
92 </>
93 ) : (
94 <>
95 You sign out everywhere and leave every workspace at once. Your account is kept for {ACCOUNT_RESTORE_DAYS}{" "}
96 days, and support can restore it until then.
97 </>
98 )}
99 <AlertDialog
100 open={open}
101 onOpenChange={(next) => {
102 setOpen(next);
103 setConfirm("");
104 }}
105 >
106 <AlertDialogContent>
107 <Form method="post" className="grid gap-4">
108 <input type="hidden" name="intent" value="delete-account" />
109 <AlertDialogHeader>
110 <AlertDialogTitle>Delete your account?</AlertDialogTitle>
111 <AlertDialogDescription>
112 Everything you sign in with stops working now. For {ACCOUNT_RESTORE_DAYS} days, support can restore
113 your account; after that it is gone for good.
114 </AlertDialogDescription>
115 </AlertDialogHeader>
116 {goes.length > 0 ? (
117 <div className="grid gap-1.5">
118 <p className="text-sm font-medium">What goes with it</p>
119 <ul className="list-disc space-y-1 pl-5 text-sm text-muted">
120 {goes.map((line) => (
121 <li key={line}>{line}</li>
122 ))}
123 </ul>
124 </div>
125 ) : null}
126 <ul className="list-disc space-y-1.5 pl-5 text-sm text-muted">
127 <li>You are signed out everywhere. Your access tokens, SSH keys, deploy keys you added and applications stop working.</li>
128 <li>You leave every workspace, team and repository. Workspaces you share keep everything in them.</li>
129 <li>Your profile is no longer found, and nobody can add you to anything.</li>
130 <li>
131 To get it back within {ACCOUNT_RESTORE_DAYS} days, write to support from one of its addresses. After
132 that your addresses, keys, profile and settings are removed for good.
133 </li>
134 <li>
135 What you wrote stays where it is: issues, pull requests, comments and reviews show as{" "}
136 <span className="font-mono text-fg">ghost</span> once it is removed.
137 </li>
138 <li>
139 The username <span className="font-mono text-fg">{username}</span> is never given to anyone else.
140 </li>
141 </ul>
142 <FormField>
143 <FieldLabel htmlFor="confirm-account">
144 Type <span className="font-mono text-fg">{username}</span> to confirm
145 </FieldLabel>
146 <TextInput
147 id="confirm-account"
148 name="confirm"
149 value={confirm}
150 spellCheck={false}
151 autoCapitalize="off"
152 autoComplete="off"
153 onChange={(event) => setConfirm(event.target.value)}
154 className="font-mono"
155 />
156 </FormField>
157 {hasPassword ? (
158 <FormField>
159 <FieldLabel htmlFor="confirm-password">Your password</FieldLabel>
160 <TextInput id="confirm-password" name="password" type="password" autoComplete="current-password" />
161 <FieldDescription>Not needed if you signed in within the last 10 minutes.</FieldDescription>
162 </FormField>
163 ) : (
164 <p className="text-sm text-muted">
165 Your account signs in with GitHub only: sign out, sign in with GitHub again, and delete it within 10
166 minutes.
167 </p>
168 )}
169 <ErrorText>{error}</ErrorText>
170 <AlertDialogFooter>
171 <AlertDialogCancel type="button">Cancel</AlertDialogCancel>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.172 <Button type="submit" variant="destructive" disabled={!confirmsUsername(username, confirm) || deleting}>
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)173 {deleting ? "Deleting…" : "Delete account"}
174 </Button>
175 </AlertDialogFooter>
176 </Form>
177 </AlertDialogContent>
178 </AlertDialog>
179 </DangerAction>
180 );
181}

This file's history is long; its oldest lines are credited to the oldest commit read.