Use shared modals and combine selected-day actions
This commit is contained in:
@@ -12,37 +12,38 @@ export function AccountSettings({ user, onChanged, onClose }: { user: PublicUser
|
||||
const [confirmation, setConfirmation] = useState("");
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [reminderBusy, setReminderBusy] = useState(false);
|
||||
const saving = useRef(false);
|
||||
const [error, setError] = useState("");
|
||||
const listId = useId();
|
||||
async function run(action: () => Promise<unknown>) {
|
||||
if (saving.current) return;
|
||||
if (saving.current || reminderBusy) return;
|
||||
saving.current = true; setBusy(true); setError("");
|
||||
try { await action(); onChanged(); }
|
||||
catch (error) { setError(error instanceof Error ? error.message : "Could not save. Try again."); }
|
||||
finally { saving.current = false; setBusy(false); }
|
||||
}
|
||||
return <WorkspacePanel id="account-settings" eyebrow="YOUR WORKSPACE" title="Account settings" description="A few preferences to make this space yours." onClose={busy ? undefined : onClose} closeLabel="Close settings">
|
||||
return <WorkspacePanel id="account-settings" eyebrow="YOUR WORKSPACE" title="Account settings" description="A few preferences to make this space yours." onClose={onClose} busy={busy || reminderBusy} closeLabel="Close settings">
|
||||
<SettingRow title="Your daily rhythm" description={<p>Your timezone sets the start and end of each day. Earlier deadlines stay as recorded.</p>}>
|
||||
<form className="ds-form-stack" onSubmit={event => { event.preventDefault(); void run(() => habitRequest("/me", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ timezone }) })); }}>
|
||||
<Field label="Timezone">
|
||||
{id => <input id={id} list={listId} value={timezone} required maxLength={100} disabled={busy} onChange={event => setTimezone(event.target.value)} />}
|
||||
{id => <input id={id} list={listId} value={timezone} required maxLength={100} disabled={busy || reminderBusy} onChange={event => setTimezone(event.target.value)} />}
|
||||
</Field>
|
||||
<datalist id={listId}>{["UTC", ...Intl.supportedValuesOf("timeZone")].map(zone => <option key={zone} value={zone} />)}</datalist>
|
||||
<div className="ds-action-row"><Button type="submit" variant="secondary" disabled={busy}>{busy && !deleting ? "Saving…" : "Save timezone"}</Button></div>
|
||||
<div className="ds-action-row"><Button type="submit" variant="secondary" disabled={busy || reminderBusy}>{busy && !deleting ? "Saving…" : "Save timezone"}</Button></div>
|
||||
</form>
|
||||
</SettingRow>
|
||||
<ReminderSettings timezone={user.timezone} />
|
||||
<ReminderSettings timezone={user.timezone} onBusyChange={setReminderBusy} disabled={busy} />
|
||||
<SettingRow title="A copy for you" description={<p>Take your profile, habits, history, and sharing records with you. Sessions and credentials are excluded.</p>}>
|
||||
<div className="ds-action-row"><ButtonLink variant="secondary" href="/api/account/export" download="minabot-export.json"><Download size={16} aria-hidden="true" />Export my data</ButtonLink><span className="ds-meta-label">JSON file</span></div>
|
||||
</SettingRow>
|
||||
<SettingRow title="Delete account" description={<p>Permanently remove your account and habit history, and sign out every device.</p>}>
|
||||
{!deleting ? <div className="ds-action-row"><Button variant="text" disabled={busy} onClick={() => setDeleting(true)} aria-expanded={false}><Trash2 size={16} aria-hidden="true" />Delete account</Button></div> :
|
||||
{!deleting ? <div className="ds-action-row"><Button variant="text" disabled={busy || reminderBusy} onClick={() => setDeleting(true)} aria-expanded={false}><Trash2 size={16} aria-hidden="true" />Delete account</Button></div> :
|
||||
<form className="ds-form-stack ds-confirmation" onSubmit={event => { event.preventDefault(); void run(() => habitRequest("/account", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ confirmation }) })); }}>
|
||||
<p className="type-ui-heading">This cannot be undone.</p>
|
||||
<p className="ds-supporting-copy">Download an export first if you want a copy. Images already posted to Discord remain there; server backups expire under the operator’s retention policy.</p>
|
||||
<Field label="Type DELETE to confirm">{id => <input id={id} value={confirmation} disabled={busy} autoComplete="off" onChange={event => setConfirmation(event.target.value)} />}</Field>
|
||||
<div className="ds-action-row"><Button type="submit" disabled={busy || confirmation !== "DELETE"}>Permanently delete my account</Button><Button variant="text" disabled={busy} onClick={() => { setDeleting(false); setConfirmation(""); }}>Cancel deletion</Button></div>
|
||||
<Field label="Type DELETE to confirm">{id => <input id={id} value={confirmation} disabled={busy || reminderBusy} autoComplete="off" onChange={event => setConfirmation(event.target.value)} />}</Field>
|
||||
<div className="ds-action-row"><Button type="submit" disabled={busy || reminderBusy || confirmation !== "DELETE"}>Permanently delete my account</Button><Button variant="text" disabled={busy || reminderBusy} onClick={() => { setDeleting(false); setConfirmation(""); }}>Cancel deletion</Button></div>
|
||||
</form>}
|
||||
</SettingRow>
|
||||
<FormMessage error>{error}</FormMessage>
|
||||
|
||||
Reference in New Issue
Block a user