mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-app.git
synced 2025-12-14 12:06:46 +00:00
✨ Add CRUD support for Cities and Venues
This commit is contained in:
54
lang/de.json
54
lang/de.json
@@ -322,5 +322,57 @@
|
|||||||
"Öffnen/RSVP": "",
|
"Öffnen/RSVP": "",
|
||||||
"Über den Dozenten": "",
|
"Über den Dozenten": "",
|
||||||
"Über den Kurs": "",
|
"Über den Kurs": "",
|
||||||
"Über uns": ""
|
"Über uns": "",
|
||||||
|
"Diverses": "",
|
||||||
|
"Orte/Gebiete": "",
|
||||||
|
"Städte/Gebiete": "",
|
||||||
|
"Veranstaltungsorte": "",
|
||||||
|
"Copy": "",
|
||||||
|
"Click to connect": "",
|
||||||
|
"City successfully created!": "",
|
||||||
|
"Create City": "",
|
||||||
|
"Country": "",
|
||||||
|
"Select a country": "",
|
||||||
|
"Latitude": "",
|
||||||
|
"Longitude": "",
|
||||||
|
"Population": "",
|
||||||
|
"Population Date": "",
|
||||||
|
"City successfully updated!": "",
|
||||||
|
"Edit City": "",
|
||||||
|
"Update City": "",
|
||||||
|
"Cities": "",
|
||||||
|
"Search cities...": "",
|
||||||
|
"Created By": "",
|
||||||
|
"Actions": "",
|
||||||
|
"Edit": "",
|
||||||
|
"Wann beginnt das Event?": "",
|
||||||
|
"Endzeit": "",
|
||||||
|
"Wann endet das Event?": "",
|
||||||
|
"Veranstaltungsort": "",
|
||||||
|
"Ort hinzufügen": "",
|
||||||
|
"Veranstaltungsort auswählen": "",
|
||||||
|
"Suche nach Ort...": "",
|
||||||
|
"Link zu weiteren Informationen oder zur Anmeldung": "",
|
||||||
|
"Veranstaltungsort hinzufügen": "",
|
||||||
|
"Füge einen neuen Veranstaltungsort zur Datenbank hinzu.": "",
|
||||||
|
"z.B. Bitcoin Zentrum München": "",
|
||||||
|
"Straße": "",
|
||||||
|
"z.B. Hauptstraße 1": "",
|
||||||
|
"Ort erstellen": "",
|
||||||
|
"Anmeldungen": "",
|
||||||
|
"weitere Termine": "",
|
||||||
|
"Venue successfully created!": "",
|
||||||
|
"Create Venue": "",
|
||||||
|
"City": "",
|
||||||
|
"Select a city": "",
|
||||||
|
"Street": "",
|
||||||
|
"Venue successfully updated!": "",
|
||||||
|
"Edit Venue": "",
|
||||||
|
"Update Venue": "",
|
||||||
|
"Venues": "",
|
||||||
|
"Search venues...": "",
|
||||||
|
"Basic Information": "",
|
||||||
|
"Coordinates": "",
|
||||||
|
"Demographics": "",
|
||||||
|
"Venue Information": ""
|
||||||
}
|
}
|
||||||
54
lang/en.json
54
lang/en.json
@@ -322,5 +322,57 @@
|
|||||||
"Öffnen/RSVP": "Open/RSVP",
|
"Öffnen/RSVP": "Open/RSVP",
|
||||||
"Über den Dozenten": "About the lecturer",
|
"Über den Dozenten": "About the lecturer",
|
||||||
"Über den Kurs": "About the course",
|
"Über den Kurs": "About the course",
|
||||||
"Über uns": "About us"
|
"Über uns": "About us",
|
||||||
|
"Diverses": "Miscellaneous",
|
||||||
|
"Orte/Gebiete": "Places/Areas",
|
||||||
|
"Städte/Gebiete": "Cities/Areas",
|
||||||
|
"Veranstaltungsorte": "Venues",
|
||||||
|
"Copy": "Copy",
|
||||||
|
"Click to connect": "Click to connect",
|
||||||
|
"City successfully created!": "City successfully created!",
|
||||||
|
"Create City": "Create City",
|
||||||
|
"Country": "Country",
|
||||||
|
"Select a country": "Select a country",
|
||||||
|
"Latitude": "Latitude",
|
||||||
|
"Longitude": "Longitude",
|
||||||
|
"Population": "Population",
|
||||||
|
"Population Date": "Population Date",
|
||||||
|
"City successfully updated!": "City successfully updated!",
|
||||||
|
"Edit City": "Edit City",
|
||||||
|
"Update City": "Update City",
|
||||||
|
"Cities": "Cities",
|
||||||
|
"Search cities...": "Search cities...",
|
||||||
|
"Created By": "Created By",
|
||||||
|
"Actions": "Actions",
|
||||||
|
"Edit": "Edit",
|
||||||
|
"Wann beginnt das Event?": "When does the event start?",
|
||||||
|
"Endzeit": "End time",
|
||||||
|
"Wann endet das Event?": "When does the event end?",
|
||||||
|
"Veranstaltungsort": "Venue",
|
||||||
|
"Ort hinzufügen": "Add location",
|
||||||
|
"Veranstaltungsort auswählen": "Select venue",
|
||||||
|
"Suche nach Ort...": "Search for location...",
|
||||||
|
"Link zu weiteren Informationen oder zur Anmeldung": "Link to further information or registration",
|
||||||
|
"Veranstaltungsort hinzufügen": "Add venue",
|
||||||
|
"Füge einen neuen Veranstaltungsort zur Datenbank hinzu.": "Add a new venue to the database.",
|
||||||
|
"z.B. Bitcoin Zentrum München": "e.g. Bitcoin Center Munich",
|
||||||
|
"Straße": "Street",
|
||||||
|
"z.B. Hauptstraße 1": "e.g. Main Street 1",
|
||||||
|
"Ort erstellen": "Create location",
|
||||||
|
"Anmeldungen": "Registrations",
|
||||||
|
"weitere Termine": "more dates",
|
||||||
|
"Venue successfully created!": "Venue successfully created!",
|
||||||
|
"Create Venue": "Create Venue",
|
||||||
|
"City": "City",
|
||||||
|
"Select a city": "Select a city",
|
||||||
|
"Street": "Street",
|
||||||
|
"Venue successfully updated!": "Venue successfully updated!",
|
||||||
|
"Edit Venue": "Edit Venue",
|
||||||
|
"Update Venue": "Update Venue",
|
||||||
|
"Venues": "Venues",
|
||||||
|
"Search venues...": "Search venues...",
|
||||||
|
"Basic Information": "Basic Information",
|
||||||
|
"Coordinates": "Coordinates",
|
||||||
|
"Demographics": "Demographics",
|
||||||
|
"Venue Information": "Venue Information"
|
||||||
}
|
}
|
||||||
54
lang/es.json
54
lang/es.json
@@ -321,5 +321,57 @@
|
|||||||
"Öffnen/RSVP": "Abrir/RSVP",
|
"Öffnen/RSVP": "Abrir/RSVP",
|
||||||
"Über den Dozenten": "Sobre el profesor",
|
"Über den Dozenten": "Sobre el profesor",
|
||||||
"Über den Kurs": "Sobre el curso",
|
"Über den Kurs": "Sobre el curso",
|
||||||
"Über uns": "Sobre nosotros"
|
"Über uns": "Sobre nosotros",
|
||||||
|
"Diverses": "Varios",
|
||||||
|
"Orte/Gebiete": "Lugares/Áreas",
|
||||||
|
"Städte/Gebiete": "Ciudades/Áreas",
|
||||||
|
"Veranstaltungsorte": "Lugares de eventos",
|
||||||
|
"Copy": "Copiar",
|
||||||
|
"Click to connect": "Haz clic para conectar",
|
||||||
|
"City successfully created!": "¡Ciudad creada exitosamente!",
|
||||||
|
"Create City": "Crear ciudad",
|
||||||
|
"Country": "País",
|
||||||
|
"Select a country": "Seleccionar país",
|
||||||
|
"Latitude": "Latitud",
|
||||||
|
"Longitude": "Longitud",
|
||||||
|
"Population": "Población",
|
||||||
|
"Population Date": "Fecha de población",
|
||||||
|
"City successfully updated!": "¡Ciudad actualizada exitosamente!",
|
||||||
|
"Edit City": "Editar ciudad",
|
||||||
|
"Update City": "Actualizar ciudad",
|
||||||
|
"Cities": "Ciudades",
|
||||||
|
"Search cities...": "Buscar ciudades...",
|
||||||
|
"Created By": "Creado por",
|
||||||
|
"Actions": "Acciones",
|
||||||
|
"Edit": "Editar",
|
||||||
|
"Wann beginnt das Event?": "¿Cuándo comienza el evento?",
|
||||||
|
"Endzeit": "Hora de finalización",
|
||||||
|
"Wann endet das Event?": "¿Cuándo termina el evento?",
|
||||||
|
"Veranstaltungsort": "Lugar del evento",
|
||||||
|
"Ort hinzufügen": "Agregar lugar",
|
||||||
|
"Veranstaltungsort auswählen": "Seleccionar lugar del evento",
|
||||||
|
"Suche nach Ort...": "Buscar lugar...",
|
||||||
|
"Link zu weiteren Informationen oder zur Anmeldung": "Enlace para más información o registro",
|
||||||
|
"Veranstaltungsort hinzufügen": "Agregar lugar de evento",
|
||||||
|
"Füge einen neuen Veranstaltungsort zur Datenbank hinzu.": "Agrega un nuevo lugar de evento a la base de datos.",
|
||||||
|
"z.B. Bitcoin Zentrum München": "ej. Centro Bitcoin Múnich",
|
||||||
|
"Straße": "Calle",
|
||||||
|
"z.B. Hauptstraße 1": "ej. Calle Principal 1",
|
||||||
|
"Ort erstellen": "Crear lugar",
|
||||||
|
"Anmeldungen": "Registros",
|
||||||
|
"weitere Termine": "más fechas",
|
||||||
|
"Venue successfully created!": "¡Lugar creado exitosamente!",
|
||||||
|
"Create Venue": "Crear lugar",
|
||||||
|
"City": "Ciudad",
|
||||||
|
"Select a city": "Seleccionar ciudad",
|
||||||
|
"Street": "Calle",
|
||||||
|
"Venue successfully updated!": "¡Lugar actualizado exitosamente!",
|
||||||
|
"Edit Venue": "Editar lugar",
|
||||||
|
"Update Venue": "Actualizar lugar",
|
||||||
|
"Venues": "Lugares",
|
||||||
|
"Search venues...": "Buscar lugares...",
|
||||||
|
"Basic Information": "Información básica",
|
||||||
|
"Coordinates": "Coordenadas",
|
||||||
|
"Demographics": "Demografía",
|
||||||
|
"Venue Information": "Información del lugar"
|
||||||
}
|
}
|
||||||
@@ -47,9 +47,23 @@
|
|||||||
{{ __('Dozenten') }}
|
{{ __('Dozenten') }}
|
||||||
</flux:navlist.item>
|
</flux:navlist.item>
|
||||||
</flux:navlist.group>
|
</flux:navlist.group>
|
||||||
{{--<flux:navlist.group :heading="__('Wallpaper')" class="grid">
|
|
||||||
|
|
||||||
</flux:navlist.group>--}}
|
<flux:navlist.group :heading="__('Diverses')" class="grid">
|
||||||
|
<flux:navlist.group :heading="__('Orte/Gebiete')" expandable :expanded="request()->routeIs('cities.*') || request()->routeIs('venues.*')">
|
||||||
|
<flux:navlist.item icon="building-office-2" :href="route_with_country('cities.index')"
|
||||||
|
:current="request()->routeIs('cities.index')"
|
||||||
|
wire:navigate
|
||||||
|
badge="{{ \App\Models\City::query()->count() }}">
|
||||||
|
{{ __('Städte/Gebiete') }}
|
||||||
|
</flux:navlist.item>
|
||||||
|
<flux:navlist.item icon="map-pin" :href="route_with_country('venues.index')"
|
||||||
|
:current="request()->routeIs('venues.index')"
|
||||||
|
wire:navigate
|
||||||
|
badge="{{ \App\Models\Venue::query()->count() }}">
|
||||||
|
{{ __('Veranstaltungsorte') }}
|
||||||
|
</flux:navlist.item>
|
||||||
|
</flux:navlist.group>
|
||||||
|
</flux:navlist.group>
|
||||||
</flux:navlist>
|
</flux:navlist>
|
||||||
|
|
||||||
<flux:spacer/>
|
<flux:spacer/>
|
||||||
|
|||||||
88
resources/views/livewire/cities/create.blade.php
Normal file
88
resources/views/livewire/cities/create.blade.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\City;
|
||||||
|
use App\Models\Country;
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public string $name = '';
|
||||||
|
public ?int $country_id = null;
|
||||||
|
public float $latitude = 0;
|
||||||
|
public float $longitude = 0;
|
||||||
|
public ?int $population = null;
|
||||||
|
public ?string $population_date = null;
|
||||||
|
|
||||||
|
public function createCity(): void
|
||||||
|
{
|
||||||
|
$validated = $this->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255', 'unique:cities,name'],
|
||||||
|
'country_id' => ['required', 'exists:countries,id'],
|
||||||
|
'latitude' => ['required', 'numeric', 'between:-90,90'],
|
||||||
|
'longitude' => ['required', 'numeric', 'between:-180,180'],
|
||||||
|
'population' => ['nullable', 'integer', 'min:0'],
|
||||||
|
'population_date' => ['nullable', 'string', 'max:255'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validated['slug'] = str($validated['name'])->slug();
|
||||||
|
$validated['created_by'] = auth()->id();
|
||||||
|
|
||||||
|
$city = City::create($validated);
|
||||||
|
|
||||||
|
session()->flash('status', __('City successfully created!'));
|
||||||
|
|
||||||
|
$this->redirect(route_with_country('cities.index'), navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'countries' => Country::query()->orderBy('name')->get(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}; ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="mb-6">
|
||||||
|
<flux:heading size="xl">{{ __('Create City') }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form wire:submit="createCity" class="space-y-8">
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Basic Information') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<flux:input label="{{ __('Name') }}" wire:model="name" required />
|
||||||
|
|
||||||
|
<flux:select label="{{ __('Country') }}" wire:model="country_id" required>
|
||||||
|
<option value="">{{ __('Select a country') }}</option>
|
||||||
|
@foreach($countries as $country)
|
||||||
|
<option value="{{ $country->id }}">{{ $country->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</flux:select>
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Coordinates') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-6">
|
||||||
|
<flux:input label="{{ __('Latitude') }}" type="number" step="any" wire:model="latitude" required />
|
||||||
|
<flux:input label="{{ __('Longitude') }}" type="number" step="any" wire:model="longitude" required />
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Demographics') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-6">
|
||||||
|
<flux:input label="{{ __('Population') }}" type="number" wire:model="population" />
|
||||||
|
<flux:input label="{{ __('Population Date') }}" wire:model="population_date" placeholder="e.g. 2024" />
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<flux:button type="submit" variant="primary">{{ __('Create City') }}</flux:button>
|
||||||
|
<flux:button :href="route_with_country('cities.index')" variant="ghost">{{ __('Cancel') }}</flux:button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
99
resources/views/livewire/cities/edit.blade.php
Normal file
99
resources/views/livewire/cities/edit.blade.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\City;
|
||||||
|
use App\Models\Country;
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public City $city;
|
||||||
|
public string $name = '';
|
||||||
|
public ?int $country_id = null;
|
||||||
|
public float $latitude = 0;
|
||||||
|
public float $longitude = 0;
|
||||||
|
public ?int $population = null;
|
||||||
|
public ?string $population_date = null;
|
||||||
|
|
||||||
|
public function mount(City $city): void
|
||||||
|
{
|
||||||
|
$this->city = $city;
|
||||||
|
$this->name = $city->name;
|
||||||
|
$this->country_id = $city->country_id;
|
||||||
|
$this->latitude = $city->latitude;
|
||||||
|
$this->longitude = $city->longitude;
|
||||||
|
$this->population = $city->population;
|
||||||
|
$this->population_date = $city->population_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateCity(): void
|
||||||
|
{
|
||||||
|
$validated = $this->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255', 'unique:cities,name,'.$this->city->id],
|
||||||
|
'country_id' => ['required', 'exists:countries,id'],
|
||||||
|
'latitude' => ['required', 'numeric', 'between:-90,90'],
|
||||||
|
'longitude' => ['required', 'numeric', 'between:-180,180'],
|
||||||
|
'population' => ['nullable', 'integer', 'min:0'],
|
||||||
|
'population_date' => ['nullable', 'string', 'max:255'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validated['slug'] = str($validated['name'])->slug();
|
||||||
|
|
||||||
|
$this->city->update($validated);
|
||||||
|
|
||||||
|
session()->flash('status', __('City successfully updated!'));
|
||||||
|
|
||||||
|
$this->redirect(route_with_country('cities.index'), navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'countries' => Country::query()->orderBy('name')->get(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}; ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="mb-6">
|
||||||
|
<flux:heading size="xl">{{ __('Edit City') }}: {{ $city->name }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form wire:submit="updateCity" class="space-y-8">
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Basic Information') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<flux:input label="{{ __('Name') }}" wire:model="name" required />
|
||||||
|
|
||||||
|
<flux:select label="{{ __('Country') }}" wire:model="country_id" required>
|
||||||
|
<option value="">{{ __('Select a country') }}</option>
|
||||||
|
@foreach($countries as $country)
|
||||||
|
<option value="{{ $country->id }}">{{ $country->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</flux:select>
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Coordinates') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-6">
|
||||||
|
<flux:input label="{{ __('Latitude') }}" type="number" step="any" wire:model="latitude" required />
|
||||||
|
<flux:input label="{{ __('Longitude') }}" type="number" step="any" wire:model="longitude" required />
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Demographics') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-6">
|
||||||
|
<flux:input label="{{ __('Population') }}" type="number" wire:model="population" />
|
||||||
|
<flux:input label="{{ __('Population Date') }}" wire:model="population_date" placeholder="e.g. 2024" />
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<flux:button type="submit" variant="primary">{{ __('Update City') }}</flux:button>
|
||||||
|
<flux:button :href="route_with_country('cities.index')" variant="ghost">{{ __('Cancel') }}</flux:button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
94
resources/views/livewire/cities/index.blade.php
Normal file
94
resources/views/livewire/cities/index.blade.php
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\City;
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
use WithPagination;
|
||||||
|
|
||||||
|
public $country = 'de';
|
||||||
|
public $search = '';
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->country = request()->route('country');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cities' => City::with(['country', 'createdBy'])
|
||||||
|
->when($this->search, fn($query)
|
||||||
|
=> $query->where('name', 'ilike', '%'.$this->search.'%'),
|
||||||
|
)
|
||||||
|
->orderBy('name')
|
||||||
|
->paginate(15),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}; ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<flux:heading size="xl">{{ __('Cities') }}</flux:heading>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<flux:input
|
||||||
|
wire:model.live="search"
|
||||||
|
:placeholder="__('Search cities...')"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
@auth
|
||||||
|
<flux:button class="cursor-pointer" :href="route_with_country('cities.create')" icon="plus" variant="primary">
|
||||||
|
{{ __('Create City') }}
|
||||||
|
</flux:button>
|
||||||
|
@endauth
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<flux:table :paginate="$cities" class="mt-6">
|
||||||
|
<flux:table.columns>
|
||||||
|
<flux:table.column>{{ __('Name') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('Country') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('Population') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('Created By') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('Actions') }}</flux:table.column>
|
||||||
|
</flux:table.columns>
|
||||||
|
|
||||||
|
<flux:table.rows>
|
||||||
|
@foreach ($cities as $city)
|
||||||
|
<flux:table.row :key="$city->id">
|
||||||
|
<flux:table.cell variant="strong">
|
||||||
|
{{ $city->name }}
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
@if($city->country)
|
||||||
|
{{ $city->country->name }}
|
||||||
|
@endif
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
@if($city->population)
|
||||||
|
{{ number_format($city->population) }}
|
||||||
|
@if($city->population_date)
|
||||||
|
<span class="text-xs text-zinc-500">({{ $city->population_date }})</span>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
@if($city->createdBy)
|
||||||
|
{{ $city->createdBy->name }}
|
||||||
|
@endif
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
@auth
|
||||||
|
<flux:button size="sm" :href="route('cities.edit',['city' => $city, 'country' => $country])" icon="pencil">
|
||||||
|
{{ __('Edit') }}
|
||||||
|
</flux:button>
|
||||||
|
@endauth
|
||||||
|
</div>
|
||||||
|
</flux:table.cell>
|
||||||
|
</flux:table.row>
|
||||||
|
@endforeach
|
||||||
|
</flux:table.rows>
|
||||||
|
</flux:table>
|
||||||
|
</div>
|
||||||
71
resources/views/livewire/venues/create.blade.php
Normal file
71
resources/views/livewire/venues/create.blade.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Venue;
|
||||||
|
use App\Models\City;
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public string $name = '';
|
||||||
|
public ?int $city_id = null;
|
||||||
|
public string $street = '';
|
||||||
|
|
||||||
|
public function createVenue(): void
|
||||||
|
{
|
||||||
|
$validated = $this->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255', 'unique:venues,name'],
|
||||||
|
'city_id' => ['required', 'exists:cities,id'],
|
||||||
|
'street' => ['required', 'string', 'max:255'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validated['slug'] = str($validated['name'])->slug();
|
||||||
|
$validated['created_by'] = auth()->id();
|
||||||
|
|
||||||
|
$venue = Venue::create($validated);
|
||||||
|
|
||||||
|
session()->flash('status', __('Venue successfully created!'));
|
||||||
|
|
||||||
|
$this->redirect(route_with_country('venues.index'), navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cities' => City::query()->with('country')->orderBy('name')->get(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}; ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="mb-6">
|
||||||
|
<flux:heading size="xl">{{ __('Create Venue') }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form wire:submit="createVenue" class="space-y-8">
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Venue Information') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<flux:input label="{{ __('Name') }}" wire:model="name" required />
|
||||||
|
|
||||||
|
<flux:select label="{{ __('City') }}" wire:model="city_id" required>
|
||||||
|
<option value="">{{ __('Select a city') }}</option>
|
||||||
|
@foreach($cities as $city)
|
||||||
|
<option value="{{ $city->id }}">
|
||||||
|
{{ $city->name }}
|
||||||
|
@if($city->country)
|
||||||
|
({{ $city->country->name }})
|
||||||
|
@endif
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</flux:select>
|
||||||
|
|
||||||
|
<flux:input label="{{ __('Street') }}" wire:model="street" required />
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<flux:button type="submit" variant="primary">{{ __('Create Venue') }}</flux:button>
|
||||||
|
<flux:button :href="route_with_country('venues.index')" variant="ghost">{{ __('Cancel') }}</flux:button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
79
resources/views/livewire/venues/edit.blade.php
Normal file
79
resources/views/livewire/venues/edit.blade.php
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Venue;
|
||||||
|
use App\Models\City;
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public Venue $venue;
|
||||||
|
public string $name = '';
|
||||||
|
public ?int $city_id = null;
|
||||||
|
public string $street = '';
|
||||||
|
|
||||||
|
public function mount(Venue $venue): void
|
||||||
|
{
|
||||||
|
$this->venue = $venue;
|
||||||
|
$this->name = $venue->name;
|
||||||
|
$this->city_id = $venue->city_id;
|
||||||
|
$this->street = $venue->street;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateVenue(): void
|
||||||
|
{
|
||||||
|
$validated = $this->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255', 'unique:venues,name,'.$this->venue->id],
|
||||||
|
'city_id' => ['required', 'exists:cities,id'],
|
||||||
|
'street' => ['required', 'string', 'max:255'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$validated['slug'] = str($validated['name'])->slug();
|
||||||
|
|
||||||
|
$this->venue->update($validated);
|
||||||
|
|
||||||
|
session()->flash('status', __('Venue successfully updated!'));
|
||||||
|
|
||||||
|
$this->redirect(route_with_country('venues.index'), navigate: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cities' => City::query()->with('country')->orderBy('name')->get(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}; ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="mb-6">
|
||||||
|
<flux:heading size="xl">{{ __('Edit Venue') }}: {{ $venue->name }}</flux:heading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form wire:submit="updateVenue" class="space-y-8">
|
||||||
|
<flux:fieldset>
|
||||||
|
<flux:legend>{{ __('Venue Information') }}</flux:legend>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<flux:input label="{{ __('Name') }}" wire:model="name" required />
|
||||||
|
|
||||||
|
<flux:select label="{{ __('City') }}" wire:model="city_id" required>
|
||||||
|
<option value="">{{ __('Select a city') }}</option>
|
||||||
|
@foreach($cities as $city)
|
||||||
|
<option value="{{ $city->id }}">
|
||||||
|
{{ $city->name }}
|
||||||
|
@if($city->country)
|
||||||
|
({{ $city->country->name }})
|
||||||
|
@endif
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</flux:select>
|
||||||
|
|
||||||
|
<flux:input label="{{ __('Street') }}" wire:model="street" required />
|
||||||
|
</div>
|
||||||
|
</flux:fieldset>
|
||||||
|
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<flux:button type="submit" variant="primary">{{ __('Update Venue') }}</flux:button>
|
||||||
|
<flux:button :href="route_with_country('venues.index')" variant="ghost">{{ __('Cancel') }}</flux:button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
88
resources/views/livewire/venues/index.blade.php
Normal file
88
resources/views/livewire/venues/index.blade.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Venue;
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
use WithPagination;
|
||||||
|
|
||||||
|
public $country = 'de';
|
||||||
|
public $search = '';
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->country = request()->route('country');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function with(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'venues' => Venue::with(['city.country', 'createdBy'])
|
||||||
|
->when($this->search, fn($query)
|
||||||
|
=> $query->where('name', 'ilike', '%'.$this->search.'%'),
|
||||||
|
)
|
||||||
|
->orderBy('name')
|
||||||
|
->paginate(15),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}; ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<flux:heading size="xl">{{ __('Venues') }}</flux:heading>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<flux:input
|
||||||
|
wire:model.live="search"
|
||||||
|
:placeholder="__('Search venues...')"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
@auth
|
||||||
|
<flux:button class="cursor-pointer" :href="route_with_country('venues.create')" icon="plus" variant="primary">
|
||||||
|
{{ __('Create Venue') }}
|
||||||
|
</flux:button>
|
||||||
|
@endauth
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<flux:table :paginate="$venues" class="mt-6">
|
||||||
|
<flux:table.columns>
|
||||||
|
<flux:table.column>{{ __('Name') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('City') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('Created By') }}</flux:table.column>
|
||||||
|
<flux:table.column>{{ __('Actions') }}</flux:table.column>
|
||||||
|
</flux:table.columns>
|
||||||
|
|
||||||
|
<flux:table.rows>
|
||||||
|
@foreach ($venues as $venue)
|
||||||
|
<flux:table.row :key="$venue->id">
|
||||||
|
<flux:table.cell variant="strong">
|
||||||
|
{{ $venue->name }}
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
@if($venue->city)
|
||||||
|
{{ $venue->city->name }}
|
||||||
|
@if($venue->city->country)
|
||||||
|
<span class="text-xs text-zinc-500">({{ $venue->city->country->name }})</span>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
@if($venue->createdBy)
|
||||||
|
{{ $venue->createdBy->name }}
|
||||||
|
@endif
|
||||||
|
</flux:table.cell>
|
||||||
|
<flux:table.cell>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
@auth
|
||||||
|
<flux:button size="sm" :href="route('venues.edit', ['venue' => $venue, 'country' => $country])" icon="pencil">
|
||||||
|
{{ __('Edit') }}
|
||||||
|
</flux:button>
|
||||||
|
@endauth
|
||||||
|
</div>
|
||||||
|
</flux:table.cell>
|
||||||
|
</flux:table.row>
|
||||||
|
@endforeach
|
||||||
|
</flux:table.rows>
|
||||||
|
</flux:table>
|
||||||
|
</div>
|
||||||
@@ -42,6 +42,9 @@ Route::middleware([])
|
|||||||
Volt::route('course/{course}/event/{event}', 'courses.landingpage-event')->name('courses.landingpage-event');
|
Volt::route('course/{course}/event/{event}', 'courses.landingpage-event')->name('courses.landingpage-event');
|
||||||
|
|
||||||
Volt::route('lecturers', 'lecturers.index')->name('lecturers.index');
|
Volt::route('lecturers', 'lecturers.index')->name('lecturers.index');
|
||||||
|
|
||||||
|
Volt::route('cities', 'cities.index')->name('cities.index');
|
||||||
|
Volt::route('venues', 'venues.index')->name('venues.index');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])
|
Route::middleware(['auth'])
|
||||||
@@ -60,6 +63,12 @@ Route::middleware(['auth'])
|
|||||||
|
|
||||||
Volt::route('lecturer-create', 'lecturers.create')->name('lecturers.create');
|
Volt::route('lecturer-create', 'lecturers.create')->name('lecturers.create');
|
||||||
Volt::route('lecturer-edit/{lecturer}', 'lecturers.edit')->name('lecturers.edit');
|
Volt::route('lecturer-edit/{lecturer}', 'lecturers.edit')->name('lecturers.edit');
|
||||||
|
|
||||||
|
Volt::route('city-create', 'cities.create')->name('cities.create');
|
||||||
|
Volt::route('city-edit/{city}', 'cities.edit')->name('cities.edit');
|
||||||
|
|
||||||
|
Volt::route('venue-create', 'venues.create')->name('venues.create');
|
||||||
|
Volt::route('venue-edit/{venue}', 'venues.edit')->name('venues.edit');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])
|
Route::middleware(['auth'])
|
||||||
|
|||||||
Reference in New Issue
Block a user