♻️(frontend) introduce a reusable tools sidepanel

tools will be added in the future, let's generalize the sidepanel
previously reserved to transcription.
This commit is contained in:
lebaudantoine
2025-04-04 17:01:02 +02:00
committed by aleb_the_flash
parent 60321296e5
commit 91562d049c
11 changed files with 167 additions and 46 deletions

View File

@@ -9,9 +9,9 @@ import { ParticipantsList } from './controls/Participants/ParticipantsList'
import { useSidePanel } from '../hooks/useSidePanel' import { useSidePanel } from '../hooks/useSidePanel'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { Chat } from '../prefabs/Chat' import { Chat } from '../prefabs/Chat'
import { Transcript } from './Transcript'
import { Effects } from './effects/Effects' import { Effects } from './effects/Effects'
import { Admin } from './Admin' import { Admin } from './Admin'
import { Tools } from './Tools'
type StyledSidePanelProps = { type StyledSidePanelProps = {
title: string title: string
@@ -114,7 +114,7 @@ export const SidePanel = () => {
isEffectsOpen, isEffectsOpen,
isChatOpen, isChatOpen,
isSidePanelOpen, isSidePanelOpen,
isTranscriptOpen, isToolsOpen,
isAdminOpen, isAdminOpen,
} = useSidePanel() } = useSidePanel()
const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' }) const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' })
@@ -137,8 +137,8 @@ export const SidePanel = () => {
<Panel isOpen={isChatOpen}> <Panel isOpen={isChatOpen}>
<Chat /> <Chat />
</Panel> </Panel>
<Panel isOpen={isTranscriptOpen}> <Panel isOpen={isToolsOpen}>
<Transcript /> <Tools />
</Panel> </Panel>
<Panel isOpen={isAdminOpen}> <Panel isOpen={isAdminOpen}>
<Admin /> <Admin />

View File

@@ -0,0 +1,95 @@
import { A, Div, Text } from '@/primitives'
import { css } from '@/styled-system/css'
import { Button as RACButton } from 'react-aria-components'
import { useTranslation } from 'react-i18next'
import { CRISP_HELP_ARTICLE_MORE_TOOLS } from '@/utils/constants'
import { ReactNode } from 'react'
export interface ToolsButtonProps {
icon: ReactNode
title: string
description: string
onPress: () => void
}
const ToolButton = ({
icon,
title,
description,
onPress,
}: ToolsButtonProps) => {
return (
<RACButton
className={css({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'start',
paddingY: '0.5rem',
paddingX: '0.75rem 1.5rem',
borderRadius: '5px',
gap: '1.25rem',
width: 'full',
textAlign: 'start',
'&[data-hovered]': {
backgroundColor: 'primary.50',
cursor: 'pointer',
},
})}
onPress={onPress}
>
<div
className={css({
height: '50px',
minWidth: '50px',
borderRadius: '25px',
backgroundColor: 'primary.800',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
})}
>
{icon}
</div>
<div>
<Text margin={false} as="h3">
{title}
</Text>
<Text as="p" variant="smNote" wrap="pretty">
{description}
</Text>
</div>
</RACButton>
)
}
export const Tools = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'moreTools' })
return (
<Div
display="flex"
overflowY="scroll"
padding="0 0.75rem"
flexGrow={1}
flexDirection="column"
alignItems="start"
>
<Text
variant="note"
wrap="balance"
className={css({
textStyle: 'sm',
paddingX: '0.75rem',
})}
margin="md"
>
{t('body')}{' '}
<A href={CRISP_HELP_ARTICLE_MORE_TOOLS} target="_blank">
{t('moreLink')}
</A>
.
</Text>
WIP
</Div>
)
}

View File

@@ -1,24 +1,19 @@
import { ToggleButton } from '@/primitives' import { ToggleButton } from '@/primitives'
import { RiBardLine } from '@remixicon/react' import { RiShapesLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSidePanel } from '../../hooks/useSidePanel' import { useSidePanel } from '../../hooks/useSidePanel'
import { useHasTranscriptAccess } from '../../hooks/useHasTranscriptAccess'
import { css } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { ToggleButtonProps } from '@/primitives/ToggleButton' import { ToggleButtonProps } from '@/primitives/ToggleButton'
export const TranscriptToggle = ({ export const ToolsToggle = ({
variant = 'primaryTextDark', variant = 'primaryTextDark',
onPress, onPress,
...props ...props
}: ToggleButtonProps) => { }: ToggleButtonProps) => {
const { t } = useTranslation('rooms', { keyPrefix: 'controls.transcript' }) const { t } = useTranslation('rooms', { keyPrefix: 'controls.tools' })
const { isTranscriptOpen, toggleTranscript } = useSidePanel() const { isToolsOpen, toggleTools } = useSidePanel()
const tooltipLabel = isTranscriptOpen ? 'open' : 'closed' const tooltipLabel = isToolsOpen ? 'open' : 'closed'
const hasTranscriptAccess = useHasTranscriptAccess()
if (!hasTranscriptAccess) return
return ( return (
<div <div
@@ -32,15 +27,15 @@ export const TranscriptToggle = ({
variant={variant} variant={variant}
aria-label={t(tooltipLabel)} aria-label={t(tooltipLabel)}
tooltip={t(tooltipLabel)} tooltip={t(tooltipLabel)}
isSelected={isTranscriptOpen} isSelected={isToolsOpen}
onPress={(e) => { onPress={(e) => {
toggleTranscript() toggleTools()
onPress?.(e) onPress?.(e)
}} }}
{...props} {...props}
data-attr="toggle-transcript" data-attr="toggle-tools"
> >
<RiBardLine /> <RiShapesLine />
</ToggleButton> </ToggleButton>
</div> </div>
) )

View File

@@ -5,7 +5,7 @@ export enum PanelId {
PARTICIPANTS = 'participants', PARTICIPANTS = 'participants',
EFFECTS = 'effects', EFFECTS = 'effects',
CHAT = 'chat', CHAT = 'chat',
TRANSCRIPT = 'transcript', TOOLS = 'tools',
ADMIN = 'admin', ADMIN = 'admin',
} }
@@ -16,7 +16,7 @@ export const useSidePanel = () => {
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 isTranscriptOpen = activePanelId == PanelId.TRANSCRIPT const isToolsOpen = activePanelId == PanelId.TOOLS
const isAdminOpen = activePanelId == PanelId.ADMIN const isAdminOpen = activePanelId == PanelId.ADMIN
const isSidePanelOpen = !!activePanelId const isSidePanelOpen = !!activePanelId
@@ -36,8 +36,8 @@ export const useSidePanel = () => {
layoutStore.activePanelId = isEffectsOpen ? null : PanelId.EFFECTS layoutStore.activePanelId = isEffectsOpen ? null : PanelId.EFFECTS
} }
const toggleTranscript = () => { const toggleTools = () => {
layoutStore.activePanelId = isTranscriptOpen ? null : PanelId.TRANSCRIPT layoutStore.activePanelId = isToolsOpen ? null : PanelId.TOOLS
} }
return { return {
@@ -45,13 +45,13 @@ export const useSidePanel = () => {
toggleParticipants, toggleParticipants,
toggleChat, toggleChat,
toggleEffects, toggleEffects,
toggleTranscript, toggleTools,
toggleAdmin, toggleAdmin,
isChatOpen, isChatOpen,
isParticipantsOpen, isParticipantsOpen,
isEffectsOpen, isEffectsOpen,
isSidePanelOpen, isSidePanelOpen,
isTranscriptOpen, isToolsOpen,
isAdminOpen, isAdminOpen,
} }
} }

View File

@@ -21,7 +21,7 @@ import { useSidePanel } from '../../hooks/useSidePanel'
import { LinkButton } from '@/primitives' import { LinkButton } from '@/primitives'
import { useSettingsDialog } from '../../components/controls/SettingsDialogContext' import { useSettingsDialog } from '../../components/controls/SettingsDialogContext'
import { ResponsiveMenu } from './ResponsiveMenu' import { ResponsiveMenu } from './ResponsiveMenu'
import { TranscriptToggle } from '../../components/controls/TranscriptToggle' import { ToolsToggle } from '../../components/controls/ToolsToggle'
import { CameraSwitchButton } from '../../components/controls/CameraSwitchButton' import { CameraSwitchButton } from '../../components/controls/CameraSwitchButton'
export function MobileControlBar({ export function MobileControlBar({
@@ -133,7 +133,7 @@ export function MobileControlBar({
description={true} description={true}
onPress={() => setIsMenuOpened(false)} onPress={() => setIsMenuOpened(false)}
/> />
<TranscriptToggle <ToolsToggle
description={true} description={true}
onPress={() => setIsMenuOpened(false)} onPress={() => setIsMenuOpened(false)}
/> />

View File

@@ -1,7 +1,7 @@
import { css } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { ChatToggle } from '../../components/controls/ChatToggle' import { ChatToggle } from '../../components/controls/ChatToggle'
import { ParticipantsToggle } from '../../components/controls/Participants/ParticipantsToggle' import { ParticipantsToggle } from '../../components/controls/Participants/ParticipantsToggle'
import { TranscriptToggle } from '../../components/controls/TranscriptToggle' import { ToolsToggle } from '../../components/controls/ToolsToggle'
import { AdminToggle } from '../../components/AdminToggle' import { AdminToggle } from '../../components/AdminToggle'
import { useSize } from '../../hooks/useResizeObserver' import { useSize } from '../../hooks/useResizeObserver'
import { useState, RefObject } from 'react' import { useState, RefObject } from 'react'
@@ -20,7 +20,7 @@ const NavigationControls = ({
<> <>
<ChatToggle onPress={onPress} tooltipType={tooltipType} /> <ChatToggle onPress={onPress} tooltipType={tooltipType} />
<ParticipantsToggle onPress={onPress} tooltipType={tooltipType} /> <ParticipantsToggle onPress={onPress} tooltipType={tooltipType} />
<TranscriptToggle onPress={onPress} tooltipType={tooltipType} /> <ToolsToggle onPress={onPress} tooltipType={tooltipType} />
<AdminToggle onPress={onPress} tooltipType={tooltipType} /> <AdminToggle onPress={onPress} tooltipType={tooltipType} />
</> </>
) )

View File

@@ -104,7 +104,7 @@
"open": "", "open": "",
"closed": "" "closed": ""
}, },
"transcript": { "tools": {
"open": "", "open": "",
"closed": "" "closed": ""
}, },
@@ -169,20 +169,27 @@
"effects": "", "effects": "",
"chat": "", "chat": "",
"transcript": "", "transcript": "",
"admin": "" "admin": "",
"tools": ""
}, },
"content": { "content": {
"participants": "", "participants": "",
"effects": "", "effects": "",
"chat": "", "chat": "",
"transcript": "", "transcript": "",
"admin": "" "admin": "",
"tools": ""
}, },
"closeButton": "" "closeButton": ""
}, },
"chat": { "chat": {
"disclaimer": "" "disclaimer": ""
}, },
"moreTools": {
"body": "",
"moreLink": "",
"tools": {}
},
"transcript": { "transcript": {
"start": { "start": {
"heading": "", "heading": "",

View File

@@ -103,9 +103,9 @@
"open": "Hide everyone", "open": "Hide everyone",
"closed": "See everyone" "closed": "See everyone"
}, },
"transcript": { "tools": {
"open": "Hide AI assistant", "open": "Hide more tools",
"closed": "Show AI assistant" "closed": "Show more tools"
}, },
"admin": { "admin": {
"open": "Hide admin", "open": "Hide admin",
@@ -168,20 +168,27 @@
"effects": "Effects", "effects": "Effects",
"chat": "Messages in the chat", "chat": "Messages in the chat",
"transcript": "AI Assistant", "transcript": "AI Assistant",
"admin": "Admin settings" "admin": "Admin settings",
"tools": "More tools"
}, },
"content": { "content": {
"participants": "participants", "participants": "participants",
"effects": "effects", "effects": "effects",
"chat": "messages", "chat": "messages",
"transcript": "AI assistant", "transcript": "AI assistant",
"admin": "Admin settings" "admin": "admin settings",
"tools": "more tools"
}, },
"closeButton": "Hide {{content}}" "closeButton": "Hide {{content}}"
}, },
"chat": { "chat": {
"disclaimer": "The messages are visible to participants only at the time they are sent. All messages are deleted at the end of the call." "disclaimer": "The messages are visible to participants only at the time they are sent. All messages are deleted at the end of the call."
}, },
"moreTools": {
"body": "Access more tools in Visio to enhance your meetings,",
"moreLink": "learn more",
"tools": {}
},
"transcript": { "transcript": {
"start": { "start": {
"heading": "Start the Assistant!", "heading": "Start the Assistant!",

View File

@@ -103,9 +103,9 @@
"open": "Masquer les participants", "open": "Masquer les participants",
"closed": "Afficher les participants" "closed": "Afficher les participants"
}, },
"transcript": { "tools": {
"open": "Masquer l'assistant IA", "open": "Masquer plus d'outils",
"closed": "Afficher l'assistant IA" "closed": "Afficher plus d'outils"
}, },
"admin": { "admin": {
"open": "Masquer l'admin", "open": "Masquer l'admin",
@@ -168,20 +168,27 @@
"effects": "Effets", "effects": "Effets",
"chat": "Messages dans l'appel", "chat": "Messages dans l'appel",
"transcript": "Assistant IA", "transcript": "Assistant IA",
"admin": "Commandes de l'organisateur" "admin": "Commandes de l'organisateur",
"tools": "Plus d'outils"
}, },
"content": { "content": {
"participants": "les participants", "participants": "les participants",
"effects": "les effets", "effects": "les effets",
"chat": "les messages", "chat": "les messages",
"transcript": "l'assistant IA", "transcript": "l'assistant IA",
"admin": "Commandes de l'organisateur" "admin": "commandes de l'organisateur",
"tools": "plus d'outils"
}, },
"closeButton": "Masquer {{content}}" "closeButton": "Masquer {{content}}"
}, },
"chat": { "chat": {
"disclaimer": "Les messages sont visibles par les participants uniquement au moment de\nleur envoi. Tous les messages sont supprimés à la fin de l'appel." "disclaimer": "Les messages sont visibles par les participants uniquement au moment de\nleur envoi. Tous les messages sont supprimés à la fin de l'appel."
}, },
"moreTools": {
"body": "Accèder à d'avantage d'outils dans Visio pour améliorer vos réunions,",
"moreLink": "en savoir plus",
"tools": {}
},
"transcript": { "transcript": {
"start": { "start": {
"heading": "Démarrer l'assistant !", "heading": "Démarrer l'assistant !",

View File

@@ -103,9 +103,9 @@
"open": "Verberg iedereen", "open": "Verberg iedereen",
"closed": "Toon iedereen" "closed": "Toon iedereen"
}, },
"transcript": { "tools": {
"open": "Verberg AI-assistent", "open": "Meer tools verbergen",
"closed": "Toon AI-assistant" "closed": "Meer tools weergeven"
}, },
"admin": { "admin": {
"open": "Verberg beheerder", "open": "Verberg beheerder",
@@ -168,20 +168,27 @@
"effects": "Effecten", "effects": "Effecten",
"chat": "Berichten in de chat", "chat": "Berichten in de chat",
"transcript": "AI-assistent", "transcript": "AI-assistent",
"admin": "Beheerdersbediening" "admin": "Beheerdersbediening",
"tools": "Meer tools"
}, },
"content": { "content": {
"participants": "deelnemers", "participants": "deelnemers",
"effects": "effecten", "effects": "effecten",
"chat": "berichten", "chat": "berichten",
"transcript": "AI-assistent", "transcript": "AI-assistent",
"admin": "Beheerdersbediening" "admin": "beheerdersbediening",
"tools": "meer tools"
}, },
"closeButton": "Verberg {{content}}" "closeButton": "Verberg {{content}}"
}, },
"chat": { "chat": {
"disclaimer": "De berichten zijn alleen voor de deelnemers zichtbaar op het moment dat ze worden verzonden. Alle berichten worden verwijderd aan het einde van het gesprek." "disclaimer": "De berichten zijn alleen voor de deelnemers zichtbaar op het moment dat ze worden verzonden. Alle berichten worden verwijderd aan het einde van het gesprek."
}, },
"moreTools": {
"body": "Toegang tot meer tools in Visio om je vergaderingen te verbeteren,",
"moreLink": "lees meer",
"tools": {}
},
"transcript": { "transcript": {
"start": { "start": {
"heading": "Start de assistent!", "heading": "Start de assistent!",

View File

@@ -3,3 +3,6 @@ export const GRIST_FEEDBACKS_FORM =
export const BETA_USERS_FORM_URL = export const BETA_USERS_FORM_URL =
'https://grist.numerique.gouv.fr/o/docs/forms/3fFfvJoTBEQ6ZiMi8zsQwX/17' as const 'https://grist.numerique.gouv.fr/o/docs/forms/3fFfvJoTBEQ6ZiMi8zsQwX/17' as const
export const CRISP_HELP_ARTICLE_MORE_TOOLS =
'https://lasuite.crisp.help/fr/article/visio-tools-bvxj23' as const