diff --git a/app/Actions/PasswordResetAction.php b/app/Actions/PasswordResetAction.php
new file mode 100644
index 0000000..b8a152b
--- /dev/null
+++ b/app/Actions/PasswordResetAction.php
@@ -0,0 +1,24 @@
+first();
+ throw_if(! $user, new UserNotFoundException('User not found'));
+
+ $otp = $this->otpService->generate($user);
+ $this->mailAction->execute($user->email, $otp);
+ }
+}
diff --git a/app/Actions/SendPasswordResetMailAction.php b/app/Actions/SendPasswordResetMailAction.php
new file mode 100644
index 0000000..2fe064d
--- /dev/null
+++ b/app/Actions/SendPasswordResetMailAction.php
@@ -0,0 +1,21 @@
+send(new PasswordResetMail($otp));
+ \Log::info('Mail sent successfully', ['message' => $message]);
+ } catch (\Throwable $e) {
+ \Log::info('Mail send failed', ['message' => $e->getMessage()]);
+ }
+ }
+}
diff --git a/app/Exceptions/UserNotFoundException.php b/app/Exceptions/UserNotFoundException.php
new file mode 100644
index 0000000..d99e442
--- /dev/null
+++ b/app/Exceptions/UserNotFoundException.php
@@ -0,0 +1,7 @@
+validate([
+ 'email' => 'required|email',
+ ]);
+
+ try {
+ $action->execute($data);
+
+ return to_route('password.reset.show.verify')->with('success', 'Password reset code is sent');
+ } catch (UserNotFoundException $e) {
+ return to_route('password.reset.show.verify')->with('success', 'Password reset code is sent');
+ }
+ }
+
+ public function showVerify()
+ {
+ return view('auth.passwords.verify');
+ }
+
+ public function verify(Request $request, OTPService $otpService)
+ {
+ $data = $request->validate(['otp' => 'required|string:min:5:max:6']);
+ try {
+ $isVerified = $otpService->verify($data['otp']);
+ if (! $isVerified) {
+ return back()->with('error', 'Invalid OTP');
+ }
+
+ return to_route('password.reset.show.update')->with('success', 'OTP Verified');
+ } catch (UserNotFoundException $e) {
+ return back()->with('error', 'Session Expired');
+ }
+ }
+
+ public function showUpdate()
+ {
+ return view('auth.passwords.update');
+ }
+
+ public function update(Request $request)
+ {
+ $data = $request->validate(['password' => 'required', 'confirmed', Password::min(8)->letters()->mixedCase()->numbers()->symbols()]);
+ $user = User::find(Session::get('user_id'));
+ if (! $user) {
+ return back()->with('error', 'Session Expired');
+ }
+ $user->update(['password' => $data['password']]);
+
+ return to_route('login.create')->with('success', 'Password updated successfully');
+ }
+}
diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php
index 20d9fda..f6aef36 100644
--- a/app/Http/Controllers/Auth/RegisteredUserController.php
+++ b/app/Http/Controllers/Auth/RegisteredUserController.php
@@ -45,7 +45,7 @@ public function store(StoreRegisterdUser $request)
});
return to_route('login.create')
- ->with('userRegistered', 'User registered successfully.');
+ ->with('success', 'User registered successfully.');
} catch (\Throwable $e) {
Log::error('Registration Failed: '.$e->getMessage());
diff --git a/app/Mail/PasswordResetMail.php b/app/Mail/PasswordResetMail.php
new file mode 100644
index 0000000..32fea89
--- /dev/null
+++ b/app/Mail/PasswordResetMail.php
@@ -0,0 +1,38 @@
+ $this->otp]
+ );
+ }
+
+ public function attachments(): array
+ {
+ return [];
+ }
+}
diff --git a/app/Services/OTPService.php b/app/Services/OTPService.php
new file mode 100644
index 0000000..6fc49e1
--- /dev/null
+++ b/app/Services/OTPService.php
@@ -0,0 +1,42 @@
+id", $code, now()->addMinutes(10));
+ Session::put('user_id', $user->id);
+
+ return $code;
+ }
+
+ /**
+ * @throws \Exception
+ */
+ public function verify(string $otp): bool
+ {
+ $user = User::find(Session::get('user_id'));
+
+ if (! $user) {
+ throw new UserNotFoundException('User not found');
+ }
+
+ $code = Cache::get("otp_$user->id");
+ if ($code === $otp) {
+ Cache::forget("otp_$user->id");
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php
index 9a70de9..18c0650 100644
--- a/resources/views/auth/login.blade.php
+++ b/resources/views/auth/login.blade.php
@@ -20,7 +20,7 @@ class="bg-linear-135 h-screen from-[#EFF6FF] to-[#FCF3F8] flex flex-col justify-
@endsession
- @session('userRegistered')
+ @session('success')
Reset Password
+ Reset Password
+ Verify OTP
+
{{$description}}
+{{$description}}
@endif