Deploy Ladill Meet / deploy (push) Successful in 50s
Route guests through silent SSO to the Meet product page, fix Afia context query, add conference green-room UX and copy, and extend service API for Care/CRM/Invoice calendar integration. Co-authored-by: Cursor <cursoragent@cursor.com>
135 lines
7.4 KiB
PHP
135 lines
7.4 KiB
PHP
@php
|
|
$room = $recording->session->room;
|
|
$sessionNoun = $room->isConference() ? 'conference' : 'meeting';
|
|
$roomDetailsRoute = match (true) {
|
|
$room->isConference() => route('meet.conferences.show', $room),
|
|
$room->isWebinar() => route('meet.webinars.show', $room),
|
|
$room->isSpace() => route('meet.spaces.show', $room),
|
|
default => route('meet.rooms.show', $room),
|
|
};
|
|
$statusLabel = config('meet.recording_statuses')[$recording->status] ?? ucfirst($recording->status);
|
|
$statusClass = match ($recording->status) {
|
|
'ready' => 'bg-emerald-50 text-emerald-700',
|
|
'processing' => 'bg-amber-50 text-amber-700',
|
|
'recording' => 'bg-red-50 text-red-700',
|
|
'failed' => 'bg-red-50 text-red-700',
|
|
default => 'bg-slate-100 text-slate-600',
|
|
};
|
|
$summary = $recording->session->aiSummaries->where('status', 'ready')->sortByDesc('created_at')->first();
|
|
$fileExtension = $recording->storage_path ? strtoupper(pathinfo($recording->storage_path, PATHINFO_EXTENSION)) : null;
|
|
$fileSizeLabel = null;
|
|
if ($recording->file_size) {
|
|
$bytes = (int) $recording->file_size;
|
|
if ($bytes >= 1073741824) {
|
|
$fileSizeLabel = number_format($bytes / 1073741824, 2).' GB';
|
|
} elseif ($bytes >= 1048576) {
|
|
$fileSizeLabel = number_format($bytes / 1048576, 1).' MB';
|
|
} elseif ($bytes >= 1024) {
|
|
$fileSizeLabel = number_format($bytes / 1024, 1).' KB';
|
|
} else {
|
|
$fileSizeLabel = $bytes.' B';
|
|
}
|
|
}
|
|
@endphp
|
|
|
|
<x-app-layout title="Recording">
|
|
<div class="mx-auto max-w-2xl">
|
|
<a href="{{ route('meet.recordings.index') }}" class="inline-flex items-center gap-1.5 text-sm text-slate-500 transition hover:text-slate-700">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18"/>
|
|
</svg>
|
|
Recordings
|
|
</a>
|
|
|
|
<div class="mt-4 flex items-start justify-between gap-4">
|
|
<div class="min-w-0">
|
|
<h1 class="text-2xl font-semibold text-slate-900">{{ $room->title }}</h1>
|
|
<p class="mt-1 text-sm text-slate-500">
|
|
{{ $recording->started_at?->timezone($room->timezone)->format('l, M j, Y · g:i A') ?? $recording->created_at->format('M j, Y g:i A') }}
|
|
</p>
|
|
</div>
|
|
<span class="shrink-0 rounded-full px-2.5 py-1 text-xs font-medium {{ $statusClass }}">{{ $statusLabel }}</span>
|
|
</div>
|
|
|
|
<div class="mt-6 rounded-2xl border border-slate-200 bg-white p-6">
|
|
<dl class="grid gap-4 sm:grid-cols-2">
|
|
@if ($recording->duration_seconds)
|
|
<div>
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Duration</dt>
|
|
<dd class="mt-1 text-sm font-medium text-slate-900">{{ gmdate('H:i:s', $recording->duration_seconds) }}</dd>
|
|
</div>
|
|
@endif
|
|
@if ($fileSizeLabel)
|
|
<div>
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">File size</dt>
|
|
<dd class="mt-1 text-sm font-medium text-slate-900">{{ $fileSizeLabel }}@if ($fileExtension) <span class="font-normal text-slate-500">· {{ $fileExtension }}</span>@endif</dd>
|
|
</div>
|
|
@endif
|
|
@if ($recording->ended_at)
|
|
<div>
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Ended</dt>
|
|
<dd class="mt-1 text-sm font-medium text-slate-900">{{ $recording->ended_at->timezone($room->timezone)->format('M j, Y g:i A') }}</dd>
|
|
</div>
|
|
@endif
|
|
<div>
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Layout</dt>
|
|
<dd class="mt-1 text-sm font-medium capitalize text-slate-900">{{ $recording->layout ?? 'gallery' }}</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
@if ($recording->hasPlayableFile())
|
|
<p class="mt-5 text-sm text-slate-600">Stored on Ladill as WebM — VLC, Chrome, and QuickTime can play it after download.</p>
|
|
@elseif ($recording->status === 'processing')
|
|
<div class="mt-5 flex items-start gap-3 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3">
|
|
<svg class="mt-0.5 h-5 w-5 shrink-0 animate-spin text-amber-600" fill="none" viewBox="0 0 24 24" aria-hidden="true">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4z"></path>
|
|
</svg>
|
|
<div>
|
|
<p class="text-sm font-medium text-amber-900">Processing recording</p>
|
|
<p class="mt-0.5 text-sm text-amber-800">This usually takes a moment after the {{ $sessionNoun }} ends. Refresh shortly.</p>
|
|
</div>
|
|
</div>
|
|
@elseif ($recording->status === 'failed')
|
|
<div class="mt-5 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
|
|
{{ $recording->failure_reason ?? 'This recording could not be processed.' }}
|
|
</div>
|
|
@endif
|
|
|
|
<div class="btn-group mt-6">
|
|
@if ($recording->hasPlayableFile())
|
|
<a href="{{ route('meet.recordings.download', $recording) }}" class="btn-secondary btn-secondary-sm">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24" aria-hidden="true">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12M12 16.5V3"/>
|
|
</svg>
|
|
Download
|
|
</a>
|
|
@endif
|
|
<a href="{{ $roomDetailsRoute }}" class="btn-secondary btn-secondary-sm">View {{ $sessionNoun }}</a>
|
|
@if ($summary)
|
|
<a href="{{ route('meet.summaries.show', $summary) }}" class="btn-secondary btn-secondary-sm">AI summary</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@if ($canManage)
|
|
<div class="mt-4">
|
|
<x-confirm-dialog
|
|
:name="'delete-recording-'.$recording->id"
|
|
title="Delete this recording?"
|
|
message="This permanently removes the recording file from Ladill storage. This cannot be undone."
|
|
:action="route('meet.recordings.destroy', $recording)"
|
|
method="DELETE"
|
|
confirm-label="Delete recording"
|
|
>
|
|
<x-slot:trigger>
|
|
<button type="button" class="btn-secondary btn-secondary-sm text-red-600 hover:border-red-200 hover:bg-red-50 hover:text-red-700">
|
|
Delete recording
|
|
</button>
|
|
</x-slot:trigger>
|
|
</x-confirm-dialog>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-app-layout>
|