├── .editorconfig ├── .env.example ├── .envTest ├── .gitattributes ├── .gitignore ├── README.md ├── app ├── Http │ ├── Controllers │ │ ├── Auth │ │ │ ├── EmailVerificationController.php │ │ │ ├── LogoutController.php │ │ │ └── VerifyEmailController.php │ │ └── Controller.php │ └── Middleware │ │ └── RedirectToDashboard.php ├── Livewire │ ├── Actions │ │ └── Logout.php │ └── Forms │ │ └── LoginForm.php ├── Models │ └── User.php ├── Providers │ ├── AppServiceProvider.php │ ├── FolioServiceProvider.php │ └── VoltServiceProvider.php └── View │ └── Components │ ├── AppLayout.php │ └── GuestLayout.php ├── artisan ├── bootstrap ├── app.php ├── cache │ └── .gitignore └── providers.php ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── cache.php ├── database.php ├── devdojo │ └── auth │ │ ├── appearance.php │ │ ├── descriptions.php │ │ ├── language.php │ │ ├── providers.php │ │ └── settings.php ├── filesystems.php ├── logging.php ├── mail.php ├── queue.php ├── services.php └── session.php ├── database ├── .gitignore ├── factories │ └── UserFactory.php ├── migrations │ ├── 0001_01_01_000000_create_users_table.php │ ├── 0001_01_01_000001_create_cache_table.php │ ├── 0001_01_01_000002_create_jobs_table.php │ ├── 2024_04_24_000001_add_user_social_provider_table.php │ ├── 2024_04_24_000002_update_passwords_field_to_be_nullable.php │ └── 2024_05_07_000003_add_two_factor_auth_columns.php └── seeders │ └── DatabaseSeeder.php ├── package-lock.json ├── package.json ├── phpunit.xml ├── postcss.config.cjs ├── postcss.config.js ├── public ├── .htaccess ├── assets │ └── audio │ │ ├── dark.mp3 │ │ └── light.mp3 ├── auth │ ├── app.css │ ├── build │ │ ├── assets │ │ │ ├── scripts.js │ │ │ └── styles.css │ │ └── manifest.json │ └── img │ │ ├── favicon-dark.png │ │ ├── favicon.ico │ │ └── favicon.png ├── favicon.ico ├── genesis │ └── power-ups.json ├── index.php └── robots.txt ├── resources ├── css │ └── app.css ├── js │ ├── app.js │ └── bootstrap.js └── views │ ├── components │ ├── action-message.blade.php │ ├── application-logo.blade.php │ ├── auth-session-status.blade.php │ ├── danger-button.blade.php │ ├── dropdown-link.blade.php │ ├── dropdown.blade.php │ ├── input-error.blade.php │ ├── input-label.blade.php │ ├── layouts │ │ ├── app.blade.php │ │ ├── main.blade.php │ │ └── marketing.blade.php │ ├── modal.blade.php │ ├── nav-link.blade.php │ ├── primary-button.blade.php │ ├── responsive-nav-link.blade.php │ ├── secondary-button.blade.php │ ├── text-input.blade.php │ └── ui │ │ ├── app │ │ └── header.blade.php │ │ ├── badge.blade.php │ │ ├── button.blade.php │ │ ├── checkbox.blade.php │ │ ├── input.blade.php │ │ ├── light-dark-switch.blade.php │ │ ├── link.blade.php │ │ ├── logo.blade.php │ │ ├── marketing │ │ ├── breadcrumbs.blade.php │ │ ├── header.blade.php │ │ └── page-header.blade.php │ │ ├── modal.blade.php │ │ ├── nav-link.blade.php │ │ ├── placeholder.blade.php │ │ ├── select.blade.php │ │ ├── slide-over.blade.php │ │ └── text-link.blade.php │ ├── dashboard.blade.php │ ├── layouts │ ├── app.blade.php │ └── guest.blade.php │ ├── livewire │ ├── .gitkeep │ ├── layout │ │ └── navigation.blade.php │ ├── pages │ │ └── auth │ │ │ ├── confirm-password.blade.php │ │ │ ├── forgot-password.blade.php │ │ │ ├── login.blade.php │ │ │ ├── register.blade.php │ │ │ ├── reset-password.blade.php │ │ │ └── verify-email.blade.php │ ├── profile │ │ ├── delete-user-form.blade.php │ │ ├── update-password-form.blade.php │ │ └── update-profile-information-form.blade.php │ ├── toast.blade.php │ └── welcome │ │ └── navigation.blade.php │ ├── pages │ ├── auth │ │ ├── login.blade.php │ │ ├── password │ │ │ ├── [token].blade.php │ │ │ ├── confirm.blade.php │ │ │ └── reset.blade.php │ │ ├── register.blade.php │ │ └── verify.blade.php │ ├── dashboard │ │ └── index.blade.php │ ├── genesis │ │ ├── about.blade.php │ │ └── power-ups.blade.php │ ├── index.blade.php │ ├── learn │ │ └── index.blade.php │ └── profile │ │ └── edit.blade.php │ ├── profile.blade.php │ ├── vendor │ └── mail │ │ └── html │ │ └── header.blade.php │ └── welcome.blade.php ├── routes ├── auth.php ├── console.php └── web.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tailwind.config.js ├── tests ├── Feature │ ├── Auth │ │ ├── AuthenticationTest.php │ │ ├── EmailVerificationTest.php │ │ ├── LoginTest.php │ │ ├── LogoutTest.php │ │ ├── PasswordConfirmationTest.php │ │ ├── PasswordResetTest.php │ │ ├── PasswordUpdateTest.php │ │ ├── Passwords │ │ │ ├── ConfirmTest.php │ │ │ ├── EmailTest.php │ │ │ └── [Token]Test.php │ │ ├── RegisterTest.php │ │ ├── RegistrationTest.php │ │ └── VerifyTest.php │ ├── ExampleTest.php │ ├── HomeTest.php │ └── ProfileTest.php ├── Pest.php ├── TestCase.php └── Unit │ └── ExampleTest.php └── vite.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_TIMEZONE=UTC 6 | APP_URL=http://localhost 7 | 8 | APP_LOCALE=en 9 | APP_FALLBACK_LOCALE=en 10 | APP_FAKER_LOCALE=en_US 11 | 12 | APP_MAINTENANCE_DRIVER=file 13 | # APP_MAINTENANCE_STORE=database 14 | 15 | BCRYPT_ROUNDS=12 16 | 17 | LOG_CHANNEL=stack 18 | LOG_STACK=single 19 | LOG_DEPRECATIONS_CHANNEL=null 20 | LOG_LEVEL=debug 21 | 22 | DB_CONNECTION=sqlite 23 | # DB_HOST=127.0.0.1 24 | # DB_PORT=3306 25 | # DB_DATABASE=laravel 26 | # DB_USERNAME=root 27 | # DB_PASSWORD= 28 | 29 | SESSION_DRIVER=database 30 | SESSION_LIFETIME=120 31 | SESSION_ENCRYPT=false 32 | SESSION_PATH=/ 33 | SESSION_DOMAIN=null 34 | 35 | BROADCAST_CONNECTION=log 36 | FILESYSTEM_DISK=local 37 | QUEUE_CONNECTION=database 38 | 39 | CACHE_STORE=database 40 | CACHE_PREFIX= 41 | 42 | MEMCACHED_HOST=127.0.0.1 43 | 44 | REDIS_CLIENT=phpredis 45 | REDIS_HOST=127.0.0.1 46 | REDIS_PASSWORD=null 47 | REDIS_PORT=6379 48 | 49 | MAIL_MAILER=log 50 | MAIL_HOST=127.0.0.1 51 | MAIL_PORT=2525 52 | MAIL_USERNAME=null 53 | MAIL_PASSWORD=null 54 | MAIL_ENCRYPTION=null 55 | MAIL_FROM_ADDRESS="hello@example.com" 56 | MAIL_FROM_NAME="${APP_NAME}" 57 | 58 | AWS_ACCESS_KEY_ID= 59 | AWS_SECRET_ACCESS_KEY= 60 | AWS_DEFAULT_REGION=us-east-1 61 | AWS_BUCKET= 62 | AWS_USE_PATH_STYLE_ENDPOINT=false 63 | 64 | VITE_APP_NAME="${APP_NAME}" 65 | -------------------------------------------------------------------------------- /.envTest: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY=base64:HR/Pyyk0vw+/FzFc5uL7LAOPS63Wug6Vq4zGceJ6Tuw= 4 | APP_DEBUG=true 5 | APP_TIMEZONE=UTC 6 | APP_URL=http://template2024.test 7 | 8 | APP_LOCALE=en 9 | APP_FALLBACK_LOCALE=en 10 | APP_FAKER_LOCALE=en_US 11 | 12 | APP_MAINTENANCE_DRIVER=file 13 | # APP_MAINTENANCE_STORE=database 14 | 15 | BCRYPT_ROUNDS=12 16 | 17 | LOG_CHANNEL=stack 18 | LOG_STACK=single 19 | LOG_DEPRECATIONS_CHANNEL=null 20 | LOG_LEVEL=debug 21 | 22 | DB_CONNECTION=sqlite 23 | # DB_HOST=127.0.0.1 24 | # DB_PORT=3306 25 | # DB_DATABASE=laravel 26 | # DB_USERNAME=root 27 | # DB_PASSWORD= 28 | 29 | SESSION_DRIVER=database 30 | SESSION_LIFETIME=120 31 | SESSION_ENCRYPT=false 32 | SESSION_PATH=/ 33 | SESSION_DOMAIN=null 34 | 35 | BROADCAST_CONNECTION=log 36 | FILESYSTEM_DISK=local 37 | QUEUE_CONNECTION=database 38 | 39 | CACHE_STORE=database 40 | CACHE_PREFIX= 41 | 42 | MEMCACHED_HOST=127.0.0.1 43 | 44 | REDIS_CLIENT=phpredis 45 | REDIS_HOST=127.0.0.1 46 | REDIS_PASSWORD=null 47 | REDIS_PORT=6379 48 | 49 | MAIL_MAILER=log 50 | MAIL_HOST=127.0.0.1 51 | MAIL_PORT=2525 52 | MAIL_USERNAME=null 53 | MAIL_PASSWORD=null 54 | MAIL_ENCRYPTION=null 55 | MAIL_FROM_ADDRESS="hello@example.com" 56 | MAIL_FROM_NAME="${APP_NAME}" 57 | 58 | AWS_ACCESS_KEY_ID= 59 | AWS_SECRET_ACCESS_KEY= 60 | AWS_DEFAULT_REGION=us-east-1 61 | AWS_BUCKET= 62 | AWS_USE_PATH_STYLE_ENDPOINT=false 63 | 64 | VITE_APP_NAME="${APP_NAME}" 65 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.blade.php diff=html 4 | *.css diff=css 5 | *.html diff=html 6 | *.md diff=markdown 7 | *.php diff=php 8 | 9 | /.github export-ignore 10 | CHANGELOG.md export-ignore 11 | .styleci.yml export-ignore 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public/build 4 | /public/hot 5 | /public/storage 6 | /storage/*.key 7 | /vendor 8 | .env 9 | .env.backup 10 | .env.production 11 | .phpactor.json 12 | .phpunit.result.cache 13 | Homestead.json 14 | Homestead.yaml 15 | auth.json 16 | npm-debug.log 17 | yarn-error.log 18 | /.fleet 19 | /.idea 20 | /.vscode 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Template 2024 2 | Template que añade las siguientes características: 3 | - Livewire 4 | - Tailwind 5 | - Volt 6 | - Auth 7 | - Tests 8 | - Plantilla DeevDojo Genesis 9 | - Paquete de autenticación de DevDojo (Permite personalizar la autenticación) 10 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/EmailVerificationController.php: -------------------------------------------------------------------------------- 1 | getKey())) { 16 | throw new AuthorizationException(); 17 | } 18 | 19 | if (! hash_equals((string) $hash, sha1(Auth::user()->getEmailForVerification()))) { 20 | throw new AuthorizationException(); 21 | } 22 | 23 | if (Auth::user()->hasVerifiedEmail()) { 24 | return redirect()->route('home'); 25 | } 26 | 27 | if (Auth::user()->markEmailAsVerified()) { 28 | event(new Verified(Auth::user())); 29 | } 30 | 31 | return redirect()->route('home'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/LogoutController.php: -------------------------------------------------------------------------------- 1 | route('home'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/VerifyEmailController.php: -------------------------------------------------------------------------------- 1 | user()->hasVerifiedEmail()) { 18 | return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); 19 | } 20 | 21 | if ($request->user()->markEmailAsVerified()) { 22 | event(new Verified($request->user())); 23 | } 24 | 25 | return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | route('dashboard'); 21 | } 22 | 23 | return $next($request); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/Livewire/Actions/Logout.php: -------------------------------------------------------------------------------- 1 | logout(); 16 | 17 | Session::invalidate(); 18 | Session::regenerateToken(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Livewire/Forms/LoginForm.php: -------------------------------------------------------------------------------- 1 | ensureIsNotRateLimited(); 32 | 33 | if (! Auth::attempt($this->only(['email', 'password']), $this->remember)) { 34 | RateLimiter::hit($this->throttleKey()); 35 | 36 | throw ValidationException::withMessages([ 37 | 'form.email' => trans('auth.failed'), 38 | ]); 39 | } 40 | 41 | RateLimiter::clear($this->throttleKey()); 42 | } 43 | 44 | /** 45 | * Ensure the authentication request is not rate limited. 46 | */ 47 | protected function ensureIsNotRateLimited(): void 48 | { 49 | if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { 50 | return; 51 | } 52 | 53 | event(new Lockout(request())); 54 | 55 | $seconds = RateLimiter::availableIn($this->throttleKey()); 56 | 57 | throw ValidationException::withMessages([ 58 | 'form.email' => trans('auth.throttle', [ 59 | 'seconds' => $seconds, 60 | 'minutes' => ceil($seconds / 60), 61 | ]), 62 | ]); 63 | } 64 | 65 | /** 66 | * Get the authentication rate limiting throttle key. 67 | */ 68 | protected function throttleKey(): string 69 | { 70 | return Str::transliterate(Str::lower($this->email).'|'.request()->ip()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected $fillable = [ 21 | 'name', 22 | 'email', 23 | 'password', 24 | ]; 25 | 26 | /** 27 | * The attributes that should be hidden for serialization. 28 | * 29 | * @var array 30 | */ 31 | protected $hidden = [ 32 | 'password', 33 | 'remember_token', 34 | ]; 35 | 36 | /** 37 | * Get the attributes that should be cast. 38 | * 39 | * @return array 40 | */ 41 | protected function casts(): array 42 | { 43 | return [ 44 | 'email_verified_at' => 'datetime', 45 | 'password' => 'hashed', 46 | ]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | middleware([ 24 | '*' => [ 25 | // 26 | ], 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Providers/VoltServiceProvider.php: -------------------------------------------------------------------------------- 1 | handleCommand(new ArgvInput); 14 | 15 | exit($status); 16 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | withRouting( 9 | web: __DIR__.'/../routes/web.php', 10 | commands: __DIR__.'/../routes/console.php', 11 | health: '/up', 12 | ) 13 | ->withMiddleware(function (Middleware $middleware) { 14 | $middleware->alias([ 15 | 'redirect-to-dashboard' => \App\Http\Middleware\RedirectToDashboard::class 16 | ]); 17 | // 18 | }) 19 | ->withExceptions(function (Exceptions $exceptions) { 20 | // 21 | })->create(); 22 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /bootstrap/providers.php: -------------------------------------------------------------------------------- 1 | env('APP_NAME', 'Laravel'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application Environment 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This value determines the "environment" your application is currently 24 | | running in. This may determine how you prefer to configure various 25 | | services the application utilizes. Set this in your ".env" file. 26 | | 27 | */ 28 | 29 | 'env' => env('APP_ENV', 'production'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application Debug Mode 34 | |-------------------------------------------------------------------------- 35 | | 36 | | When your application is in debug mode, detailed error messages with 37 | | stack traces will be shown on every error that occurs within your 38 | | application. If disabled, a simple generic error page is shown. 39 | | 40 | */ 41 | 42 | 'debug' => (bool) env('APP_DEBUG', false), 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application URL 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This URL is used by the console to properly generate URLs when using 50 | | the Artisan command line tool. You should set this to the root of 51 | | the application so that it's available within Artisan commands. 52 | | 53 | */ 54 | 55 | 'url' => env('APP_URL', 'http://localhost'), 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Application Timezone 60 | |-------------------------------------------------------------------------- 61 | | 62 | | Here you may specify the default timezone for your application, which 63 | | will be used by the PHP date and date-time functions. The timezone 64 | | is set to "UTC" by default as it is suitable for most use cases. 65 | | 66 | */ 67 | 68 | 'timezone' => env('APP_TIMEZONE', 'UTC'), 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Application Locale Configuration 73 | |-------------------------------------------------------------------------- 74 | | 75 | | The application locale determines the default locale that will be used 76 | | by Laravel's translation / localization methods. This option can be 77 | | set to any locale for which you plan to have translation strings. 78 | | 79 | */ 80 | 81 | 'locale' => env('APP_LOCALE', 'en'), 82 | 83 | 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), 84 | 85 | 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Encryption Key 90 | |-------------------------------------------------------------------------- 91 | | 92 | | This key is utilized by Laravel's encryption services and should be set 93 | | to a random, 32 character string to ensure that all encrypted values 94 | | are secure. You should do this prior to deploying the application. 95 | | 96 | */ 97 | 98 | 'cipher' => 'AES-256-CBC', 99 | 100 | 'key' => env('APP_KEY'), 101 | 102 | 'previous_keys' => [ 103 | ...array_filter( 104 | explode(',', env('APP_PREVIOUS_KEYS', '')) 105 | ), 106 | ], 107 | 108 | /* 109 | |-------------------------------------------------------------------------- 110 | | Maintenance Mode Driver 111 | |-------------------------------------------------------------------------- 112 | | 113 | | These configuration options determine the driver used to determine and 114 | | manage Laravel's "maintenance mode" status. The "cache" driver will 115 | | allow maintenance mode to be controlled across multiple machines. 116 | | 117 | | Supported drivers: "file", "cache" 118 | | 119 | */ 120 | 121 | 'maintenance' => [ 122 | 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), 123 | 'store' => env('APP_MAINTENANCE_STORE', 'database'), 124 | ], 125 | 126 | ]; 127 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => env('AUTH_GUARD', 'web'), 18 | 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | which utilizes session storage plus the Eloquent user provider. 29 | | 30 | | All authentication guards have a user provider, which defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | system used by the application. Typically, Eloquent is utilized. 33 | | 34 | | Supported: "session" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | ], 44 | 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | User Providers 48 | |-------------------------------------------------------------------------- 49 | | 50 | | All authentication guards have a user provider, which defines how the 51 | | users are actually retrieved out of your database or other storage 52 | | system used by the application. Typically, Eloquent is utilized. 53 | | 54 | | If you have multiple user tables or models you may configure multiple 55 | | providers to represent the model / table. These providers may then 56 | | be assigned to any extra authentication guards you have defined. 57 | | 58 | | Supported: "database", "eloquent" 59 | | 60 | */ 61 | 62 | 'providers' => [ 63 | 'users' => [ 64 | 'driver' => 'eloquent', 65 | 'model' => env('AUTH_MODEL', App\Models\User::class), 66 | ], 67 | 68 | // 'users' => [ 69 | // 'driver' => 'database', 70 | // 'table' => 'users', 71 | // ], 72 | ], 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Resetting Passwords 77 | |-------------------------------------------------------------------------- 78 | | 79 | | These configuration options specify the behavior of Laravel's password 80 | | reset functionality, including the table utilized for token storage 81 | | and the user provider that is invoked to actually retrieve users. 82 | | 83 | | The expiry time is the number of minutes that each reset token will be 84 | | considered valid. This security feature keeps tokens short-lived so 85 | | they have less time to be guessed. You may change this as needed. 86 | | 87 | | The throttle setting is the number of seconds a user must wait before 88 | | generating more password reset tokens. This prevents the user from 89 | | quickly generating a very large amount of password reset tokens. 90 | | 91 | */ 92 | 93 | 'passwords' => [ 94 | 'users' => [ 95 | 'provider' => 'users', 96 | 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), 97 | 'expire' => 60, 98 | 'throttle' => 60, 99 | ], 100 | ], 101 | 102 | /* 103 | |-------------------------------------------------------------------------- 104 | | Password Confirmation Timeout 105 | |-------------------------------------------------------------------------- 106 | | 107 | | Here you may define the amount of seconds before a password confirmation 108 | | window expires and users are asked to re-enter their password via the 109 | | confirmation screen. By default, the timeout lasts for three hours. 110 | | 111 | */ 112 | 113 | 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), 114 | 115 | ]; 116 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_STORE', 'database'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Cache Stores 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the cache "stores" for your application as 26 | | well as their drivers. You may even define multiple stores for the 27 | | same cache driver to group types of items stored in your caches. 28 | | 29 | | Supported drivers: "array", "database", "file", "memcached", 30 | | "redis", "dynamodb", "octane", "null" 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'array' => [ 37 | 'driver' => 'array', 38 | 'serialize' => false, 39 | ], 40 | 41 | 'database' => [ 42 | 'driver' => 'database', 43 | 'connection' => env('DB_CACHE_CONNECTION'), 44 | 'table' => env('DB_CACHE_TABLE', 'cache'), 45 | 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), 46 | 'lock_table' => env('DB_CACHE_LOCK_TABLE'), 47 | ], 48 | 49 | 'file' => [ 50 | 'driver' => 'file', 51 | 'path' => storage_path('framework/cache/data'), 52 | 'lock_path' => storage_path('framework/cache/data'), 53 | ], 54 | 55 | 'memcached' => [ 56 | 'driver' => 'memcached', 57 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 58 | 'sasl' => [ 59 | env('MEMCACHED_USERNAME'), 60 | env('MEMCACHED_PASSWORD'), 61 | ], 62 | 'options' => [ 63 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 64 | ], 65 | 'servers' => [ 66 | [ 67 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 68 | 'port' => env('MEMCACHED_PORT', 11211), 69 | 'weight' => 100, 70 | ], 71 | ], 72 | ], 73 | 74 | 'redis' => [ 75 | 'driver' => 'redis', 76 | 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), 77 | 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), 78 | ], 79 | 80 | 'dynamodb' => [ 81 | 'driver' => 'dynamodb', 82 | 'key' => env('AWS_ACCESS_KEY_ID'), 83 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 84 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 85 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 86 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 87 | ], 88 | 89 | 'octane' => [ 90 | 'driver' => 'octane', 91 | ], 92 | 93 | ], 94 | 95 | /* 96 | |-------------------------------------------------------------------------- 97 | | Cache Key Prefix 98 | |-------------------------------------------------------------------------- 99 | | 100 | | When utilizing the APC, database, memcached, Redis, and DynamoDB cache 101 | | stores, there might be other applications using the same cache. For 102 | | that reason, you may prefix every cache key to avoid collisions. 103 | | 104 | */ 105 | 106 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), 107 | 108 | ]; 109 | -------------------------------------------------------------------------------- /config/devdojo/auth/descriptions.php: -------------------------------------------------------------------------------- 1 | [ 8 | 'redirect_after_auth' => 'Where should the user be redirected to after they are authenticated?', 9 | 'registration_show_password_same_screen' => 'During registrations, show the password on the same screen or show it on an individual screen.', 10 | 'registration_include_name_field' => 'During registration, include the Name field.', 11 | 'registration_include_password_confirmation_field' => 'During registration, include the Password Confirmation field.', 12 | 'registration_require_email_verification' => 'During registration, require users to verify their email.', 13 | 'enable_branding' => 'This will toggle on/off the Auth branding at the bottom of each auth screen. Consider leaving on to support and help grow this project.', 14 | 'dev_mode' => 'This is for development mode, when set in Dev Mode Assets will be loaded from Vite', 15 | 'enable_2fa' => 'Enable the ability for users to turn on Two Factor Authentication', 16 | 'login_show_social_providers' => 'Show the social providers login buttons on the login form', 17 | 'center_align_social_provider_button_content' => 'Center align the content in the social provider button?', 18 | 'social_providers_location' => 'The location of the social provider buttons (top or bottom)', 19 | ], 20 | ]; 21 | -------------------------------------------------------------------------------- /config/devdojo/auth/language.php: -------------------------------------------------------------------------------- 1 | [ 8 | 'page_title' => 'Sign in', 9 | 'headline' => 'Sign in', 10 | 'subheadline' => 'Login to your account below', 11 | 'show_subheadline' => false, 12 | 'email_address' => 'Email Address', 13 | 'password' => 'Password', 14 | 'edit' => 'Edit', 15 | 'button' => 'Continue', 16 | 'forget_password' => 'Forget your password?', 17 | 'dont_have_an_account' => "Don't have an account?", 18 | 'sign_up' => 'Sign up', 19 | 'social_auth_authenticated_message' => 'You have been authenticated via __social_providers_list__. Please login to that network below.', 20 | 'change_email' => 'Change Email', 21 | ], 22 | 'register' => [ 23 | 'page_title' => 'Sign up', 24 | 'headline' => 'Sign up', 25 | 'subheadline' => 'Register for your free account below.', 26 | 'show_subheadline' => false, 27 | 'name' => 'Name', 28 | 'email_address' => 'Email Address', 29 | 'password' => 'Password', 30 | 'password_confirmation' => 'Confirm Password', 31 | 'already_have_an_account' => 'Already have an account?', 32 | 'sign_in' => 'Sign in', 33 | 'button' => 'Continue', 34 | ], 35 | 'verify' => [ 36 | 'page_title' => 'Verify Your Account', 37 | 'headline' => 'Verify your email address', 38 | 'subheadline' => 'Before you can proceed you must verify your email.', 39 | 'show_subheadline' => false, 40 | 'description' => 'Before proceeding, please check your email for a verification link. If you did not receive the email,', 41 | 'new_request_link' => 'click here to request another', 42 | 'new_link_sent' => 'A new link has been sent to your email address.', 43 | 'or' => 'Or', 44 | 'logout' => 'click here to logout', 45 | ], 46 | 'passwordConfirm' => [ 47 | 'page_title' => 'Confirm Your Password', 48 | 'headline' => 'Confirm Password', 49 | 'subheadline' => 'Be sure to confirm your password below', 50 | 'show_subheadline' => false, 51 | 'password' => 'Password', 52 | 'button' => 'Confirm password', 53 | ], 54 | 'passwordResetRequest' => [ 55 | 'page_title' => 'Request a Password Reset', 56 | 'headline' => 'Reset password', 57 | 'subheadline' => 'Enter your email below to reset your password', 58 | 'show_subheadline' => false, 59 | 'email' => 'Email Address', 60 | 'button' => 'Send password reset link', 61 | 'or' => 'or', 62 | 'return_to_login' => 'return to login', 63 | ], 64 | 'passwordReset' => [ 65 | 'page_title' => 'Reset Your Password', 66 | 'headline' => 'Reset Password', 67 | 'subheadline' => 'Reset your password below', 68 | 'show_subheadline' => false, 69 | 'email' => 'Email Address', 70 | 'password' => 'Password', 71 | 'password_confirm' => 'Confirm Password', 72 | 'button' => 'Reset Password', 73 | ], 74 | 'twoFactorChallenge' => [ 75 | 'page_title' => 'Two Factor Challenge', 76 | 'headline_auth' => 'Authentication Code', 77 | 'subheadline_auth' => 'Enter the authentication code provided by your authenticator application.', 78 | 'show_subheadline_auth' => false, 79 | 'headline_recovery' => 'Recovery Code', 80 | 'subheadline_recovery' => 'Please confirm access to your account by entering one of your emergency recovery codes.', 81 | 'show_subheadline_recovery' => false, 82 | ], 83 | 84 | ]; 85 | -------------------------------------------------------------------------------- /config/devdojo/auth/settings.php: -------------------------------------------------------------------------------- 1 | '/', 8 | 'registration_show_password_same_screen' => true, 9 | 'registration_include_name_field' => true, 10 | 'registration_include_password_confirmation_field' => false, 11 | 'registration_require_email_verification' => false, 12 | 'enable_branding' => true, 13 | 'dev_mode' => false, 14 | 'enable_2fa' => false, // Enable or disable 2FA functionality globally 15 | 'login_show_social_providers' => true, 16 | 'center_align_social_provider_button_content' => true, 17 | 'social_providers_location' => 'bottom', 18 | ]; 19 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DISK', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Filesystem Disks 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Below you may configure as many filesystem disks as necessary, and you 24 | | may even configure multiple disks for the same driver. Examples for 25 | | most supported storage drivers are configured here for reference. 26 | | 27 | | Supported drivers: "local", "ftp", "sftp", "s3" 28 | | 29 | */ 30 | 31 | 'disks' => [ 32 | 33 | 'local' => [ 34 | 'driver' => 'local', 35 | 'root' => storage_path('app'), 36 | 'throw' => false, 37 | ], 38 | 39 | 'public' => [ 40 | 'driver' => 'local', 41 | 'root' => storage_path('app/public'), 42 | 'url' => env('APP_URL').'/storage', 43 | 'visibility' => 'public', 44 | 'throw' => false, 45 | ], 46 | 47 | 's3' => [ 48 | 'driver' => 's3', 49 | 'key' => env('AWS_ACCESS_KEY_ID'), 50 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 51 | 'region' => env('AWS_DEFAULT_REGION'), 52 | 'bucket' => env('AWS_BUCKET'), 53 | 'url' => env('AWS_URL'), 54 | 'endpoint' => env('AWS_ENDPOINT'), 55 | 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 56 | 'throw' => false, 57 | ], 58 | 59 | ], 60 | 61 | /* 62 | |-------------------------------------------------------------------------- 63 | | Symbolic Links 64 | |-------------------------------------------------------------------------- 65 | | 66 | | Here you may configure the symbolic links that will be created when the 67 | | `storage:link` Artisan command is executed. The array keys should be 68 | | the locations of the links and the values should be their targets. 69 | | 70 | */ 71 | 72 | 'links' => [ 73 | public_path('storage') => storage_path('app/public'), 74 | ], 75 | 76 | ]; 77 | -------------------------------------------------------------------------------- /config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Deprecations Log Channel 26 | |-------------------------------------------------------------------------- 27 | | 28 | | This option controls the log channel that should be used to log warnings 29 | | regarding deprecated PHP and library features. This allows you to get 30 | | your application ready for upcoming major versions of dependencies. 31 | | 32 | */ 33 | 34 | 'deprecations' => [ 35 | 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 36 | 'trace' => env('LOG_DEPRECATIONS_TRACE', false), 37 | ], 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Log Channels 42 | |-------------------------------------------------------------------------- 43 | | 44 | | Here you may configure the log channels for your application. Laravel 45 | | utilizes the Monolog PHP logging library, which includes a variety 46 | | of powerful log handlers and formatters that you're free to use. 47 | | 48 | | Available drivers: "single", "daily", "slack", "syslog", 49 | | "errorlog", "monolog", "custom", "stack" 50 | | 51 | */ 52 | 53 | 'channels' => [ 54 | 55 | 'stack' => [ 56 | 'driver' => 'stack', 57 | 'channels' => explode(',', env('LOG_STACK', 'single')), 58 | 'ignore_exceptions' => false, 59 | ], 60 | 61 | 'single' => [ 62 | 'driver' => 'single', 63 | 'path' => storage_path('logs/laravel.log'), 64 | 'level' => env('LOG_LEVEL', 'debug'), 65 | 'replace_placeholders' => true, 66 | ], 67 | 68 | 'daily' => [ 69 | 'driver' => 'daily', 70 | 'path' => storage_path('logs/laravel.log'), 71 | 'level' => env('LOG_LEVEL', 'debug'), 72 | 'days' => env('LOG_DAILY_DAYS', 14), 73 | 'replace_placeholders' => true, 74 | ], 75 | 76 | 'slack' => [ 77 | 'driver' => 'slack', 78 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 79 | 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), 80 | 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), 81 | 'level' => env('LOG_LEVEL', 'critical'), 82 | 'replace_placeholders' => true, 83 | ], 84 | 85 | 'papertrail' => [ 86 | 'driver' => 'monolog', 87 | 'level' => env('LOG_LEVEL', 'debug'), 88 | 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), 89 | 'handler_with' => [ 90 | 'host' => env('PAPERTRAIL_URL'), 91 | 'port' => env('PAPERTRAIL_PORT'), 92 | 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), 93 | ], 94 | 'processors' => [PsrLogMessageProcessor::class], 95 | ], 96 | 97 | 'stderr' => [ 98 | 'driver' => 'monolog', 99 | 'level' => env('LOG_LEVEL', 'debug'), 100 | 'handler' => StreamHandler::class, 101 | 'formatter' => env('LOG_STDERR_FORMATTER'), 102 | 'with' => [ 103 | 'stream' => 'php://stderr', 104 | ], 105 | 'processors' => [PsrLogMessageProcessor::class], 106 | ], 107 | 108 | 'syslog' => [ 109 | 'driver' => 'syslog', 110 | 'level' => env('LOG_LEVEL', 'debug'), 111 | 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), 112 | 'replace_placeholders' => true, 113 | ], 114 | 115 | 'errorlog' => [ 116 | 'driver' => 'errorlog', 117 | 'level' => env('LOG_LEVEL', 'debug'), 118 | 'replace_placeholders' => true, 119 | ], 120 | 121 | 'null' => [ 122 | 'driver' => 'monolog', 123 | 'handler' => NullHandler::class, 124 | ], 125 | 126 | 'emergency' => [ 127 | 'path' => storage_path('logs/laravel.log'), 128 | ], 129 | 130 | ], 131 | 132 | ]; 133 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'log'), 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Mailer Configurations 22 | |-------------------------------------------------------------------------- 23 | | 24 | | Here you may configure all of the mailers used by your application plus 25 | | their respective settings. Several examples have been configured for 26 | | you and you are free to add your own as your application requires. 27 | | 28 | | Laravel supports a variety of mail "transport" drivers that can be used 29 | | when delivering an email. You may specify which one you're using for 30 | | your mailers below. You may also add additional mailers if needed. 31 | | 32 | | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", 33 | | "postmark", "resend", "log", "array", 34 | | "failover", "roundrobin" 35 | | 36 | */ 37 | 38 | 'mailers' => [ 39 | 40 | 'smtp' => [ 41 | 'transport' => 'smtp', 42 | 'url' => env('MAIL_URL'), 43 | 'host' => env('MAIL_HOST', '127.0.0.1'), 44 | 'port' => env('MAIL_PORT', 2525), 45 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 46 | 'username' => env('MAIL_USERNAME'), 47 | 'password' => env('MAIL_PASSWORD'), 48 | 'timeout' => null, 49 | 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), 50 | ], 51 | 52 | 'ses' => [ 53 | 'transport' => 'ses', 54 | ], 55 | 56 | 'postmark' => [ 57 | 'transport' => 'postmark', 58 | // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), 59 | // 'client' => [ 60 | // 'timeout' => 5, 61 | // ], 62 | ], 63 | 64 | 'resend' => [ 65 | 'transport' => 'resend', 66 | ], 67 | 68 | 'sendmail' => [ 69 | 'transport' => 'sendmail', 70 | 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), 71 | ], 72 | 73 | 'log' => [ 74 | 'transport' => 'log', 75 | 'channel' => env('MAIL_LOG_CHANNEL'), 76 | ], 77 | 78 | 'array' => [ 79 | 'transport' => 'array', 80 | ], 81 | 82 | 'failover' => [ 83 | 'transport' => 'failover', 84 | 'mailers' => [ 85 | 'smtp', 86 | 'log', 87 | ], 88 | ], 89 | 90 | 'roundrobin' => [ 91 | 'transport' => 'roundrobin', 92 | 'mailers' => [ 93 | 'ses', 94 | 'postmark', 95 | ], 96 | ], 97 | 98 | ], 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Global "From" Address 103 | |-------------------------------------------------------------------------- 104 | | 105 | | You may wish for all emails sent by your application to be sent from 106 | | the same address. Here you may specify a name and address that is 107 | | used globally for all emails that are sent by your application. 108 | | 109 | */ 110 | 111 | 'from' => [ 112 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 113 | 'name' => env('MAIL_FROM_NAME', 'Example'), 114 | ], 115 | 116 | ]; 117 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'database'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection options for every queue backend 24 | | used by your application. An example configuration is provided for 25 | | each backend supported by Laravel. You're also free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'connection' => env('DB_QUEUE_CONNECTION'), 40 | 'table' => env('DB_QUEUE_TABLE', 'jobs'), 41 | 'queue' => env('DB_QUEUE', 'default'), 42 | 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), 43 | 'after_commit' => false, 44 | ], 45 | 46 | 'beanstalkd' => [ 47 | 'driver' => 'beanstalkd', 48 | 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), 49 | 'queue' => env('BEANSTALKD_QUEUE', 'default'), 50 | 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), 51 | 'block_for' => 0, 52 | 'after_commit' => false, 53 | ], 54 | 55 | 'sqs' => [ 56 | 'driver' => 'sqs', 57 | 'key' => env('AWS_ACCESS_KEY_ID'), 58 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 59 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 60 | 'queue' => env('SQS_QUEUE', 'default'), 61 | 'suffix' => env('SQS_SUFFIX'), 62 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 63 | 'after_commit' => false, 64 | ], 65 | 66 | 'redis' => [ 67 | 'driver' => 'redis', 68 | 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), 69 | 'queue' => env('REDIS_QUEUE', 'default'), 70 | 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), 71 | 'block_for' => null, 72 | 'after_commit' => false, 73 | ], 74 | 75 | ], 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Job Batching 80 | |-------------------------------------------------------------------------- 81 | | 82 | | The following options configure the database and table that store job 83 | | batching information. These options can be updated to any database 84 | | connection and table which has been defined by your application. 85 | | 86 | */ 87 | 88 | 'batching' => [ 89 | 'database' => env('DB_CONNECTION', 'sqlite'), 90 | 'table' => 'job_batches', 91 | ], 92 | 93 | /* 94 | |-------------------------------------------------------------------------- 95 | | Failed Queue Jobs 96 | |-------------------------------------------------------------------------- 97 | | 98 | | These options configure the behavior of failed queue job logging so you 99 | | can control how and where failed jobs are stored. Laravel ships with 100 | | support for storing failed jobs in a simple file or in a database. 101 | | 102 | | Supported drivers: "database-uuids", "dynamodb", "file", "null" 103 | | 104 | */ 105 | 106 | 'failed' => [ 107 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), 108 | 'database' => env('DB_CONNECTION', 'sqlite'), 109 | 'table' => 'failed_jobs', 110 | ], 111 | 112 | ]; 113 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'token' => env('POSTMARK_TOKEN'), 19 | ], 20 | 21 | 'ses' => [ 22 | 'key' => env('AWS_ACCESS_KEY_ID'), 23 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 24 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 25 | ], 26 | 27 | 'resend' => [ 28 | 'key' => env('RESEND_KEY'), 29 | ], 30 | 31 | 'slack' => [ 32 | 'notifications' => [ 33 | 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), 34 | 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), 35 | ], 36 | ], 37 | 38 | ]; 39 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class UserFactory extends Factory 13 | { 14 | /** 15 | * The current password being used by the factory. 16 | */ 17 | protected static ?string $password; 18 | 19 | /** 20 | * Define the model's default state. 21 | * 22 | * @return array 23 | */ 24 | public function definition(): array 25 | { 26 | return [ 27 | 'name' => fake()->name(), 28 | 'email' => fake()->unique()->safeEmail(), 29 | 'email_verified_at' => now(), 30 | 'password' => static::$password ??= Hash::make('password'), 31 | 'remember_token' => Str::random(10), 32 | ]; 33 | } 34 | 35 | /** 36 | * Indicate that the model's email address should be unverified. 37 | */ 38 | public function unverified(): static 39 | { 40 | return $this->state(fn (array $attributes) => [ 41 | 'email_verified_at' => null, 42 | ]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /database/migrations/0001_01_01_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('name'); 17 | $table->string('email')->unique(); 18 | $table->timestamp('email_verified_at')->nullable(); 19 | $table->string('password'); 20 | $table->rememberToken(); 21 | $table->timestamps(); 22 | }); 23 | 24 | Schema::create('password_reset_tokens', function (Blueprint $table) { 25 | $table->string('email')->primary(); 26 | $table->string('token'); 27 | $table->timestamp('created_at')->nullable(); 28 | }); 29 | 30 | Schema::create('sessions', function (Blueprint $table) { 31 | $table->string('id')->primary(); 32 | $table->foreignId('user_id')->nullable()->index(); 33 | $table->string('ip_address', 45)->nullable(); 34 | $table->text('user_agent')->nullable(); 35 | $table->longText('payload'); 36 | $table->integer('last_activity')->index(); 37 | }); 38 | } 39 | 40 | /** 41 | * Reverse the migrations. 42 | */ 43 | public function down(): void 44 | { 45 | Schema::dropIfExists('users'); 46 | Schema::dropIfExists('password_reset_tokens'); 47 | Schema::dropIfExists('sessions'); 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /database/migrations/0001_01_01_000001_create_cache_table.php: -------------------------------------------------------------------------------- 1 | string('key')->primary(); 16 | $table->mediumText('value'); 17 | $table->integer('expiration'); 18 | }); 19 | 20 | Schema::create('cache_locks', function (Blueprint $table) { 21 | $table->string('key')->primary(); 22 | $table->string('owner'); 23 | $table->integer('expiration'); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | */ 30 | public function down(): void 31 | { 32 | Schema::dropIfExists('cache'); 33 | Schema::dropIfExists('cache_locks'); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /database/migrations/0001_01_01_000002_create_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('queue')->index(); 17 | $table->longText('payload'); 18 | $table->unsignedTinyInteger('attempts'); 19 | $table->unsignedInteger('reserved_at')->nullable(); 20 | $table->unsignedInteger('available_at'); 21 | $table->unsignedInteger('created_at'); 22 | }); 23 | 24 | Schema::create('job_batches', function (Blueprint $table) { 25 | $table->string('id')->primary(); 26 | $table->string('name'); 27 | $table->integer('total_jobs'); 28 | $table->integer('pending_jobs'); 29 | $table->integer('failed_jobs'); 30 | $table->longText('failed_job_ids'); 31 | $table->mediumText('options')->nullable(); 32 | $table->integer('cancelled_at')->nullable(); 33 | $table->integer('created_at'); 34 | $table->integer('finished_at')->nullable(); 35 | }); 36 | 37 | Schema::create('failed_jobs', function (Blueprint $table) { 38 | $table->id(); 39 | $table->string('uuid')->unique(); 40 | $table->text('connection'); 41 | $table->text('queue'); 42 | $table->longText('payload'); 43 | $table->longText('exception'); 44 | $table->timestamp('failed_at')->useCurrent(); 45 | }); 46 | } 47 | 48 | /** 49 | * Reverse the migrations. 50 | */ 51 | public function down(): void 52 | { 53 | Schema::dropIfExists('jobs'); 54 | Schema::dropIfExists('job_batches'); 55 | Schema::dropIfExists('failed_jobs'); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /database/migrations/2024_04_24_000001_add_user_social_provider_table.php: -------------------------------------------------------------------------------- 1 | foreignId('user_id')->constrained()->onDelete('cascade'); 16 | $table->string('provider_slug'); // maps to providers slug in the devdojo.auth.providers 17 | 18 | $table->string('provider_user_id'); 19 | $table->string('nickname')->nullable(); 20 | $table->string('name')->nullable(); 21 | $table->string('email')->nullable(); 22 | $table->string('avatar')->nullable(); 23 | $table->text('provider_data')->nullable(); // JSON data containing additional provider data we want to include 24 | 25 | $table->string('token'); 26 | $table->string('refresh_token')->nullable(); 27 | $table->timestamp('token_expires_at')->nullable(); 28 | $table->timestamps(); 29 | 30 | $table->primary(['user_id', 'provider_slug']); 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | */ 37 | public function down(): void 38 | { 39 | Schema::dropIfExists('social_provider_user'); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /database/migrations/2024_04_24_000002_update_passwords_field_to_be_nullable.php: -------------------------------------------------------------------------------- 1 | string('password')->nullable()->change(); 17 | $table->string('name')->nullable()->change(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down() 25 | { 26 | // Update records with NULL values to avoid constraint violations 27 | DB::table('users')->whereNull('name')->update(['name' => '']); 28 | DB::table('users')->whereNull('password')->update(['password' => '']); 29 | 30 | // Change the table structure 31 | Schema::table('users', function (Blueprint $table) { 32 | $table->string('name')->nullable(false)->change(); 33 | $table->string('password')->nullable(false)->change(); 34 | }); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /database/migrations/2024_05_07_000003_add_two_factor_auth_columns.php: -------------------------------------------------------------------------------- 1 | text('two_factor_secret') 18 | ->after('password') 19 | ->nullable(); 20 | } 21 | 22 | if (! Schema::hasColumn('users', 'two_factor_recovery_codes')) { 23 | $table->text('two_factor_recovery_codes') 24 | ->after('two_factor_secret') 25 | ->nullable(); 26 | } 27 | 28 | if (! Schema::hasColumn('users', 'two_factor_confirmed_at')) { 29 | $table->timestamp('two_factor_confirmed_at') 30 | ->after('two_factor_recovery_codes') 31 | ->nullable(); 32 | } 33 | 34 | }); 35 | } 36 | 37 | /** 38 | * Reverse the migrations. 39 | */ 40 | public function down(): void 41 | { 42 | Schema::table('users', function (Blueprint $table) { 43 | $table->dropColumn([ 44 | 'two_factor_secret', 45 | 'two_factor_recovery_codes', 46 | 'two_factor_confirmed_at', 47 | ]); 48 | }); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 17 | 18 | User::factory()->create([ 19 | 'name' => 'Test User', 20 | 'email' => 'test@example.com', 21 | ]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "type": "module", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vite build" 7 | }, 8 | "devDependencies": { 9 | "@tailwindcss/forms": "^0.5.2", 10 | "@tailwindcss/typography": "^0.5.9", 11 | "alpinejs": "^3.12.3", 12 | "autoprefixer": "^10.4.2", 13 | "laravel-vite-plugin": "^1.0", 14 | "postcss": "^8.4.31", 15 | "tailwindcss": "^3.1.0", 16 | "vite": "^5.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | tests/Unit 10 | 11 | 12 | tests/Feature 13 | 14 | 15 | 16 | 17 | app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/assets/audio/dark.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/public/assets/audio/dark.mp3 -------------------------------------------------------------------------------- /public/assets/audio/light.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/public/assets/audio/light.mp3 -------------------------------------------------------------------------------- /public/auth/app.css: -------------------------------------------------------------------------------- 1 | #auth-body{ 2 | opacity:80; 3 | } 4 | 5 | #auth-container{ 6 | border:0px !important; 7 | } 8 | 9 | #auth-heading-container{ 10 | padding-left:5px; 11 | } -------------------------------------------------------------------------------- /public/auth/build/assets/scripts.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/auth/build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources/css/auth.css": { 3 | "file": "assets/styles.css", 4 | "src": "resources/css/auth.css", 5 | "isEntry": true 6 | }, 7 | "resources/js/auth.js": { 8 | "file": "assets/scripts.js", 9 | "name": "scripts", 10 | "src": "resources/js/auth.js", 11 | "isEntry": true 12 | } 13 | } -------------------------------------------------------------------------------- /public/auth/img/favicon-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/public/auth/img/favicon-dark.png -------------------------------------------------------------------------------- /public/auth/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/public/auth/img/favicon.ico -------------------------------------------------------------------------------- /public/auth/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/public/auth/img/favicon.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/public/favicon.ico -------------------------------------------------------------------------------- /public/genesis/power-ups.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "thedevdojo\/blog": true 4 | } 5 | ] -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | handleRequest(Request::capture()); 18 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /resources/css/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | [x-cloak] { 6 | display: none; 7 | } -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/resources/js/app.js -------------------------------------------------------------------------------- /resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | window.axios = axios; 3 | 4 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 5 | -------------------------------------------------------------------------------- /resources/views/components/action-message.blade.php: -------------------------------------------------------------------------------- 1 | @props(['on']) 2 | 3 |
merge(['class' => 'text-sm text-gray-600 dark:text-gray-400']) }}> 9 | {{ $slot->isEmpty() ? 'Saved.' : $slot }} 10 |
11 | -------------------------------------------------------------------------------- /resources/views/components/application-logo.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/components/auth-session-status.blade.php: -------------------------------------------------------------------------------- 1 | @props(['status']) 2 | 3 | @if ($status) 4 |
merge(['class' => 'font-medium text-sm text-green-600 dark:text-green-400']) }}> 5 | {{ $status }} 6 |
7 | @endif 8 | -------------------------------------------------------------------------------- /resources/views/components/danger-button.blade.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /resources/views/components/dropdown-link.blade.php: -------------------------------------------------------------------------------- 1 | merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out']) }}>{{ $slot }} 2 | -------------------------------------------------------------------------------- /resources/views/components/dropdown.blade.php: -------------------------------------------------------------------------------- 1 | @props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-gray-700']) 2 | 3 | @php 4 | $alignmentClasses = match ($align) { 5 | 'left' => 'ltr:origin-top-left rtl:origin-top-right start-0', 6 | 'top' => 'origin-top', 7 | default => 'ltr:origin-top-right rtl:origin-top-left end-0', 8 | }; 9 | 10 | $width = match ($width) { 11 | '48' => 'w-48', 12 | default => $width, 13 | }; 14 | @endphp 15 | 16 |
17 |
18 | {{ $trigger }} 19 |
20 | 21 | 35 |
36 | -------------------------------------------------------------------------------- /resources/views/components/input-error.blade.php: -------------------------------------------------------------------------------- 1 | @props(['messages']) 2 | 3 | @if ($messages) 4 |
    merge(['class' => 'text-sm text-red-600 dark:text-red-400 space-y-1']) }}> 5 | @foreach ((array) $messages as $message) 6 |
  • {{ $message }}
  • 7 | @endforeach 8 |
