*/ public array $openingHours = [ 'monday' => ['open' => '09:00', 'close' => '18:00', 'closed' => false], 'tuesday' => ['open' => '09:00', 'close' => '18:00', 'closed' => false], 'wednesday' => ['open' => '09:00', 'close' => '18:00', 'closed' => false], 'thursday' => ['open' => '09:00', 'close' => '18:00', 'closed' => false], 'friday' => ['open' => '09:00', 'close' => '18:00', 'closed' => false], 'saturday' => ['open' => '10:00', 'close' => '16:00', 'closed' => false], 'sunday' => ['open' => '', 'close' => '', 'closed' => true], ]; // Neue Fotos (temporäre Upload-Objekte) /** @var array */ public array $newTeamPhotos = []; /** @var array */ public array $newShowroomPhotos = []; /** @var array */ public array $newBrandImages = []; // Bestehende Fotos (aus DB, für Drag-&-Drop) /** @var array */ public array $existingTeamPhotos = []; /** @var array */ public array $existingShowroomPhotos = []; /** @var array */ public array $existingBrandImages = []; public string $roleIcon = 'shield-check'; public string $roleName = '-'; public function mount(): void { $user = Auth::user(); if (! $user->partner_id) { $this->redirect(route('dashboard'), navigate: true); return; } $role = $user->roles->first(); if ($role) { $this->roleIcon = $role->icon ?? 'shield-check'; $this->roleName = $role->display_name ?? $role->name; } $this->partner = Partner::with(['users', 'media'])->findOrFail($user->partner_id); $this->partnerType = $this->partner->type?->value ?? ''; // Stammdaten $this->companyName = $this->partner->company_name ?? ''; $this->displayName = $this->partner->display_name ?? ''; $this->salutation = $this->partner->salutation ?? ''; $this->firstName = $this->partner->first_name ?? ''; $this->lastName = $this->partner->last_name ?? ''; $this->description = $this->partner->description ?? ''; $this->street = $this->partner->street ?? ''; $this->houseNumber = $this->partner->house_number ?? ''; $this->zip = $this->partner->zip ?? ''; $this->city = $this->partner->city ?? ''; $this->country = $this->partner->country ?? 'Deutschland'; $this->phone = $this->partner->phone ?? ''; $this->website = $this->partner->website ?? ''; $this->deliveryRadius = $this->partner->delivery_radius_km; $this->assemblyRadius = $this->partner->assembly_radius_km; // Platzhalter wie "roles.broker M10000004" ersetzen if (str_contains($this->companyName, 'roles.')) { $parts = explode(' ', $this->companyName, 2); $translatedRole = isset($parts[0]) ? __($parts[0]) : $this->companyName; $partnerId = isset($parts[1]) ? ' '.$parts[1] : ''; $this->companyName = $translatedRole.$partnerId; } // Namen aus User übernehmen, falls Partner-Felder leer sind if (empty($this->firstName) && empty($this->lastName)) { $nameParts = explode(' ', $user->name, 2); $this->firstName = $nameParts[0] ?? ''; $this->lastName = $nameParts[1] ?? ''; } // Profil-Felder $this->storyText = $this->partner->story_text ?? ''; $this->foundedYear = $this->partner->founded_year ?? ''; $this->specialtiesInput = $this->partner->specialties ? implode(', ', $this->partner->specialties) : ''; if ($this->partner->opening_hours) { $this->openingHours = array_merge($this->openingHours, $this->partner->opening_hours); } // Marke für Manufacturer if ($this->isManufacturer()) { $brand = Brand::where('partner_id', $this->partner->id)->first(); if ($brand) { $this->brandName = $brand->name; $this->brandDescription = $brand->description ?? ''; } } $this->loadExistingMedia(); } // ── Foto-Verwaltung ──────────────────────────────────────────────────────── public function removeQueuedPhoto(int $index, string $type): void { $property = $this->queuedPropertyForType($type); if ($property && isset($this->$property[$index])) { unset($this->$property[$index]); $this->$property = array_values($this->$property); } } public function removeExistingPhoto(int $mediaId, string $type): void { $media = Media::where('id', $mediaId) ->where('model_type', Partner::class) ->where('model_id', $this->partner->id) ->firstOrFail(); Storage::disk('public')->delete($media->file_path); $media->delete(); $property = $this->existingPropertyForType($type); if ($property) { $this->$property = array_values( array_filter($this->$property, fn ($m) => $m['id'] !== $mediaId) ); } } /** * Reihenfolge per Drag-&-Drop aktualisieren. * * @param array $orderedIds */ public function updatePhotoOrder(array $orderedIds, string $type): void { foreach ($orderedIds as $position => $mediaId) { $this->partner->media() ->where('id', $mediaId) ->where('type', $type) ->update(['order_column' => $position + 1]); } $property = $this->existingPropertyForType($type); if (! $property) { return; } $reordered = collect($orderedIds)->map(function ($id, $index) use ($property) { $media = collect($this->$property)->firstWhere('id', $id); return $media ? array_merge($media, ['order_column' => $index + 1]) : null; })->filter()->values()->toArray(); $this->$property = $reordered; } // ── Speichern ────────────────────────────────────────────────────────────── public function saveData(): void { $rules = [ 'salutation' => 'required|in:Herr,Frau,Divers', 'firstName' => 'required|string|max:255', 'lastName' => 'required|string|max:255', 'street' => 'required|string|max:255', 'houseNumber' => 'required|string|max:20', 'zip' => 'required|string|max:10', 'city' => 'required|string|max:255', 'country' => 'required|string|max:255', 'phone' => 'nullable|string|max:50', 'storyText' => 'nullable|string|max:2000', 'foundedYear' => 'nullable|integer|min:1800|max:'.now()->year, 'specialtiesInput' => 'nullable|string|max:500', ]; if (! $this->isCustomer()) { $rules['companyName'] = 'required|string|max:255'; $rules['description'] = 'nullable|string|max:1000'; $rules['website'] = 'nullable|url|max:255'; } if ($this->isBroker()) { $rules['displayName'] = 'required|string|max:255'; } if ($this->isRetailer()) { $rules['deliveryRadius'] = 'required|integer|min:1|max:500'; $rules['assemblyRadius'] = 'required|integer|min:1|max:500'; $rules['newTeamPhotos'] = 'nullable|array|max:10'; $rules['newTeamPhotos.*'] = 'image|mimes:jpeg,jpg,png|max:204800'; $rules['newShowroomPhotos'] = 'nullable|array|max:20'; $rules['newShowroomPhotos.*'] = 'image|mimes:jpeg,jpg,png|max:204800'; } if ($this->isManufacturer()) { $rules['brandName'] = 'required|string|max:255'; $rules['brandDescription'] = 'nullable|string|max:1000'; $rules['newBrandImages'] = 'nullable|array|max:10'; $rules['newBrandImages.*'] = 'image|mimes:jpeg,jpg,png|max:204800'; } $this->validate($rules, [ 'salutation.required' => __('Bitte wählen Sie eine Anrede.'), 'firstName.required' => __('Bitte geben Sie einen Vornamen ein.'), 'lastName.required' => __('Bitte geben Sie einen Nachnamen ein.'), 'companyName.required' => __('Bitte geben Sie einen Firmennamen ein.'), 'displayName.required' => __('Bitte geben Sie einen Anzeigenamen ein.'), 'street.required' => __('Bitte geben Sie eine Straße ein.'), 'houseNumber.required' => __('Bitte geben Sie eine Hausnummer ein.'), 'zip.required' => __('Bitte geben Sie eine Postleitzahl ein.'), 'city.required' => __('Bitte geben Sie eine Stadt ein.'), 'country.required' => __('Bitte wählen Sie ein Land.'), 'website.url' => __('Bitte geben Sie eine gültige URL ein.'), 'deliveryRadius.required' => __('Bitte geben Sie einen Lieferradius ein.'), 'deliveryRadius.min' => __('Der Lieferradius muss mindestens 1 km betragen.'), 'assemblyRadius.required' => __('Bitte geben Sie einen Montageradius ein.'), 'assemblyRadius.min' => __('Der Montageradius muss mindestens 1 km betragen.'), 'brandName.required' => __('Bitte geben Sie einen Markennamen ein.'), 'foundedYear.integer' => __('Bitte geben Sie eine gültige Jahreszahl ein.'), 'foundedYear.min' => __('Das Gründungsjahr muss nach 1800 liegen.'), 'foundedYear.max' => __('Das Gründungsjahr darf nicht in der Zukunft liegen.'), 'newTeamPhotos.*.image' => __('Nur Bilder (JPG, PNG) erlaubt.'), 'newTeamPhotos.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'), 'newShowroomPhotos.*.image' => __('Nur Bilder (JPG, PNG) erlaubt.'), 'newShowroomPhotos.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'), 'newBrandImages.*.image' => __('Nur Bilder (JPG, PNG) erlaubt.'), 'newBrandImages.*.max' => __('Bilder dürfen maximal 200 MB groß sein.'), ]); $specialties = array_values(array_filter( array_map('trim', explode(',', $this->specialtiesInput)) )); $updateData = [ 'salutation' => $this->salutation, 'first_name' => $this->firstName, 'last_name' => $this->lastName, 'street' => $this->street, 'house_number' => $this->houseNumber, 'zip' => $this->zip, 'city' => $this->city, 'country' => $this->country, 'phone' => $this->phone, 'story_text' => $this->storyText ?: null, 'founded_year' => $this->foundedYear ?: null, 'specialties' => $specialties ?: null, ]; if (! $this->isCustomer()) { $updateData['company_name'] = $this->companyName; $updateData['description'] = $this->description; $updateData['website'] = $this->website; } if ($this->isBroker()) { $updateData['display_name'] = $this->displayName; } if ($this->isRetailer()) { $updateData['delivery_radius_km'] = $this->deliveryRadius; $updateData['assembly_radius_km'] = $this->assemblyRadius; $updateData['opening_hours'] = $this->openingHours; } $this->partner->update($updateData); if ($this->isManufacturer()) { Brand::updateOrCreate( ['partner_id' => $this->partner->id], [ 'name' => $this->brandName, 'slug' => Str::slug($this->brandName), 'description' => $this->brandDescription, 'is_active' => true, ] ); } $this->saveUploadedPhotos($this->newTeamPhotos, 'team_photo'); $this->saveUploadedPhotos($this->newShowroomPhotos, 'showroom'); $this->saveUploadedPhotos($this->newBrandImages, 'brand_image'); $this->newTeamPhotos = []; $this->newShowroomPhotos = []; $this->newBrandImages = []; $this->partner->load('media'); $this->loadExistingMedia(); session()->flash('message', __('Ihre Daten wurden erfolgreich aktualisiert.')); } // ── Hilfsmethoden ────────────────────────────────────────────────────────── private function isCustomer(): bool { return strtolower(str_replace('-', '', $this->partnerType)) === 'customer'; } private function isRetailer(): bool { return strtolower(str_replace('-', '', $this->partnerType)) === 'retailer'; } private function isManufacturer(): bool { return strtolower(str_replace('-', '', $this->partnerType)) === 'manufacturer'; } private function isBroker(): bool { $t = strtolower(str_replace('-', '', $this->partnerType)); return $t === 'broker' || $t === 'estateagent'; } private function loadExistingMedia(): void { $this->existingTeamPhotos = $this->partner->media ->where('type', 'team_photo') ->sortBy('order_column') ->values() ->map(fn ($m) => ['id' => $m->id, 'file_path' => $m->file_path, 'alt_text' => $m->alt_text ?? '']) ->toArray(); $this->existingShowroomPhotos = $this->partner->media ->where('type', 'showroom') ->sortBy('order_column') ->values() ->map(fn ($m) => ['id' => $m->id, 'file_path' => $m->file_path, 'alt_text' => $m->alt_text ?? '']) ->toArray(); $this->existingBrandImages = $this->partner->media ->where('type', 'brand_image') ->sortBy('order_column') ->values() ->map(fn ($m) => ['id' => $m->id, 'file_path' => $m->file_path, 'alt_text' => $m->alt_text ?? '']) ->toArray(); } /** @param array $files */ private function saveUploadedPhotos(array $files, string $type): void { if (empty($files)) { return; } $maxOrder = $this->partner->media() ->where('type', $type) ->max('order_column') ?? 0; $index = $maxOrder + 1; foreach ($files as $file) { $path = $file->store('partners/'.$this->partner->id.'/'.$type, 'public'); $this->partner->media()->create([ 'file_path' => $path, 'type' => $type, 'alt_text' => $this->partner->company_name, 'order_column' => $index++, ]); } } private function queuedPropertyForType(string $type): ?string { return match ($type) { 'team_photo' => 'newTeamPhotos', 'showroom' => 'newShowroomPhotos', 'brand_image' => 'newBrandImages', default => null, }; } private function existingPropertyForType(string $type): ?string { return match ($type) { 'team_photo' => 'existingTeamPhotos', 'showroom' => 'existingShowroomPhotos', 'brand_image' => 'existingBrandImages', default => null, }; } /** @return array */ protected function dayLabels(): array { return [ 'monday' => __('Montag'), 'tuesday' => __('Dienstag'), 'wednesday' => __('Mittwoch'), 'thursday' => __('Donnerstag'), 'friday' => __('Freitag'), 'saturday' => __('Samstag'), 'sunday' => __('Sonntag'), ]; } public function with(): array { return [ 'dayLabels' => $this->dayLabels(), 'isRetailer' => $this->isRetailer(), 'isManufacturer' => $this->isManufacturer(), 'isCustomer' => $this->isCustomer(), 'isBroker' => $this->isBroker(), ]; } }; ?>
{{-- Header --}}
{{ __('Meine Daten') }} {{ __('Verwalten Sie Ihre Firmendaten und Ihr Profil') }}
@svg('heroicon-o-'.$roleIcon, 'w-6 h-6 text-accent-600 dark:text-accent-400') {{ $roleName }}
{{-- Tab-Navigation --}} {{ __('Stammdaten') }} {{ $isRetailer ? __('Präsentation') : __('Über uns') }} @if ($isRetailer) {{ __('Öffnungszeiten') }} @endif @if ($isRetailer || $isManufacturer) {{ __('Fotos') }} @endif {{-- ── TAB 1: STAMMDATEN ── --}} @if ($activeTab === 'stammdaten')
{{ __('Firmendaten') }} {{ __('Ihre Kontakt- und Adressdaten') }}
@if (!$isCustomer) {{ __('Firmenname') }} * @error('companyName') {{ $message }} @enderror @if ($isBroker) {{ __('Anzeigename') }} * {{ __('Der Name, der Ihren Kunden angezeigt wird') }} @error('displayName') {{ $message }} @enderror @endif {{ __('Kurzbeschreibung') }} @error('description') {{ $message }} @enderror @endif {{-- Persönliche Daten --}}
{{ __('Anrede') }} * {{ __('Bitte wählen') }} {{ __('Herr') }} {{ __('Frau') }} {{ __('Divers') }} @error('salutation') {{ $message }} @enderror {{ __('Vorname') }} * @error('firstName') {{ $message }} @enderror {{ __('Nachname') }} * @error('lastName') {{ $message }} @enderror
{{-- Adresse --}}
{{ __('Straße') }} * @error('street') {{ $message }} @enderror {{ __('Hausnummer') }} * @error('houseNumber') {{ $message }} @enderror
{{ __('Postleitzahl') }} * @error('zip') {{ $message }} @enderror {{ __('Ort') }} * @error('city') {{ $message }} @enderror
{{ __('Land') }} * {{ __('Deutschland') }} {{ __('Österreich') }} {{ __('Schweiz') }} @error('country') {{ $message }} @enderror
{{ __('Telefon') }} @error('phone') {{ $message }} @enderror @if (!$isCustomer) {{ __('Website') }} @error('website') {{ $message }} @enderror @endif
{{-- Liefergebiete (nur Händler) --}} @if ($isRetailer)

