feat(auth):forgot-password page

This commit is contained in:
arieeefajar 2025-01-23 17:51:07 +07:00
parent 4bfb472dbe
commit 968a9598fb
7 changed files with 281 additions and 79 deletions

View File

@ -3,9 +3,13 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\PasswordResetToken;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Validator;
use Illuminate\View\View;
class PasswordResetLinkController extends Controller
@ -23,22 +27,48 @@ public function create(): View
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request): RedirectResponse
public function store(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
$customMessages = [
'email.required' => 'Email tidak boleh kosong',
'email.email' => 'Email tidak valid',
'email.exists' => 'Email tidak terdaftar',
];
$validator = Validator::make($request->all(), [
'email' => ['required', 'email', 'exists:users,email'],
], $customMessages);
if ($validator->fails()) {
toast($validator->messages()->all()[0], 'error')->position('top')->autoclose(3000);
return redirect()->back()->withInput();
}
DB::table('password_reset_tokens')->updateOrInsert(['email' => $request->email], [
'token' => Hash::make($request->_token),
'created_at' => now(),
]);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$status = Password::sendResetLink(
$request->only('email')
);
return $status == Password::RESET_LINK_SENT
? back()->with('status', __($status))
: back()->withInput($request->only('email'))
->withErrors(['email' => __($status)]);
alert()->success('Berhasil', 'Silahkan cek email anda untuk mereset password');
return redirect()->back();
}
// public function store(Request $request): RedirectResponse
// {
// $request->validate([
// 'email' => ['required', 'email'],
// ]);
// // We will send the password reset link to this user. Once we have attempted
// // to send the link, we will examine the response then see the message we
// // need to show to the user. Finally, we'll send out a proper response.
// $status = Password::sendResetLink(
// $request->only('email')
// );
// return $status == Password::RESET_LINK_SENT
// ? back()->with('status', __($status))
// : back()->withInput($request->only('email'))
// ->withErrors(['email' => __($status)]);
// }
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ResetPasswordMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct()
{
//
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Reset Password Mail',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'auth.mail-reset-password',
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

View File

@ -1,25 +1,154 @@
<x-guest-layout>
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }}
<!doctype html>
<html lang="en" data-layout="vertical" data-topbar="light" data-sidebar="light" data-sidebar-size="lg">
<head>
<meta charset="utf-8" />
<title>Reset Password | CornQuest</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta content="Premium Multipurpose Admin & Dashboard Template" name="description" />
<meta content="Themesbrand" name="author" />
<!-- App favicon -->
<link rel="shortcut icon" href="assets/images/favicon.ico">
<!-- Layout config Js -->
<script src="assets/js/layout.js"></script>
<!-- Bootstrap Css -->
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<!-- Icons Css -->
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
<!-- App Css-->
<link href="assets/css/app.min.css" rel="stylesheet" type="text/css" />
<!-- custom Css-->
<link href="assets/css/custom.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="auth-page-wrapper pt-5">
<!-- auth page bg -->
<div class="auth-one-bg-position auth-one-bg" id="auth-particles">
<div class="bg-overlay"></div>
<div class="shape">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 1440 120">
<path d="M 0,36 C 144,53.6 432,123.2 720,124 C 1008,124.8 1296,56.8 1440,40L1440 140L0 140z"></path>
</svg>
</div>
</div>
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<form method="POST" action="{{ route('password.email') }}">
@csrf
<!-- Email Address -->
<!-- auth page content -->
<div class="auth-page-content">
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="text-center mt-sm-5 mb-4 text-white-50">
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
<x-input-error :messages="$errors->get('email')" class="mt-2" />
<a href="index.html" class="d-inline-block auth-logo">
<img src="assets/images/logo-light.png" alt="" height="20">
</a>
</div>
</div>
</div>
</div>
<!-- end row -->
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6 col-xl-5">
<div class="card mt-4">
<div class="card-body p-4">
<div class="text-center mt-2">
<h5 class="text-primary">Lupa Password?</h5>
<p class="text-muted">Ingin melakukan reset password?</p>
<lord-icon src="https://cdn.lordicon.com/rhvddzym.json" trigger="loop"
colors="primary:#0ab39c" class="avatar-xl">
</lord-icon>
</div>
<div class="flex items-center justify-end mt-4">
<x-primary-button>
{{ __('Email Password Reset Link') }}
</x-primary-button>
<div class="alert alert-borderless alert-warning text-center mb-2 mx-2" role="alert">
Masukan email anda dan instruksi akan dikirimkan kepada anda!
</div>
</form>
</x-guest-layout>
<div class="p-2">
<form action="{{ route('auth.reset_password') }}" class="needs-validation"
novalidate method="POST">
@csrf
<div class="mb-4">
<label class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email"
placeholder="Masukan Email" autofocus required>
<div class="invalid-feedback">
Masukan email anda
</div>
</div>
<div class="text-center mt-4">
<button class="btn btn-success w-100" type="submit">Kirim Reset Password
Link!</button>
</div>
</form><!-- end form -->
</div>
</div>
<!-- end card body -->
</div>
<!-- end card -->
<div class="mt-4 text-center">
<p class="mb-0">Tunggu, saya ingat password saya... <a href="{{ route('auth.login') }}"
class="fw-semibold text-primary text-decoration-underline"> Login </a> </p>
</div>
</div>
</div>
<!-- end row -->
</div>
<!-- end container -->
</div>
<!-- end auth page content -->
<!-- footer -->
<footer class="footer">
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="text-center">
<p class="mb-0 text-muted">&copy;
<script>
document.write(new Date().getFullYear())
</script> CornQuest. Crafted with <i
class="mdi mdi-heart text-danger"></i>
by LAB KSI Politeknik Negeri Jember
</p>
</div>
</div>
</div>
</div>
</footer>
<!-- end Footer -->
</div>
<!-- end auth-page-wrapper -->
@include('sweetalert::alert')
<!-- JAVASCRIPT -->
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="assets/libs/simplebar/simplebar.min.js"></script>
<script src="assets/libs/node-waves/waves.min.js"></script>
<script src="assets/libs/feather-icons/feather.min.js"></script>
<script src="assets/js/pages/plugins/lord-icon-2.1.0.js"></script>
<script src="assets/js/plugins.js"></script>
<!-- particles js -->
<script src="assets/libs/particles.js/particles.js"></script>
<!-- particles app js -->
<script src="assets/js/pages/particles.app.js"></script>
<script src="assets/js/pages/form-validation.init.js"></script>
</body>
</html>