9 | @endif 10 | -------------------------------------------------------------------------------- /resources/views/components/input-label.blade.php: -------------------------------------------------------------------------------- 1 | @props(['value']) 2 | 3 | 6 | -------------------------------------------------------------------------------- /resources/views/components/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @if (isset($header)) 7 |
8 |
9 | {{ $header }} 10 |
11 |
12 | @endif 13 | 14 |
15 |
16 | {{ $slot }} 17 |
18 |
19 | 20 |
-------------------------------------------------------------------------------- /resources/views/components/layouts/main.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | @vite(['resources/css/app.css', 'resources/js/app.js']) 18 | 19 | {{ $title ?? 'Genesis' }} 20 | 21 | 22 | {{ $slot }} 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /resources/views/components/layouts/marketing.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ $slot }} 6 | 7 | -------------------------------------------------------------------------------- /resources/views/components/modal.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'name', 3 | 'show' => false, 4 | 'maxWidth' => '2xl' 5 | ]) 6 | 7 | @php 8 | $maxWidth = [ 9 | 'sm' => 'sm:max-w-sm', 10 | 'md' => 'sm:max-w-md', 11 | 'lg' => 'sm:max-w-lg', 12 | 'xl' => 'sm:max-w-xl', 13 | '2xl' => 'sm:max-w-2xl', 14 | ][$maxWidth]; 15 | @endphp 16 | 17 |
52 |
63 |
64 |
65 | 66 |
76 | {{ $slot }} 77 |
78 |
79 | -------------------------------------------------------------------------------- /resources/views/components/nav-link.blade.php: -------------------------------------------------------------------------------- 1 | @props(['active']) 2 | 3 | @php 4 | $classes = ($active ?? false) 5 | ? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 dark:border-indigo-600 text-sm font-medium leading-5 text-gray-900 dark:text-gray-100 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out' 6 | : 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out'; 7 | @endphp 8 | 9 | merge(['class' => $classes]) }}> 10 | {{ $slot }} 11 | 12 | -------------------------------------------------------------------------------- /resources/views/components/primary-button.blade.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /resources/views/components/responsive-nav-link.blade.php: -------------------------------------------------------------------------------- 1 | @props(['active']) 2 | 3 | @php 4 | $classes = ($active ?? false) 5 | ? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 dark:border-indigo-600 text-start text-base font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:outline-none focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300 transition duration-150 ease-in-out' 6 | : 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-gray-800 dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out'; 7 | @endphp 8 | 9 | merge(['class' => $classes]) }}> 10 | {{ $slot }} 11 | 12 | -------------------------------------------------------------------------------- /resources/views/components/secondary-button.blade.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /resources/views/components/text-input.blade.php: -------------------------------------------------------------------------------- 1 | @props(['disabled' => false]) 2 | 3 | merge(['class' => 'border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm']) !!}> 4 | -------------------------------------------------------------------------------- /resources/views/components/ui/badge.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'background' => 'bg-blue-600', 3 | 'color' => 'text-white' 4 | ]) 5 | 6 | 7 | {{ $slot }} 8 | -------------------------------------------------------------------------------- /resources/views/components/ui/button.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'type' => 'primary', 3 | 'size' => 'md', 4 | 'tag' => 'button', 5 | 'href' => '/', 6 | 'submit' => false, 7 | 'rounded' => 'full' 8 | ]) 9 | 10 | @php 11 | $sizeClasses = match ($size) { 12 | 'sm' => 'px-2.5 py-1.5 text-xs font-medium rounded-' . $rounded, 13 | 'md' => 'px-4 py-2 text-sm font-medium rounded-' . $rounded, 14 | 'lg' => 'px-5 py-3 text-sm font-medium rounded-' . $rounded, 15 | 'xl' => 'px-6 py-3.5 text-base font-medium rounded-' . $rounded, 16 | '2xl' => 'px-7 py-4 text-base font-medium rounded-' . $rounded 17 | }; 18 | @endphp 19 | 20 | @php 21 | $typeClasses = match ($type) { 22 | 'primary' => 'bg-gray-800 dark:bg-gray-100 text-white dark:text-gray-700 hover:bg-gray-900 dark:focus:ring-offset-gray-900 dark:focus:ring-gray-100 dark:hover:bg-white dark:hover:text-gray-800 focus:ring-2 focus:ring-gray-900 focus:ring-offset-2', 23 | 'secondary' => 'bg-white border text-gray-500 hover:text-gray-700 border-gray-200/70 dark:focus:ring-offset-gray-900 dark:border-gray-400/10 hover:bg-gray-50 active:bg-white dark:focus:ring-gray-700 focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-200/60 dark:bg-gray-800/50 dark:hover:bg-gray-800/70 dark:text-gray-400 focus:shadow-outline', 24 | 'success' => 'bg-green-600 text-white hover:bg-green-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-green-700/90 focus:ring-green-700', 25 | 'info' => 'bg-blue-600 text-white hover:bg-blue-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-blue-700/90 focus:ring-blue-700', 26 | 'warning' => 'bg-amber-500 text-white hover:bg-amber-500/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-amber-600/90 focus:ring-amber-600', 27 | 'danger' => 'bg-red-600 text-white hover:bg-red-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-red-700/90 focus:ring-red-700', 28 | }; 29 | @endphp 30 | 31 | @php 32 | switch ($tag ?? 'button') { 33 | case 'button': 34 | $tagAttr = ($submit) ? 'button type="submit"' : 'button type="button"'; 35 | $tagClose = 'button'; 36 | break; 37 | case 'a': 38 | $link = $href ?? ''; 39 | $tagAttr = 'a href="' . $link . '"'; 40 | $tagClose = 'a'; 41 | break; 42 | default: 43 | $tagAttr = 'button type="button"'; 44 | $tagClose = 'button'; 45 | break; 46 | } 47 | @endphp 48 | 49 | <{!! $tagAttr !!} {!! $attributes->except(['class']) !!} class="{{ $sizeClasses }} {{ $typeClasses }} cursor-pointer inline-flex items-center w-full justify-center disabled:opacity-50 font-semibold focus:outline-none"> 50 | {{ $slot }} 51 | -------------------------------------------------------------------------------- /resources/views/components/ui/checkbox.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'name' => null, 4 | 'id' => null, 5 | ]) 6 | 7 |
8 | whereStartsWith('wire:model') }} id="{{ $id ?? '' }}" name="{{ $name ?? '' }}" class="hidden peer"> 9 | 17 |
-------------------------------------------------------------------------------- /resources/views/components/ui/input.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'id' => null, 4 | 'name' => null, 5 | 'type' => 'text', 6 | ]) 7 | 8 | @php $wireModel = $attributes->get('wire:model'); @endphp 9 | 10 |
11 | @if($label) 12 | 15 | @endif 16 | 17 |
18 | whereStartsWith('wire:model') }} id="{{ $id ?? '' }}" name="{{ $name ?? '' }}" type="{{ $type ?? '' }}" required autofocus class="appearance-none flex w-full h-10 px-3 py-2 text-sm bg-white dark:text-gray-300 dark:bg-white/[4%] border rounded-md border-gray-300 dark:border-white/10 ring-offset-background placeholder:text-gray-500 dark:placeholder:text-gray-400 focus:border-gray-300 dark:focus:border-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-200/60 dark:focus:ring-white/20 disabled:cursor-not-allowed disabled:opacity-50 @error($wireModel) border-red-300 text-red-900 placeholder-red-300 focus:border-red-300 focus:ring-red @enderror" /> 19 |
20 | 21 | @error($wireModel) 22 |

