From 4dc64c22cba4bad56be22becbbaa3363d5efef7b Mon Sep 17 00:00:00 2001 From: Jonathan van Rij Date: Mon, 16 Feb 2026 11:19:06 +0100 Subject: [PATCH] adds roles --- app/Console/Commands/DevMenuCommand.php | 86 +++++++++++++++++++ .../Controllers/Auth/SocialiteController.php | 15 +++- app/Http/Controllers/SessionController.php | 4 - app/Http/Middleware/HandleInertiaRequests.php | 17 ++++ .../Requests/Session/UpdateSessionRequest.php | 19 ---- app/Models/Question.php | 9 ++ app/Models/Role.php | 23 +++++ app/Models/Session.php | 2 - app/Models/User.php | 17 ++++ app/Nova/AnswerResource.php | 17 ++++ app/Nova/CategoryResource.php | 16 ++++ app/Nova/LogResource.php | 16 ++++ app/Nova/QuestionGroupResource.php | 16 ++++ app/Nova/QuestionResource.php | 19 ++++ app/Nova/RoleResource.php | 75 ++++++++++++++++ app/Nova/ScreeningResource.php | 16 ++++ app/Nova/SessionResource.php | 45 +++++++--- app/Nova/User.php | 32 ++++++- app/Providers/NovaServiceProvider.php | 28 +++++- database/factories/SessionFactory.php | 1 - .../0000_00_00_000000_create_roles_table.php | 32 +++++++ .../0001_01_01_000000_create_users_table.php | 8 +- ...026_02_03_083000_create_sessions_table.php | 1 - database/seeders/JonathanSeeder.php | 10 ++- resources/js/Components/AppButton.vue | 6 +- resources/js/Components/PageHeader.vue | 9 +- resources/js/Components/RadioButtonGroup.vue | 11 ++- resources/js/Pages/Session/Result.vue | 8 -- tests/Feature/SessionLifecycleTest.php | 26 ------ 29 files changed, 495 insertions(+), 89 deletions(-) create mode 100644 app/Console/Commands/DevMenuCommand.php create mode 100644 app/Models/Role.php create mode 100644 app/Nova/RoleResource.php create mode 100644 database/migrations/0000_00_00_000000_create_roles_table.php diff --git a/app/Console/Commands/DevMenuCommand.php b/app/Console/Commands/DevMenuCommand.php new file mode 100644 index 0000000..76a43cb --- /dev/null +++ b/app/Console/Commands/DevMenuCommand.php @@ -0,0 +1,86 @@ +environment(), ['local', 'testing'])) { + $this->error('This command can only be run in local or testing environments.'); + + return Command::FAILURE; + } + + $this->info(''); + $this->info(' ╔═══════════════════════════════╗'); + $this->info(' ║ Go No Go — Dev Tools ║'); + $this->info(' ╚═══════════════════════════════╝'); + $this->info(''); + + $choice = $this->choice('Select an action', [ + 0 => 'Exit', + 1 => 'Fresh migrate, seed & build', + ]); + + if ($choice === 'Exit') { + $this->info('Bye!'); + + return Command::SUCCESS; + } + + if ($choice === 'Fresh migrate, seed & build') { + $this->freshMigrateAndBuild(); + } + + return Command::SUCCESS; + } + + /** + * Runs migrate:fresh with seeding, then runs npm build. + * + * Displays output from both processes and confirms success or failure. + */ + private function freshMigrateAndBuild(): void + { + $this->info(''); + $this->comment('Running migrate:fresh --seed...'); + $this->call('migrate:fresh', ['--seed' => true]); + + $this->info(''); + $this->comment('Running npm run build...'); + + $process = new Process(['npm', 'run', 'build']); + $process->setWorkingDirectory(base_path()); + $process->setTimeout(120); + $process->run(function (string $type, string $output): void { + $this->output->write($output); + }); + + if ($process->isSuccessful()) { + $this->info(''); + $this->info('Environment rebuilt successfully.'); + } else { + $this->error('Build failed.'); + } + } +} diff --git a/app/Http/Controllers/Auth/SocialiteController.php b/app/Http/Controllers/Auth/SocialiteController.php index 6cce353..8b3365a 100644 --- a/app/Http/Controllers/Auth/SocialiteController.php +++ b/app/Http/Controllers/Auth/SocialiteController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; +use App\Models\Role; use App\Models\User; use App\Services\ActivityLogger; use Illuminate\Http\RedirectResponse; @@ -29,17 +30,25 @@ public function callback(): RedirectResponse { $azureUser = Socialite::driver('azure')->user(); - $user = User::query()->firstOrCreate( + $user = User::query()->updateOrCreate( ['email' => $azureUser->getEmail()], [ 'name' => $azureUser->getName(), - 'password' => null, + 'azure_id' => $azureUser->getId(), + 'photo' => $azureUser->getAvatar(), + 'job_title' => Arr::get($azureUser->user, 'jobTitle'), + 'department' => Arr::get($azureUser->user, 'department'), + 'phone' => Arr::get($azureUser->user, 'mobilePhone', Arr::get($azureUser->user, 'businessPhones.0')), ] ); + if ($user->role_id === null) { + $user->update(['role_id' => Role::where('name', 'user')->first()->id]); + } + auth()->login($user); - ActivityLogger::log('login', $user->id, metadata: ['email' => $user->email, 'firm_name' => Arr::get($azureUser, 'companyName')]); + ActivityLogger::log('login', $user->id, metadata: ['email' => $user->email, 'firm_name' => Arr::get($azureUser->user, 'companyName')]); return redirect('/'); } diff --git a/app/Http/Controllers/SessionController.php b/app/Http/Controllers/SessionController.php index 9251c4f..1d15ec0 100644 --- a/app/Http/Controllers/SessionController.php +++ b/app/Http/Controllers/SessionController.php @@ -68,10 +68,6 @@ public function update(UpdateSessionRequest $request, Session $session): Redirec { $validated = $request->validated(); - if (Arr::has($validated, 'basic_info')) { - $session->update(['basic_info' => Arr::get($validated, 'basic_info')]); - } - if (Arr::has($validated, 'answers')) { $this->saveAnswers($session, Arr::get($validated, 'answers')); } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 77aed1f..897517d 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -6,7 +6,9 @@ use Illuminate\Http\Request; use Illuminate\Support\Arr; +use Illuminate\Support\Facades\Gate; use Inertia\Middleware; +use Laravel\Nova\Nova; final class HandleInertiaRequests extends Middleware { @@ -32,6 +34,7 @@ public function share(Request $request): array ...parent::share($request), 'auth' => [ 'user' => $this->getAuthenticatedUser(), + 'logo_href' => $this->getLogoHref(), ], 'flash' => [ 'success' => fn () => Arr::get($request->session()->all(), 'success'), @@ -57,4 +60,18 @@ private function getAuthenticatedUser(): ?array 'email' => $user->email, ]; } + + /** + * Determine logo href based on user Nova access. + */ + private function getLogoHref(): string + { + $user = auth()->user(); + + if ($user !== null && Gate::allows('viewNova', $user)) { + return Nova::path(); + } + + return '/'; + } } diff --git a/app/Http/Requests/Session/UpdateSessionRequest.php b/app/Http/Requests/Session/UpdateSessionRequest.php index 1a488cd..9de5b80 100644 --- a/app/Http/Requests/Session/UpdateSessionRequest.php +++ b/app/Http/Requests/Session/UpdateSessionRequest.php @@ -22,11 +22,6 @@ public function authorize(): bool public function rules(): array { return [ - 'basic_info' => ['sometimes', 'required', 'array'], - 'basic_info.client_name' => ['required_with:basic_info', 'string', 'max:255'], - 'basic_info.client_contact' => ['required_with:basic_info', 'string', 'max:255'], - 'basic_info.lead_firm_name' => ['required_with:basic_info', 'string', 'max:255'], - 'basic_info.lead_firm_contact' => ['required_with:basic_info', 'string', 'max:255'], 'answers' => ['sometimes', 'array'], 'answers.*.value' => ['nullable', 'string', 'in:yes,no,not_applicable'], 'answers.*.text_value' => ['nullable', 'string', 'max:10000'], @@ -41,20 +36,6 @@ public function rules(): array public function messages(): array { return [ - 'basic_info.required' => 'Basic information is required.', - 'basic_info.array' => 'Basic information must be a valid data structure.', - 'basic_info.client_name.required_with' => 'The client name is required.', - 'basic_info.client_name.string' => 'The client name must be text.', - 'basic_info.client_name.max' => 'The client name cannot exceed 255 characters.', - 'basic_info.client_contact.required_with' => 'The client contact is required.', - 'basic_info.client_contact.string' => 'The client contact must be text.', - 'basic_info.client_contact.max' => 'The client contact cannot exceed 255 characters.', - 'basic_info.lead_firm_name.required_with' => 'The lead firm name is required.', - 'basic_info.lead_firm_name.string' => 'The lead firm name must be text.', - 'basic_info.lead_firm_name.max' => 'The lead firm name cannot exceed 255 characters.', - 'basic_info.lead_firm_contact.required_with' => 'The lead firm contact is required.', - 'basic_info.lead_firm_contact.string' => 'The lead firm contact must be text.', - 'basic_info.lead_firm_contact.max' => 'The lead firm contact cannot exceed 255 characters.', 'answers.array' => 'Answers must be a valid data structure.', 'answers.*.value.in' => 'Answer value must be yes, no, or not_applicable.', 'answers.*.text_value.string' => 'Answer text must be text.', diff --git a/app/Models/Question.php b/app/Models/Question.php index 486a59e..4a27850 100644 --- a/app/Models/Question.php +++ b/app/Models/Question.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasMany; final class Question extends Model { @@ -48,4 +49,12 @@ public function questionGroup(): BelongsTo { return $this->belongsTo(QuestionGroup::class); } + + /** + * Get all answers for this question. + */ + public function answers(): HasMany + { + return $this->hasMany(Answer::class); + } } diff --git a/app/Models/Role.php b/app/Models/Role.php new file mode 100644 index 0000000..1b15858 --- /dev/null +++ b/app/Models/Role.php @@ -0,0 +1,23 @@ +hasMany(User::class); + } +} diff --git a/app/Models/Session.php b/app/Models/Session.php index be0c1e3..513bf91 100644 --- a/app/Models/Session.php +++ b/app/Models/Session.php @@ -25,7 +25,6 @@ final class Session extends Model 'status', 'score', 'result', - 'basic_info', 'additional_comments', 'completed_at', ]; @@ -40,7 +39,6 @@ protected function casts(): array 'category_id' => 'integer', 'screening_id' => 'integer', 'score' => 'integer', - 'basic_info' => 'array', 'completed_at' => 'datetime', ]; } diff --git a/app/Models/User.php b/app/Models/User.php index 6065d2c..73fb91e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,6 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; @@ -23,6 +24,12 @@ final class User extends Authenticatable 'name', 'email', 'password', + 'azure_id', + 'photo', + 'job_title', + 'department', + 'phone', + 'role_id', ]; /** @@ -33,6 +40,7 @@ final class User extends Authenticatable protected $hidden = [ 'password', 'remember_token', + 'azure_id', ]; /** @@ -45,9 +53,18 @@ protected function casts(): array return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', + 'role_id' => 'integer', ]; } + /** + * Get the role assigned to this user. + */ + public function role(): BelongsTo + { + return $this->belongsTo(Role::class); + } + /** * Get all sessions for this user. */ diff --git a/app/Nova/AnswerResource.php b/app/Nova/AnswerResource.php index 5db5ce3..b57080d 100644 --- a/app/Nova/AnswerResource.php +++ b/app/Nova/AnswerResource.php @@ -49,6 +49,22 @@ final class AnswerResource extends Resource */ public static $with = ['session', 'question']; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Answers'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Answer'; + } + /** * Get the fields displayed by the resource. * @@ -76,6 +92,7 @@ public function fields(NovaRequest $request): array ->rules('nullable', 'max:255'), Textarea::make('Text Value') + ->alwaysShow() ->rules('nullable'), DateTime::make('Created At') diff --git a/app/Nova/CategoryResource.php b/app/Nova/CategoryResource.php index f0733fc..5fb42ec 100644 --- a/app/Nova/CategoryResource.php +++ b/app/Nova/CategoryResource.php @@ -42,6 +42,22 @@ final class CategoryResource extends Resource */ public static $displayInNavigation = false; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Categories'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Category'; + } + /** * Get the fields displayed by the resource. * diff --git a/app/Nova/LogResource.php b/app/Nova/LogResource.php index fecb3c7..84c47e4 100644 --- a/app/Nova/LogResource.php +++ b/app/Nova/LogResource.php @@ -56,6 +56,22 @@ final class LogResource extends Resource */ public static $with = ['user', 'session', 'category']; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Logs'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Log'; + } + /** * Get the fields displayed by the resource. * diff --git a/app/Nova/QuestionGroupResource.php b/app/Nova/QuestionGroupResource.php index 895c115..65957dc 100644 --- a/app/Nova/QuestionGroupResource.php +++ b/app/Nova/QuestionGroupResource.php @@ -44,6 +44,22 @@ final class QuestionGroupResource extends Resource */ public static $displayInNavigation = false; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Question Groups'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Question Group'; + } + /** * Get the fields displayed by the resource. * diff --git a/app/Nova/QuestionResource.php b/app/Nova/QuestionResource.php index 6780167..1d24e43 100644 --- a/app/Nova/QuestionResource.php +++ b/app/Nova/QuestionResource.php @@ -7,6 +7,7 @@ use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Boolean; use Laravel\Nova\Fields\DateTime; +use Laravel\Nova\Fields\HasMany; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Number; use Laravel\Nova\Fields\Text; @@ -51,6 +52,22 @@ final class QuestionResource extends Resource */ public static $group = 'Questionnaire'; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Questions'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Question'; + } + /** * Get the fields displayed by the resource. * @@ -111,6 +128,8 @@ public function fields(NovaRequest $request): array ->exceptOnForms() ->sortable() ->filterable(), + + HasMany::make('Answers', 'answers', AnswerResource::class), ]; } diff --git a/app/Nova/RoleResource.php b/app/Nova/RoleResource.php new file mode 100644 index 0000000..c0481ac --- /dev/null +++ b/app/Nova/RoleResource.php @@ -0,0 +1,75 @@ +sortable(), + + Text::make('Name') + ->sortable() + ->filterable() + ->copyable() + ->rules('required', 'max:255'), + + DateTime::make('Created At') + ->exceptOnForms() + ->sortable(), + + DateTime::make('Updated At') + ->exceptOnForms() + ->sortable(), + + HasMany::make('Users', 'users', User::class), + ]; + } + + public function cards(NovaRequest $request): array + { + return []; + } + + public function filters(NovaRequest $request): array + { + return []; + } + + public function lenses(NovaRequest $request): array + { + return []; + } + + public function actions(NovaRequest $request): array + { + return []; + } +} diff --git a/app/Nova/ScreeningResource.php b/app/Nova/ScreeningResource.php index b31a15f..fe77642 100644 --- a/app/Nova/ScreeningResource.php +++ b/app/Nova/ScreeningResource.php @@ -57,6 +57,22 @@ final class ScreeningResource extends Resource */ public static $with = ['user']; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Screenings'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Screening'; + } + /** * Get the fields displayed by the resource. * diff --git a/app/Nova/SessionResource.php b/app/Nova/SessionResource.php index 1bdb2c4..d0cc6f4 100644 --- a/app/Nova/SessionResource.php +++ b/app/Nova/SessionResource.php @@ -5,12 +5,11 @@ namespace App\Nova; use Laravel\Nova\Fields\BelongsTo; -use Laravel\Nova\Fields\Code; use Laravel\Nova\Fields\DateTime; use Laravel\Nova\Fields\HasMany; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Number; -use Laravel\Nova\Fields\Text; +use Laravel\Nova\Fields\Select; use Laravel\Nova\Fields\Textarea; use Laravel\Nova\Http\Requests\NovaRequest; use Maatwebsite\LaravelNovaExcel\Actions\DownloadExcel; @@ -59,6 +58,22 @@ final class SessionResource extends Resource */ public static $with = ['user', 'category', 'screening']; + /** + * Get the displayable label of the resource. + */ + public static function label(): string + { + return 'Sessions'; + } + + /** + * Get the displayable singular label of the resource. + */ + public static function singularLabel(): string + { + return 'Session'; + } + /** * Get the fields displayed by the resource. * @@ -85,11 +100,16 @@ public function fields(NovaRequest $request): array ->filterable() ->rules('nullable'), - Text::make('Status') + Select::make('Status') + ->options([ + 'in_progress' => 'In Progress', + 'completed' => 'Completed', + 'abandoned' => 'Abandoned', + ]) + ->displayUsingLabels() ->sortable() ->filterable() - ->copyable() - ->rules('required', 'max:255'), + ->readonly(), Number::make('Score') ->sortable() @@ -97,15 +117,16 @@ public function fields(NovaRequest $request): array ->copyable() ->rules('nullable', 'integer'), - Text::make('Result') + Select::make('Result') + ->options([ + 'go' => 'Go', + 'no_go' => 'No Go', + 'consult_leadership' => 'Consult Leadership', + ]) + ->displayUsingLabels() ->sortable() ->filterable() - ->copyable() - ->rules('nullable', 'max:255'), - - Code::make('Basic Info', 'basic_info') - ->json() - ->rules('nullable'), + ->readonly(), Textarea::make('Additional Comments') ->rules('nullable'), diff --git a/app/Nova/User.php b/app/Nova/User.php index aa0d224..b614df0 100644 --- a/app/Nova/User.php +++ b/app/Nova/User.php @@ -6,6 +6,7 @@ use Illuminate\Http\Request; use Laravel\Nova\Auth\PasswordValidationRules; +use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Password; use Laravel\Nova\Fields\Text; @@ -35,7 +36,7 @@ final class User extends Resource * @var array */ public static $search = [ - 'id', 'name', 'email', + 'id', 'name', 'email', 'department', 'job_title', ]; /** @@ -48,6 +49,10 @@ public function fields(NovaRequest $request): array return [ ID::make()->sortable(), + BelongsTo::make('Role', 'role', RoleResource::class) + ->sortable() + ->filterable(), + Text::make('Name') ->sortable() ->rules('required', 'max:255'), @@ -58,6 +63,31 @@ public function fields(NovaRequest $request): array ->creationRules('unique:users,email') ->updateRules('unique:users,email,{{resourceId}}'), + Text::make('Azure ID', 'azure_id') + ->onlyOnDetail() + ->copyable(), + + Text::make('Photo', 'photo') + ->onlyOnDetail() + ->copyable(), + + Text::make('Job Title', 'job_title') + ->sortable() + ->filterable() + ->copyable() + ->readonly(), + + Text::make('Department') + ->sortable() + ->filterable() + ->copyable() + ->readonly(), + + Text::make('Phone') + ->sortable() + ->copyable() + ->readonly(), + Password::make('Password') ->onlyOnForms() ->creationRules($this->passwordRules()) diff --git a/app/Providers/NovaServiceProvider.php b/app/Providers/NovaServiceProvider.php index 4d0d22b..c3aaa86 100644 --- a/app/Providers/NovaServiceProvider.php +++ b/app/Providers/NovaServiceProvider.php @@ -3,8 +3,16 @@ namespace App\Providers; use App\Models\User; +use App\Nova\Dashboards\Main; +use App\Nova\LogResource; +use App\Nova\QuestionResource; +use App\Nova\ScreeningResource; +use App\Nova\SessionResource; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; use Laravel\Fortify\Features; +use Laravel\Nova\Menu\MenuItem; +use Laravel\Nova\Menu\MenuSection; use Laravel\Nova\Nova; use Laravel\Nova\NovaApplicationServiceProvider; @@ -17,7 +25,25 @@ public function boot(): void { parent::boot(); - // + Nova::mainMenu(function (Request $request) { + return [ + MenuSection::dashboard(Main::class)->icon('home'), + + MenuSection::make('Questionnaire', [ + MenuItem::resource(QuestionResource::class), + MenuItem::resource(ScreeningResource::class), + MenuItem::resource(SessionResource::class), + ])->icon('clipboard-document-list')->collapsible(), + + MenuSection::make('Logs', [ + MenuItem::resource(LogResource::class), + ])->icon('chart-bar')->collapsible(), + + MenuSection::make('Users', [ + MenuItem::resource(\App\Nova\User::class), + ])->icon('users')->collapsible(), + ]; + }); } /** diff --git a/database/factories/SessionFactory.php b/database/factories/SessionFactory.php index 8fe5d7e..c10890b 100644 --- a/database/factories/SessionFactory.php +++ b/database/factories/SessionFactory.php @@ -30,7 +30,6 @@ public function definition(): array 'status' => 'in_progress', 'score' => null, 'result' => null, - 'basic_info' => null, 'additional_comments' => null, 'completed_at' => null, ]; diff --git a/database/migrations/0000_00_00_000000_create_roles_table.php b/database/migrations/0000_00_00_000000_create_roles_table.php new file mode 100644 index 0000000..5fea017 --- /dev/null +++ b/database/migrations/0000_00_00_000000_create_roles_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name')->unique(); + $table->timestamps(); + }); + + $now = now(); + + DB::table('roles')->insert([ + ['name' => 'user', 'created_at' => $now, 'updated_at' => $now], + ['name' => 'admin', 'created_at' => $now, 'updated_at' => $now], + ]); + } + + public function down(): void + { + Schema::dropIfExists('roles'); + } +}; diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..5b09d72 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -13,10 +13,16 @@ public function up(): void { Schema::create('users', function (Blueprint $table) { $table->id(); + $table->foreignId('role_id')->default(1)->constrained(); $table->string('name'); $table->string('email')->unique(); + $table->string('azure_id')->nullable()->unique(); + $table->string('photo')->nullable(); + $table->string('job_title')->nullable(); + $table->string('department')->nullable(); + $table->string('phone')->nullable(); $table->timestamp('email_verified_at')->nullable(); - $table->string('password'); + $table->string('password')->nullable(); $table->rememberToken(); $table->timestamps(); }); diff --git a/database/migrations/2026_02_03_083000_create_sessions_table.php b/database/migrations/2026_02_03_083000_create_sessions_table.php index f64526a..0c05b43 100644 --- a/database/migrations/2026_02_03_083000_create_sessions_table.php +++ b/database/migrations/2026_02_03_083000_create_sessions_table.php @@ -21,7 +21,6 @@ public function up(): void $table->string('status', 50)->default('in_progress'); $table->integer('score')->nullable(); $table->string('result', 50)->nullable(); - $table->json('basic_info')->nullable(); $table->text('additional_comments')->nullable(); $table->timestamp('completed_at')->nullable(); $table->timestamps(); diff --git a/database/seeders/JonathanSeeder.php b/database/seeders/JonathanSeeder.php index c9c4ff9..a929074 100644 --- a/database/seeders/JonathanSeeder.php +++ b/database/seeders/JonathanSeeder.php @@ -1,22 +1,28 @@ first(); + User::factory()->create([ 'name' => 'Jonathan', 'email' => 'jonathan@blijnder.nl', 'password' => bcrypt('secret'), 'email_verified_at' => now(), + 'role_id' => $adminRole->id, ]); } } diff --git a/resources/js/Components/AppButton.vue b/resources/js/Components/AppButton.vue index b3f237b..b5854cb 100644 --- a/resources/js/Components/AppButton.vue +++ b/resources/js/Components/AppButton.vue @@ -44,11 +44,11 @@ const buttonClasses = computed(() => { // Size classes if (props.size === 'sm') { - classes.push('px-3 py-1.5 text-sm') + classes.push('px-4 py-2 text-sm') } else if (props.size === 'md') { - classes.push('px-5 py-2.5 text-base') + classes.push('px-6 py-3 text-base') } else if (props.size === 'lg') { - classes.push('px-7 py-3 text-lg') + classes.push('px-8 py-3.5 text-lg') } // Variant classes diff --git a/resources/js/Components/PageHeader.vue b/resources/js/Components/PageHeader.vue index 87a2fdd..d19fd46 100644 --- a/resources/js/Components/PageHeader.vue +++ b/resources/js/Components/PageHeader.vue @@ -1,4 +1,6 @@