b2in/resources/views/livewire/admin/cms/cabinet-info-tablet.blade.php
Kevin Adametz 07816dce19 Kontaktdaten: Telefon +49 521 986 20 100, E-Mail interior@b2in.eu
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>
2026-10-09 13:29:34 +00:00

196 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>