{{ $message }}

23 | @enderror 24 |
-------------------------------------------------------------------------------- /resources/views/components/ui/light-dark-switch.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/views/components/ui/link.blade.php: -------------------------------------------------------------------------------- 1 | except('wire:navigate') }} 3 | wire:navigate 4 | > 5 | {{ $slot }} 6 | -------------------------------------------------------------------------------- /resources/views/components/ui/logo.blade.php: -------------------------------------------------------------------------------- 1 | 2 | {{ config('app.name') }} 3 | 4 | -------------------------------------------------------------------------------- /resources/views/components/ui/marketing/breadcrumbs.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'crumbs' => [], 3 | 'page' => 'About' 4 | ]) 5 | 6 | {{-- 7 | Example Usage: 8 | 9 | 18 | 19 | --}} 20 | 21 | -------------------------------------------------------------------------------- /resources/views/components/ui/marketing/header.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 |
17 | 25 |
26 |
27 | 30 | @auth 31 |
32 | View Dashboard 33 |
34 | @else 35 |
36 | Login 37 |
38 |
39 | Sign Up 40 |
41 | @endauth 42 | 43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /resources/views/components/ui/marketing/page-header.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'title' => 'Page Header Title', 3 | 'description' => 'Description goes here' 4 | ]) 5 | 6 | 7 |
8 |
9 |

