{{-- Admin Demo show page. MIRROR OF: admin.committees.show — same rd-shell + rd-card scaffolding, same overview tiles, same sticky section nav, same investor/startup roster pattern. Demo-specific: - Hero card uses the bilingual title + type/mode pills - Optional cover image rendered as a hero strip on top - Evaluations matrix (Alpine) reused from the earlier baseline - No Pass/Fail panel chevron yet — matrix lives inside its own rd-card with the same chrome as committee evaluations --}} @extends('admin.layouts.app') @section('title', $demo->localizedTitle() . ' — ' . __('admin.brand.name')) @section('page_title', $demo->localizedTitle()) @php use Illuminate\Support\Carbon; $isActive = $demo->status === \App\Models\Demo::STATUS_ACTIVE; $locale = app()->getLocale(); $meetingDt = $demo->meeting_date; $monthShort = $meetingDt instanceof Carbon ? $meetingDt->locale($locale)->translatedFormat('M') : '—'; $dayNumber = $meetingDt instanceof Carbon ? $meetingDt->format('j') : '—'; $dayLabel = $meetingDt instanceof Carbon ? $meetingDt->locale($locale)->translatedFormat('l') : '—'; $typeLabel = $demo->type?->{$locale === 'ar' ? 'name_ar' : 'name_en'}; $modeLabel = $demo->mode?->{$locale === 'ar' ? 'name_ar' : 'name_en'}; // ── Shared attendance/registration presentation helpers ─────────────── // Defined ONCE at page scope so the Attendance investors table and the // Webinar summary render pills identically (single source of truth). $pill = fn ($v, $tone) => ''.e(ucfirst((string) $v)).''; $regTone = fn ($s) => ['registered'=>'ok','failed'=>'danger','awaiting'=>'warn','registering'=>'warn','pending'=>'muted'][$s] ?? 'muted'; $attTone = fn ($s) => ['attended'=>'ok','absent'=>'danger','registered'=>'warn','pending'=>'muted'][$s] ?? 'muted'; // Attendance timestamps are stored in UTC (Microsoft Graph returns UTC and the // app timezone is UTC). Display them in the webinar's BUSINESS timezone so they // match the meeting time the admin sees — never a hard-coded offset. $attTz = config('demo_webinars.timezone', 'Asia/Riyadh'); $fmtTime = fn ($dt) => $dt ? Carbon::parse($dt)->timezone($attTz)->format('H:i') : '—'; $isRegistered = fn ($att) => $att && $att->registration_status === \App\Models\DemoAttendance::REG_STATUS_REGISTERED; @endphp @push('styles') @endpush @section('content')
@include('admin.partials.flash') {{-- ── Cover hero (only when uploaded) ─────────────────────────── --}} @if ($demo->cover_image_url)
{{ $demo->localizedTitle() }}
@endif {{-- ═════════ 1. Overview (locked, always open) ═════════ --}}

{{ $demo->localizedTitle() }} @if ($typeLabel || $modeLabel) @if ($typeLabel){{ $typeLabel }}@endif @if ($modeLabel){{ $modeLabel }}@endif @endif

{{-- When tile --}}
{{ __('admin.demos.overview.when') }} {{ $dayLabel }} {{ optional($demo->meeting_date)->format('Y-m-d') ?: '—' }} {{ $demo->formattedMeetingTime() ?: '—' }}
{{-- Webinar tile — Teams webinar mirrors the demo. --}}
{{ __('admin.demos.fields.startups_count') }} {{ $demo->startups->count() }}
{{ __('admin.demos.fields.investors_count') }} {{ $effectiveInvestors->count() }}
{{ __('admin.demos.fields.status') }} {{ $isActive ? __('admin.demos.status.active') : __('admin.demos.status.expired') }}
{{-- Sticky section nav (committee-identical chrome). --}} {{-- ═════════ Webinar (Microsoft Teams) ═════════ --}}
@unless ($webinarEnabled)

{{ __('admin.demos.webinar.disabled') }}

@endunless @if (! $webinar || ! $webinar->webinar_id)

{{ __('admin.demos.webinar.none') }}

@if ($webinar && $webinar->last_error)

{{ $webinar->last_error }}

@endif @if ($webinarEnabled)
@csrf
@endif @else @php // $pill / $regTone / $attTone are defined at page scope (top of file). $webTone = ['created'=>'ok','failed'=>'danger','cancelled'=>'muted','deleted'=>'muted','pending'=>'warn','creating'=>'warn'][$webinar->status] ?? 'muted'; $coEmails = collect($webinar->co_organizers ?? [])->pluck('email')->filter()->implode(', ') ?: '—'; @endphp
{{ __('admin.demos.webinar.status') }} {!! $pill($webinar->status, $webTone) !!}
{{ __('admin.demos.webinar.fields.organizer') }} {{ $webinar->organizer_email ?: config('demo_webinars.organizer_upn') }}
{{ __('admin.demos.webinar.fields.coorganizers') }} {{ $coEmails }}
{{ __('admin.demos.webinar.webinar_id') }} {{ $webinar->webinar_id }}
{{ __('admin.demos.webinar.meeting_id') }} {{ $webinar->meeting_id ?: '—' }}
@if ($webinar->registration_url)
{{ __('admin.demos.webinar.registration_url') }}
@endif
{{ __('admin.demos.webinar.total_investors') }}{{ $webinarStats['total'] }}
{{ __('admin.demos.webinar.registered') }}{{ $webinarStats['registered'] }}
{{ __('admin.demos.webinar.attended') }}{{ $webinarStats['attended'] }}
{{ __('admin.demos.webinar.absent') }}{{ $webinarStats['absent'] }}
{{ __('admin.demos.webinar.attendance_pct') }}{{ $webinarStats['attendance_pct'] }}%

