Deploy Ladill Meet / deploy (push) Successful in 1m21s
Server-render the speaker pill on load, hide noisy connection status on mobile, and use a single sidebarPanel slot so desktop panels replace in place instead of animating side by side. Co-authored-by: Cursor <cursoragent@cursor.com>
146 lines
4.5 KiB
PHP
146 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Meet;
|
|
|
|
use App\Models\Participant;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class ParticipantPresenter
|
|
{
|
|
/**
|
|
* @param Collection<int, Participant> $participants
|
|
*/
|
|
public static function avatarMap(Collection $participants, ?string $roomHostUserRef = null): Collection
|
|
{
|
|
$refs = $participants->pluck('user_ref')->filter();
|
|
|
|
if ($roomHostUserRef) {
|
|
$refs = $refs->push($roomHostUserRef)->unique();
|
|
}
|
|
|
|
if ($refs->isEmpty()) {
|
|
return collect();
|
|
}
|
|
|
|
return User::query()
|
|
->whereIn('public_id', $refs->all())
|
|
->get()
|
|
->keyBy('public_id');
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function toArray(Participant $participant, Collection $avatars, ?string $roomHostUserRef = null): array
|
|
{
|
|
return [
|
|
'uuid' => $participant->uuid,
|
|
'user_ref' => $participant->user_ref,
|
|
'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,
|
|
'breakout_room_id' => $participant->breakout_room_id,
|
|
'avatar_url' => self::avatarUrl($participant, $avatars, $roomHostUserRef),
|
|
];
|
|
}
|
|
|
|
public static function avatarUrl(Participant $participant, Collection $avatars, ?string $roomHostUserRef = null): ?string
|
|
{
|
|
if ($participant->user_ref) {
|
|
$url = $avatars->get($participant->user_ref)?->avatarUrl();
|
|
if ($url) {
|
|
return $url;
|
|
}
|
|
}
|
|
|
|
if (in_array($participant->role, ['host', 'co_host'], true) && $roomHostUserRef) {
|
|
return $avatars->get($roomHostUserRef)?->avatarUrl();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $participants
|
|
* @param list<string> $presenterRefs
|
|
*/
|
|
public static function isSpeakerPerson(array $person, array $presenterRefs = []): bool
|
|
{
|
|
if (in_array($person['role'] ?? '', ['host', 'co_host', 'panelist'], true)) {
|
|
return true;
|
|
}
|
|
|
|
$userRef = $person['user_ref'] ?? null;
|
|
|
|
return is_string($userRef) && $userRef !== '' && in_array($userRef, $presenterRefs, true);
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $participants
|
|
* @param list<string> $presenterRefs
|
|
*/
|
|
public static function headerCountLabel(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
|
|
{
|
|
$joined = array_values(array_filter($participants, fn ($p) => ($p['status'] ?? '') === 'joined'));
|
|
|
|
if ($usesStageLayout) {
|
|
$count = count(array_filter($joined, fn ($p) => self::isSpeakerPerson($p, $presenterRefs)));
|
|
|
|
return $count === 1 ? '1 speaker' : "{$count} speakers";
|
|
}
|
|
|
|
$count = count($joined);
|
|
|
|
return "{$count} in call";
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $participants
|
|
* @return array{display_name: string, avatar_url: ?string}|null
|
|
*/
|
|
public static function headerHost(array $participants, array $roomHost): ?array
|
|
{
|
|
foreach ($participants as $person) {
|
|
if (($person['status'] ?? '') !== 'joined') {
|
|
continue;
|
|
}
|
|
|
|
if (in_array($person['role'] ?? '', ['host', 'co_host'], true)) {
|
|
return [
|
|
'display_name' => (string) ($person['display_name'] ?? 'Host'),
|
|
'avatar_url' => $person['avatar_url'] ?? null,
|
|
];
|
|
}
|
|
}
|
|
|
|
if (($roomHost['display_name'] ?? '') !== '') {
|
|
return [
|
|
'display_name' => (string) $roomHost['display_name'],
|
|
'avatar_url' => $roomHost['avatar_url'] ?? null,
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static function initials(?string $name): string
|
|
{
|
|
$parts = preg_split('/\s+/', trim($name ?? '')) ?: [];
|
|
$parts = array_values(array_filter($parts, fn ($part) => $part !== ''));
|
|
|
|
if ($parts === []) {
|
|
return '?';
|
|
}
|
|
|
|
if (count($parts) === 1) {
|
|
return strtoupper(substr($parts[0], 0, 2));
|
|
}
|
|
|
|
return strtoupper(substr($parts[0], 0, 1).substr($parts[count($parts) - 1], 0, 1));
|
|
}
|
|
}
|