{{ $title }}

10 |

{{ $description }}

11 |
12 |
-------------------------------------------------------------------------------- /resources/views/components/ui/modal.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'name', 3 | 'show' => false, 4 | 'maxWidth' => '2xl' 5 | ]) 6 | 7 | @php 8 | $maxWidth = [ 9 | 'sm' => 'sm:max-w-sm', 10 | 'md' => 'sm:max-w-md', 11 | 'lg' => 'sm:max-w-lg', 12 | 'xl' => 'sm:max-w-xl', 13 | '2xl' => 'sm:max-w-2xl', 14 | ][$maxWidth]; 15 | @endphp 16 | 17 |
18 | @teleport('body') 19 |
51 | 52 |
60 |
69 | {{ $slot }} 70 | 73 | 74 |
75 |
76 | @endteleport 77 |
78 | -------------------------------------------------------------------------------- /resources/views/components/ui/nav-link.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'href' => '/' 3 | ]) 4 | 5 | 9 | {{ $slot }} 10 | -------------------------------------------------------------------------------- /resources/views/components/ui/placeholder.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
-------------------------------------------------------------------------------- /resources/views/components/ui/select.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'id' => null, 4 | 'name' => null, 5 | 'options' => [], 6 | 'selected'=>null 7 | ]) 8 | 9 | @php $wireModel = $attributes->get('wire:model');@endphp 10 |
11 | 12 |
13 | 15 | 22 | @error($wireModel) 23 |

