etiquetas.js 1.0.0-alpha.1

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.
@@ -0,0 +1,158 @@
1
+ import pkg from "lodash";
2
+ const { omit, groupBy } = pkg;
3
+
4
+ // Função para filtrar e preparar os dados de acordo com o tipo selecionado
5
+ export const dataTypeList = (actualFilter, values) => {
6
+ const value = [...values];
7
+ switch (actualFilter) {
8
+ case "input":
9
+ let arr = [];
10
+ value.map((v, k) => {
11
+ arr = arr.concat(
12
+ ...v.data.woodwork.reduce((accumulator, w, wi) => {
13
+ const inputsWithProjectData = w.inputs.map((input, inputIndex) => ({
14
+ ...input,
15
+ project_id: v.data.project_id,
16
+ project_description: v.data.project_description,
17
+ project_customer_id: v.data.project_customer_id,
18
+ project_customer_name: v.data.project_customer_name,
19
+ project_note: v.data.project_note,
20
+ mref: w.ref,
21
+ mname: w.name,
22
+ mnote: w.note,
23
+ }));
24
+ accumulator = accumulator.concat(inputsWithProjectData);
25
+ return accumulator;
26
+ }, [])
27
+ );
28
+ });
29
+ return groupBy(arr, "category_id");
30
+
31
+ case "part":
32
+ let aux = [];
33
+ let partNumber = 1;
34
+ value.map((val, key) =>
35
+ val.data.woodwork.map(
36
+ (v, k) =>
37
+ (aux = aux.concat(
38
+ ...v.parts.reduce((accumulator, part, partIndex) => {
39
+ accumulator = accumulator.concat({
40
+ id: part.id,
41
+ pid: part.id,
42
+ pref: part.ref,
43
+ mref: v.ref,
44
+ mname: v.name,
45
+ mnote: v.note,
46
+ index: partNumber,
47
+ number: partNumber,
48
+ key: k,
49
+ name: part.name,
50
+ material_name: part.material_name,
51
+ material_id: part.material_id,
52
+ material_width: part.material_width,
53
+ material_height: part.material_height,
54
+ note: part.note,
55
+ width: part.height,
56
+ height: part.width,
57
+ thickness: part.thickness,
58
+ type: part.type,
59
+ edge_left: part.edge_left,
60
+ edge_left_id: part.edge_left_id,
61
+ edge_right: part.edge_right,
62
+ edge_right_id: part.edge_right_id,
63
+ edge_top: part.edge_top,
64
+ edge_top_id: part.edge_top_id,
65
+ edge_bottom: part.edge_bottom,
66
+ edge_bottom_id: part.edge_bottom_id,
67
+ code_a: `${part.code_a}`,
68
+ code_b: `${part.code_b}`,
69
+ project_id: val.data.project_id,
70
+ project_description: val.data.project_description,
71
+ project_customer_id: val.data.project_customer_id,
72
+ project_customer_name: val.data.project_customer_name,
73
+ project_note: val.data.project_note,
74
+ });
75
+ partNumber++;
76
+ return accumulator;
77
+ }, [])
78
+ ))
79
+ )
80
+ );
81
+ return aux;
82
+
83
+ case 'volume':
84
+ return value.map((v) => {
85
+ return {
86
+ project_id: v?.volume?.project_id,
87
+ project_description: v?.volume?.project_name,
88
+ project_customer_id: '',
89
+ project_customer_name: v?.volume?.customer,
90
+ project_note: '',
91
+ itemList: [
92
+ ...(v.inputs || []),
93
+ ...(v.parts || []).map((part) => ({
94
+ ...part,
95
+ name: `${part.name} ${part.thickness}mm`,
96
+ dimensions: `${part.width} x ${part.height} mm`
97
+ }))
98
+ ],
99
+ volume_name: v?.volume?.description,
100
+ volume_id: v?.volume?.id,
101
+ volume_date: v?.volume?.created_at ? new Date(v.volume.created_at).toLocaleDateString('pt-BR') : '',
102
+ volume_weight: '0kg',
103
+ };
104
+ });
105
+
106
+ case "thickened":
107
+ let thickNumber = 1;
108
+ const thickArr = value.flatMap((v) =>
109
+ v.data.woodwork.reduce((accumulator, wd) => {
110
+ if (wd.type === "thickened") {
111
+ accumulator.push({
112
+ ...omit(wd, ["inputs", "parts"]),
113
+ index: thickNumber,
114
+ mref: wd.ref,
115
+ mnote: wd.note,
116
+ ref: null,
117
+ project_id: v.data.project_id,
118
+ project_description: v.data.project_description,
119
+ project_customer_id: v.data.project_customer_id,
120
+ project_customer_name: v.data.project_customer_name,
121
+ project_note: v.data.project_note,
122
+ rotated: true,
123
+ });
124
+ thickNumber++;
125
+ }
126
+ return accumulator;
127
+ }, [])
128
+ );
129
+ return thickArr;
130
+
131
+ default:
132
+ return [];
133
+ }
134
+ };
135
+
136
+ // Função para filtrar insumos por categoria
137
+ export const getInputsByCategory = (inputs, category_id = []) => {
138
+ if (category_id.length === 0) {
139
+ return Object.values(inputs).reduce((accumulator, input) => {
140
+ accumulator = accumulator.concat(input);
141
+ return accumulator;
142
+ }, []);
143
+ }
144
+ return category_id.reduce((accumulator, id) => {
145
+ if (inputs[id]) {
146
+ accumulator = accumulator.concat(inputs[id]);
147
+ }
148
+ return accumulator;
149
+ }, []);
150
+ };
151
+
152
+ // Função para obter todas as categorias de insumos
153
+ export const getAllCategoriesId = (inputs = []) =>
154
+ inputs.reduce((accumulator, input) => {
155
+ const ids = input.map((inp) => [inp.category_id, inp.category_name]);
156
+ accumulator = accumulator.concat(ids);
157
+ return [...new Set(accumulator)];
158
+ }, []);
@@ -0,0 +1,280 @@
1
+ /**
2
+ * * Adicionar ao insertPdfToImage
3
+
4
+ * Adicione essas variáveis :
5
+ * // Volume information
6
+ "VOLUME_ID": "volume_id",
7
+ "VOLUME_NOME": "volume_name",
8
+ "VOLUME_PESO": "volume_weight",
9
+ "VOLUME_DATA": "volume_date",
10
+
11
+ // Additional properties
12
+ "MATERIAL_NOME": "material",
13
+ "LADO_USINAGEM": "machining_side",
14
+
15
+ "LOTE_ID": "lot_id"
16
+ *
17
+ *
18
+ *Adicione uma nova função de specialProp
19
+ * case "volumeContent":
20
+ const xzz = generateTableSVG(currentPart.itemList, {
21
+
22
+ });
23
+ const { headers, rows } = convertSVGTableToAutoTableData(currentPart.itemList);
24
+
25
+ // Gerar a tabela no PDF
26
+ autoTable(pdfInstance, {
27
+ head: [headers], // Cabeçalho
28
+ body: rows, // Linhas
29
+ startY: height * x + (horizontalSpace * x + marginTop) + vTop,
30
+ theme: 'grid', // Estilo da tabela
31
+ styles: {
32
+ fontSize: 4,
33
+ cellPadding: 0.5,
34
+ lineHeight: 0.6,
35
+ minCellHeight: 1.8,
36
+ overflow: 'linebreak',
37
+ halign: 'center'
38
+ },
39
+ headStyles: {
40
+ fillColor: [240, 240, 240],
41
+ textColor: [0, 0, 0],
42
+ fontStyle: 'bold',
43
+ minCellHeight: 1.8
44
+ },
45
+ margin: { top: 10, right: 5, bottom: 0, left: width * y + (verticalSpace * y + marginLeft) + vLeft },
46
+ tableWidth: vWidth,
47
+ rowPageBreak:'avoid',
48
+ pageBreak:'auto',
49
+
50
+
51
+ showHead: 'firstPage',
52
+ didDrawPage: function(data) {
53
+ // Quando nova página for criada, redefine Y mas mantém a mesma margem esquerda
54
+ data.settings.margin.top = 0.5;
55
+ data.cursor.y = 0.5 ;
56
+ },
57
+
58
+ columnStyles: {
59
+ // Você pode definir larguras específicas para colunas, se necessário
60
+ }
61
+ });
62
+ */
63
+
64
+ /**
65
+ * Utility functions for the label services
66
+ */
67
+
68
+ /**
69
+ * Converts millimeters to pixels
70
+ * @param {number} mm - Value in millimeters
71
+ * @returns {number} Value in pixels (assuming 96 DPI)
72
+ */
73
+ export const mmToPx = (mm) => {
74
+ // 1 mm = 3.7795275591 pixels at 96 DPI
75
+ return mm * 3.7795275591;
76
+ };
77
+
78
+ /**
79
+ * Converts pixels to millimeters
80
+ * @param {number} px - Value in pixels
81
+ * @returns {number} Value in millimeters (assuming 96 DPI)
82
+ */
83
+ export const pxToMm = (px) => {
84
+ // 1 pixel = 0.2645833333 mm at 96 DPI
85
+ return px * 0.2645833333;
86
+ };
87
+
88
+ /**
89
+ * Loads images from URLs and returns the URL (basic implementation)
90
+ * @param {string} url - URL of the image
91
+ * @returns {Promise<string>} The image URL
92
+ */
93
+ export const getImagesFromUrl = async (url) => {
94
+ try {
95
+ // Basic implementation - returns the URL as is
96
+ // Can be enhanced to validate the URL or fetch the image
97
+ if (!url || typeof url !== 'string') {
98
+ throw new Error('Invalid URL provided');
99
+ }
100
+ return url;
101
+ } catch (error) {
102
+ console.error('Error loading image from URL:', error);
103
+ return null;
104
+ }
105
+ };
106
+
107
+ /**
108
+ * Loads images from URLs and converts them to Base64
109
+ * @param {string} url - URL of the image
110
+ * @returns {Promise<string>} Base64 encoded image data
111
+ */
112
+ export const getImagesFromUrlToBase64 = async (url) => {
113
+ try {
114
+ if (!url || typeof url !== 'string') {
115
+ throw new Error('Invalid URL provided');
116
+ }
117
+ console.log('getImagesFromUrlToBase64: Converting URL to Base64:', url);
118
+
119
+ // Browser environment handling
120
+ if (typeof window !== 'undefined' && typeof fetch !== 'undefined') {
121
+ try {
122
+ const response = await fetch(url);
123
+ if (!response.ok) {
124
+ throw new Error(`HTTP error! status: ${response.status}`);
125
+ }
126
+
127
+ const blob = await response.blob();
128
+
129
+ // Check if FileReader is available
130
+ if (typeof FileReader !== 'undefined') {
131
+ return new Promise((resolve, reject) => {
132
+ const reader = new FileReader();
133
+ reader.onloadend = () => resolve(reader.result);
134
+ reader.onerror = reject;
135
+ reader.readAsDataURL(blob);
136
+ });
137
+ } else {
138
+ console.warn('FileReader not available, falling back to Node.js methods');
139
+ // Continue to Node.js methods
140
+ }
141
+ } catch (browserError) {
142
+ console.error('Browser fetch error:', browserError);
143
+ // Fall back to Node.js method if browser method fails
144
+ }
145
+ }
146
+
147
+ // Node.js environment handling
148
+ try {
149
+ // Dynamic import for Node.js modules
150
+ const fs = await import('fs').catch(() => require('fs'));
151
+ const path = await import('path').catch(() => require('path'));
152
+
153
+ // Check if URL is a file path or an actual URL
154
+ if (url.startsWith('http://') || url.startsWith('https://')) {
155
+ // For HTTP URLs, use Node.js http/https modules
156
+ let http, https;
157
+ try {
158
+ https = await import('https').catch(() => require('https'));
159
+ http = await import('http').catch(() => require('http'));
160
+ } catch (importError) {
161
+ console.error('Failed to import http/https modules:', importError);
162
+ return null;
163
+ }
164
+
165
+ return new Promise((resolve, reject) => {
166
+ const client = url.startsWith('https') ? https : http;
167
+ const request = client.get(url, (response) => {
168
+ if (response.statusCode < 200 || response.statusCode >= 300) {
169
+ return reject(new Error(`HTTP Status Code: ${response.statusCode}`));
170
+ }
171
+
172
+ const data = [];
173
+ response.on('data', (chunk) => data.push(chunk));
174
+ response.on('end', () => {
175
+ const buffer = Buffer.concat(data);
176
+ const base64 = `data:${response.headers['content-type'] || 'image/jpeg'};base64,${buffer.toString('base64')}`;
177
+ resolve(base64);
178
+ });
179
+ });
180
+
181
+ request.on('error', (err) => {
182
+ console.error('HTTP request error:', err);
183
+ reject(err);
184
+ });
185
+ });
186
+ } else {
187
+ // For local files
188
+ try {
189
+ const localFilePath = url.startsWith('file://') ? url.slice(7) : url;
190
+ const buffer = fs.readFileSync(localFilePath);
191
+ const extension = path.extname(localFilePath).toLowerCase().substring(1);
192
+ const mimeType = {
193
+ 'png': 'image/png',
194
+ 'jpg': 'image/jpeg',
195
+ 'jpeg': 'image/jpeg',
196
+ 'gif': 'image/gif',
197
+ 'webp': 'image/webp'
198
+ }[extension] || 'image/jpeg';
199
+
200
+ return `data:${mimeType};base64,${buffer.toString('base64')}`;
201
+ } catch (fileError) {
202
+ console.error('Error reading local file:', fileError);
203
+ throw fileError;
204
+ }
205
+ }
206
+ } catch (nodeError) {
207
+ console.error('Node.js specific error:', nodeError);
208
+ throw nodeError;
209
+ }
210
+ } catch (error) {
211
+ console.error('Error converting image to Base64:', error);
212
+ return null;
213
+ }
214
+ };
215
+ export function convertSVGTableToAutoTableData(items) {
216
+ // Cabeçalhos da tabela
217
+ const headers = ['ID', 'Nome', 'Qtd', 'Dimensões'];
218
+
219
+ // Dados formatados para o autoTable
220
+ const rows = items.map(item => [
221
+ item.id,
222
+ item.name,
223
+ item.quantity,
224
+ item.dimensions
225
+ ]);
226
+
227
+ return { headers, rows };
228
+ }
229
+
230
+ /**
231
+ * Generates an SVG table from item list
232
+ * @param {Array} items - Array of items to display in table
233
+ * @param {Object} options - Configuration options for the table
234
+ * @returns {string} SVG string representation of the table
235
+ */
236
+ export function generateTableSVG(items, options = {}) {
237
+ if (!items || !Array.isArray(items)) {
238
+ return '';
239
+ }
240
+
241
+ const {
242
+ width = 200,
243
+ height = 100,
244
+ cellPadding = 5,
245
+ fontSize = 12,
246
+ headerColor = '#f0f0f0',
247
+ borderColor = '#000000'
248
+ } = options;
249
+
250
+ const headers = ['ID', 'Nome', 'Qtd', 'Dimensões'];
251
+ const cellWidth = width / headers.length;
252
+ const rowHeight = 20;
253
+
254
+ let svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">`;
255
+
256
+ // Header row
257
+ svg += `<rect x="0" y="0" width="${width}" height="${rowHeight}" fill="${headerColor}" stroke="${borderColor}" stroke-width="1"/>`;
258
+
259
+ headers.forEach((header, index) => {
260
+ const x = index * cellWidth + cellPadding;
261
+ const y = rowHeight / 2 + fontSize / 3;
262
+ svg += `<text x="${x}" y="${y}" font-size="${fontSize}" font-weight="bold" fill="black">${header}</text>`;
263
+ });
264
+
265
+ // Data rows
266
+ items.forEach((item, rowIndex) => {
267
+ const y = (rowIndex + 1) * rowHeight;
268
+ svg += `<rect x="0" y="${y}" width="${width}" height="${rowHeight}" fill="white" stroke="${borderColor}" stroke-width="1"/>`;
269
+
270
+ const rowData = [item.id, item.name, item.quantity, item.dimensions];
271
+ rowData.forEach((data, colIndex) => {
272
+ const x = colIndex * cellWidth + cellPadding;
273
+ const textY = y + rowHeight / 2 + fontSize / 3;
274
+ svg += `<text x="${x}" y="${textY}" font-size="${fontSize}" fill="black">${data || ''}</text>`;
275
+ });
276
+ });
277
+
278
+ svg += '</svg>';
279
+ return svg;
280
+ }
@@ -0,0 +1,123 @@
1
+ import { createLabelsGenerator } from './createLabel.js';
2
+
3
+ /**
4
+ * Worker class for handling label generation without UI
5
+ * Uses the createLabelsGenerator from createLabel.jsx
6
+ */
7
+ export class LabelWorker {
8
+ constructor() {
9
+ this.isGenerating = false;
10
+ this.currentGenerator = null;
11
+ this.progressCallback = null;
12
+ }
13
+
14
+ /**
15
+ * Generate labels using the generator pattern
16
+ * @param {Object} params - Parameters for label generation
17
+ * @param {Array} params.dataSource - Array of data for labels
18
+ * @param {Array} params.labels - Label configuration
19
+ * @param {Object} params.userPrefs - User preferences
20
+ * @param {Array} params.sheets - Sheet data
21
+ * @param {string} params.group - Group identifier
22
+ * @param {string} params.labelId - Label identifier
23
+ * @param {string} params.cacheKey - Cache key for the operation
24
+ * @param {Object} params.sheetsByPartCode - Sheets indexed by part code
25
+ * @param {Function} progressCallback - Callback for progress updates
26
+ * @returns {Promise} Promise that resolves with the generated PDF
27
+ */
28
+ async generateLabels(params, progressCallback = null) {
29
+ if (this.isGenerating) {
30
+ throw new Error('Label generation already in progress');
31
+ }
32
+
33
+ this.isGenerating = true;
34
+ this.progressCallback = progressCallback;
35
+
36
+ try {
37
+ this.currentGenerator = createLabelsGenerator(params);
38
+
39
+ let result;
40
+ let done = false;
41
+
42
+ while (!done) {
43
+ const { value, done: generatorDone } = await this.currentGenerator.next();
44
+ done = generatorDone;
45
+
46
+ if (!done && value) {
47
+ const [percentage, cacheKey, pdfInstance] = value;
48
+
49
+ // Call progress callback if provided
50
+ if (this.progressCallback) {
51
+ this.progressCallback({
52
+ percentage,
53
+ cacheKey,
54
+ pdfInstance
55
+ });
56
+ }
57
+ } else if (done && value) {
58
+ result = value;
59
+ }
60
+ }
61
+
62
+ return result;
63
+ } catch (error) {
64
+ console.error('Error generating labels:', error);
65
+ throw error;
66
+ } finally {
67
+ this.isGenerating = false;
68
+ this.currentGenerator = null;
69
+ this.progressCallback = null;
70
+ }
71
+ }
72
+
73
+
74
+
75
+ /**
76
+ * Cancel the current label generation
77
+ */
78
+ cancel() {
79
+ if (this.currentGenerator) {
80
+ this.currentGenerator.return();
81
+ this.currentGenerator = null;
82
+ }
83
+ this.isGenerating = false;
84
+ this.progressCallback = null;
85
+ }
86
+
87
+ /**
88
+ * Check if generation is currently in progress
89
+ * @returns {boolean} True if generation is in progress
90
+ */
91
+ isInProgress() {
92
+ return this.isGenerating;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Create a new instance of LabelWorker
98
+ * @returns {LabelWorker} New worker instance
99
+ */
100
+ export const createLabelWorker = () => {
101
+ return new LabelWorker();
102
+ };
103
+
104
+ /**
105
+ * Utility function to generate labels with data from useLabelData hook
106
+ * @param {Object} labelData - Data from useLabelData hook
107
+ * @param {Object} additionalParams - Additional parameters for generation
108
+ * @param {Function} progressCallback - Progress callback
109
+ * @returns {Promise} Promise that resolves with generated PDF
110
+ */
111
+ export const generateLabelsFromHookData = async (labelData, additionalParams = {}, progressCallback = null) => {
112
+ const worker = createLabelWorker();
113
+ console.log("labelData =>>>>>",labelData)
114
+ const params = {
115
+ dataSource: labelData.data || [],
116
+ labels: labelData.label || [],
117
+ userPrefs: labelData.userPrefs || {},
118
+ cacheKey: labelData.cacheKey,
119
+ ...additionalParams
120
+ };
121
+
122
+ return await worker.generateLabels(params, progressCallback);
123
+ };
package/src/reducer.js ADDED
@@ -0,0 +1,40 @@
1
+ export const initialState = {
2
+ type: "parts",
3
+ index: 0,
4
+ specific: false,
5
+ dataIndex: null,
6
+ source: null,
7
+ otherData: null,
8
+ category: [],
9
+ };
10
+ export function reducer(state, action) {
11
+ switch (action.type) {
12
+ case "CHANGE_INDEX":
13
+ return { ...state, index: action.payload.index };
14
+ case "CHANGE_TYPE":
15
+ return {
16
+ ...state,
17
+ type: action.payload.type,
18
+ specific: false,
19
+ source: null,
20
+ category: [],
21
+ index: 0,
22
+ };
23
+ //return {...state.components,...action.payload};
24
+ case "CHANGE_TO_SPECIFIC":
25
+ return {
26
+ ...state,
27
+ type: action.payload.type,
28
+ dataIndex: action.payload.source ? null : action.payload.dataIndex,
29
+ index: 0,
30
+ source: action.payload.source ? action.payload.source : null,
31
+ category: action.payload.category ? action.payload.category : [],
32
+ otherData: action.payload.otherData ? action.payload.otherData : null,
33
+ specific: true,
34
+ };
35
+ case "RESET":
36
+ return initialState;
37
+ default:
38
+ return state;
39
+ }
40
+ }
package/src/store.js ADDED
@@ -0,0 +1,55 @@
1
+ import {create} from 'zustand';
2
+
3
+ const useLabelStore = create((set, get) => ({
4
+ // PDF Instance and basic data
5
+ pdfInstance: null,
6
+ cacheKey: null,
7
+ labelType: null,
8
+ isGenerating: false,
9
+ progress: 0,
10
+ error: null,
11
+
12
+ // Label data
13
+ currentData: null,
14
+ currentConfig: null,
15
+
16
+ // Setters
17
+ setPDFInstance: (pdfInstance, cacheKey, labelType) => set({
18
+ pdfInstance,
19
+ cacheKey,
20
+ labelType
21
+ }),
22
+
23
+ setGenerating: (isGenerating) => set({ isGenerating }),
24
+
25
+ setProgress: (progress) => set({ progress }),
26
+
27
+ setError: (error) => set({ error }),
28
+
29
+ setCurrentData: (data) => set({ currentData: data }),
30
+
31
+ setCurrentConfig: (config) => set({ currentConfig: config }),
32
+
33
+ // Reset function
34
+ resetPDFInstance: () => set({
35
+ pdfInstance: null,
36
+ cacheKey: null,
37
+ labelType: null,
38
+ progress: 0,
39
+ error: null
40
+ }),
41
+
42
+ // Reset all
43
+ reset: () => set({
44
+ pdfInstance: null,
45
+ cacheKey: null,
46
+ labelType: null,
47
+ isGenerating: false,
48
+ progress: 0,
49
+ error: null,
50
+ currentData: null,
51
+ currentConfig: null
52
+ }),
53
+ }));
54
+
55
+ export default useLabelStore;