diff --git a/src/frontend/apps/e2e/__tests__/app-impress/common.ts b/src/frontend/apps/e2e/__tests__/app-impress/common.ts
index 542638cc..0aea93c5 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/common.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/common.ts
@@ -45,6 +45,35 @@ export const createPad = async (
return randomPads;
};
+export const createTemplate = async (
+ page: Page,
+ templateName: string,
+ browserName: string,
+ length: number,
+) => {
+ const menu = page.locator('menu').first();
+ await menu.getByLabel(`Template button`).click();
+
+ const panel = page.getByLabel('Templates panel').first();
+ const buttonCreate = page.getByRole('button', {
+ name: 'Create the template',
+ });
+
+ const randomTemplates = randomName(templateName, browserName, length);
+
+ for (let i = 0; i < randomTemplates.length; i++) {
+ await panel.getByRole('button', { name: 'Add a template' }).click();
+ await page.getByText('Template name').fill(randomTemplates[i]);
+ await expect(buttonCreate).toBeEnabled();
+ await buttonCreate.click();
+ await expect(
+ panel.locator('li').getByText(randomTemplates[i]),
+ ).toBeVisible();
+ }
+
+ return randomTemplates;
+};
+
export const addNewMember = async (
page: Page,
index: number,
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/menu.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/menu.spec.ts
index 4bd73852..1eafa55a 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/menu.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/menu.spec.ts
@@ -10,6 +10,7 @@ test.beforeEach(async ({ page, browserName }) => {
test.describe('Menu', () => {
const menuItems = [
{ name: 'Search', isDefault: true },
+ { name: 'Template', isDefault: false },
{ name: 'Favorite', isDefault: false },
{ name: 'Recent', isDefault: false },
{ name: 'Contacts', isDefault: false },
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/template-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/template-editor.spec.ts
new file mode 100644
index 00000000..e8ea725a
--- /dev/null
+++ b/src/frontend/apps/e2e/__tests__/app-impress/template-editor.spec.ts
@@ -0,0 +1,29 @@
+import { expect, test } from '@playwright/test';
+
+import { createTemplate, keyCloakSignIn } from './common';
+
+test.beforeEach(async ({ page, browserName }) => {
+ await page.goto('/');
+ await keyCloakSignIn(page, browserName);
+});
+
+test.describe('Template Editor', () => {
+ test('checks the template editor interact correctly', async ({
+ page,
+ browserName,
+ }) => {
+ const randomTemplate = await createTemplate(
+ page,
+ 'template-editor',
+ browserName,
+ 1,
+ );
+
+ await expect(page.locator('h2').getByText(randomTemplate[0])).toBeVisible();
+
+ await page.getByTitle('Open Blocks').click();
+ await expect(
+ page.locator('.gjs-editor .gjs-block[title="Text"]'),
+ ).toBeVisible();
+ });
+});
diff --git a/src/frontend/apps/impress/package.json b/src/frontend/apps/impress/package.json
index a8d9eb9d..70951af3 100644
--- a/src/frontend/apps/impress/package.json
+++ b/src/frontend/apps/impress/package.json
@@ -19,6 +19,7 @@
"@blocknote/react": "0.12.4",
"@openfun/cunningham-react": "2.7.0",
"@tanstack/react-query": "5.28.14",
+ "grapesjs-blocks-basic": "1.0.2",
"i18next": "23.10.1",
"lodash": "4.17.21",
"luxon": "3.4.4",
@@ -34,6 +35,7 @@
"zustand": "4.5.2"
},
"devDependencies": {
+ "@grapesjs/react": "1.0.0",
"@svgr/webpack": "8.1.0",
"@tanstack/react-query-devtools": "5.28.14",
"@testing-library/jest-dom": "6.4.2",
@@ -48,6 +50,7 @@
"dotenv": "16.4.5",
"eslint-config-impress": "*",
"fetch-mock": "9.11.0",
+ "grapesjs": "0.21.10",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"node-fetch": "2.7.0",
diff --git a/src/frontend/apps/impress/src/features/templates/template/components/TemplateEditor.tsx b/src/frontend/apps/impress/src/features/templates/template/components/TemplateEditor.tsx
new file mode 100644
index 00000000..22277202
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/templates/template/components/TemplateEditor.tsx
@@ -0,0 +1,35 @@
+import GjsEditor from '@grapesjs/react';
+import grapesjs, { Editor, ProjectData } from 'grapesjs';
+import 'grapesjs/dist/css/grapes.min.css';
+import pluginBlocksBasic from 'grapesjs-blocks-basic';
+
+import { Card, Text } from '@/components';
+
+import { useUpdateTemplateCodeEditor } from '../api/useUpdateTemplateCodeEditor';
+import { Template } from '../types';
+
+interface TemplateEditorProps {
+ template: Template;
+}
+
+export const TemplateEditor = ({ template }: TemplateEditorProps) => {
+ const onEditor = (editor: Editor) => {};
+
+ return (
+ <>
+
+ {template.title}
+
+
+ pluginBlocksBasic(editor, {})]}
+ onEditor={onEditor}
+ />
+
+ >
+ );
+};
diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock
index 292c72e1..ecd89d01 100644
--- a/src/frontend/yarn.lock
+++ b/src/frontend/yarn.lock
@@ -1485,6 +1485,11 @@
dependencies:
tslib "^2.4.0"
+"@grapesjs/react@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@grapesjs/react/-/react-1.0.0.tgz#bfa938128db7b69ca1c23439b66decf4eaa0ca9a"
+ integrity sha512-HHttzxwgvhbxQqqsiiQzb+OJtKFl8yWI9Yp3IgPgiKXqwY19lEJWSkCukvfqxugbYRxi0M1uERLAt209AmY5vQ==
+
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
@@ -3428,6 +3433,14 @@
dependencies:
"@babel/types" "^7.20.7"
+"@types/backbone@^1.4.15":
+ version "1.4.19"
+ resolved "https://registry.yarnpkg.com/@types/backbone/-/backbone-1.4.19.tgz#f6e8406fed40ca3fe224f6e59115142b62be76d6"
+ integrity sha512-byyn236JymGByOajKA7mi1k+/jKn162TIvArOB4SHgOGbVlFj8CSfJH4jekP0qo0vJwW5khrrsiiO1Jsos6ZvA==
+ dependencies:
+ "@types/jquery" "*"
+ "@types/underscore" "*"
+
"@types/debug@^4.0.0":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@@ -3488,6 +3501,13 @@
expect "^29.0.0"
pretty-format "^29.0.0"
+"@types/jquery@*":
+ version "3.5.29"
+ resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.29.tgz#3c06a1f519cd5fc3a7a108971436c00685b5dcea"
+ integrity sha512-oXQQC9X9MOPRrMhPHHOsXqeQDnWeCDT3PelUIg/Oy8FAbzSZtFHRjc7IpbfFVmpLtJ+UOoywpRsuO5Jxjybyeg==
+ dependencies:
+ "@types/sizzle" "*"
+
"@types/jsdom@^20.0.0":
version "20.0.1"
resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.1.tgz#07c14bc19bd2f918c1929541cdaacae894744808"
@@ -3588,6 +3608,11 @@
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
+"@types/sizzle@*":
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.8.tgz#518609aefb797da19bf222feb199e8f653ff7627"
+ integrity sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==
+
"@types/stack-utils@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
@@ -3608,6 +3633,11 @@
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304"
integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==
+"@types/underscore@*":
+ version "1.11.15"
+ resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.11.15.tgz#29c776daecf6f1935da9adda17509686bf979947"
+ integrity sha512-HP38xE+GuWGlbSRq9WrZkousaQ7dragtZCruBVMi0oX1migFZavZ3OROKHSkNp/9ouq82zrWtZpg18jFnVN96g==
+
"@types/unist@*", "@types/unist@^3.0.0":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20"
@@ -4202,6 +4232,28 @@ babel-preset-jest@^29.6.3:
babel-plugin-jest-hoist "^29.6.3"
babel-preset-current-node-syntax "^1.0.0"
+backbone-undo@^0.2.5:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/backbone-undo/-/backbone-undo-0.2.6.tgz#00c4d78ab2425c18a76f2a96a1eee181560a5d8d"
+ integrity sha512-AsfpNiljLXlk7TcffDUu3EAUq7CxWbyTNwARWrql5XTzN4vh6WzEEBZYaKK4kTTz+iW1tSzqUooaGRIwO83kWA==
+ dependencies:
+ backbone ">=1.0.0"
+ underscore ">=1.4.4"
+
+backbone@1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.4.1.tgz#099a78184bc07b034048a8332229c2ccca1e3e62"
+ integrity sha512-ADy1ztN074YkWbHi8ojJVFe3vAanO/lrzMGZWUClIP7oDD/Pjy2vrASraUP+2EVCfIiTtCW4FChVow01XneivA==
+ dependencies:
+ underscore ">=1.8.3"
+
+backbone@>=1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.6.0.tgz#5cdfa25257819b223109a77a74dde26d38995930"
+ integrity sha512-13PUjmsgw/49EowNcQvfG4gmczz1ximTMhUktj0Jfrjth0MVaTxehpU+qYYX4MxnuIuhmvBLC6/ayxuAGnOhbA==
+ dependencies:
+ underscore ">=1.8.3"
+
bail@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d"
@@ -4539,6 +4591,16 @@ co@^4.6.0:
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+codemirror-formatting@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/codemirror-formatting/-/codemirror-formatting-1.0.0.tgz#879cc1fdd9018343c1d5511769ce5360d705ebf2"
+ integrity sha512-br9yM6eJI3pJHekEnoyHaBEb1B7XxxDjju+vRyBe8QGLp5saTIXXkZ+eFCTqXSAtI8QEZDFVEX2/SOjH2sVWRQ==
+
+codemirror@^5.63.0:
+ version "5.65.16"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.16.tgz#efc0661be6bf4988a6a1c2fe6893294638cdb334"
+ integrity sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==
+
collect-v8-coverage@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9"
@@ -6094,6 +6156,24 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0,
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+grapesjs-blocks-basic@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/grapesjs-blocks-basic/-/grapesjs-blocks-basic-1.0.2.tgz#d7e4cc44a2ad1f41d6622ca337668e3fd5945191"
+ integrity sha512-SsPKf/CvQkZ+kABOsN01auAPHXh/2J20g0AWYF7fHR3Gw3TZLtdIxT1mk90Qzi76u/7sUYi3CTI+i3ZaTtXHRA==
+
+grapesjs@0.21.10:
+ version "0.21.10"
+ resolved "https://registry.yarnpkg.com/grapesjs/-/grapesjs-0.21.10.tgz#f64c7eeac17412555b523249f80ae0ce3297a9c0"
+ integrity sha512-wvOBa8kjBLDeH006p4/krSzGNze2H7Rsncv37LxvDzC6QCQucEjQ7Lb+Fd50jDSWNnxavRRJLJPnXyPTGZYGuQ==
+ dependencies:
+ "@types/backbone" "^1.4.15"
+ backbone "1.4.1"
+ backbone-undo "^0.2.5"
+ codemirror "^5.63.0"
+ codemirror-formatting "^1.0.0"
+ promise-polyfill "^8.1.3"
+ underscore "^1.13.1"
+
graphemer@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
@@ -8730,6 +8810,11 @@ promise-map-series@^0.3.0:
resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.3.0.tgz#41873ca3652bb7a042b387d538552da9b576f8a1"
integrity sha512-3npG2NGhTc8BWBolLLf8l/92OxMGaRLbqvIh9wjCHhDXNvk4zsxaTaCpiCunW09qWPrN2zeNSNwRLVBrQQtutA==
+promise-polyfill@^8.1.3:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63"
+ integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==
+
prompts@^2.0.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
@@ -10424,6 +10509,11 @@ underscore.string@~3.3.4:
sprintf-js "^1.1.1"
util-deprecate "^1.0.2"
+underscore@>=1.4.4, underscore@>=1.8.3, underscore@^1.13.1:
+ version "1.13.6"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441"
+ integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==
+
undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"