{{ $message }}

24 | @enderror 25 |
26 |
27 | -------------------------------------------------------------------------------- /resources/views/components/ui/slide-over.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'name', 3 | 'title' => 'Slide-over Title', 4 | 'open' => false, 5 | 'maxWidth' => 'md' 6 | ]) 7 | 8 | @php 9 | $maxWidth = [ 10 | 'sm' => 'sm:max-w-sm', 11 | 'md' => 'sm:max-w-md', 12 | 'lg' => 'sm:max-w-lg', 13 | 'xl' => 'sm:max-w-xl', 14 | '2xl' => 'sm:max-w-2xl', 15 | ][$maxWidth]; 16 | @endphp 17 | 18 |
23 |
24 | {{ $trigger }} 25 |
26 | 74 |
75 | 76 | -------------------------------------------------------------------------------- /resources/views/components/ui/text-link.blade.php: -------------------------------------------------------------------------------- 1 | except('wire:navigate') }} 3 | class="text-gray-500 underline cursor-pointer dark:text-gray-400 dark:hover:text-gray-300 hover:text-gray-800"> 4 | {{ $slot }} 5 | -------------------------------------------------------------------------------- /resources/views/dashboard.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Dashboard') }} 5 |

6 |
7 | 8 |
9 |
10 |
11 |
12 | {{ __("You're logged in!") }} 13 |
14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /resources/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ config('app.name', 'Laravel') }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | @vite(['resources/css/app.css', 'resources/js/app.js']) 16 | 17 | 18 |
19 | 20 | 21 | 22 | @if (isset($header)) 23 |
24 |
25 | {{ $header }} 26 |
27 |
28 | @endif 29 | 30 | 31 |
32 | {{ $slot }} 33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /resources/views/layouts/guest.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ config('app.name', 'Laravel') }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | @vite(['resources/css/app.css', 'resources/js/app.js']) 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 | 25 |
26 | {{ $slot }} 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /resources/views/livewire/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elrincondeisma/template-laravel-2024/f268c8b7537a3dde8daa4b8880cd28fd0a1a52ac/resources/views/livewire/.gitkeep -------------------------------------------------------------------------------- /resources/views/livewire/layout/navigation.blade.php: -------------------------------------------------------------------------------- 1 | redirect('/', navigate: true); 16 | } 17 | }; ?> 18 | 19 | 111 | -------------------------------------------------------------------------------- /resources/views/livewire/pages/auth/confirm-password.blade.php: -------------------------------------------------------------------------------- 1 | validate([ 18 | 'password' => ['required', 'string'], 19 | ]); 20 | 21 | if (! Auth::guard('web')->validate([ 22 | 'email' => Auth::user()->email, 23 | 'password' => $this->password, 24 | ])) { 25 | throw ValidationException::withMessages([ 26 | 'password' => __('auth.password'), 27 | ]); 28 | } 29 | 30 | session(['auth.password_confirmed_at' => time()]); 31 | 32 | $this->redirectIntended(default: route('dashboard', absolute: false), navigate: true); 33 | } 34 | }; ?> 35 | 36 |
37 |
38 | {{ __('This is a secure area of the application. Please confirm your password before continuing.') }} 39 |
40 | 41 |
42 | 43 |
44 | 45 | 46 | 52 | 53 | 54 |
55 | 56 |
57 | 58 | {{ __('Confirm') }} 59 | 60 |
61 |
62 |
63 | -------------------------------------------------------------------------------- /resources/views/livewire/pages/auth/forgot-password.blade.php: -------------------------------------------------------------------------------- 1 | validate([ 17 | 'email' => ['required', 'string', 'email'], 18 | ]); 19 | 20 | // We will send the password reset link to this user. Once we have attempted 21 | // to send the link, we will examine the response then see the message we 22 | // need to show to the user. Finally, we'll send out a proper response. 23 | $status = Password::sendResetLink( 24 | $this->only('email') 25 | ); 26 | 27 | if ($status != Password::RESET_LINK_SENT) { 28 | $this->addError('email', __($status)); 29 | 30 | return; 31 | } 32 | 33 | $this->reset('email'); 34 | 35 | session()->flash('status', __($status)); 36 | } 37 | }; ?> 38 | 39 |
40 |
41 | {{ __('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.') }} 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 |
50 | 51 | 52 | 53 |
54 | 55 |
56 | 57 | {{ __('Email Password Reset Link') }} 58 | 59 |
60 |
61 |
62 | -------------------------------------------------------------------------------- /resources/views/livewire/pages/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | validate(); 18 | 19 | $this->form->authenticate(); 20 | 21 | Session::regenerate(); 22 | 23 | $this->redirectIntended(default: route('dashboard', absolute: false), navigate: true); 24 | } 25 | }; ?> 26 | 27 |
28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 |
38 | 39 | 40 |
41 | 42 | 43 | 47 | 48 | 49 |
50 | 51 | 52 |
53 | 57 |
58 | 59 |
60 | @if (Route::has('password.request')) 61 | 62 | {{ __('Forgot your password?') }} 63 | 64 | @endif 65 | 66 | 67 | {{ __('Log in') }} 68 | 69 |
70 |
71 |
72 | -------------------------------------------------------------------------------- /resources/views/livewire/pages/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | validate([ 24 | 'name' => ['required', 'string', 'max:255'], 25 | 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], 26 | 'password' => ['required', 'string', 'confirmed', Rules\Password::defaults()], 27 | ]); 28 | 29 | $validated['password'] = Hash::make($validated['password']); 30 | 31 | event(new Registered($user = User::create($validated))); 32 | 33 | Auth::login($user); 34 | 35 | $this->redirect(route('dashboard', absolute: false), navigate: true); 36 | } 37 | }; ?> 38 | 39 |
40 |
41 | 42 |
43 | 44 | 45 | 46 |
47 | 48 | 49 |
50 | 51 | 52 | 53 |
54 | 55 | 56 |
57 | 58 | 59 | 63 | 64 | 65 |
66 | 67 | 68 |
69 | 70 | 71 | 74 | 75 | 76 |
77 | 78 |
79 | 80 | {{ __('Already registered?') }} 81 | 82 | 83 | 84 | {{ __('Register') }} 85 | 86 |
87 |
88 |
89 | -------------------------------------------------------------------------------- /resources/views/livewire/pages/auth/reset-password.blade.php: -------------------------------------------------------------------------------- 1 | token = $token; 27 | 28 | $this->email = request()->string('email'); 29 | } 30 | 31 | /** 32 | * Reset the password for the given user. 33 | */ 34 | public function resetPassword(): void 35 | { 36 | $this->validate([ 37 | 'token' => ['required'], 38 | 'email' => ['required', 'string', 'email'], 39 | 'password' => ['required', 'string', 'confirmed', Rules\Password::defaults()], 40 | ]); 41 | 42 | // Here we will attempt to reset the user's password. If it is successful we 43 | // will update the password on an actual user model and persist it to the 44 | // database. Otherwise we will parse the error and return the response. 45 | $status = Password::reset( 46 | $this->only('email', 'password', 'password_confirmation', 'token'), 47 | function ($user) { 48 | $user->forceFill([ 49 | 'password' => Hash::make($this->password), 50 | 'remember_token' => Str::random(60), 51 | ])->save(); 52 | 53 | event(new PasswordReset($user)); 54 | } 55 | ); 56 | 57 | // If the password was successfully reset, we will redirect the user back to 58 | // the application's home authenticated view. If there is an error we can 59 | // redirect them back to where they came from with their error message. 60 | if ($status != Password::PASSWORD_RESET) { 61 | $this->addError('email', __($status)); 62 | 63 | return; 64 | } 65 | 66 | Session::flash('status', __($status)); 67 | 68 | $this->redirectRoute('login', navigate: true); 69 | } 70 | }; ?> 71 | 72 |
73 |
74 | 75 |
76 | 77 | 78 | 79 |
80 | 81 | 82 |
83 | 84 | 85 | 86 |
87 | 88 | 89 |
90 | 91 | 92 | 95 | 96 | 97 |
98 | 99 |
100 | 101 | {{ __('Reset Password') }} 102 | 103 |
104 |
105 |
106 | -------------------------------------------------------------------------------- /resources/views/livewire/pages/auth/verify-email.blade.php: -------------------------------------------------------------------------------- 1 | hasVerifiedEmail()) { 17 | $this->redirectIntended(default: route('dashboard', absolute: false), navigate: true); 18 | 19 | return; 20 | } 21 | 22 | Auth::user()->sendEmailVerificationNotification(); 23 | 24 | Session::flash('status', 'verification-link-sent'); 25 | } 26 | 27 | /** 28 | * Log the current user out of the application. 29 | */ 30 | public function logout(Logout $logout): void 31 | { 32 | $logout(); 33 | 34 | $this->redirect('/', navigate: true); 35 | } 36 | }; ?> 37 | 38 |
39 |
40 | {{ __('Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }} 41 |
42 | 43 | @if (session('status') == 'verification-link-sent') 44 |
45 | {{ __('A new verification link has been sent to the email address you provided during registration.') }} 46 |
47 | @endif 48 | 49 |
50 | 51 | {{ __('Resend Verification Email') }} 52 | 53 | 54 | 57 |
58 |
59 | -------------------------------------------------------------------------------- /resources/views/livewire/profile/delete-user-form.blade.php: -------------------------------------------------------------------------------- 1 | validate([ 17 | 'password' => ['required', 'string', 'current_password'], 18 | ]); 19 | 20 | tap(Auth::user(), $logout(...))->delete(); 21 | 22 | $this->redirect('/', navigate: true); 23 | } 24 | }; ?> 25 | 26 |
27 |
28 |

29 | {{ __('Delete Account') }} 30 |

31 | 32 |

33 | {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }} 34 |

