kunde: PM-Liste zeigt Firmen-Kontext unter der Headline und Bild-Thumbnails
Der aktive Firmen-Kontext (Firmen-Umschalter) steht jetzt prominent unter der Überschrift — Firmenname oder „Alle Firmen" — statt als kleiner Hinweistext. Neue Spalte „Bild" zwischen Status und Titel mit dem Titelbild (thumb-Variante, is_preview zuerst), dem gewählten Platzhalter bei bildlosen PMs oder einem generischen Icon-Fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
17e22d2d46
commit
45dc4ce66c
4 changed files with 100 additions and 8 deletions
|
|
@ -178,6 +178,18 @@ class PressRelease extends Model
|
|||
return $image?->variantUrl('card') ?? $image?->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bild-URL für Listen-Thumbnails: thumb-Variante des Titelbildes,
|
||||
* Fallback card-Variante bzw. Original. Null bei bildlosen PMs
|
||||
* (dann greift chosenPlaceholderUrl() bzw. der generische Fallback).
|
||||
*/
|
||||
public function thumbImageUrl(): ?string
|
||||
{
|
||||
$image = $this->images?->first();
|
||||
|
||||
return $image?->variantUrl('thumb') ?? $image?->variantUrl('card') ?? $image?->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag-freier, whitespace-normalisierter Anriss des PM-Textes.
|
||||
*/
|
||||
|
|
@ -607,8 +619,14 @@ class PressRelease extends Model
|
|||
|
||||
$models = static::query()->withoutGlobalScopes()
|
||||
->whereKey($pageIds)
|
||||
// Kategorie fürs Listen-Rendering (localizedCategoryName, 13.07.).
|
||||
->with(['company:id,name', 'category.translations'])
|
||||
// Kategorie fürs Listen-Rendering (localizedCategoryName, 13.07.);
|
||||
// Bilder fürs Listen-Thumbnail — Titelbild zuerst (is_preview,
|
||||
// gleiche Reihenfolge wie in der PM-Vorschau).
|
||||
->with([
|
||||
'company:id,name',
|
||||
'category.translations',
|
||||
'images' => fn ($query) => $query->orderByDesc('is_preview')->orderBy('sort_order'),
|
||||
])
|
||||
// Für das Einreichungs-Modal je Zeile: ohne eigenes Bild entfällt
|
||||
// die Bildrechte-Bestätigung.
|
||||
->withCount('images')
|
||||
|
|
|
|||
|
|
@ -205,6 +205,17 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
|
|||
{{ __('Meine Pressemitteilungen') }}
|
||||
</h1>
|
||||
|
||||
{{-- Aktiver Firmen-Kontext direkt unter der Headline: macht sichtbar,
|
||||
auf welche Firma (Firmen-Umschalter oben) die Liste eingeschränkt ist. --}}
|
||||
<div class="mt-2 flex items-center gap-1.5 text-[13.5px] font-semibold text-[color:var(--color-ink-2)]">
|
||||
<flux:icon.building-office variant="micro" class="size-4 text-[color:var(--color-ink-3)]" />
|
||||
@if ($selectedCompany)
|
||||
<span>{{ $selectedCompany->name }}</span>
|
||||
@else
|
||||
<span>{{ __('Alle Firmen') }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Counter-Strip + Kontext-Hinweis --}}
|
||||
@if ($hasAnyPR)
|
||||
<div class="counter-strip mt-3">
|
||||
|
|
@ -236,11 +247,7 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
|
|||
</div>
|
||||
@endif
|
||||
|
||||
@if ($selectedCompany)
|
||||
<p class="text-[12.5px] leading-[1.55] mt-2 m-0 text-[color:var(--color-ink-3)]">
|
||||
{{ __('Gefiltert auf :company', ['company' => $selectedCompany->name]) }}
|
||||
</p>
|
||||
@elseif (!$hasAnyPR)
|
||||
@if (!$hasAnyPR)
|
||||
<p class="text-[13.5px] leading-[1.55] mt-2 m-0 max-w-[640px] text-[color:var(--color-ink-2)]">
|
||||
{{ __('Übersicht aller PMs Ihres Kundenkontos, mit Filter und Schnellaktionen.') }}
|
||||
</p>
|
||||
|
|
@ -426,6 +433,7 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
|
|||
<flux:table>
|
||||
<flux:table.columns>
|
||||
<flux:table.column class="w-[140px]">{{ __('Status') }}</flux:table.column>
|
||||
<flux:table.column class="w-[88px]">{{ __('Bild') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'title'" :direction="$sortDir"
|
||||
wire:click="sort('title')">
|
||||
{{ __('Titel') }}
|
||||
|
|
@ -506,6 +514,24 @@ new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class
|
|||
@endif
|
||||
</flux:table.cell>
|
||||
|
||||
<flux:table.cell>
|
||||
{{-- Vorschaubild: Titelbild der PM, sonst der gewählte
|
||||
Platzhalter, sonst generischer Bild-Fallback. --}}
|
||||
@php $thumbUrl = $pr->thumbImageUrl() ?? $pr->chosenPlaceholderUrl(); @endphp
|
||||
<a href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate class="block w-16">
|
||||
@if ($thumbUrl)
|
||||
<img src="{{ $thumbUrl }}" alt=""
|
||||
class="h-12 w-16 rounded-[3px] object-cover border border-[color:var(--color-bg-rule)]"
|
||||
loading="lazy">
|
||||
@else
|
||||
<span
|
||||
class="flex h-12 w-16 items-center justify-center rounded-[3px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] text-[color:var(--color-ink-4)]">
|
||||
<flux:icon.photo variant="micro" class="size-4" />
|
||||
</span>
|
||||
@endif
|
||||
</a>
|
||||
</flux:table.cell>
|
||||
|
||||
<flux:table.cell>
|
||||
<div class="flex items-start gap-1.5">
|
||||
<a href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate
|
||||
|
|
|
|||
|
|
@ -98,7 +98,8 @@ test('customer press release list is filtered by selected company context', func
|
|||
->withSession([CustomerCompanyContext::SessionKey => $company->id]);
|
||||
|
||||
LivewireVolt::test('customer.press-releases.index')
|
||||
->assertSee('Gefiltert auf Alpha GmbH')
|
||||
->assertSee('Alpha GmbH')
|
||||
->assertDontSee('Alle Firmen')
|
||||
->assertSee('Alpha Produktmeldung')
|
||||
->assertDontSee('Beta Produktmeldung');
|
||||
});
|
||||
|
|
@ -124,6 +125,7 @@ test('customer press release list can filter unassigned legacy press releases',
|
|||
|
||||
LivewireVolt::test('customer.press-releases.index')
|
||||
->set('companyFilter', 'unassigned')
|
||||
->assertSee('Alle Firmen')
|
||||
->assertSee('Legacy ohne Firma')
|
||||
->assertDontSee('Alpha Firmenmeldung');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -205,3 +205,49 @@ test('admin list filtert nach KI-Klassifikation', function () {
|
|||
->assertSee('Gelber Grenzfall')
|
||||
->assertDontSee('Grüne Mitteilung');
|
||||
});
|
||||
|
||||
test('customer list zeigt das Titelbild als Thumbnail in der Bild-Spalte', function () {
|
||||
/** @var TestCase $this */
|
||||
$customer = makeCustomerForIndexPhase8b();
|
||||
$this->actingAs($customer);
|
||||
|
||||
$pr = PressRelease::factory()->create([
|
||||
'user_id' => $customer->id,
|
||||
'title' => 'PM mit Titelbild',
|
||||
]);
|
||||
// Zweitbild zuerst angelegt — das Titelbild (is_preview) muss trotzdem gewinnen.
|
||||
$pr->images()->create([
|
||||
'disk' => 'public',
|
||||
'path' => 'press/second.jpg',
|
||||
'variants' => ['thumb' => 'press/second-thumb.jpg'],
|
||||
'is_preview' => false,
|
||||
'sort_order' => 2,
|
||||
]);
|
||||
$pr->images()->create([
|
||||
'disk' => 'public',
|
||||
'path' => 'press/cover.jpg',
|
||||
'variants' => ['thumb' => 'press/cover-thumb.jpg'],
|
||||
'is_preview' => true,
|
||||
'sort_order' => 1,
|
||||
]);
|
||||
|
||||
LivewireVolt::test('customer.press-releases.index')
|
||||
->assertSee('Bild')
|
||||
->assertSee('storage/press/cover-thumb.jpg', false)
|
||||
->assertDontSee('storage/press/second-thumb.jpg', false);
|
||||
});
|
||||
|
||||
test('customer list zeigt den gewählten Platzhalter als Thumbnail bei bildlosen PMs', function () {
|
||||
/** @var TestCase $this */
|
||||
$customer = makeCustomerForIndexPhase8b();
|
||||
$this->actingAs($customer);
|
||||
|
||||
PressRelease::factory()->create([
|
||||
'user_id' => $customer->id,
|
||||
'title' => 'PM ohne Bild',
|
||||
'placeholder_variant' => '05-lines-green',
|
||||
]);
|
||||
|
||||
LivewireVolt::test('customer.press-releases.index')
|
||||
->assertSee('press-release-placeholders/05-lines-green.svg', false);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue