Skip to content

Commit ecd4b8a

Browse files
committed
Redesign ForgotPasswordModal with a modern UI and replace quirky copy with professional messaging
1 parent 05c1f38 commit ecd4b8a

2 files changed

Lines changed: 189 additions & 180 deletions

File tree

src/components/auth/ForgotPasswordModal.tsx

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,26 @@ import {
88
} from '@/components/ui/dialog';
99
import { apiClient } from '@/lib/apiClient';
1010
import { toast } from 'sonner';
11-
import { AlertTriangle, X } from 'lucide-react';
11+
import { X, ArrowRight, Loader2 } from 'lucide-react';
1212

1313
interface ForgotPasswordModalProps {
1414
isOpen: boolean;
1515
onClose: () => void;
1616
initialEmail?: string;
1717
}
1818

19-
const FUNNY_RECOVERY_MESSAGES = [
20-
"Searching for your lost brain cells...",
21-
"Consulting the archives of shame...",
22-
"Sending a rescue helicopter (email)...",
23-
"Pinging your inner child...",
24-
"Recrusting data from the void...",
25-
"Hacking into your memory banks...",
26-
"Calculating the probability of you forgetting again...",
27-
"Establishing a neural bridge..."
19+
const RECOVERY_MESSAGES = [
20+
"Verifying account status...",
21+
"Generating reset token...",
22+
"Preparing recovery dispatch...",
23+
"Sending secure email link...",
24+
"Finalizing security handshake..."
2825
];
2926

3027
const ForgotPasswordModal: React.FC<ForgotPasswordModalProps> = ({ isOpen, onClose, initialEmail = '' }) => {
3128
const [email, setEmail] = useState(initialEmail);
3229
const [loading, setLoading] = useState(false);
33-
const [loadingMsg, setLoadingMsg] = useState(FUNNY_RECOVERY_MESSAGES[0]);
30+
const [loadingMsg, setLoadingMsg] = useState(RECOVERY_MESSAGES[0]);
3431

3532
useEffect(() => {
3633
if (isOpen) {
@@ -42,43 +39,37 @@ const ForgotPasswordModal: React.FC<ForgotPasswordModalProps> = ({ isOpen, onClo
4239
let interval: NodeJS.Timeout;
4340
if (loading) {
4441
interval = setInterval(() => {
45-
setLoadingMsg(FUNNY_RECOVERY_MESSAGES[Math.floor(Math.random() * FUNNY_RECOVERY_MESSAGES.length)]);
46-
}, 1000);
42+
setLoadingMsg(RECOVERY_MESSAGES[Math.floor(Math.random() * RECOVERY_MESSAGES.length)]);
43+
}, 1200);
4744
}
4845
return () => clearInterval(interval);
4946
}, [loading]);
5047

5148
const handleSubmit = async (e: React.FormEvent) => {
5249
e.preventDefault();
5350
if (!email) {
54-
toast.error("I CAN'T READ MINDS. ENTER THE EMAIL.", {
55-
className: "font-black uppercase border-4 border-black"
56-
});
51+
toast.error("Please enter your email address.");
5752
return;
5853
}
5954

6055
setLoading(true);
6156

6257
try {
63-
// Small artificial delay for the funny loading messages to be seen
64-
await new Promise(resolve => setTimeout(resolve, 2000));
58+
await new Promise(resolve => setTimeout(resolve, 1500));
6559

6660
const { error } = await apiClient.auth.resetPasswordForEmail(email, {
6761
redirectTo: window.location.origin + '/reset-password',
6862
});
6963

7064
if (error) throw error;
7165

72-
toast.success("FINE. WE SENT THE EXTRACTION LINK.", {
73-
description: "Check your spam. It belongs there.",
74-
className: "font-black uppercase border-4 border-black"
66+
toast.success("Recovery link sent.", {
67+
description: "Please check your email inbox and spam folder.",
7568
});
7669
onClose();
7770
} catch (error: any) {
78-
toast.error("EVERYTHING IS BROKEN.", {
79-
description: error.message || "Even the system gave up on you.",
80-
className: "font-black uppercase border-4 border-red-600 text-red-600",
81-
icon: <AlertTriangle className="w-5 h-5" />
71+
toast.error("Recovery failed.", {
72+
description: error.message || "An unexpected error occurred. Please try again.",
8273
});
8374
} finally {
8475
setLoading(false);
@@ -87,71 +78,69 @@ const ForgotPasswordModal: React.FC<ForgotPasswordModalProps> = ({ isOpen, onClo
8778

8879
return (
8980
<Dialog open={isOpen} onOpenChange={(v) => !loading && !v && onClose()}>
90-
<DialogContent className="sm:max-w-[500px] bg-[#F0F0F0] border-[8px] border-black shadow-[16px_16px_0px_0px_rgba(0,0,0,1)] p-0 overflow-hidden rounded-none [&>button:last-child]:hidden">
81+
<DialogContent className="sm:max-w-[440px] bg-white border border-black/10 rounded-2xl shadow-xl p-8 overflow-hidden font-sans [&>button:last-child]:hidden">
9182

92-
{/* CUSTOM CLOSE BUTTON */}
9383
<button
9484
onClick={onClose}
9585
disabled={loading}
96-
className="absolute right-6 top-6 z-50 w-10 h-10 border-4 border-black bg-white flex items-center justify-center shadow-brutal hover:shadow-none hover:translate-x-1 hover:translate-y-1 transition-all disabled:opacity-50"
86+
className="absolute right-4 top-4 z-50 w-8 h-8 rounded-full border border-black/10 bg-white flex items-center justify-center text-black/40 hover:text-black/75 hover:bg-black/[0.03] transition-all disabled:opacity-50"
9787
>
98-
<X className="w-5 h-5 stroke-[3px]" />
88+
<X className="w-4 h-4" />
9989
</button>
10090

101-
<div className="p-8 md:p-12">
102-
<DialogHeader className="mb-8 text-left">
103-
<div className="flex items-center gap-4 mb-4">
104-
<DialogTitle className="text-4xl md:text-5xl font-black uppercase italic tracking-tighter leading-none">
105-
BRAIN_FART<span className="text-[#FF4500]">.</span>
106-
</DialogTitle>
107-
</div>
108-
<DialogDescription className="text-sm font-black uppercase tracking-tight opacity-70 border-l-8 border-[#FF4500] pl-6 py-2 leading-tight">
109-
ENTITY_ACCESS_DENIED. FORGOT YOUR RECRUSTION CODE? DON'T WORRY, WE'VE ALL BEEN THERE (MOSTLY YOU, THOUGH).
91+
<div className="relative z-10">
92+
<DialogHeader className="mb-6 text-left">
93+
<DialogTitle className="text-[28px] font-semibold tracking-[-0.03em] leading-tight text-foreground font-sans">
94+
Forgot password<span className="text-accent">.</span>
95+
</DialogTitle>
96+
<DialogDescription className="text-[14px] text-black/40 mt-3 leading-relaxed font-sans normal-case">
97+
Enter the email address associated with your account, and we will send you a recovery link to reset your password.
11098
</DialogDescription>
11199
</DialogHeader>
112100

113-
<form onSubmit={handleSubmit} className="space-y-8">
114-
<div className="space-y-3 group">
115-
<label className="text-xs font-black uppercase tracking-[0.2em] flex items-center gap-2 group-focus-within:text-[#FF4500] transition-colors">
116-
TARGET EMAIL <span className="text-[10px] opacity-40">(WHERE THE HELICOPTER GOES)</span>
117-
</label>
101+
<form onSubmit={handleSubmit} className="space-y-5">
102+
<div className="space-y-1.5">
103+
<p className="text-[10px] font-mono font-bold uppercase tracking-widest text-black/40">
104+
Email address
105+
</p>
118106
<input
119107
type="email"
120108
value={email}
121109
onChange={(e) => setEmail(e.target.value)}
122-
placeholder="SOMEONE_IMPORTANT@VOID.COM"
110+
placeholder="you@example.com"
123111
required
124112
disabled={loading}
125-
className="w-full bg-white border-4 border-black p-5 text-lg font-black outline-none focus:bg-[#FF4500]/5 focus:border-[#FF4500] transition-all placeholder:opacity-20 uppercase"
113+
className="w-full bg-white border border-black/12 rounded-xl px-4 py-3.5 text-[15px] outline-none focus:border-accent focus:ring-2 focus:ring-accent/10 transition-all placeholder:text-black/25 shadow-sm font-sans"
126114
/>
127115
</div>
128116

129117
<button
130118
type="submit"
131119
disabled={loading}
132-
className="w-full bg-black text-white py-5 px-8 border-4 border-black font-black uppercase text-xl shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-2 hover:translate-y-2 transition-all flex items-center justify-center gap-3 active:scale-95 disabled:opacity-50"
120+
className="w-full bg-foreground text-background rounded-xl px-5 py-4 text-[15px] font-medium hover:bg-accent hover:text-white transition-colors flex items-center justify-center gap-2.5 disabled:opacity-50 disabled:cursor-not-allowed shadow-sm font-sans mt-2"
133121
>
134122
{loading ? (
135-
<div className="flex items-center gap-3">
136-
<div className="w-4 h-4 border-4 border-white border-t-transparent animate-spin" />
137-
<span className="text-sm">{loadingMsg}</span>
123+
<div className="flex items-center gap-2.5">
124+
<Loader2 className="w-4 h-4 animate-spin text-current" />
125+
<span className="text-[13px] font-mono uppercase tracking-wider">{loadingMsg}</span>
138126
</div>
139127
) : (
140128
<>
141-
INITIATE_RECOVERY
129+
<span>Send recovery link</span>
130+
<ArrowRight size={15} />
142131
</>
143132
)}
144133
</button>
145134
</form>
146-
147-
{/* FUNNY FOOTER */}
148-
<div className="mt-12 flex items-center justify-between opacity-30 text-[9px] font-black uppercase tracking-[0.2em] border-t-2 border-black/10 pt-4">
149-
<div>AQORA_SYS_v4.2</div>
150-
</div>
151135
</div>
152136

153-
{/* GLITCH OVERLAYS */}
154-
<div className="absolute inset-0 pointer-events-none opacity-[0.03] bg-[repeating-linear-gradient(0deg,transparent,transparent_2px,black_2px,black_4px)]" />
137+
<div
138+
className="absolute inset-0 pointer-events-none opacity-[0.02] z-0"
139+
style={{
140+
backgroundImage: 'radial-gradient(#000 1px, transparent 1px)',
141+
backgroundSize: '16px 16px',
142+
}}
143+
/>
155144
</DialogContent>
156145
</Dialog>
157146
);

0 commit comments

Comments
 (0)