107 lines
5.3 KiB
PHP
107 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Services\Availability\AvailabilityService;
|
|
use App\Services\Booking\BookingService;
|
|
use App\Services\Tenant\TenantContext;
|
|
use App\Models\Appointment;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
use Throwable;
|
|
|
|
class BookingController extends Controller
|
|
{
|
|
public function services(TenantContext $tenant): View
|
|
{
|
|
$business = $tenant->require();
|
|
$categories = $business->serviceCategories()->where('isActive', true)->with(['services' => fn ($query) => $query->where('isActive', true)->where('allowOnlineBooking', true)->orderBy('displayOrder')])->orderBy('displayOrder')->get();
|
|
return view('booking.services', compact('business', 'categories'));
|
|
}
|
|
|
|
public function selectServices(Request $request): RedirectResponse
|
|
{
|
|
$ids = array_values(array_filter((array) $request->input('serviceIds')));
|
|
if ($ids === []) return back()->withErrors(['serviceIds' => 'Choose at least one service.']);
|
|
$request->session()->put('booking.serviceIds', $ids);
|
|
return redirect()->route('booking.time');
|
|
}
|
|
|
|
public function time(Request $request, TenantContext $tenant, AvailabilityService $availability): View|RedirectResponse
|
|
{
|
|
$business = $tenant->require();
|
|
$serviceIds = $request->session()->get('booking.serviceIds', []);
|
|
if ($serviceIds === []) return redirect()->route('booking.services');
|
|
$date = CarbonImmutable::parse($request->query('date', now($business->timezone)->toDateString()), $business->timezone);
|
|
$slots = $availability->slots($business, $date, $serviceIds);
|
|
$services = $business->services()->whereIn('id', $serviceIds)->get();
|
|
return view('booking.time', compact('business', 'date', 'slots', 'services'));
|
|
}
|
|
|
|
public function selectTime(Request $request): RedirectResponse
|
|
{
|
|
$validated = $request->validate(['staffId' => ['required', 'string'], 'startAt' => ['required', 'date']]);
|
|
$request->session()->put('booking.time', $validated);
|
|
return redirect()->route('booking.details');
|
|
}
|
|
|
|
public function details(Request $request, TenantContext $tenant): View|RedirectResponse
|
|
{
|
|
$business = $tenant->require();
|
|
if (! $request->session()->has('booking.time')) return redirect()->route('booking.time');
|
|
return view('booking.details', compact('business'));
|
|
}
|
|
|
|
public function saveDetails(Request $request): RedirectResponse
|
|
{
|
|
$validated = $request->validate(['firstName' => ['required', 'string', 'max:80'], 'lastName' => ['required', 'string', 'max:80'], 'email' => ['required', 'email', 'max:190'], 'phone' => ['nullable', 'string', 'max:40'], 'notes' => ['nullable', 'string', 'max:2000']]);
|
|
$request->session()->put('booking.customer', $validated);
|
|
return redirect()->route('booking.review');
|
|
}
|
|
|
|
public function review(Request $request, TenantContext $tenant): View|RedirectResponse
|
|
{
|
|
$business = $tenant->require();
|
|
$draft = $request->session()->get('booking');
|
|
if (! isset($draft['serviceIds'], $draft['time'], $draft['customer'])) return redirect()->route('booking.services');
|
|
$services = $business->services()->whereIn('id', $draft['serviceIds'])->get();
|
|
$staff = $business->staff()->with('user')->find($draft['time']['staffId']);
|
|
if (! $staff) return redirect()->route('booking.time')->withErrors(['time' => 'That barber is no longer available.']);
|
|
return view('booking.review', ['business' => $business, 'services' => $services, 'staff' => $staff, 'draft' => $draft, 'total' => $services->sum('price')]);
|
|
}
|
|
|
|
public function confirm(Request $request, TenantContext $tenant, BookingService $booking): RedirectResponse
|
|
{
|
|
$business = $tenant->require();
|
|
$draft = $request->session()->get('booking');
|
|
if (! isset($draft['serviceIds'], $draft['time'], $draft['customer'])) return redirect()->route('booking.services');
|
|
try {
|
|
$result = $booking->create($business, array_merge($draft['customer'], $draft['time'], ['serviceIds' => $draft['serviceIds']]));
|
|
} catch (Throwable $exception) {
|
|
return redirect()->route('booking.time')->withErrors(['booking' => $exception->getMessage()]);
|
|
}
|
|
$request->session()->forget('booking');
|
|
$request->session()->put('booking.result', [
|
|
'appointmentId' => $result['appointment']->id,
|
|
'accessToken' => $result['accessToken'],
|
|
]);
|
|
return redirect()->route('booking.confirmation');
|
|
}
|
|
|
|
public function confirmation(Request $request, TenantContext $tenant): View|RedirectResponse
|
|
{
|
|
$business = $tenant->require();
|
|
$result = $request->session()->get('booking.result');
|
|
if (! $result) return redirect()->route('public.home');
|
|
$request->session()->forget('booking.result');
|
|
$appointment = Appointment::query()
|
|
->where('businessId', $business->id)
|
|
->with(['customer', 'staff.user', 'services.service'])
|
|
->find($result['appointmentId'] ?? null);
|
|
if (! $appointment) return redirect()->route('public.home');
|
|
return view('booking.confirmation', compact('business', 'appointment'));
|
|
}
|
|
}
|