💩(frontend) add confirmation before muting participant
This commit focuses on the UX more than the code quality. In facts, we should design a centralized component/alert service, that we can trigger anywhere in the codebase, when a user is prompted for confirmation. The alert modal with cancel/submit buttons and a description is generic. Creating technical debt here.
This commit is contained in:
committed by
aleb_the_flash
parent
490aaba30a
commit
c218a1f7a2
@@ -7,7 +7,7 @@ import { Avatar } from '@/components/Avatar'
|
|||||||
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
import { getParticipantColor } from '@/features/rooms/utils/getParticipantColor'
|
||||||
import { Participant, Track } from 'livekit-client'
|
import { Participant, Track } from 'livekit-client'
|
||||||
import { isLocal } from '@/utils/livekit'
|
import { isLocal } from '@/utils/livekit'
|
||||||
import { Button } from 'react-aria-components'
|
import { Button as RACButton } from 'react-aria-components'
|
||||||
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
|
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
|
||||||
import {
|
import {
|
||||||
useIsSpeaking,
|
useIsSpeaking,
|
||||||
@@ -16,6 +16,35 @@ import {
|
|||||||
import Source = Track.Source
|
import Source = Track.Source
|
||||||
import { RiMicOffLine } from '@remixicon/react'
|
import { RiMicOffLine } from '@remixicon/react'
|
||||||
import { TooltipWrapper } from '@/primitives/TooltipWrapper.tsx'
|
import { TooltipWrapper } from '@/primitives/TooltipWrapper.tsx'
|
||||||
|
import { Button, Dialog, P } from '@/primitives'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
const MuteAlertDialog = ({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
onSubmit,
|
||||||
|
name,
|
||||||
|
}: {
|
||||||
|
isOpen: boolean
|
||||||
|
onClose: () => void
|
||||||
|
onSubmit: () => void
|
||||||
|
name: string
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation('rooms')
|
||||||
|
return (
|
||||||
|
<Dialog isOpen={isOpen} role="alertdialog">
|
||||||
|
<P>{t('participants.muteParticipantAlert.description', { name })}</P>
|
||||||
|
<HStack gap={1}>
|
||||||
|
<Button size="sm" invisible onPress={onClose}>
|
||||||
|
{t('participants.muteParticipantAlert.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" invisible onPress={onSubmit}>
|
||||||
|
{t('participants.muteParticipantAlert.confirm')}
|
||||||
|
</Button>
|
||||||
|
</HStack>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type MicIndicatorProps = {
|
type MicIndicatorProps = {
|
||||||
participant: Participant
|
participant: Participant
|
||||||
@@ -29,38 +58,51 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
|||||||
})
|
})
|
||||||
const isSpeaking = useIsSpeaking(participant)
|
const isSpeaking = useIsSpeaking(participant)
|
||||||
const isDisabled = isLocal(participant) || (!isLocal(participant) && isMuted)
|
const isDisabled = isLocal(participant) || (!isLocal(participant) && isMuted)
|
||||||
|
|
||||||
|
const [isAlertOpen, setIsAlertOpen] = useState(false)
|
||||||
|
|
||||||
|
const name = participant.name || participant.identity
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipWrapper
|
<>
|
||||||
tooltip={t('participants.muteParticipant', {
|
<TooltipWrapper
|
||||||
name: participant.name || participant.identity,
|
tooltip={t('participants.muteParticipant', {
|
||||||
})}
|
name,
|
||||||
tooltipType="instant"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
className={css({
|
|
||||||
padding: '10px',
|
|
||||||
minWidth: '24px',
|
|
||||||
minHeight: '24px',
|
|
||||||
borderRadius: '50%',
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
transition: 'background 200ms',
|
|
||||||
'&[data-hovered]': {
|
|
||||||
backgroundColor: '#f5f5f5',
|
|
||||||
},
|
|
||||||
'&[data-focused]': {
|
|
||||||
backgroundColor: '#f5f5f5',
|
|
||||||
},
|
|
||||||
})}
|
})}
|
||||||
onPress={() => !isMuted && console.log(`mute ${participant.identity}`)}
|
tooltipType="instant"
|
||||||
>
|
>
|
||||||
{isMuted ? (
|
<RACButton
|
||||||
<RiMicOffLine color="gray" />
|
isDisabled={isDisabled}
|
||||||
) : (
|
className={css({
|
||||||
<ActiveSpeaker isSpeaking={isSpeaking} />
|
padding: '10px',
|
||||||
)}
|
minWidth: '24px',
|
||||||
</Button>
|
minHeight: '24px',
|
||||||
</TooltipWrapper>
|
borderRadius: '50%',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
transition: 'background 200ms',
|
||||||
|
'&[data-hovered]': {
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
},
|
||||||
|
'&[data-focused]': {
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
onPress={() => !isMuted && setIsAlertOpen(true)}
|
||||||
|
>
|
||||||
|
{isMuted ? (
|
||||||
|
<RiMicOffLine color="gray" />
|
||||||
|
) : (
|
||||||
|
<ActiveSpeaker isSpeaking={isSpeaking} />
|
||||||
|
)}
|
||||||
|
</RACButton>
|
||||||
|
</TooltipWrapper>
|
||||||
|
<MuteAlertDialog
|
||||||
|
isOpen={isAlertOpen}
|
||||||
|
onSubmit={() => setIsAlertOpen(false)}
|
||||||
|
onClose={() => setIsAlertOpen(false)}
|
||||||
|
name={name}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,11 @@
|
|||||||
"heading": "",
|
"heading": "",
|
||||||
"closeButton": "",
|
"closeButton": "",
|
||||||
"you": "",
|
"you": "",
|
||||||
"muteParticipant": ""
|
"muteParticipant": "",
|
||||||
|
"muteParticipantAlert": {
|
||||||
|
"description": "",
|
||||||
|
"confirm": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,11 @@
|
|||||||
"heading": "Participants",
|
"heading": "Participants",
|
||||||
"closeButton": "Hide participants",
|
"closeButton": "Hide participants",
|
||||||
"you": "You",
|
"you": "You",
|
||||||
"muteParticipant": "Close the mic of {{name}}"
|
"muteParticipant": "Close the mic of {{name}}",
|
||||||
|
"muteParticipantAlert": {
|
||||||
|
"description": "Mute {{name}} for all participants? {{name}} is the only person who can unmute themselves.",
|
||||||
|
"confirm": "Mute",
|
||||||
|
"cancel": "Cancel"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,11 @@
|
|||||||
"heading": "Participants",
|
"heading": "Participants",
|
||||||
"closeButton": "Masquer les participants",
|
"closeButton": "Masquer les participants",
|
||||||
"you": "Vous",
|
"you": "Vous",
|
||||||
"muteParticipant": "Couper le micro de {{name}}"
|
"muteParticipant": "Couper le micro de {{name}}",
|
||||||
|
"muteParticipantAlert": {
|
||||||
|
"description": "Couper le micro de {{name}} pour tous les participants ? {{name}} est la seule personne habilitée à réactiver son micro",
|
||||||
|
"confirm": "Couper le micro",
|
||||||
|
"cancel": "Annuler"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user