Add kiosk join/leave pages, waiting room, and meeting feedback.
Deploy Ladill Meet / deploy (push) Successful in 47s

Redesign public join flows on the Frontdesk kiosk template, enforce host
admission when waiting room is enabled, and collect star ratings after leave.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-01 13:33:48 +00:00
co-authored by Cursor
parent 5e34d71de0
commit 7ae26a467c
26 changed files with 865 additions and 124 deletions
@@ -38,6 +38,7 @@ class ParticipantPresenter
'uuid' => $participant->uuid,
'display_name' => $participant->display_name,
'role' => $participant->role,
'status' => $participant->status,
'hand_raised' => $participant->hand_raised,
'is_muted' => $participant->is_muted,
'is_video_off' => $participant->is_video_off,
+71 -12
View File
@@ -63,7 +63,7 @@ class SessionService
$session->room->update(['status' => 'ended']);
$session->participants()
->where('status', 'joined')
->whereIn('status', ['joined', 'waiting'])
->update(['status' => 'left', 'left_at' => now()]);
foreach ($session->recordings()->where('status', 'recording')->get() as $recording) {
@@ -89,22 +89,32 @@ class SessionService
string $role,
?string $displayName = null,
?string $email = null,
string $status = 'joined',
): Participant {
$userRef = $user?->ownerRef();
$existing = $this->findExistingParticipant($session, $userRef, $email);
if ($existing) {
$existing->update([
'status' => 'joined',
'joined_at' => now(),
$updates = [
'left_at' => null,
'display_name' => $displayName ?? $existing->display_name,
'ip_address' => request()?->ip(),
]);
];
if ($existing->status === 'waiting') {
$updates['status'] = 'waiting';
} else {
$updates['status'] = 'joined';
$updates['joined_at'] = $existing->joined_at ?? now();
}
$existing->update($updates);
return $existing;
}
$joinedAt = $status === 'joined' ? now() : null;
$participant = Participant::create([
'owner_ref' => $session->owner_ref,
'session_id' => $session->id,
@@ -112,23 +122,72 @@ class SessionService
'display_name' => $displayName ?? $user?->name ?? 'Guest',
'email' => $email,
'role' => $role,
'status' => 'joined',
'joined_at' => now(),
'status' => $status,
'joined_at' => $joinedAt,
'ip_address' => request()?->ip(),
]);
$this->updatePeakParticipants($session);
if ($status === 'joined') {
$this->updatePeakParticipants($session);
}
if ($status === 'joined') {
AuditLogger::record(
$session->owner_ref,
'participant.joined',
$session->room->organization_id,
$userRef,
Participant::class,
$participant->id,
);
}
return $participant;
}
public function admitParticipant(Participant $participant): Participant
{
abort_unless($participant->status === 'waiting', 422);
$participant->update([
'status' => 'joined',
'joined_at' => now(),
'left_at' => null,
]);
$this->updatePeakParticipants($participant->session);
AuditLogger::record(
$session->owner_ref,
$participant->owner_ref,
'participant.joined',
$session->room->organization_id,
$userRef,
$participant->session->room->organization_id,
$participant->user_ref,
Participant::class,
$participant->id,
);
return $participant;
return $participant->fresh();
}
public function denyParticipant(Participant $participant): Participant
{
abort_unless($participant->status === 'waiting', 422);
$participant->update([
'status' => 'removed',
'left_at' => now(),
]);
AuditLogger::record(
$participant->owner_ref,
'participant.removed',
$participant->session->room->organization_id,
$participant->user_ref,
Participant::class,
$participant->id,
);
return $participant->fresh();
}
protected function findExistingParticipant(Session $session, ?string $userRef, ?string $email): ?Participant