Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/auth/forgot-password/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client';

import ForgotPasswordForm from "@/components/auth/forgotPassword";


export default function ForgotPassword() {
return <ForgotPasswordForm />;
}
1 change: 0 additions & 1 deletion app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export default function Dashboard() {
}, [checkDeposits]);

useEffect(() => {
// run once immediately
checkRef.current();

const id = window.setInterval(() => {
Expand Down
117 changes: 117 additions & 0 deletions components/auth/forgotPassword.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
'use client'

import React, { useState } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { Mail, Lock, Eye, EyeOff, ArrowLeft } from 'lucide-react'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/buttons'
import { apiClient } from '@/lib/api-client'
import { toast } from 'sonner'

export default function ForgotPasswordForm() {
const router = useRouter()
const [isLoading, setIsLoading] = useState(false)
const [apiMessage, setApiMessage] = useState<string | null>(null)
const [formData, setFormData] = useState({
email: '',
})

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setApiMessage(null)
setIsLoading(true)

try {
const success = await apiClient.ForgotPassword(formData.email)

if (success) {
toast.success("Reset Password Email sent successfully")
} else {
setApiMessage('failed. Please check your credentials.')
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err)
setApiMessage(message)
} finally {
setIsLoading(false)
}
}

return (
<div className="min-h-screen max-w-md w-full flex items-center justify-center p-4">
<div className="w-full max-w-md space-y-8">
{/* Back button */}
<Link
href="/"
className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
>
<ArrowLeft className="h-4 w-4" />
Back to home
</Link>

{/* Header */}
<div className="text-center space-y-2">
<h1 className="text-3xl font-bold tracking-tight">
Welcome to <span className="velo-text-gradient">VELO</span>
</h1>
<p className="text-muted-foreground">
Reset Your password
</p>
</div>

{/* Login form */}
<form
onSubmit={handleSubmit}
className="bg-card border border-border/50 w-full rounded-2xl p-8 space-y-6"
>
{apiMessage && (
<div className="text-center text-red-500 text-sm">{apiMessage}</div>
)}

<div className="space-y-4">
{/* Email */}
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<div className="relative flex items-center space-x-3 ">
<Mail className=" h-5 w-5 text-muted-foreground" />
<Input
id="email"
type="email"
placeholder="Enter your email"
value={formData.email}
onChange={(e) =>
setFormData({ ...formData, email: e.target.value })
}
required
className=" bg-background/50"
/>
</div>
</div>


</div>

<Button
type="submit"
disabled={isLoading}
className="w-full velo-gradient text-white font-semibold"
>
{isLoading ? 'Sending email...' : 'Continue'}
</Button>

<p className="text-center text-sm text-muted-foreground">
Back to {" "}
<Link
href="/auth/login"
className="text-primary font-medium hover:underline"
>
Login
</Link>
</p>
</form>
</div>
</div>
)
}
11 changes: 10 additions & 1 deletion lib/api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
ResendOtpResponse,
// Response types
MerchantPaymentStats,
ForgotPasswordCredentials,
ForgotPasswordResponse,
} from "./api-types";

import {
Expand Down Expand Up @@ -197,6 +199,13 @@ class ApiClient {
});
}

async ForgotPassword(email: string): Promise<ForgotPasswordResponse> {
return this.request<RegisterResponse>("/auth/forgot-password", {
method: "POST",
body: {email},
});
}

async verifyOtp(
credentials: VerifyOtpCredentials
): Promise<VerifyOtpResponse> {
Expand Down Expand Up @@ -304,7 +313,7 @@ class ApiClient {
method: "GET",
},
{
ttl: 30 * 1000, // 30 seconds
ttl: 30 * 1000,
backgroundRefresh: true,
}
);
Expand Down
8 changes: 8 additions & 0 deletions lib/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export interface RegisterCredentials {
password: string;
}

export interface ForgotPasswordCredentials {
email: string;
}

export interface VerifyOtpCredentials {
email: string;
otp: string;
Expand All @@ -81,6 +85,10 @@ export interface ResendOtpResponse {
message?: string;
}

export interface ForgotPasswordResponse {
success: boolean;
message?: string;
}
// API Response wrapper
export interface ApiResponse<T = any> {
success: boolean;
Expand Down