diff --git a/app/Livewire/Auth/Register.php b/app/Livewire/Auth/Register.php
new file mode 100644
index 0000000..1152b1d
--- /dev/null
+++ b/app/Livewire/Auth/Register.php
@@ -0,0 +1,92 @@
+ 'Daftar Akun',
+])]
+class Register extends Component
+{
+ public RegisterForm $form;
+
+ public array $steps = [];
+
+ public int $currentStep = 1;
+
+ public int $totalSteps = 2;
+
+ public function mount()
+ {
+ $this->steps = [
+ ['id' => 1, 'name' => 'Kredensial'],
+ ['id' => 2, 'name' => 'Informasi'],
+ ];
+ }
+
+ public function updateStep(int $value)
+ {
+ if ($this->currentStep === 1) {
+ $this->form->validateStep1();
+ }
+
+ $this->currentStep = $value;
+ }
+
+ public function nextStep()
+ {
+ match ($this->currentStep) {
+ 1 => $this->form->validateStep1(),
+ 2 => $this->form->validateStep2(),
+ default => null,
+ };
+
+ if ($this->currentStep < $this->totalSteps) {
+ $this->currentStep++;
+ }
+ }
+
+ public function prevStep()
+ {
+ if ($this->currentStep > 1) {
+ $this->currentStep--;
+ }
+ }
+
+ public function updated(string $propertyName, $value)
+ {
+ $field = Str::replace('form.', '', $propertyName);
+
+ if (array_key_exists($field, $this->form->rulesStep1())) {
+ $this->validateOnly($propertyName, $this->form->rulesStep1());
+ }
+
+ if (array_key_exists($field, $this->form->rulesStep2())) {
+ $this->validateOnly($propertyName, $this->form->rulesStep2());
+ }
+ }
+
+ public function register()
+ {
+ $this->form->auth();
+
+ Flux::toast(
+ heading: 'Berhasil',
+ text: 'Selamat, akun Anda berhasil didaftarkan. Silakan cek email Anda untuk melakukan verifikasi.',
+ variant: 'success',
+ duration: 3000
+ );
+
+ $this->redirectIntended('/customer/dashboard/overview', navigate: true);
+ }
+
+ public function render()
+ {
+ return view('livewire.auth.register');
+ }
+}
diff --git a/app/Livewire/Forms/RegisterForm.php b/app/Livewire/Forms/RegisterForm.php
new file mode 100644
index 0000000..b4c1f5b
--- /dev/null
+++ b/app/Livewire/Forms/RegisterForm.php
@@ -0,0 +1,140 @@
+ ['required', 'email', 'max:100', Rule::unique('users', 'email')],
+ 'username' => ['required', 'alpha_num', 'min:5', 'max:20', Rule::unique('users', 'username')],
+ 'password' => [
+ 'required',
+ 'string',
+ 'min:8',
+ Password::min(8)->letters()->mixedCase()
+ ->numbers()
+ ->symbols()
+ ->uncompromised(),
+ ],
+ ];
+ }
+
+ public function rulesStep2(): array
+ {
+ return [
+ 'name' => ['required', 'string', 'max:50'],
+ 'phone_number' => ['required', 'string', new PhoneNumber],
+ 'gender' => ['required', Rule::in(Gender::values())],
+ 'referral_code' => ['nullable', 'string', Rule::exists('referral_codes', 'code')],
+ ];
+ }
+
+ public function validateStep1()
+ {
+ $this->validate($this->rulesStep1());
+ }
+
+ public function validateStep2()
+ {
+ $this->validate($this->rulesStep2());
+ }
+
+ public function validateAll()
+ {
+ $this->validate(array_merge(
+ $this->rulesStep1(),
+ $this->rulesStep2()
+ ));
+ }
+
+ public function validationAttributes(): array
+ {
+ return [
+ 'username' => 'nama pengguna',
+ 'password' => 'kata sandi',
+ 'name' => 'nama',
+ 'phone_number' => 'nomor telepon',
+ 'gender' => 'jenis kelamin',
+ ];
+ }
+
+ public function auth()
+ {
+ $this->validateAll();
+
+ $tier = Tier::orderBy('min_points')->first();
+ $maxUser = User::max('id') + 1;
+ $referralCode = ReferralCode::where('code', $this->referral_code)->first();
+
+ DB::transaction(function () use ($tier, $maxUser, $referralCode) {
+ $user = User::create([
+ 'email' => $this->email,
+ 'username' => $this->username,
+ 'password' => Hash::make($this->password),
+ 'status' => UserStatus::ACTIVE,
+ ]);
+
+ Customer::create([
+ 'user_id' => $user->id,
+ 'name' => $this->name,
+ 'phone_number' => $this->phone_number,
+ 'gender' => $this->gender,
+ ]);
+
+ Membership::create([
+ 'user_id' => $user->id,
+ 'tier_id' => $tier->id,
+ 'total_points' => 0,
+ ]);
+
+ ReferralCode::create([
+ 'user_id' => $user->id,
+ 'code' => generateReferralCode($this->username, $maxUser),
+ ]);
+
+ if ($this->referral_code) {
+ ReferralUsage::create([
+ 'user_id' => $user->id,
+ 'referral_code_id' => $referralCode->id,
+ ]);
+
+ $referralCode->update(['uses_count', $referralCode->uses_count + 1]);
+ }
+
+ auth()->login($user);
+
+ $user->sendEmailVerificationNotification();
+ });
+ }
+}
diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php
index 4ef026a..b2daeb4 100644
--- a/database/migrations/0001_01_01_000000_create_users_table.php
+++ b/database/migrations/0001_01_01_000000_create_users_table.php
@@ -18,6 +18,7 @@ public function up(): void
$table->string('username', 20)->unique();
$table->string('password', 97);
$table->enum('status', [UserStatus::values()])->default(UserStatus::ACTIVE)->comment(UserStatus::comment());
+ $table->timestamp('email_verified_at')->nullable();
$table->timestamp('last_login_at')->nullable();
$table->timestamp('last_password_change_at')->nullable();
$table->timestamps();
diff --git a/resources/views/livewire/auth/login.blade.php b/resources/views/livewire/auth/login.blade.php
index d12ddd5..b5f947a 100644
--- a/resources/views/livewire/auth/login.blade.php
+++ b/resources/views/livewire/auth/login.blade.php
@@ -36,6 +36,11 @@ class="size-8 rounded shrink-0 bg-accent text-accent-foreground flex items-cente