View File

@ -83,7 +83,7 @@
<div class="mb-3">
<div class="float-end">
<a href="auth-pass-reset-basic.html" class="text-muted">Lupa
<a href="{{ route('auth.forgot_password') }}" class="text-muted">Lupa
Password?</a>
</div>
<label class="form-label" for="password-input">Password</label>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>Document</title>
</head>
<body>
<p>Halo,</p>
<p>Kami menerima permintaan untuk mereset password akun Anda.</p>
<p>Klik tautan di bawah ini untuk mereset password:</p>
<a href="{{ $resetLink }}">{{ $resetLink }}</a>
<p>Tautan ini akan kadaluarsa dalam waktu 60 menit.</p>
<p>Jika Anda tidak meminta reset password, abaikan email ini.</p>
<p>Terima kasih,</p>
<p>Tim {{ config('app.name') }}</p>
</body>
</html>

View File

@ -1,39 +0,0 @@
<x-guest-layout>
<form method="POST" action="{{ route('password.store') }}">
@csrf
<!-- Password Reset Token -->
<input type="hidden" name="token" value="{{ $request->route('token') }}">
<!-- Email Address -->
<div>
<x-input-label for="email" :value="__('Email')" />
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email', $request->email)" required autofocus autocomplete="username" />
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<!-- Password -->
<div class="mt-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<!-- Confirm Password -->
<div class="mt-4">
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
<x-text-input id="password_confirmation" class="block mt-1 w-full"
type="password"
name="password_confirmation" required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
</div>
<div class="flex items-center justify-end mt-4">
<x-primary-button>
{{ __('Reset Password') }}
</x-primary-button>
</div>
</form>
</x-guest-layout>

View File

@ -1,10 +1,9 @@
<?php
use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
use SebastianBergmann\CodeCoverage\Report\Html\Dashboard;
/*
|--------------------------------------------------------------------------
@ -19,10 +18,21 @@
Route::middleware('guest')->group(function () {
Route::controller(AuthenticatedSessionController::class)->name('auth.')->group(function () {
Route::name('auth.')->group(function () {
Route::controller(AuthenticatedSessionController::class)->group(function () {
Route::get('/', 'create')->name('login');
Route::post('/', 'store')->name('login_post');
});
Route::controller(PasswordResetLinkController::class)->group(function () {
Route::get('/forgot-password', 'create')->name('forgot_password');
Route::post('/reset-password', 'store')->name('reset_password');
Route::get('/validasi-lupa-password/{token}', 'validation')->name('validation_forgot_password');
Route::post('/validasi-lupa-password/{token}', 'update')->name('update_forgot_password');
});
});
});
Route::middleware('auth')->group(function () {