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

@@ -17,8 +17,8 @@ class extends Component {
public $country = 'de';
#[Validate('required|date')]
public string $start = '';
public string $startDate = '';
public string $startTime = '';
#[Validate('required|string|max:255')]
public ?string $location = null;
@@ -32,29 +32,54 @@ class extends Component {
public function mount(): void
{
$this->country = request()->route('country');
$timezone = auth()->user()->timezone ?? 'Europe/Berlin';
if ($this->event) {
$this->start = $this->event->start->format('Y-m-d\TH:i');
$localStart = $this->event->start->setTimezone($timezone);
$this->startDate = $localStart->format('Y-m-d');
$this->startTime = $localStart->format('H:i');
$this->location = $this->event->location;
$this->description = $this->event->description;
$this->link = $this->event->link;
} else {
// Set default start time to next Monday at 19:00
$this->start = now()->next('Monday')->setTime(19, 0)->format('Y-m-d\TH:i');
// Set default start time to next Monday at 19:00 in user's timezone
$defaultStart = now($timezone)->next('Monday')->setTime(19, 0);
$this->startDate = $defaultStart->format('Y-m-d');
$this->startTime = $defaultStart->format('H:i');
}
}
public function save(): void
{
$validated = $this->validate();
$this->validate([
'startDate' => 'required|date',
'startTime' => 'required',
'location' => 'required|string|max:255',
'description' => 'required|string',
'link' => 'required|url|max:255',
]);
$timezone = auth()->user()->timezone ?? 'Europe/Berlin';
// Combine date and time in user's timezone, then convert to UTC
$localDateTime = \Carbon\Carbon::createFromFormat('Y-m-d H:i', $this->startDate . ' ' . $this->startTime, $timezone);
$utcDateTime = $localDateTime->setTimezone('UTC');
$data = [
'start' => $utcDateTime,
'location' => $this->location,
'description' => $this->description,
'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->meetup->meetupEvents()->create([
...$validated,
...$data,
'created_by' => auth()->id(),
'attendees' => [],
'might_attendees' => [],
@@ -90,20 +115,27 @@ class extends Component {
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<flux:field>
<flux:label>{{ __('Startzeit') }} <span class="text-red-500">*</span></flux:label>
<flux:input wire:model="start" type="datetime-local" required/>
<flux:description>{{ __('Wann findet das Event statt?') }}</flux:description>
<flux:error name="start"/>
<flux:label>{{ __('Datum') }} <span class="text-red-500">*</span></flux:label>
<flux:date-picker min="today" wire:model="startDate" required locale="{{ session('lang_country', 'de-DE') }}"/>
<flux:description>{{ __('An welchem Tag findet das Event statt?') }}</flux:description>
<flux:error name="startDate"/>
</flux:field>
<flux:field>
<flux:label>{{ __('Ort') }}</flux:label>
<flux:input wire:model="location" placeholder="{{ __('z.B. Café Mustermann, Hauptstr. 1') }}"/>
<flux:description>{{ __('Wo findet das Event statt?') }}</flux:description>
<flux:error name="location"/>
<flux:label>{{ __('Uhrzeit') }} <span class="text-red-500">*</span></flux:label>
<flux:time-picker wire:model="startTime" required locale="{{ session('lang_country', 'de-DE') }}"/>
<flux:description>{{ __('Um wie viel Uhr startet das Event?') }} ({{ auth()->user()->timezone ?? 'Europe/Berlin' }})</flux:description>
<flux:error name="startTime"/>
</flux:field>
</div>
<flux:field>
<flux:label>{{ __('Ort') }}</flux:label>
<flux:input wire:model="location" placeholder="{{ __('z.B. Café Mustermann, Hauptstr. 1') }}"/>
<flux:description>{{ __('Wo findet das Event statt?') }}</flux:description>
<flux:error name="location"/>
</flux:field>
<flux:field>
<flux:label>{{ __('Beschreibung') }}</flux:label>
<flux:textarea wire:model="description" rows="6" placeholder="{{ __('Beschreibe das Event...') }}"/>

View File

@@ -100,8 +100,15 @@ class extends Component {
public function with(): array
{
return [
'cities' => City::query()->orderBy('name')->get(),
'countries' => Country::query()->orderBy('countries.name')->get(),
'cities' => City::query()
->with([
'country',
])
->orderBy('name')
->get(),
'countries' => Country::query()
->orderBy('countries.name')
->get(),
];
}
}; ?>
@@ -120,20 +127,20 @@ class extends Component {
<flux:file-upload wire:model="logo">
<!-- Custom logo uploader -->
<div class="
relative flex items-center justify-center size-20 rounded-full transition-colors cursor-pointer
relative flex items-center justify-center size-20 rounded transition-colors cursor-pointer
border border-zinc-200 dark:border-white/10 hover:border-zinc-300 dark:hover:border-white/10
bg-zinc-100 hover:bg-zinc-200 dark:bg-white/10 hover:dark:bg-white/15 in-data-dragging:dark:bg-white/15
">
@if($logo)
<img src="{{ $logo?->temporaryUrl() }}" alt="Logo"
class="size-full object-cover rounded-full"/>
class="size-full object-cover rounded"/>
@else
<!-- Show the default icon if no file is uploaded -->
<flux:icon name="user-group" variant="solid" class="text-zinc-500 dark:text-zinc-400"/>
@endif
<!-- Corner upload icon -->
<div class="absolute bottom-0 right-0 bg-white dark:bg-zinc-800 rounded-full">
<div class="absolute bottom-0 right-0 bg-white dark:bg-zinc-800 rounded">
<flux:icon name="arrow-up-circle" variant="solid" class="text-zinc-500 dark:text-zinc-400"/>
</div>
</div>