datastake-daf 0.6.183 → 0.6.185
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.
- package/dist/components/index.js +493 -421
- package/dist/utils/index.js +441 -404
- package/package.json +2 -2
- package/src/@daf/core/components/Dashboard/Globe/index.jsx +34 -0
- package/src/@daf/core/components/Dashboard/Globe/style.js +4 -1
- package/src/@daf/core/components/ExcelTest/ExcelTest.stories.js +38 -0
- package/src/@daf/core/components/ExcelTest/config.js +254 -0
- package/src/@daf/core/components/ExcelTest/index.jsx +139 -0
- package/src/@daf/core/components/ExcelTest/planningConfig.js +371 -0
- package/src/@daf/core/components/ExcelTest/planningDemo.js +164 -0
- package/src/@daf/core/components/ExcelTest/storyConfig2.js +10413 -0
- package/src/@daf/core/components/ExcelTest/storyconfig.js +8439 -0
- package/src/@daf/core/components/Icon/configs/Briefcase.js +14 -0
- package/src/@daf/core/components/Icon/configs/Certificate.js +15 -0
- package/src/@daf/core/components/Icon/configs/SchoolHat.js +14 -0
- package/src/@daf/core/components/Icon/configs/index.js +6 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { showHideInput } from "../ViewForm/helper";
|
|
2
|
+
import { renderDateFormatted } from "../../../../helpers/Forms";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// Helper function to format references - show only one line to distinguish each
|
|
6
|
+
const formatReferences = (description) => {
|
|
7
|
+
if (!description) return "";
|
|
8
|
+
return description.split("<br>")
|
|
9
|
+
.filter(line => line.trim())
|
|
10
|
+
.map(line => line.trim().replace(/^-+\s*/, '')) // Remove existing dashes
|
|
11
|
+
.filter(line => line) // Remove empty lines
|
|
12
|
+
.join("\n"); // Single line separation
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Helper function to format planning comments
|
|
16
|
+
const formatPlanningComments = (comments, t = (key) => key) => {
|
|
17
|
+
if (!comments || !Array.isArray(comments)) return t("not answered");
|
|
18
|
+
const validComments = comments.map(comment => comment.text || "").filter(text => text);
|
|
19
|
+
return validComments.length > 0 ? validComments.join(", ") : t("not answered");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Helper function to format responsible persons - map IDs to names using linking data
|
|
23
|
+
const formatResponsiblePerson = (accountablePersonnel, linkingData = {}, t = (key) => key) => {
|
|
24
|
+
if (!accountablePersonnel || !Array.isArray(accountablePersonnel) || accountablePersonnel.length === 0) return t("not answered");
|
|
25
|
+
|
|
26
|
+
const names = accountablePersonnel.map(id => {
|
|
27
|
+
// Check if linking data has this ID
|
|
28
|
+
const continuousImprovementData = linkingData?.continuousImprovement || {};
|
|
29
|
+
const person = continuousImprovementData[id];
|
|
30
|
+
|
|
31
|
+
if (person) {
|
|
32
|
+
return person.firstName || person.label || id;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fallback to ID if no name found
|
|
36
|
+
return id;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return names.length > 0 ? names.join(", ") : t("not answered");
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Helper function to format target completion date
|
|
43
|
+
const formatTargetCompletionDate = (targetCompletionDate, t = (key) => key) => {
|
|
44
|
+
if (!targetCompletionDate) return t("not answered");
|
|
45
|
+
return renderDateFormatted(targetCompletionDate, 'DD MMM YYYY', 'en');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Helper function to format evaluation documents from previousStage criteria - show document names with dashes
|
|
49
|
+
const formatEvaluationDocuments = (previousStageCriteria, subCategory, criteriaKey, t = (key) => key) => {
|
|
50
|
+
if (!previousStageCriteria || !Array.isArray(previousStageCriteria)) return t("not answered");
|
|
51
|
+
|
|
52
|
+
// Find the matching criteria by subCategory
|
|
53
|
+
const matchingCriteria = previousStageCriteria.find(criteria => criteria.subCategory === subCategory);
|
|
54
|
+
|
|
55
|
+
if (!matchingCriteria) return t("not answered");
|
|
56
|
+
|
|
57
|
+
const allDocuments = [];
|
|
58
|
+
|
|
59
|
+
// Get document names from the specific field's documentation (same as documentation field)
|
|
60
|
+
const fieldData = matchingCriteria[criteriaKey];
|
|
61
|
+
if (fieldData && fieldData.documentation && Array.isArray(fieldData.documentation)) {
|
|
62
|
+
fieldData.documentation.forEach(doc => {
|
|
63
|
+
if (doc && doc.documents && Array.isArray(doc.documents)) {
|
|
64
|
+
doc.documents.forEach(document => {
|
|
65
|
+
if (document && document.name) {
|
|
66
|
+
allDocuments.push(`- ${document.name}`);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return allDocuments.length > 0 ? allDocuments.join("\n") : t("not answered");
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Helper function to format valuation from previousStage criteria
|
|
77
|
+
const formatValuation = (previousStageCriteria, subCategory, criteriaKey, t = (key) => key) => {
|
|
78
|
+
if (!previousStageCriteria || !Array.isArray(previousStageCriteria)) return t("not answered");
|
|
79
|
+
|
|
80
|
+
// Find the matching criteria by subCategory
|
|
81
|
+
const matchingCriteria = previousStageCriteria.find(criteria => criteria.subCategory === subCategory);
|
|
82
|
+
|
|
83
|
+
if (!matchingCriteria) return t("not answered");
|
|
84
|
+
|
|
85
|
+
// Get valuation from the specific field in the criteria
|
|
86
|
+
const fieldData = matchingCriteria[criteriaKey];
|
|
87
|
+
if (fieldData && fieldData.valuation !== undefined && fieldData.valuation !== null) {
|
|
88
|
+
return fieldData.valuation === 'na' ? 'N/A' : `${fieldData.valuation}%`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return t("not answered");
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Helper function to format documentation from previousStage criteria
|
|
95
|
+
const formatDocumentation = (previousStageCriteria, subCategory, criteriaKey, t = (key) => key) => {
|
|
96
|
+
if (!previousStageCriteria || !Array.isArray(previousStageCriteria)) return t("not answered");
|
|
97
|
+
|
|
98
|
+
// Find the matching criteria by subCategory
|
|
99
|
+
const matchingCriteria = previousStageCriteria.find(criteria => criteria.subCategory === subCategory);
|
|
100
|
+
|
|
101
|
+
if (!matchingCriteria) return t("not answered");
|
|
102
|
+
|
|
103
|
+
const allDocuments = [];
|
|
104
|
+
|
|
105
|
+
// Check if the criteria has the specific field and its documentation
|
|
106
|
+
if (matchingCriteria[criteriaKey] && matchingCriteria[criteriaKey].documentation) {
|
|
107
|
+
const docs = matchingCriteria[criteriaKey].documentation;
|
|
108
|
+
|
|
109
|
+
if (Array.isArray(docs)) {
|
|
110
|
+
docs.forEach(doc => {
|
|
111
|
+
if (doc && doc.documents && Array.isArray(doc.documents)) {
|
|
112
|
+
doc.documents.forEach(document => {
|
|
113
|
+
if (document.name) {
|
|
114
|
+
allDocuments.push(document.name);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return allDocuments.length > 0 ? allDocuments.join(", ") : t("not answered");
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Helper function to format verification method - remove <br> and add appropriate separators
|
|
126
|
+
const formatVerificationMethod = (description, forCSV = false, t = (key) => key) => {
|
|
127
|
+
if (!description) return t("not answered");
|
|
128
|
+
const lines = description.split("<br>")
|
|
129
|
+
.filter(line => line.trim())
|
|
130
|
+
.map(line => line.trim());
|
|
131
|
+
|
|
132
|
+
if (lines.length === 0) return t("not answered");
|
|
133
|
+
|
|
134
|
+
// For CSV export, use semicolon separator to avoid newline issues
|
|
135
|
+
if (forCSV) {
|
|
136
|
+
return lines.join("; ");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// For display, use newlines
|
|
140
|
+
return lines.join("\n");
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Helper function to get description by language
|
|
144
|
+
const getDescriptionByLanguage = (descriptions, language = "en") => {
|
|
145
|
+
if (!descriptions) return "";
|
|
146
|
+
return descriptions[language] || descriptions.en || descriptions.sp || descriptions.fr || "";
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const getAspectToVerify = (form, sectionKey, kidPosition, country) => {
|
|
150
|
+
const titlesSection = form?.titles?.[sectionKey];
|
|
151
|
+
if (!titlesSection) return "";
|
|
152
|
+
|
|
153
|
+
const matchingTitles = Object.keys(titlesSection)
|
|
154
|
+
.filter(key => key.startsWith('title'))
|
|
155
|
+
.map(key => titlesSection[key])
|
|
156
|
+
.filter(title => {
|
|
157
|
+
if (!title.showIf) return false;
|
|
158
|
+
const condition = title.showIf.toLowerCase();
|
|
159
|
+
if (condition.includes('country is')) {
|
|
160
|
+
const requiredCountry = condition.replace('country is', '').trim();
|
|
161
|
+
return country && country.toLowerCase() === requiredCountry.toLowerCase();
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
})
|
|
165
|
+
.sort((a, b) => (a.position || 0) - (b.position || 0));
|
|
166
|
+
|
|
167
|
+
if (matchingTitles.length === 0) return "";
|
|
168
|
+
|
|
169
|
+
let selectedTitle = matchingTitles[0];
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < matchingTitles.length; i++) {
|
|
172
|
+
const titlePosition = matchingTitles[i].position || 0;
|
|
173
|
+
if (titlePosition <= kidPosition) {
|
|
174
|
+
selectedTitle = matchingTitles[i];
|
|
175
|
+
} else {
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
const label = selectedTitle?.label || "";
|
|
182
|
+
return label.replace(/\\"/g, '"').replace(/\n/g, " ").replace(/\r/g, " ").replace(/\t/g, " ").trim();
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export const fixDataForExcel = (originalData, stepParam = 1, module = "", t = (key) => key) => {
|
|
186
|
+
const {form, data} = originalData;
|
|
187
|
+
const language = data?.user?.language || "en";
|
|
188
|
+
const step = Number(stepParam);
|
|
189
|
+
|
|
190
|
+
// Table 1 data - Basic Information (vertical key-value format)
|
|
191
|
+
const table1Data = [
|
|
192
|
+
{ key: t('mine'), value: data?.location?.name || "Adimental S.A.C" }, // Use placeholder if location data is missing
|
|
193
|
+
{ key: t('module'), value: module },
|
|
194
|
+
{ key: t('sources'), value: "" }, // Leave blank as requested
|
|
195
|
+
{ key: t('version'), value: data?.version || "1" },
|
|
196
|
+
{ key: t('date'), value: renderDateFormatted(new Date().toISOString(), 'DD MMM YYYY', (language === 'sp' ? 'es' : language) || 'en') }
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
console.log("Planning Table 1 Data:", table1Data);
|
|
200
|
+
|
|
201
|
+
// Table 2 data - Planning Data
|
|
202
|
+
const table2Data = [];
|
|
203
|
+
|
|
204
|
+
const sections = (form?.identification?.category?.options || [])?.map((option) => ({
|
|
205
|
+
group: option.label,
|
|
206
|
+
key: option.value,
|
|
207
|
+
criterias: (form?.identification?.subCategory?.options || [])
|
|
208
|
+
.filter((_option) => {
|
|
209
|
+
const categoryFilter = _option?.filters?.find((f) => f.name === "category");
|
|
210
|
+
const stepFilter = _option?.filters?.find((f) => f.name === "step");
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
(stepFilter?.value || 1) === step &&
|
|
214
|
+
(categoryFilter?.value || []).includes(option.value) &&
|
|
215
|
+
!!(data?.criteria || []).find(
|
|
216
|
+
(c) => c.subCategory === _option.value,
|
|
217
|
+
)
|
|
218
|
+
);
|
|
219
|
+
})
|
|
220
|
+
.map((_option) => {
|
|
221
|
+
const _criteria = (data?.criteria || []).find(
|
|
222
|
+
(c) => c.subCategory === _option.value,
|
|
223
|
+
);
|
|
224
|
+
const subCategoryForm = form[_criteria.subCategory];
|
|
225
|
+
|
|
226
|
+
const kids = Object.keys(subCategoryForm)
|
|
227
|
+
.filter((k) => {
|
|
228
|
+
const val = subCategoryForm[k];
|
|
229
|
+
if (val.showIf) {
|
|
230
|
+
const show = showHideInput(val, data);
|
|
231
|
+
return show;
|
|
232
|
+
}
|
|
233
|
+
return val?.type === "group";
|
|
234
|
+
})
|
|
235
|
+
.sort((a, b) => {
|
|
236
|
+
const valA = subCategoryForm[a];
|
|
237
|
+
const valB = subCategoryForm[b];
|
|
238
|
+
return valA?.position - valB?.position;
|
|
239
|
+
})
|
|
240
|
+
.map((k) => {
|
|
241
|
+
const formVal = subCategoryForm[k];
|
|
242
|
+
const evalData = _criteria[k];
|
|
243
|
+
const meta = (_criteria?.meta?.inputs || {})[k];
|
|
244
|
+
|
|
245
|
+
// Get reference description from form object description field
|
|
246
|
+
const referenceDescription = formVal.description || "";
|
|
247
|
+
|
|
248
|
+
// Get verification method from form meta
|
|
249
|
+
const verificationMethod = getDescriptionByLanguage(
|
|
250
|
+
formVal?.meta?.groupInfo?.description,
|
|
251
|
+
language
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
key: k,
|
|
256
|
+
group: option.value,
|
|
257
|
+
criteria: formVal.label,
|
|
258
|
+
position: formVal.position || 0,
|
|
259
|
+
lastUpdate: _criteria.updatedAt,
|
|
260
|
+
meta,
|
|
261
|
+
referenceDescription,
|
|
262
|
+
verificationMethod,
|
|
263
|
+
// Planning specific data from individual field in criteria
|
|
264
|
+
targetCompletionDate: evalData?.targetCompletionDate,
|
|
265
|
+
accountablePersonnel: evalData?.accountablePersonnel,
|
|
266
|
+
planningComment: evalData?.planningComment,
|
|
267
|
+
...evalData,
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
key: _option.value,
|
|
273
|
+
group: option.value,
|
|
274
|
+
criteria: _option.label,
|
|
275
|
+
completion: _criteria.completion,
|
|
276
|
+
evaluationScore: _criteria.evaluationScore,
|
|
277
|
+
description: (form?.identification?.dscription?.options || []).find(
|
|
278
|
+
(d) => d.value === _option.value,
|
|
279
|
+
)?.label || "-",
|
|
280
|
+
lastUpdate: _criteria.updatedAt,
|
|
281
|
+
linking: _criteria.linking || {}, // Pass linking data for responsible person mapping
|
|
282
|
+
kids,
|
|
283
|
+
};
|
|
284
|
+
})
|
|
285
|
+
}));
|
|
286
|
+
|
|
287
|
+
// Process sections to create table 2 data
|
|
288
|
+
sections.forEach((section) => {
|
|
289
|
+
section.criterias.forEach((criteria) => {
|
|
290
|
+
criteria.kids.forEach((kid) => {
|
|
291
|
+
// Get previous stage criteria for evaluation documents and documentation
|
|
292
|
+
const previousStageCriteria = data?.previousStage?.criteria || [];
|
|
293
|
+
|
|
294
|
+
// Get linking data for responsible person mapping
|
|
295
|
+
const linkingData = criteria.linking || {};
|
|
296
|
+
|
|
297
|
+
const row = {
|
|
298
|
+
stage: `0${step}`,
|
|
299
|
+
aspect: section.group,
|
|
300
|
+
criteria: criteria.criteria,
|
|
301
|
+
subcriteria: kid.criteria,
|
|
302
|
+
verificationMethod: formatVerificationMethod(kid.verificationMethod || "", false, t),
|
|
303
|
+
targetCompletionDate: formatTargetCompletionDate(kid.targetCompletionDate, t),
|
|
304
|
+
evaluationDocuments: formatEvaluationDocuments(previousStageCriteria, criteria.key, kid.key, t),
|
|
305
|
+
responsiblePerson: formatResponsiblePerson(kid.accountablePersonnel, linkingData, t),
|
|
306
|
+
comments: formatPlanningComments(kid.planningComment, t),
|
|
307
|
+
valuation: formatValuation(previousStageCriteria, criteria.key, kid.key, t)
|
|
308
|
+
};
|
|
309
|
+
table2Data.push(row);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
console.log("Planning Table 2 Data:", table2Data);
|
|
315
|
+
console.log("Planning Sections:", sections);
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
table1: table1Data,
|
|
319
|
+
table2: table2Data,
|
|
320
|
+
sections: sections
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
export const exportToCSV = (data, filename = "planning_data.csv", t = (key) => key) => {
|
|
325
|
+
const { table1, table2 } = data;
|
|
326
|
+
|
|
327
|
+
let csvContent = "";
|
|
328
|
+
|
|
329
|
+
// Add Table 1 data (vertical key-value format, no title)
|
|
330
|
+
table1.forEach(item => {
|
|
331
|
+
csvContent += `"${item.key}","${item.value}"\n`;
|
|
332
|
+
});
|
|
333
|
+
csvContent += "\n"; // Empty line separator
|
|
334
|
+
|
|
335
|
+
// Add Table 2 header and data with planning-specific columns (correct order)
|
|
336
|
+
csvContent += `"${t('stage')}","${t('aspect')}","${t('criteria')}","${t('subcriteria')}","${t('verificationMethod')}","${t('targetCompletionDate')}","${t('evaluationDocuments')}","${t('responsiblePerson')}","${t('comments')}","${t('valuation')}"\n`;
|
|
337
|
+
|
|
338
|
+
table2.forEach(row => {
|
|
339
|
+
const csvRow = [
|
|
340
|
+
row.stage,
|
|
341
|
+
row.aspect,
|
|
342
|
+
row.criteria,
|
|
343
|
+
row.subcriteria,
|
|
344
|
+
formatVerificationMethod(row.verificationMethod || "", true, t).replace(/"/g, '""'),
|
|
345
|
+
row.targetCompletionDate,
|
|
346
|
+
(row.evaluationDocuments || "").replace(/"/g, '""'),
|
|
347
|
+
(row.responsiblePerson || "").replace(/"/g, '""'),
|
|
348
|
+
(row.comments || "").replace(/"/g, '""'),
|
|
349
|
+
row.valuation
|
|
350
|
+
].map(field => `"${field}"`).join(",");
|
|
351
|
+
|
|
352
|
+
csvContent += csvRow + "\n";
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
return csvContent;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// Utility function to download CSV file
|
|
359
|
+
export const downloadCSV = (data, filename = "planning_data.csv", t = (key) => key) => {
|
|
360
|
+
const csvContent = exportToCSV(data, filename, t);
|
|
361
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
362
|
+
const link = document.createElement("a");
|
|
363
|
+
const url = URL.createObjectURL(blob);
|
|
364
|
+
|
|
365
|
+
link.setAttribute("href", url);
|
|
366
|
+
link.setAttribute("download", filename);
|
|
367
|
+
link.style.visibility = 'hidden';
|
|
368
|
+
document.body.appendChild(link);
|
|
369
|
+
link.click();
|
|
370
|
+
document.body.removeChild(link);
|
|
371
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { fixDataForExcel, exportToCSV, downloadCSV } from './planningConfig';
|
|
3
|
+
import { storyData } from './storyConfig2';
|
|
4
|
+
|
|
5
|
+
// Translation function for demo purposes
|
|
6
|
+
const t = (key) => {
|
|
7
|
+
const translations = {
|
|
8
|
+
// Table 1 translations
|
|
9
|
+
'mine': 'Mine',
|
|
10
|
+
'module': 'Module',
|
|
11
|
+
'sources': 'Source',
|
|
12
|
+
'version': 'Version',
|
|
13
|
+
'date': 'Date',
|
|
14
|
+
|
|
15
|
+
// Table 2 translations
|
|
16
|
+
'stage': 'Step',
|
|
17
|
+
'aspect': 'Aspect',
|
|
18
|
+
'criteria': 'Criteria',
|
|
19
|
+
'subcriteria': 'Subcriteria',
|
|
20
|
+
'verificationMethod': 'Means of verification',
|
|
21
|
+
'targetCompletionDate': 'Target completion date',
|
|
22
|
+
'responsiblePerson': 'Responsible person',
|
|
23
|
+
'comments': 'Comments',
|
|
24
|
+
'evaluationDocuments': 'Evaluation Documents',
|
|
25
|
+
'valuation': 'Valuation',
|
|
26
|
+
'not answered': 'not answered'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return translations[key] || key;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const PlanningDemo = () => {
|
|
33
|
+
// Process the planning story data using our configuration
|
|
34
|
+
const processedData = fixDataForExcel(storyData, 1, "Planning", t);
|
|
35
|
+
|
|
36
|
+
const handleDownloadCSV = () => {
|
|
37
|
+
downloadCSV(processedData, "planning_data.csv", t);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleViewCSV = () => {
|
|
41
|
+
const csvContent = exportToCSV(processedData, "planning_data.csv", t);
|
|
42
|
+
console.log("CSV Content:", csvContent);
|
|
43
|
+
|
|
44
|
+
// Create a downloadable blob URL for viewing
|
|
45
|
+
const blob = new Blob([csvContent], { type: 'text/csv' });
|
|
46
|
+
const url = URL.createObjectURL(blob);
|
|
47
|
+
window.open(url, '_blank');
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Helper function to render cell with gray styling for "not answered"
|
|
51
|
+
const renderCellContent = (content) => {
|
|
52
|
+
if (content === t("not answered")) {
|
|
53
|
+
return <span style={{ color: '#6c757d', opacity: 0.7, fontStyle: 'italic' }}>{content}</span>;
|
|
54
|
+
}
|
|
55
|
+
return content;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
|
|
60
|
+
<h1>Planning Data Configuration Demo</h1>
|
|
61
|
+
|
|
62
|
+
<div style={{ marginBottom: '20px' }}>
|
|
63
|
+
<button
|
|
64
|
+
onClick={handleDownloadCSV}
|
|
65
|
+
style={{
|
|
66
|
+
padding: '10px 20px',
|
|
67
|
+
margin: '5px',
|
|
68
|
+
backgroundColor: '#007bff',
|
|
69
|
+
color: 'white',
|
|
70
|
+
border: 'none',
|
|
71
|
+
borderRadius: '4px',
|
|
72
|
+
cursor: 'pointer'
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
Download Planning CSV
|
|
76
|
+
</button>
|
|
77
|
+
<button
|
|
78
|
+
onClick={handleViewCSV}
|
|
79
|
+
style={{
|
|
80
|
+
padding: '10px 20px',
|
|
81
|
+
margin: '5px',
|
|
82
|
+
backgroundColor: '#28a745',
|
|
83
|
+
color: 'white',
|
|
84
|
+
border: 'none',
|
|
85
|
+
borderRadius: '4px',
|
|
86
|
+
cursor: 'pointer'
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
View CSV Content
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div style={{ marginBottom: '30px' }}>
|
|
94
|
+
<h2>Table 1 - Basic Information</h2>
|
|
95
|
+
<table style={{ borderCollapse: 'collapse', width: '100%', border: '1px solid #ddd' }}>
|
|
96
|
+
<tbody>
|
|
97
|
+
{processedData.table1.map((item, index) => (
|
|
98
|
+
<tr key={index}>
|
|
99
|
+
<td style={{ border: '1px solid #ddd', padding: '8px', fontWeight: 'bold', backgroundColor: '#f8f9fa' }}>
|
|
100
|
+
{item.key}
|
|
101
|
+
</td>
|
|
102
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>
|
|
103
|
+
{item.value}
|
|
104
|
+
</td>
|
|
105
|
+
</tr>
|
|
106
|
+
))}
|
|
107
|
+
</tbody>
|
|
108
|
+
</table>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div>
|
|
112
|
+
<h2>Table 2 - Planning Data</h2>
|
|
113
|
+
<div style={{ overflowX: 'auto' }}>
|
|
114
|
+
<table style={{ borderCollapse: 'collapse', width: '100%', border: '1px solid #ddd' }}>
|
|
115
|
+
<thead>
|
|
116
|
+
<tr style={{ backgroundColor: '#f8f9fa' }}>
|
|
117
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '60px' }}>Step</th>
|
|
118
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '120px' }}>Aspect</th>
|
|
119
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '150px' }}>Criteria</th>
|
|
120
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '150px' }}>Subcriteria</th>
|
|
121
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '200px' }}>Means of verification</th>
|
|
122
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '120px' }}>Target completion date</th>
|
|
123
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '150px' }}>Evaluation Documents</th>
|
|
124
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '150px' }}>Responsible person</th>
|
|
125
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '200px' }}>Comments</th>
|
|
126
|
+
<th style={{ border: '1px solid #ddd', padding: '8px', minWidth: '80px' }}>Valoración</th>
|
|
127
|
+
</tr>
|
|
128
|
+
</thead>
|
|
129
|
+
<tbody>
|
|
130
|
+
{processedData.table2.map((row, index) => (
|
|
131
|
+
<tr key={index} style={{ backgroundColor: index % 2 === 0 ? '#ffffff' : '#f8f9fa' }}>
|
|
132
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.stage)}</td>
|
|
133
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.aspect)}</td>
|
|
134
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.criteria)}</td>
|
|
135
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.subcriteria)}</td>
|
|
136
|
+
<td style={{ border: '1px solid #ddd', padding: '8px', whiteSpace: 'pre-wrap' }}>{renderCellContent(row.verificationMethod)}</td>
|
|
137
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.targetCompletionDate)}</td>
|
|
138
|
+
<td style={{ border: '1px solid #ddd', padding: '8px', whiteSpace: 'pre-wrap' }}>{renderCellContent(row.evaluationDocuments)}</td>
|
|
139
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.responsiblePerson)}</td>
|
|
140
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.comments)}</td>
|
|
141
|
+
<td style={{ border: '1px solid #ddd', padding: '8px' }}>{renderCellContent(row.valuation)}</td>
|
|
142
|
+
</tr>
|
|
143
|
+
))}
|
|
144
|
+
</tbody>
|
|
145
|
+
</table>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div style={{ marginTop: '30px', padding: '15px', backgroundColor: '#e9ecef', borderRadius: '4px' }}>
|
|
150
|
+
<h3>Data Structure Overview</h3>
|
|
151
|
+
<p><strong>Planning-specific fields extracted:</strong></p>
|
|
152
|
+
<ul>
|
|
153
|
+
<li><strong>Target Completion Date:</strong> From <code>data?.criteria</code> → <code>targetCompletionDate</code></li>
|
|
154
|
+
<li><strong>Responsible Person:</strong> From <code>data?.criteria</code> → <code>accountablePersonnel</code> (array joined with commas)</li>
|
|
155
|
+
<li><strong>Comments:</strong> From <code>data?.criteria</code> → <code>planningComment</code> (array of objects with text key)</li>
|
|
156
|
+
<li><strong>Evaluation Documents:</strong> From <code>previousStage?.criteria</code> → <code>documentation</code> → <code>documents</code> → <code>name</code> (with dashes on new lines)</li>
|
|
157
|
+
<li><strong>Valuation:</strong> From individual field <code>valuation</code> property</li>
|
|
158
|
+
</ul>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export default PlanningDemo;
|