started on the 2 step register process
This commit is contained in:
@@ -33,12 +33,31 @@ class RegisteredUserController extends Controller
|
|||||||
'name' => ['required', 'string', 'max:255'],
|
'name' => ['required', 'string', 'max:255'],
|
||||||
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||||
|
// Fitness profile (all optional to avoid breaking tests unless specified)
|
||||||
|
'age' => ['nullable', 'integer', 'min:5', 'max:120'],
|
||||||
|
'weight_kg' => ['nullable', 'numeric', 'min:20', 'max:400'],
|
||||||
|
'height_cm' => ['nullable', 'numeric', 'min:80', 'max:250'],
|
||||||
|
'fitness_level' => ['nullable', 'in:beginner,intermediate,advanced'],
|
||||||
|
'goal' => ['nullable', 'string', 'max:50'],
|
||||||
|
'health_notes' => ['nullable', 'string', 'max:65535'],
|
||||||
|
'available_equipment' => ['nullable', 'string', 'max:65535'],
|
||||||
|
'days_per_week' => ['nullable', 'integer', 'min:1', 'max:7'],
|
||||||
|
'minutes_per_session' => ['nullable', 'integer', 'min:5', 'max:600'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
'name' => $request->name,
|
'name' => $request->name,
|
||||||
'email' => $request->email,
|
'email' => $request->email,
|
||||||
'password' => Hash::make($request->password),
|
'password' => Hash::make($request->password),
|
||||||
|
'age' => $request->age,
|
||||||
|
'weight_kg' => $request->weight_kg,
|
||||||
|
'height_cm' => $request->height_cm,
|
||||||
|
'fitness_level' => $request->fitness_level,
|
||||||
|
'goal' => $request->goal,
|
||||||
|
'health_notes' => $request->health_notes,
|
||||||
|
'available_equipment' => $request->available_equipment,
|
||||||
|
'days_per_week' => $request->days_per_week,
|
||||||
|
'minutes_per_session' => $request->minutes_per_session,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new Registered($user));
|
event(new Registered($user));
|
||||||
|
|||||||
@@ -21,6 +21,15 @@ class User extends Authenticatable
|
|||||||
'name',
|
'name',
|
||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
|
'age',
|
||||||
|
'weight_kg',
|
||||||
|
'height_cm',
|
||||||
|
'fitness_level',
|
||||||
|
'goal',
|
||||||
|
'health_notes',
|
||||||
|
'available_equipment',
|
||||||
|
'days_per_week',
|
||||||
|
'minutes_per_session',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,6 +52,11 @@ class User extends Authenticatable
|
|||||||
return [
|
return [
|
||||||
'email_verified_at' => 'datetime',
|
'email_verified_at' => 'datetime',
|
||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
|
'age' => 'integer',
|
||||||
|
'weight_kg' => 'decimal:2',
|
||||||
|
'height_cm' => 'decimal:2',
|
||||||
|
'days_per_week' => 'integer',
|
||||||
|
'minutes_per_session' => 'integer',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->unsignedTinyInteger('age')->nullable()->after('email_verified_at');
|
||||||
|
$table->decimal('weight_kg', 5, 2)->nullable()->after('age');
|
||||||
|
$table->decimal('height_cm', 5, 2)->nullable()->after('weight_kg');
|
||||||
|
$table->string('fitness_level', 20)->nullable()->after('height_cm'); // beginner, intermediate, advanced
|
||||||
|
$table->string('goal', 50)->nullable()->after('fitness_level'); // strength, endurance, weight_loss, hypertrophy, mobility, etc
|
||||||
|
$table->text('health_notes')->nullable()->after('goal'); // health conditions / injuries
|
||||||
|
$table->text('available_equipment')->nullable()->after('health_notes');
|
||||||
|
$table->unsignedTinyInteger('days_per_week')->nullable()->after('available_equipment');
|
||||||
|
$table->unsignedSmallInteger('minutes_per_session')->nullable()->after('days_per_week');
|
||||||
|
$table->index(['fitness_level', 'goal']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropIndex(['fitness_level', 'goal']);
|
||||||
|
$table->dropColumn([
|
||||||
|
'age',
|
||||||
|
'weight_kg',
|
||||||
|
'height_cm',
|
||||||
|
'fitness_level',
|
||||||
|
'goal',
|
||||||
|
'health_notes',
|
||||||
|
'available_equipment',
|
||||||
|
'days_per_week',
|
||||||
|
'minutes_per_session',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -161,4 +161,51 @@ return [
|
|||||||
'similar' => 'Similar poses',
|
'similar' => 'Similar poses',
|
||||||
'similar_none' => 'No similar poses found.',
|
'similar_none' => 'No similar poses found.',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'auth' => [
|
||||||
|
'register' => [
|
||||||
|
'age' => 'Age',
|
||||||
|
'weight_kg' => 'Weight (kg)',
|
||||||
|
'height_cm' => 'Height (cm)',
|
||||||
|
'fitness_level' => 'Fitness level',
|
||||||
|
'goal' => 'Primary goal',
|
||||||
|
'health_notes' => 'Health conditions or injuries',
|
||||||
|
'available_equipment' => 'Available equipment',
|
||||||
|
'available_equipment_ph' => 'e.g. dumbbells, barbell, kettlebell, bands, pull-up bar',
|
||||||
|
'days_per_week' => 'Days per week',
|
||||||
|
'minutes_per_session' => 'Minutes per session',
|
||||||
|
'select_optional' => 'Select (optional)',
|
||||||
|
'levels' => [
|
||||||
|
'beginner' => 'Beginner',
|
||||||
|
'intermediate' => 'Intermediate',
|
||||||
|
'advanced' => 'Advanced',
|
||||||
|
],
|
||||||
|
'goals' => [
|
||||||
|
'strength' => 'Strength',
|
||||||
|
'endurance' => 'Endurance',
|
||||||
|
'weight_loss' => 'Weight loss',
|
||||||
|
'hypertrophy' => 'Hypertrophy',
|
||||||
|
'mobility' => 'Mobility',
|
||||||
|
],
|
||||||
|
'steps' => [
|
||||||
|
'step1_title' => 'Create your account',
|
||||||
|
'step2_title' => 'Tell us about your fitness profile (optional)',
|
||||||
|
'next' => 'Next',
|
||||||
|
'back' => 'Back',
|
||||||
|
'register' => 'Register',
|
||||||
|
],
|
||||||
|
'equipment_options' => [
|
||||||
|
'dumbbells' => 'Dumbbells',
|
||||||
|
'barbell' => 'Barbell',
|
||||||
|
'kettlebell' => 'Kettlebell',
|
||||||
|
'bands' => 'Resistance bands',
|
||||||
|
'pullup_bar' => 'Pull-up bar',
|
||||||
|
'bench' => 'Bench',
|
||||||
|
'machines' => 'Gym machines',
|
||||||
|
'yoga_mat' => 'Yoga mat',
|
||||||
|
'treadmill' => 'Treadmill',
|
||||||
|
'bodyweight' => 'Bodyweight only',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -161,4 +161,51 @@ return [
|
|||||||
'similar' => 'Poziții similare',
|
'similar' => 'Poziții similare',
|
||||||
'similar_none' => 'Nu s-au găsit poziții similare.',
|
'similar_none' => 'Nu s-au găsit poziții similare.',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'auth' => [
|
||||||
|
'register' => [
|
||||||
|
'age' => 'Vârstă',
|
||||||
|
'weight_kg' => 'Greutate (kg)',
|
||||||
|
'height_cm' => 'Înălțime (cm)',
|
||||||
|
'fitness_level' => 'Nivel de fitness',
|
||||||
|
'goal' => 'Obiectiv principal',
|
||||||
|
'health_notes' => 'Afectiuni de sănătate sau accidentări',
|
||||||
|
'available_equipment' => 'Echipament disponibil',
|
||||||
|
'available_equipment_ph' => 'ex: gantere, bară, kettlebell, benzi, bară de tracțiuni',
|
||||||
|
'days_per_week' => 'Zile pe săptămână',
|
||||||
|
'minutes_per_session' => 'Minute pe sesiune',
|
||||||
|
'select_optional' => 'Selectează (opțional)',
|
||||||
|
'levels' => [
|
||||||
|
'beginner' => 'Începător',
|
||||||
|
'intermediate' => 'Intermediar',
|
||||||
|
'advanced' => 'Avansat',
|
||||||
|
],
|
||||||
|
'goals' => [
|
||||||
|
'strength' => 'Forță',
|
||||||
|
'endurance' => 'Anduranță',
|
||||||
|
'weight_loss' => 'Scădere în greutate',
|
||||||
|
'hypertrophy' => 'Hipertrofie',
|
||||||
|
'mobility' => 'Mobilitate',
|
||||||
|
],
|
||||||
|
'steps' => [
|
||||||
|
'step1_title' => 'Creează-ți contul',
|
||||||
|
'step2_title' => 'Spune-ne despre profilul tău de fitness (opțional)',
|
||||||
|
'next' => 'Înainte',
|
||||||
|
'back' => 'Înapoi',
|
||||||
|
'register' => 'Înregistrare',
|
||||||
|
],
|
||||||
|
'equipment_options' => [
|
||||||
|
'dumbbells' => 'Gantere',
|
||||||
|
'barbell' => 'Bară',
|
||||||
|
'kettlebell' => 'Kettlebell',
|
||||||
|
'bands' => 'Benzi elastice',
|
||||||
|
'pullup_bar' => 'Bară de tracțiuni',
|
||||||
|
'bench' => 'Bancă',
|
||||||
|
'machines' => 'Aparate',
|
||||||
|
'yoga_mat' => 'Saltea de yoga',
|
||||||
|
'treadmill' => 'Banda de alergare',
|
||||||
|
'bodyweight' => 'Doar greutatea corpului',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,7 +1,22 @@
|
|||||||
<x-guest-layout>
|
<x-guest-layout>
|
||||||
<form method="POST" action="{{ route('register') }}">
|
<form method="POST" action="{{ route('register') }}" x-data="registerSteps()" x-init="init()" @keydown.enter.prevent="onEnter($event)">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
|
<!-- Step indicator (visually simple) -->
|
||||||
|
<div class="mb-6 flex items-center gap-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div :class="step===1?'bg-indigo-600 text-white':'bg-gray-200 text-gray-700'" class="h-6 w-6 rounded-full flex items-center justify-center text-xs font-bold">1</div>
|
||||||
|
<div class="text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('app.auth.register.steps.step1_title') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="h-px w-8 bg-gray-300 dark:bg-gray-700"></div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div :class="step===2?'bg-indigo-600 text-white':'bg-gray-200 text-gray-700'" class="h-6 w-6 rounded-full flex items-center justify-center text-xs font-bold">2</div>
|
||||||
|
<div class="text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('app.auth.register.steps.step2_title') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 1: account basics -->
|
||||||
|
<div x-show="step===1" x-cloak>
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div>
|
<div>
|
||||||
<x-input-label for="name" :value="__('Name')" />
|
<x-input-label for="name" :value="__('Name')" />
|
||||||
@@ -19,34 +34,178 @@
|
|||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<x-input-label for="password" :value="__('Password')" />
|
<x-input-label for="password" :value="__('Password')" />
|
||||||
|
<x-text-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
|
||||||
<x-text-input id="password" class="block mt-1 w-full"
|
|
||||||
type="password"
|
|
||||||
name="password"
|
|
||||||
required autocomplete="new-password" />
|
|
||||||
|
|
||||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Confirm Password -->
|
<!-- Confirm Password -->
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
||||||
|
<x-text-input id="password_confirmation" class="block mt-1 w-full" type="password" name="password_confirmation" required autocomplete="new-password" />
|
||||||
<x-text-input id="password_confirmation" class="block mt-1 w-full"
|
|
||||||
type="password"
|
|
||||||
name="password_confirmation" required autocomplete="new-password" />
|
|
||||||
|
|
||||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end mt-4">
|
<div class="flex items-center justify-end mt-6">
|
||||||
<a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="{{ route('login') }}">
|
<a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="{{ route('login') }}">
|
||||||
{{ __('Already registered?') }}
|
{{ __('Already registered?') }}
|
||||||
</a>
|
</a>
|
||||||
|
<button type="button" @click="goNext()" class="ms-4 inline-flex items-center rounded-md bg-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow hover:bg-indigo-500">{{ __('app.auth.register.steps.next') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 2: fitness profile (optional) -->
|
||||||
|
<div x-show="step===2" x-cloak>
|
||||||
|
<div class="mt-4 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<x-input-label for="age" :value="__('app.auth.register.age')" />
|
||||||
|
<x-text-input id="age" class="block mt-1 w-full" type="number" min="5" max="120" name="age" :value="old('age')" />
|
||||||
|
<x-input-error :messages="$errors->get('age')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<x-input-label for="height_cm" :value="__('app.auth.register.height_cm')" />
|
||||||
|
<x-text-input id="height_cm" class="block mt-1 w-full" type="number" step="0.5" min="80" max="250" name="height_cm" :value="old('height_cm')" />
|
||||||
|
<x-input-error :messages="$errors->get('height_cm')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<x-input-label for="weight_kg" :value="__('app.auth.register.weight_kg')" />
|
||||||
|
<x-text-input id="weight_kg" class="block mt-1 w-full" type="number" step="0.1" min="20" max="400" name="weight_kg" :value="old('weight_kg')" />
|
||||||
|
<x-input-error :messages="$errors->get('weight_kg')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<x-input-label for="fitness_level" :value="__('app.auth.register.fitness_level')" />
|
||||||
|
<select id="fitness_level" name="fitness_level" class="block mt-1 w-full rounded-md border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||||
|
<option value="">{{ __('app.auth.register.select_optional') }}</option>
|
||||||
|
<option value="beginner" @selected(old('fitness_level')==='beginner')>{{ __('app.auth.register.levels.beginner') }}</option>
|
||||||
|
<option value="intermediate" @selected(old('fitness_level')==='intermediate')>{{ __('app.auth.register.levels.intermediate') }}</option>
|
||||||
|
<option value="advanced" @selected(old('fitness_level')==='advanced')>{{ __('app.auth.register.levels.advanced') }}</option>
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('fitness_level')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<x-input-label for="goal" :value="__('app.auth.register.goal')" />
|
||||||
|
<select id="goal" name="goal" class="block mt-1 w-full rounded-md border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||||
|
<option value="">{{ __('app.auth.register.select_optional') }}</option>
|
||||||
|
<option value="strength" @selected(old('goal')==='strength')>{{ __('app.auth.register.goals.strength') }}</option>
|
||||||
|
<option value="endurance" @selected(old('goal')==='endurance')>{{ __('app.auth.register.goals.endurance') }}</option>
|
||||||
|
<option value="weight_loss" @selected(old('goal')==='weight_loss')>{{ __('app.auth.register.goals.weight_loss') }}</option>
|
||||||
|
<option value="hypertrophy" @selected(old('goal')==='hypertrophy')>{{ __('app.auth.register.goals.hypertrophy') }}</option>
|
||||||
|
<option value="mobility" @selected(old('goal')==='mobility')>{{ __('app.auth.register.goals.mobility') }}</option>
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('goal')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<x-input-label for="health_notes" :value="__('app.auth.register.health_notes')" />
|
||||||
|
<textarea id="health_notes" name="health_notes" rows="3" class="block mt-1 w-full rounded-md border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">{{ old('health_notes') }}</textarea>
|
||||||
|
<x-input-error :messages="$errors->get('health_notes')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Available equipment icon grid -->
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<x-input-label for="available_equipment" :value="__('app.auth.register.available_equipment')" />
|
||||||
|
<input type="hidden" id="available_equipment" name="available_equipment" value="{{ old('available_equipment') }}">
|
||||||
|
@php
|
||||||
|
$equipmentOptions = [
|
||||||
|
// Simple, high-contrast stroke-based icons to ensure visibility
|
||||||
|
['key' => 'dumbbells', 'icon' => '<path d="M2 10h3v4H2v-4Zm17 0h3v4h-3v-4ZM7 9h3v6H7V9Zm7 0h3v6h-3V9Zm-3 2h2v2h-2v-2Z"/>'],
|
||||||
|
['key' => 'barbell', 'icon' => '<path d="M3 10h2v4H3v-4Zm4-2h2v8H7V8Zm6 0h2v8h-2V8Zm6 2h2v4h-2v-4ZM5 11h14v2H5v-2Z"/>'],
|
||||||
|
['key' => 'kettlebell', 'icon' => '<path d="M9 9a3 3 0 1 1 6 0v1H9V9Zm-2 6a5 5 0 1 1 10 0v2a3 3 0 0 1-3 3H10a3 3 0 0 1-3-3v-2Z"/>'],
|
||||||
|
['key' => 'bands', 'icon' => '<path d="M4 8c3-3 13-3 16 0M4 12c3-3 13-3 16 0M4 16c3-3 13-3 16 0"/>'],
|
||||||
|
['key' => 'pullup_bar', 'icon' => '<path d="M3 7h18v2H3V7Zm4 2h2v8H7V9Zm8 0h2v8h-2V9Z"/>'],
|
||||||
|
['key' => 'bench', 'icon' => '<path d="M5 13h14v2H5v-2Zm2 2h2v3H7v-3Zm8 0h2v3h-2v-3Z"/>'],
|
||||||
|
['key' => 'machines', 'icon' => '<rect x="6" y="6" width="12" height="12" rx="2"/><rect x="9" y="8" width="6" height="8" rx="1"/>'],
|
||||||
|
['key' => 'yoga_mat', 'icon' => '<path d="M5 17l9-9a3 3 0 1 1 4 4l-9 9a3 3 0 1 1-4-4Z"/>'],
|
||||||
|
['key' => 'treadmill', 'icon' => '<path d="M4 17h10l4-8h2l-5 10H4v-2Zm2-8h6v2H6V9Z"/>'],
|
||||||
|
['key' => 'bodyweight', 'icon' => '<circle cx="12" cy="6" r="2"/><path d="M9 10h6l3 5h-2v5h-2v-4h-2v4H10v-5H8l1-2.5V10Z"/>'],
|
||||||
|
];
|
||||||
|
$oldEquip = collect(explode(',', (string) old('available_equipment')))->map(fn($s)=>trim($s))->filter()->values()->all();
|
||||||
|
@endphp
|
||||||
|
<div class="mt-3 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
|
||||||
|
@foreach($equipmentOptions as $opt)
|
||||||
|
@php $selected = in_array($opt['key'], $oldEquip, true); @endphp
|
||||||
|
<button type="button" class="equip-option group flex items-center gap-3 rounded-xl border-2 px-4 py-3 text-base select-none transition transform hover:-translate-y-0.5 hover:shadow focus:outline-none focus:ring-2 focus:ring-indigo-500/60 cursor-pointer {{ $selected ? 'border-indigo-500 bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 shadow' : 'border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-800 dark:text-gray-200' }}" data-key="{{ $opt['key'] }}" aria-pressed="{{ $selected ? 'true' : 'false' }}" aria-label="{{ __('app.auth.register.equipment_options.' . $opt['key']) }}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-8 w-8 {{ $selected ? 'text-indigo-600' : 'text-gray-500' }}">{!! $opt['icon'] !!}</svg>
|
||||||
|
<span class="">{{ __('app.auth.register.equipment_options.' . $opt['key']) }}</span>
|
||||||
|
</button>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
<p class="mt-2 text-xs text-gray-500">{{ __('app.auth.register.available_equipment_ph') }}</p>
|
||||||
|
<x-input-error :messages="$errors->get('available_equipment')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<x-input-label for="days_per_week" :value="__('app.auth.register.days_per_week')" />
|
||||||
|
<x-text-input id="days_per_week" class="block mt-1 w-full" type="number" min="1" max="7" name="days_per_week" :value="old('days_per_week')" />
|
||||||
|
<x-input-error :messages="$errors->get('days_per_week')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<x-input-label for="minutes_per_session" :value="__('app.auth.register.minutes_per_session')" />
|
||||||
|
<x-text-input id="minutes_per_session" class="block mt-1 w-full" type="number" min="5" max="600" name="minutes_per_session" :value="old('minutes_per_session')" />
|
||||||
|
<x-input-error :messages="$errors->get('minutes_per_session')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between mt-6">
|
||||||
|
<button type="button" @click="goBack()" class="inline-flex items-center rounded-md border border-gray-300 dark:border-gray-700 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-800">{{ __('app.auth.register.steps.back') }}</button>
|
||||||
<x-primary-button class="ms-4">
|
<x-primary-button class="ms-4">
|
||||||
{{ __('Register') }}
|
{{ __('app.auth.register.steps.register') }}
|
||||||
</x-primary-button>
|
</x-primary-button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function registerSteps(){
|
||||||
|
return {
|
||||||
|
step: 1,
|
||||||
|
init(){
|
||||||
|
// Attach equipment toggles
|
||||||
|
const hidden = document.getElementById('available_equipment');
|
||||||
|
const selected = new Set((hidden.value||'').split(',').map(s=>s.trim()).filter(Boolean));
|
||||||
|
const sync = ()=>{ hidden.value = Array.from(selected).join(','); };
|
||||||
|
document.querySelectorAll('.equip-option').forEach(btn=>{
|
||||||
|
btn.addEventListener('click', ()=>{
|
||||||
|
const key = btn.getAttribute('data-key');
|
||||||
|
const isOn = btn.getAttribute('aria-pressed') === 'true';
|
||||||
|
if (isOn) {
|
||||||
|
btn.setAttribute('aria-pressed','false');
|
||||||
|
btn.classList.remove('border-indigo-500','bg-indigo-50','dark:bg-indigo-900/30','text-indigo-700','dark:text-indigo-300','shadow');
|
||||||
|
btn.classList.add('border-gray-300','dark:border-gray-700','bg-white','dark:bg-gray-900','text-gray-800','dark:text-gray-200');
|
||||||
|
selected.delete(key);
|
||||||
|
} else {
|
||||||
|
btn.setAttribute('aria-pressed','true');
|
||||||
|
btn.classList.add('border-indigo-500','bg-indigo-50','dark:bg-indigo-900/30','text-indigo-700','dark:text-indigo-300','shadow');
|
||||||
|
btn.classList.remove('border-gray-300','dark:border-gray-700','bg-white','dark:bg-gray-900','text-gray-800','dark:text-gray-200');
|
||||||
|
selected.add(key);
|
||||||
|
}
|
||||||
|
const icon = btn.querySelector('svg');
|
||||||
|
if (icon) {
|
||||||
|
icon.classList.toggle('text-indigo-600', !isOn);
|
||||||
|
icon.classList.toggle('text-gray-500', isOn);
|
||||||
|
}
|
||||||
|
sync();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
goNext(){
|
||||||
|
// basic HTML5 validity check for step 1
|
||||||
|
const name = document.getElementById('name');
|
||||||
|
const email = document.getElementById('email');
|
||||||
|
const pass = document.getElementById('password');
|
||||||
|
const pass2 = document.getElementById('password_confirmation');
|
||||||
|
if (name.checkValidity() && email.checkValidity() && pass.checkValidity() && pass2.checkValidity()) {
|
||||||
|
this.step = 2;
|
||||||
|
// focus first optional field
|
||||||
|
setTimeout(()=>{ const age = document.getElementById('age'); if (age) age.focus(); }, 0);
|
||||||
|
} else {
|
||||||
|
// trigger browser messages
|
||||||
|
[name,email,pass,pass2].forEach(i=>!i.checkValidity() && i.reportValidity());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goBack(){ this.step = 1; setTimeout(()=>{ const name = document.getElementById('name'); if (name) name.focus(); }, 0); },
|
||||||
|
onEnter(e){
|
||||||
|
if (this.step===1) { this.goNext(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</form>
|
</form>
|
||||||
</x-guest-layout>
|
</x-guest-layout>
|
||||||
|
|||||||
Reference in New Issue
Block a user