{{ __('Liefergebiete') }}

{{ __('Definieren Sie, in welchem Umkreis Sie liefern und montieren können.') }}

{{ __('Lieferradius (km)') }} * {{ __('Ich liefere im Umkreis von ... km') }} @error('deliveryRadius') {{ $message }} @enderror {{ __('Montageradius (km)') }} * {{ __('Ich montiere im Umkreis von ... km') }} @error('assemblyRadius') {{ $message }} @enderror
@endif
@endif {{-- ── TAB 2: PRÄSENTATION / ÜBER UNS ── --}} @if ($activeTab === 'praesentation')
{{-- Story & Profil --}}
{{ $isRetailer ? __('Präsentation & Story') : __('Über das Unternehmen') }} {{ $isRetailer ? __('Erzählen Sie Ihre Geschichte – was macht Ihren Showroom besonders?') : __('Teilen Sie Ihre Unternehmensgeschichte und Spezialisierungen.') }}
{{ __('Über uns / Story') }} {{ __('Sichtbar auf Ihrem öffentlichen Profil. Max. 2000 Zeichen.') }}
{{ strlen($storyText) }} / 2000
@error('storyText') {{ $message }} @enderror
{{ __('Gründungsjahr') }} @error('foundedYear') {{ $message }} @enderror {{ __('Spezialisierungen') }} {{ __('Kommagetrennt, z.B.: Polstermöbel, Outdoor, Küchen') }} @error('specialtiesInput') {{ $message }} @enderror
{{-- Marke (nur Hersteller) --}} @if ($isManufacturer)
{{ __('Ihre Marke') }} {{ __('Unter dieser Marke werden Ihre Produkte auf B2in gelistet.') }}
{{ __('Markenname') }} * @error('brandName') {{ $message }} @enderror {{ __('Marken-Beschreibung') }} @error('brandDescription') {{ $message }} @enderror
@endif
@endif {{-- ── TAB 3: ÖFFNUNGSZEITEN (nur Händler) ── --}} @if ($activeTab === 'oeffnungszeiten' && $isRetailer)
{{ __('Öffnungszeiten') }} {{ __('Wann sind Sie für Kunden erreichbar oder Ihr Showroom geöffnet?') }}
@foreach ($dayLabels as $dayKey => $dayLabel)
{{ $dayLabel }}
@unless ($openingHours[$dayKey]['closed'] ?? false)
@endunless
@endforeach
@endif {{-- ── TAB 4: FOTOS ── --}} @if ($activeTab === 'fotos' && ($isRetailer || $isManufacturer))
@if ($isRetailer) {{-- ── Team-Fotos ── --}}
{{ __('Team-Fotos') }} {{ __('Nur JPG/PNG – max. 200 MB pro Bild') }}
@if (count($existingTeamPhotos) > 0)
{{ __('Vorhandene Fotos') }} {{ __('Per Drag & Drop sortieren – das erste Foto wird als Hauptbild verwendet.') }}
@foreach ($existingTeamPhotos as $photo)
{{ $photo['alt_text'] }}
@endforeach
@endif @if (count($newTeamPhotos) > 0)
@foreach ($newTeamPhotos as $index => $photo) @endforeach
@endif
{{-- ── Showroom-Galerie ── --}}
{{ __('Showroom-Galerie') }} {{ __('Bilder Ihres Showrooms für das öffentliche Profil – nur JPG/PNG, max. 200 MB') }}
@if (count($existingShowroomPhotos) > 0)
{{ __('Vorhandene Bilder') }} {{ __('Per Drag & Drop sortieren.') }}
@foreach ($existingShowroomPhotos as $photo)
{{ $photo['alt_text'] }}
@endforeach
@endif @if (count($newShowroomPhotos) > 0)
@foreach ($newShowroomPhotos as $index => $photo) @endforeach
@endif
@endif @if ($isManufacturer) {{-- ── Marken-Bilder ── --}}
{{ __('Marken-Bilder') }} {{ __('Bilder für Ihre Marken-Präsentation (Atmosphäre, Brand-Story etc.) – nur JPG/PNG, max. 200 MB') }}
@if (count($existingBrandImages) > 0)
{{ __('Vorhandene Bilder') }} {{ __('Per Drag & Drop sortieren.') }}
@foreach ($existingBrandImages as $photo)
{{ $photo['alt_text'] }}
@endforeach
@endif @if (count($newBrandImages) > 0)
@foreach ($newBrandImages as $index => $photo) @endforeach
@endif
@endif
@endif {{-- Speichern-Button --}}
{{ __('Änderungen speichern') }} {{ __('Wird gespeichert...') }}