projects/deliberation_at_scale/packages/frontend/components/RoomParticipants/controls.tsx (92 lines of code) (raw):
'use client';
import { useLeaveRoomMutation } from '@/generated/graphql';
import { useLocalMedia } from '@/hooks/useLocalMedia';
import useRoom from '@/hooks/useRoom';
import useTheme, { ThemeColors } from '@/hooks/useTheme';
import { faMicrophoneAlt, faMicrophoneAltSlash, faVideo, faVideoSlash, faDoorOpen } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useLingui } from '@lingui/react';
import classNames from 'classnames';
import { motion } from 'framer-motion';
import { MouseEvent, useCallback } from 'react';
import { msg } from "@lingui/macro";
import useLocalizedPush from '@/hooks/useLocalizedPush';
const bgColorMap: Record<ThemeColors, string> = {
'blue': 'text-blue-400 bg-blue-800/50',
'green': 'text-green-400 bg-green-800/50',
'orange': 'text-orange-400 bg-orange-800/50',
};
export default function LocalParticipantControls() {
const { actions, state } = useLocalMedia();
const theme = useTheme();
const { _ } = useLingui();
const { push } = useLocalizedPush();
const { participantId, roomId } = useRoom();
const [leaveRoom] = useLeaveRoomMutation({ variables: { participantId }});
const handleToggleMicrophone = useCallback((e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
actions.toggleMicrophoneEnabled();
}, [actions]);
const handleToggleCamera = useCallback((e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
actions.toggleCameraEnabled();
}, [actions]);
const handleLeaveRoomClick = useCallback(async (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
push(`/evaluate/${roomId}`);
await leaveRoom();
}, [leaveRoom, push, roomId]);
return (
<motion.div
className="absolute top-0 bottom-0 left-0 flex flex-col justify-center gap-2 text-xl pr-2"
initial={{ opacity: 0, scale: 0.7, x: '-75%' }}
animate={{ opacity: 1, scale: 1, x: '-100%' }}
exit={{ opacity: 0, scale: 0.7, x: '-75%' }}
transition={{ duration: 0.1, bounce: 1 }}
>
<button
className={classNames(
"w-8 md:w-12 rounded-lg aspect-square flex justify-center items-center backdrop-blur-lg border-none bg-gray-600/50",
state.isAudioEnabled
? bgColorMap[theme]
: 'text-gray-200 bg-gray-600/50',
)}
title={state.isAudioEnabled ? _(msg`Disable audio`) : _(msg`Enable audio`)}
onClick={handleToggleMicrophone}
>
<FontAwesomeIcon
icon={state.isAudioEnabled ? faMicrophoneAlt : faMicrophoneAltSlash}
fixedWidth
/>
</button>
<button
className={classNames(
"w-8 md:w-12 rounded-lg aspect-square flex justify-center items-center backdrop-blur-lg border-none",
state.isVideoEnabled
? bgColorMap[theme]
: 'text-gray-200 bg-gray-600/50',
)}
title={state.isVideoEnabled ? _(msg`Disable video`) : _(msg`Enable video`)}
onClick={handleToggleCamera}
>
<FontAwesomeIcon
icon={state.isVideoEnabled ? faVideo : faVideoSlash}
fixedWidth
/>
</button>
<button
className={classNames(
"w-8 md:w-12 rounded-lg aspect-square flex justify-center items-center backdrop-blur-lg border-none bg-gray-200/50 text-red-600",
)}
title={_(msg`Leave conversation`)}
onClick={handleLeaveRoomClick}
>
<FontAwesomeIcon
icon={faDoorOpen}
fixedWidth
/>
</button>
</motion.div>
);
}