admin: PM-Detailseite verlinkt Firma, Autor und Firmen-Benutzer
Firma und Autor sind im Header und Status-Grid klickbar
(admin/companies/{id} bzw. admin/users/{id}). Das Kontakte-Panel heißt
jetzt "Firma & Pressekontakte" und zeigt die Firmendaten (Adresse,
E-Mail, Telefon, Website) über den Pressekontakten. Neu: "Benutzer mit
Zugriff (über Firma)" listet alle Firmen-Mitglieder mit Rolle und
Autor-Markierung — mehrere User hängen nur über die Firma an einer PM,
Magic-Links sind reine Login-Tokens.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
fa303360ee
commit
e3ce626b73
2 changed files with 127 additions and 10 deletions
|
|
@ -73,7 +73,8 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
{
|
||||
$pr = PressRelease::withoutGlobalScopes()
|
||||
->with([
|
||||
'company:id,name,email,phone,slug',
|
||||
'company:id,name,email,phone,website,address,country_code,slug',
|
||||
'company.users:users.id,users.name,users.email',
|
||||
'category.translations',
|
||||
'user:id,name,email',
|
||||
'images',
|
||||
|
|
@ -161,13 +162,27 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
@endif
|
||||
<p class="text-[13px] leading-[1.55] mt-2 m-0 max-w-[720px] text-[color:var(--color-ink-2)]">
|
||||
<strong class="font-semibold text-[color:var(--color-ink)]">{{ __('Firma') }}:</strong>
|
||||
{{ $pr->company?->name ?? '–' }}
|
||||
@if ($pr->company)
|
||||
<a href="{{ route('admin.companies.show', $pr->company->id) }}" wire:navigate
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->company->name }}
|
||||
</a>
|
||||
@else
|
||||
–
|
||||
@endif
|
||||
<span class="text-[color:var(--color-bg-rule)] mx-1">·</span>
|
||||
<strong class="font-semibold text-[color:var(--color-ink)]">{{ __('Kategorie') }}:</strong>
|
||||
{{ $categoryName }}
|
||||
<span class="text-[color:var(--color-bg-rule)] mx-1">·</span>
|
||||
<strong class="font-semibold text-[color:var(--color-ink)]">{{ __('Autor') }}:</strong>
|
||||
{{ $pr->user?->name ?? '–' }}
|
||||
@if ($pr->user)
|
||||
<a href="{{ route('admin.users.show', $pr->user->id) }}" wire:navigate
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->user->name }}
|
||||
</a>
|
||||
@else
|
||||
–
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -321,17 +336,52 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
<div class="grid gap-6 xl:grid-cols-2">
|
||||
<article class="panel">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('Zugeordnete Pressekontakte') }}</span>
|
||||
<span class="section-eyebrow">{{ __('Firma & Pressekontakte') }}</span>
|
||||
@if ($pr->company)
|
||||
<flux:button size="sm" variant="filled" icon="building-office" href="{{ route('admin.companies.show', $pr->company->id) }}" wire:navigate>
|
||||
{{ __('Firma') }}
|
||||
{{ __('Firma öffnen') }}
|
||||
</flux:button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<p class="text-[12px] text-[color:var(--color-ink-3)] mt-0 mb-4">
|
||||
{{ __('Kontakte, die dieser Pressemitteilung zugeordnet sind.') }}
|
||||
</p>
|
||||
@if ($pr->company)
|
||||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[13px] font-semibold">
|
||||
<a href="{{ route('admin.companies.show', $pr->company->id) }}" wire:navigate
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->company->name }}
|
||||
</a>
|
||||
</div>
|
||||
@if ($pr->company->address || $pr->company->country_code)
|
||||
<div class="text-[12px] text-[color:var(--color-ink-3)] whitespace-pre-line">{{ trim($pr->company->address.' '.$pr->company->country_code) }}</div>
|
||||
@endif
|
||||
<div class="mt-1 flex flex-wrap gap-x-3 gap-y-1 text-[11.5px] text-[color:var(--color-ink-3)]">
|
||||
@if ($pr->company->email)
|
||||
<a href="mailto:{{ $pr->company->email }}"
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->company->email }}
|
||||
</a>
|
||||
@endif
|
||||
@if ($pr->company->phone)
|
||||
<span>{{ $pr->company->phone }}</span>
|
||||
@endif
|
||||
@if ($pr->company->website)
|
||||
<a href="{{ $pr->company->website }}" target="_blank" rel="noopener"
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->company->website }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="rounded-[5px] border border-dashed border-[color:var(--color-bg-rule)] p-4 text-[12.5px] text-[color:var(--color-ink-3)]">
|
||||
{{ __('Dieser Pressemitteilung ist keine Firma zugeordnet.') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold mt-4 mb-2">
|
||||
{{ __('Zugeordnete Pressekontakte') }}
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
@forelse ($contacts as $contact)
|
||||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
|
|
@ -372,7 +422,14 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold">{{ __('Autor') }}</div>
|
||||
<div class="text-[13px] font-semibold text-[color:var(--color-ink)] mt-1 truncate">
|
||||
{{ $pr->user?->name ?? '–' }}
|
||||
@if ($pr->user)
|
||||
<a href="{{ route('admin.users.show', $pr->user->id) }}" wire:navigate
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->user->name }}
|
||||
</a>
|
||||
@else
|
||||
–
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
|
|
@ -411,6 +468,32 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
@endif
|
||||
</div>
|
||||
|
||||
@php
|
||||
// Neben dem Autor können weitere User (Firmen-Mitglieder, z. B.
|
||||
// per Magic-Link eingeladen) auf die PM zugreifen.
|
||||
$companyUsers = $pr->company?->users ?? collect();
|
||||
@endphp
|
||||
@if ($companyUsers->isNotEmpty())
|
||||
<div class="mt-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold">
|
||||
{{ __('Benutzer mit Zugriff (über Firma)') }}
|
||||
</div>
|
||||
<div class="mt-1.5 flex flex-wrap gap-x-3 gap-y-1 text-[12.5px]">
|
||||
@foreach ($companyUsers as $companyUser)
|
||||
<span class="inline-flex items-center gap-1.5">
|
||||
<a href="{{ route('admin.users.show', $companyUser->id) }}" wire:navigate
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $companyUser->name }}
|
||||
</a>
|
||||
<span class="text-[11px] text-[color:var(--color-ink-3)]">
|
||||
{{ $companyUser->pivot->role === 'owner' ? __('Owner') : __('Member') }}@if ($companyUser->id === $pr->user_id) · {{ __('Autor') }}@endif
|
||||
</span>
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($pr->no_export)
|
||||
<div class="mt-3 flex items-center gap-2 text-[12px] text-[color:var(--color-ink-3)]">
|
||||
<flux:icon.no-symbol variant="micro" class="size-3.5" />
|
||||
|
|
|
|||
|
|
@ -51,7 +51,12 @@ test('admin show zeigt zugeordnete Pressekontakte', function () {
|
|||
$admin = makeAdminForShow();
|
||||
$this->actingAs($admin);
|
||||
|
||||
$company = Company::factory()->presseecho()->create();
|
||||
$company = Company::factory()->presseecho()->create([
|
||||
'name' => 'Muster GmbH',
|
||||
'email' => 'firma@example.test',
|
||||
'phone' => '+49 30 1234567',
|
||||
'website' => 'https://muster.example.test',
|
||||
]);
|
||||
$contact = Contact::factory()->for($company)->create([
|
||||
'first_name' => 'Max',
|
||||
'last_name' => 'Mustermann',
|
||||
|
|
@ -64,6 +69,11 @@ test('admin show zeigt zugeordnete Pressekontakte', function () {
|
|||
$pr->contacts()->sync([$contact->id]);
|
||||
|
||||
LivewireVolt::test('admin.press-releases.show', ['id' => $pr->id])
|
||||
->assertSee('Firma & Pressekontakte')
|
||||
->assertSee('Muster GmbH')
|
||||
->assertSee('firma@example.test')
|
||||
->assertSee('+49 30 1234567')
|
||||
->assertSee('https://muster.example.test')
|
||||
->assertSee('Zugeordnete Pressekontakte')
|
||||
->assertSee('Max Mustermann')
|
||||
->assertSee('Pressesprecher')
|
||||
|
|
@ -112,6 +122,30 @@ test('admin show zeigt Embargo-Info im Published-Workflow', function () {
|
|||
->assertSee('Sperrfrist bis');
|
||||
});
|
||||
|
||||
test('admin show verlinkt Firma, Autor und Firmen-Benutzer', function () {
|
||||
/** @var TestCase $this */
|
||||
$admin = makeAdminForShow();
|
||||
$this->actingAs($admin);
|
||||
|
||||
$company = Company::factory()->presseecho()->create(['name' => 'Muster GmbH']);
|
||||
$author = User::factory()->create(['name' => 'Anna Autorin']);
|
||||
$coEditor = User::factory()->create(['name' => 'Carl Co-Editor']);
|
||||
$company->users()->attach($author->id, ['role' => 'owner']);
|
||||
$company->users()->attach($coEditor->id, ['role' => 'member']);
|
||||
|
||||
$pr = PressRelease::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
'user_id' => $author->id,
|
||||
]);
|
||||
|
||||
LivewireVolt::test('admin.press-releases.show', ['id' => $pr->id])
|
||||
->assertSee('Benutzer mit Zugriff')
|
||||
->assertSee('Carl Co-Editor')
|
||||
->assertSeeHtml(route('admin.companies.show', $company->id))
|
||||
->assertSeeHtml(route('admin.users.show', $author->id))
|
||||
->assertSeeHtml(route('admin.users.show', $coEditor->id));
|
||||
});
|
||||
|
||||
test('admin show zeigt Autor im Status-Verlauf-Grid', function () {
|
||||
/** @var TestCase $this */
|
||||
$admin = makeAdminForShow();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue