🔧(frontend) make feedback form configurable via backend settings

Implement conditional rendering that hides all feedback-related UI components
when feedback is disabled in backend configuration.

Also, feedback URL is now customizable.
This commit is contained in:
lebaudantoine
2025-04-28 16:48:26 +02:00
committed by aleb_the_flash
parent f2e6edb90d
commit 56c1cd98fa
10 changed files with 37 additions and 22 deletions

View File

@@ -312,6 +312,9 @@ class Base(Configuration):
"is_silent_login_enabled": values.BooleanValue(
True, environ_name="FRONTEND_IS_SILENT_LOGING_ENABLED", environ_prefix=None
),
"feedback": values.DictValue(
{}, environ_name="FRONTEND_FEEDBACK", environ_prefix=None
),
}
# Mail

View File

@@ -11,6 +11,9 @@ export interface ApiConfig {
support?: {
id: string
}
feedback: {
url: string
}
silence_livekit_debug_logs?: boolean
is_silent_login_enabled?: boolean
recording?: {

View File

@@ -2,10 +2,14 @@ import { css } from '@/styled-system/css'
import { RiErrorWarningLine, RiExternalLinkLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { Text, A } from '@/primitives'
import { GRIST_FEEDBACKS_FORM } from '@/utils/constants'
import { useConfig } from '@/api/useConfig'
export const FeedbackBanner = () => {
const { t } = useTranslation()
const { data } = useConfig()
if (!data?.feedback?.url) return
return (
<div
className={css({
@@ -35,7 +39,7 @@ export const FeedbackBanner = () => {
gap: 0.25,
})}
>
<A href={GRIST_FEEDBACKS_FORM} target="_blank" size="sm">
<A href={data?.feedback?.url} target="_blank" size="sm">
{t('feedback.cta')}
</A>
<RiExternalLinkLine size={16} aria-hidden="true" />

View File

@@ -2,14 +2,17 @@ import { RiMegaphoneLine } from '@remixicon/react'
import { MenuItem } from 'react-aria-components'
import { useTranslation } from 'react-i18next'
import { menuRecipe } from '@/primitives/menuRecipe'
import { GRIST_FEEDBACKS_FORM } from '@/utils/constants'
import { useConfig } from '@/api/useConfig'
export const FeedbackMenuItem = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
const { data } = useConfig()
if (!data?.feedback?.url) return
return (
<MenuItem
href={GRIST_FEEDBACKS_FORM}
href={data?.feedback?.url}
target="_blank"
className={menuRecipe({ icon: true, variant: 'dark' }).item}
>

View File

@@ -14,7 +14,6 @@ import {
RiMore2Line,
RiSettings3Line,
} from '@remixicon/react'
import { GRIST_FEEDBACKS_FORM } from '@/utils/constants'
import { ScreenShareToggle } from '../../components/controls/ScreenShareToggle'
import { ChatToggle } from '../../components/controls/ChatToggle'
import { ParticipantsToggle } from '../../components/controls/Participants/ParticipantsToggle'
@@ -24,6 +23,7 @@ import { useSettingsDialog } from '../../components/controls/SettingsDialogConte
import { ResponsiveMenu } from './ResponsiveMenu'
import { ToolsToggle } from '../../components/controls/ToolsToggle'
import { CameraSwitchButton } from '../../components/controls/CameraSwitchButton'
import { useConfig } from '@/api/useConfig'
export function MobileControlBar({
onDeviceError,
@@ -38,6 +38,8 @@ export function MobileControlBar({
const { toggleEffects } = useSidePanel()
const { setDialogOpen } = useSettingsDialog()
const { data } = useConfig()
return (
<>
<div
@@ -150,17 +152,19 @@ export function MobileControlBar({
>
<RiAccountBoxLine size={20} />
</Button>
<LinkButton
href={GRIST_FEEDBACKS_FORM}
variant="primaryTextDark"
tooltip={t('options.items.feedback')}
aria-label={t('options.items.feedback')}
description={true}
target="_blank"
onPress={() => setIsMenuOpened(false)}
>
<RiMegaphoneLine size={20} />
</LinkButton>
{data?.feedback?.url && (
<LinkButton
href={data?.feedback?.url}
variant="primaryTextDark"
tooltip={t('options.items.feedback')}
aria-label={t('options.items.feedback')}
description={true}
target="_blank"
onPress={() => setIsMenuOpened(false)}
>
<RiMegaphoneLine size={20} />
</LinkButton>
)}
<Button
onPress={() => {
setDialogOpen(true)

View File

@@ -7,7 +7,7 @@
"heading": "An error occurred while loading the page"
},
"feedback": {
"context": "Visio is still in early development — your input matters!",
"context": "Product under development — your input matters!",
"cta": "Share your feedback"
},
"forbidden": {

View File

@@ -7,7 +7,7 @@
"heading": "Une erreur est survenue lors du chargement de la page"
},
"feedback": {
"context": "Visio est en pleine construction — votre avis compte !",
"context": "Produit en cours de développement — votre avis compte !",
"cta": "Partagez votre avis"
},
"forbidden": {

View File

@@ -7,7 +7,7 @@
"heading": "Er is een fout opgetreden bij het laden van de pagina"
},
"feedback": {
"context": "Visio is nog in vroege ontwikkeling - uw input is belangrijk!",
"context": "Product in ontwikkeling - uw input is belangrijk!",
"cta": "Deel uw feedback"
},
"forbidden": {

View File

@@ -1,6 +1,3 @@
export const GRIST_FEEDBACKS_FORM =
'https://grist.numerique.gouv.fr/o/docs/cbMv4G7pLY3Z/USER-RESEARCH-or-LA-SUITE/f/26' as const
export const BETA_USERS_FORM_URL =
'https://grist.numerique.gouv.fr/o/docs/forms/3fFfvJoTBEQ6ZiMi8zsQwX/17' as const

View File

@@ -55,6 +55,7 @@ backend:
ALLOW_UNREGISTERED_ROOMS: False
FRONTEND_SILENCE_LIVEKIT_DEBUG: False
FRONTEND_SUPPORT: "{'id': '58ea6697-8eba-4492-bc59-ad6562585041'}"
FRONTEND_FEEDBACK: "{'url': 'https://grist.numerique.gouv.fr/o/docs/cbMv4G7pLY3Z/USER-RESEARCH-or-LA-SUITE/f/26'}"
AWS_S3_ENDPOINT_URL: http://minio.meet.svc.cluster.local:9000
AWS_S3_ACCESS_KEY_ID: meet
AWS_S3_SECRET_ACCESS_KEY: password