✨(app-impress) print to pdf
Feature to print the pad to pdf. It display a button in the pad toolbar, when clicked it will convert the pad to markdown, send the markdown with a template to the backend to convert it to pdf and then download the pdf.
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Box } from '@/components';
|
||||||
|
import { Pad } from '@/features/pads/pad';
|
||||||
|
|
||||||
|
import PrintToPDFButton from './PrintToPDFButton';
|
||||||
|
|
||||||
|
interface PadToolBoxProps {
|
||||||
|
pad: Pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PadToolBox = ({ pad }: PadToolBoxProps) => {
|
||||||
|
return (
|
||||||
|
<Box className="m-b" $align="flex-end">
|
||||||
|
<PrintToPDFButton pad={pad} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
VariantType,
|
||||||
|
useToastProvider,
|
||||||
|
} from '@openfun/cunningham-react';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Pad, usePadStore } from '@/features/pads/pad';
|
||||||
|
|
||||||
|
import { useCreatePdfFromMarkdown } from '../api/useCreatePdfFromMarkdown';
|
||||||
|
import { downloadFile } from '../utils';
|
||||||
|
|
||||||
|
interface PrintToPDFButtonProps {
|
||||||
|
pad: Pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PrintToPDFButton = ({ pad }: PrintToPDFButtonProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [isFetching, setIsFetching] = useState(false);
|
||||||
|
const { toast } = useToastProvider();
|
||||||
|
const { padsStore } = usePadStore();
|
||||||
|
const {
|
||||||
|
mutate: createPdfFromMarkdown,
|
||||||
|
data: pdf,
|
||||||
|
isSuccess,
|
||||||
|
isPending,
|
||||||
|
error,
|
||||||
|
} = useCreatePdfFromMarkdown();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsFetching(isPending);
|
||||||
|
}, [isPending]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast(error.message, VariantType.ERROR);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [error, t]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!pdf || !isSuccess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadFile(pdf, 'impress-document.pdf');
|
||||||
|
setIsFetching(false);
|
||||||
|
|
||||||
|
toast(t('Your pdf was downloaded succesfully'), VariantType.SUCCESS);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [pdf, isSuccess, t]);
|
||||||
|
|
||||||
|
async function onSubmit() {
|
||||||
|
const editor = padsStore[pad.id].editor;
|
||||||
|
|
||||||
|
if (!editor) {
|
||||||
|
toast(t('No editor found'), VariantType.ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const markdown = await editor.blocksToMarkdownLossy(editor.document);
|
||||||
|
|
||||||
|
createPdfFromMarkdown({
|
||||||
|
templateId: '472d0633-20b8-4cb1-998a-1134ade092ba',
|
||||||
|
markdown,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onClick={() => void onSubmit()}
|
||||||
|
style={{
|
||||||
|
width: 'fit-content',
|
||||||
|
}}
|
||||||
|
disabled={isFetching}
|
||||||
|
>
|
||||||
|
{t('Print the pad')}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PrintToPDFButton;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './PadToolBox';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './components/';
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export function downloadFile(blob: Blob, filename: string) {
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.style.display = 'none';
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
|
|
||||||
import { Card, Text } from '@/components';
|
import { Card, Text } from '@/components';
|
||||||
|
|
||||||
|
import { PadToolBox } from '../../pad-tools';
|
||||||
import { Pad } from '../types';
|
import { Pad } from '../types';
|
||||||
|
|
||||||
import { BlockNoteEditor } from './BlockNoteEditor';
|
import { BlockNoteEditor } from './BlockNoteEditor';
|
||||||
@@ -12,9 +13,14 @@ interface PadEditorProps {
|
|||||||
|
|
||||||
export const PadEditor = ({ pad }: PadEditorProps) => {
|
export const PadEditor = ({ pad }: PadEditorProps) => {
|
||||||
return (
|
return (
|
||||||
<Card className="m-b p-b" $height="100%">
|
<>
|
||||||
<Text as="h2">{pad.name}</Text>
|
<PadToolBox pad={pad} />
|
||||||
<BlockNoteEditor pad={pad} />
|
<Card className="m-b p-b" $css="margin-top:0;flex:1;" $overflow="auto">
|
||||||
</Card>
|
<Text as="h2" $align="center">
|
||||||
|
{pad.name}
|
||||||
|
</Text>
|
||||||
|
<BlockNoteEditor pad={pad} />
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user