{{ __('admin.demos.webinar.last_sync') }}: {{ optional($webinar->last_synced_at)->diffForHumans() ?? '—' }} @if ($webinar->last_sync_error) · {{ $webinar->last_sync_error }}@endif

@if ($webinar->join_web_url) {{ __('admin.demos.webinar.open_in_teams') }} @endif @if ($webinarEnabled && ! $webinar->isClosed())
@csrf
@csrf
@csrf
@csrf
@endif

{{ __('admin.demos.attendance_section.subtitle') }} ↓ {{ __('admin.demos.attendance_section.title') }}

@endif
{{-- ═════════ 2. Attendance (investors + startups) ═════════ --}}
{{-- Startups roster --}}

{{ __('admin.demos.show.slots') }} ({{ $demo->startups->count() }})

@forelse ($demo->startups as $startup) @php($att = $startupAttendances->get($startup->id)) @php( $logoFile = $startup->files?->first(fn ($f) => ($f->slot ?? null) === 'logo') )
@if ($logoFile) @else {{ mb_substr($startup->display_name ?? '—', 0, 1) }} @endif
{{ $startup->display_name }}
{{ substr((string) $startup->pivot->start_time, 0, 5) }} – {{ substr((string) $startup->pivot->end_time, 0, 5) }} @if ($startup->sector) · {{ $startup->sector->{$locale === 'ar' ? 'name_ar' : 'name_en'} }} @endif
@csrf @method('PATCH')
@empty

—

@endforelse
{{-- Investors roster — the SINGLE investor table (registration + attendance columns were merged in here; the old separate Webinar per-investor table was removed). Iterates the LIVE effective audience (explicit `demo_investors` pins + every member of every attached group, resolved by Demo::effectiveInvestors()). --}}

{{ __('admin.demos.show.investors') }} ({{ $effectiveInvestors->count() }})

@forelse ($effectiveInvestors as $investor) @php($att = $investorAttendances->get($investor->id)) @php($selfStatus = $att?->status ?? 'pending') @php($registered = $isRegistered($att)) {{-- The admin VERIFICATION workflow only exists once the investor has CONFIRMED their attendance. Pending / cancelled ⇒ no verification dropdown at all — only the RSVP badge. --}} @php($confirmed = $att && $att->status === \App\Models\DemoAttendance::STATUS_CONFIRMED) @empty @endforelse
{{ __('admin.demos.webinar.col_investor') }} {{ __('admin.demos.attendance_section.rsvp') }} {{ __('admin.demos.webinar.col_reg_status') }} {{ __('admin.demos.webinar.col_att_status') }} {{ __('admin.demos.webinar.col_join') }} {{ __('admin.demos.webinar.col_leave') }} {{ __('admin.demos.webinar.col_duration') }} {{ __('admin.demos.webinar.col_join_url') }} {{ __('admin.demos.attendance_section.verification') }}
@if (! empty($investor->avatar_path)) @else {{ mb_substr($investor->display_name ?: '—', 0, 1) }} @endif {{ $investor->display_name }} @if ($investor->email)@endif
{{ __('admin.demos.attendance.self.' . $selfStatus) }}
{!! $att ? $pill($att->registration_status, $regTone($att->registration_status)) : $pill(__('admin.demos.webinar.not_registered'), 'muted') !!} @if ($webinarEnabled && $att && $att->registration_status === \App\Models\DemoAttendance::REG_STATUS_FAILED)
@csrf
@endif
{!! $registered ? $pill($att->attendance_status, $attTone($att->attendance_status)) : '—' !!} {{ $fmtTime($att?->join_time) }} {{ $fmtTime($att?->leave_time) }} {{ $att && $att->duration_minutes !== null ? $att->duration_minutes . ' ' . __('admin.demos.attendance_section.min') : '—' }} @if ($att?->join_url) @else — @endif {{-- Admin VERIFICATION dropdown appears ONLY after the investor has CONFIRMED their attendance. Before confirmation (pending / cancelled) there is no admin verification workflow at all — the RSVP badge in the RSVP column already states where they stand. --}} @if ($confirmed)
@csrf @method('PATCH')
@else — @endif
—
{{-- Demo evaluations were fully removed (2026-06): no model, table, endpoint, or UI. Demo has no Pass/Fail matrix. --}} {{-- ═════════ 3. Investor notes per startup ═════════ --}} @if ($investorNotesByStartup->isNotEmpty())
@foreach ($demo->startups as $startup) @php($notes = $investorNotesByStartup->get($startup->id)) @if ($notes && $notes->isNotEmpty())

{{ $startup->display_name }}

@foreach ($notes as $n)
{{-- investor `name` column dropped 2026-06-09 — use the locale-aware display_name accessor (the note's investor relation is loaded with the full_name_* pair it reads). --}} {{ $n->investor?->display_name ?: '—' }} {{ optional($n->updated_at)->format('Y-m-d H:i') }}

{{ $n->note }}

@endforeach
@endif @endforeach
@endif {{-- ═════════ 5. Admin notes ═════════ --}}
@csrf @method('PATCH')
{{-- Delete action — separate footer so it isn't lost among the sections. Same confirm-on-submit pattern as committee's. --}}
@csrf @method('DELETE')
{{-- Shared copy toast (requirement #7). One element, reused by every copy button. --}}
{{ __('admin.demos.webinar.copied') }}
@endsection @push('scripts') @endpush @push('styles') @endpush