diff --git a/src/backend/impress/configuration/theme/default.json b/src/backend/impress/configuration/theme/default.json index 99479ea7..578e5cc0 100644 --- a/src/backend/impress/configuration/theme/default.json +++ b/src/backend/impress/configuration/theme/default.json @@ -162,5 +162,8 @@ "onboarding": { "enabled": true, "learn_more_url": "" + }, + "help": { + "documentation_url": "" } } diff --git a/src/frontend/apps/e2e/__tests__/app-impress/help.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/help.spec.ts index 9f43eb4d..cb979a36 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/help.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/help.spec.ts @@ -8,6 +8,68 @@ import { } from './utils-common'; test.describe('Help feature', () => { + test.describe('Documentation button', () => { + if (process.env.IS_INSTANCE !== 'true') { + test('is not displayed if documentation_url is not set', async ({ + page, + }) => { + await overrideConfig(page, { + theme_customization: { + help: { + documentation_url: '', + }, + onboarding: { + enabled: true, + }, + }, + }); + + await page.goto('/'); + + await page.getByRole('button', { name: 'Open help menu' }).click(); + await expect( + page.getByRole('menuitem', { name: 'Documentation' }), + ).toBeHidden(); + }); + } + + test('is displayed if documentation_url is set', async ({ page }) => { + let documentationUrl: string; + + if (process.env.IS_INSTANCE !== 'true') { + documentationUrl = `${process.env.BASE_URL}/docs/`; + await overrideConfig(page, { + theme_customization: { + help: { + documentation_url: documentationUrl, + }, + }, + }); + } else { + const currentConfig = await getCurrentConfig(page); + test.skip( + !currentConfig.theme_customization?.help?.documentation_url, + 'Documentation URL is not set', + ); + documentationUrl = + currentConfig.theme_customization.help.documentation_url; + } + + await page.goto('/'); + + await page.getByRole('button', { name: 'Open help menu' }).click(); + const docMenuItem = page.getByRole('menuitem', { name: 'Documentation' }); + await expect(docMenuItem).toBeVisible(); + + const [newPage] = await Promise.all([ + page.context().waitForEvent('page'), + docMenuItem.click(), + ]); + + await expect(newPage).toHaveURL(documentationUrl); + }); + }); + test.describe('Support button', () => { if (process.env.IS_INSTANCE !== 'true') { test('is not displayed if CRISP_WEBSITE_ID is not set', async ({ diff --git a/src/frontend/apps/impress/src/assets/icons/ui-kit/doc.svg b/src/frontend/apps/impress/src/assets/icons/ui-kit/doc.svg index e62b7498..785dab85 100644 --- a/src/frontend/apps/impress/src/assets/icons/ui-kit/doc.svg +++ b/src/frontend/apps/impress/src/assets/icons/ui-kit/doc.svg @@ -1,3 +1,6 @@ - - + + diff --git a/src/frontend/apps/impress/src/core/config/api/useConfig.tsx b/src/frontend/apps/impress/src/core/config/api/useConfig.tsx index 3597c1cc..d15ba71f 100644 --- a/src/frontend/apps/impress/src/core/config/api/useConfig.tsx +++ b/src/frontend/apps/impress/src/core/config/api/useConfig.tsx @@ -16,17 +16,20 @@ interface ThemeCustomization { light: LinkHTMLAttributes; dark: LinkHTMLAttributes; }; - onboarding?: { - enabled: true; - learn_more_url?: string; - }; footer?: FooterType; + header?: HeaderType; + help: { + documentation_url?: string; + }; home: { 'with-proconnect'?: boolean; 'icon-banner'?: Imagetype; }; + onboarding?: { + enabled: true; + learn_more_url?: string; + }; translations?: Resource; - header?: HeaderType; waffle?: WaffleType; } diff --git a/src/frontend/apps/impress/src/features/help/components/HelpMenu.tsx b/src/frontend/apps/impress/src/features/help/components/HelpMenu.tsx index 7173d32e..fbff4b45 100644 --- a/src/frontend/apps/impress/src/features/help/components/HelpMenu.tsx +++ b/src/frontend/apps/impress/src/features/help/components/HelpMenu.tsx @@ -3,15 +3,16 @@ import { ButtonProps, useModal, } from '@gouvfr-lasuite/cunningham-react'; -import { DropdownMenu } from '@gouvfr-lasuite/ui-kit'; +import { DropdownMenu, DropdownMenuOption } from '@gouvfr-lasuite/ui-kit'; import { useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; import BubbleTextIcon from '@/assets/icons/ui-kit/bubble-text.svg'; +import DocIcon from '@/assets/icons/ui-kit/doc.svg'; import HelpIcon from '@/assets/icons/ui-kit/question-mark.svg'; import WandAndStarsIcon from '@/assets/icons/ui-kit/wand-and-stars.svg'; -import { Box, DropdownMenuOption } from '@/components'; +import { Box } from '@/components'; import { useConfig } from '@/core'; import { openCrispChat } from '@/services'; @@ -27,6 +28,7 @@ export const HelpMenu = ({ const modalOnbording = useModal(); const { data: config } = useConfig(); const onboardingEnabled = config?.theme_customization?.onboarding?.enabled; + const documentationUrl = config?.theme_customization?.help?.documentation_url; const crispEnabled = !!config?.CRISP_WEBSITE_ID; const toggleMenu = useCallback(() => { @@ -39,16 +41,26 @@ export const HelpMenu = ({ label: t('Get Support'), icon: , callback: openCrispChat, - show: crispEnabled, + isHidden: !crispEnabled, + }, + { + label: t('Documentation'), + icon: , + callback: () => { + if (documentationUrl) { + window.open(documentationUrl, '_blank', 'noopener,noreferrer'); + } + }, + isHidden: !documentationUrl, }, { label: t('Onboarding'), icon: , callback: modalOnbording.open, - show: onboardingEnabled, + isHidden: !onboardingEnabled, }, ], - [modalOnbording.open, t, onboardingEnabled, crispEnabled], + [t, crispEnabled, documentationUrl, modalOnbording.open, onboardingEnabled], ); return ( diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx index 59966e10..6d6c8da5 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx @@ -42,7 +42,8 @@ export const LeftPanelDesktop = () => { */ const showHelpMenu = config?.theme_customization?.onboarding?.enabled || - !!config?.CRISP_WEBSITE_ID; + !!config?.CRISP_WEBSITE_ID || + !!config?.theme_customization?.help?.documentation_url; return (