Glos na zywo po stronie serwera, ikona blokady czatu
Deploy PROD / deploy (push) Successful in 26s

Przyznanie i odebranie glosu oraz oba tryby (otwarty mikrofon, wideo dla
wszystkich) zmieniaja uprawnienia uczestnika przez updateParticipant,
bez ponownego wejscia na sale. Odebranie najpierw wycisza sciezke na
serwerze, wiec dziala takze u klienta, ktory nie odebral zdarzenia.
Sala LiveKit ma staly key; mikrofon wlacza sie sam po przyznaniu glosu.

Rola uczestnika liczona w jednym miejscu (VideoService.participantRole)
dla biletu i zmiany na zywo. RoomPermissionTest pilnuje jawnej listy
zrodel publikacji.

Blokada pisania na czacie ma ikone przekreslonego dymku i znacznik
"bez czatu" zamiast przekreslonego mikrofonu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 08:55:24 +02:00
parent e9bb4af59f
commit 515d9a41e2
14 changed files with 465 additions and 75 deletions
@@ -134,7 +134,7 @@ export function RoomParticipants({ webinarId, timezone }: { webinarId: string; t
`/admin/webinars/${webinarId}/interactions/participants/${participant.registrationId}/mute`,
{ value: !participant.chatMuted },
)
toasts.success(participant.chatMuted ? 'Przywrócono pisanie na czacie' : 'Wyciszono na czacie')
toasts.success(participant.chatMuted ? 'Przywrócono pisanie na czacie' : 'Zablokowano pisanie na czacie')
await refresh()
} catch (error) {
toasts.error(errorMessage(error, 'Nie udało się zmienić wyciszenia'))
@@ -229,7 +229,7 @@ export function RoomParticipants({ webinarId, timezone }: { webinarId: string; t
<span className="truncate font-medium text-slate-800">{participant.name}</span>
{participant.kind === 'SPEAKER' && <Badge tone="brand">prowadzący</Badge>}
{participant.kind === 'OTHER' && <Badge tone="warn">spoza zapisu</Badge>}
{participant.chatMuted && <Badge tone="warn">wyciszony</Badge>}
{participant.chatMuted && <Badge tone="warn">bez czatu</Badge>}
</div>
<div className="flex flex-wrap items-center gap-x-2 text-xs text-slate-500">
{participant.email && <span className="truncate">{participant.email}</span>}
@@ -271,12 +271,12 @@ export function RoomParticipants({ webinarId, timezone }: { webinarId: string; t
aria-label={
participant.chatMuted
? `Przywróć pisanie na czacie: ${participant.name}`
: `Wycisz na czacie: ${participant.name}`
: `Zablokuj pisanie na czacie: ${participant.name}`
}
title={participant.chatMuted ? 'Przywróć pisanie na czacie' : 'Wycisz na czacie'}
title={participant.chatMuted ? 'Przywróć pisanie na czacie' : 'Zablokuj pisanie na czacie'}
className="flex h-9 w-9 items-center justify-center rounded-md text-warn-600 hover:bg-warn-50 disabled:opacity-40"
>
<Icon name={participant.chatMuted ? 'message-square' : 'mic-off'} size={16} />
<Icon name={participant.chatMuted ? 'message-square' : 'message-square-off'} size={16} />
</button>
)}
<button