From 5cc8ba26b2d0fc69582f7ace8793f635a983f641 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Mon, 3 Aug 2026 13:43:30 +0700 Subject: [PATCH] feat: update user registration to use username instead of name, add user profile model and migration, and implement gender enum - Changed user creation to use 'username' instead of 'name'. - Added UserProfile model with relationships to User and gender enum. - Updated validation rules for username and email. - Modified migrations to create user_profiles table and adjust users table. - Updated seeder to create users with profiles. - Translated various UI texts to Indonesian and improved layout components. --- app/Actions/Fortify/CreateNewUser.php | 7 +- app/Concerns/ProfileValidationRules.php | 31 ++--- app/Enums/Gender.php | 17 +++ app/Models/User.php | 53 ++++---- app/Models/UserProfile.php | 28 ++++ app/Providers/FortifyServiceProvider.php | 27 ---- config/fortify.php | 24 +--- database/factories/UserFactory.php | 21 +-- .../0001_01_01_000000_create_users_table.php | 13 +- ...8_03_000002_create_user_profiles_table.php | 30 +++++ database/seeders/DatabaseSeeder.php | 11 +- database/seeders/UserSeeder.php | 78 ++++++++++++ resources/js/layouts/auth-layout.tsx | 2 +- .../js/layouts/auth/auth-split-layout.tsx | 9 +- resources/js/pages/auth/confirm-password.tsx | 23 +--- resources/js/pages/auth/forgot-password.tsx | 17 ++- resources/js/pages/auth/login.tsx | 82 ++++++++---- resources/js/pages/auth/register.tsx | 120 ------------------ resources/js/pages/auth/reset-password.tsx | 10 +- .../js/pages/auth/two-factor-challenge.tsx | 20 +-- resources/js/pages/auth/verify-email.tsx | 15 +-- resources/js/pages/welcome.tsx | 21 +-- 22 files changed, 301 insertions(+), 358 deletions(-) create mode 100644 app/Enums/Gender.php create mode 100644 app/Models/UserProfile.php create mode 100644 database/migrations/2026_08_03_000002_create_user_profiles_table.php create mode 100644 database/seeders/UserSeeder.php delete mode 100644 resources/js/pages/auth/register.tsx diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php index 3c7c00c..4dfb39d 100644 --- a/app/Actions/Fortify/CreateNewUser.php +++ b/app/Actions/Fortify/CreateNewUser.php @@ -12,11 +12,6 @@ class CreateNewUser implements CreatesNewUsers { use PasswordValidationRules, ProfileValidationRules; - /** - * Validate and create a newly registered user. - * - * @param array $input - */ public function create(array $input): User { Validator::make($input, [ @@ -25,7 +20,7 @@ public function create(array $input): User ])->validate(); return User::create([ - 'name' => $input['name'], + 'username' => $input['username'], 'email' => $input['email'], 'password' => $input['password'], ]); diff --git a/app/Concerns/ProfileValidationRules.php b/app/Concerns/ProfileValidationRules.php index a9c069b..33b6909 100644 --- a/app/Concerns/ProfileValidationRules.php +++ b/app/Concerns/ProfileValidationRules.php @@ -3,39 +3,32 @@ namespace App\Concerns; use App\Models\User; -use Illuminate\Contracts\Validation\ValidationRule; use Illuminate\Validation\Rule; trait ProfileValidationRules { - /** - * Get the validation rules used to validate user profiles. - * - * @return array|string>> - */ protected function profileRules(?int $userId = null): array { return [ - 'name' => $this->nameRules(), + 'username' => $this->usernameRules($userId), 'email' => $this->emailRules($userId), ]; } - /** - * Get the validation rules used to validate user names. - * - * @return array|string> - */ - protected function nameRules(): array + protected function usernameRules(?int $userId = null): array { - return ['required', 'string', 'max:255']; + return [ + 'required', + 'string', + 'max:20', + 'min:3', + 'alpha_dash', + $userId === null + ? Rule::unique(User::class) + : Rule::unique(User::class)->ignore($userId), + ]; } - /** - * Get the validation rules used to validate user emails. - * - * @return array|string> - */ protected function emailRules(?int $userId = null): array { return [ diff --git a/app/Enums/Gender.php b/app/Enums/Gender.php new file mode 100644 index 0000000..b96c362 --- /dev/null +++ b/app/Enums/Gender.php @@ -0,0 +1,17 @@ + 'Laki-laki', + self::Female => 'Perempuan', + }; + } +} diff --git a/app/Models/User.php b/app/Models/User.php index e67ee72..069f358 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,49 +2,40 @@ namespace App\Models; -// use Illuminate\Contracts\Auth\MustVerifyEmail; -use Database\Factories\UserFactory; -use Illuminate\Database\Eloquent\Attributes\Fillable; +use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Hidden; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\HasOne; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; -use Illuminate\Support\Carbon; -use Laravel\Fortify\Contracts\PasskeyUser; -use Laravel\Fortify\PasskeyAuthenticatable; -use Laravel\Fortify\TwoFactorAuthenticatable; -/** - * @property int $id - * @property string $name - * @property string $email - * @property Carbon|null $email_verified_at - * @property string $password - * @property string|null $two_factor_secret - * @property string|null $two_factor_recovery_codes - * @property Carbon|null $two_factor_confirmed_at - * @property string|null $remember_token - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - */ -#[Fillable(['name', 'email', 'password'])] -#[Hidden(['password', 'two_factor_secret', 'two_factor_recovery_codes', 'remember_token'])] -class User extends Authenticatable implements PasskeyUser +#[Hidden(['password'])] +#[Guarded(['id', 'last_login_at'])] +class User extends Authenticatable { - /** @use HasFactory */ - use HasFactory, Notifiable, PasskeyAuthenticatable, TwoFactorAuthenticatable; + use HasFactory, Notifiable, SoftDeletes; - /** - * Get the attributes that should be cast. - * - * @return array - */ protected function casts(): array { return [ - 'email_verified_at' => 'datetime', + 'is_active' => 'boolean', + 'last_login_at' => 'datetime', 'password' => 'hashed', 'two_factor_confirmed_at' => 'datetime', ]; } + + protected function fullName(): Attribute + { + return Attribute::get(function () { + return $this->profile?->full_name ?? $this->username; + }); + } + + public function profile(): HasOne + { + return $this->hasOne(UserProfile::class); + } } diff --git a/app/Models/UserProfile.php b/app/Models/UserProfile.php new file mode 100644 index 0000000..4d3ba5b --- /dev/null +++ b/app/Models/UserProfile.php @@ -0,0 +1,28 @@ + Gender::class, + 'birth_date' => 'date', + ]; + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index 0215f0c..2bf0787 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -2,7 +2,6 @@ namespace App\Providers; -use App\Actions\Fortify\CreateNewUser; use App\Actions\Fortify\ResetUserPassword; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; @@ -16,17 +15,11 @@ class FortifyServiceProvider extends ServiceProvider { - /** - * Register any application services. - */ public function register(): void { // } - /** - * Bootstrap any application services. - */ public function boot(): void { $this->configureActions(); @@ -34,18 +27,11 @@ public function boot(): void $this->configureRateLimiting(); } - /** - * Configure Fortify actions. - */ private function configureActions(): void { Fortify::resetUserPasswordsUsing(ResetUserPassword::class); - Fortify::createUsersUsing(CreateNewUser::class); } - /** - * Configure Fortify views. - */ private function configureViews(): void { Fortify::loginView(fn (Request $request) => Inertia::render('auth/login', [ @@ -67,18 +53,11 @@ private function configureViews(): void 'status' => $request->session()->get('status'), ])); - Fortify::registerView(fn () => Inertia::render('auth/register', [ - 'passwordRules' => Password::defaults()->toPasswordRulesString(), - ])); - Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/two-factor-challenge')); Fortify::confirmPasswordView(fn () => Inertia::render('auth/confirm-password')); } - /** - * Configure rate limiting. - */ private function configureRateLimiting(): void { RateLimiter::for('two-factor', function (Request $request) { @@ -90,11 +69,5 @@ private function configureRateLimiting(): void return Limit::perMinute(5)->by($throttleKey); }); - - RateLimiter::for('passkeys', function (Request $request) { - return Limit::perMinute(10)->by( - ($request->input('credential.id') ?: $request->session()->getId()).'|'.$request->ip(), - ); - }); } } diff --git a/config/fortify.php b/config/fortify.php index cedebce..928f100 100644 --- a/config/fortify.php +++ b/config/fortify.php @@ -45,7 +45,7 @@ | */ - 'username' => 'email', + 'username' => 'username', 'email' => 'email', @@ -117,7 +117,6 @@ 'limiters' => [ 'login' => 'login', 'two-factor' => 'two-factor', - 'passkeys' => 'passkeys', ], /* @@ -133,22 +132,6 @@ 'views' => true, - /* - |-------------------------------------------------------------------------- - | Passkeys - |-------------------------------------------------------------------------- - | - | These settings configure Fortify's passkey (WebAuthn) support. - | - */ - - 'passkeys' => [ - 'relying_party_id' => parse_url(config('app.url'), PHP_URL_HOST), - 'allowed_origins' => [config('app.url')], - 'user_handle_secret' => env('PASSKEYS_USER_HANDLE_SECRET', config('app.key')), - 'timeout' => 60000, - ], - /* |-------------------------------------------------------------------------- | Features @@ -161,16 +144,11 @@ */ 'features' => [ - Features::registration(), Features::resetPasswords(), Features::emailVerification(), Features::twoFactorAuthentication([ 'confirm' => true, 'confirmPassword' => true, - // 'window' => 0 - ]), - Features::passkeys([ - 'confirmPassword' => true, ]), ], diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 98825c8..391bc5f 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -5,40 +5,28 @@ use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Facades\Hash; -use Illuminate\Support\Str; /** * @extends Factory */ class UserFactory extends Factory { - /** - * The current password being used by the factory. - */ protected static ?string $password; - /** - * Define the model's default state. - * - * @return array - */ public function definition(): array { return [ - 'name' => fake()->name(), + 'username' => fake()->unique()->userName(), 'email' => fake()->unique()->safeEmail(), - 'email_verified_at' => now(), 'password' => static::$password ??= Hash::make('password'), - 'remember_token' => Str::random(10), + 'is_active' => true, + 'last_login_at' => null, 'two_factor_secret' => null, 'two_factor_recovery_codes' => null, 'two_factor_confirmed_at' => null, ]; } - /** - * Indicate that the model's email address should be unverified. - */ public function unverified(): static { return $this->state(fn (array $attributes) => [ @@ -46,9 +34,6 @@ public function unverified(): static ]); } - /** - * Indicate that the model has two-factor authentication configured. - */ public function withTwoFactor(): static { return $this->state(fn (array $attributes) => [ 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 05fb5d9..38745b2 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -6,19 +6,17 @@ return new class extends Migration { - /** - * Run the migrations. - */ public function up(): void { Schema::create('users', function (Blueprint $table) { $table->id(); - $table->string('name'); + $table->string('username', 20)->unique(); $table->string('email')->unique(); - $table->timestamp('email_verified_at')->nullable(); $table->string('password'); - $table->rememberToken(); + $table->boolean('is_active')->default(true); + $table->timestamp('last_login_at')->nullable(); $table->timestamps(); + $table->softDeletes(); }); Schema::create('password_reset_tokens', function (Blueprint $table) { @@ -37,9 +35,6 @@ public function up(): void }); } - /** - * Reverse the migrations. - */ public function down(): void { Schema::dropIfExists('users'); diff --git a/database/migrations/2026_08_03_000002_create_user_profiles_table.php b/database/migrations/2026_08_03_000002_create_user_profiles_table.php new file mode 100644 index 0000000..594f390 --- /dev/null +++ b/database/migrations/2026_08_03_000002_create_user_profiles_table.php @@ -0,0 +1,30 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('full_name', 150); + $table->string('phone_number', 20)->nullable(); + $table->text('address')->nullable(); + $table->enum('gender', array_values(Gender::cases()))->nullable(); + $table->string('birth_place', 100)->nullable(); + $table->date('birth_date')->nullable(); + $table->timestamps(); + $table->softDeletes(); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_profiles'); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 6b901f8..d71892e 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,7 +2,6 @@ namespace Database\Seeders; -use App\Models\User; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; @@ -10,16 +9,10 @@ class DatabaseSeeder extends Seeder { use WithoutModelEvents; - /** - * Seed the application's database. - */ public function run(): void { - // User::factory(10)->create(); - - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', + $this->call([ + UserSeeder::class, ]); } } diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 0000000..12582f6 --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,78 @@ + 'pangestu', + 'email' => 'pangestu@student.itmpwk.ac.id', + 'profile' => [ + 'full_name' => 'Yoga Pangestu', + 'phone_number' => '082121495806', + 'address' => 'Jl. Merdeka No. 1, Purwakarta', + 'gender' => 'male', + 'birth_place' => 'Subang', + 'birth_date' => '2005-03-13', + ], + ], + [ + 'username' => 'doni', + 'email' => 'doni@student.itmpwk.ac.id', + 'profile' => [ + 'full_name' => 'Doni Setiawan Ramadhan', + 'phone_number' => '085793462823', + 'address' => 'Jl. Merdeka No. 1, Purwakarta', + 'gender' => 'male', + 'birth_place' => 'Purwakarta', + 'birth_date' => '2004-10-30', + ], + ], + [ + 'username' => 'asep', + 'email' => 'asep@student.itmpwk.ac.id', + 'profile' => [ + 'full_name' => 'Asep Saepudin', + 'phone_number' => '081546505033', + 'address' => 'Jl. Merdeka No. 1, Purwakarta', + 'gender' => 'male', + 'birth_place' => 'Purwakarta', + 'birth_date' => '2005-09-24', + ], + ], + [ + 'username' => 'komoala', + 'email' => 'komoala@student.itmpwk.ac.id', + 'profile' => [ + 'full_name' => 'Komala Dewi', + 'phone_number' => '085819894938', + 'address' => 'Jl. Merdeka No. 1, Purwakarta', + 'gender' => 'female', + 'birth_place' => 'Purwakarta', + 'birth_date' => '2005-05-04', + ], + ], + ]; + + foreach ($users as $userData) { + $profile = $userData['profile']; + unset($userData['profile']); + + $userData['password'] = Hash::make('Minimal8@'); + + $user = User::create($userData); + $user->profile()->create($profile); + } + } +} diff --git a/resources/js/layouts/auth-layout.tsx b/resources/js/layouts/auth-layout.tsx index 698dd75..94d22db 100644 --- a/resources/js/layouts/auth-layout.tsx +++ b/resources/js/layouts/auth-layout.tsx @@ -1,4 +1,4 @@ -import AuthLayoutTemplate from '@/layouts/auth/auth-simple-layout'; +import AuthLayoutTemplate from '@/layouts/auth/auth-split-layout'; export default function AuthLayout({ title = '', diff --git a/resources/js/layouts/auth/auth-split-layout.tsx b/resources/js/layouts/auth/auth-split-layout.tsx index a567729..05dffa0 100644 --- a/resources/js/layouts/auth/auth-split-layout.tsx +++ b/resources/js/layouts/auth/auth-split-layout.tsx @@ -13,7 +13,14 @@ export default function AuthSplitLayout({ return (
-
+
+
- - - +
{({ processing, errors }) => ( @@ -49,7 +34,7 @@ export default function ConfirmPassword() { data-test="confirm-password-button" > {processing && } - Confirm password + Konfirmasi password
@@ -60,7 +45,7 @@ export default function ConfirmPassword() { } ConfirmPassword.layout = { - title: 'Confirm password', + title: 'Konfirmasi password', description: - 'This is a secure area of the application. Please confirm your password before continuing.', + 'Ini adalah area aman dari aplikasi. Silakan konfirmasi password Anda sebelum melanjutkan.', }; diff --git a/resources/js/pages/auth/forgot-password.tsx b/resources/js/pages/auth/forgot-password.tsx index 25c81b9..b94a900 100644 --- a/resources/js/pages/auth/forgot-password.tsx +++ b/resources/js/pages/auth/forgot-password.tsx @@ -1,4 +1,3 @@ -// Components import { Form, Head } from '@inertiajs/react'; import { LoaderCircle } from 'lucide-react'; import InputError from '@/components/input-error'; @@ -12,7 +11,7 @@ import { email } from '@/routes/password'; export default function ForgotPassword({ status }: { status?: string }) { return ( <> - + {status && (
@@ -25,14 +24,14 @@ export default function ForgotPassword({ status }: { status?: string }) { {({ processing, errors }) => ( <>
- + @@ -47,7 +46,7 @@ export default function ForgotPassword({ status }: { status?: string }) { {processing && ( )} - Email password reset link + Kirim link reset password
@@ -55,8 +54,8 @@ export default function ForgotPassword({ status }: { status?: string }) {
- Or, return to - log in + Atau kembali ke + masuk
@@ -64,6 +63,6 @@ export default function ForgotPassword({ status }: { status?: string }) { } ForgotPassword.layout = { - title: 'Forgot password', - description: 'Enter your email to receive a password reset link', + title: 'Lupa password', + description: 'Masukkan email Anda untuk menerima link reset password', }; diff --git a/resources/js/pages/auth/login.tsx b/resources/js/pages/auth/login.tsx index f5402ae..188b18c 100644 --- a/resources/js/pages/auth/login.tsx +++ b/resources/js/pages/auth/login.tsx @@ -1,16 +1,15 @@ -import { Form, Head } from '@inertiajs/react'; import InputError from '@/components/input-error'; -import PasskeyVerify from '@/components/passkey-verify'; import PasswordInput from '@/components/password-input'; import TextLink from '@/components/text-link'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; +import { Separator } from '@/components/ui/separator'; import { Spinner } from '@/components/ui/spinner'; -import { register } from '@/routes'; import { store } from '@/routes/login'; import { request } from '@/routes/password'; +import { Form, Head } from '@inertiajs/react'; type Props = { status?: string; @@ -20,9 +19,7 @@ type Props = { export default function Login({ status, canResetPassword }: Props) { return ( <> - - - +
- + - +
- + {canResetPassword && ( - Forgot your password? + Lupa kata sandi? )}
@@ -65,8 +60,7 @@ export default function Login({ status, canResetPassword }: Props) { name="password" required tabIndex={2} - autoComplete="current-password" - placeholder="Password" + placeholder="Kata Sandi" />
@@ -77,7 +71,9 @@ export default function Login({ status, canResetPassword }: Props) { name="remember" tabIndex={3} /> - +
-
-
- Don't have an account?{' '} - - Sign up - +
+
+ +
+
+ + Atau + +
+
+ +
)} @@ -112,6 +138,6 @@ export default function Login({ status, canResetPassword }: Props) { } Login.layout = { - title: 'Log in to your account', - description: 'Enter your email and password below to log in', + title: 'Masuk ke akun Anda', + description: 'Masukkan username dan password Anda di bawah ini untuk masuk', }; diff --git a/resources/js/pages/auth/register.tsx b/resources/js/pages/auth/register.tsx deleted file mode 100644 index ce766ef..0000000 --- a/resources/js/pages/auth/register.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { Form, Head } from '@inertiajs/react'; -import InputError from '@/components/input-error'; -import PasswordInput from '@/components/password-input'; -import TextLink from '@/components/text-link'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Label } from '@/components/ui/label'; -import { Spinner } from '@/components/ui/spinner'; -import { login } from '@/routes'; -import { store } from '@/routes/register'; - -type Props = { - passwordRules: string; -}; - -export default function Register({ passwordRules }: Props) { - return ( - <> - - - {({ processing, errors }) => ( - <> -
-
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
- - -
- -
- Already have an account?{' '} - - Log in - -
- - )} - - - ); -} - -Register.layout = { - title: 'Create an account', - description: 'Enter your details below to create your account', -}; diff --git a/resources/js/pages/auth/reset-password.tsx b/resources/js/pages/auth/reset-password.tsx index 8b762c3..b760f98 100644 --- a/resources/js/pages/auth/reset-password.tsx +++ b/resources/js/pages/auth/reset-password.tsx @@ -43,14 +43,14 @@ export default function ResetPassword({ token, email, passwordRules }: Props) {
- + @@ -58,14 +58,14 @@ export default function ResetPassword({ token, email, passwordRules }: Props) {
(() => { if (showRecoveryInput) { return { - title: 'Recovery code', + title: 'Kode pemulihan', description: - 'Please confirm access to your account by entering one of your emergency recovery codes.', - toggleText: 'login using an authentication code', + 'Silakan konfirmasi akses ke akun Anda dengan memasukkan salah satu kode pemulihan darurat Anda.', + toggleText: 'masuk menggunakan kode autentikasi', }; } return { - title: 'Authentication code', + title: 'Kode autentikasi', description: - 'Enter the authentication code provided by your authenticator application.', - toggleText: 'login using a recovery code', + 'Masukkan kode autentikasi yang diberikan oleh aplikasi autentikator Anda.', + toggleText: 'masuk menggunakan kode pemulihan', }; }, [showRecoveryInput]); @@ -51,7 +51,7 @@ export default function TwoFactorChallenge() { return ( <> - +
@@ -109,11 +109,11 @@ export default function TwoFactorChallenge() { className="w-full" disabled={processing} > - Continue + Lanjutkan
- or you can + atau Anda bisa - Log out + Keluar )} @@ -40,7 +39,7 @@ export default function VerifyEmail({ status }: { status?: string }) { } VerifyEmail.layout = { - title: 'Email verification', + title: 'Verifikasi email', description: - 'Please verify your email address by clicking on the link we just emailed to you.', + 'Silakan verifikasi alamat email Anda dengan mengklik tautan yang baru saja kami kirimkan.', }; diff --git a/resources/js/pages/welcome.tsx b/resources/js/pages/welcome.tsx index fd91ee3..3dd95ee 100644 --- a/resources/js/pages/welcome.tsx +++ b/resources/js/pages/welcome.tsx @@ -1,6 +1,5 @@ import { Head, Link, usePage } from '@inertiajs/react'; import { dashboard, login } from '@/routes'; -import { register } from '@/routes'; export default function Welcome() { const { auth } = usePage().props; @@ -19,20 +18,12 @@ export default function Welcome() { Dashboard ) : ( - <> - - Log in - - - Register - - + + Masuk + )} -- 2.45.2