Lang-Dateien (Kontaktformular, Impressum, Datenschutz, de/en), Support-Link im Partnerportal, WhatsApp-Schreibweise und Platzhalter im Admin. ContactDetailsSeeder ersetzt die alten Werte in den gespeicherten CMS-Einträgen (beide Sprachen), Marken und Magazin; Display-Folien und Info-Tablet (CABINET-Showroom) bleiben unberührt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
196 lines
12 KiB
PHP
196 lines
12 KiB
PHP
<div>
|
||
<flux:header class="mb-6">
|
||
<flux:heading size="xl">{{ __('Cabinet Info-Tablet') }}</flux:heading>
|
||
<flux:subheading>{{ __('Einstellungen für das Schaufenster-Tablet') }}</flux:subheading>
|
||
</flux:header>
|
||
|
||
{{-- Hilfe-Banner --}}
|
||
<flux:card class="mb-6 bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800">
|
||
<div class="flex items-start gap-4">
|
||
<flux:icon.information-circle class="w-6 h-6 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
|
||
<div class="flex-1">
|
||
<h3 class="font-semibold text-blue-900 dark:text-blue-100 mb-2">{{ __('Info-Tablet Steuerung') }}</h3>
|
||
<div class="text-sm text-blue-800 dark:text-blue-200 space-y-1">
|
||
<p>Das Info-Tablet im Schaufenster zeigt Store-Status, Öffnungszeiten und den nächsten freien
|
||
Termin.</p>
|
||
<p>• <strong>Automatisch:</strong> Offen/Geschlossen wird automatisch aus den hinterlegten
|
||
Öffnungszeiten berechnet.</p>
|
||
<p>• <strong>API-Endpunkt:</strong> <code
|
||
class="px-2 py-0.5 bg-blue-100 dark:bg-blue-800 rounded">{{ url('/api/cabinet-tablet/status') }}</code>
|
||
</p>
|
||
<p>• <strong>Website-Endpunkt:</strong> <code
|
||
class="px-2 py-0.5 bg-blue-100 dark:bg-blue-800 rounded"><a target="_blank"
|
||
href="https://cabinet.b2in.eu/info">https://cabinet.b2in.eu/info</a></code></p>
|
||
<p>• <strong>Quick-Status-Endpunkt:</strong> <code
|
||
class="px-2 py-0.5 bg-blue-100 dark:bg-blue-800 rounded"><a target="_blank"
|
||
href="https://portal.b2in.eu/info/status?key={{ config('domains.cabinet_status_key') }}">https://portal.b2in.eu/info/status?key={{ config('domains.cabinet_status_key') }}</a></code>
|
||
</p>
|
||
<p>• <strong>Quick-Status-Hinweis:</strong> Der Quick-Status-Endpunkt ist ein kleines Tool, um den
|
||
Store-Status schnell zu ändern. Auf dem Mobiltelefon den Link öffen und dem Home-Screen
|
||
hinzufügen.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Success-Meldungen --}}
|
||
@if (session()->has('success'))
|
||
<x-success-alert>
|
||
{{ session('success') }}
|
||
</x-success-alert>
|
||
@endif
|
||
|
||
{{-- Nur EIN Submit-Handler: die Zeit-Picker melden das Leeren nicht zuverlaessig an
|
||
wire:model, deshalb werden ihre Werte hier direkt aus dem DOM gelesen und an save()
|
||
uebergeben. Ein zusaetzliches wire:submit wuerde save() ein zweites Mal aufrufen. --}}
|
||
<form x-data
|
||
x-on:submit.prevent="
|
||
const hours = {};
|
||
$el.querySelectorAll('[data-hours-prop]').forEach(el => {
|
||
const prop = el.dataset.hoursProp;
|
||
const picker = el.querySelector('ui-time-picker');
|
||
hours[prop] = picker ? (picker.value ?? '') : '';
|
||
});
|
||
$wire.save(hours);
|
||
">
|
||
<div class="space-y-6">
|
||
|
||
{{-- Store-Status --}}
|
||
<flux:card>
|
||
<flux:heading size="lg" class="mb-4">{{ __('Store-Status') }}</flux:heading>
|
||
|
||
<div class="space-y-4">
|
||
<flux:select wire:model.live="storeStatus" label="Modus">
|
||
<option value="auto">Automatisch (aus Öffnungszeiten)</option>
|
||
<option value="notice">Hinweis (Orange)</option>
|
||
<option value="warning">Warnung (Rot)</option>
|
||
<option value="closed">Manuell geschlossen (Gelb)</option>
|
||
</flux:select>
|
||
|
||
@if ($storeStatus !== 'auto')
|
||
@php
|
||
$noticeColors = match ($storeStatus) {
|
||
'notice'
|
||
=> 'bg-orange-50 dark:bg-orange-900/20 border border-orange-200 dark:border-orange-800',
|
||
'warning' => 'bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800',
|
||
default
|
||
=> 'bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800',
|
||
};
|
||
@endphp
|
||
<div class="space-y-4 p-4 rounded-lg {{ $noticeColors }}">
|
||
<flux:input wire:model="noticeHeadline" label="Headline"
|
||
placeholder="z.B. Heute erst ab 11:00 Uhr" maxlength="40" />
|
||
@error('noticeHeadline')
|
||
<span class="text-red-600 text-sm">{{ $message }}</span>
|
||
@enderror
|
||
|
||
<flux:input wire:model="noticeSubtext" label="Subtext (optional)"
|
||
placeholder="z.B. Wegen eines Kundentermins öffnen wir heute später." maxlength="80" />
|
||
@error('noticeSubtext')
|
||
<span class="text-red-600 text-sm">{{ $message }}</span>
|
||
@enderror
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Öffnungszeiten --}}
|
||
<flux:card>
|
||
<flux:heading size="lg" class="mb-1">{{ __('Öffnungszeiten') }}</flux:heading>
|
||
<p class="text-sm text-zinc-500 dark:text-zinc-400 mb-4">Felder leer lassen = Geschlossen. Der Status
|
||
"Geöffnet/Geschlossen" wird automatisch aus diesen Zeiten berechnet.</p>
|
||
|
||
<div class="space-y-3">
|
||
@foreach ([['label' => 'Montag', 'open' => 'hoursMondayOpen', 'close' => 'hoursMondayClose'], ['label' => 'Dienstag', 'open' => 'hoursTuesdayOpen', 'close' => 'hoursTuesdayClose'], ['label' => 'Mittwoch', 'open' => 'hoursWednesdayOpen', 'close' => 'hoursWednesdayClose'], ['label' => 'Donnerstag', 'open' => 'hoursThursdayOpen', 'close' => 'hoursThursdayClose'], ['label' => 'Freitag', 'open' => 'hoursFridayOpen', 'close' => 'hoursFridayClose'], ['label' => 'Samstag', 'open' => 'hoursSaturdayOpen', 'close' => 'hoursSaturdayClose'], ['label' => 'Sonntag', 'open' => 'hoursSundayOpen', 'close' => 'hoursSundayClose']] as $row)
|
||
{{-- Geoeffnet/Geschlossen wird clientseitig gerechnet, damit die Anzeige
|
||
sofort auf das Leeren per X reagiert. wire:model.live wuerde bei jeder
|
||
Aenderung einen Roundtrip ausloesen, der geleerte Felder wieder mit dem
|
||
alten Serverwert ueberschreibt. --}}
|
||
<div class="grid grid-cols-[120px_1fr_1fr_80px] items-center gap-3 py-2 border-b border-zinc-100 dark:border-zinc-800 last:border-0"
|
||
x-data="{
|
||
open: @js((string) ($this->{$row['open']} ?? '')),
|
||
close: @js((string) ($this->{$row['close']} ?? '')),
|
||
get isClosed() { return this.open === '' && this.close === '' },
|
||
}">
|
||
<span
|
||
class="text-sm font-medium text-zinc-700 dark:text-zinc-300">{{ $row['label'] }}</span>
|
||
<div data-hours-prop="{{ $row['open'] }}"
|
||
x-on:input="open = $event.target.value ?? ''">
|
||
<flux:time-picker wire:model="{{ $row['open'] }}" label="Öffnung"
|
||
time-format="24-hour" interval="15" clearable placeholder="–" />
|
||
</div>
|
||
<div data-hours-prop="{{ $row['close'] }}"
|
||
x-on:input="close = $event.target.value ?? ''">
|
||
<flux:time-picker wire:model="{{ $row['close'] }}" label="Schluss"
|
||
time-format="24-hour" interval="15" clearable placeholder="–" />
|
||
</div>
|
||
<span class="text-xs text-center"
|
||
:class="isClosed ? 'text-red-500 dark:text-red-400' : 'text-emerald-600 dark:text-emerald-400'"
|
||
x-text="isClosed ? 'Geschlossen' : 'Geöffnet'">
|
||
</span>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Sonderöffnung heute
|
||
<flux:card>
|
||
<div class="flex items-center justify-between mb-4">
|
||
<flux:heading size="lg">{{ __('Sonderöffnung heute') }}</flux:heading>
|
||
@if ($overrideOpenToday || $overrideCloseToday)
|
||
<flux:button wire:click="clearOverrides" size="sm" variant="ghost" icon="x-mark">
|
||
{{ __('Zurücksetzen') }}
|
||
</flux:button>
|
||
@endif
|
||
</div>
|
||
<p class="text-sm text-zinc-500 dark:text-zinc-400 mb-4">Überschreibt die reguläre Öffnungszeit für heute. Wird um Mitternacht automatisch zurückgesetzt.</p>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<flux:time-picker wire:model="overrideOpenToday" label="Öffnung" time-format="24-hour" interval="15" clearable placeholder="–" />
|
||
@error('overrideOpenToday') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
|
||
|
||
<flux:time-picker wire:model="overrideCloseToday" label="Schluss" time-format="24-hour" interval="15" clearable placeholder="–" />
|
||
@error('overrideCloseToday') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
|
||
</div>
|
||
</flux:card> --}}
|
||
|
||
{{-- Nächster Termin
|
||
<flux:card>
|
||
<flux:heading size="lg" class="mb-4">{{ __('Nächster freier Termin') }}</flux:heading>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<flux:input wire:model="nextAppointmentDate" type="date" label="Datum" />
|
||
@error('nextAppointmentDate') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
|
||
|
||
<flux:time-picker wire:model="nextAppointmentTime" label="Uhrzeit" time-format="24-hour" interval="15" clearable placeholder="–" />
|
||
@error('nextAppointmentTime') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
|
||
</div>
|
||
</flux:card> --}}
|
||
|
||
{{-- Kontakt --}}
|
||
<flux:card>
|
||
<flux:heading size="lg" class="mb-4">{{ __('Kontakt') }}</flux:heading>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<flux:input wire:model="contactPhone" label="Telefon" placeholder="z.B. +49 521 986 20 100" />
|
||
@error('contactPhone')
|
||
<span class="text-red-600 text-sm">{{ $message }}</span>
|
||
@enderror
|
||
|
||
<flux:input wire:model="contactEmail" label="E-Mail" type="email"
|
||
placeholder="z.B. info@cabinet-bielefeld.de" />
|
||
@error('contactEmail')
|
||
<span class="text-red-600 text-sm">{{ $message }}</span>
|
||
@enderror
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Speichern --}}
|
||
<div class="flex justify-end">
|
||
<flux:button type="submit" variant="primary" icon="check">
|
||
{{ __('Einstellungen speichern') }}
|
||
</flux:button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|