Just to clarify before I give any suggestions: Currently the validation works when you leave more time between adding the reservations but not when you add them close after each other right?
Why is validation not working properly?
Hello everyone, I am experiencing an issue with form validation after submission. I attempted to create two reservations simultaneously in separate browsers. Although they were not created at exactly the same time, I have configured the system such that a reservation can only have one unique available business hour ID. However, I am still able to create two reservations for the same unique available business hour ID at the same time. I cannot figure out why this is happening.
this is my component
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Reservation;
use App\Mail\ReservationMail;
use Illuminate\Support\Facades\Mail;
use App\Models\AvailableBusinessHour;
class Booking extends Component
{
public $full_name;
public $email;
public $phone_number;
public $reservation;
public $selectedService;
public $available_business_hour_id;
public $selectedBusinessHourId;
public $verification_code;
public $successMessage;
public $successMessageVisible;
public $successMessageTimeout = 3000;
public $verificationCodeSubmitted = false;
public $successMessageClosed = false;
public function getAvailableBusinessHours()
{
return AvailableBusinessHour::whereDoesntHave('reservation')
->where(function ($query) {
$query->where('day', '>', now()->format('Y-m-d'))
->orWhere(function ($query) {
$query->where('day', '=', now()->format('Y-m-d'))
->where('from', '>', now()->format('H:i'));
});
})
->orderBy('day')
->orderBy('from')
->get();
}
public function render()
{
$this->available_business_hour_id = $this->getAvailableBusinessHours();
return view('livewire.booking', [
'emptyOption' => 'Vyber si čas rezervace',
]);
}
public function store()
{
$this->validate([
'full_name' => 'required|string|max:250',
'email' => 'required|email|max:250',
'phone_number' => 'required|phone:CZ',
'selectedService' => 'required',
'available_business_hour_id' => 'required|unique:reservations'
], [
'available_business_hour_id.unique' => 'Tento termín byl již obsazen, vyber jiný pokud je nějaký dostupný.',
'available_business_hour_id.required' => 'Výběr času objednání je povinné pole.',
'phone_number.phone' => 'Chybný formát telefonního čísla.',
'selectedService.required' => 'Toto je povinné pole',
]);
$selectedBusinessHour = AvailableBusinessHour::find($this->selectedBusinessHourId);
if (
$selectedBusinessHour->day < now()->format('Y-m-d') ||
($selectedBusinessHour->day == now()->format('Y-m-d') && $selectedBusinessHour->from < now()->format('H:i'))
) {
$this->addError('selectedBusinessHourId', 'Tento termín již není dostupný, vyber jiný.');
return;
}
$verification_code = rand(100000, 999999);
$reservation = Reservation::create([
'full_name' => $this->full_name,
'email' => $this->email,
'phone_number' => $this->phone_number,
'service' => $this->selectedService,
'available_business_hour_id' => $this->selectedBusinessHourId,
'day' => $selectedBusinessHour['day'],
'from' => $selectedBusinessHour['from'],
'to' => $selectedBusinessHour['to'],
'verification_code' => $verification_code
]);
dd($reservation);
session(['verification_code' => $verification_code, 'current_reservation_id' => $reservation->id]);
$this->sendReservationConfirmationMail($reservation);
$this->dispatch('show-verification-modal');
$this->dispatch('update-success-message', ['closed' => $this->successMessageClosed]);
$this->reset(['full_name', 'email', 'phone_number', 'available_business_hour_id']);
}
public function sendReservationConfirmationMail($reservation)
{
Mail::to($reservation->email)->send(new ReservationMail($reservation));
}
public function services()
{
return ["Stříhání vlasů", "Stříhání + úprava vousů", "Barvení vousů", "Junior střih", "Úprava vousů"];
}
public function confirmReservation()
{
$this->validate([
'verification_code' => 'required|digits:6',
], [
'verification_code.required' => 'Zadejte prosím verifikační kód.',
'verification_code.digits' => 'Verifikační kód musí mít 6 čísel.',
]);
$user_entered_code = $this->verification_code;
$reservation = Reservation::where('verification_code', $user_entered_code)
->where('is_confirmed', false)
->where('id', session('current_reservation_id'))
->latest()
->first();
if ($reservation) {
$reservation->update(['is_confirmed' => true]);
$this->reset(['verification_code']);
$this->successMessage = 'Rezervace proběhla úspěšně.';
$this->successMessageVisible = true;
$this->dispatch('hide-verification-modal');
$this->dispatch('update-success-message', ['closed' => $this->successMessageClosed]);
} else {
$this->addError('verification_code', 'Neplatný verifikační kód nebo rezervace již byla potvrzena.');
}
}
}
this is blade
<div class="container">
@if ($successMessageVisible && !$verificationCodeSubmitted)
<div x-data="{ show: @entangle('successMessageVisible'), closed: @entangle('successMessageClosed') }" x-init="setTimeout(() => { show = false; if (!closed) Livewire.emit('refresh-view'); }, {{ $successMessageTimeout }})" x-show="show" class="alert alert-success text-center">
{{ $successMessage }}
</div>
@endif
<form wire:submit.prevent="store">
@csrf
<div class="col-12 mb-4">
<h1 class="modal-title fs-5 text-center" id="bookingModalLabel">Objednej se</h1>
<p class="text-center">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Lorem, ipsum
dolor sit amet consectetur adipisicing elit.</p>
</div>
<div class="form-group col-12">
<input type="text" wire:model="full_name" id="full_name" name="full_name" class="form-control"
placeholder="Celé jméno*" required>
</div>
<div class="form-group col-12">
<input type="email" wire:model="email" id="email" name="email" class="form-control"
placeholder="Email*" required>
</div>
<div class="form-group col-12">
<input type="text" wire:model="phone_number" id="phone_number" name="phone_number"
class="form-control" placeholder="Tel. číslo ve formátu +420700700700" required>
@error('phone_number')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group col-12">
<select wire:model="selectedService" class="form-control">
<option value="">Vyberte službu</option>
@foreach ($this->services() as $service)
<option value="{{ $service }}">{{ $service }}</option>
@endforeach
</select>
@error('selectedService')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<div class="form-group col-12 mt-3">
<select wire:model="selectedBusinessHourId" class="form-control">
<option value="">{{ $emptyOption }}</option>
@foreach ($available_business_hour_id as $time)
<option value="{{ $time['id'] }}">{{ $time['formattedDayAndDate'] }} od {{ $time['from'] }} do
{{ $time['to'] }}</option>
@endforeach
</select>
@if ($errors->has('available_business_hour_id') && !$errors->has('selectedBusinessHourId'))
<span class="text-danger">{{ $errors->first('available_business_hour_id') }}</span>
@endif
@if ($errors->has('selectedBusinessHourId'))
<span class="text-danger">{{ $errors->first('selectedBusinessHourId') }}</span>
@endif
</div>
<div class="form-group col-12 text-center">
<div class="cta-btns">
<button type="submit" class="btn btn-service me-sm-2">Odeslat</button>
</div>
</div>
</form>
</div>
I will be glad for any advice.
@jakubjv Ok I see that the value of $this->selectedBusinessHourId is a string, but it should be an integer because the id in the db has type integer.
You can remove the quotes around the option value, currently it the quotes around the value make it a string value:
<option value="{{ $time['id'] }}">
But you can use this without quotes so it will be returned as an integer to the back end
<option value={{ $time['id'] }}>
Like this:
<option value={{ $time['id'] }}>{{ $time['formattedDayAndDate'] }} od {{ $time['from'] }} do
{{ $time['to'] }}
</option>
Please or to participate in this conversation.