35 |
36 | 37 | {{ __('Delete Account') }} 41 | 42 | 43 |
44 | 45 |

46 | {{ __('Are you sure you want to delete your account?') }} 47 |

48 | 49 |

50 | {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }} 51 |

52 | 53 |
54 | 55 | 56 | 64 | 65 | 66 |
67 | 68 |
69 | 70 | {{ __('Cancel') }} 71 | 72 | 73 | 74 | {{ __('Delete Account') }} 75 | 76 |
77 |
78 |
79 |
80 | -------------------------------------------------------------------------------- /resources/views/livewire/profile/update-password-form.blade.php: -------------------------------------------------------------------------------- 1 | validate([ 22 | 'current_password' => ['required', 'string', 'current_password'], 23 | 'password' => ['required', 'string', Password::defaults(), 'confirmed'], 24 | ]); 25 | } catch (ValidationException $e) { 26 | $this->reset('current_password', 'password', 'password_confirmation'); 27 | 28 | throw $e; 29 | } 30 | 31 | Auth::user()->update([ 32 | 'password' => Hash::make($validated['password']), 33 | ]); 34 | 35 | $this->reset('current_password', 'password', 'password_confirmation'); 36 | 37 | $this->dispatch('password-updated'); 38 | } 39 | }; ?> 40 | 41 |
42 |
43 |

44 | {{ __('Update Password') }} 45 |

46 | 47 |

48 | {{ __('Ensure your account is using a long, random password to stay secure.') }} 49 |

50 |
51 | 52 |
53 |
54 | 55 | 56 | 57 |
58 | 59 |
60 | 61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 | 69 |
70 | 71 |
72 | {{ __('Save') }} 73 | 74 | 75 | {{ __('Saved.') }} 76 | 77 |
78 |
79 |
80 | -------------------------------------------------------------------------------- /resources/views/livewire/profile/update-profile-information-form.blade.php: -------------------------------------------------------------------------------- 1 | name = Auth::user()->name; 20 | $this->email = Auth::user()->email; 21 | } 22 | 23 | /** 24 | * Update the profile information for the currently authenticated user. 25 | */ 26 | public function updateProfileInformation(): void 27 | { 28 | $user = Auth::user(); 29 | 30 | $validated = $this->validate([ 31 | 'name' => ['required', 'string', 'max:255'], 32 | 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', Rule::unique(User::class)->ignore($user->id)], 33 | ]); 34 | 35 | $user->fill($validated); 36 | 37 | if ($user->isDirty('email')) { 38 | $user->email_verified_at = null; 39 | } 40 | 41 | $user->save(); 42 | 43 | $this->dispatch('profile-updated', name: $user->name); 44 | } 45 | 46 | /** 47 | * Send an email verification notification to the current user. 48 | */ 49 | public function sendVerification(): void 50 | { 51 | $user = Auth::user(); 52 | 53 | if ($user->hasVerifiedEmail()) { 54 | $this->redirectIntended(default: route('dashboard', absolute: false)); 55 | 56 | return; 57 | } 58 | 59 | $user->sendEmailVerificationNotification(); 60 | 61 | Session::flash('status', 'verification-link-sent'); 62 | } 63 | }; ?> 64 | 65 |
66 |
67 |

68 | {{ __('Profile Information') }} 69 |

70 | 71 |

72 | {{ __("Update your account's profile information and email address.") }} 73 |

74 |
75 | 76 |
77 |
78 | 79 | 80 | 81 |
82 | 83 |
84 | 85 | 86 | 87 | 88 | @if (auth()->user() instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! auth()->user()->hasVerifiedEmail()) 89 |
90 |

91 | {{ __('Your email address is unverified.') }} 92 | 93 | 96 |

97 | 98 | @if (session('status') === 'verification-link-sent') 99 |

100 | {{ __('A new verification link has been sent to your email address.') }} 101 |

102 | @endif 103 |
104 | @endif 105 |
106 | 107 |
108 | {{ __('Save') }} 109 | 110 | 111 | {{ __('Saved.') }} 112 | 113 |
114 |
115 |
116 | -------------------------------------------------------------------------------- /resources/views/livewire/welcome/navigation.blade.php: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /resources/views/pages/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | '', 'password' => '', 'remember' => false]); 10 | rules(['email' => 'required|email', 'password' => 'required']); 11 | name('login'); 12 | 13 | $authenticate = function(){ 14 | $this->validate(); 15 | 16 | if (!Auth::attempt(['email' => $this->email, 'password' => $this->password], $this->remember)) { 17 | $this->addError('email', trans('auth.failed')); 18 | 19 | return; 20 | } 21 | 22 | event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), $this->remember)); 23 | 24 | return redirect()->intended('/'); 25 | } 26 | 27 | ?> 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 |

Sign in to your account

39 |
40 | Or 41 | create a new account 42 |
43 |
44 | 45 |
46 |
47 | @volt('auth.login') 48 |
49 | 50 | 51 | 52 | 53 |
54 | 55 | Forgot your password? 56 |
57 | 58 | Sign in 59 | 60 | @endvolt 61 |
62 |
63 | 64 |
65 | 66 |
-------------------------------------------------------------------------------- /resources/views/pages/auth/password/[token].blade.php: -------------------------------------------------------------------------------- 1 | 'required', 'email' => 'required|email', 'password' => 'required|min:8|same:passwordConfirmation']); 14 | name('password.reset'); 15 | 16 | mount(function ($token){ 17 | $this->email = request()->query('email', ''); 18 | $this->token = $token; 19 | }); 20 | 21 | $resetPassword = function(){ 22 | $this->validate(); 23 | 24 | $response = Password::broker()->reset( 25 | [ 26 | 'token' => $this->token, 27 | 'email' => $this->email, 28 | 'password' => $this->password 29 | ], 30 | function ($user, $password) { 31 | $user->password = Hash::make($password); 32 | 33 | $user->setRememberToken(Str::random(60)); 34 | 35 | $user->save(); 36 | 37 | event(new PasswordReset($user)); 38 | 39 | Auth::guard()->login($user); 40 | } 41 | ); 42 | 43 | if ($response == Password::PASSWORD_RESET) { 44 | session()->flash(trans($response)); 45 | 46 | return redirect('/'); 47 | } 48 | 49 | $this->addError('email', trans($response)); 50 | } 51 | 52 | ?> 53 | 54 | 55 |
56 | 57 |
58 | 59 | 60 | 61 |

Reset password

62 |
63 |
64 |
65 | @volt('auth.password.token') 66 |
67 | 68 | 69 | 70 | Reset password 71 | 72 | @endvolt 73 |
74 |
75 |
76 |
77 | -------------------------------------------------------------------------------- /resources/views/pages/auth/password/confirm.blade.php: -------------------------------------------------------------------------------- 1 | '']); 7 | rules(['password' => 'required|current_password']); 8 | name('password.confirm'); 9 | 10 | $confirm = function(){ 11 | $this->validate(); 12 | 13 | session()->put('auth.password_confirmed_at', time()); 14 | 15 | return redirect()->intended('/'); 16 | }; 17 | ?> 18 | 19 | 20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 |

28 | Confirm your password 29 |

30 |

31 | Please confirm your password before continuing 32 |

33 |
34 | 35 |
36 |
37 | @volt('auth.password.confirm') 38 |
39 | 40 |
41 | Forgot your password? 42 |
43 | Confirm password 44 | 45 | @endvolt 46 |
47 |
48 |
49 | 50 |
-------------------------------------------------------------------------------- /resources/views/pages/auth/password/reset.blade.php: -------------------------------------------------------------------------------- 1 | null, 'emailSentMessage' => false]); 8 | rules(['email' => 'required|email']); 9 | name('password.request'); 10 | 11 | 12 | 13 | $sendResetPasswordLink = function(){ 14 | $this->validate(); 15 | 16 | $response = Password::broker()->sendResetLink(['email' => $this->email]); 17 | 18 | if ($response == Password::RESET_LINK_SENT) { 19 | $this->emailSentMessage = trans($response); 20 | 21 | return; 22 | } 23 | 24 | $this->addError('email', trans($response)); 25 | } 26 | 27 | ?> 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 |

39 | Reset password 40 |

41 |
42 | Or 43 | return to login 44 |
45 |
46 | 47 | @volt('auth.password.reset') 48 |
49 |
50 | @if ($emailSentMessage) 51 |
52 |
53 |
54 | 55 | 56 | 57 |
58 | 59 |
60 |

61 | {{ $emailSentMessage }} 62 |

63 |
64 |
65 |
66 | @else 67 |
68 | 69 | Send password reset link 70 | 71 | @endif 72 |
73 |
74 | @endvolt 75 | 76 |
77 | 78 |
-------------------------------------------------------------------------------- /resources/views/pages/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | '', 'email' => '', 'password' => '', 'passwordConfirmation' => '']); 13 | rules(['name' => 'required', 'email' => 'required|email|unique:users', 'password' => 'required|min:8|same:passwordConfirmation']); 14 | name('register'); 15 | 16 | $register = function(){ 17 | $this->validate(); 18 | 19 | $user = User::create([ 20 | 'email' => $this->email, 21 | 'name' => $this->name, 22 | 'password' => Hash::make($this->password), 23 | ]); 24 | 25 | event(new Registered($user)); 26 | 27 | Auth::login($user, true); 28 | 29 | return redirect()->intended('/'); 30 | } 31 | 32 | ?> 33 | 34 | 35 | 36 |
37 | 38 |
39 | 40 | 41 | 42 |

Create a new account

43 |
44 | Or 45 | sign in to your account 46 |
47 |
48 | 49 |
50 |
51 | @volt('auth.register') 52 |
53 | 54 | 55 | 56 | 57 | Register 58 | 59 | @endvolt 60 |
61 |
62 | 63 |
64 | 65 |
66 | -------------------------------------------------------------------------------- /resources/views/pages/auth/verify.blade.php: -------------------------------------------------------------------------------- 1 | user(); 12 | if ($user->hasVerifiedEmail()) { 13 | redirect('/'); 14 | } 15 | 16 | $user->sendEmailVerificationNotification(); 17 | 18 | event(new Verified($user)); 19 | 20 | $this->dispatch('resent'); 21 | session()->flash('resent'); 22 | } 23 | 24 | ?> 25 | 26 | 27 | 28 |
29 | 30 |
31 | 32 | 33 | 34 | 35 |

36 | Verify your email address 37 |

38 | 39 |
40 | Or 41 | 44 | 47 |
48 |
49 | 50 |
51 | 52 | @volt('auth.verify') 53 |
54 | @if (session('resent')) 55 | 62 | @endif 63 | 64 |
65 |

Before proceeding, please check your email for a verification link. If you did not receive the email, click here to request another.

66 |
67 |
68 | @endvolt 69 | 70 |
71 |
72 | 73 |
74 | -------------------------------------------------------------------------------- /resources/views/pages/dashboard/index.blade.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 |

13 | {{ __('Dashboard') }} 14 |

15 |
16 | 17 | @volt('dashboard') 18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 | Genesis 26 |
27 |

This is the default dashboard which you can use and customize. Alternatively we also have three dashboard starter templates available.

28 |

You can get all three designs, each with dark mode for only $29. Learn more below.

29 |
30 | Get It Here 31 | Video Preview 32 |
33 |

Thanks for using Genesis ✌️

34 |
35 | Dashboard 36 |
37 |
38 |
39 |
40 | @endvolt 41 |
-------------------------------------------------------------------------------- /resources/views/pages/index.blade.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | @volt('home') 14 |
15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |

Welcome to Genesis

23 |
24 |

The Beginning of Your
Next Great Idea.

25 |

The ultimate application starter kit with built-in features like Authentication, User Dashboards, Edit Profiles, UI Components, and much more!

26 |
27 | View the Docs 28 | View Github Repo 29 |
30 |
31 |
32 | 33 |
34 | @endvolt 35 | 36 |
37 | -------------------------------------------------------------------------------- /resources/views/pages/learn/index.blade.php: -------------------------------------------------------------------------------- 1 | $res->body()]) 14 | 15 | 16 | ?> 17 | 18 | 21 | 22 | 23 | 24 | 25 |

26 | {{ __('Learn More') }} 27 |

28 |
29 | 30 | @volt('learn') 31 |
32 | 33 |
34 | {!! Str::markdown($readme) !!} 35 |
36 |
37 | @endvolt 38 |
-------------------------------------------------------------------------------- /resources/views/profile.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Profile') }} 5 |

