mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-13 05:07:52 +02:00
🔥(frontend) remove Crisp from the project
Remove Crisp chat SDK, provider, analytics, session management and all related references across the codebase.
This commit is contained in:
@@ -20,6 +20,7 @@ and this project adheres to
|
||||
- ♿️(frontend) hide mobile left panel from screen readers when collapsed #2450
|
||||
- ♿️(frontend) enable blocknote heading ids for toc anchors #2449
|
||||
- ♿️(frontend) focus export modal on format select #2421
|
||||
- ♿️(frontend) configurable legal submenu in HelpMenu, remove Crisp #2416
|
||||
|
||||
## [v5.3.0] - 2026-06-19
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ These are the environment variables you can set for the `impress-backend` contai
|
||||
| CONVERSION_FILE_MAX_SIZE | The file max size allowed when uploaded to convert it | 20971520 (20MB) |
|
||||
| CONVERSION_FILE_EXTENSIONS_ALLOWED | Extension list managed by the conversion service | [".docx", ".md"] |
|
||||
| CONVERSION_UPLOAD_ENABLED | Enable or not the conversion feature. Without it the endpoint will fail and the logo in the front application will not appear | False |
|
||||
| CRISP_WEBSITE_ID | Crisp website id for support | |
|
||||
| DB_ENGINE | Engine to use for database connections | django.db.backends.postgresql_psycopg2 |
|
||||
| DB_HOST | Host of the database | localhost |
|
||||
| DB_NAME | Name of the database | impress |
|
||||
|
||||
@@ -3076,7 +3076,6 @@ class ConfigView(drf.views.APIView):
|
||||
"CONVERSION_FILE_EXTENSIONS_ALLOWED",
|
||||
"CONVERSION_FILE_MAX_SIZE",
|
||||
"CONVERSION_UPLOAD_ENABLED",
|
||||
"CRISP_WEBSITE_ID",
|
||||
"ENVIRONMENT",
|
||||
"FRONTEND_CSS_URL",
|
||||
"FRONTEND_HOMEPAGE_FEATURE_ENABLED",
|
||||
|
||||
@@ -28,7 +28,6 @@ pytestmark = pytest.mark.django_db
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY=True,
|
||||
COLLABORATION_WS_INACTIVITY_TIMEOUT=300,
|
||||
CONVERSION_UPLOAD_ENABLED=False,
|
||||
CRISP_WEBSITE_ID="123",
|
||||
FRONTEND_CSS_URL="http://testcss/",
|
||||
FRONTEND_JS_URL="http://testjs/",
|
||||
FRONTEND_THEME="test-theme",
|
||||
@@ -62,7 +61,6 @@ def test_api_config(is_authenticated):
|
||||
"CONVERSION_FILE_EXTENSIONS_ALLOWED": [".docx", ".md"],
|
||||
"CONVERSION_FILE_MAX_SIZE": 20971520,
|
||||
"CONVERSION_UPLOAD_ENABLED": False,
|
||||
"CRISP_WEBSITE_ID": "123",
|
||||
"ENVIRONMENT": "test",
|
||||
"FRONTEND_CSS_URL": "http://testcss/",
|
||||
"FRONTEND_HOMEPAGE_FEATURE_ENABLED": True,
|
||||
|
||||
@@ -569,11 +569,6 @@ class Base(Configuration):
|
||||
"https://eu.i.posthog.com", environ_name="POSTHOG_HOST", environ_prefix=None
|
||||
)
|
||||
|
||||
# Crisp
|
||||
CRISP_WEBSITE_ID = values.Value(
|
||||
None, environ_name="CRISP_WEBSITE_ID", environ_prefix=None
|
||||
)
|
||||
|
||||
# Easy thumbnails
|
||||
THUMBNAIL_EXTENSION = "webp"
|
||||
THUMBNAIL_TRANSPARENCY_EXTENSION = "webp"
|
||||
|
||||
@@ -80,61 +80,6 @@ test.describe('Help feature', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Support button', () => {
|
||||
if (process.env.IS_INSTANCE !== 'true') {
|
||||
test('is not displayed if CRISP_WEBSITE_ID is not set', async ({
|
||||
page,
|
||||
}) => {
|
||||
await overrideConfig(page, {
|
||||
CRISP_WEBSITE_ID: '',
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
await page.getByRole('button', { name: 'Open help menu' }).click();
|
||||
await expect(
|
||||
page.getByRole('menuitem', { name: 'Get Support' }),
|
||||
).toBeHidden();
|
||||
});
|
||||
|
||||
test('is displayed if CRISP_WEBSITE_ID is set', async ({ page }) => {
|
||||
await overrideConfig(page, {
|
||||
CRISP_WEBSITE_ID: 'test_website_id',
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
await page.getByRole('button', { name: 'Open help menu' }).click();
|
||||
await expect(
|
||||
page.getByRole('menuitem', {
|
||||
name: 'Get Support',
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env.IS_INSTANCE === 'true') {
|
||||
test('it displays Crisp chatbox', async ({ page }) => {
|
||||
const currentConfig = await getCurrentConfig(page);
|
||||
test.skip(
|
||||
!currentConfig.CRISP_WEBSITE_ID,
|
||||
'Crisp chatbox is not enabled',
|
||||
);
|
||||
await page.goto('/');
|
||||
|
||||
await page.getByRole('button', { name: 'Open help menu' }).click();
|
||||
await page
|
||||
.getByRole('menuitem', {
|
||||
name: 'Get Support',
|
||||
})
|
||||
.click();
|
||||
|
||||
const crispElement = page.locator('#crisp-chatbox');
|
||||
await expect(crispElement).toBeAttached();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('Legal submenu', () => {
|
||||
if (process.env.IS_INSTANCE !== 'true') {
|
||||
test('is not displayed if legal_links are not set', async ({ page }) => {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const CONFIG = {
|
||||
AI_FEATURE_BLOCKNOTE_ENABLED: false,
|
||||
AI_FEATURE_LEGACY_ENABLED: true,
|
||||
API_USERS_SEARCH_QUERY_MIN_LENGTH: 3,
|
||||
CRISP_WEBSITE_ID: null,
|
||||
COLLABORATION_WS_INACTIVITY_TIMEOUT: 15,
|
||||
COLLABORATION_WS_URL: process.env.COLLABORATION_WS_URL,
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY: true,
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
"canvg": "4.0.3",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"crisp-sdk-web": "1.1.2",
|
||||
"emoji-datasource-apple": "16.0.0",
|
||||
"emoji-mart": "5.6.0",
|
||||
"emoji-regex": "10.6.0",
|
||||
|
||||
@@ -77,16 +77,6 @@ export const ConfigProvider = ({ children }: PropsWithChildren) => {
|
||||
});
|
||||
}, [conf?.POSTHOG_KEY, conf?.POSTHOG_HOST]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!conf?.CRISP_WEBSITE_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
void import('@/services').then(({ CrispAnalytic }) => {
|
||||
new CrispAnalytic({ websiteId: conf.CRISP_WEBSITE_ID });
|
||||
});
|
||||
}, [conf?.CRISP_WEBSITE_ID]);
|
||||
|
||||
useEffect(() => {
|
||||
const frontendVersion = process.env.NEXT_PUBLIC_APP_VERSION;
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ export interface ConfigResponse {
|
||||
CONVERSION_FILE_EXTENSIONS_ALLOWED: string[];
|
||||
CONVERSION_FILE_MAX_SIZE: number;
|
||||
CONVERSION_UPLOAD_ENABLED?: boolean;
|
||||
CRISP_WEBSITE_ID?: string;
|
||||
ENVIRONMENT: string;
|
||||
FRONTEND_CSS_URL?: string;
|
||||
FRONTEND_HOMEPAGE_FEATURE_ENABLED?: boolean;
|
||||
|
||||
@@ -4,11 +4,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { SILENT_LOGIN_RETRY } from '../conf';
|
||||
import { gotoLogout, gotoSilentLogin } from '../utils';
|
||||
|
||||
// Mock the Crisp service
|
||||
vi.mock('@/services/Crisp', () => ({
|
||||
terminateCrispSession: vi.fn(),
|
||||
}));
|
||||
|
||||
// Add mock on window.location.replace
|
||||
const mockReplace = vi.fn();
|
||||
Object.defineProperty(window, 'location', {
|
||||
@@ -32,12 +27,9 @@ describe('utils', () => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('checks support session is terminated when logout', async () => {
|
||||
const { terminateCrispSession } = await import('@/services/Crisp');
|
||||
|
||||
it('checks logout redirects to logout URL', async () => {
|
||||
gotoLogout();
|
||||
|
||||
expect(terminateCrispSession).toHaveBeenCalled();
|
||||
expect(mockReplace).toHaveBeenCalledWith(
|
||||
'http://test.jest/api/v1.0/logout/',
|
||||
);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { terminateCrispSession } from '@/services/Crisp';
|
||||
import { safeLocalStorage, safeSessionStorage } from '@/utils/storages';
|
||||
|
||||
import {
|
||||
@@ -66,6 +65,5 @@ export const resetSilent = () => {
|
||||
};
|
||||
|
||||
export const gotoLogout = () => {
|
||||
terminateCrispSession();
|
||||
window.location.replace(LOGOUT_URL);
|
||||
};
|
||||
|
||||
@@ -8,15 +8,12 @@ import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { createGlobalStyle, css } from 'styled-components';
|
||||
|
||||
import BubbleTextIcon from '@/assets/icons/ui-kit/bubble-text.svg';
|
||||
import DocIcon from '@/assets/icons/ui-kit/doc.svg';
|
||||
import LegalIcon from '@/assets/icons/ui-kit/legal.svg';
|
||||
import HelpIcon from '@/assets/icons/ui-kit/question-mark.svg';
|
||||
import WandAndStarsIcon from '@/assets/icons/ui-kit/wand-and-stars.svg';
|
||||
import { Box } from '@/components';
|
||||
import { useConfig } from '@/core';
|
||||
import { openCrispChat } from '@/services';
|
||||
|
||||
import { OnBoarding } from './OnBoarding';
|
||||
|
||||
const HelpMenuStyle = createGlobalStyle`
|
||||
@@ -36,7 +33,6 @@ export const HelpMenu = ({
|
||||
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 legalLinks = config?.theme_customization?.help?.legal_links;
|
||||
|
||||
const toggleMenu = useCallback(() => {
|
||||
@@ -55,12 +51,6 @@ export const HelpMenu = ({
|
||||
|
||||
const options = useMemo<DropdownMenuItem[]>(
|
||||
() => [
|
||||
{
|
||||
label: t('Get Support'),
|
||||
icon: <BubbleTextIcon aria-hidden="true" width="24" height="24" />,
|
||||
callback: openCrispChat,
|
||||
isHidden: !crispEnabled,
|
||||
},
|
||||
{
|
||||
label: t('Documentation'),
|
||||
icon: <DocIcon aria-hidden="true" width="24" height="24" />,
|
||||
@@ -108,7 +98,6 @@ export const HelpMenu = ({
|
||||
],
|
||||
[
|
||||
t,
|
||||
crispEnabled,
|
||||
documentationUrl,
|
||||
modalOnbording.open,
|
||||
onboardingEnabled,
|
||||
|
||||
@@ -37,7 +37,6 @@ export const LeftPanelDesktop = () => {
|
||||
const { data: config } = useConfig();
|
||||
const showHelpMenu =
|
||||
config?.theme_customization?.onboarding?.enabled ||
|
||||
!!config?.CRISP_WEBSITE_ID ||
|
||||
!!config?.theme_customization?.help?.documentation_url ||
|
||||
!!config?.theme_customization?.help?.legal_links;
|
||||
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/**
|
||||
* Configure Crisp chat for real-time support across all pages.
|
||||
*/
|
||||
|
||||
import { ChatboxPosition, Crisp } from 'crisp-sdk-web';
|
||||
import { JSX, PropsWithChildren, ReactNode, useEffect, useState } from 'react';
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
|
||||
import { User } from '@/features/auth';
|
||||
import { AbstractAnalytic, AnalyticEvent } from '@/libs';
|
||||
|
||||
const CrispStyle = createGlobalStyle`
|
||||
#crisp-chatbox div[role="button"] {
|
||||
zoom: 0.7;
|
||||
right: auto !important;
|
||||
left: 24px !important;
|
||||
}
|
||||
|
||||
#crisp-chatbox div[data-chat-status="initial"] {
|
||||
bottom: 65px!important;
|
||||
left: 24px !important;
|
||||
margin-left: var(--crisp-customization-button-horizontal) !important;
|
||||
right: auto !important;
|
||||
}
|
||||
`;
|
||||
|
||||
export const initializeCrispSession = (user: User) => {
|
||||
if (!Crisp.isCrispInjected()) {
|
||||
return;
|
||||
}
|
||||
Crisp.setTokenId(`impress-${user.id}`);
|
||||
Crisp.user.setEmail(user.email);
|
||||
};
|
||||
|
||||
export const configureCrispSession = (websiteId: string) => {
|
||||
if (Crisp.isCrispInjected()) {
|
||||
return;
|
||||
}
|
||||
Crisp.configure(websiteId);
|
||||
Crisp.setSafeMode(true);
|
||||
Crisp.setPosition(ChatboxPosition.Left);
|
||||
Crisp.chat.hide();
|
||||
Crisp.chat.onChatClosed(() => {
|
||||
Crisp.chat.hide();
|
||||
});
|
||||
};
|
||||
|
||||
export const openCrispChat = () => {
|
||||
if (!Crisp.isCrispInjected()) {
|
||||
return;
|
||||
}
|
||||
Crisp.setPosition(ChatboxPosition.Left);
|
||||
Crisp.chat.show();
|
||||
setTimeout(() => {
|
||||
Crisp.chat.open();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
export const terminateCrispSession = () => {
|
||||
if (!Crisp.isCrispInjected()) {
|
||||
return;
|
||||
}
|
||||
Crisp.setTokenId();
|
||||
Crisp.session.reset();
|
||||
};
|
||||
|
||||
interface CrispProviderProps {
|
||||
websiteId?: string;
|
||||
}
|
||||
|
||||
export const CrispProvider = ({
|
||||
children,
|
||||
websiteId,
|
||||
}: PropsWithChildren<CrispProviderProps>) => {
|
||||
const [isConfigured, setIsConfigured] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!websiteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsConfigured(true);
|
||||
configureCrispSession(websiteId);
|
||||
}, [websiteId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isConfigured && <CrispStyle />}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export class CrispAnalytic extends AbstractAnalytic {
|
||||
private conf?: CrispProviderProps = undefined;
|
||||
private EVENT = {
|
||||
PUBLIC_DOC_NOT_CONNECTED: 'public-doc-not-connected',
|
||||
};
|
||||
|
||||
public constructor(conf?: CrispProviderProps) {
|
||||
super();
|
||||
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
public Provider(children?: ReactNode): JSX.Element {
|
||||
return (
|
||||
<CrispProvider websiteId={this.conf?.websiteId}>{children}</CrispProvider>
|
||||
);
|
||||
}
|
||||
|
||||
public trackEvent(evt: AnalyticEvent): void {
|
||||
if (evt.eventName === 'doc') {
|
||||
if (evt.isPublic && !evt.authenticated) {
|
||||
Crisp.trigger.run(this.EVENT.PUBLIC_DOC_NOT_CONNECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public isFeatureFlagActivated(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1 @@
|
||||
export * from './Crisp';
|
||||
export * from './PosthogAnalytic';
|
||||
|
||||
Reference in New Issue
Block a user