Refactor event scheduling to separate date and time inputs

- Split `from` and `to` fields in courses into `fromDate`, `fromTime`, `toDate`, and `toTime` for improved flexibility.
- Refactored meetups to use `startDate` and `startTime` instead of `start`.
- Enhanced validation to handle new date and time fields.
- Applied user-specific timezone conversions for event dates and times.
- Updated views to utilize new date and time pickers for consistent scheduling.
This commit is contained in:
HolgerHatGarKeineNode
2025-11-23 19:36:34 +01:00
parent ca9cd9b875
commit c48455a6be
3 changed files with 145 additions and 43 deletions

View File

@@ -19,11 +19,10 @@ class extends Component {
public $country = 'de';
#[Validate('required|date')]
public string $from = '';
#[Validate('required|date|after:from')]
public string $to = '';
public string $fromDate = '';
public string $fromTime = '';
public string $toDate = '';
public string $toTime = '';
#[Validate('required|exists:venues,id')]
public ?int $venue_id = null;
@@ -39,31 +38,69 @@ class extends Component {
public function mount(): void
{
$this->country = request()->route('country');
$timezone = auth()->user()->timezone ?? 'Europe/Berlin';
if ($this->event) {
$this->from = $this->event->from->format('Y-m-d\TH:i');
$this->to = $this->event->to->format('Y-m-d\TH:i');
$localFrom = $this->event->from->setTimezone($timezone);
$localTo = $this->event->to->setTimezone($timezone);
$this->fromDate = $localFrom->format('Y-m-d');
$this->fromTime = $localFrom->format('H:i');
$this->toDate = $localTo->format('Y-m-d');
$this->toTime = $localTo->format('H:i');
$this->venue_id = $this->event->venue_id;
$this->link = $this->event->link;
} else {
// Set default start time to next Monday at 09:00
$nextMonday = now()->next('Monday')->setTime(9, 0);
$this->from = $nextMonday->format('Y-m-d\TH:i');
$this->to = $nextMonday->copy()->addHours(3)->format('Y-m-d\TH:i');
// Set default start time to next Monday at 09:00 in user's timezone
$nextMonday = now($timezone)->next('Monday')->setTime(9, 0);
$this->fromDate = $nextMonday->format('Y-m-d');
$this->fromTime = $nextMonday->format('H:i');
$this->toDate = $nextMonday->format('Y-m-d');
$this->toTime = $nextMonday->copy()->addHours(3)->format('H:i');
}
}
public function save(): void
{
$validated = $this->validate();
$this->validate([
'fromDate' => 'required|date',
'fromTime' => 'required',
'toDate' => 'required|date|after_or_equal:fromDate',
'toTime' => 'required',
'venue_id' => 'required|exists:venues,id',
'link' => 'required|url|max:255',
]);
$timezone = auth()->user()->timezone ?? 'Europe/Berlin';
// Combine date and time in user's timezone, then convert to UTC
$localFrom = \Carbon\Carbon::createFromFormat('Y-m-d H:i', $this->fromDate . ' ' . $this->fromTime, $timezone);
$utcFrom = $localFrom->setTimezone('UTC');
$localTo = \Carbon\Carbon::createFromFormat('Y-m-d H:i', $this->toDate . ' ' . $this->toTime, $timezone);
$utcTo = $localTo->setTimezone('UTC');
// Additional validation: to must be after from
if ($utcTo->lte($utcFrom)) {
$this->addError('toTime', __('Die Endzeit muss nach der Startzeit liegen.'));
return;
}
$data = [
'from' => $utcFrom,
'to' => $utcTo,
'venue_id' => $this->venue_id,
'link' => $this->link,
];
if ($this->event) {
// Update existing event
$this->event->update($validated);
$this->event->update($data);
session()->flash('status', __('Event erfolgreich aktualisiert!'));
} else {
// Create new event
$this->course->courseEvents()->create([
...$validated,
...$data,
'created_by' => auth()->id(),
]);
session()->flash('status', __('Event erfolgreich erstellt!'));
@@ -108,8 +145,18 @@ class extends Component {
public function with(): array
{
return [
'venues' => Venue::query()->orderBy('name')->get(),
'cities' => City::query()->orderBy('name')->get(),
'venues' => Venue::query()
->with([
'city',
])
->orderBy('name')
->get(),
'cities' => City::query()
->with([
'country',
])
->orderBy('name')
->get(),
];
}
}; ?>
@@ -126,18 +173,34 @@ class extends Component {
<flux:legend>{{ __('Event Details') }}</flux:legend>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<flux:field>
<flux:label>{{ __('Startdatum') }} <span class="text-red-500">*</span></flux:label>
<flux:date-picker wire:model="fromDate" required/>
<flux:description>{{ __('An welchem Tag beginnt das Event?') }}</flux:description>
<flux:error name="fromDate"/>
</flux:field>
<flux:field>
<flux:label>{{ __('Startzeit') }} <span class="text-red-500">*</span></flux:label>
<flux:input wire:model="from" type="datetime-local" required/>
<flux:description>{{ __('Wann beginnt das Event?') }}</flux:description>
<flux:error name="from"/>
<flux:time-picker wire:model="fromTime" required/>
<flux:description>{{ __('Um wie viel Uhr beginnt das Event?') }} ({{ auth()->user()->timezone ?? 'Europe/Berlin' }})</flux:description>
<flux:error name="fromTime"/>
</flux:field>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<flux:field>
<flux:label>{{ __('Enddatum') }} <span class="text-red-500">*</span></flux:label>
<flux:date-picker wire:model="toDate" required/>
<flux:description>{{ __('An welchem Tag endet das Event?') }}</flux:description>
<flux:error name="toDate"/>
</flux:field>
<flux:field>
<flux:label>{{ __('Endzeit') }} <span class="text-red-500">*</span></flux:label>
<flux:input wire:model="to" type="datetime-local" required/>
<flux:description>{{ __('Wann endet das Event?') }}</flux:description>
<flux:error name="to"/>
<flux:time-picker wire:model="toTime" required/>
<flux:description>{{ __('Um wie viel Uhr endet das Event?') }} ({{ auth()->user()->timezone ?? 'Europe/Berlin' }})</flux:description>
<flux:error name="toTime"/>
</flux:field>
</div>