diff --git a/src/Generator.jsx b/src/Generator.jsx
index b0647af..7a1f14e 100644
--- a/src/Generator.jsx
+++ b/src/Generator.jsx
@@ -1,6 +1,6 @@
import { useState, useRef, useEffect } from 'react';
import './Generator.css';
-import { renderQRCode, downloadIDCards, downloadBulkIDCards, getXLSXLib } from './script/script.jsx';
+import { renderQRCode, downloadIDCards, downloadBulkIDCards, getXLSXLib, clientTemplates } from './script/script.jsx';
import { uploadEmployeePhoto } from './services/storage.js';
import { supabase } from "./services/supabase";
@@ -148,11 +148,11 @@ export default function IdCardGenerator() {
};
// --- ALMACENAMIENTO AUTOMÁTICO EN EL STORAGE E INSTANCIACIÓN RPC ---
- const handleBulkSupabasePhotoSync = async (cedula, blobData) => {
+ const handleBulkSupabasePhotoSync = async (cedula, blobData, clientKey = '') => {
const cleanCedula = String(cedula).replace(/[-\s]/g, '');
try {
const customFile = new File([blobData], `${cleanCedula}.jpg`, { type: 'image/jpeg' });
- const remoteStorageUrl = await uploadEmployeePhoto(cleanCedula, customFile);
+ const remoteStorageUrl = await uploadEmployeePhoto(cleanCedula, customFile, clientKey);
if (remoteStorageUrl) {
const { data, error } = await supabase.rpc("save_employee_photo", {
@@ -354,7 +354,7 @@ export default function IdCardGenerator() {
if (!validateForm()) return;
try {
if (photoFile) {
- const photoUrl = await uploadEmployeePhoto(employeeId, photoFile);
+ const photoUrl = await uploadEmployeePhoto(employeeId, photoFile, selectedClient);
await supabase.rpc("save_employee_photo", {
p_employee_number: employeeId,
p_photo_url: photoUrl
@@ -557,7 +557,13 @@ export default function IdCardGenerator() {
Reverso
-
+
diff --git a/src/script/script.jsx b/src/script/script.jsx
index 983cda1..112416a 100644
--- a/src/script/script.jsx
+++ b/src/script/script.jsx
@@ -330,7 +330,7 @@ export async function downloadBulkIDCards({ employees, baseUrl, onStateChange, o
if (blobData) {
validatedPhotoUrl = URL.createObjectURL(blobData);
if (onProcessEmployeePhoto) {
- await onProcessEmployeePhoto(strictCleanId, blobData);
+ await onProcessEmployeePhoto(strictCleanId, blobData, emp.selectedClient || '');
}
}
} catch (err) {
diff --git a/src/services/storage.js b/src/services/storage.js
index d6e59c3..15e455f 100644
--- a/src/services/storage.js
+++ b/src/services/storage.js
@@ -1,21 +1,59 @@
import { supabase } from "./supabase";
-export async function uploadEmployeePhoto(employeeNumber, file) {
+/**
+ * Sube la foto de un empleado al bucket "foto_empleados".
+ *
+ * El nombre del archivo sigue el patrón:
+ *
_.jpg — primera foto
+ * _1.jpg — segunda foto del mismo empleado+cliente
+ * _2.jpg — tercera, etc.
+ *
+ * @param {string} employeeNumber - Número de cédula limpio (sin guiones/espacios)
+ * @param {File} file - Archivo de imagen a subir
+ * @param {string} [clientKey=''] - Nombre del cliente/proyecto (p.ej. "claro", "nestle")
+ * @returns {Promise} - URL pública del archivo subido
+ */
+export async function uploadEmployeePhoto(employeeNumber, file, clientKey = '') {
+ const extension = file.name.split('.').pop() || 'jpg';
- const extension = file.name.split(".").pop();
+ // Normalizar el nombre del cliente: minúsculas, sin espacios ni caracteres especiales
+ const safeClient = clientKey
+ ? '_' + clientKey.toLowerCase().replace(/[^a-z0-9]/g, '')
+ : '';
- const fileName = `${employeeNumber}.${extension}`;
+ const baseName = `${employeeNumber}${safeClient}`;
+
+ // Buscar archivos existentes con el mismo prefijo para elegir el sufijo correcto
+ const { data: existingFiles } = await supabase.storage
+ .from('foto_empleados')
+ .list('', { search: baseName });
+
+ // Filtrar exactamente los archivos que tengan el mismo baseName base
+ const pattern = new RegExp(`^${baseName}(\\d*)\\.${extension}$`);
+ const matches = (existingFiles || []).filter(f => pattern.test(f.name));
+
+ let fileName;
+ if (matches.length === 0) {
+ // No existe ninguno: usar el nombre base sin sufijo numérico
+ fileName = `${baseName}.${extension}`;
+ } else {
+ // Extraer los sufijos numéricos usados y elegir el siguiente
+ const usedSuffixes = matches.map(f => {
+ const m = f.name.match(pattern);
+ return m ? parseInt(m[1] || '0', 10) : 0;
+ });
+ const nextSuffix = Math.max(...usedSuffixes) + 1;
+ fileName = `${baseName}${nextSuffix}.${extension}`;
+ }
const { error } = await supabase.storage
- .from("foto_empleados")
- .upload(fileName, file, {
- upsert: false
- });
+ .from('foto_empleados')
+ .upload(fileName, file, { upsert: false });
if (error) throw error;
const { data } = supabase.storage
- .from("foto_empleados")
+ .from('foto_empleados')
.getPublicUrl(fileName);
return data.publicUrl;