6 |
7 | 8 |
9 |
10 |
11 |
12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /resources/views/vendor/mail/html/header.blade.php: -------------------------------------------------------------------------------- 1 | @props(['url']) 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /routes/auth.php: -------------------------------------------------------------------------------- 1 | group(function () { 8 | Volt::route('register', 'pages.auth.register') 9 | ->name('register'); 10 | 11 | Volt::route('login', 'pages.auth.login') 12 | ->name('login'); 13 | 14 | Volt::route('forgot-password', 'pages.auth.forgot-password') 15 | ->name('password.request'); 16 | 17 | Volt::route('reset-password/{token}', 'pages.auth.reset-password') 18 | ->name('password.reset'); 19 | }); 20 | 21 | Route::middleware('auth')->group(function () { 22 | Volt::route('verify-email', 'pages.auth.verify-email') 23 | ->name('verification.notice'); 24 | 25 | Route::get('verify-email/{id}/{hash}', VerifyEmailController::class) 26 | ->middleware(['signed', 'throttle:6,1']) 27 | ->name('verification.verify'); 28 | 29 | Volt::route('confirm-password', 'pages.auth.confirm-password') 30 | ->name('password.confirm'); 31 | }); 32 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 8 | })->purpose('Display an inspiring quote')->hourly(); 9 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | name('home'); 19 | 20 | Route::middleware('auth')->group(function () { 21 | Route::get('email/verify/{id}/{hash}', EmailVerificationController::class) 22 | ->middleware('signed') 23 | ->name('verification.verify'); 24 | Route::post('logout', LogoutController::class) 25 | ->name('logout'); 26 | }); 27 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | compiled.php 2 | config.php 3 | down 4 | events.scanned.php 5 | maintenance.php 6 | routes.php 7 | routes.scanned.php 8 | schedule-* 9 | services.json 10 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme') 2 | 3 | module.exports = { 4 | darkMode: 'class', 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: ['Inter var', ...defaultTheme.fontFamily.sans], 9 | }, 10 | }, 11 | }, 12 | variants: { 13 | extend: { 14 | backgroundColor: ['active'], 15 | } 16 | }, 17 | content: [ 18 | './app/**/*.php', 19 | "./resources/**/*.{php,html,js,jsx,ts,tsx,vue,twig}", 20 | ], 21 | plugins: [ 22 | require('@tailwindcss/forms'), 23 | require('@tailwindcss/typography'), 24 | ], 25 | } -------------------------------------------------------------------------------- /tests/Feature/Auth/AuthenticationTest.php: -------------------------------------------------------------------------------- 1 | get('/login'); 8 | 9 | $response 10 | ->assertOk() 11 | ->assertSeeVolt('pages.auth.login'); 12 | }); 13 | 14 | test('users can authenticate using the login screen', function () { 15 | $user = User::factory()->create(); 16 | 17 | $component = Volt::test('pages.auth.login') 18 | ->set('form.email', $user->email) 19 | ->set('form.password', 'password'); 20 | 21 | $component->call('login'); 22 | 23 | $component 24 | ->assertHasNoErrors() 25 | ->assertRedirect(route('dashboard', absolute: false)); 26 | 27 | $this->assertAuthenticated(); 28 | }); 29 | 30 | test('users can not authenticate with invalid password', function () { 31 | $user = User::factory()->create(); 32 | 33 | $component = Volt::test('pages.auth.login') 34 | ->set('form.email', $user->email) 35 | ->set('form.password', 'wrong-password'); 36 | 37 | $component->call('login'); 38 | 39 | $component 40 | ->assertHasErrors() 41 | ->assertNoRedirect(); 42 | 43 | $this->assertGuest(); 44 | }); 45 | 46 | test('navigation menu can be rendered', function () { 47 | $user = User::factory()->create(); 48 | 49 | $this->actingAs($user); 50 | 51 | $response = $this->get('/dashboard'); 52 | 53 | $response 54 | ->assertOk() 55 | ->assertSeeVolt('layout.navigation'); 56 | }); 57 | 58 | test('users can logout', function () { 59 | $user = User::factory()->create(); 60 | 61 | $this->actingAs($user); 62 | 63 | $component = Volt::test('layout.navigation'); 64 | 65 | $component->call('logout'); 66 | 67 | $component 68 | ->assertHasNoErrors() 69 | ->assertRedirect('/'); 70 | 71 | $this->assertGuest(); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/Feature/Auth/EmailVerificationTest.php: -------------------------------------------------------------------------------- 1 | unverified()->create(); 10 | 11 | $response = $this->actingAs($user)->get('/verify-email'); 12 | 13 | $response->assertStatus(200); 14 | }); 15 | 16 | test('email can be verified', function () { 17 | $user = User::factory()->unverified()->create(); 18 | 19 | Event::fake(); 20 | 21 | $verificationUrl = URL::temporarySignedRoute( 22 | 'verification.verify', 23 | now()->addMinutes(60), 24 | ['id' => $user->id, 'hash' => sha1($user->email)] 25 | ); 26 | 27 | $response = $this->actingAs($user)->get($verificationUrl); 28 | 29 | Event::assertDispatched(Verified::class); 30 | expect($user->fresh()->hasVerifiedEmail())->toBeTrue(); 31 | $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); 32 | }); 33 | 34 | test('email is not verified with invalid hash', function () { 35 | $user = User::factory()->unverified()->create(); 36 | 37 | $verificationUrl = URL::temporarySignedRoute( 38 | 'verification.verify', 39 | now()->addMinutes(60), 40 | ['id' => $user->id, 'hash' => sha1('wrong-email')] 41 | ); 42 | 43 | $this->actingAs($user)->get($verificationUrl); 44 | 45 | expect($user->fresh()->hasVerifiedEmail())->toBeFalse(); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/Feature/Auth/LoginTest.php: -------------------------------------------------------------------------------- 1 | get('/auth/login') 12 | ->assertSuccessful(); 13 | }); 14 | 15 | test('is redirected if already logged in', function () { 16 | $user = User::factory()->create(); 17 | 18 | $this->be($user); 19 | 20 | $this->get('/auth/login') 21 | ->assertRedirect('/home'); 22 | }); 23 | 24 | test('a user can login', function () { 25 | $user = User::factory()->create(['password' => Hash::make('password')]); 26 | 27 | Volt::test('auth.login') 28 | ->set('email', $user->email) 29 | ->set('password', 'password') 30 | ->call('authenticate'); 31 | 32 | $this->assertAuthenticatedAs($user); 33 | }); 34 | 35 | test('is redirected to home after login', function () { 36 | $user = User::factory()->create(['password' => Hash::make('password')]); 37 | 38 | Volt::test('auth.login') 39 | ->set('email', $user->email) 40 | ->set('password', 'password') 41 | ->call('authenticate') 42 | ->assertRedirect('/'); 43 | }); 44 | 45 | test('email is required', function () { 46 | $user = User::factory()->create(['password' => Hash::make('password')]); 47 | 48 | Volt::test('auth.login') 49 | ->set('password', 'password') 50 | ->call('authenticate') 51 | ->assertHasErrors(['email' => 'required']); 52 | }); 53 | 54 | test('email must be valid email', function () { 55 | $user = User::factory()->create(['password' => Hash::make('password')]); 56 | 57 | Volt::test('auth.login') 58 | ->set('email', 'invalid-email') 59 | ->set('password', 'password') 60 | ->call('authenticate') 61 | ->assertHasErrors(['email' => 'email']); 62 | }); 63 | 64 | test('password is required', function () { 65 | $user = User::factory()->create(['password' => Hash::make('password')]); 66 | 67 | Volt::test('auth.login') 68 | ->set('email', $user->email) 69 | ->call('authenticate') 70 | ->assertHasErrors(['password' => 'required']); 71 | }); 72 | 73 | test('bad login attempt shows message', function () { 74 | $user = User::factory()->create(); 75 | 76 | Volt::test('auth.login') 77 | ->set('email', $user->email) 78 | ->set('password', 'bad-password') 79 | ->call('authenticate') 80 | ->assertHasErrors('email'); 81 | 82 | expect(Auth::check())->toBeFalse(); 83 | }); 84 | -------------------------------------------------------------------------------- /tests/Feature/Auth/LogoutTest.php: -------------------------------------------------------------------------------- 1 | create(); 10 | $this->be($user); 11 | 12 | $this->post(route('logout')) 13 | ->assertRedirect(route('home')); 14 | 15 | expect(Auth::check())->toBeFalse(); 16 | }); 17 | 18 | test('an unauthenticated user can not log out', function () { 19 | $this->post(route('logout')) 20 | ->assertRedirect(route('login')); 21 | 22 | expect(Auth::check())->toBeFalse(); 23 | }); 24 | -------------------------------------------------------------------------------- /tests/Feature/Auth/PasswordConfirmationTest.php: -------------------------------------------------------------------------------- 1 | create(); 10 | 11 | $response = $this->actingAs($user)->get('/confirm-password'); 12 | 13 | $response 14 | ->assertSeeVolt('pages.auth.confirm-password') 15 | ->assertStatus(200); 16 | }); 17 | 18 | test('password can be confirmed', function () { 19 | $user = User::factory()->create(); 20 | 21 | $this->actingAs($user); 22 | 23 | $component = Volt::test('pages.auth.confirm-password') 24 | ->set('password', 'password'); 25 | 26 | $component->call('confirmPassword'); 27 | 28 | $component 29 | ->assertRedirect('/dashboard') 30 | ->assertHasNoErrors(); 31 | }); 32 | 33 | test('password is not confirmed with invalid password', function () { 34 | $user = User::factory()->create(); 35 | 36 | $this->actingAs($user); 37 | 38 | $component = Volt::test('pages.auth.confirm-password') 39 | ->set('password', 'wrong-password'); 40 | 41 | $component->call('confirmPassword'); 42 | 43 | $component 44 | ->assertNoRedirect() 45 | ->assertHasErrors('password'); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/Feature/Auth/PasswordResetTest.php: -------------------------------------------------------------------------------- 1 | get('/forgot-password'); 12 | 13 | $response 14 | ->assertSeeVolt('pages.auth.forgot-password') 15 | ->assertStatus(200); 16 | }); 17 | 18 | test('reset password link can be requested', function () { 19 | Notification::fake(); 20 | 21 | $user = User::factory()->create(); 22 | 23 | Volt::test('pages.auth.forgot-password') 24 | ->set('email', $user->email) 25 | ->call('sendPasswordResetLink'); 26 | 27 | Notification::assertSentTo($user, ResetPassword::class); 28 | }); 29 | 30 | test('reset password screen can be rendered', function () { 31 | Notification::fake(); 32 | 33 | $user = User::factory()->create(); 34 | 35 | Volt::test('pages.auth.forgot-password') 36 | ->set('email', $user->email) 37 | ->call('sendPasswordResetLink'); 38 | 39 | Notification::assertSentTo($user, ResetPassword::class, function ($notification) { 40 | $response = $this->get('/reset-password/'.$notification->token); 41 | 42 | $response 43 | ->assertSeeVolt('pages.auth.reset-password') 44 | ->assertStatus(200); 45 | 46 | return true; 47 | }); 48 | }); 49 | 50 | test('password can be reset with valid token', function () { 51 | Notification::fake(); 52 | 53 | $user = User::factory()->create(); 54 | 55 | Volt::test('pages.auth.forgot-password') 56 | ->set('email', $user->email) 57 | ->call('sendPasswordResetLink'); 58 | 59 | Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { 60 | $component = Volt::test('pages.auth.reset-password', ['token' => $notification->token]) 61 | ->set('email', $user->email) 62 | ->set('password', 'password') 63 | ->set('password_confirmation', 'password'); 64 | 65 | $component->call('resetPassword'); 66 | 67 | $component 68 | ->assertRedirect('/login') 69 | ->assertHasNoErrors(); 70 | 71 | return true; 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /tests/Feature/Auth/PasswordUpdateTest.php: -------------------------------------------------------------------------------- 1 | create(); 11 | 12 | $this->actingAs($user); 13 | 14 | $component = Volt::test('profile.update-password-form') 15 | ->set('current_password', 'password') 16 | ->set('password', 'new-password') 17 | ->set('password_confirmation', 'new-password') 18 | ->call('updatePassword'); 19 | 20 | $component 21 | ->assertHasNoErrors() 22 | ->assertNoRedirect(); 23 | 24 | $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); 25 | }); 26 | 27 | test('correct password must be provided to update password', function () { 28 | $user = User::factory()->create(); 29 | 30 | $this->actingAs($user); 31 | 32 | $component = Volt::test('profile.update-password-form') 33 | ->set('current_password', 'wrong-password') 34 | ->set('password', 'new-password') 35 | ->set('password_confirmation', 'new-password') 36 | ->call('updatePassword'); 37 | 38 | $component 39 | ->assertHasErrors(['current_password']) 40 | ->assertNoRedirect(); 41 | }); 42 | -------------------------------------------------------------------------------- /tests/Feature/Auth/Passwords/ConfirmTest.php: -------------------------------------------------------------------------------- 1 | middleware(['web', 'password.confirm']); 14 | }); 15 | 16 | test('a user must confirm their password before visiting a protected page', function () { 17 | $user = User::factory()->create(); 18 | $this->be($user); 19 | 20 | $this->get('/must-be-confirmed') 21 | ->assertRedirect(route('password.confirm')); 22 | }); 23 | 24 | test('a user must enter a password to confirm it', function () { 25 | Volt::test('auth.password.confirm') 26 | ->call('confirm') 27 | ->assertHasErrors(['password' => 'required']); 28 | }); 29 | 30 | test('a user must enter their own password to confirm it', function () { 31 | $user = User::factory()->create([ 32 | 'password' => Hash::make('password'), 33 | ]); 34 | 35 | Volt::test('auth.password.confirm') 36 | ->set('password', 'not-password') 37 | ->call('confirm') 38 | ->assertHasErrors(['password' => 'current_password']); 39 | }); 40 | 41 | test('a user who confirms their password will get redirected', function () { 42 | $user = User::factory()->create([ 43 | 'password' => Hash::make('password'), 44 | ]); 45 | 46 | $this->be($user); 47 | 48 | $this->withSession(['url.intended' => '/must-be-confirmed']); 49 | 50 | Volt::test('auth.password.confirm') 51 | ->set('password', 'password') 52 | ->call('confirm') 53 | ->assertRedirect('/must-be-confirmed'); 54 | }); 55 | -------------------------------------------------------------------------------- /tests/Feature/Auth/Passwords/EmailTest.php: -------------------------------------------------------------------------------- 1 | get('/auth/password/reset') 10 | ->assertSuccessful(); 11 | }); 12 | 13 | test('a user must enter an email address', function () { 14 | Volt::test('auth.password.reset') 15 | ->call('sendResetPasswordLink') 16 | ->assertHasErrors(['email' => 'required']); 17 | }); 18 | 19 | test('a user must enter a valid email address', function () { 20 | Volt::test('auth.password.reset') 21 | ->set('email', 'email') 22 | ->call('sendResetPasswordLink') 23 | ->assertHasErrors(['email' => 'email']); 24 | }); 25 | 26 | test('a user who enters a valid email address will get sent an email', function () { 27 | $user = User::factory()->create(); 28 | 29 | Volt::test('auth.password.reset') 30 | ->set('email', $user->email) 31 | ->call('sendResetPasswordLink') 32 | ->assertNotSet('emailSentMessage', false); 33 | 34 | $this->assertDatabaseHas('password_reset_tokens', [ 35 | 'email' => $user->email, 36 | ]); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/Feature/Auth/Passwords/[Token]Test.php: -------------------------------------------------------------------------------- 1 | create(); 15 | 16 | $token = Str::random(16); 17 | 18 | DB::table('password_reset_tokens')->insert([ 19 | 'email' => $user->email, 20 | 'token' => Hash::make($token), 21 | 'created_at' => Carbon::now(), 22 | ]); 23 | 24 | $this->get('/auth/password/'.$token.'/?email='.$user->email) 25 | ->assertSuccessful() 26 | ->assertSee($user->email); 27 | }); 28 | 29 | test('can reset password', function () { 30 | $user = User::factory()->create(); 31 | 32 | $token = Str::random(16); 33 | 34 | DB::table('password_reset_tokens')->insert([ 35 | 'email' => $user->email, 36 | 'token' => Hash::make($token), 37 | 'created_at' => Carbon::now(), 38 | ]); 39 | 40 | Volt::test('auth.password.token', [ 41 | 'token' => $token, 42 | ]) 43 | ->set('email', $user->email) 44 | ->set('password', 'new-password') 45 | ->set('passwordConfirmation', 'new-password') 46 | ->call('resetPassword'); 47 | 48 | expect(Auth::attempt([ 49 | 'email' => $user->email, 50 | 'password' => 'new-password', 51 | ]))->toBeTrue(); 52 | }); 53 | 54 | test('token is required', function () { 55 | Volt::test('auth.password.token', [ 56 | 'token' => null, 57 | ]) 58 | ->call('resetPassword') 59 | ->assertHasErrors(['token' => 'required']); 60 | }); 61 | 62 | test('email is required', function () { 63 | Volt::test('auth.password.token', [ 64 | 'token' => Str::random(16), 65 | ]) 66 | ->set('email', null) 67 | ->call('resetPassword') 68 | ->assertHasErrors(['email' => 'required']); 69 | }); 70 | 71 | test('email is valid email', function () { 72 | Volt::test('auth.password.token', [ 73 | 'token' => Str::random(16), 74 | ]) 75 | ->set('email', 'email') 76 | ->call('resetPassword') 77 | ->assertHasErrors(['email' => 'email']); 78 | }); 79 | 80 | test('password is required', function () { 81 | Volt::test('auth.password.token', [ 82 | 'token' => Str::random(16), 83 | ]) 84 | ->set('password', '') 85 | ->call('resetPassword') 86 | ->assertHasErrors(['password' => 'required']); 87 | }); 88 | 89 | test('password is minimum of eight characters', function () { 90 | Volt::test('auth.password.token', [ 91 | 'token' => Str::random(16), 92 | ]) 93 | ->set('password', 'secret') 94 | ->call('resetPassword') 95 | ->assertHasErrors(['password' => 'min']); 96 | }); 97 | 98 | test('password matches password confirmation', function () { 99 | Volt::test('auth.password.token', [ 100 | 'token' => Str::random(16), 101 | ]) 102 | ->set('password', 'new-password') 103 | ->set('passwordConfirmation', 'not-new-password') 104 | ->call('resetPassword') 105 | ->assertHasErrors(['password' => 'same']); 106 | }); 107 | -------------------------------------------------------------------------------- /tests/Feature/Auth/RegisterTest.php: -------------------------------------------------------------------------------- 1 | get('auth/register') 13 | ->assertSuccessful(); 14 | }); 15 | 16 | test('is redirected if already logged in', function () { 17 | $user = User::factory()->create(); 18 | 19 | $this->be($user); 20 | 21 | $this->get('auth/register') 22 | ->assertRedirect(route('home')); 23 | }); 24 | 25 | test('a user can register', function () { 26 | Event::fake(); 27 | 28 | Volt::test('auth.register') 29 | ->set('name', 'Genesis') 30 | ->set('email', 'genesis@example.com') 31 | ->set('password', 'password') 32 | ->set('passwordConfirmation', 'password') 33 | ->call('register') 34 | ->assertRedirect('/'); 35 | 36 | expect(User::whereEmail('genesis@example.com')->exists())->toBeTrue(); 37 | expect(Auth::user()->email)->toEqual('genesis@example.com'); 38 | 39 | Event::assertDispatched(Registered::class); 40 | }); 41 | 42 | test('name is required', function () { 43 | Volt::test('auth.register') 44 | ->set('name', '') 45 | ->call('register') 46 | ->assertHasErrors(['name' => 'required']); 47 | }); 48 | 49 | test('email is required', function () { 50 | Volt::test('auth.register') 51 | ->set('email', '') 52 | ->call('register') 53 | ->assertHasErrors(['email' => 'required']); 54 | }); 55 | 56 | test('email is valid email', function () { 57 | Volt::test('auth.register') 58 | ->set('email', 'tallstack') 59 | ->call('register') 60 | ->assertHasErrors(['email' => 'email']); 61 | }); 62 | 63 | test('email hasnt been taken already', function () { 64 | User::factory()->create(['email' => 'tallstack@example.com']); 65 | 66 | Volt::test('auth.register') 67 | ->set('email', 'tallstack@example.com') 68 | ->call('register') 69 | ->assertHasErrors(['email' => 'unique']); 70 | }); 71 | 72 | test('see email hasnt already been taken validation message as user types', function () { 73 | User::factory()->create(['email' => 'genesis@example.com']); 74 | 75 | Volt::test('auth.register') 76 | ->set('email', 'genesis@gmail.com') 77 | ->assertHasNoErrors() 78 | ->set('email', 'genesis@example.com') 79 | ->call('register') 80 | ->assertHasErrors(['email' => 'unique']); 81 | }); 82 | 83 | test('password is required', function () { 84 | Volt::test('auth.register') 85 | ->set('password', '') 86 | ->set('passwordConfirmation', 'password') 87 | ->call('register') 88 | ->assertHasErrors(['password' => 'required']); 89 | }); 90 | 91 | test('password is minimum of eight characters', function () { 92 | Volt::test('auth.register') 93 | ->set('password', 'secret') 94 | ->set('passwordConfirmation', 'secret') 95 | ->call('register') 96 | ->assertHasErrors(['password' => 'min']); 97 | }); 98 | 99 | test('password matches password confirmation', function () { 100 | Volt::test('auth.register') 101 | ->set('email', 'tallstack@example.com') 102 | ->set('password', 'password') 103 | ->set('passwordConfirmation', 'not-password') 104 | ->call('register') 105 | ->assertHasErrors(['password' => 'same']); 106 | }); 107 | -------------------------------------------------------------------------------- /tests/Feature/Auth/RegistrationTest.php: -------------------------------------------------------------------------------- 1 | get('/register'); 9 | 10 | $response 11 | ->assertOk() 12 | ->assertSeeVolt('pages.auth.register'); 13 | }); 14 | 15 | test('new users can register', function () { 16 | $component = Volt::test('pages.auth.register') 17 | ->set('name', 'Test User') 18 | ->set('email', 'test@example.com') 19 | ->set('password', 'password') 20 | ->set('password_confirmation', 'password'); 21 | 22 | $component->call('register'); 23 | 24 | $component->assertRedirect(route('dashboard', absolute: false)); 25 | 26 | $this->assertAuthenticated(); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/Feature/Auth/VerifyTest.php: -------------------------------------------------------------------------------- 1 | create([ 15 | 'email_verified_at' => null, 16 | ]); 17 | 18 | Auth::login($user); 19 | 20 | $this->get('/auth/verify') 21 | ->assertSuccessful(); 22 | }); 23 | 24 | test('can resend verification email', function () { 25 | $user = User::factory()->create(); 26 | 27 | Livewire::actingAs($user); 28 | 29 | Volt::test('auth.verify') 30 | ->call('resend') 31 | ->assertDispatched('resent'); 32 | }); 33 | 34 | test('can verify', function () { 35 | $user = User::factory()->create([ 36 | 'email_verified_at' => null, 37 | ]); 38 | 39 | Auth::login($user); 40 | 41 | $url = URL::temporarySignedRoute('verification.verify', Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)), [ 42 | 'id' => $user->getKey(), 43 | 'hash' => sha1($user->getEmailForVerification()), 44 | ]); 45 | 46 | $this->get($url) 47 | ->assertRedirect(route('home')); 48 | 49 | expect($user->hasVerifiedEmail())->toBeTrue(); 50 | }); 51 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 5 | 6 | $response->assertStatus(200); 7 | }); 8 | -------------------------------------------------------------------------------- /tests/Feature/HomeTest.php: -------------------------------------------------------------------------------- 1 | get('/')->assertSuccessful(); 5 | }); 6 | -------------------------------------------------------------------------------- /tests/Feature/ProfileTest.php: -------------------------------------------------------------------------------- 1 | create(); 8 | 9 | $this->actingAs($user); 10 | 11 | $response = $this->get('/profile'); 12 | 13 | $response 14 | ->assertOk() 15 | ->assertSeeVolt('profile.update-profile-information-form') 16 | ->assertSeeVolt('profile.update-password-form') 17 | ->assertSeeVolt('profile.delete-user-form'); 18 | }); 19 | 20 | test('profile information can be updated', function () { 21 | $user = User::factory()->create(); 22 | 23 | $this->actingAs($user); 24 | 25 | $component = Volt::test('profile.update-profile-information-form') 26 | ->set('name', 'Test User') 27 | ->set('email', 'test@example.com') 28 | ->call('updateProfileInformation'); 29 | 30 | $component 31 | ->assertHasNoErrors() 32 | ->assertNoRedirect(); 33 | 34 | $user->refresh(); 35 | 36 | $this->assertSame('Test User', $user->name); 37 | $this->assertSame('test@example.com', $user->email); 38 | $this->assertNull($user->email_verified_at); 39 | }); 40 | 41 | test('email verification status is unchanged when the email address is unchanged', function () { 42 | $user = User::factory()->create(); 43 | 44 | $this->actingAs($user); 45 | 46 | $component = Volt::test('profile.update-profile-information-form') 47 | ->set('name', 'Test User') 48 | ->set('email', $user->email) 49 | ->call('updateProfileInformation'); 50 | 51 | $component 52 | ->assertHasNoErrors() 53 | ->assertNoRedirect(); 54 | 55 | $this->assertNotNull($user->refresh()->email_verified_at); 56 | }); 57 | 58 | test('user can delete their account', function () { 59 | $user = User::factory()->create(); 60 | 61 | $this->actingAs($user); 62 | 63 | $component = Volt::test('profile.delete-user-form') 64 | ->set('password', 'password') 65 | ->call('deleteUser'); 66 | 67 | $component 68 | ->assertHasNoErrors() 69 | ->assertRedirect('/'); 70 | 71 | $this->assertGuest(); 72 | $this->assertNull($user->fresh()); 73 | }); 74 | 75 | test('correct password must be provided to delete account', function () { 76 | $user = User::factory()->create(); 77 | 78 | $this->actingAs($user); 79 | 80 | $component = Volt::test('profile.delete-user-form') 81 | ->set('password', 'wrong-password') 82 | ->call('deleteUser'); 83 | 84 | $component 85 | ->assertHasErrors('password') 86 | ->assertNoRedirect(); 87 | 88 | $this->assertNotNull($user->fresh()); 89 | }); 90 | -------------------------------------------------------------------------------- /tests/Pest.php: -------------------------------------------------------------------------------- 1 | in('Feature'); 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Expectations 22 | |-------------------------------------------------------------------------- 23 | | 24 | | When you're writing tests, you often need to check that values meet certain conditions. The 25 | | "expect()" function gives you access to a set of "expectations" methods that you can use 26 | | to assert different things. Of course, you may extend the Expectation API at any time. 27 | | 28 | */ 29 | 30 | expect()->extend('toBeOne', function () { 31 | return $this->toBe(1); 32 | }); 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Functions 37 | |-------------------------------------------------------------------------- 38 | | 39 | | While Pest is very powerful out-of-the-box, you may have some testing code specific to your 40 | | project that you don't want to repeat in every file. Here you can also expose helpers as 41 | | global functions to help you to reduce the number of lines of code in your test files. 42 | | 43 | */ 44 | 45 | function something() 46 | { 47 | // .. 48 | } 49 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | toBeTrue(); 5 | }); 6 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import laravel from 'laravel-vite-plugin'; 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | laravel({ 7 | input: [ 8 | 'resources/css/app.css', 9 | 'resources/js/app.js', 10 | ], 11 | refresh: true, 12 | }), 13 | ], 14 | }); 15 | --------------------------------------------------------------------------------