✨(app-impress) select template on pad
We add a template select component to the pad toolbox. This component is a dropdown that allows the user to select a template for the pad to add in a PDF.
This commit is contained in:
@@ -2,7 +2,7 @@ import { expect, test } from '@playwright/test';
|
|||||||
import cs from 'convert-stream';
|
import cs from 'convert-stream';
|
||||||
import pdf from 'pdf-parse';
|
import pdf from 'pdf-parse';
|
||||||
|
|
||||||
import { createPad, keyCloakSignIn } from './common';
|
import { createPad, createTemplate, keyCloakSignIn } from './common';
|
||||||
|
|
||||||
test.beforeEach(async ({ page, browserName }) => {
|
test.beforeEach(async ({ page, browserName }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
@@ -51,33 +51,6 @@ test.describe('Pad Editor', () => {
|
|||||||
expect(typeCases.includes(payload.type)).toBeTruthy();
|
expect(typeCases.includes(payload.type)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it converts the pad to pdf with a template integrated', async ({
|
|
||||||
page,
|
|
||||||
browserName,
|
|
||||||
}) => {
|
|
||||||
const downloadPromise = page.waitForEvent('download', (download) => {
|
|
||||||
return download.suggestedFilename().includes('impress-document.pdf');
|
|
||||||
});
|
|
||||||
|
|
||||||
const randomPad = await createPad(page, 'pad-editor', browserName, 1);
|
|
||||||
await expect(page.locator('h2').getByText(randomPad[0])).toBeVisible();
|
|
||||||
|
|
||||||
await page.locator('.ProseMirror.bn-editor').click();
|
|
||||||
await page.locator('.ProseMirror.bn-editor').fill('Hello World');
|
|
||||||
|
|
||||||
await page.getByText('Print the pad').first().click();
|
|
||||||
|
|
||||||
const download = await downloadPromise;
|
|
||||||
expect(download.suggestedFilename()).toBe('impress-document.pdf');
|
|
||||||
|
|
||||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
|
||||||
const pdfText = (await pdf(pdfBuffer)).text;
|
|
||||||
|
|
||||||
expect(pdfText).toContain('Monsieur le Premier Ministre'); // This is the template text
|
|
||||||
expect(pdfText).toContain('La directrice'); // This is the template text
|
|
||||||
expect(pdfText).toContain('Hello World'); // This is the pad text
|
|
||||||
});
|
|
||||||
|
|
||||||
test('markdown button converts from markdown to the editor syntax json', async ({
|
test('markdown button converts from markdown to the editor syntax json', async ({
|
||||||
page,
|
page,
|
||||||
browserName,
|
browserName,
|
||||||
@@ -103,4 +76,62 @@ test.describe('Pad Editor', () => {
|
|||||||
}),
|
}),
|
||||||
).toHaveAttribute('href', 'http://test-markdown.html');
|
).toHaveAttribute('href', 'http://test-markdown.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it converts the pad to pdf with a template created', async ({
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
}) => {
|
||||||
|
// eslint-disable-next-line playwright/no-skipped-test
|
||||||
|
test.skip(
|
||||||
|
browserName !== 'chromium',
|
||||||
|
'This test failed with safary because of the dragNdrop',
|
||||||
|
);
|
||||||
|
|
||||||
|
const downloadPromise = page.waitForEvent('download', (download) => {
|
||||||
|
return download.suggestedFilename().includes('impress-document.pdf');
|
||||||
|
});
|
||||||
|
|
||||||
|
const templates = await createTemplate(
|
||||||
|
page,
|
||||||
|
'template-pad',
|
||||||
|
browserName,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
const iframe = page.frameLocator('iFrame.gjs-frame');
|
||||||
|
await page.getByTitle('Open Blocks').click();
|
||||||
|
await page
|
||||||
|
.locator('.gjs-editor .gjs-block[title="Text"]')
|
||||||
|
.dragTo(iframe.locator('body.gjs-dashed'));
|
||||||
|
|
||||||
|
await iframe
|
||||||
|
.getByText('Insert your text here')
|
||||||
|
.fill('My template ! {{body}}');
|
||||||
|
await iframe.locator('body.gjs-dashed').click();
|
||||||
|
|
||||||
|
await page.getByText('Save template').click();
|
||||||
|
|
||||||
|
const menu = page.locator('menu').first();
|
||||||
|
await menu.getByLabel(`Search button`).click();
|
||||||
|
|
||||||
|
const randomPad = await createPad(page, 'pad-editor', browserName, 1);
|
||||||
|
await expect(page.locator('h2').getByText(randomPad[0])).toBeVisible();
|
||||||
|
|
||||||
|
await page.locator('.ProseMirror.bn-editor').click();
|
||||||
|
await page.locator('.ProseMirror.bn-editor').fill('And my pad !');
|
||||||
|
|
||||||
|
await page.getByRole('combobox', { name: 'Template' }).click();
|
||||||
|
await page.getByRole('option', { name: templates[0] }).click();
|
||||||
|
|
||||||
|
await page.getByText('Generate PDF').first().click();
|
||||||
|
|
||||||
|
const download = await downloadPromise;
|
||||||
|
expect(download.suggestedFilename()).toBe('impress-document.pdf');
|
||||||
|
|
||||||
|
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||||
|
const pdfText = (await pdf(pdfBuffer)).text;
|
||||||
|
|
||||||
|
expect(pdfText).toContain('My template !');
|
||||||
|
expect(pdfText).toContain('And my pad !');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import React from 'react';
|
import { Select } from '@openfun/cunningham-react';
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Box } from '@/components';
|
import { Box } from '@/components';
|
||||||
import { Pad } from '@/features/pads/pad';
|
import { Pad } from '@/features/pads/pad';
|
||||||
|
import { TemplatesOrdering, useTemplates } from '@/features/templates';
|
||||||
|
|
||||||
import PrintToPDFButton from './PrintToPDFButton';
|
import PrintToPDFButton from './PrintToPDFButton';
|
||||||
|
|
||||||
@@ -10,9 +13,53 @@ interface PadToolBoxProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const PadToolBox = ({ pad }: PadToolBoxProps) => {
|
export const PadToolBox = ({ pad }: PadToolBoxProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { data: templates } = useTemplates({
|
||||||
|
ordering: TemplatesOrdering.BY_CREATED_ON_DESC,
|
||||||
|
});
|
||||||
|
const [templateIdSelected, setTemplateIdSelected] = useState<string>();
|
||||||
|
|
||||||
|
const templateOptions = useMemo(() => {
|
||||||
|
if (!templates?.pages) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateOptions = templates.pages
|
||||||
|
.map((page) =>
|
||||||
|
page.results.map((template) => ({
|
||||||
|
label: template.title,
|
||||||
|
value: template.id,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
if (templateOptions.length) {
|
||||||
|
setTemplateIdSelected(templateOptions[0].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return templateOptions;
|
||||||
|
}, [templates?.pages]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="m-b" $align="flex-end">
|
<Box
|
||||||
<PrintToPDFButton pad={pad} />
|
className="m-b"
|
||||||
|
$align="center"
|
||||||
|
$direction="row"
|
||||||
|
$gap="1rem"
|
||||||
|
$justify="flex-end"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
clearable={false}
|
||||||
|
label={t('Template')}
|
||||||
|
options={templateOptions}
|
||||||
|
value={templateIdSelected}
|
||||||
|
onChange={(options) =>
|
||||||
|
setTemplateIdSelected(options.target.value as string)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{templateIdSelected && (
|
||||||
|
<PrintToPDFButton pad={pad} templateId={templateIdSelected} />
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Pad, usePadStore } from '@/features/pads/pad';
|
import { Pad, usePadStore } from '@/features/pads/pad';
|
||||||
|
import { Template } from '@/features/templates/template';
|
||||||
|
|
||||||
import { useCreatePdf } from '../api/useCreatePdf';
|
import { useCreatePdf } from '../api/useCreatePdf';
|
||||||
import { downloadFile } from '../utils';
|
import { downloadFile } from '../utils';
|
||||||
|
|
||||||
interface PrintToPDFButtonProps {
|
interface PrintToPDFButtonProps {
|
||||||
pad: Pad;
|
pad: Pad;
|
||||||
|
templateId: Template['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const PrintToPDFButton = ({ pad }: PrintToPDFButtonProps) => {
|
const PrintToPDFButton = ({ pad, templateId }: PrintToPDFButtonProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isFetching, setIsFetching] = useState(false);
|
const [isFetching, setIsFetching] = useState(false);
|
||||||
const { toast } = useToastProvider();
|
const { toast } = useToastProvider();
|
||||||
@@ -64,7 +66,7 @@ const PrintToPDFButton = ({ pad }: PrintToPDFButtonProps) => {
|
|||||||
const body = await editor.blocksToHTMLLossy(editor.document);
|
const body = await editor.blocksToHTMLLossy(editor.document);
|
||||||
|
|
||||||
createPdf({
|
createPdf({
|
||||||
templateId: '472d0633-20b8-4cb1-998a-1134ade092ba',
|
templateId,
|
||||||
body,
|
body,
|
||||||
body_type: 'markdown',
|
body_type: 'markdown',
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user