diff --git a/README.md b/README.md index edc0fe2..6a5e92d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # laravel-stubs -Some helper files and stubs that I may include on various Laravel projects. \ No newline at end of file +Some helper files and stubs that I may include on various Laravel projects. diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh new file mode 100644 index 0000000..19884a2 --- /dev/null +++ b/scripts/bootstrap.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +composer require itsgoingd/clockwork diff --git a/scripts/genres.sh b/scripts/genres.sh new file mode 100644 index 0000000..52b129e --- /dev/null +++ b/scripts/genres.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +php artisan make:model ${1} -mf +php artisan make:controller Dashboard/${1}Controller +php artisan make:request ${1}/StoreRequest +php artisan make:request ${1}/UpdateRequest +mkdir -pv resources/js/Pages/${1}s +touch resources/js/Pages/${1}s/{Index,Show,Create,Edit}.vue diff --git a/src/.env.example b/src/.env.example new file mode 100644 index 0000000..e9c6c72 --- /dev/null +++ b/src/.env.example @@ -0,0 +1,53 @@ +APP_NAME=Invoicer +APP_ENV=local +APP_KEY=base64:hSCTwZ507IdKQ5QJHJ+mQw0DSMgDdAspasjwHCdiB8Y= +APP_DEBUG=true +APP_URL=https://invoicer.test +APP_UID_BYTES=8 + +LOG_CHANNEL=stack +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=mysql +DB_HOST=mariadb +DB_PORT=3306 +DB_DATABASE=invoicer_v3 +DB_USERNAME=root +DB_PASSWORD=root + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +FILESYSTEM_DRIVER=local +QUEUE_CONNECTION=sync +SESSION_DRIVER=database +SESSION_LIFETIME=120 + +MEMCACHED_HOST=memcached + +REDIS_HOST=redis +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=smtp +MAIL_HOST=mailhog +MAIL_PORT=1125 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS=null +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +PUSHER_APP_ID= +PUSHER_APP_KEY= +PUSHER_APP_SECRET= +PUSHER_APP_CLUSTER=mt1 + +MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" +MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" diff --git a/src/app/Console/Commands/ResetPassword.php b/src/app/Console/Commands/ResetPassword.php new file mode 100644 index 0000000..00e09e4 --- /dev/null +++ b/src/app/Console/Commands/ResetPassword.php @@ -0,0 +1,78 @@ +option('id'); + $email = $this->option('email'); + $password = $this->option('password'); + $column = null; + $value = null; + + if (! empty($id) && empty($email)) { + $column = 'id'; + $value = $id; + } elseif (empty($id) && ! empty($email)) { + $column = 'email'; + $value = $email; + } else { + $column = strtolower($this->choice('What column would you like to search by?', ['ID', 'Email'])); + $value = $this->ask("Please provide an $column to search for"); + } + + $user = User::where($column, $value)->first(); + if (! $user) { + $this->error('Unable to find a user matching your input.'); + return 1; + } + + if (empty($password)) { + $password = $this->secret('What is the new password?'); + } + try { + $user->update(['password' => Hash::make($password)]); + $this->info("User {$user->id} ({$user->email}) password update successful!"); + return 0; + } catch (\Exception $e) { + $this->error('Unable to set the password!'); + $this->line($e->getMessage()); + return 1; + } + } +} diff --git a/src/app/Http/Middleware/CheckCustomSessionData.php b/src/app/Http/Middleware/CheckCustomSessionData.php new file mode 100644 index 0000000..afbc6d4 --- /dev/null +++ b/src/app/Http/Middleware/CheckCustomSessionData.php @@ -0,0 +1,28 @@ +has('timezone_name') || empty(session('timezone_name'))) && $request->user()) { + session()->put('timezone_name', $request->user()->timezone_name); + } + + return $next($request); + } +} diff --git a/src/app/Http/Middleware/HandleInertiaRequests.php b/src/app/Http/Middleware/HandleInertiaRequests.php new file mode 100644 index 0000000..99b1c54 --- /dev/null +++ b/src/app/Http/Middleware/HandleInertiaRequests.php @@ -0,0 +1,59 @@ +user())) { + $notifications = $request->user()->notifications; + if (count($request->user()->unreadNotifications) > 0) { + $unreadNotifications = true; + } + } + + return array_merge(parent::share($request), [ + 'app_name' => config('app.name'), + 'notifications' => $notifications, + 'unreadNotifications' => $unreadNotifications, + ]); + } +} diff --git a/src/app/Models/Address.php b/src/app/Models/Address.php new file mode 100644 index 0000000..2263472 --- /dev/null +++ b/src/app/Models/Address.php @@ -0,0 +1,160 @@ + 'boolean', + ]; + + /** @var array */ + protected $dates = []; + + /** @var array */ + protected $appends = []; + + /** @var array */ + protected $touches = []; + + /** @var array */ + protected $dispatchesEvents = []; + + /* + |-------------------------------------------------------------------------- + | Class Constants + |-------------------------------------------------------------------------- + | + */ + + // + + /* + |-------------------------------------------------------------------------- + | Custom/Private Methods + |-------------------------------------------------------------------------- + | + */ + + /** + * Get the prunable model query. + * + * @since 1.0.0 + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function prunable(): Builder + { + //return static::where('created_at', '<=', now()->subMonth()); + } + + /** + * Prepare the model for pruning. + * + * @since 1.0.0 + * + * @return void + */ + protected function pruning(): void + { + // + } + + /* + |-------------------------------------------------------------------------- + | Accessors + |-------------------------------------------------------------------------- + | + */ + + // + + /* + |-------------------------------------------------------------------------- + | Mutators + |-------------------------------------------------------------------------- + | + */ + + // + + /* + |-------------------------------------------------------------------------- + | Scopes + |-------------------------------------------------------------------------- + | + */ + + /** + * Enforce that a given model belongs to a Team. + * + * @since 1.0.0 + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param int|string $teamId + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeOnTeam($query, $teamId): Builder + { + return $query->where('team_id', $teamId); + } + + /* + |-------------------------------------------------------------------------- + | Relationships + |-------------------------------------------------------------------------- + | + */ + + /** + * Morphable relationship method. + * + * @since 1.0.0 + * + * @return \Illuminate\Database\Eloquent\Relations\MorphTo + */ + public function addressable(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/src/app/Models/Traits/FormattedAddressTrait.php b/src/app/Models/Traits/FormattedAddressTrait.php new file mode 100644 index 0000000..83d71d6 --- /dev/null +++ b/src/app/Models/Traits/FormattedAddressTrait.php @@ -0,0 +1,35 @@ +street; + if (! empty($this->unit)) { + $street .= " {$this->unit}"; + } + return $street; + } + + /** + * Combine the city and state together as a single line + * + * @since 1.0.0 + * + * @return string + */ + public function getCityStateAttribute(): string + { + return "{$this->city}, {$this->state}"; + } +} diff --git a/src/app/Models/Traits/FormattedDateTrait.php b/src/app/Models/Traits/FormattedDateTrait.php new file mode 100644 index 0000000..6a24152 --- /dev/null +++ b/src/app/Models/Traits/FormattedDateTrait.php @@ -0,0 +1,171 @@ +created_at->format('M j, Y'); + } + + /** + * Return the created at datetime as month day, year. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public function getCreatedAtDateFullAttribute(): string + { + return $this->created_at->format('F jS, Y'); + } + + /** + * Return the created at datetime as month day, year hour:minute meridian. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public function getCreatedAtFullAttribute(): string + { + return $this->created_at->format('F jS, Y g:i a'); + } + + /** + * Return the updated at datetime as mon day, year. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public function getUpdatedAtDateShortAttribute(): string + { + if (empty($this->updated_at)) { + return '--'; + } + return $this->updated_at->format('M j, Y'); + } + + /** + * Return the updated at datetime as mon day, year. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public function getUpdatedAtDateFullAttribute(): string + { + if (empty($this->updated_at)) { + return '--'; + } + return $this->updated_at->format('F jS, Y'); + } + + /** + * Return the updated at datetime as mon day, year hour:minute meridian. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public function getUpdatedAtFullAttribute(): string + { + if (empty($this->updated_at)) { + return '--'; + } + return $this->updated_at->format('F jS, Y g:i a'); + } + + /** + * Return a datetime string as YYYY-MM-DD. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public static function dateStr(string $dateTimeString): string + { + return Carbon::parse($dateTimeString)->format('Y-m-d'); + } + + /** + * Return a datetime string as mon d, year. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public static function dateShort(string $dateTimeString): string + { + return Carbon::parse($dateTimeString)->format('M j, Y'); + } + + /** + * Return a datetime string as month day, year. + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public static function dateFull(string $dateTimeString): string + { + return Carbon::parse($dateTimeString)->format('F jS, Y'); + } + + /** + * Return a datetime string as HH:MM (military time) + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public static function timeShort(string $dateTimeString): string + { + return Carbon::parse($dateTimeString)->format('H:i'); + } + + /** + * Return a datetime string as hour:minute meridian + * + * @since 1.0.0 + * + * @param string $dateTimeString + * + * @return string + */ + public static function timeFull(string $dateTimeString): string + { + return Carbon::parse($dateTimeString)->format('g:i a'); + } +} diff --git a/src/app/Models/Traits/FormattedPhoneTrait.php b/src/app/Models/Traits/FormattedPhoneTrait.php new file mode 100644 index 0000000..a5038ae --- /dev/null +++ b/src/app/Models/Traits/FormattedPhoneTrait.php @@ -0,0 +1,55 @@ +phone); + $phoneNumber = preg_replace('//', '', $this->phone); + + if ($phoneLength > 10) { + $countryCode = substr($phoneNumber, 0, $phoneLength - 10); + $areaCode = substr($phoneNumber, -10, 3); + $nextThree = substr($phoneNumber, -7, 3); + $lastFour = substr($phoneNumber, -4, 4); + + $phoneNumber = "({$areaCode}) {$nextThree}-{$lastFour}"; + } elseif ($phoneLength == 10) { + $areaCode = substr($phoneNumber, 0, 3); + $nextThree = substr($phoneNumber, 3, 3); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = "({$areaCode}) {$nextThree}-{$lastFour}"; + } elseif ($phoneLength == 7) { + $nextThree = substr($phoneNumber, 0, 3); + $lastFour = substr($phoneNumber, 3, 4); + + $phoneNumber = "{$nextThree}-{$lastFour}"; + } + + return $phoneNumber; + } + + /** + * Remove all non-numeric characters from the phone number. + * + * @since 1.0.0 + * + * @param string $value + * + * @return void + */ + public function setPhoneNumberAttribute($value): void + { + $this->attributes['phone'] = preg_replace('/[^0-9]/', '', $value); + } +} diff --git a/src/app/Models/Traits/HasUidTrait.php b/src/app/Models/Traits/HasUidTrait.php new file mode 100644 index 0000000..274df5a --- /dev/null +++ b/src/app/Models/Traits/HasUidTrait.php @@ -0,0 +1,44 @@ +id = $this->generateUid(); + } + + /** + * Generates a cryptographically safe unique ID. + * + * @since 1.0.0 + * + * @return string + */ + public function generateUid(): string + { + $bytes = openssl_random_pseudo_bytes(env('APP_UID_BYTES', 8)); + return bin2hex($bytes); + } +} diff --git a/src/app/Models/User.php b/src/app/Models/User.php new file mode 100644 index 0000000..b8cfe71 --- /dev/null +++ b/src/app/Models/User.php @@ -0,0 +1,182 @@ + 'datetime', + ]; + + /** @var array */ + protected $dates = []; + + /** @var array */ + protected $appends = [ + 'full_name', + 'name_full', + 'profile_photo_url', + ]; + + /** @var array */ + protected $touches = []; + + /** @var array */ + protected $dispatchesEvents = []; + + /* + |-------------------------------------------------------------------------- + | Class Constants + |-------------------------------------------------------------------------- + | + */ + + // + + /* + |-------------------------------------------------------------------------- + | Custom/Private Methods + |-------------------------------------------------------------------------- + | + */ + + /** + * Get the prunable model query. + * + * @since 1.0.0 + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function prunable()//: Builder + { + //return static::where('created_at', '<=', now()->subMonth()); + } + + /** + * Prepare the model for pruning. + * + * @since 1.0.0 + * + * @return void + */ + protected function pruning(): void + { + // + } + + /* + |-------------------------------------------------------------------------- + | Accessors + |-------------------------------------------------------------------------- + | + */ + + /** + * Return the surname then (first)name separated by a comma. + * + * @since 1.0.0 + * + * @return string + */ + public function getFullNameAttribute(): string + { + return "{$this->surname}, {$this->name}"; + } + + /** + * Return both the (first)name and surname. + * + * @since 1.0.0 + * + * @return string + */ + public function getNameFullAttribute(): string + { + return "{$this->name} {$this->surname}"; + } + + /* + |-------------------------------------------------------------------------- + | Mutators + |-------------------------------------------------------------------------- + | + */ + + // + + /* + |-------------------------------------------------------------------------- + | Scopes + |-------------------------------------------------------------------------- + | + */ + + // + + /* + |-------------------------------------------------------------------------- + | Relationships + |-------------------------------------------------------------------------- + | + */ + + /** + * Return the associated Address with a User. + * + * @since 1.0.0 + * + * @return \Illuminate\Database\Eloquent\Relations\MorphOne + */ + public function addresses(): MorphOne + { + return $this->morphOne(Address::class, 'addressable'); + } +} diff --git a/src/app/Providers/AppServiceProvider.php b/src/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..89b0a05 --- /dev/null +++ b/src/app/Providers/AppServiceProvider.php @@ -0,0 +1,30 @@ +isProduction()); + } +} diff --git a/src/app/Providers/JetstreamServiceProvider.php b/src/app/Providers/JetstreamServiceProvider.php new file mode 100644 index 0000000..fb94431 --- /dev/null +++ b/src/app/Providers/JetstreamServiceProvider.php @@ -0,0 +1,84 @@ +configurePermissions(); + + Jetstream::createTeamsUsing(CreateTeam::class); + Jetstream::updateTeamNamesUsing(UpdateTeamName::class); + Jetstream::addTeamMembersUsing(AddTeamMember::class); + Jetstream::inviteTeamMembersUsing(InviteTeamMember::class); + Jetstream::removeTeamMembersUsing(RemoveTeamMember::class); + + Jetstream::deleteTeamsUsing(DeleteTeam::class); + + Jetstream::deleteUsersUsing(DeleteUser::class); + + // Allow a user to authenticate with either email or username fields + Fortify::authenticateUsing(function (Request $request) { + $user = User::where('email', $request->username) + ->orWhere('username', $request->username) + ->first(); + + if ($user && Hash::check($request->password, $user->password)) { + return $user; + } + }); + } + + /** + * Configure the roles and permissions that are available within the application. + * + * @return void + */ + protected function configurePermissions() + { + Jetstream::defaultApiTokenPermissions(['read']); + + Jetstream::role('admin', 'Administrator', [ + 'create', + 'read', + 'update', + 'delete', + ])->description('Administrator users can perform any action.'); + + Jetstream::role('editor', 'Editor', [ + 'read', + 'create', + 'update', + ])->description('Editor users have the ability to read, create, and update.'); + } +} diff --git a/src/database/factories/AddressFactory.php b/src/database/factories/AddressFactory.php new file mode 100644 index 0000000..03ce304 --- /dev/null +++ b/src/database/factories/AddressFactory.php @@ -0,0 +1,35 @@ + $this->faker->buildingNumber() . ' ' . $this->faker->streetName(), + 'unit' => mt_rand(1, 10) === 10 ? $this->faker->secondaryAddress() : null, + 'city' => $this->faker->city(), + 'state' => $this->faker->state(), + 'postal_code' => $this->faker->postcode(), + 'country' => 'United States', + 'latitude' => $this->faker->latitude(), + 'longitude' => $this->faker->longitude(), + ]; + } +} diff --git a/src/database/factories/UserFactory.php b/src/database/factories/UserFactory.php new file mode 100644 index 0000000..e0a9d34 --- /dev/null +++ b/src/database/factories/UserFactory.php @@ -0,0 +1,72 @@ + $this->faker->firstName(), + 'surname' => $this->faker->lastName(), + 'username' => $this->faker->unique()->userName(), + 'email' => $this->faker->unique()->safeEmail(), + 'email_verified_at' => now(), + 'timezone_name' => $this->faker->timezone(), + 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password + 'remember_token' => Str::random(10), + ]; + } + + /** + * Indicate that the model's email address should be unverified. + * + * @return \Illuminate\Database\Eloquent\Factories\Factory + */ + public function unverified() + { + return $this->state(function (array $attributes) { + return [ + 'email_verified_at' => null, + ]; + }); + } + + /** + * Indicate that the user should have a personal team. + * + * @return $this + */ + public function withPersonalTeam() + { + if (! Features::hasTeamFeatures()) { + return $this->state([]); + } + + return $this->has( + Team::factory() + ->state(function (array $attributes, User $user) { + return ['name' => $user->name.'\'s Team', 'user_id' => $user->id, 'personal_team' => true]; + }), + 'ownedTeams' + ); + } +} diff --git a/src/database/migrations/0000_00_00_000000_create_users_table.php b/src/database/migrations/0000_00_00_000000_create_users_table.php new file mode 100644 index 0000000..c0a4878 --- /dev/null +++ b/src/database/migrations/0000_00_00_000000_create_users_table.php @@ -0,0 +1,43 @@ +string('id', 64)->primary(); + $table->string('name'); + $table->string('surname'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('timezone_name')->default('UTC'); + $table->string('current_team_id', 64)->nullable(); + $table->string('profile_photo_path', 2048)->nullable(); + $table->string('password'); + $table->text('two_factor_secret')->nullable(); + $table->text('two_factor_recovery_codes')->nullable(); + $table->rememberToken(); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('users'); + } +} diff --git a/src/database/migrations/1000_00_00_000000_create_addresses_table.php b/src/database/migrations/1000_00_00_000000_create_addresses_table.php new file mode 100644 index 0000000..cefbe47 --- /dev/null +++ b/src/database/migrations/1000_00_00_000000_create_addresses_table.php @@ -0,0 +1,44 @@ +string('id', 64)->primary(); + $table->uuidMorphs('addressable'); + $table->string('street'); + $table->string('unit')->nullable(); + $table->string('city'); + $table->string('state'); + $table->string('postal_code'); // leave as string to accomodate 12345-6789 or Canada + $table->string('country')->default('United States'); + $table->float('latitude', 12, 9)->index()->nullable(); + $table->float('longitude', 12, 9)->index()->nullable(); + $table->point('location')->nullable(); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + + $table->spatialIndex('location'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('addresses'); + } +} diff --git a/src/helpers/constants/cache_ttl.php b/src/helpers/constants/cache_ttl.php new file mode 100644 index 0000000..a7d0806 --- /dev/null +++ b/src/helpers/constants/cache_ttl.php @@ -0,0 +1,11 @@ + 'HTTP_SUCCESS', + 201 => 'HTTP_CREATED', + 202 => 'HTTP_ACCEPTED', + 204 => 'HTTP_NO_CONTENT', + 205 => 'HTTP_RESET_CONTENT', + 206 => 'HTTP_PARTIAL_CONTENT', + 208 => 'HTTP_ALREADY_REPORTED', + + // 300's (redirections) + 301 => 'HTTP_MOVED_PERMANENTLY', + 302 => 'HTTP_REDIRECT_FOUND', + 304 => 'HTTP_NOT_MODIFIED', + 307 => 'HTTP_TEMP_REDIRECT', + 308 => 'HTTP_PERMANENT_REDIRECT', + + // 400's (app got the request but couldn't process it successfully, coding error) + 400 => 'HTTP_BAD_REQUEST', + 401 => 'HTTP_UNAUTHORIZED', + 402 => 'HTTP_PAYMENT_REQUIRED', + 403 => 'HTTP_FORBIDDEN', + 404 => 'HTTP_NOT_FOUND', + 405 => 'HTTP_METHOD_NOT_ALLOWED', + 406 => 'HTTP_NOT_ACCEPTABLE', + 408 => 'HTTP_TIMEOUT', + 409 => 'HTTP_CONFLICT', + 410 => 'HTTP_GONE', + 412 => 'HTTP_PRECONDITION_FAILED', + 413 => 'HTTP_PAYLOAD_TOO_LARGE', + 415 => 'HTTP_UNSUPPORTED_MEDIA', + 413 => 'HTTP_TOO_LARGE', + 417 => 'HTTP_EXPECTATION_FAIL', + 418 => 'HTTP_TEAPOT', + 422 => 'HTTP_UNPROCESSABLE_ENTITY', + 423 => 'HTTP_LOCKED', + 424 => 'HTTP_FAILED_DEPENDENCY', + 236 => 'HTTP_UPGRADE_REQUIRED', + 428 => 'HTTP_PRECONDITION_REQUIRED', + 429 => 'HTTP_TOO_MANY_REQUESTS', + 451 => 'HTTP_GAG_ORDER', + + // 500's (server-level problem, process died or configuration is incorrect) + 500 => 'HTTP_SERVER_ERROR', + 501 => 'HTTP_NOT_IMPLEMENTED', + 503 => 'HTTP_UNAVAILABLE', + 530 => 'HTTP_SUSPENDED', +]; + +foreach ($httpCodes as $code => $slug) { + if (! defined($slug)) { + define($slug, $code); + } +} diff --git a/src/helpers/global_functions.php b/src/helpers/global_functions.php new file mode 100644 index 0000000..8911269 --- /dev/null +++ b/src/helpers/global_functions.php @@ -0,0 +1,43 @@ + +
+
+ +
+
+ +
+
+ + + diff --git a/src/resources/js/Components/DropdownMenu.vue b/src/resources/js/Components/DropdownMenu.vue new file mode 100644 index 0000000..88efdf1 --- /dev/null +++ b/src/resources/js/Components/DropdownMenu.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/resources/js/Components/Notifications/ErrorNotifications.vue b/src/resources/js/Components/Notifications/ErrorNotifications.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/resources/js/Components/Notifications/GenericNotifications.vue b/src/resources/js/Components/Notifications/GenericNotifications.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/resources/js/Components/Notifications/SuccessNotifications.vue b/src/resources/js/Components/Notifications/SuccessNotifications.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/resources/js/Components/Paginator.vue b/src/resources/js/Components/Paginator.vue new file mode 100644 index 0000000..5c58c83 --- /dev/null +++ b/src/resources/js/Components/Paginator.vue @@ -0,0 +1,127 @@ + + + diff --git a/src/resources/js/Components/ResponsiveNavLink.vue b/src/resources/js/Components/ResponsiveNavLink.vue new file mode 100644 index 0000000..ab5e7a4 --- /dev/null +++ b/src/resources/js/Components/ResponsiveNavLink.vue @@ -0,0 +1,85 @@ + + + diff --git a/src/resources/js/Components/SidenavLink.vue b/src/resources/js/Components/SidenavLink.vue new file mode 100644 index 0000000..f5ba5fc --- /dev/null +++ b/src/resources/js/Components/SidenavLink.vue @@ -0,0 +1,74 @@ + + + diff --git a/src/resources/js/Layouts/AppLayout.vue b/src/resources/js/Layouts/AppLayout.vue new file mode 100644 index 0000000..86908d7 --- /dev/null +++ b/src/resources/js/Layouts/AppLayout.vue @@ -0,0 +1,291 @@ + + + diff --git a/src/resources/js/Pages/Auth/ConfirmPassword.vue b/src/resources/js/Pages/Auth/ConfirmPassword.vue new file mode 100644 index 0000000..05aaed0 --- /dev/null +++ b/src/resources/js/Pages/Auth/ConfirmPassword.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/resources/js/Pages/Auth/ForgotPassword.vue b/src/resources/js/Pages/Auth/ForgotPassword.vue new file mode 100644 index 0000000..6314257 --- /dev/null +++ b/src/resources/js/Pages/Auth/ForgotPassword.vue @@ -0,0 +1,73 @@ + + + diff --git a/src/resources/js/Pages/Auth/Login.vue b/src/resources/js/Pages/Auth/Login.vue new file mode 100644 index 0000000..8e78bb0 --- /dev/null +++ b/src/resources/js/Pages/Auth/Login.vue @@ -0,0 +1,98 @@ + + + diff --git a/src/resources/js/Pages/Auth/Register.vue b/src/resources/js/Pages/Auth/Register.vue new file mode 100644 index 0000000..c892924 --- /dev/null +++ b/src/resources/js/Pages/Auth/Register.vue @@ -0,0 +1,114 @@ + + + diff --git a/src/resources/js/Pages/Auth/ResetPassword.vue b/src/resources/js/Pages/Auth/ResetPassword.vue new file mode 100644 index 0000000..386bf07 --- /dev/null +++ b/src/resources/js/Pages/Auth/ResetPassword.vue @@ -0,0 +1,81 @@ + + + diff --git a/src/resources/js/Pages/Auth/TwoFactorChallenge.vue b/src/resources/js/Pages/Auth/TwoFactorChallenge.vue new file mode 100644 index 0000000..af93abf --- /dev/null +++ b/src/resources/js/Pages/Auth/TwoFactorChallenge.vue @@ -0,0 +1,102 @@ + + + diff --git a/src/resources/js/Pages/Auth/VerifyEmail.vue b/src/resources/js/Pages/Auth/VerifyEmail.vue new file mode 100644 index 0000000..77715c3 --- /dev/null +++ b/src/resources/js/Pages/Auth/VerifyEmail.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/resources/js/Pages/Dashboard.vue b/src/resources/js/Pages/Dashboard.vue new file mode 100644 index 0000000..1eb5bb7 --- /dev/null +++ b/src/resources/js/Pages/Dashboard.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/resources/js/Pages/Profile/Partials/DeleteUserForm.vue b/src/resources/js/Pages/Profile/Partials/DeleteUserForm.vue new file mode 100644 index 0000000..6062017 --- /dev/null +++ b/src/resources/js/Pages/Profile/Partials/DeleteUserForm.vue @@ -0,0 +1,107 @@ + + + diff --git a/src/resources/js/Pages/Profile/Partials/LogoutOtherBrowserSessionsForm.vue b/src/resources/js/Pages/Profile/Partials/LogoutOtherBrowserSessionsForm.vue new file mode 100644 index 0000000..ed181b4 --- /dev/null +++ b/src/resources/js/Pages/Profile/Partials/LogoutOtherBrowserSessionsForm.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue b/src/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue new file mode 100644 index 0000000..8e36257 --- /dev/null +++ b/src/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue @@ -0,0 +1,167 @@ + + + diff --git a/src/resources/js/Pages/Profile/Partials/UpdatePasswordForm.vue b/src/resources/js/Pages/Profile/Partials/UpdatePasswordForm.vue new file mode 100644 index 0000000..76f418c --- /dev/null +++ b/src/resources/js/Pages/Profile/Partials/UpdatePasswordForm.vue @@ -0,0 +1,93 @@ + + + diff --git a/src/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue b/src/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue new file mode 100644 index 0000000..055679b --- /dev/null +++ b/src/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.vue @@ -0,0 +1,174 @@ + + + diff --git a/src/resources/js/Pages/Profile/Show.vue b/src/resources/js/Pages/Profile/Show.vue new file mode 100644 index 0000000..511beeb --- /dev/null +++ b/src/resources/js/Pages/Profile/Show.vue @@ -0,0 +1,68 @@ + + + diff --git a/src/resources/js/app.js b/src/resources/js/app.js new file mode 100644 index 0000000..357e8a5 --- /dev/null +++ b/src/resources/js/app.js @@ -0,0 +1,26 @@ +require("./bootstrap"); + +import { createApp, h } from "vue"; +import { createInertiaApp } from "@inertiajs/inertia-vue3"; +import { InertiaProgress } from "@inertiajs/progress"; +import Notifications from "notiwind"; + +const appName = window.document.getElementsByTagName("title")[0]?.innerText || "Laravel"; + +window.genUid = function () { + return [...Array(16)].map(() => Math.floor(Math.random() * 16).toString(16)).join(""); +}; + +createInertiaApp({ + title: (title) => `${title} - ${appName}`, + resolve: (name) => require(`./Pages/${name}.vue`), + setup({ el, app, props, plugin }) { + return createApp({ render: () => h(app, props) }) + .use(plugin) + .use(Notifications) + .mixin({ methods: { route } }) + .mount(el); + }, +}); + +InertiaProgress.init({ color: "#4b5563" }); diff --git a/src/resources/js/bootstrap.js b/src/resources/js/bootstrap.js new file mode 100644 index 0000000..870b3c1 --- /dev/null +++ b/src/resources/js/bootstrap.js @@ -0,0 +1,27 @@ +window._ = require('lodash'); + +/** + * We'll load the axios HTTP library which allows us to easily issue requests + * to our Laravel back-end. This library automatically handles sending the + * CSRF token as a header based on the value of the "XSRF" token cookie. + */ + +window.axios = require('axios'); +window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; + +/** + * Echo exposes an expressive API for subscribing to channels and listening + * for events that are broadcast by Laravel. Echo and event broadcasting + * allows your team to easily build robust real-time web applications. + */ + +// import Echo from 'laravel-echo'; + +// window.Pusher = require('pusher-js'); + +// window.Echo = new Echo({ +// broadcaster: 'pusher', +// key: process.env.MIX_PUSHER_APP_KEY, +// cluster: process.env.MIX_PUSHER_APP_CLUSTER, +// forceTLS: true +// }); diff --git a/src/resources/lang/en/app.php b/src/resources/lang/en/app.php new file mode 100644 index 0000000..3c6afec --- /dev/null +++ b/src/resources/lang/en/app.php @@ -0,0 +1,42 @@ + [ + // + + 'nav_' => [ + // + ], + ], + + // Text used as a label of some sort, not restricted to + // label HTML elements. + 'labels_' => [ + // + ], + + // Text that may really only show up in a button. + 'buttons_' => [ + // + ], + + // These will be longer status messages or short descriptions that serve + // as an informational/warning notice to the user. + 'notices_' => [ + // + ], +]; diff --git a/src/resources/views/app.blade.php b/src/resources/views/app.blade.php new file mode 100644 index 0000000..f961ee0 --- /dev/null +++ b/src/resources/views/app.blade.php @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + + + + + + {{-- --}} + + + {{-- --}} + + + + + + + {{-- --}} + {{-- --}} + + + {{-- --}} + {{-- --}} + {{-- --}} + + + + + + + + + + + @routes + + + + @inertia + + +