♻️(frontend) move reaction-related code into a dedicated feature folder

Group all reaction components, hooks, and logic under a single
feature directory to improve code organization and maintainability.
This commit is contained in:
lebaudantoine
2026-03-25 16:51:38 +01:00
parent 0cd44a8f93
commit 74b71f4a9b
11 changed files with 47 additions and 38 deletions
@@ -13,8 +13,8 @@ import { WaitingParticipantNotification } from './components/WaitingParticipantN
import { layoutStore } from '@/stores/layout'
import { PanelId } from '@/features/rooms/livekit/hooks/useSidePanel'
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
import { useReactions } from '@/features/rooms/livekit/hooks/useReactions'
import { Emoji } from '@/stores/reactions'
import { Emoji } from '@/features/reactions/types'
import { useReactions } from '@/features/reactions/hooks/useReactions'
export const MainNotificationToast = () => {
const room = useRoomContext()
@@ -3,14 +3,16 @@ import { useState, useEffect, useMemo } from 'react'
import { Text } from '@/primitives'
import { css } from '@/styled-system/css'
import { useSnapshot } from 'valtio'
import { Reaction, reactionsStore } from '@/stores/reactions'
import { reactionsStore } from '@/stores/reactions'
import { useAnnounceReaction } from '../hooks/useAnnounceReaction'
export const ANIMATION_DURATION = 3000
export const ANIMATION_DISTANCE = 300
export const FADE_OUT_THRESHOLD = 0.7
export const REACTION_SPAWN_WIDTH_RATIO = 0.2
export const INITIAL_POSITION = 200
import { Reaction } from '../types'
import {
ANIMATION_DISTANCE,
ANIMATION_DURATION,
FADE_OUT_THRESHOLD,
INITIAL_POSITION,
REACTION_SPAWN_WIDTH_RATIO,
} from '../constants'
interface FloatingReactionProps {
emoji: string
@@ -112,7 +114,7 @@ export function FloatingReaction({
)
}
export function ReactionPortal({ reaction }: { reaction: Reaction }) {
const ReactionPortal = ({ reaction }: { reaction: Reaction }) => {
const speed = useMemo(() => Math.random() * 1.5 + 0.5, [])
const scale = useMemo(() => Math.max(Math.random() + 0.5, 1), [])
return createPortal(
@@ -4,7 +4,6 @@ import { useState } from 'react'
import { css } from '@/styled-system/css'
import { ToggleButton, Button } from '@/primitives'
import { getEmojiLabel } from '@/features/rooms/livekit/utils/reactionUtils'
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
import {
Popover as RACPopover,
@@ -12,8 +11,9 @@ import {
DialogTrigger,
} from 'react-aria-components'
import { FocusScope } from '@react-aria/focus'
import { useReactions } from '../../hooks/useReactions'
import { Emoji } from '@/stores/reactions.ts'
import { useReactions } from '../hooks/useReactions'
import { Emoji } from '../types'
import { getEmojiLabel } from '../utils'
export const ReactionsToggle = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
@@ -0,0 +1,5 @@
export const ANIMATION_DURATION = 3000
export const ANIMATION_DISTANCE = 300
export const FADE_OUT_THRESHOLD = 0.7
export const REACTION_SPAWN_WIDTH_RATIO = 0.2
export const INITIAL_POSITION = 200
@@ -3,8 +3,9 @@ import { useTranslation } from 'react-i18next'
import { useSnapshot } from 'valtio'
import { accessibilityStore } from '@/stores/accessibility'
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
import { getEmojiLabel } from '@/features/rooms/livekit/utils/reactionUtils'
import { Reaction } from '@/stores/reactions'
import { getEmojiLabel } from '../utils'
import { Reaction } from '../types'
export const useAnnounceReaction = (latestReaction: Reaction | undefined) => {
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
@@ -1,11 +1,12 @@
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { Emoji, reactionsStore } from '@/stores/reactions'
import { reactionsStore } from '@/stores/reactions'
import { NotificationType } from '@/features/notifications/NotificationType'
import { ANIMATION_DURATION } from '@/features/rooms/livekit/components/ReactionPortal'
import useRateLimiter from '@/hooks/useRateLimiter'
import { useNotifyParticipants } from '@/features/notifications'
import useRateLimiter from '@/hooks/useRateLimiter'
import { Participant } from 'livekit-client'
import { Emoji } from '../types'
import { ANIMATION_DURATION } from '../constants'
export const useReactions = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
@@ -0,0 +1,17 @@
export enum Emoji {
THUMBS_UP = 'thumbs-up',
THUMBS_DOWN = 'thumbs-down',
CLAP = 'clapping-hands',
HEART = 'red-heart',
LAUGHING = 'face-with-tears-of-joy',
SURPRISED = 'face-with-open-mouth',
CELEBRATION = 'party-popper',
PLEASE = 'folded-hands',
}
export interface Reaction {
id: string
emoji: Emoji
participantName: string
isLocal: boolean
}
@@ -3,7 +3,6 @@ import { ControlBarAuxProps } from './ControlBar'
import { css } from '@/styled-system/css'
import { LeaveButton } from '../../components/controls/LeaveButton'
import { Track } from 'livekit-client'
import { ReactionsToggle } from '../../components/controls/ReactionsToggle'
import { HandToggle } from '../../components/controls/HandToggle'
import { ScreenShareToggle } from '../../components/controls/ScreenShareToggle'
import { SubtitlesToggle } from '../../components/controls/SubtitlesToggle'
@@ -15,6 +14,7 @@ import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKey
import { useFullScreen } from '../../hooks/useFullScreen'
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl'
import { ReactionsToggle } from '@/features/reactions/components/ReactionsToggle'
export function DesktopControlBar({
onDeviceError,
@@ -44,7 +44,7 @@ import { GridLayout } from '../components/layout/GridLayout'
import { IsIdleDisconnectModal } from '../components/IsIdleDisconnectModal'
import { getParticipantName } from '@/features/rooms/utils/getParticipantName'
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
import { ReactionPortals } from '@/features/rooms/livekit/components/ReactionPortal'
import { ReactionPortals } from '@/features/reactions/components/ReactionPortals'
const LayoutWrapper = styled(
'div',
+1 -18
View File
@@ -1,22 +1,5 @@
import { proxy } from 'valtio'
export enum Emoji {
THUMBS_UP = 'thumbs-up',
THUMBS_DOWN = 'thumbs-down',
CLAP = 'clapping-hands',
HEART = 'red-heart',
LAUGHING = 'face-with-tears-of-joy',
SURPRISED = 'face-with-open-mouth',
CELEBRATION = 'party-popper',
PLEASE = 'folded-hands',
}
export interface Reaction {
id: string
emoji: Emoji
participantName: string
isLocal: boolean
}
import { Reaction } from '@/features/reactions/types'
type State = {
reactions: Reaction[]