🔒️(frontend) hide admin actions from unprivileged users in UI
Update interface to hide admin-only actions like participant muting from users without room admin privileges, reflecting backend permission restrictions implemented in previous commits.
This commit is contained in:
committed by
aleb_the_flash
parent
4793f2fa8f
commit
a85a62eb1a
@@ -21,6 +21,7 @@ import { useFullScreen } from '../hooks/useFullScreen'
|
|||||||
import { Participant, Track } from 'livekit-client'
|
import { Participant, Track } from 'livekit-client'
|
||||||
import { MuteAlertDialog } from './MuteAlertDialog'
|
import { MuteAlertDialog } from './MuteAlertDialog'
|
||||||
import { useMuteParticipant } from '@/features/rooms/api/muteParticipant'
|
import { useMuteParticipant } from '@/features/rooms/api/muteParticipant'
|
||||||
|
import { useCanMute } from '@/features/rooms/livekit/hooks/useCanMute'
|
||||||
|
|
||||||
const ZoomButton = ({
|
const ZoomButton = ({
|
||||||
trackRef,
|
trackRef,
|
||||||
@@ -165,6 +166,8 @@ export const ParticipantTileFocus = ({
|
|||||||
const isScreenShare = trackRef.source == Track.Source.ScreenShare
|
const isScreenShare = trackRef.source == Track.Source.ScreenShare
|
||||||
const isLocal = trackRef.participant.isLocal
|
const isLocal = trackRef.participant.isLocal
|
||||||
|
|
||||||
|
const canMute = useCanMute(participant)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
@@ -210,7 +213,7 @@ export const ParticipantTileFocus = ({
|
|||||||
{participant.isLocal ? (
|
{participant.isLocal ? (
|
||||||
<EffectsButton />
|
<EffectsButton />
|
||||||
) : (
|
) : (
|
||||||
<MuteButton participant={participant} />
|
canMute && <MuteButton participant={participant} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { Avatar } from '@/components/Avatar'
|
import { Avatar } from '@/components/Avatar'
|
||||||
import { useLowerHandParticipant } from '@/features/rooms/api/lowerHandParticipant'
|
import { useLowerHandParticipant } from '@/features/rooms/api/lowerHandParticipant'
|
||||||
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
||||||
|
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||||
import { Participant } from 'livekit-client'
|
import { Participant } from 'livekit-client'
|
||||||
import { isLocal } from '@/utils/livekit'
|
import { isLocal } from '@/utils/livekit'
|
||||||
import { RiHand } from '@remixicon/react'
|
import { RiHand } from '@remixicon/react'
|
||||||
@@ -22,6 +23,7 @@ export const HandRaisedListItem = ({
|
|||||||
const name = participant.name || participant.identity
|
const name = participant.name || participant.identity
|
||||||
|
|
||||||
const { lowerHandParticipant } = useLowerHandParticipant()
|
const { lowerHandParticipant } = useLowerHandParticipant()
|
||||||
|
const isAdminOrOwner = useIsAdminOrOwner()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HStack
|
<HStack
|
||||||
@@ -67,16 +69,18 @@ export const HandRaisedListItem = ({
|
|||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
<Button
|
{isAdminOrOwner && (
|
||||||
square
|
<Button
|
||||||
variant="greyscale"
|
square
|
||||||
size="sm"
|
variant="greyscale"
|
||||||
onPress={() => lowerHandParticipant(participant)}
|
size="sm"
|
||||||
tooltip={t('participants.lowerParticipantHand', { name })}
|
onPress={() => lowerHandParticipant(participant)}
|
||||||
data-attr="participants-lower-hand"
|
tooltip={t('participants.lowerParticipantHand', { name })}
|
||||||
>
|
data-attr="participants-lower-hand"
|
||||||
<RiHand />
|
>
|
||||||
</Button>
|
<RiHand />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Button } from '@/primitives'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Participant } from 'livekit-client'
|
import { Participant } from 'livekit-client'
|
||||||
import { useLowerHandParticipants } from '@/features/rooms/api/lowerHandParticipants'
|
import { useLowerHandParticipants } from '@/features/rooms/api/lowerHandParticipants'
|
||||||
|
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
||||||
|
|
||||||
type LowerAllHandsButtonProps = {
|
type LowerAllHandsButtonProps = {
|
||||||
participants: Array<Participant>
|
participants: Array<Participant>
|
||||||
@@ -12,6 +13,10 @@ export const LowerAllHandsButton = ({
|
|||||||
}: LowerAllHandsButtonProps) => {
|
}: LowerAllHandsButtonProps) => {
|
||||||
const { lowerHandParticipants } = useLowerHandParticipants()
|
const { lowerHandParticipants } = useLowerHandParticipants()
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
|
const isAdminOrOwner = useIsAdminOrOwner()
|
||||||
|
if (!isAdminOrOwner) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
aria-label={t('participants.lowerParticipantsHand')}
|
aria-label={t('participants.lowerParticipantsHand')}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { Button } from '@/primitives'
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { MuteAlertDialog } from '../../MuteAlertDialog'
|
import { MuteAlertDialog } from '../../MuteAlertDialog'
|
||||||
import { useMuteParticipant } from '@/features/rooms/api/muteParticipant'
|
import { useMuteParticipant } from '@/features/rooms/api/muteParticipant'
|
||||||
|
import { useCanMute } from '@/features/rooms/livekit/hooks/useCanMute'
|
||||||
|
|
||||||
type MicIndicatorProps = {
|
type MicIndicatorProps = {
|
||||||
participant: Participant
|
participant: Participant
|
||||||
@@ -30,6 +31,8 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
|||||||
participant: participant,
|
participant: participant,
|
||||||
source: Source.Microphone,
|
source: Source.Microphone,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const canMute = useCanMute(participant)
|
||||||
const isSpeaking = useIsSpeaking(participant)
|
const isSpeaking = useIsSpeaking(participant)
|
||||||
const [isAlertOpen, setIsAlertOpen] = useState(false)
|
const [isAlertOpen, setIsAlertOpen] = useState(false)
|
||||||
const name = participant.name || participant.identity
|
const name = participant.name || participant.identity
|
||||||
@@ -48,7 +51,7 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
tooltip={label}
|
tooltip={label}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
isDisabled={isMuted}
|
isDisabled={isMuted || !canMute}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
!isMuted && isLocal(participant)
|
!isMuted && isLocal(participant)
|
||||||
? muteParticipant(participant)
|
? muteParticipant(participant)
|
||||||
@@ -105,7 +108,7 @@ export const ParticipantListItem = ({
|
|||||||
<Avatar name={name} bgColor={getParticipantColor(participant)} />
|
<Avatar name={name} bgColor={getParticipantColor(participant)} />
|
||||||
<VStack gap={0} alignItems="start">
|
<VStack gap={0} alignItems="start">
|
||||||
<Text
|
<Text
|
||||||
sm
|
variant="sm"
|
||||||
className={css({
|
className={css({
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { useIsAdminOrOwner } from './useIsAdminOrOwner'
|
||||||
|
import { Participant } from 'livekit-client'
|
||||||
|
|
||||||
|
export const useCanMute = (participant: Participant) => {
|
||||||
|
const isAdminOrOwner = useIsAdminOrOwner()
|
||||||
|
return participant.isLocal || isAdminOrOwner
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user