24-5: home booking card (strip variant, compact booking) — implemented, QA Review; footer brand layout fix from 24-2

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Naser Mansour
2026-10-31 18:49:28 +02:00
parent 10a4e1f4c0
commit b1ac864573
10 changed files with 433 additions and 5 deletions
@@ -2,6 +2,7 @@
use App\Services\AvailabilityService;
use Carbon\Carbon;
use Livewire\Attributes\Reactive;
use Livewire\Volt\Component;
new class extends Component
@@ -18,12 +19,54 @@ new class extends Component
public array $bookedDates = [];
public string $variant = 'month';
#[Reactive]
public ?string $pickedDate = null;
#[Reactive]
public ?string $pickedTime = null;
public function mount(array $bookedDates = []): void
{
$this->bookedDates = $bookedDates;
$this->year = now()->year;
$this->month = now()->month;
$this->loadMonthAvailability();
if ($this->variant === 'strip') {
$first = $this->buildStripDays()[0]['date'] ?? null;
if ($first) {
$this->selectedDate = $first;
$this->loadAvailableSlots();
}
}
}
/**
* The next 14 days (looking up to 60 days ahead) that can be booked.
*
* @return array<int, array{date: string, label: string, day: int}>
*/
private function buildStripDays(): array
{
$service = app(AvailabilityService::class);
$days = [];
for ($i = 0; $i < 60 && count($days) < 14; $i++) {
$date = today()->addDays($i);
if (in_array($service->getDateStatus($date), ['available', 'partial'])) {
$days[] = [
'date' => $date->format('Y-m-d'),
'label' => $date->translatedFormat('l'),
'day' => $date->day,
];
}
}
return $days;
}
public function loadMonthAvailability(): void
@@ -65,7 +108,9 @@ new class extends Component
return;
}
$status = $this->monthAvailability[$date] ?? 'unavailable';
$status = $this->variant === 'strip'
? app(AvailabilityService::class)->getDateStatus(Carbon::parse($date))
: ($this->monthAvailability[$date] ?? 'unavailable');
if (in_array($status, ['available', 'partial'])) {
$this->selectedDate = $date;
@@ -151,11 +196,47 @@ new class extends Component
'calendarDays' => $this->buildCalendarDays(),
'dayHeaders' => $this->getDayHeaders(),
'bookedDates' => $this->bookedDates,
'stripDays' => $this->variant === 'strip' ? $this->buildStripDays() : [],
];
}
}; ?>
<div>
@if($variant === 'strip')
@if(count($stripDays) > 0)
<span class="strip-label">{{ __('site.booking_day') }}</span>
<div class="days" role="group" aria-label="{{ __('site.booking_day') }}">
@foreach($stripDays as $day)
<button
type="button"
class="day"
aria-pressed="{{ $selectedDate === $day['date'] ? 'true' : 'false' }}"
wire:click="selectDate('{{ $day['date'] }}')"
>
{{ $day['label'] }}
<b>{{ $day['day'] }}</b>
</button>
@endforeach
</div>
<span class="strip-label">{{ __('site.booking_time') }}</span>
<div class="slots" role="group" aria-label="{{ __('site.booking_time') }}">
@foreach($availableSlots as $slot)
<button
type="button"
class="slot"
dir="ltr"
aria-pressed="{{ $pickedDate === $selectedDate && $pickedTime === $slot ? 'true' : 'false' }}"
wire:click="$parent.selectSlot('{{ $selectedDate }}', '{{ $slot }}')"
>
{{ \Carbon\Carbon::parse($slot)->format('g:i A') }}
</button>
@endforeach
</div>
@else
<p class="strip-none">{{ __('site.booking_none') }}</p>
@endif
@else
<!-- Calendar Header -->
<div class="flex items-center justify-between mb-4">
<flux:button size="sm" wire:click="previousMonth" variant="outline">
@@ -248,4 +329,5 @@ new class extends Component
<span class="text-zinc-600">{{ __('booking.unavailable') }}</span>
</div>
</div>
@endif
</div>