datastake-daf 0.6.463 → 0.6.464

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26579,8 +26579,8 @@ function DataLinkFlat$1({
26579
26579
  return (dataLinkFormData || []).map(d => {
26580
26580
  const dataLinkData = d[dataLinkKey];
26581
26581
  return {
26582
- ...dataLinkData,
26583
26582
  ...d,
26583
+ ...dataLinkData,
26584
26584
  dataLinkKey: undefined
26585
26585
  };
26586
26586
  });
@@ -42895,15 +42895,6 @@ const checkCondition = (condition, repeatValues, formsValue) => {
42895
42895
  };
42896
42896
  function showHideInput(input, formsValue, repeatIndex, repeatValues, setValues, ref) {
42897
42897
  if (input?.meta?.hidden === true) {
42898
- // Set default value for hidden fields
42899
- if (input?.meta?.defaultValue !== undefined && !propHasValue(formsValue[ref])) {
42900
- formsValue[ref] = input.meta.defaultValue;
42901
- if (setValues && typeof setValues === 'function') {
42902
- setValues({
42903
- ...formsValue
42904
- });
42905
- }
42906
- }
42907
42898
  return false;
42908
42899
  }
42909
42900
  if (input.showIf) {
@@ -45390,34 +45381,6 @@ function DynamicForm(_ref) {
45390
45381
  // MainForm.resetFields();
45391
45382
  }
45392
45383
  }, [data]);
45393
-
45394
- // Initialize default values for hidden fields
45395
- React.useEffect(() => {
45396
- if (Object.keys(form).length > 0) {
45397
- const updatedValues = _objectSpread2({}, values);
45398
- let hasChanges = false;
45399
-
45400
- // Process all form fields to set default values for hidden fields
45401
- Object.keys(form).forEach(formKey => {
45402
- Object.keys(form[formKey]).forEach(fieldKey => {
45403
- var _field$meta, _field$meta2;
45404
- const field = form[formKey][fieldKey];
45405
- if ((field === null || field === void 0 || (_field$meta = field.meta) === null || _field$meta === void 0 ? void 0 : _field$meta.hidden) === true && (field === null || field === void 0 || (_field$meta2 = field.meta) === null || _field$meta2 === void 0 ? void 0 : _field$meta2.defaultValue) !== undefined) {
45406
- const fieldId = field.dataId || fieldKey;
45407
- if (!propHasValue(updatedValues[fieldId])) {
45408
- updatedValues[fieldId] = field.meta.defaultValue;
45409
- hasChanges = true;
45410
- }
45411
- }
45412
- });
45413
- });
45414
- if (hasChanges) {
45415
- setValues(updatedValues);
45416
- // Also set the values in the Ant Design form
45417
- MainForm.setFieldsValue(updatedValues);
45418
- }
45419
- }
45420
- }, [form]);
45421
45384
  const setSelectedForm = id => {
45422
45385
  setForms(Forms.map(form => {
45423
45386
  id === form.id ? form.selected = true : form.selected = false;
@@ -45454,7 +45417,7 @@ function DynamicForm(_ref) {
45454
45417
  }).every(key => key);
45455
45418
  };
45456
45419
  const getData = (name, input, value, commentValue, path, disabledPath) => {
45457
- var _input$meta, _input$meta2, _input$meta3, _input$meta4, _input$meta5, _input$meta6, _input$meta7, _input$meta8, _input$meta9, _input$meta10, _input$meta11, _input$meta12;
45420
+ var _input$meta, _input$meta2, _input$meta3, _input$meta4, _input$meta5, _input$meta6, _input$meta7, _input$meta8, _input$meta9, _input$meta10;
45458
45421
  const props = {
45459
45422
  // placeholder: input.labelHint ? input.labelHint : getInputLabel(input, values, true),
45460
45423
  placeholder: input.labelHint,
@@ -45491,17 +45454,9 @@ function DynamicForm(_ref) {
45491
45454
  }
45492
45455
  value = fileList;
45493
45456
  }
45494
-
45495
- // Handle default values for hidden fields
45496
- if ((input === null || input === void 0 || (_input$meta7 = input.meta) === null || _input$meta7 === void 0 ? void 0 : _input$meta7.hidden) === true && (input === null || input === void 0 || (_input$meta8 = input.meta) === null || _input$meta8 === void 0 ? void 0 : _input$meta8.defaultValue) !== undefined && !propHasValue(value)) {
45497
- value = input.meta.defaultValue;
45498
- if (typeof path === 'string') {
45499
- dot__default["default"].str(path, value, values);
45500
- }
45501
- }
45502
45457
  const config = {
45503
45458
  name,
45504
- call: input.call ? input.call : input === null || input === void 0 || (_input$meta9 = input.meta) === null || _input$meta9 === void 0 ? void 0 : _input$meta9.call,
45459
+ call: input.call ? input.call : input === null || input === void 0 || (_input$meta7 = input.meta) === null || _input$meta7 === void 0 ? void 0 : _input$meta7.call,
45505
45460
  automaticallyLink: input.automaticallyLink,
45506
45461
  props,
45507
45462
  formsValue: values,
@@ -45513,8 +45468,8 @@ function DynamicForm(_ref) {
45513
45468
  updateOptions: input.updateOptions || false,
45514
45469
  options: input.options,
45515
45470
  optionGroup: input.optionGroup,
45516
- optionsFilter: input === null || input === void 0 || (_input$meta10 = input.meta) === null || _input$meta10 === void 0 ? void 0 : _input$meta10.optionsFilter,
45517
- filterCond: input === null || input === void 0 || (_input$meta11 = input.meta) === null || _input$meta11 === void 0 ? void 0 : _input$meta11.filterCond,
45471
+ optionsFilter: input === null || input === void 0 || (_input$meta8 = input.meta) === null || _input$meta8 === void 0 ? void 0 : _input$meta8.optionsFilter,
45472
+ filterCond: input === null || input === void 0 || (_input$meta9 = input.meta) === null || _input$meta9 === void 0 ? void 0 : _input$meta9.filterCond,
45518
45473
  disableOtherFields: input.disableOtherFields,
45519
45474
  updateOtherFields: input.updateOtherFields,
45520
45475
  repeatLabel: input.repeatLabel,
@@ -45524,7 +45479,7 @@ function DynamicForm(_ref) {
45524
45479
  restricted: input.restricted || false,
45525
45480
  totalMax: input.totalMax,
45526
45481
  country: input.country || undefined,
45527
- address: (input === null || input === void 0 || (_input$meta12 = input.meta) === null || _input$meta12 === void 0 ? void 0 : _input$meta12.address) || undefined,
45482
+ address: (input === null || input === void 0 || (_input$meta10 = input.meta) === null || _input$meta10 === void 0 ? void 0 : _input$meta10.address) || undefined,
45528
45483
  stakeholderId: input.stakeholderId,
45529
45484
  preSelected,
45530
45485
  addressData,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.463",
3
+ "version": "0.6.464",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -18,7 +18,10 @@
18
18
  "datastake-daf": "^0.6.378",
19
19
  "dayjs": "^1.11.12",
20
20
  "deepmerge": "^4.3.1",
21
+ "docx": "^9.5.1",
22
+ "docx-preview": "^0.3.7",
21
23
  "dot-object": "^2.1.5",
24
+ "file-saver": "^2.0.5",
22
25
  "leaflet": "^1.0.3",
23
26
  "leaflet-editable": "^1.3.0",
24
27
  "leaflet-geosearch": "^3.1.0",
@@ -0,0 +1,441 @@
1
+ import WordDocumentPreview from "./index";
2
+
3
+ export default {
4
+ title: "Core/Document/WordDocument",
5
+ component: WordDocumentPreview,
6
+ tags: ["autodocs"],
7
+ };
8
+
9
+
10
+ export const HeadingExample = {
11
+ name: "Heading Types",
12
+ args: {
13
+ title: "Heading Examples",
14
+ fileName: "headings-example.docx",
15
+ config: [
16
+ {
17
+ type: 'heading',
18
+ data: 'Heading Level 1',
19
+ style: { heading: 'HEADING_1', spacing: { after: 200 } }
20
+ },
21
+ {
22
+ type: 'heading',
23
+ data: 'Heading Level 2',
24
+ style: { heading: 'HEADING_2', spacing: { after: 200 } }
25
+ },
26
+ {
27
+ type: 'heading',
28
+ data: 'Heading Level 3',
29
+ style: { heading: 'HEADING_3', spacing: { after: 200 } }
30
+ }
31
+ ]
32
+ }
33
+ };
34
+
35
+ export const TableExample = {
36
+ name: "Table Example",
37
+ args: {
38
+ title: "Table Document",
39
+ fileName: "table-example.docx",
40
+ config: [
41
+ {
42
+ type: 'heading',
43
+ data: 'Employee Data',
44
+ style: { heading: 'HEADING_1', spacing: { after: 200 } }
45
+ },
46
+ {
47
+ type: 'table',
48
+ data: [
49
+ ['Employee ID', 'Name', 'Department', 'Salary'],
50
+ ['001', 'John Doe', 'Engineering', '$75,000'],
51
+ ['002', 'Jane Smith', 'Marketing', '$65,000'],
52
+ ['003', 'Bob Johnson', 'Sales', '$70,000']
53
+ ]
54
+ }
55
+ ]
56
+ }
57
+ };
58
+
59
+ export const ListsExample = {
60
+ name: "Lists Example",
61
+ args: {
62
+ title: "Lists Document",
63
+ fileName: "lists-example.docx",
64
+ config: [
65
+ {
66
+ type: 'heading',
67
+ data: 'Shopping List (Bullets)',
68
+ style: { heading: 'HEADING_2', spacing: { after: 200 } }
69
+ },
70
+ {
71
+ type: 'bulletList',
72
+ data: 'Milk',
73
+ style: { level: 0 }
74
+ },
75
+ {
76
+ type: 'bulletList',
77
+ data: 'Bread',
78
+ style: { level: 0 }
79
+ },
80
+ {
81
+ type: 'bulletList',
82
+ data: 'Eggs',
83
+ style: { level: 0 }
84
+ },
85
+ {
86
+ type: 'heading',
87
+ data: 'Instructions (Numbered)',
88
+ style: { heading: 'HEADING_2', spacing: { before: 300, after: 200 } }
89
+ },
90
+ {
91
+ type: 'numberedList',
92
+ data: 'Preheat oven to 350°F',
93
+ style: { reference: 'default-numbering', level: 0 }
94
+ },
95
+ {
96
+ type: 'numberedList',
97
+ data: 'Mix ingredients in a bowl',
98
+ style: { reference: 'default-numbering', level: 0 }
99
+ },
100
+ {
101
+ type: 'numberedList',
102
+ data: 'Bake for 25 minutes',
103
+ style: { reference: 'default-numbering', level: 0 }
104
+ }
105
+ ]
106
+ }
107
+ };
108
+
109
+ export const ReportTemplate = {
110
+ name: "Report Template (Like Image)",
111
+ args: {
112
+ title: "Inspection Report",
113
+ fileName: "inspection-report.docx",
114
+ config: [
115
+ // Image with Text Section 1
116
+ {
117
+ type: 'imageWithText',
118
+ data: {
119
+ imageTitle: 'Facility Overview - Main Entrance',
120
+ // Sample industrial facility image from Unsplash
121
+ imageUrl: 'https://images.unsplash.com/photo-1581094794329-c8112a89af12?w=600&h=400&fit=crop',
122
+ image: null, // Will be populated from imageUrl
123
+ imageWidth: 280,
124
+ imageHeight: 200,
125
+ text: 'Main entrance facility showing security gates and access control points. Observation date: 2025-10-13. Weather conditions: Clear. Temperature: 22°C.'
126
+ }
127
+ },
128
+ // Image with Text Section 2 - Image on RIGHT side
129
+ {
130
+ type: 'imageWithText',
131
+ data: {
132
+ imageTitle: 'Storage Area - Chemical Warehouse',
133
+ // Sample warehouse image from Unsplash
134
+ imageUrl: 'https://images.unsplash.com/photo-1553413077-190dd305871c?w=600&h=400&fit=crop',
135
+ image: null, // Will be populated from imageUrl
136
+ imageWidth: 280,
137
+ imageHeight: 200,
138
+ imagePosition: 'right', // Image on the right, text on the left
139
+ text: 'Chemical storage warehouse with proper ventilation and safety signage. All containers are properly labeled. Emergency equipment is accessible and well-maintained.',
140
+ hasSpacing: true
141
+ }
142
+ },
143
+ // Main Takeaways Section with Border
144
+ {
145
+ type: 'borderedSection',
146
+ data: {
147
+ title: 'Provide your main takeaways here',
148
+ content: 'Editable - to be filled by the user\n\nThis is a bordered section where the user can add their main observations and conclusions from the inspection.'
149
+ },
150
+ style: {
151
+ margins: {
152
+ top: 300,
153
+ bottom: 300
154
+ }
155
+ }
156
+ },
157
+ // Mercury Management Section with percentage
158
+ {
159
+ type: 'commentSection',
160
+ data: {
161
+ title: 'Mercury management',
162
+ percentage: 51,
163
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
164
+ comments: [
165
+ 'Mercury storage areas are properly labeled and secured with restricted access',
166
+ 'Safety protocols are documented and clearly displayed in work areas',
167
+ 'Regular monitoring of mercury levels is conducted with weekly reports',
168
+ 'Emergency response kits are available and inspected monthly',
169
+ 'Staff training records are up to date for all personnel handling mercury'
170
+ ]
171
+ }
172
+ },
173
+ // Cyanide Management Section with percentage
174
+ {
175
+ type: 'commentSection',
176
+ data: {
177
+ title: 'Cyanide management',
178
+ percentage: 51,
179
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
180
+ comments: [
181
+ 'Cyanide storage facilities meet international safety standards',
182
+ 'Emergency response procedures are documented and regularly tested',
183
+ 'Staff training on cyanide safety is up to date and comprehensive',
184
+ 'Proper ventilation systems are installed and functioning correctly',
185
+ 'Neutralization agents are stored nearby and easily accessible'
186
+ ]
187
+ }
188
+ },
189
+ // Page Break
190
+ // {
191
+ // type: 'pageBreak'
192
+ // },
193
+ // Climate Change Section on new page
194
+ {
195
+ type: 'commentSection',
196
+ data: {
197
+ title: 'Climate change',
198
+ percentage: 51,
199
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
200
+ comments: [
201
+ 'Carbon emission reduction strategies are actively implemented',
202
+ 'Energy efficiency measures have reduced consumption by 15% year-over-year',
203
+ 'Renewable energy sources provide 30% of total energy requirements',
204
+ 'Water conservation programs are in place with recycling systems',
205
+ 'Environmental impact assessments are conducted quarterly'
206
+ ]
207
+ }
208
+ }
209
+ ]
210
+ }
211
+ };
212
+
213
+ export const ImageWithTextExample = {
214
+ name: "Image With Text Layout",
215
+ args: {
216
+ title: "Image and Text Layout Example",
217
+ fileName: "image-text-layout.docx",
218
+ config: [
219
+ {
220
+ type: 'imageWithText',
221
+ data: {
222
+ imageTitle: 'Image on Left Side',
223
+ // Sample office/building image from Unsplash
224
+ imageUrl: 'https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=600&h=400&fit=crop',
225
+ image: null,
226
+ imageWidth: 300,
227
+ imageHeight: 200,
228
+ imagePosition: 'left', // Default: image on left
229
+ text: 'This is a two-column layout with the image on the LEFT side and text on the right. Both columns have borders.'
230
+ }
231
+ },
232
+ {
233
+ type: 'imageWithText',
234
+ data: {
235
+ imageTitle: 'Image on Right Side',
236
+ // Sample technology image from Unsplash
237
+ imageUrl: 'https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=600&h=400&fit=crop',
238
+ image: null,
239
+ imageWidth: 300,
240
+ imageHeight: 200,
241
+ imagePosition: 'right', // Image on right
242
+ text: 'This shows the same two-column layout but with the image on the RIGHT side and text on the left. You can alternate the positions for visual variety.'
243
+ }
244
+ }
245
+ ]
246
+ }
247
+ };
248
+
249
+ export const BorderedSectionExample = {
250
+ name: "Bordered Section Example",
251
+ args: {
252
+ title: "Bordered Section Example",
253
+ fileName: "bordered-section.docx",
254
+ config: [
255
+ {
256
+ type: 'borderedSection',
257
+ data: {
258
+ title: 'Important Notice',
259
+ content: 'This is a bordered section with a gray background. It can be used for editable areas, important notices, or user input fields.'
260
+ }
261
+ }
262
+ ]
263
+ }
264
+ };
265
+
266
+ export const CommentSectionExample = {
267
+ name: "Comment Section Example",
268
+ args: {
269
+ title: "Comment Section Example",
270
+ fileName: "comment-section.docx",
271
+ config: [
272
+ {
273
+ type: 'commentSection',
274
+ data: {
275
+ title: 'Legitimacy of ASM',
276
+ percentage: 51,
277
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
278
+ comments: []
279
+ }
280
+ },
281
+ {
282
+ type: 'commentSection',
283
+ data: {
284
+ title: 'Ensure traceability',
285
+ percentage: 51,
286
+ comments: [
287
+ 'Comment 1',
288
+ 'Comment 2',
289
+ 'Comment 3',
290
+ '...'
291
+ ]
292
+ }
293
+ },
294
+ {
295
+ type: 'commentSection',
296
+ data: {
297
+ title: 'ASM Companies',
298
+ percentage: 51,
299
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
300
+ comments: [
301
+ 'Comment 1',
302
+ 'Comment 2',
303
+ 'Comment 3',
304
+ '...'
305
+ ]
306
+ }
307
+ },
308
+ {
309
+ type: 'commentSection',
310
+ data: {
311
+ title: 'Armed conflict',
312
+ percentage: 51,
313
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
314
+ comments: []
315
+ }
316
+ }
317
+ ]
318
+ }
319
+ };
320
+
321
+ export const DocumentHeaderExample = {
322
+ name: "Document Header (Dynamic)",
323
+ args: {
324
+ title: "Document with Custom Header",
325
+ fileName: "document-header-example.docx",
326
+ config: [
327
+ // Document Header with icon and dynamic info fields
328
+ {
329
+ type: 'documentHeader',
330
+ data: {
331
+ title: 'Executive Monitoring Report',
332
+ icon: '/logo192.png', // Path to image (will be fetched automatically)
333
+ iconWidth: 60,
334
+ iconHeight: 60,
335
+ titleTextColor: '000000', // Black text (default)
336
+ infoFields: [
337
+ { label: 'Mine:', value: '<Mine Name>' },
338
+ { label: 'Date:', value: 'DD Mmm YY' },
339
+ { label: 'Step:', value: '<Step>' },
340
+ { label: 'Code:', value: '<Code>' }
341
+ ]
342
+ }
343
+ },
344
+ // Add some content below the header
345
+ {
346
+ type: 'paragraph',
347
+ data: 'This document demonstrates the new documentHeader type with dynamic fields.',
348
+ meta: { size: 24 },
349
+ style: { spacing: { after: 200 } }
350
+ },
351
+ {
352
+ type: 'heading',
353
+ data: 'Report Content',
354
+ style: {
355
+ heading: 'HEADING_2',
356
+ spacing: { before: 200, after: 200 }
357
+ }
358
+ },
359
+ {
360
+ type: 'paragraph',
361
+ data: 'The document header above is fully dynamic. You can customize the title, add a logo on the right, and pass any number of info fields with their own labels and values.',
362
+ meta: { size: 22 },
363
+ style: { spacing: { after: 100 } }
364
+ }
365
+ ]
366
+ }
367
+ };
368
+
369
+ export const SectionTitlesExample = {
370
+ name: "Section Titles Demo",
371
+ args: {
372
+ title: "Document with Section Titles",
373
+ fileName: "section-titles-example.docx",
374
+ config: [
375
+ // Document Header
376
+ {
377
+ type: 'documentHeader',
378
+ data: {
379
+ title: 'Executive Monitoring Report',
380
+ icon: '/logo192.png',
381
+ iconWidth: 60,
382
+ iconHeight: 60,
383
+ titleTextColor: '000000',
384
+ infoFields: [
385
+ { label: 'Mine:', value: 'Gold Valley Mine' },
386
+ { label: 'Date:', value: '13 Oct 2025' },
387
+ { label: 'Step:', value: 'Phase 2' },
388
+ { label: 'Code:', value: 'EMR-001' }
389
+ ]
390
+ }
391
+ },
392
+ // Section 1 with title
393
+ {
394
+ title: '1. Environmental Compliance', // Section title
395
+ type: 'commentSection',
396
+ data: {
397
+ title: 'Mercury management',
398
+ percentage: 85,
399
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
400
+ comments: [
401
+ 'Mercury storage areas are properly labeled and secured',
402
+ 'Safety protocols are documented and clearly displayed',
403
+ 'Regular monitoring of mercury levels is conducted',
404
+ 'Emergency response kits are available'
405
+ ]
406
+ }
407
+ },
408
+ {
409
+ type: 'commentSection',
410
+ data: {
411
+ title: 'Cyanide management',
412
+ percentage: 78,
413
+ description: 'Automatic filled by comments contained in associated sub-criteria - editable',
414
+ comments: [
415
+ 'Cyanide storage facilities meet international standards',
416
+ 'Emergency response procedures are regularly tested',
417
+ 'Staff training on cyanide safety is comprehensive',
418
+ 'Proper ventilation systems are functioning correctly'
419
+ ]
420
+ }
421
+ },
422
+ // Section 3 with title
423
+ {
424
+ title: '3. Climate Action', // Section title
425
+ type: 'borderedSection',
426
+ data: {
427
+ title: 'Provide your main takeaways here',
428
+ content: 'Editable section for climate change action plans and observations.'
429
+ }
430
+ },
431
+ // Section 4 with title and custom paragraph
432
+ {
433
+ title: '4. Recommendations', // Section title
434
+ type: 'paragraph',
435
+ data: 'Based on the findings above, we recommend implementing additional safety measures and conducting quarterly reviews of all environmental protocols.',
436
+ meta: { size: 22 },
437
+ style: { spacing: { after: 200 } }
438
+ }
439
+ ]
440
+ }
441
+ };
@@ -0,0 +1,118 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Packer } from 'docx';
3
+ import { saveAs } from 'file-saver';
4
+ import { renderAsync } from 'docx-preview';
5
+ import createDocument from '../createDocument';
6
+
7
+ const WordDocumentPreview = ({ title = "React Word Document Example", content = "This is a sample Word document created with docx library.", fileName = "document.docx", config = [] }) => {
8
+ const previewRef = useRef(null);
9
+
10
+ // Helper function to fetch image from URL and convert to buffer
11
+ const fetchImageAsBuffer = async (url) => {
12
+ try {
13
+ const response = await fetch(url);
14
+ const arrayBuffer = await response.arrayBuffer();
15
+ return arrayBuffer;
16
+ } catch (error) {
17
+ console.error('Error fetching image:', error);
18
+ return null;
19
+ }
20
+ };
21
+
22
+ // Process config to fetch images from URLs
23
+ const processConfig = async (configArray) => {
24
+ const processedConfig = await Promise.all(
25
+ configArray.map(async (item) => {
26
+ // Handle imageWithText type
27
+ if (item.type === 'imageWithText' && item.data?.imageUrl && !item.data.image) {
28
+ const imageBuffer = await fetchImageAsBuffer(item.data.imageUrl);
29
+ return {
30
+ ...item,
31
+ data: {
32
+ ...item.data,
33
+ image: imageBuffer
34
+ }
35
+ };
36
+ }
37
+
38
+ // Handle documentHeader type with icon URL
39
+ if (item.type === 'documentHeader' && item.data?.icon && typeof item.data.icon === 'string') {
40
+ const iconBuffer = await fetchImageAsBuffer(item.data.icon);
41
+ return {
42
+ ...item,
43
+ data: {
44
+ ...item.data,
45
+ icon: iconBuffer
46
+ }
47
+ };
48
+ }
49
+
50
+ return item;
51
+ })
52
+ );
53
+ return processedConfig;
54
+ };
55
+
56
+ const downloadDocument = async () => {
57
+ const processedConfig = await processConfig(config);
58
+ const doc = createDocument({ title, content, config: processedConfig });
59
+ const blob = await Packer.toBlob(doc);
60
+ saveAs(blob, fileName);
61
+ };
62
+
63
+ useEffect(() => {
64
+ const renderPreview = async () => {
65
+ if (previewRef.current) {
66
+ const processedConfig = await processConfig(config);
67
+ const doc = createDocument({ title, content, config: processedConfig });
68
+ const blob = await Packer.toBlob(doc);
69
+
70
+ await renderAsync(blob, previewRef.current, null, {
71
+ className: "docx-preview",
72
+ inWrapper: true,
73
+ ignoreWidth: false,
74
+ ignoreHeight: false,
75
+ renderHeaders: true,
76
+ renderFooters: true,
77
+ });
78
+ }
79
+ };
80
+
81
+ renderPreview();
82
+ }, [title, content, config]);
83
+
84
+ return (
85
+ <div style={{ padding: '20px' }}>
86
+ <div style={{ marginBottom: '20px' }}>
87
+ <button
88
+ onClick={downloadDocument}
89
+ style={{
90
+ padding: '10px 20px',
91
+ fontSize: '16px',
92
+ backgroundColor: '#4CAF50',
93
+ color: 'white',
94
+ border: 'none',
95
+ borderRadius: '4px',
96
+ cursor: 'pointer'
97
+ }}
98
+ >
99
+ Download Word Document
100
+ </button>
101
+ </div>
102
+
103
+ <div
104
+ ref={previewRef}
105
+ style={{
106
+ border: '1px solid #ddd',
107
+ borderRadius: '4px',
108
+ padding: '20px',
109
+ backgroundColor: 'white',
110
+ minHeight: '400px',
111
+ maxWidth: '800px'
112
+ }}
113
+ />
114
+ </div>
115
+ );
116
+ };
117
+
118
+ export default WordDocumentPreview;