TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import * as React from "react";3import { authClient } from "@/lib/auth-client";4import { Button } from "@/components/ui/button";5import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";6import { Input } from "@/components/ui/input";7import { Field, Hint, Label } from "@/components/ui/label";8import { Alert } from "@/components/ui/alert";910export function ChangeEmailDialog({ currentEmail }: { currentEmail: string }) {11 const [open, setOpen] = React.useState(false);12 const [email, setEmail] = React.useState("");13 const [error, setError] = React.useState<string | null>(null);14 const [sent, setSent] = React.useState(false);15 const [loading, setLoading] = React.useState(false);1617 async function submit(e: React.FormEvent) {18 e.preventDefault();19 setError(null);20 const newEmail = email.trim().toLowerCase();21 if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(newEmail)) {22 setError("Enter a valid email address.");23 return;24 }25 if (newEmail === currentEmail.toLowerCase()) {26 setError("That is already your email address.");27 return;28 }29 setLoading(true);30 const { error } = await authClient.changeEmail({ newEmail, callbackURL: "/dashboard/settings?email-changed=1" });31 setLoading(false);32 if (error) {33 setError(error.message ?? "Could not start the email change. Try again.");34 return;35 }36 setSent(true);37 }3839 return (40 <Dialog41 open={open}42 onOpenChange={(o) => {43 setOpen(o);44 if (!o) {45 setSent(false);46 setError(null);47 setEmail("");48 }49 }}50 >51 <DialogTrigger asChild>52 <Button variant="outline" size="sm">53 Change email54 </Button>55 </DialogTrigger>56 <DialogContent size="sm">57 <DialogHeader>58 <DialogTitle>Change email address</DialogTitle>59 <DialogDescription>60 For your security we first send an approval link to your <strong className="text-fg">current</strong> address ({currentEmail}). Once you approve it, the new address becomes your login and must be verified in turn.61 </DialogDescription>62 </DialogHeader>63 {sent ? (64 <>65 <Alert variant="success" title="Approval email sent">66 Open the link we sent to {currentEmail} to approve switching to <strong className="text-fg">{email.trim()}</strong>. The link expires in 24 hours. Until then you keep signing in with your current address.67 </Alert>68 <DialogFooter>69 <Button onClick={() => setOpen(false)}>Done</Button>70 </DialogFooter>71 </>72 ) : (73 <form onSubmit={submit} className="grid gap-4" noValidate>74 {error ? <Alert variant="danger">{error}</Alert> : null}75 <Field>76 <Label htmlFor="new-email">New email</Label>77 <Input id="new-email" type="email" autoComplete="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@company.com" required autoFocus />78 <Hint>API keys, projects and usage are unaffected.</Hint>79 </Field>80 <DialogFooter>81 <Button type="button" variant="outline" onClick={() => setOpen(false)} disabled={loading}>82 Cancel83 </Button>84 <Button type="submit" variant="primary" loading={loading} disabled={!email.trim()}>85 Send approval email86 </Button>87 </DialogFooter>88 </form>89 )}90 </DialogContent>91 </Dialog>92 );93}94