♻️(frontend) refactor the transcription side panel into a sub menu

Add a new level of nesting while handling side panel.
Code quality is quite poor, we need a better interface.
This commit is contained in:
lebaudantoine
2025-04-04 18:02:55 +02:00
committed by aleb_the_flash
parent 6dccb507d2
commit 255da4bf60
8 changed files with 105 additions and 17 deletions

View File

@@ -3,7 +3,7 @@ import { css } from '@/styled-system/css'
import { Heading } from 'react-aria-components' import { Heading } from 'react-aria-components'
import { text } from '@/primitives/Text' import { text } from '@/primitives/Text'
import { Button, Div } from '@/primitives' import { Button, Div } from '@/primitives'
import { RiCloseLine } from '@remixicon/react' import { RiArrowLeftLine, RiCloseLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { ParticipantsList } from './controls/Participants/ParticipantsList' import { ParticipantsList } from './controls/Participants/ParticipantsList'
import { useSidePanel } from '../hooks/useSidePanel' import { useSidePanel } from '../hooks/useSidePanel'
@@ -19,6 +19,8 @@ type StyledSidePanelProps = {
onClose: () => void onClose: () => void
isClosed: boolean isClosed: boolean
closeButtonTooltip: string closeButtonTooltip: string
isSubmenu: boolean
onBack: () => void
} }
const StyledSidePanel = ({ const StyledSidePanel = ({
@@ -27,6 +29,8 @@ const StyledSidePanel = ({
onClose, onClose,
isClosed, isClosed,
closeButtonTooltip, closeButtonTooltip,
isSubmenu = false,
onBack,
}: StyledSidePanelProps) => ( }: StyledSidePanelProps) => (
<div <div
className={css({ className={css({
@@ -61,9 +65,22 @@ const StyledSidePanel = ({
style={{ style={{
paddingLeft: '1.5rem', paddingLeft: '1.5rem',
paddingTop: '1rem', paddingTop: '1rem',
display: isClosed ? 'none' : undefined, display: isClosed ? 'none' : 'flex',
justifyContent: 'start',
alignItems: 'center',
}} }}
> >
{isSubmenu && (
<Button
variant="secondaryText"
size={'sm'}
square
className={css({ marginRight: '0.5rem' })}
onPress={onBack}
>
<RiArrowLeftLine size={20} />
</Button>
)}
{title} {title}
</Heading> </Heading>
<Div <Div
@@ -116,17 +133,24 @@ export const SidePanel = () => {
isSidePanelOpen, isSidePanelOpen,
isToolsOpen, isToolsOpen,
isAdminOpen, isAdminOpen,
isSubPanelOpen,
activeSubPanelId,
} = useSidePanel() } = useSidePanel()
const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' }) const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' })
return ( return (
<StyledSidePanel <StyledSidePanel
title={t(`heading.${activePanelId}`)} title={t(`heading.${activeSubPanelId || activePanelId}`)}
onClose={() => (layoutStore.activePanelId = null)} onClose={() => {
layoutStore.activePanelId = null
layoutStore.activeSubPanelId = null
}}
closeButtonTooltip={t('closeButton', { closeButtonTooltip={t('closeButton', {
content: t(`content.${activePanelId}`), content: t(`content.${activeSubPanelId || activePanelId}`),
})} })}
isClosed={!isSidePanelOpen} isClosed={!isSidePanelOpen}
isSubmenu={isSubPanelOpen}
onBack={() => (layoutStore.activeSubPanelId = null)}
> >
<Panel isOpen={isParticipantsOpen}> <Panel isOpen={isParticipantsOpen}>
<ParticipantsList /> <ParticipantsList />

View File

@@ -4,6 +4,10 @@ import { Button as RACButton } from 'react-aria-components'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { CRISP_HELP_ARTICLE_MORE_TOOLS } from '@/utils/constants' import { CRISP_HELP_ARTICLE_MORE_TOOLS } from '@/utils/constants'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { Transcript } from './Transcript'
import { RiFileTextFill } from '@remixicon/react'
import { useIsTranscriptEnabled } from '../hooks/useIsTranscriptEnabled'
import { useSidePanel } from '../hooks/useSidePanel'
export interface ToolsButtonProps { export interface ToolsButtonProps {
icon: ReactNode icon: ReactNode
@@ -64,7 +68,14 @@ const ToolButton = ({
} }
export const Tools = () => { export const Tools = () => {
const { openTranscript, isTranscriptOpen } = useSidePanel()
const { t } = useTranslation('rooms', { keyPrefix: 'moreTools' }) const { t } = useTranslation('rooms', { keyPrefix: 'moreTools' })
const isTranscriptEnabled = useIsTranscriptEnabled()
if (isTranscriptOpen && isTranscriptEnabled) {
return <Transcript />
}
return ( return (
<Div <Div
display="flex" display="flex"
@@ -89,7 +100,14 @@ export const Tools = () => {
</A> </A>
. .
</Text> </Text>
WIP {isTranscriptEnabled && (
<ToolButton
icon={<RiFileTextFill size={24} color="white" />}
title={t('tools.transcript.title')}
description={t('tools.transcript.body')}
onPress={() => openTranscript()}
/>
)}
</Div> </Div>
) )
} }

View File

@@ -9,49 +9,70 @@ export enum PanelId {
ADMIN = 'admin', ADMIN = 'admin',
} }
export enum SubPanelId {
TRANSCRIPT = 'transcript',
}
export const useSidePanel = () => { export const useSidePanel = () => {
const layoutSnap = useSnapshot(layoutStore) const layoutSnap = useSnapshot(layoutStore)
const activePanelId = layoutSnap.activePanelId const activePanelId = layoutSnap.activePanelId
const activeSubPanelId = layoutSnap.activeSubPanelId
const isParticipantsOpen = activePanelId == PanelId.PARTICIPANTS const isParticipantsOpen = activePanelId == PanelId.PARTICIPANTS
const isEffectsOpen = activePanelId == PanelId.EFFECTS const isEffectsOpen = activePanelId == PanelId.EFFECTS
const isChatOpen = activePanelId == PanelId.CHAT const isChatOpen = activePanelId == PanelId.CHAT
const isToolsOpen = activePanelId == PanelId.TOOLS const isToolsOpen = activePanelId == PanelId.TOOLS
const isAdminOpen = activePanelId == PanelId.ADMIN const isAdminOpen = activePanelId == PanelId.ADMIN
const isTranscriptOpen = activeSubPanelId == SubPanelId.TRANSCRIPT
const isSidePanelOpen = !!activePanelId const isSidePanelOpen = !!activePanelId
const isSubPanelOpen = !!activeSubPanelId
const toggleAdmin = () => { const toggleAdmin = () => {
layoutStore.activePanelId = isAdminOpen ? null : PanelId.ADMIN layoutStore.activePanelId = isAdminOpen ? null : PanelId.ADMIN
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
} }
const toggleParticipants = () => { const toggleParticipants = () => {
layoutStore.activePanelId = isParticipantsOpen ? null : PanelId.PARTICIPANTS layoutStore.activePanelId = isParticipantsOpen ? null : PanelId.PARTICIPANTS
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
} }
const toggleChat = () => { const toggleChat = () => {
layoutStore.activePanelId = isChatOpen ? null : PanelId.CHAT layoutStore.activePanelId = isChatOpen ? null : PanelId.CHAT
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
} }
const toggleEffects = () => { const toggleEffects = () => {
layoutStore.activePanelId = isEffectsOpen ? null : PanelId.EFFECTS layoutStore.activePanelId = isEffectsOpen ? null : PanelId.EFFECTS
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
} }
const toggleTools = () => { const toggleTools = () => {
layoutStore.activePanelId = isToolsOpen ? null : PanelId.TOOLS layoutStore.activePanelId = isToolsOpen ? null : PanelId.TOOLS
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
}
const openTranscript = () => {
layoutStore.activeSubPanelId = SubPanelId.TRANSCRIPT
layoutStore.activePanelId = PanelId.TOOLS
} }
return { return {
activePanelId, activePanelId,
activeSubPanelId,
toggleParticipants, toggleParticipants,
toggleChat, toggleChat,
toggleEffects, toggleEffects,
toggleTools, toggleTools,
toggleAdmin, toggleAdmin,
openTranscript,
isSubPanelOpen,
isChatOpen, isChatOpen,
isParticipantsOpen, isParticipantsOpen,
isEffectsOpen, isEffectsOpen,
isSidePanelOpen, isSidePanelOpen,
isToolsOpen, isToolsOpen,
isAdminOpen, isAdminOpen,
isTranscriptOpen,
} }
} }

View File

@@ -188,7 +188,12 @@
"moreTools": { "moreTools": {
"body": "", "body": "",
"moreLink": "", "moreLink": "",
"tools": {} "tools": {
"transcript": {
"title": "",
"body": ""
}
}
}, },
"transcript": { "transcript": {
"start": { "start": {

View File

@@ -167,7 +167,7 @@
"participants": "Participants", "participants": "Participants",
"effects": "Effects", "effects": "Effects",
"chat": "Messages in the chat", "chat": "Messages in the chat",
"transcript": "AI Assistant", "transcript": "Transcription",
"admin": "Admin settings", "admin": "Admin settings",
"tools": "More tools" "tools": "More tools"
}, },
@@ -175,7 +175,7 @@
"participants": "participants", "participants": "participants",
"effects": "effects", "effects": "effects",
"chat": "messages", "chat": "messages",
"transcript": "AI assistant", "transcript": "Transcription",
"admin": "admin settings", "admin": "admin settings",
"tools": "more tools" "tools": "more tools"
}, },
@@ -187,7 +187,12 @@
"moreTools": { "moreTools": {
"body": "Access more tools in Visio to enhance your meetings,", "body": "Access more tools in Visio to enhance your meetings,",
"moreLink": "learn more", "moreLink": "learn more",
"tools": {} "tools": {
"transcript": {
"title": "Transcription",
"body": "Transcribe your meeting for later"
}
}
}, },
"transcript": { "transcript": {
"start": { "start": {

View File

@@ -167,7 +167,7 @@
"participants": "Participants", "participants": "Participants",
"effects": "Effets", "effects": "Effets",
"chat": "Messages dans l'appel", "chat": "Messages dans l'appel",
"transcript": "Assistant IA", "transcript": "Transcription",
"admin": "Commandes de l'organisateur", "admin": "Commandes de l'organisateur",
"tools": "Plus d'outils" "tools": "Plus d'outils"
}, },
@@ -175,7 +175,7 @@
"participants": "les participants", "participants": "les participants",
"effects": "les effets", "effects": "les effets",
"chat": "les messages", "chat": "les messages",
"transcript": "l'assistant IA", "transcript": "transcription",
"admin": "commandes de l'organisateur", "admin": "commandes de l'organisateur",
"tools": "plus d'outils" "tools": "plus d'outils"
}, },
@@ -187,7 +187,12 @@
"moreTools": { "moreTools": {
"body": "Accèder à d'avantage d'outils dans Visio pour améliorer vos réunions,", "body": "Accèder à d'avantage d'outils dans Visio pour améliorer vos réunions,",
"moreLink": "en savoir plus", "moreLink": "en savoir plus",
"tools": {} "tools": {
"transcript": {
"title": "Transcription",
"body": "Transcrivez votre réunion pour plus tard"
}
}
}, },
"transcript": { "transcript": {
"start": { "start": {

View File

@@ -167,7 +167,7 @@
"participants": "Deelnemers", "participants": "Deelnemers",
"effects": "Effecten", "effects": "Effecten",
"chat": "Berichten in de chat", "chat": "Berichten in de chat",
"transcript": "AI-assistent", "transcript": "Transcriptie",
"admin": "Beheerdersbediening", "admin": "Beheerdersbediening",
"tools": "Meer tools" "tools": "Meer tools"
}, },
@@ -175,7 +175,7 @@
"participants": "deelnemers", "participants": "deelnemers",
"effects": "effecten", "effects": "effecten",
"chat": "berichten", "chat": "berichten",
"transcript": "AI-assistent", "transcript": "transcriptie",
"admin": "beheerdersbediening", "admin": "beheerdersbediening",
"tools": "meer tools" "tools": "meer tools"
}, },
@@ -187,7 +187,12 @@
"moreTools": { "moreTools": {
"body": "Toegang tot meer tools in Visio om je vergaderingen te verbeteren,", "body": "Toegang tot meer tools in Visio om je vergaderingen te verbeteren,",
"moreLink": "lees meer", "moreLink": "lees meer",
"tools": {} "tools": {
"transcript": {
"title": "Transcriptie",
"body": "Transcribeer je vergadering voor later"
}
}
}, },
"transcript": { "transcript": {
"start": { "start": {

View File

@@ -1,14 +1,19 @@
import { proxy } from 'valtio' import { proxy } from 'valtio'
import { PanelId } from '@/features/rooms/livekit/hooks/useSidePanel' import {
PanelId,
SubPanelId,
} from '@/features/rooms/livekit/hooks/useSidePanel'
type State = { type State = {
showHeader: boolean showHeader: boolean
showFooter: boolean showFooter: boolean
activePanelId: PanelId | null activePanelId: PanelId | null
activeSubPanelId: SubPanelId | null
} }
export const layoutStore = proxy<State>({ export const layoutStore = proxy<State>({
showHeader: false, showHeader: false,
showFooter: false, showFooter: false,
activePanelId: null, activePanelId: null,
activeSubPanelId: null,
}) })