From 8dcc57673dbd0a44ee0420c895aa504bdd1d09d6 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Mon, 8 Dec 2025 15:16:07 +0700 Subject: [PATCH] refactor(auth): menggunakan class form, menyesuaikan view dan test atas pemindahan tersebut --- app/Livewire/Auth/ForgotPassword.php | 14 ++++---- app/Livewire/Auth/Login.php | 35 +++++++++---------- app/Livewire/Auth/Logout.php | 5 +-- app/Livewire/Auth/Register.php | 25 ++++++------- app/Livewire/Auth/ResetPassword.php | 11 +++--- .../Forms/Auth/ForgotPasswordForm.php | 24 +++++++++++++ app/Livewire/Forms/Auth/LoginForm.php | 28 +++++++++++++++ app/Livewire/Forms/Auth/RegisterForm.php | 10 +++--- app/Livewire/Forms/Auth/ResetPasswordForm.php | 6 ++-- .../livewire/auth/forgot-password.blade.php | 4 +-- resources/views/livewire/auth/login.blade.php | 8 ++--- .../Livewire/Auth/ForgotPasswordTest.php | 10 +++--- tests/Feature/Livewire/Auth/LoginTest.php | 34 +++++++++--------- 13 files changed, 134 insertions(+), 80 deletions(-) create mode 100644 app/Livewire/Forms/Auth/ForgotPasswordForm.php create mode 100644 app/Livewire/Forms/Auth/LoginForm.php diff --git a/app/Livewire/Auth/ForgotPassword.php b/app/Livewire/Auth/ForgotPassword.php index cc75872..2fd2762 100644 --- a/app/Livewire/Auth/ForgotPassword.php +++ b/app/Livewire/Auth/ForgotPassword.php @@ -2,10 +2,11 @@ namespace App\Livewire\Auth; +use App\Livewire\Forms\Auth\ForgotPasswordForm; use App\Traits\WithToast; use Illuminate\Support\Facades\Password; +use Illuminate\View\View; use Livewire\Attributes\Layout; -use Livewire\Attributes\Validate; use Livewire\Component; #[Layout('components.layouts.auth', [ @@ -15,15 +16,14 @@ class ForgotPassword extends Component { use WithToast; - #[Validate(['required', 'string'])] - public string $email = ''; + public ForgotPasswordForm $form; - public function sendLink() + public function sendLink(): mixed { - $this->validate(); + $this->form->validate(); $status = Password::sendResetLink( - $this->only('email') + ['form.email' => $this->form->email] ); return $status === Password::ResetLinkSent @@ -31,7 +31,7 @@ public function sendLink() : $this->toast(__($status), 'Gagal', 'danger'); } - public function render() + public function render(): View { return view('livewire.auth.forgot-password'); } diff --git a/app/Livewire/Auth/Login.php b/app/Livewire/Auth/Login.php index 086e3e9..78db28d 100644 --- a/app/Livewire/Auth/Login.php +++ b/app/Livewire/Auth/Login.php @@ -3,9 +3,12 @@ namespace App\Livewire\Auth; use App\Enums\UserStatus; +use App\Livewire\Forms\Auth\LoginForm; +use App\Models\User; use App\Traits\WithToast; +use Illuminate\Support\Facades\Auth; +use Illuminate\View\View; use Livewire\Attributes\Layout; -use Livewire\Attributes\Validate; use Livewire\Component; #[Layout('components.layouts.auth', [ @@ -15,13 +18,9 @@ class Login extends Component { use WithToast; - #[Validate(['required', 'string'], attribute: 'nama pengguna atau email')] - public string $login = ''; + public LoginForm $form; - #[Validate('required', attribute: 'kata sandi')] - public string $password = ''; - - public function mount() + public function mount(): void { if (! request()->has('message')) { return; @@ -36,9 +35,9 @@ public function mount() JS); } - public function auth() + public function auth(): void { - $this->validate(); + $this->form->validate(); if (! $this->attemptLogin()) { $this->toast('Oops! Nama pengguna, email, atau kata sandi tidak sesuai.', 'Gagal', 'danger'); @@ -49,7 +48,7 @@ public function auth() $user = auth()->user(); if (! $this->userIsActive($user)) { - auth()->logout(); + Auth::logout(); $this->toast( 'Akun Anda belum aktif. Mohon periksa email untuk mengaktifkan akun, dan hubungi kami jika memerlukan bantuan lebih lanjut.', @@ -67,22 +66,22 @@ public function auth() $this->redirectByRole($user->roles->pluck('name')->toArray()); } - protected function attemptLogin() + protected function attemptLogin(): bool { - $field = filter_var($this->login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; + $field = filter_var($this->form->login, FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; - return auth()->attempt([ - $field => $this->login, - 'password' => $this->password, + return Auth::attempt([ + $field => $this->form->login, + 'password' => $this->form->password, ]); } - protected function userIsActive($user) + protected function userIsActive(?User $user): bool { return $user?->status === UserStatus::ACTIVE; } - protected function redirectByRole(array $roles) + protected function redirectByRole(array $roles): void { if (array_intersect($roles, ['Developer', 'Owner', 'Leader', 'Admin'])) { $this->redirectIntended('/studio/dashboard/overview', navigate: true); @@ -105,7 +104,7 @@ protected function redirectByRole(array $roles) $this->redirectIntended('/login', navigate: true); } - public function render() + public function render(): View { return view('livewire.auth.login'); } diff --git a/app/Livewire/Auth/Logout.php b/app/Livewire/Auth/Logout.php index b612e02..77ce539 100644 --- a/app/Livewire/Auth/Logout.php +++ b/app/Livewire/Auth/Logout.php @@ -2,11 +2,12 @@ namespace App\Livewire\Auth; +use Illuminate\View\View; use Livewire\Component; class Logout extends Component { - public function logout() + public function logout(): void { auth()->logout(); @@ -16,7 +17,7 @@ public function logout() $this->redirectRoute('login'); } - public function render() + public function render(): View { return view('livewire.auth.logout'); } diff --git a/app/Livewire/Auth/Register.php b/app/Livewire/Auth/Register.php index 0fb30cb..d7bd223 100644 --- a/app/Livewire/Auth/Register.php +++ b/app/Livewire/Auth/Register.php @@ -9,6 +9,7 @@ use App\Traits\WithToast; use App\Traits\WithUpdatedData; use Illuminate\Support\Str; +use Illuminate\View\View; use Livewire\Attributes\Layout; use Livewire\Component; @@ -27,7 +28,7 @@ class Register extends Component public int $totalSteps = 2; - public function mount() + public function mount(): void { $this->steps = [ ['id' => 1, 'name' => 'Kredensial'], @@ -35,7 +36,7 @@ public function mount() ]; } - public function updateStep(int $value) + public function updateStep(int $value): void { if ($this->shouldValidateBeforeChangingStep()) { $this->form->validateStep1(); @@ -44,7 +45,7 @@ public function updateStep(int $value) $this->currentStep = $value; } - public function nextStep() + public function nextStep(): void { match ($this->currentStep) { 1 => $this->form->validateStep1(), @@ -57,19 +58,19 @@ public function nextStep() } } - public function prevStep() + public function prevStep(): void { if ($this->currentStep > 1) { $this->currentStep--; } } - public function updated(string $propertyName, $value) + public function updated(string $propertyName, mixed $value): void { $this->validateUpdatedField($propertyName); } - public function register() + public function register(): void { $this->form->auth(); @@ -78,7 +79,7 @@ public function register() $this->redirectAfterRegistration(); } - public function render() + public function render(): View { return view('livewire.auth.register'); } @@ -86,7 +87,7 @@ public function render() /** * Determine whether validation is required before changing step. */ - protected function shouldValidateBeforeChangingStep() + protected function shouldValidateBeforeChangingStep(): bool { return $this->currentStep === 1; } @@ -94,7 +95,7 @@ protected function shouldValidateBeforeChangingStep() /** * Validate updated field based on current form step rules. */ - protected function validateUpdatedField(string $propertyName) + protected function validateUpdatedField(string $propertyName): void { $field = Str::replace('form.', '', $propertyName); @@ -110,7 +111,7 @@ protected function validateUpdatedField(string $propertyName) /** * Show success toast after registration. */ - protected function sendRegistrationSuccessToast() + protected function sendRegistrationSuccessToast(): void { $this->toast('Selamat, akun Anda berhasil didaftarkan. Silakan periksa email Anda untuk melakukan verifikasi.'); } @@ -118,7 +119,7 @@ protected function sendRegistrationSuccessToast() /** * Dispatch notification to privileged users when a new member registers. */ - protected function notifyPrivilegedUsersAboutNewMember() + protected function notifyPrivilegedUsersAboutNewMember(): void { $userIds = User::role(['Developer', 'Owner'])->pluck('id')->toArray(); @@ -135,7 +136,7 @@ protected function notifyPrivilegedUsersAboutNewMember() /** * Redirect user after successful registration. */ - protected function redirectAfterRegistration() + protected function redirectAfterRegistration(): void { $this->redirectIntended('/member/overview', navigate: true); } diff --git a/app/Livewire/Auth/ResetPassword.php b/app/Livewire/Auth/ResetPassword.php index 1efe01c..29c400d 100644 --- a/app/Livewire/Auth/ResetPassword.php +++ b/app/Livewire/Auth/ResetPassword.php @@ -5,6 +5,7 @@ use App\Livewire\Forms\Auth\ResetPasswordForm; use App\Traits\WithToast; use Illuminate\Support\Facades\Password; +use Illuminate\View\View; use Livewire\Attributes\Layout; use Livewire\Attributes\Url; use Livewire\Component; @@ -19,17 +20,17 @@ class ResetPassword extends Component public ResetPasswordForm $form; #[Url] - public $token = ''; + public string $token = ''; #[Url] - public $email = ''; + public string $email = ''; - public function mount() + public function mount(): void { $this->form->setTokenAndEmail($this->token, $this->email); } - public function resetPassword() + public function resetPassword(): mixed { $status = $this->form->store(); @@ -40,7 +41,7 @@ public function resetPassword() : $this->toast(__($status), 'Gagal', 'danger'); } - public function render() + public function render(): View { return view('livewire.auth.reset-password'); } diff --git a/app/Livewire/Forms/Auth/ForgotPasswordForm.php b/app/Livewire/Forms/Auth/ForgotPasswordForm.php new file mode 100644 index 0000000..12ca3b3 --- /dev/null +++ b/app/Livewire/Forms/Auth/ForgotPasswordForm.php @@ -0,0 +1,24 @@ + ['required', 'string', 'email'], + ]; + } + + public function validationAttributes(): array + { + return [ + 'email' => 'email', + ]; + } +} diff --git a/app/Livewire/Forms/Auth/LoginForm.php b/app/Livewire/Forms/Auth/LoginForm.php new file mode 100644 index 0000000..0f29b80 --- /dev/null +++ b/app/Livewire/Forms/Auth/LoginForm.php @@ -0,0 +1,28 @@ + ['required', 'string'], + 'password' => ['required'], + ]; + } + + public function validationAttributes(): array + { + return [ + 'login' => 'nama pengguna atau email', + 'password' => 'kata sandi', + ]; + } +} diff --git a/app/Livewire/Forms/Auth/RegisterForm.php b/app/Livewire/Forms/Auth/RegisterForm.php index 5fddfa7..ac33639 100644 --- a/app/Livewire/Forms/Auth/RegisterForm.php +++ b/app/Livewire/Forms/Auth/RegisterForm.php @@ -62,17 +62,17 @@ public function rulesStep2(): array ]; } - public function validateStep1() + public function validateStep1(): void { $this->validate($this->rulesStep1()); } - public function validateStep2() + public function validateStep2(): void { $this->validate($this->rulesStep2()); } - public function validateAll() + public function validateAll(): void { $this->validate(array_merge( $this->rulesStep1(), @@ -91,7 +91,7 @@ public function validationAttributes(): array ]; } - public function auth() + public function auth(): string { $this->validateAll(); @@ -99,7 +99,7 @@ public function auth() $maxUser = User::max('id') + 1; $referralCode = ReferralCode::where('code', $this->referral_code)->first(); - DB::transaction(function () use ($tier, $maxUser, $referralCode, &$customer) { + DB::transaction(function () use ($tier, $maxUser, $referralCode, &$customer): void { $user = User::create([ 'email' => $this->email, 'username' => $this->username, diff --git a/app/Livewire/Forms/Auth/ResetPasswordForm.php b/app/Livewire/Forms/Auth/ResetPasswordForm.php index 2a2f920..817e69f 100644 --- a/app/Livewire/Forms/Auth/ResetPasswordForm.php +++ b/app/Livewire/Forms/Auth/ResetPasswordForm.php @@ -18,7 +18,7 @@ class ResetPasswordForm extends Form public string $password_confirmation = ''; - public function rules() + public function rules(): array { return [ 'token' => 'required', @@ -36,13 +36,13 @@ public function validationAttributes(): array ]; } - public function setTokenAndEmail(string $token, string $email) + public function setTokenAndEmail(string $token, string $email): void { $this->token = $token; $this->email = $email; } - public function store() + public function store(): string { $this->validate(); diff --git a/resources/views/livewire/auth/forgot-password.blade.php b/resources/views/livewire/auth/forgot-password.blade.php index 115afb7..efcc207 100644 --- a/resources/views/livewire/auth/forgot-password.blade.php +++ b/resources/views/livewire/auth/forgot-password.blade.php @@ -20,9 +20,9 @@ class="size-8 rounded shrink-0 bg-accent text-accent-foreground flex items-cente
Email * - - + Kirim Tautan diff --git a/resources/views/livewire/auth/login.blade.php b/resources/views/livewire/auth/login.blade.php index c2db9ab..cb7684b 100644 --- a/resources/views/livewire/auth/login.blade.php +++ b/resources/views/livewire/auth/login.blade.php @@ -20,9 +20,9 @@ class="size-8 rounded shrink-0 bg-accent text-accent-foreground flex items-cente
Nama Pengguna atau Email * - - + @@ -34,9 +34,9 @@ class="size-8 rounded shrink-0 bg-accent text-accent-foreground flex items-cente sandi?
- + - + Masuk diff --git a/tests/Feature/Livewire/Auth/ForgotPasswordTest.php b/tests/Feature/Livewire/Auth/ForgotPasswordTest.php index 9750be5..d7546c1 100644 --- a/tests/Feature/Livewire/Auth/ForgotPasswordTest.php +++ b/tests/Feature/Livewire/Auth/ForgotPasswordTest.php @@ -16,7 +16,7 @@ function attemptSendResetLink(string $email) { return Livewire::test(ForgotPassword::class) - ->set('email', $email) + ->set('form.email', $email) ->call('sendLink'); } @@ -24,7 +24,7 @@ function mockPasswordResetStatus(string $status, string $email = 'user@example.c { Password::shouldReceive('sendResetLink') ->once() - ->with(['email' => $email]) + ->with(['form.email' => $email]) ->andReturn($status); } @@ -37,7 +37,7 @@ function mockPasswordResetStatus(string $status, string $email = 'user@example.c it('renders forgot password component successfully', function () { Livewire::test(ForgotPassword::class) ->assertViewIs('livewire.auth.forgot-password') - ->assertSet('email', ''); + ->assertSet('form.email', ''); }); /* @@ -48,9 +48,9 @@ function mockPasswordResetStatus(string $status, string $email = 'user@example.c it('validates email field is required', function () { Livewire::test(ForgotPassword::class) - ->set('email', '') + ->set('form.email', '') ->call('sendLink') - ->assertHasErrors(['email' => 'required']); + ->assertHasErrors(['form.email' => 'required']); }); /* diff --git a/tests/Feature/Livewire/Auth/LoginTest.php b/tests/Feature/Livewire/Auth/LoginTest.php index 43d4dd8..3b26676 100644 --- a/tests/Feature/Livewire/Auth/LoginTest.php +++ b/tests/Feature/Livewire/Auth/LoginTest.php @@ -46,8 +46,8 @@ function makeUser(?string $role = null, bool $isActive = true): User function attemptLogin(string $login, string $password) { return Livewire::test(Login::class) - ->set('login', $login) - ->set('password', $password) + ->set('form.login', $login) + ->set('form.password', $password) ->call('auth'); } @@ -60,14 +60,14 @@ function attemptLogin(string $login, string $password) it('renders login component successfully', function () { Livewire::test(Login::class) ->assertViewIs('livewire.auth.login') - ->assertSet('login', '') - ->assertSet('password', ''); + ->assertSet('form.login', '') + ->assertSet('form.password', ''); }); it('mounts component without query parameters', function () { Livewire::test(Login::class) - ->assertSet('login', '') - ->assertSet('password', ''); + ->assertSet('form.login', '') + ->assertSet('form.password', ''); }); it('mounts component with message query parameter', function () { @@ -75,8 +75,8 @@ function attemptLogin(string $login, string $password) Livewire::withQueryParams(['message' => $message]) ->test(Login::class) - ->assertSet('login', '') - ->assertSet('password', ''); + ->assertSet('form.login', '') + ->assertSet('form.password', ''); }); /* @@ -87,26 +87,26 @@ function attemptLogin(string $login, string $password) it('validates required fields', function () { Livewire::test(Login::class) - ->set('login', '') - ->set('password', '') + ->set('form.login', '') + ->set('form.password', '') ->call('auth') - ->assertHasErrors(['login', 'password']); + ->assertHasErrors(['form.login', 'form.password']); }); it('validates login field is required', function () { Livewire::test(Login::class) - ->set('login', '') - ->set('password', 'password123') + ->set('form.login', '') + ->set('form.password', 'password123') ->call('auth') - ->assertHasErrors(['login']); + ->assertHasErrors(['form.login']); }); it('validates password field is required', function () { Livewire::test(Login::class) - ->set('login', 'testuser') - ->set('password', '') + ->set('form.login', 'testuser') + ->set('form.password', '') ->call('auth') - ->assertHasErrors(['password']); + ->assertHasErrors(['form.password']); }); /*