Deploy Ladill Meet / deploy (push) Successful in 42s
Enforce invite-only room access, validate invite emails on create, assign attendee role for listener invitations, and add invite UI on the room show page. Redesign meetings, rooms, conferences, and webinars indexes to match the Events hero, stats cards, and icon list layout. Co-authored-by: Cursor <cursoragent@cursor.com>
128 lines
6.8 KiB
PHP
128 lines
6.8 KiB
PHP
<x-app-layout title="{{ $room->title }}">
|
|
<div class="mx-auto max-w-2xl">
|
|
<div>
|
|
<p class="text-xs font-semibold uppercase tracking-wide text-emerald-600">Room</p>
|
|
<h1 class="text-2xl font-semibold text-slate-900">{{ $room->title }}</h1>
|
|
<p class="mt-1 text-sm text-slate-500">{{ config('meet.room_statuses')[$room->status] ?? $room->status }}</p>
|
|
</div>
|
|
|
|
@if (session('success'))
|
|
<div class="mt-4 rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700">
|
|
{{ session('success') }}
|
|
</div>
|
|
@endif
|
|
|
|
@if ($errors->any())
|
|
<div class="mt-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
|
|
{{ $errors->first() }}
|
|
</div>
|
|
@endif
|
|
|
|
<div class="mt-4 rounded-xl border border-emerald-100 bg-emerald-50 px-4 py-3 text-sm text-emerald-900">
|
|
Host-led audio room. Assigned speakers can talk when the room opens; during a live session, open <strong>People</strong> to invite listeners who raised a hand.
|
|
@if ($room->setting('invite_only'))
|
|
This room is private — share the join link only with invited people.
|
|
@endif
|
|
</div>
|
|
|
|
<div class="mt-6 rounded-2xl border border-slate-200 bg-white p-6">
|
|
<h2 class="text-sm font-medium text-slate-700">Join link</h2>
|
|
<div class="mt-2 flex gap-2">
|
|
<input type="text" readonly value="{{ $room->joinUrl() }}" class="flex-1 rounded-lg border-slate-300 bg-slate-50 text-sm font-mono">
|
|
<x-copy-button :text="$room->joinUrl()" class="btn-secondary btn-secondary-sm shrink-0" />
|
|
</div>
|
|
|
|
<div class="btn-group mt-4">
|
|
@if ($room->status === 'live' && $room->activeSession())
|
|
<a href="{{ route('meet.join', $room) }}" class="btn-primary btn-primary-sm">Join room</a>
|
|
@elseif ($room->canRestart())
|
|
<form method="POST" action="{{ route('meet.spaces.start', $room) }}" class="inline">
|
|
@csrf
|
|
<button type="submit" class="btn-primary btn-primary-sm">{{ $room->restartLabel() }}</button>
|
|
</form>
|
|
@endif
|
|
<a href="{{ route('meet.rooms.qr', $room) }}" target="_blank" class="btn-secondary btn-secondary-sm">QR code</a>
|
|
</div>
|
|
|
|
@if ($speakers->isNotEmpty())
|
|
<div class="mt-5 border-t border-slate-100 pt-4">
|
|
<h3 class="text-sm font-medium text-slate-700">Assigned speakers</h3>
|
|
<ul class="mt-2 space-y-1 text-sm text-slate-600">
|
|
@foreach ($speakers as $speaker)
|
|
<li>{{ $speaker->user_ref }}</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($room->passcode)
|
|
<p class="mt-3 text-sm text-slate-600">Passcode: <span class="font-mono font-medium">{{ $room->passcode }}</span></p>
|
|
@endif
|
|
|
|
@if ($room->description)
|
|
<p class="mt-3 text-sm text-slate-600">{{ $room->description }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="mt-6 rounded-2xl border border-slate-200 bg-white p-6">
|
|
<div class="flex items-start justify-between gap-3">
|
|
<div>
|
|
<h2 class="text-sm font-medium text-slate-900">Listener invitations</h2>
|
|
<p class="mt-1 text-sm text-slate-500">Email join links to listeners. Invited people can enter private rooms.</p>
|
|
</div>
|
|
<a href="{{ route('meet.invitations.index', $room) }}" class="shrink-0 text-sm text-indigo-600 hover:underline">Bulk import</a>
|
|
</div>
|
|
|
|
<form method="POST" action="{{ route('meet.invitations.store', $room) }}" class="mt-4 space-y-3">
|
|
@csrf
|
|
<div>
|
|
<label class="block text-sm text-slate-700">Email addresses</label>
|
|
<textarea name="emails" rows="2" placeholder="listener@example.com, guest@example.com" class="mt-1 w-full rounded-lg border-slate-300 text-sm">{{ old('emails') }}</textarea>
|
|
@error('emails')
|
|
<p class="mt-1 text-xs text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
<button type="submit" class="btn-primary btn-primary-sm">Send invitations</button>
|
|
</form>
|
|
|
|
@if ($room->invitations->isNotEmpty())
|
|
<ul class="mt-5 divide-y divide-slate-100 border-t border-slate-100 pt-4 text-sm">
|
|
@foreach ($room->invitations->take(8) as $invitation)
|
|
<li class="flex items-center justify-between gap-3 py-2">
|
|
<div class="min-w-0">
|
|
<p class="truncate font-medium text-slate-900">{{ $invitation->display_name ?? $invitation->email }}</p>
|
|
<p class="truncate text-xs text-slate-500">{{ $invitation->email }} · {{ ucfirst($invitation->status) }}</p>
|
|
</div>
|
|
<form method="POST" action="{{ route('meet.invitations.resend', $invitation) }}">
|
|
@csrf
|
|
<button type="submit" class="text-xs text-indigo-600 hover:underline">Resend</button>
|
|
</form>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
@if ($room->invitations->count() > 8)
|
|
<a href="{{ route('meet.invitations.index', $room) }}" class="mt-2 inline-block text-sm text-indigo-600 hover:underline">
|
|
View all {{ $room->invitations->count() }} invitations
|
|
</a>
|
|
@endif
|
|
@else
|
|
<p class="mt-4 text-sm text-slate-500">No listener invitations sent yet.</p>
|
|
@endif
|
|
</div>
|
|
|
|
@if ($room->sessions->isNotEmpty())
|
|
<div class="mt-6 rounded-2xl border border-slate-200 bg-white p-6">
|
|
<h2 class="text-sm font-medium text-slate-700">Past sessions</h2>
|
|
<ul class="mt-3 divide-y divide-slate-100 text-sm">
|
|
@foreach ($room->sessions as $session)
|
|
<li class="flex items-center justify-between py-2">
|
|
<span>{{ $session->started_at?->format('M j, Y g:i A') ?? 'Pending' }}</span>
|
|
<span class="text-slate-500">{{ $session->peak_participants }} joined</span>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-app-layout>
|