import { ActionIcon, Button, Flex, Group, Input, Stack, Text, TextInput } from "@mantine/core" import { useEffect, useState } from "react" import createReport, { listCommands } from 'docx-templates' import { Dropzone, DropzoneProps, IMAGE_MIME_TYPE, MS_WORD_MIME_TYPE } from '@mantine/dropzone' import { IconFile, IconFileTypeDocx, IconPhoto, IconPlus, IconUpload, IconX } from "@tabler/icons-react" import { CommandSummary } from "docx-templates/lib/types" import { Control, Controller, FieldValues, SubmitHandler, useFieldArray, useForm, UseFormRegister } from "react-hook-form" import { TemplateHandler } from 'easy-template-x' const xslTemplate = ` progid="Excel.Sheet" Регион Нас. пункт Котельная Адрес Кол-во домов Этаж. Общая пл. Кол-во прожив. Отопление ГВС ХВС Канализация Сальдо исход. Объем Сумма Объем Сумма Объем Сумма Объем Сумма
2 2 2
Регион Нас. пункт Котельная Наименование Кол-во объектов Объем здания Отопление Подогрев ГВС ХВС Канализация Итого Объем Сумма Объем Сумма Объем Сумма Объем Сумма Объем Сумма
` const handleGenerateExcel = () => { // Define the example XML data const xmlData = ` 1 Region 1 City 1 10 1000 500 200 1000 300 1500 400 2000 500 2500 300 ` // Parse the XSL template and XML data const parser = new DOMParser() const xslDoc = parser.parseFromString(xslTemplate, "application/xml") const xmlDoc = parser.parseFromString(xmlData, "application/xml") // Apply the transformation const xsltProcessor = new XSLTProcessor() xsltProcessor.importStylesheet(xslDoc) const resultDocument = xsltProcessor.transformToDocument(xmlDoc) // Serialize the result to a string const serializer = new XMLSerializer() const resultXml = serializer.serializeToString(resultDocument) // Add missing Excel-specific headers if needed const correctedXml = `\n` + resultXml // Convert to Blob and trigger download const blob = new Blob([correctedXml], { type: "application/vnd.ms-excel" }) const url = URL.createObjectURL(blob) const link = document.createElement("a") link.href = url link.download = "template.xls" link.click() URL.revokeObjectURL(url) } const TemplateFormET = ({ templateUrl }: { templateUrl: string }) => { const [templateUint8Array, setTemplateUint8Array] = useState(null) const [loading, setLoading] = useState(false) const loadTemplate = async (templateUrl: string) => { setLoading(true) try { const response = await fetch(templateUrl) const templateArrayBuffer = await response.arrayBuffer() setTemplateUint8Array(new Uint8Array(templateArrayBuffer)) } catch (error) { console.error("Error generating DOCX:", error) } finally { setLoading(false) } } const loadTags = async (templateUint8Array: Uint8Array) => { const handler = new TemplateHandler() const tags = await handler.parseTags(templateUint8Array) console.log(tags) } useEffect(() => { if (templateUint8Array) { loadTags(templateUint8Array) } }, [templateUint8Array]) useEffect(() => { if (templateUrl) { loadTemplate(templateUrl) } }, [templateUrl]) return (
) } interface TemplateCommand extends CommandSummary { children?: CommandSummary[] } export function parseCommandList(commands: CommandSummary[]): TemplateCommand[] { function parseBlock(startIndex: number, currentElement?: string): [TemplateCommand[], number] { const block: TemplateCommand[] = [] let i = startIndex while (i < commands.length) { const command = commands[i] if (command.type === "FOR") { const [elementName, , arrayName] = command.code.split(" ") const forCommand: TemplateCommand = { raw: command.raw, type: command.type, code: arrayName, children: [], } const [children, nextIndex] = parseBlock(i + 1, elementName) forCommand.children = children i = nextIndex block.push(forCommand) } else if (command.type === "END-FOR") { return [block, i + 1] } else { let code = command.code if (currentElement && (code.startsWith(`${currentElement}.`) || code.startsWith(`$${currentElement}.`))) { code = code.replace(`$${currentElement}.`, "").replace(`${currentElement}.`, "") } block.push({ ...command, code, }) i++ } } return [block, i] } const [parsed] = parseBlock(0) return parsed } const FormLoop = ({ control, register, command, }: { control: Control, register: UseFormRegister, command: TemplateCommand, }) => { const { fields, append, remove } = useFieldArray({ name: command.code, control }) return ( { fields.map((field, index) => ( {command.children && command.children.map(c => renderCommand( control, register, c, `${c.code}`, `${command.code}.${index}.${c.code}`, `${command.code}.${index}.${c.code}` ) )} )) } { if (command.children) { append(command.children.map(c => c.code).reduce((acc, key) => { acc[key] = ''; return acc; }, {} as Record)) } }}> ) } const renderCommand = ( control: Control, register: UseFormRegister, command: CommandSummary, label: string, key: string, name: string, ) => { if (command.type === 'INS') { return ( ) } if (command.type === 'IMAGE') { return ( ( console.log('rejected files', files)} onDrop={(files) => { console.log(files[0]) files[0].arrayBuffer().then(res => { onChange({ width: 6, height: 6, data: new Uint8Array(res), extension: files[0]?.path?.match(/\.[^.]+$/)?.[0] || "" }) }) }} maxFiles={1} >
Drag files here or click to select files Attach as many files as you like, each file should not exceed 5mb
)} /> ) } } const TemplateForm = ({ templateUrl, }: { templateUrl: string, }) => { const { register, control, handleSubmit, reset, watch, formState } = useForm({ mode: 'onChange', }) const [loading, setLoading] = useState(false) const [saving, setSaving] = useState(false) const [templateUint8Array, setTemplateUint8Array] = useState(null) const [commandList, setCommandList] = useState([]) const saveTest = async (templateUint8Array: Uint8Array, data: any) => { setSaving(true) try { // Generate the DOCX file with the replacement const report = await createReport({ template: templateUint8Array, // Ensure it's Uint8Array data: data, }) // Convert Uint8Array to a Blob const blob = new Blob([report], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", }) // Create a download link and trigger the download const url = URL.createObjectURL(blob) const a = document.createElement("a") a.href = url a.download = "report.docx" document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) } catch (error) { console.error("Error generating DOCX:", error) } finally { setSaving(false) } } const loadTemplate = async () => { setLoading(true) try { const response = await fetch(templateUrl) const templateArrayBuffer = await response.arrayBuffer() setTemplateUint8Array(new Uint8Array(templateArrayBuffer)) } catch (error) { console.error("Error generating DOCX:", error) } finally { setLoading(false) } } const loadCommands = async (templateUint8Array: Uint8Array) => { try { await listCommands(templateUint8Array).then(l => { setCommandList(parseCommandList(l)) }) } catch (error) { console.error("Error loading commands from DOCX:", error) } } useEffect(() => { if (templateUint8Array) { loadCommands(templateUint8Array) } }, [templateUint8Array]) const onSubmit: SubmitHandler = async (data) => { try { if (templateUint8Array && data) { saveTest(templateUint8Array, data) } } catch (error) { console.error(error) } } useEffect(() => { if (templateUrl) { loadTemplate() } }, [templateUrl]) if (commandList) { return (
{commandList.map(command => { if (command.type === 'FOR') { return ( ) } else { return renderCommand(control, register, command, command.code, command.code, command.code) } })}
) } } const PrintReport = () => { const [loading, setLoading] = useState(false) return ( ) } export default PrintReport