MERAKI
Estética & Bienestar
Cargando datos...
✦ Estética & Bienestar ✦

Tu piel merece
lo mejor

Tratamientos faciales y corporales con la más alta capacitación y los mejores productos del mercado.

🌸

Faciales

💆

Corporales

Depilación

Créditos

💎

Golden

🎁

Regalos

🔔

¿Querés recibir las promos?

Registrate y te avisamos por WhatsApp cuando haya novedades, descuentos y turnos disponibles. ¡Sin reservar turno!

Nuestros Tratamientos

Diseñados para
realzar tu belleza

Profesionales certificadas, productos de calidad y técnicas de vanguardia.

Agenda Especial

Días de Depilación

Días limitados. Seleccioná la fecha y reservá tu turno directamente acá.

Agendá tu turno

Reserva de tratamientos

Turnos de 1 hora, de 9 a 21 hs.

Programa de Fidelidad

Meraki Créditos

Cada tratamiento suma puntos que podés canjear por servicios o productos.

TUS PUNTOS
Consultá en cada visita
Los créditos nunca vencen.

Cómo ganar puntos

ServicioPuntos

Canjeá tus puntos

PremioCosto
Membresía Premium

Meraki Golden

Invertí en tu bienestar con paquetes extendidos.

Para Regalar

Tarjetas Regalo

Regalá una experiencia única.

Meraki
Sobre Nosotros

La pasión que
nos mueve

En Meraki entendemos que el cuidado de la piel es mucho más que estética: es bienestar, confianza y amor propio.

Nuestro equipo se capacita continuamente. Cada clienta es única y cada tratamiento se adapta a sus necesidades.

Encontranos

¿Dónde estamos?

📍

San Juan, Argentina

Estética Meraki — encontranos en Google Maps

🗺️ Abrir en Google Maps

Funciona en todos los navegadores — Chrome, Firefox, Safari y en el celular

📍 San Juan, Argentina | ⏰ Lun a Vie 9 a 21 hs | Sáb 9 a 17 hs

💡 Actualizá el mapa desde Admin → Configuración.

¡Consultanos! +total.toLocaleString('es-AR')+'' +'' +'' :''; cont.innerHTML='
' +'

🧮 Simulador de precio

' +'

Seleccioná las zonas para ver el total estimado

' +selHtml +detalle +(detalle?'':'') +'
'; } function toggleSimZona(nombre){ var idx=_simZonas.indexOf(nombre); if(idx>=0)_simZonas.splice(idx,1);else _simZonas.push(nombre); renderSimuladorDep(); } function renderDepDates(){var g=document.getElementById('dep-dates-grid');if(!g)return;if(!D.depil.fechas.length){g.innerHTML='

No hay fechas disponibles. Consultá por WhatsApp.

';document.getElementById('dep-form-wrap').classList.add('hidden');return;}g.innerHTML=D.depil.fechas.map(function(f){var dt=new Date(f+'T12:00:00');return'
'+dt.toLocaleDateString('es-AR',{day:'numeric'})+'
'+dt.toLocaleDateString('es-AR',{month:'long'})+'
'+dt.toLocaleDateString('es-AR',{weekday:'long'})+'
';}).join('');if(DB.sel)document.getElementById('dep-form-wrap').classList.remove('hidden');else document.getElementById('dep-form-wrap').classList.add('hidden');renderDepForm();} function selDep(f){DB.sel=f;DB.hora='';DB.step=1;renderDepDates();} function renderDepForm(){ var el=document.getElementById('dep-bk-area'); if(!el)return; if(!DB.sel||DB.step===0){ el.innerHTML='

👆 Seleccioná un día para comenzar.

'; return; } if(DB.step===4){ // ─── PASO 4: Confirmación final ─── var mpHtml=''; if(D.cfg.mpLink){ mpHtml='💳 Pagar seña en Mercado Pago
'+D.cfg.senal+(D.cfg.mpAlias?' — Alias: '+D.cfg.mpAlias:'')+'

'; } else if(D.cfg.mpAlias){ mpHtml='

💳 Pagar seña por Mercado Pago

Transferí '+D.cfg.senal+' al alias: '+D.cfg.mpAlias+'

'; } el.innerHTML='
' +'
' +'

¡Turno Confirmado!

' +'

' +DB.nombre.split(' ')[0]+', te esperamos el '+fd(DB.sel)+' a las '+DB.hora+' hs.' +'

' +mpHtml +'
' +'⚠️ El turno queda confirmado una vez acreditada la seña. ¡Gracias!' +'
' +'📅 Google Calendar
' +'' +'
'; return; } // ─── PASO 1-3: Formulario de reserva ─── // Zona/servicio selector var zonaHtml='' +''; // Datos personales var datosHtml='' +'' +''; // Señal + botón MP — bloquea el horario hasta confirmar var senalPagado=DB.senalPagada; var mpBtnHtml=''; if(D.cfg.mpLink){ mpBtnHtml='💳 Pagar '+D.cfg.senal+' en Mercado Pago'; } else if(D.cfg.mpAlias){ mpBtnHtml='
💳 Alias MP: '+D.cfg.mpAlias+'
Transferí '+D.cfg.senal+' para reservar
'; } var senalHtml='
' +'

💰 '+D.cfg.senalMsg+' '+D.cfg.senal+'

' +mpBtnHtml +'
' +'

📎 Adjuntá el comprobante de pago *

' +'

Captura de pantalla o foto del comprobante de transferencia / Mercado Pago

' +(DB.comprobante ?'
' +'' +'
✅ Comprobante cargado
' +'
' :'') +'
' +'' +'
' +'' +'
'; // Horarios — bloqueados hasta que se marque la seña var horaHtml=''; if(senalPagado){ horaHtml='' +'

⚫ Los horarios en gris ya están reservados.

' +'
'; var ocD=DB.sel?getSlotsOcupados(DB.sel,'dep'):{}; HORAS_DEP.forEach(function(h){if(ocD[h]){horaHtml+='
'+h+'
';}else{horaHtml+='
'+h+'
';}}); horaHtml+='
'; } else { horaHtml='
' +'

🔒 Primero abonás la seña de '+D.cfg.senal+'
y luego elegís el horario

' +'
'; } var btnConfirmar=senalPagado&&DB.hora ?'' :''; el.innerHTML='

📅 '+flong(DB.sel)+'

' +zonaHtml +datosHtml +senalHtml +horaHtml +btnConfirmar; } function confirmarPagoSenal(){ var check=document.getElementById('senal-check'); if(check&&check.checked&&!DB.comprobante){ check.checked=false; alert('⚠️ Primero tenés que subir el comprobante de pago antes de confirmar.'); return; } if(check){ DB.senalPagada=check.checked; } else { DB.senalPagada=true; } saveDepF(); renderDepForm(); } function confirmDep(){var dni=document.getElementById('db-dni').value.trim(),nom=document.getElementById('db-nom').value.trim(),tel=document.getElementById('db-tel').value.trim();if(!dni||!nom||!tel||!DB.hora){alert('Completá todos los campos y elegí el horario.');return;}var dbsv=document.getElementById('db-svc');if(dbsv)DB.servicio=dbsv.value;DB.dni=dni;DB.nombre=nom;DB.tel=tel;var ap={id:gid(),tipo:'depilacion',dni:dni,nombre:nom,telefono:tel,fecha:DB.sel,hora:DB.hora,servicio:DB.servicio||'A convenir',senal:'pendiente',comprobante:DB.comprobante||'',creado:new Date().toISOString()};D.depilAppts.push(ap);var ex=D.clients.find(function(c){return c.dni===dni;});if(!ex)D.clients.push({id:gid(),dni:dni,nombre:nom,telefono:tel,email:'',nacimiento:'',alergias:'',isNew:true,visitas:1,puntos:0,historial:[],creado:new Date().toISOString()});else ex.visitas=(ex.visitas||0)+1;var cliDB=D.clients.find(function(c){return c.dni===DB.dni;});if(cliDB){if(!cliDB.historial)cliDB.historial=[];cliDB.historial.push({id:gid(),fecha:DB.sel,servicio:DB.servicio||'Depilación',tipo:'depilacion',nota:'',creado:new Date().toISOString()});}save();DB.step=4;renderDepForm();// No redirige a WA — Cintia confirma manualmente desde el admin } var BK={step:1,dni:'',nom:'',tel:'',isNew:null,email:'',nac:'',alg:'',fecha:'',hora:'',servicio:''}; function renderBK(){var area=document.getElementById('bk-area');if(!area)return;var steps=['Datos','¿Primera vez?','Completar','Confirmar'];var sh='
'+steps.map(function(l,i){var n=i+1,c='sdot'+(BK.step>n?' done':BK.step===n?' active':'');return(i>0?'
':'')+'
'+(BK.step>n?'✓':n)+'
'+l+'
';}).join('')+'
';var b='';if(BK.step===1){b='

Tus datos de contacto

';}else if(BK.step===2){b='

¡Hola, '+BK.nom.split(' ')[0]+'!

¿Es tu primera vez en Meraki?

✨ Sí, primera vez
Soy clienta habitual 💛
';}else if(BK.step===3){b='

'+(BK.isNew?'Tu perfil y turno':'Elegí tu turno')+'

'+(BK.isNew?'
💖 ¡Bienvenida! Necesitamos datos extra para cuidarte mejor.
':'')+ '
'+(function(){var oc=BK.fecha?getSlotsOcupados(BK.fecha,'trat'):{};var dur=getDuracion(BK.servicio);return HORAS.map(function(h){var ini=horaAMins(h),bl=false;for(var m=ini;m21*60+1)bl=true;if(bl)return'
'+h+'
';return'
'+h+'
';}).join('');})()+'
';}else if(BK.step===4){b='
🌸

¡Turno reservado!

Nos vemos el '+fd(BK.fecha)+' a las '+BK.hora+' hs.

👤'+BK.nom+'
📅'+fd(BK.fecha)+' — '+BK.hora+' hs
📱'+BK.tel+'
📅 Google Calendar
';}area.innerHTML=sh+b;} function bkN1(){var d=document.getElementById('f-dni').value.trim(),n=document.getElementById('f-nom').value.trim(),t=document.getElementById('f-tel').value.trim();if(!d||!n||!t){alert('Completá todos los campos (*)');return;}BK.dni=d;BK.nom=n;BK.tel=t;BK.step=2;renderBK();} function bkN2(){if(BK.isNew===null){alert('Seleccioná una opción.');return;}BK.step=3;renderBK();} function bkN3(){if(BK.isNew){var em=document.getElementById('f-email'),nc=document.getElementById('f-nac'),ag=document.getElementById('f-alg');if(em)BK.email=em.value.trim();if(nc)BK.nac=nc.value;if(ag)BK.alg=ag.value.trim();if(!BK.email||!BK.nac){alert('Completá email y fecha de nacimiento.');return;}}var fd2=document.getElementById('f-fecha');if(fd2)BK.fecha=fd2.value;var fsv=document.getElementById('f-svc');if(fsv)BK.servicio=fsv.value;if(!BK.fecha||!BK.hora){alert('Seleccioná fecha y horario.');return;}var ap={id:gid(),tipo:'tratamiento',dni:BK.dni,nombre:BK.nom,telefono:BK.tel,isNew:BK.isNew,email:BK.email,nacimiento:BK.nac,alergias:BK.alg,fecha:BK.fecha,hora:BK.hora,servicio:BK.servicio||'A convenir',creado:new Date().toISOString()};D.appts.push(ap);var ex=D.clients.find(function(c){return c.dni===BK.dni;});if(!ex)D.clients.push({id:gid(),dni:BK.dni,nombre:BK.nom,telefono:BK.tel,email:BK.email||'',nacimiento:BK.nac||'',alergias:BK.alg||'',isNew:BK.isNew,visitas:1,puntos:0,historial:[],creado:new Date().toISOString()});else{ex.visitas=(ex.visitas||0)+1;ex.nombre=BK.nom;ex.telefono=BK.tel;}var cliBK=D.clients.find(function(c){return c.dni===BK.dni;});if(cliBK){if(!cliBK.historial)cliBK.historial=[];cliBK.historial.push({id:gid(),fecha:BK.fecha,servicio:BK.servicio||'Tratamiento',tipo:'tratamiento',nota:'',creado:new Date().toISOString()});}save();BK.step=4;renderBK();} function openAdmin(){document.getElementById('adm-login').classList.remove('hidden');setTimeout(function(){document.getElementById('adm-pwd').focus();},80);} function closeAdmLogin(){document.getElementById('adm-login').classList.add('hidden');document.getElementById('adm-pwd').value='';document.getElementById('login-err').classList.add('hidden');} function tryLogin(){if(document.getElementById('adm-pwd').value===D.cfg.pass){closeAdmLogin();showAdmin();}else{document.getElementById('login-err').classList.remove('hidden');document.getElementById('adm-pwd').value='';document.getElementById('adm-pwd').focus();}} function logout(){document.body.classList.remove('admin-activo');document.getElementById('adm-panel').classList.add('hidden');} function showAdmin(){document.body.classList.add('admin-activo');document.getElementById('adm-panel').classList.remove('hidden');document.getElementById('adm-date').textContent=new Date().toLocaleDateString('es-AR',{weekday:'long',day:'numeric',month:'long',year:'numeric'});showS('dash',document.querySelector('.sb-item'));} var SNAMES={dash:'Dashboard',ia_asist:'Asistente IA',fin_ana:'Finanzas & Análisis',trat_ed:'Tratamientos y Duración',ag_t:'Agenda Tratamientos',ag_d:'Agenda Depilación',clients:'Base de Clientes',notif:'Notificaciones',svc_ed:'Editar Servicios',dep_ed:'Días de Depilación',pro_ed:'Promociones',gol_ed:'Pack Golden',gft_ed:'Tarjetas Regalo',crd_ed:'Meraki Créditos',foto_ed:'Fotos & Logo',txt_ed:'Editar Textos',cfg_ed:'Configuración',redes:'Redes Sociales & Contenido'}; function showS(sec,el){document.querySelectorAll('.sb-item').forEach(function(i){i.classList.remove('active');});if(el)el.classList.add('active');document.getElementById('adm-sec-title').textContent=SNAMES[sec]||sec;var fns={dash:rDash,ia_asist:rIAAsist,fin_ana:rFinAna,trat_ed:rTratEd,ag_t:rAgT,ag_d:rAgD,clients:rClients,notif:rNotif,svc_ed:rSvcEd,dep_ed:rDepEd,pro_ed:rProEd,gol_ed:rGolEd,gft_ed:rGftEd,crd_ed:rCrdEd,foto_ed:rFotoEd,txt_ed:rTxtEd,cfg_ed:rCfgEd,redes:rRedes};document.getElementById('adm-cont').innerHTML=(fns[sec]||function(){return'

En construcción

';})();} function sc2(n,l,sec){ var s='
'+l+'
'; if(sec){s+='
Ver detalle →
';} s+='
'; return s; } function goAdmin(el){ var sec=el.getAttribute('data-sec'); if(!sec)return; var items=document.querySelectorAll('.sb-item'); for(var k=0;k=0){showS(sec,items[k]);return;} } showS(sec,null); } function goAdmin(sec){ var items=document.querySelectorAll('.sb-item'); items.forEach(function(el){ if(el.getAttribute('onclick')&&el.getAttribute('onclick').indexOf("'"+sec+"'")>=0){ showS(sec,el); } }); } function aTbl(list,ed){if(!list.length)return'

Sin turnos registrados.

';return''+list.map(function(a){var dep=a.tipo==='depilacion';var cBtn=a.confirmado?'✅ Confirmado':''; return'';}).join('')+'
NombreDNIServicioFechaHoraEstadoTeléfonoAcciones
'+a.nombre+''+a.dni+''+(a.servicio&&a.servicio!='A convenir'?a.servicio:'A convenir')+''+fd(a.fecha)+''+a.hora+''+cBtn+''+a.telefono+'📅'+(ed?'':'')+'
';} function rDash(){ var today=new Date().toISOString().slice(0,10),nh=new Date().getHours(); var ta=D.appts.filter(function(a){return a.fecha===today;}); var da=D.depilAppts.filter(function(a){return a.fecha===today;}); var rem=[].concat(D.appts,D.depilAppts).filter(function(a){ return a.fecha===today&&parseInt(a.hora)===nh+1; }); var remHtml=rem.length ?'

⏰ Recordatorios — próxima hora

' +rem.map(function(a){ var btnRem=''; return '
' +''+a.nombre+' — '+a.hora+'hs'+(a.tipo==='depilacion'?' (Dep.)':'')+'' +btnRem+'
'; }).join('')+'
' :'
✅ Sin recordatorios urgentes
'; var sysHtml='
' +'
⏰ Recordatorios automáticos ACTIVOS
' +'
La app revisa cada minuto y abre WhatsApp automáticamente 1 hora antes de cada turno. La app tiene que estar abierta.
' +'
' +'
'; return '
'+sc2(D.appts.length,'Turnos Tratam.','ag_t')+sc2(D.depilAppts.length,'Turnos Depilac.','ag_d')+sc2(D.clients.length,'Clientes','clients')+sc2(ta.length+da.length,'Turnos Hoy',null)+'
' +sysHtml +remHtml +'

Últimas reservas

' +'
'+aTbl([].concat(D.appts,D.depilAppts).sort(function(a,b){return b.creado.localeCompare(a.creado);}).slice(0,7),false)+'
'; } function rAgT(){var s=[].concat(D.appts).sort(function(a,b){return(a.fecha+a.hora).localeCompare(b.fecha+b.hora);});return'
'+aTbl(s,true)+'
';} function rAgD(){ var s=[].concat(D.depilAppts).sort(function(a,b){return(a.fecha+a.hora).localeCompare(b.fecha+b.hora);}); var btnBar='
' +'' +'' +'' +'
'; if(!s.length){ // Auto-recargar después de 3 segundos por si los datos de la nube aún no llegaron setTimeout(function(){ var cont=document.getElementById('adm-cont'); if(cont&&cont.innerHTML.indexOf('Sin turnos')>=0) showS('ag_d',null); },3000); return btnBar+'
' +'⏳ Sin turnos de depilación visibles.
Si acabás de recibir una reserva, esperá 3 segundos o tocá 🔄 Recargar.
' +'Los datos se sincronizan desde la nube. Podés también agregar manualmente con ➕' +'
'; } var rows=s.map(function(a){ var compBtn=a.comprobante ?'' :'Sin imagen'; var confirmBtn=a.confirmado ?'✅ Confirmado' :''; return '' +''+a.nombre+'' +''+a.dni+'' +''+(a.servicio&&a.servicio!='A convenir'?a.servicio:'A convenir')+'' +''+fd(a.fecha)+'' +''+a.hora+'' +''+compBtn+'' +''+confirmBtn+'' +'' +'' +'📅' +'' +'' +'' +''; }).join(''); return btnBar +'
' +'' +'' +'' +''+rows+'
NombreDNIZona/ServicioFechaHora📎 ComprobanteEstadoAcciones
' +'
'; } function sndRem(id){var a=[].concat(D.appts,D.depilAppts).find(function(x){return x.id===id;});if(!a)return;waO(a.telefono,'Hola '+a.nombre.split(' ')[0]+'! 🌸 Te recordamos tu turno '+(a.tipo==='depilacion'?'de depilación ':'')+' en Meraki: '+fd(a.fecha)+' a las '+a.hora+' hs'+(a.servicio&&a.servicio!='A convenir'?' ('+a.servicio+')':'')+'. ¡Te esperamos! ✨ — Meraki');} function delAppt(id,tipo){if(!confirm('¿Eliminar este turno?'))return;if(tipo==='depilacion')D.depilAppts=D.depilAppts.filter(function(a){return a.id!==id;});else D.appts=D.appts.filter(function(a){return a.id!==id;});save();showS(tipo==='depilacion'?'ag_d':'ag_t',null);} function modalAddAppt(tipo){var dep=tipo==='d';var fh=dep&&D.depil.fechas.length?''+lbl('',''):'';openMod('

Agregar turno — '+(dep?'Depilación':'Tratamiento')+'

'+lbl('DNI *','')+lbl('Nombre completo *','')+lbl('Teléfono WhatsApp *','')+lbl('Fecha *',fh)+lbl('Servicio / Tratamiento','')+lbl('Horario *','') +'

⚠️ Los horarios ya reservados en la fecha elegida no se bloquean aquí, pero SÍ se bloquean en la app pública. Verificá en la agenda antes de agregar.

'+'
');} function saveManAppt(tipo){var dni=document.getElementById('ma-dni').value.trim(),nom=document.getElementById('ma-nom').value.trim(),tel=document.getElementById('ma-tel').value.trim(),fecha=document.getElementById('ma-f').value,hora=document.getElementById('ma-h').value;if(!dni||!nom||!tel||!fecha||!hora){alert('Completá todos los campos.');return;}var svcEl=document.getElementById('ma-svc');var apSvc=svcEl?svcEl.value:'A convenir';var ap={id:gid(),tipo:tipo==='d'?'depilacion':'tratamiento',dni:dni,nombre:nom,telefono:tel,fecha:fecha,hora:hora,servicio:apSvc,isNew:false,email:'',nacimiento:'',alergias:'',creado:new Date().toISOString()};if(tipo==='d')D.depilAppts.push(ap);else D.appts.push(ap);var ex=D.clients.find(function(c){return c.dni===dni;});if(!ex)D.clients.push({id:gid(),dni:dni,nombre:nom,telefono:tel,email:'',nacimiento:'',alergias:'',isNew:false,visitas:1,puntos:0,creado:new Date().toISOString()});else ex.visitas=(ex.visitas||0)+1;save();closeMod();showS(tipo==='d'?'ag_d':'ag_t',null);setTimeout(function(){if(typeof XLSX!=='undefined')exportarExcel(false);},500);} function editAppt(id,tipo){var a=[].concat(D.appts,D.depilAppts).find(function(x){return x.id===id;});if(!a)return;openMod('

Editar turno

'+lbl('DNI','')+lbl('Nombre','')+lbl('Teléfono','')+lbl('Fecha','')+lbl('Servicio / Tratamiento','')+lbl('Horario','')+'
');} function updAppt(id,tipo){var list=tipo==='depilacion'?D.depilAppts:D.appts,a=list.find(function(x){return x.id===id;});if(!a)return;a.dni=document.getElementById('ea-dni').value.trim()||a.dni;a.nombre=document.getElementById('ea-nom').value.trim()||a.nombre;a.telefono=document.getElementById('ea-tel').value.trim()||a.telefono;a.fecha=document.getElementById('ea-f').value||a.fecha;a.hora=document.getElementById('ea-h').value||a.hora;var eas=document.getElementById('ea-svc');if(eas)a.servicio=eas.value;save();closeMod();showS(tipo==='depilacion'?'ag_d':'ag_t',null);} function rClients(){ var rows=D.clients.length?D.clients.map(function(c){ var hist=c.historial||[]; // Count total visits from historial + agenda (deduped via historial sync) var totalVisitas=hist.length||(c.visitas||0); // Get last visit from all sources var lastV=getUltimaVisitaCliente(c); return '' +''+c.nombre+'' +''+c.dni+'' +''+c.telefono+'' +''+(c.email||'—')+'' +''+(c.nacimiento?fd(c.nacimiento):'—')+'' +''+(c.alergias||'—')+'' +''+totalVisitas+'' +''+(lastV?fd(lastV):'—')+'' +'
'+(c.puntos||0)+'
' +''+(c.isNew?'Nueva':'Habitual')+'' +'' +'' +'' +'' +'' +'' +''; }).join(''):'Sin clientes'; return '
' +'

'+D.clients.length+' clientes. 📋 = Historial de visitas.

' +'
' +'' +''+rows+'
NombreDNITeléfonoEmailNacimientoAlergiasVisitasÚltima visita★ PtsTipoAcciones
'; } function sincronizarHistorialDesdeAgenda(c){ // Sincroniza turnos reales de las agendas al historial del cliente if(!c.historial)c.historial=[]; var idsExistentes=c.historial.map(function(h){return h.id||'';}); var cambios=0; [].concat(D.appts||[],D.depilAppts||[]).forEach(function(a){ if(a.dni!==c.dni&&a.telefono!==c.telefono) return; // Verificar si ya está en historial (por id de turno o por fecha+servicio) var yaExiste=c.historial.some(function(h){return h.apptId===a.id||(h.fecha===a.fecha&&h.servicio===a.servicio&&h.tipo===a.tipo);}); if(!yaExiste){ c.historial.push({id:gid(),apptId:a.id,fecha:a.fecha,servicio:a.servicio||'Servicio',tipo:a.tipo||'tratamiento',nota:'',creado:a.creado||new Date().toISOString(),fromAgenda:true}); cambios++; } }); // Ordenar por fecha c.historial.sort(function(a,b){return new Date(b.fecha)-new Date(a.fecha);}); if(cambios>0) save(); return cambios; } function verHistorial(dni){ var c=D.clients.find(function(x){return x.dni===dni;}); if(!c)return; if(!c.historial)c.historial=[]; // Auto-sincronizar con agendas var sincronizados=sincronizarHistorialDesdeAgenda(c); var ultimaVisita=c.historial.length?c.historial[0]:null; var ultimaStr=ultimaVisita?(''+fd(ultimaVisita.fecha)+' — '+ultimaVisita.servicio):'Sin visitas registradas'; var rows=c.historial.length ?c.historial.map(function(h,i){ return '
' +'
' +'
'+fd(h.fecha)+'
' +'
'+h.servicio+'
' +(h.tipo==='depilacion'?'⚡ Depilación':'🌸 Tratamiento') +(h.fromAgenda?'📅 desde agenda':'') +'
' +'' +'
' +'' +'' +'
'; }).join('') :'
Sin visitas registradas aún.
'; openMod('

📋 Historial — '+c.nombre+'

' +'
' +'
📅 ÚLTIMA VISITA
' +'
'+ultimaStr+'
' +'
'+c.historial.length+' visita'+( c.historial.length!==1?'s':'')+' registrada'+( c.historial.length!==1?'s':'')+' en total'+(sincronizados>0?' · '+sincronizados+' sincronizada'+( sincronizados!==1?'s':'')+' desde agenda':' · al día')+'
' +'
' +'' +rows +''); } function saveNota(dni,idx){ var c=D.clients.find(function(x){return x.dni===dni;});if(!c||!c.historial)return; var ta=document.getElementById('nota-'+idx);if(ta)c.historial[idx].nota=ta.value.trim(); save();alert('✅ Nota guardada.'); } function delHistorial(dni,idx){ if(!confirm('¿Eliminar esta visita del historial?'))return; var c=D.clients.find(function(x){return x.dni===dni;});if(!c||!c.historial)return; c.historial.splice(idx,1); save();verHistorial(dni); } function modalAddHistorial(dni){ openMod('

Agregar visita manualmente

' +lbl('Fecha de la visita','') +lbl('Servicio / Tratamiento','') +lbl('Tipo','') +lbl('Nota (opcional)','') +'
' +'' +'' +'
'); } function saveAddHistorial(dni){ var c=D.clients.find(function(x){return x.dni===dni;});if(!c)return; if(!c.historial)c.historial=[]; var f=document.getElementById('ah-f').value; var s=document.getElementById('ah-s').value; var t=document.getElementById('ah-t').value; var n=document.getElementById('ah-n').value.trim(); if(!f||!s){alert('Completá la fecha y el servicio.');return;} c.historial.push({id:gid(),fecha:f,servicio:s,tipo:t,nota:n,creado:new Date().toISOString()}); c.visitas=(c.visitas||0)+1; save();verHistorial(dni); } function chgPts(id,dni,delta){var c=D.clients.find(function(x){return x.id===id||x.dni===dni;});if(!c)return;c.puntos=Math.max(0,(c.puntos||0)+delta);save();showS('clients',null);} function waClient(tel,nom){waO(tel,'Hola '+nom.split(' ')[0]+'! 🌸 Te escribe el equipo de Estética Meraki. ¿En qué podemos ayudarte?');} function delClient(dni){if(!confirm('¿Eliminar este cliente?'))return;D.clients=D.clients.filter(function(c){return c.dni!==dni;});save();showS('clients',null);} function modalAddClient(){openMod('

Agregar cliente

'+lbl('DNI *','')+lbl('Nombre completo *','')+lbl('Teléfono WhatsApp *','')+lbl('Email','')+lbl('Fecha de Nacimiento','')+lbl('Puntos iniciales','')+lbl('Alergias / Notas médicas','')+'
');} function saveNewClient(){var dni=document.getElementById('ac-dni').value.trim(),nom=document.getElementById('ac-nom').value.trim(),tel=document.getElementById('ac-tel').value.trim();if(!dni||!nom||!tel){alert('DNI, nombre y teléfono son obligatorios.');return;}if(D.clients.find(function(c){return c.dni===dni;})){alert('Ya existe un cliente con ese DNI.');return;}D.clients.push({id:gid(),dni:dni,nombre:nom,telefono:tel,email:document.getElementById('ac-email').value.trim(),nacimiento:document.getElementById('ac-nac').value,alergias:document.getElementById('ac-alg').value.trim(),isNew:true,visitas:0,puntos:parseInt(document.getElementById('ac-pts').value)||0,historial:[],creado:new Date().toISOString()});save();closeMod();showS('clients',null);setTimeout(function(){if(typeof XLSX!=='undefined')exportarExcel(false);},500);} function modalEditClient(dni){var c=D.clients.find(function(x){return x.dni===dni;});if(!c)return;openMod('

Editar cliente

'+lbl('DNI','')+lbl('Nombre','')+lbl('Teléfono','')+lbl('Email','')+lbl('Nacimiento','')+lbl('Puntos','')+lbl('Alergias / Notas','')+'
');} function updClient(oldDni){var c=D.clients.find(function(x){return x.dni===oldDni;});if(!c)return;c.dni=document.getElementById('ec-dni').value.trim()||c.dni;c.nombre=document.getElementById('ec-nom').value.trim()||c.nombre;c.telefono=document.getElementById('ec-tel').value.trim()||c.telefono;c.email=document.getElementById('ec-email').value.trim();c.nacimiento=document.getElementById('ec-nac').value;c.alergias=document.getElementById('ec-alg').value.trim();c.puntos=parseInt(document.getElementById('ec-pts').value)||0;save();closeMod();showS('clients',null);setTimeout(function(){if(typeof XLSX!=='undefined')exportarExcel(false);},500);} function rNotif(){var def='Hola {nombre}! 🌸 Te escribimos desde Estética Meraki.\n\n'+D.promos.filter(function(p){return p.activa;}).map(function(p){return'✦ '+p.titulo+': '+p.texto;}).join('\n')+'\n\n¡Reservá tu turno hoy! 💛 — Meraki ✨';return'

📣 Enviar notificación masiva por WhatsApp

Abre WhatsApp con el mensaje personalizado para cada clienta. Tenés '+D.clients.length+' clientas registradas.

📌 Publicar nueva promo rápida

Se publica inmediatamente en el banner y popup.

'+lbl('Título','')+lbl('Descripción','')+'
';} function sendAll(){var msg=document.getElementById('notif-msg').value;if(!msg.trim()||!D.clients.length)return;if(!confirm('¿Enviar a '+D.clients.length+' clientas?'))return;D.clients.forEach(function(c,i){setTimeout(function(){waO(c.telefono,msg.replace('{nombre}',c.nombre.split(' ')[0]));},i*1100);});} function pubPromo(){var t=document.getElementById('np-t').value.trim(),x=document.getElementById('np-x').value.trim();if(!t||!x){alert('Completá los dos campos.');return;}D.promos.push({id:gid(),titulo:t,texto:x,activa:true});save();renderStrip();renderPop();alert('✅ Promoción publicada.');showS('notif',null);} function rSvcEd(){return'

Actualizá precios, nombres e imágenes. Podés agregar nuevos servicios a medida que Cintia se capacite.

'+D.svcs.map(function(s,i){return'
';}).join('')+'';} function saveSvcs(){D.svcs=D.svcs.map(function(s,i){return Object.assign({},s,{nombre:document.getElementById('sn-'+i).value,precio:document.getElementById('sp-'+i).value,desc:document.getElementById('sd-'+i).value,img:document.getElementById('si-'+i).value,cat:document.getElementById('sc-'+i).value,emoji:document.getElementById('se-'+i).value});});save();renderSvcs();alert('✅ Servicios guardados. Ya se ven en la app.');} function addSvc(){D.svcs.push({id:gid(),cat:'facial',nombre:'Nuevo Servicio',desc:'Descripción del tratamiento.',precio:'$0',emoji:'✨',img:'https://images.unsplash.com/photo-1570172619644-dfd03ed5d881?w=400&q=80'});showS('svc_ed',null);} function delSvc(i){if(!confirm('¿Eliminar este servicio?'))return;D.svcs.splice(i,1);save();renderSvcs();showS('svc_ed',null);} function rDepEd(){ var zonas=getDepilZonas(); var depSvcsHtml=zonas.map(function(z,i){ var svgPrev='
'+getSVGCuerpo(z)+'
'; return '
' +svgPrev +'
' +'' +'' +'' +'
' +'
'; }).join(''); var diasHtml=D.depil.fechas.map(function(f){ return ''+flong(f)+' '; }).join(''); return '

✂️ Zonas de Depilación + Precios

' +'

Editá nombre, precio e imagen de cada zona. El simulador de precio se actualiza en la web.

' +depSvcsHtml +'' +'' +'
' +'

📆 Días de Depilación

' +'

Agregá o eliminá fechas. Las clientas las ven y reservan directamente en la app.

' +'
'+diasHtml+'
' +lbl('Agregar nueva fecha','
') +'
' +'

✏️ Texto descriptivo de la sección

' +'' +'' +'
'; } function saveDepDesc(){D.depil.desc=document.getElementById('dep-desc').value;save();applyAll();alert('Guardado');} function addDepSvc(){D.depilServicios.push('Nuevo servicio');showS('dep_ed',null);} function addDepZona(){if(!D.depilZonas)D.depilZonas=getDepilZonas();D.depilZonas.push({nombre:'Nueva zona',precio:'',imagen:''});syncDepilServicios();showS('dep_ed',null);} function delDepSvc(i){D.depilServicios.splice(i,1);save();showS('dep_ed',null);} function delDepZona(i){if(!D.depilZonas)D.depilZonas=getDepilZonas();D.depilZonas.splice(i,1);syncDepilServicios();save();showS('dep_ed',null);} function addF(){var d=document.getElementById('nf').value;if(!d)return;if(D.depil.fechas.includes(d)){alert('Esta fecha ya está agregada.');return;}D.depil.fechas.push(d);D.depil.fechas.sort();save();renderDepDates();showS('dep_ed',null);} function rmF(f){D.depil.fechas=D.depil.fechas.filter(function(x){return x!==f;});save();renderDepDates();showS('dep_ed',null);} function rProEd(){return'

Activá/desactivá sin borrar. Los cambios se ven de inmediato en el banner y popup.

'+D.promos.map(function(p,i){return'
'+(p.activa?'✅ Activa':'⏸ Pausada')+'
';}).join('')+'';} function togP(i){D.promos[i].activa=!D.promos[i].activa;var b=document.getElementById('ptog-'+i);if(b){b.className='toggle'+(D.promos[i].activa?' on':'');b.nextElementSibling.textContent=D.promos[i].activa?'✅ Activa':'⏸ Pausada';}} function savePs(){D.promos=D.promos.map(function(p,i){return Object.assign({},p,{titulo:document.getElementById('pt-'+i).value,texto:document.getElementById('px-'+i).value});});save();renderStrip();renderPop();alert('✅ Promociones guardadas.');} function addP(){D.promos.push({id:gid(),titulo:'🆕 Nueva Promo',texto:'Descripción de la promoción...',activa:true});showS('pro_ed',null);} function delP(i){if(!confirm('¿Eliminar?'))return;D.promos.splice(i,1);save();showS('pro_ed',null);} function rGolEd(){return'

💎 Paquetes Meraki Golden

Actualizá los precios cada vez que cambien por inflación. Los cambios se ven al instante.

'+D.golden.packs.map(function(p,i){return'
';}).join('')+'

✏️ Texto descriptivo

';} function saveG(){D.golden.packs=D.golden.packs.map(function(p,i){return Object.assign({},p,{nombre:document.getElementById('gn-'+i).value,precio:document.getElementById('gp-'+i).value,ahorro:document.getElementById('ga-'+i).value,icono:document.getElementById('gi-'+i).value,desc:document.getElementById('gd-'+i).value});});save();renderGol();alert('✅ Packs Golden guardados.');} function addG(){D.golden.packs.push({icono:'💫',nombre:'Nuevo Pack',desc:'Descripción del pack.',precio:'$0',ahorro:'Consultá el ahorro'});showS('gol_ed',null);} function delG(i){if(!confirm('¿Eliminar?'))return;D.golden.packs.splice(i,1);save();renderGol();showS('gol_ed',null);} function rGftEd(){return'

🎁 Tarjetas Regalo

Editá montos y descripciones cuando cambien los precios.

'+D.gifts.cards.map(function(c,i){return'
';}).join('')+'

✏️ Texto descriptivo

';} function saveGfts(){D.gifts.cards=D.gifts.cards.map(function(c,i){return Object.assign({},c,{nombre:document.getElementById('gcn-'+i).value,monto:document.getElementById('gcm-'+i).value,desc:document.getElementById('gcd-'+i).value,icono:document.getElementById('gci-'+i).value});});save();renderGfts();alert('✅ Tarjetas guardadas.');} function addGft(){D.gifts.cards.push({icono:'🎁',nombre:'Nueva Tarjeta',monto:'$0',desc:'Descripción.',color:'linear-gradient(135deg,#f9eaef,#fce0ec)',ctxt:'#9a4a6a'});showS('gft_ed',null);} function delGft(i){if(!confirm('¿Eliminar?'))return;D.gifts.cards.splice(i,1);save();renderGfts();showS('gft_ed',null);} function rCrdEd(){return'

⭐ Puntos por servicio — Cómo se ganan

'+D.credits.earn.map(function(r,i){return'
';}).join('')+'

🎁 Tabla de canjes — Qué se puede canjear

'+D.credits.redeem.map(function(r,i){return'
';}).join('')+'
';} function saveCE(){D.credits.earn=D.credits.earn.map(function(r,i){return{s:document.getElementById('ces-'+i).value,p:document.getElementById('cep-'+i).value};});save();renderCr();alert('✅ Guardado.');} function saveCR(){D.credits.redeem=D.credits.redeem.map(function(r,i){return{p:document.getElementById('crp-'+i).value,c:document.getElementById('crc-'+i).value};});save();renderCr();alert('✅ Guardado.');} function rFotoEd(){return'

🖼️ Logo de Meraki

Subí una imagen del logo (PNG con fondo transparente es lo ideal). O usá texto.

'+(D.cfg.logoImg?'':''+D.cfg.logoTxt+'')+'

📷 Clic aquí para cargar la imagen del logo de Meraki

'+(D.cfg.logoImg?'':'')+lbl('Texto del logo (cuando no hay foto)','')+'

📷 Foto de "Sobre Nosotros"

Foto de Cintia, el equipo o el espacio del local.

📷 Subir foto del local o del equipo

'+lbl('O pegar URL de imagen de internet','')+'

🌟 Galería de tratamientos

Fotos de resultados, antes/después, del local o de tratamientos. Se guardan acá para mostrar.

'+D.galeria.map(function(g,i){return'
';}).join('')+'

+ Agregar foto

';} function readImg(inp,cb){if(!inp.files[0])return;var r=new FileReader();r.onload=function(e){cb(e.target.result);};r.readAsDataURL(inp.files[0]);} function upLogo(inp){readImg(inp,function(b){D.cfg.logoImg=b;save();applyAll();showS('foto_ed',null);});} function upAbout(inp){readImg(inp,function(b){D.about.photo=b;save();applyAll();showS('foto_ed',null);});} function upGal(inp){readImg(inp,function(b){D.galeria.push(b);save();showS('foto_ed',null);});} function saveLogoTxt(){D.cfg.logoTxt=document.getElementById('ltxt').value||'MERAKI';save();applyAll();alert('✅ Logo guardado.');} function saveAboutPh(){var u=document.getElementById('aphu').value.trim();if(u){D.about.photo=u;save();applyAll();alert('✅ Foto guardada.');}} function rTxtEd(){return'

🏠 Portada (sección Hero)

'+lbl('Badge (texto de la pastilla superior)','')+lbl('Título principal (usá <em> para texto en cursiva rosa)','')+lbl('Subtítulo','')+'

👩 Sección Sobre Nosotros

'+lbl('Título','')+lbl('Párrafo 1','')+lbl('Párrafo 2','')+lbl('Certificaciones y logros (una por línea — estas aparecen como las pastillas de color dorado)','')+'

🦶 Footer (pie de página)

'+lbl('Tagline / frase','')+lbl('Dirección del local','')+lbl('Horarios línea 1','')+lbl('Horarios línea 2','')+lbl('Horarios en sección Contacto','')+'
';} function saveHeroT(){D.hero.badge=document.getElementById('hb').value;D.hero.title=document.getElementById('ht').value;D.hero.sub=document.getElementById('hs').value;save();applyAll();alert('✅ Portada guardada.');} function saveAboutT(){D.about.title=document.getElementById('at').value;D.about.t1=document.getElementById('a1').value;D.about.t2=document.getElementById('a2').value;D.about.badges=document.getElementById('ab').value.split('\n').filter(function(b){return b.trim();});save();applyAll();alert('✅ Guardado.');} function saveFooterT(){D.cfg.ftag=document.getElementById('ftag').value;D.cfg.addr=document.getElementById('fadr').value;D.cfg.fh1=document.getElementById('fh1').value;D.cfg.fh2=document.getElementById('fh2').value;D.cfg.chours=document.getElementById('fch').value;save();applyAll();alert('✅ Footer guardado.');} function rCfgEd(){ var apiKeyActual=D.cfg&&D.cfg.geminiApiKey?D.cfg.geminiApiKey:(D.cfg&&D.cfg.claudeApiKey?D.cfg.claudeApiKey:''); var apiOk=!!(apiKeyActual&&apiKeyActual.length>10); return '

💬 WhatsApp

Número que usan todos los botones de la app.

'+lbl('Número (con código de país, sin +)','')+'

Argentina: 54 + código de área sin 0 + número. Ej: 5492644123456

' +'

🗺️ Link de Google Maps

Funciona en Firefox, Chrome y en el celular.

'+lbl('Link de Google Maps (pegá la URL completa)','')+'

Buscá Meraki en Google Maps → copiá la URL de la barra → pegala acá.

' +'

💰 Seña + Mercado Pago

Configurá el cobro de la seña para los turnos de depilación. Podés usar un link de pago de Mercado Pago o solo el alias.

'+lbl('Monto de la seña (Ej: $2.000)','')+lbl('Texto del aviso de seña','')+'

💳 Datos de Mercado Pago

'+lbl('Link de pago de Mercado Pago (opcional)','')+'

En Mercado Pago → Cobrar → Compartir link de pago → copiá el link.

'+lbl('Alias de Mercado Pago (opcional, si no tenés link)','')+'
' +'
' +'

🤖 Asistente IA — Google Gemini

' +'

Necesaria para generar mensajes automáticos y analizar el negocio con IA. Obtené tu key en aistudio.google.com

' +(apiOk?'
✅ API Key configurada correctamente
':'
⚠️ Sin API Key — el Asistente IA no puede generar mensajes ni análisis
') +lbl('API Key de Gemini (AIza...)','') +'

Se guarda localmente en tu dispositivo. No se comparte con nadie.

' +'' +'
' +'

🔐 Contraseña de Admin

'+lbl('Nueva contraseña','')+lbl('Repetir contraseña','')+'
'; } function saveCfg(){var wa=document.getElementById('cwa');if(wa&&wa.value)D.cfg.wa=wa.value;var mp=document.getElementById('cmap');if(mp&&mp.value)D.cfg.mapLink=mp.value;var sn=document.getElementById('csenal');if(sn&&sn.value)D.cfg.senal=sn.value;var sm=document.getElementById('csenalmsg');if(sm&&sm.value)D.cfg.senalMsg=sm.value;var ml=document.getElementById('cmplink');if(ml)D.cfg.mpLink=ml.value.trim();var ma=document.getElementById('cmpalias');if(ma)D.cfg.mpAlias=ma.value.trim();var p1=document.getElementById('cp1'),p2=document.getElementById('cp2');if(p1&&p1.value){if(p1.value.length<6){alert('La contraseña debe tener al menos 6 caracteres.');return;}if(p1.value===p2.value)D.cfg.pass=p1.value;else{alert('Las contraseñas no coinciden.');return;}}save();applyAll();renderGol();renderGfts();alert('✅ Configuración guardada.');} function saveApiKey(){var k=document.getElementById('claude-api-key');if(!k)return;var v=k.value.trim();if(!v){alert('Ingresá la API Key.');return;}if(!D.cfg)D.cfg={};if(v.startsWith('AIza')){D.cfg.geminiApiKey=v;}else{D.cfg.claudeApiKey=v;}save();alert('✅ API Key guardada. ¡El Asistente IA ya está activo!');showS('cfg_ed',null);} // ───────────────────────────────────────────── // REDES SOCIALES & CONTENIDO // ───────────────────────────────────────────── // D.redes se inicializa en sanitizarD() function rRedes(){ if(!D.redes) D.redes={instagram:'',facebook:'',tiktok:'',spotify:'',posts:[]}; if(!D.redes.posts) D.redes.posts=[]; var ig=D.redes.instagram||''; var fb=D.redes.facebook||''; var tk=D.redes.tiktok||''; var sp=D.redes.spotify||''; function statusDot(val){ return val ?'' :''; } function netCard(icon,name,color,val,id,link,hint){ return '
' +'
' +'
' +''+icon+'' +'
' +'
'+name+'
' +'
'+statusDot(val)+(val?('Conectada — @'+val):'Sin conectar')+'
' +'
' +(val?'':'') +'
' +'
' +'' +'' +(link?'🔗 Ir a '+name+'':'') +'
' +'
'; } var out=''; // ── Header ── out+='
'; out+='

📱 Redes Sociales

Conectá tus cuentas y creá contenido con IA

'; out+=''; out+='
'; // ── Cuentas conectadas ── out+='
'; out+='

Cuentas

'; out+=netCard('📸','Instagram','#e1306c',ig,'instagram','https://www.instagram.com/accounts/login/','tu usuario de Instagram'); out+=netCard('📘','Facebook','#1877f2',fb,'facebook','https://www.facebook.com/login','tu usuario de Facebook'); out+=netCard('🎵','TikTok','#010101',tk,'tiktok','https://www.tiktok.com/login','tu usuario de TikTok'); out+=netCard('💚','Spotify','#1db954',sp,'spotify','https://open.spotify.com','link a tu perfil o playlist'); out+='
'; // ── Publicaciones guardadas ── out+='
'; out+='

Publicaciones creadas ('+D.redes.posts.length+')

'; if(D.redes.posts.length){ out+='
'; D.redes.posts.slice().reverse().forEach(function(p,ri){ var realIdx=D.redes.posts.length-1-ri; var redes_icons={instagram:'📸',facebook:'📘',tiktok:'🎵',todos:'🌐'}; var icon=redes_icons[p.red]||'🌐'; out+='
'; out+='
'; out+='
'; (p.redes||[p.red||'todos']).forEach(function(r){out+=''+( redes_icons[r]||'🌐')+'';}); out+='
'; out+='
'; out+=''; out+=''; out+='
'; if(p.imagen){out+='';} out+='

'+p.texto.slice(0,120)+(p.texto.length>120?'...':'')+'

'; if(p.hashtags){out+='

'+p.hashtags.slice(0,60)+'

';} if(p.ubicacion){out+='

📍 '+p.ubicacion+'

';} if(p.spotify){out+='

🎵 '+p.spotify+'

';} out+='
'+( p.fecha?p.fecha.slice(0,10):'—')+'
'; out+='
'; }); out+='
'; } else { out+='
'; out+='
'; out+='

Todavía no creaste ninguna publicación.

'; out+=''; out+='
'; } out+='
'; return out; } function conectarRed(id){ var val=document.getElementById('net-'+id); if(!val)return; var v=val.value.trim().replace(/^@/,''); if(!v){alert('Ingresá el usuario.');return;} if(!D.redes)D.redes={instagram:'',facebook:'',tiktok:'',spotify:'',posts:[]}; D.redes[id]=v; save(); showS('redes',null); } function desconectarRed(id){ if(!confirm('¿Desconectar '+id+'?'))return; D.redes[id]=''; save(); showS('redes',null); } function borrarPost(idx){ if(!confirm('¿Eliminar publicación?'))return; D.redes.posts.splice(idx,1); save(); showS('redes',null); } // ── Modal nueva publicación ── function abrirNuevaPublicacion(editIdx){ if(!D.redes)D.redes={instagram:'',facebook:'',tiktok:'',spotify:'',posts:[]}; var edit=editIdx!=null?D.redes.posts[editIdx]:null; var txt=edit?edit.texto:''; var hash=edit?( edit.hashtags||''):''; var ubi=edit?( edit.ubicacion||''):''; var spo=edit?( edit.spotify||''):''; var img=edit?( edit.imagen||''):''; var rdesActivas=edit?( edit.redes||[]):[].filter(Boolean); function chk(id,lbl,checked){return'';} var igC=edit?rdesActivas.indexOf('instagram')>=0:!!D.redes.instagram; var fbC=edit?rdesActivas.indexOf('facebook')>=0:!!D.redes.facebook; var tkC=edit?rdesActivas.indexOf('tiktok')>=0:!!D.redes.tiktok; var modal='

'+(edit?'✏️ Editar':'✨ Nueva')+' publicación

'; // Redes destino modal+='
'; modal+=''; modal+='
'; modal+=chk('ig','📸 Instagram',igC); modal+=chk('fb','📘 Facebook',fbC); modal+=chk('tk','🎵 TikTok',tkC); modal+='
'; // Imagen modal+='
'; modal+=''; modal+='
'; modal+='
'; modal+=''; modal+='
'; modal+=''; modal+=''; modal+='
'; modal+='
'; modal+=(img?'' :'🖼️'); modal+='
'; // Texto caption modal+='
'; modal+=''; modal+=''; modal+='
'; modal+=''; modal+=''; modal+=''; modal+=''; modal+='
'; // Hashtags modal+='
'; modal+=''; modal+=''; modal+=''; modal+='
'; // Ubicación modal+='
'; modal+=''; modal+=''; modal+='
'; // Spotify modal+='
'; modal+=''; modal+='
'; modal+=''; modal+=''; modal+='
'; modal+='
'; if(spo){ var spId=spo.match(/track\/([a-zA-Z0-9]+)/); if(spId){modal+='';} else{var spPl=spo.match(/playlist\/([a-zA-Z0-9]+)/);if(spPl){modal+='';}} } modal+='
'; // IA loading area modal+=''; // Botones finales modal+='
'; modal+=''; modal+=''; modal+='
'; openMod(modal); // Update img preview on URL change setTimeout(function(){ var u=document.getElementById('post-img-url'); if(u)u.addEventListener('input',function(){ var p=document.getElementById('post-img-preview'); if(p&&u.value)p.innerHTML=''; }); },100); } function editarPost(idx){abrirNuevaPublicacion(idx);} function previewPostImg(input){ if(!input.files||!input.files[0])return; var f=input.files[0]; var r=new FileReader(); r.onload=function(e){ var u=document.getElementById('post-img-url'); var p=document.getElementById('post-img-preview'); if(u)u.value=e.target.result; if(p)p.innerHTML=''; }; r.readAsDataURL(f); } function guardarPost(editIdx){ var txt=document.getElementById('post-txt'); if(!txt||!txt.value.trim()){alert('Escribí el texto de la publicación.');return;} var rdesSelec=[]; if(document.getElementById('post-ig')&&document.getElementById('post-ig').checked) rdesSelec.push('instagram'); if(document.getElementById('post-fb')&&document.getElementById('post-fb').checked) rdesSelec.push('facebook'); if(document.getElementById('post-tk')&&document.getElementById('post-tk').checked) rdesSelec.push('tiktok'); var post={ texto:txt.value.trim(), hashtags:(document.getElementById('post-hash')||{}).value||'', ubicacion:(document.getElementById('post-ubi')||{}).value||'', spotify:(document.getElementById('post-spotify')||{}).value||'', imagen:(document.getElementById('post-img-url')||{}).value||'', redes:rdesSelec, fecha:new Date().toISOString() }; if(editIdx!=null&&editIdx!='null'){ D.redes.posts[editIdx]=post; } else { D.redes.posts.push(post); } save(); closeMod(); showS('redes',null); } function generarCaptionIA(tipo){ var loading=document.getElementById('ia-post-loading'); if(loading)loading.style.display='block'; var svcs=D.svcs.map(function(s){return s.nombre;}).join(', ')||'tratamientos faciales y corporales'; var promos=D.promos.filter(function(p){return p.activa;}).map(function(p){return p.titulo+': '+p.texto;}).join('; ')||'sin promos activas'; var prompts={ promo:'Creá un caption atractivo para Instagram/Facebook para una estética llamada Meraki en Argentina. La publicación debe destacar esta promo: '+promos+'. Tono: cálido, femenino, cercano. Incluí emojis. Máximo 150 palabras. Solo el texto del caption, sin explicaciones.', consejo:'Creá un caption con un consejo de cuidado de la piel para Instagram de una estética llamada Meraki en Argentina. Que sea educativo, útil y con tono cálido. Servicios que ofrecen: '+svcs+'. Incluí emojis. Máximo 150 palabras. Solo el caption.', motivacion:'Creá un caption motivacional y empoderador sobre el autocuidado y el amor propio para una estética llamada Meraki en Argentina. Tono: femenino, positivo, inspirador. Incluí emojis. Máximo 120 palabras. Solo el caption.', servicio:'Creá un caption para destacar uno de estos servicios de la estética Meraki en Argentina: '+svcs+'. Elegí el más impactante. Describí el beneficio de forma atractiva. Incluí emojis. Máximo 150 palabras. Solo el caption.' }; callIA(prompts[tipo]||prompts.promo,400,function(txt){ if(loading)loading.style.display='none'; var el=document.getElementById('post-txt'); if(el&&txt)el.value=txt; },function(e){if(loading)loading.style.display='none';alert('Error IA: '+e);}); } function generarHashtagsIA(){ var loading=document.getElementById('ia-post-loading'); if(loading)loading.style.display='block'; var caption=(document.getElementById('post-txt')||{}).value||'publicación de estética'; callIA('Generá 15-20 hashtags relevantes en español e inglés para esta publicación de una estética en Argentina llamada Meraki: "'+caption.slice(0,300)+'". Solo los hashtags separados por espacios, sin explicaciones.',150,function(txt){ if(loading)loading.style.display='none'; var el=document.getElementById('post-hash'); if(el&&txt)el.value=txt.trim(); },function(e){if(loading)loading.style.display='none';alert('Error: '+e);}); } function buscarSpotify(){ var q=(document.getElementById('post-spotify')||{}).value||''; if(!q){alert('Ingresá nombre de canción o artista.');return;} // Si ya es un link de Spotify, mostrar embed directo if(q.includes('spotify.com')){ var id=q.match(/track\/([a-zA-Z0-9]+)/); var pl=q.match(/playlist\/([a-zA-Z0-9]+)/); var res=document.getElementById('spotify-results'); if(id&&res){res.innerHTML='';} else if(pl&&res){res.innerHTML='';} return; } // Buscar via embed link sugerido var res=document.getElementById('spotify-results'); if(res){ res.innerHTML='
' +'

🔍 Para buscar en Spotify abrí este link, copiá el link de la canción y pegalo acá.

' +'
'; } } function genImagenIA(){ alert('Para generar imágenes con IA, usá herramientas como Canva, Adobe Firefly o Midjourney y subí el resultado acá. ¡Te recomendamos Canva — es gratis!'); } function rTratEd(){ if(!D.tratamientos)D.tratamientos=[]; var out=''; out+='

Gestioná los tratamientos disponibles. Al agregar uno nuevo aparece también en la sección de Servicios de la app.

'; out+='

➕ Agregar nuevo tratamiento

'; out+=lbl('Nombre del tratamiento *',''); out+='
'; out+=lbl('Duración',''); out+=lbl('Precio',''); out+=lbl('Categoría',''); out+='
'; out+=lbl('Descripción',''); out+='
'; out+='

📋 Tratamientos cargados ('+D.tratamientos.length+')

'; if(!D.tratamientos.length){ out+='

Sin tratamientos cargados aún.

'; } else { out+=''; D.tratamientos.forEach(function(t,i){ var dur=t.duracion<60?t.duracion+' min':(t.duracion===60?'60 min':(t.duracion/60)+'hs'); var estadoBg=t.activo?'#f0e4c4':'#f5f5f5'; var estadoColor=t.activo?'#9a7235':'#aaa'; var estadoTxt=t.activo?'Activo':'Inactivo'; out+=''; out+=''; out+=''; out+=''; out+=''; out+=''; }); out+='
TratamientoDuraciónPrecioEstadoAcciones
'+t.nombre+''+(t.desc?'
'+t.desc+'':'')+'
'+dur+''+(t.precio||'—')+''+estadoTxt+''; out+=''; out+=''; out+='
'; } out+='
'; return out; } function addTratamiento(){ if(!D.tratamientos)D.tratamientos=[]; var nom=document.getElementById('nt-nom').value.trim(); var dur=parseInt(document.getElementById('nt-dur').value); var precio=document.getElementById('nt-precio').value.trim(); var cat=document.getElementById('nt-cat').value; var desc=document.getElementById('nt-desc').value.trim(); if(!nom){alert('El nombre es obligatorio.');return;} D.tratamientos.push({id:gid(),nombre:nom,duracion:dur,precio:precio,cat:cat,desc:desc,activo:true}); D.svcs.push({id:gid(),cat:cat,nombre:nom,desc:desc||nom,precio:precio||'Consultar',emoji:'✨',img:'https://images.unsplash.com/photo-1570172619644-dfd03ed5d881?w=400&q=80'}); save();renderSvcs();showS('trat_ed',null); } function toggleTrat(i){ if(!D.tratamientos[i])return; D.tratamientos[i].activo=!D.tratamientos[i].activo; save();showS('trat_ed',null); } function delTrat(i){ if(!confirm('Eliminar este tratamiento?'))return; var nom=D.tratamientos[i].nombre; D.tratamientos.splice(i,1); D.svcs=D.svcs.filter(function(s){return s.nombre!==nom;}); save();renderSvcs();showS('trat_ed',null); } function editTrat(i){ var t=D.tratamientos[i]; openMod('

Editar tratamiento

' +lbl('Nombre','') +'
' +lbl('Duración','') +lbl('Precio','') +'
' +lbl('Descripción','') +'
' +'' +'' +'
'); } function updateTrat(i){ var t=D.tratamientos[i]; var oldNom=t.nombre; t.nombre=document.getElementById('et-nom').value.trim()||t.nombre; t.duracion=parseInt(document.getElementById('et-dur').value)||t.duracion; t.precio=document.getElementById('et-precio').value.trim(); t.desc=document.getElementById('et-desc').value.trim(); var sv=D.svcs.find(function(s){return s.nombre===oldNom;}); if(sv){sv.nombre=t.nombre;sv.desc=t.desc||sv.desc;sv.precio=t.precio||sv.precio;} save();renderSvcs();closeMod();showS('trat_ed',null); } function getInactivaDias(){ // Lee el umbral configurable guardado en D.cfg o usa 30 por defecto return parseInt((D.cfg&&D.cfg.inactivaDias)||30)||30; } function rIAAsist(){ if(!D.clients||!D.clients.length){ return '

🤖 Asistente IA de Meraki

Aún no hay clientes registrados. Cuando tengas clientas en la base de datos, el asistente podrá ayudarte a gestionarlas.

' +'

⚠️ El Asistente IA requiere una API Key de Claude configurada en Configuración → API Key IA.

'; } // Verificar API key var apiKey=getIAKey(); var apiOk=!!(apiKey&&apiKey.length>10); var umbral=getInactivaDias(); var hoy=new Date(); var inactivas=[]; D.clients.forEach(function(c){ if(c.notifSolo) return; var ultimaFecha=getUltimaVisitaCliente(c); var diasSinVisita=Math.floor((hoy-ultimaFecha)/(1000*60*60*24)); if(diasSinVisita>=umbral){ inactivas.push({cliente:c,dias:diasSinVisita,ultima:ultimaFecha}); } }); inactivas.sort(function(a,b){return b.dias-a.dias;}); var listaChips=inactivas.slice(0,15).map(function(x){ return ''+x.cliente.nombre.split(' ')[0] +' '+x.dias+'d'; }).join(''); var out='
' +'
🤖
' +'

Asistente IA de Meraki

' +'

Conectado a Google Gemini (gratis) · Analiza la agenda completa para detectar clientas inactivas

' +'
'; // Alerta si no hay API key if(!apiOk){ out+='
' +'

🤖 Asistente IA — Google Gemini

' +'

La IA usa Google Gemini (gratis). Si querés usar Claude, configurá tu API Key en Configuración.

' +'' +'
'; } // Card configuración de umbral out+='
' +'
' +'

⏱️ Umbral de inactividad

' +'

Clientas sin reservar hace más de X días

' +'
' +'' +'días' +'' +'
' +'
'; // Card 1: Inactive clients out+='
' +'

😴 Clientas sin reservar hace +'+umbral+' días ('+inactivas.length+')

'; if(!inactivas.length){ out+='

¡Excelente! Todas tus clientas reservaron en los últimos '+umbral+' días. 🎉

'; } else { out+='

Detectadas revisando agenda de tratamientos + depilación + historial. Última visita calculada desde turnos reales:

' +'
'+listaChips+'
' +'
' +'' +'' +'' +'' +'' +'' +'' +'' +inactivas.slice(0,20).map(function(x){ var ultimaStr=x.ultima.getTime()===0?'Sin turno registrado':fd(x.ultima.toISOString().slice(0,10)); return '' +'' +'' +'' +'' +'' +''; }).join('') +'
NOMBRETELÉFONOÚLTIMA VISITADÍAS SIN VENIRACCIÓN
'+x.cliente.nombre+''+x.cliente.telefono+''+ultimaStr+''+x.dias+' días
' +(inactivas.length>20?'

Mostrando las 20 más inactivas de '+inactivas.length+' total.

':'') +'
' +(apiOk?'':'') +(apiOk?'':'') +'' +'
'; } out+='
'; // Card 2: AI message generator out+='
' +'

📲 Mensaje generado por IA

' +'' +'
' +'
'; // Card 3: Manual message tool — con lista de inactivas integrada out+='
' +'

💬 Enviar mensaje manual a clientas inactivas

' +'

Lista de clientas cargadas desde la agenda (sin reservar hace +'+umbral+' días): '+inactivas.length+' clientas

' +(inactivas.length?'

'+inactivas.map(function(x){return x.cliente.nombre.split(' ')[0];}).join(', ')+'

':'

Sin clientas inactivas en este momento.

') +'' +'
' +'' +'' +'
' +'
'; // Card 4: AI analysis out+='
' +'

📊 Análisis inteligente del negocio

' +'

El asistente analiza datos de turnos, finanzas y clientes y te da sugerencias para mejorar.

' +(apiOk ?'' :'

⚠️ Configurá la API Key de Claude para usar esta función.

') +'
' +'
'; // Card 5: Tendencias de mercado IA out+='
' +'

🌐 Tendencias del mercado + comparativa de precios

' +'

La IA analiza qué tratamientos busca más la gente en Argentina y compara con los precios de Meraki para detectar oportunidades y sugerir promociones.

' +'' +'
' +'
'; return out; } function guardarUmbralIA(){ var v=parseInt(document.getElementById('ia-umbral-input').value)||30; if(!D.cfg)D.cfg={}; D.cfg.inactivaDias=Math.max(7,Math.min(365,v)); save(); showS('ia_asist',null); } /* ══════════════════════════════════════ // ── Función central de IA — usa Gemini (gratis) o Claude como fallback ── var GEMINI_KEY_DEFAULT='AIzaSyDn-9tKHTR4zqoZ8-XSxPI48NkS9BTrhXI'; function getIAKey(){return(D.cfg&&D.cfg.geminiApiKey)||GEMINI_KEY_DEFAULT;} function isGemini(k){return k&&k.startsWith('AIza');} function isClaude(k){return k&&k.startsWith('sk-ant');} function callIA(prompt,maxTokens,onSuccess,onError){ var key=getIAKey(); if(!key){if(onError)onError('Sin API Key');return;} if(isGemini(key)){ fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key='+key,{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({contents:[{parts:[{text:prompt}]}],generationConfig:{maxOutputTokens:maxTokens||400}}) }) .then(function(r){return r.json();}) .then(function(data){ var txt=data.candidates&&data.candidates[0]&&data.candidates[0].content&&data.candidates[0].content.parts&&data.candidates[0].content.parts[0]?data.candidates[0].content.parts[0].text:(data.error?'Error: '+data.error.message:'Sin respuesta'); onSuccess(txt); }) .catch(function(e){if(onError)onError(e.message);}); } else if(isClaude(key)){ fetch('https://api.anthropic.com/v1/messages',{ method:'POST', headers:{'Content-Type':'application/json','x-api-key':key,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-access':'true'}, body:JSON.stringify({model:'claude-opus-4-5',max_tokens:maxTokens||400,messages:[{role:'user',content:prompt}]}) }) .then(function(r){return r.json();}) .then(function(data){ var txt=data.content&&data.content[0]?data.content[0].text:(data.error?'Error: '+data.error.message:'Sin respuesta'); onSuccess(txt); }) .catch(function(e){if(onError)onError(e.message);}); } } FUNCIONES DE IA — Claude API ══════════════════════════════════════ */ function getUltimaVisitaCliente(c){ // Busca la fecha más reciente entre: turnos de tratamiento, turnos de depilación e historial manual var ultimaFecha=null; [].concat(D.appts||[],D.depilAppts||[]).forEach(function(a){ if(a.dni===c.dni||(c.telefono&&a.telefono===c.telefono)){ var d=new Date(a.fecha+'T12:00:00'); if(!ultimaFecha||d>ultimaFecha) ultimaFecha=d; } }); // También revisar historial manual del cliente if(c.historial&&c.historial.length){ c.historial.forEach(function(h){ if(h.fecha){ var d=new Date(h.fecha+'T12:00:00'); if(!ultimaFecha||d>ultimaFecha) ultimaFecha=d; } }); } if(!ultimaFecha) ultimaFecha=new Date(0); return ultimaFecha; } function getClientasInactivas(){ var hoy=new Date(); var umbral=getInactivaDias(); var inactivas=[]; D.clients.forEach(function(c){ if(c.notifSolo) return; var ultimaFecha=getUltimaVisitaCliente(c); var dias=Math.floor((hoy-ultimaFecha)/(1000*60*60*24)); if(dias>=umbral) inactivas.push({nombre:c.nombre,telefono:c.telefono,dias:dias}); }); return inactivas.sort(function(a,b){return b.dias-a.dias;}); } function enviarWATodasInactivas(){ var inactivas=getClientasInactivas(); if(!inactivas.length){alert('No hay clientas inactivas en este momento.');return;} var msg='Hola {nombre}! 🌸 Te extrañamos en Meraki. Hace un tiempo que no te vemos y queremos saber cómo estás.\n\nTenemos novedades y promos especiales para vos. ¿Te animás a reservar un turno esta semana? ✨\n\n¡Te esperamos! — Meraki 💛'; if(!confirm('¿Enviar este mensaje de WhatsApp a '+inactivas.length+' clientas inactivas?\n\nSe abrirán '+inactivas.length+' ventanas de WhatsApp.'))return; inactivas.forEach(function(c,i){ setTimeout(function(){ var texto=msg.replace(/\{nombre\}/g,c.nombre.split(' ')[0]); waO(c.telefono,texto); },i*1200); }); } function generarMensajeIA(tipo){ var inactivas=getClientasInactivas(); var seccion=document.getElementById('ia-msg-section'); var loading=document.getElementById('ia-loading'); var result=document.getElementById('ia-msg-result'); if(seccion) seccion.style.display='block'; if(loading) loading.classList.remove('hidden'); if(result) result.innerHTML=''; var promos=D.promos.filter(function(p){return p.activa;}).map(function(p){return p.titulo+': '+p.texto;}).join(', '); var servicios=D.svcs.slice(0,5).map(function(s){return s.nombre;}).join(', '); var locales=D.finanzas&&D.finanzas.ingresos?D.finanzas.ingresos.length:0; var prompt=tipo==='promo' ?'Generá un mensaje de WhatsApp corto (máx 150 palabras) para clientas de una estética llamada Meraki en Argentina que no reservaron hace más de 30 días. Ofrecé una promo especial para que vuelvan. Usá un tono cálido, femenino y cercano. Las promos actuales son: '+promos+'. Los servicios son: '+servicios+'. Incluí {nombre} donde va el nombre de la clienta. Escribí solo el mensaje, sin explicaciones.' :'Generá un mensaje de WhatsApp corto (máx 150 palabras) para clientas de una estética llamada Meraki en Argentina que no reservaron hace más de 30 días. El objetivo es que vuelvan a reservar. Usá un tono cálido, femenino y cercano. Mencioná que las extrañan y que hay novedades. Los servicios son: '+servicios+'. Incluí {nombre} donde va el nombre de la clienta. Escribí solo el mensaje, sin explicaciones.'; callIA(prompt,400,function(msg){ if(loading) loading.classList.add('hidden'); if(result){ result.innerHTML='

Mensaje generado — podés editarlo antes de enviar:

' +'' +'
' +'' +'' +'
'; } },function(e){ if(loading) loading.classList.add('hidden'); if(result) result.innerHTML='

⚠️ Error al conectar con la IA: '+e+'

'; }); } function usarMensajeGenerado(){ var gen=document.getElementById('ia-gen-msg'); var manual=document.getElementById('ia-manual-msg'); if(gen&&manual) manual.value=gen.value; alert('✅ Mensaje copiado al área de envío. Podés editarlo y luego enviarlo.'); } function copiarMensajeIA(){ var el=document.getElementById('ia-manual-msg'); if(!el)return; navigator.clipboard.writeText(el.value).then(function(){alert('📋 Mensaje copiado al portapapeles.');}).catch(function(){el.select();document.execCommand('copy');alert('📋 Copiado.');}); } function enviarWAInactivas(){ var msg=document.getElementById('ia-manual-msg'); if(!msg||!msg.value.trim()){alert('Escribí o generá un mensaje primero.');return;} var inactivas=getClientasInactivas(); if(!inactivas.length){alert('No hay clientas inactivas en este momento.');return;} if(!confirm('¿Enviar este mensaje a '+inactivas.length+' clientas que no reservan hace +30 días?'))return; inactivas.forEach(function(c,i){ setTimeout(function(){ var texto=msg.value.replace(/\{nombre\}/g,c.nombre.split(' ')[0]); waO(c.telefono,texto); },i*1200); }); } function analizarNegocioIA(){ var result=document.getElementById('ia-analisis-result'); if(result) result.innerHTML='

Analizando tu negocio...

'; var totalClientes=D.clients.length; var totalTurnos=(D.appts||[]).length+(D.depilAppts||[]).length; var inactivas=getClientasInactivas().length; var mes=new Date().getMonth(); var anio=new Date().getFullYear(); var ingMes=0,gasMes=0; if(D.finanzas){ D.finanzas.ingresos.forEach(function(x){var d=new Date(x.fecha);if(d.getMonth()===mes&&d.getFullYear()===anio)ingMes+=(parseFloat(x.monto)||0);}); D.finanzas.gastos.forEach(function(x){var d=new Date(x.fecha);if(d.getMonth()===mes&&d.getFullYear()===anio)gasMes+=(parseFloat(x.monto)||0);}); } var topSvcs={}; [].concat(D.appts,D.depilAppts).forEach(function(a){var s=a.servicio&&a.servicio!='A convenir'?a.servicio:'Tratamiento';topSvcs[s]=(topSvcs[s]||0)+1;}); var top=Object.keys(topSvcs).sort(function(a,b){return topSvcs[b]-topSvcs[a];}).slice(0,3).join(', '); var prompt='Sos un consultor de negocios de estéticas en Argentina. Analizá estos datos de Meraki Estética y dá 3-4 sugerencias concretas y accionables para mejorar el negocio. Sé específico y práctico. Datos: ' +totalClientes+' clientes totales, '+totalTurnos+' turnos registrados, '+inactivas+' clientas inactivas (sin reservar hace +'+getInactivaDias()+' días), ingresos del mes: $'+Math.round(ingMes).toLocaleString('es-AR')+', gastos: $'+Math.round(gasMes).toLocaleString('es-AR')+', ganancia neta: $'+Math.round(ingMes-gasMes).toLocaleString('es-AR')+', servicios más pedidos: '+top+'. Respondé en español, de forma amigable y directa. Máximo 200 palabras.'; callIA(prompt,500,function(txt){ if(result){ result.innerHTML='
' +'

'+txt+'

' +'
'; } },function(e){ if(result) result.innerHTML='

⚠️ Error al conectar con la IA: '+e+'

'; }); } function analizarTendenciasIA(){ var result=document.getElementById('ia-tendencias-result'); if(result) result.innerHTML='

Consultando tendencias del mercado de estéticas en Argentina...

'; var misServicios=D.svcs.map(function(s){return s.nombre+' ('+s.precio+')';}).join(', '); var misZonas=getDepilZonas().filter(function(z){return z.precio;}).map(function(z){return z.nombre+' ('+z.precio+')';}).join(', '); var misPromos=D.promos.filter(function(p){return p.activa;}).map(function(p){return p.titulo;}).join(', ')||'sin promos activas'; var prompt='Sos una consultora experta en marketing de estéticas en Argentina en '+new Date().getFullYear()+'. Necesito que hagas un análisis completo en 3 partes: ' +'**PARTE 1 — TENDENCIAS WEB Y REDES (2024-2025):** Según tu conocimiento, ¿cuáles son los 5 tratamientos de estética que MÁS busca la gente en Argentina en Google e Instagram? Incluí depilación, tratamientos faciales y corporales. Mencioná si hay tendencias especiales (ej: depilación láser, hidrafacial, etc.) ' +'**PARTE 2 — COMPARATIVA DE PRECIOS:** Los precios actuales de Meraki son: Tratamientos: '+misServicios+'. Depilación: '+misZonas+'. Comparalos con precios promedio de mercado en Argentina y decí si están arriba, en línea o abajo del mercado. ' +'**PARTE 3 — OPORTUNIDADES:** Basándote en las tendencias y la comparativa de precios, sugerí 2-3 acciones concretas (nuevos servicios a ofrecer, promociones puntuales, ajustes de precios, servicios de moda que Meraki no tiene). Sé específica y práctica. ' +'Respondé en español, de forma estructurada y amigable. Máximo 350 palabras total.'; callIA(prompt,700,function(txt){ if(result){ // Formato con secciones var html=txt .replace(/\*\*([^*]+)\*\*/g,'$1') .replace(/ /g,'

') .replace(/ /g,'
'); result.innerHTML='

' +'

'+html+'

' +'
' +'' +'
' +'
'; } },function(e){ if(result) result.innerHTML='

⚠️ Error al conectar con la IA: '+e+'

'; }); } // Estado del selector de mes para finanzas var _finMes=null,_finAnio=null; function cambiarMesFin(){ var sm=document.getElementById('fin-sel-mes'); var sa=document.getElementById('fin-sel-anio'); if(sm)_finMes=parseInt(sm.value); if(sa)_finAnio=parseInt(sa.value)||_finAnio; showS('fin_ana',null); } function rFinAna(){ if(!D.finanzas||Array.isArray(D.finanzas))D.finanzas={ingresos:[],gastos:[]}; if(!D.finanzas.ingresos)D.finanzas.ingresos=[]; if(!D.finanzas.gastos)D.finanzas.gastos=[]; var ML=['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic']; var MLong=['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre']; var now=new Date(); if(_finMes===null)_finMes=now.getMonth(); if(_finAnio===null)_finAnio=now.getFullYear(); var mes=_finMes, anio=_finAnio; var fmt=function(v){return'$'+Math.round(v).toLocaleString('es-AR');}; var esMes=function(iso){var d=new Date(iso);return d.getMonth()===mes&&d.getFullYear()===anio;}; var ingM=D.finanzas.ingresos.filter(esMes); var gasM=D.finanzas.gastos.filter(esMes); var totI=0; ingM.forEach(function(r){totI+=(parseFloat(r.monto)||0);}); var totG=0; gasM.forEach(function(r){totG+=(parseFloat(r.monto)||0);}); var gan=totI-totG; var label=MLong[mes]+' '+anio; var out=''; // ── Selector de mes ── var mesOpts=ML.map(function(m,i){return'';}).join(''); var anioActual=now.getFullYear(); var anioOpts=''; for(var y=anioActual-3;y<=anioActual;y++){anioOpts+='';} out+='
'; out+='📆 Ver mes:'; out+=''; out+=''; out+=''+label+''; out+='
'; // ── Stats del mes ── out+='
'; out+='
'+fmt(totI)+'
Ingresos '+label+'
'; out+='
'+fmt(totG)+'
Gastos '+label+'
'; out+='
'+fmt(gan)+'
'+(gan>=0?'Ganancia':'Pérdida')+'
'; out+='
'; // ── Formularios ingresos/gastos ── out+='
'; // INGRESOS var turnosRecientes=[].concat(D.appts||[],D.depilAppts||[]) .filter(function(a){return a.nombre&&a.servicio;}) .sort(function(a,b){return(b.fecha+b.hora).localeCompare(a.fecha+a.hora);}) .slice(0,10); var turnoOpts=''; turnosRecientes.forEach(function(a,i){ var svc=a.servicio&&a.servicio!='A convenir'?a.servicio:(a.tipo==='depilacion'?'Depilación':'Tratamiento'); turnoOpts+=''; }); var turnosJSON=JSON.stringify(turnosRecientes.map(function(a){ var svc=a.servicio&&a.servicio!='A convenir'?a.servicio:(a.tipo==='depilacion'?'Depilación':'Tratamiento'); return{desc:svc+' '+a.nombre.split(' ')[0],precio:a.precio||''}; })); out+='
'; out+='

💰 Ingresos — '+label+'

'; if(turnosRecientes.length){ out+='
'; out+=''; out+=''; out+='
'; } out+=lbl('Descripción',''); out+=lbl('Monto ($)',''); out+=''; if(ingM.length){ out+='
'; ingM.slice().reverse().forEach(function(r){ var realIdx=D.finanzas.ingresos.indexOf(r); out+='
'; out+='
'+r.desc+'
'+fd(r.fecha.slice(0,10))+'
'; out+='
'+fmt(r.monto)+''; out+='
'; }); out+='
'; } else { out+='

Sin cobros este mes

'; } out+='
'; // GASTOS out+='
'; out+='

💸 Gastos — '+label+'

'; out+=lbl('Descripción',''); out+=lbl('Monto ($)',''); out+=''; if(gasM.length){ out+='
'; gasM.slice().reverse().forEach(function(r){ var realIdx=D.finanzas.gastos.indexOf(r); out+='
'; out+='
'+r.desc+'
'+fd(r.fecha.slice(0,10))+'
'; out+='
'+fmt(r.monto)+''; out+='
'; }); out+='
'; } else { out+='

Sin gastos este mes

'; } out+='
'; out+='
'; // ── Análisis ── out+='
'; out+='

📊 Estadísticas generales

'; var todos=[].concat(D.appts||[],D.depilAppts||[]); var nuevas=D.clients.filter(function(c){return c.isNew;}).length; out+='
'; out+='
'+todos.length+'
Total turnos
'; out+='
'+D.clients.length+'
Clientes
'; out+='
'+nuevas+'
Nuevas
'; out+='
'+(D.clients.length-nuevas)+'
Habituales
'; out+='
'; // Turnos por mes + top servicios var byMes={}; todos.forEach(function(a){ if(!a.fecha)return; var d=new Date(a.fecha+'T12:00:00'); var k=d.getFullYear()+'-'+String(d.getMonth()).padStart(2,'0'); byMes[k]=(byMes[k]||0)+1; }); var mesKeys=Object.keys(byMes).sort().slice(-6); var bySvc={}; todos.forEach(function(a){ var s=a.servicio&&a.servicio!='A convenir'?a.servicio:(a.tipo==='depilacion'?'Depilación':'Tratamiento'); bySvc[s]=(bySvc[s]||0)+1; }); var topSvcs=Object.keys(bySvc).sort(function(a,b){return bySvc[b]-bySvc[a];}).slice(0,5); out+='
'; out+='

📅 Turnos por mes

'; if(mesKeys.length){ out+=''; mesKeys.forEach(function(k){ var p=k.split('-'); out+=''; }); out+='
MesTurnos
'+MLong[parseInt(p[1])]+' '+p[0]+''+byMes[k]+'
'; } else { out+='

Sin datos aún

'; } out+='
'; out+='

✨ Servicios más pedidos

'; if(topSvcs.length){ out+=''; topSvcs.forEach(function(s){ out+=''; }); out+='
ServicioVeces
'+s+''+bySvc[s]+'
'; } else { out+='

Sin datos aún

'; } out+='
'; // Historial financiero por mes if(D.finanzas.ingresos.length||D.finanzas.gastos.length){ var ing6={},gas6={}; D.finanzas.ingresos.forEach(function(x){var k=x.fecha.slice(0,7);ing6[k]=(ing6[k]||0)+(parseFloat(x.monto)||0);}); D.finanzas.gastos.forEach(function(x){var k=x.fecha.slice(0,7);gas6[k]=(gas6[k]||0)+(parseFloat(x.monto)||0);}); var fkeys=Object.keys(ing6).concat(Object.keys(gas6)).filter(function(v,i,a){return a.indexOf(v)===i;}).sort().slice(-4); if(fkeys.length){ out+='

💰 Historial financiero mensual

'; out+=''; fkeys.forEach(function(k){ var p=k.split('-'); var ing=ing6[k]||0,gas=gas6[k]||0,gan=ing-gas; out+=''; out+=''; out+=''; out+='
MesIngresosGastosGanancia
'+MLong[parseInt(p[1])]+' '+p[0]+''+fmt(ing)+''+fmt(gas)+'' +'' +'
✅ Comprobante cargado
' +''; } }; img.src=e.target.result; }; reader.readAsDataURL(file); } function verComprobante(src){ openMod('

📎 Comprobante de pago

' +'
' +'' +'
' +''); } function saveDepSvcs(){D.depilServicios=D.depilServicios.map(function(s,i){var el=document.getElementById('ds-'+i);return el?el.value.trim():s;}).filter(function(s){return s;});save();showS('dep_ed',null);alert('Guardado!');} function saveDepZonas(){if(!D.depilZonas)D.depilZonas=getDepilZonas();D.depilZonas=D.depilZonas.map(function(z,i){var n=document.getElementById('dz-n-'+i);var p=document.getElementById('dz-p-'+i);var img=document.getElementById('dz-i-'+i);return{nombre:n?n.value.trim():z.nombre,precio:p?p.value.trim():z.precio,imagen:img?img.value.trim():z.imagen};}).filter(function(z){return z.nombre;});syncDepilServicios();save();renderSimuladorDep();showS('dep_ed',null);alert('✅ Zonas y precios guardados.');} function saveDepF(){var d=document.getElementById('db-dni');if(d)DB.dni=d.value;var n=document.getElementById('db-nom');if(n)DB.nombre=n.value;var t=document.getElementById('db-tel');if(t)DB.tel=t.value;var sv=document.getElementById('db-svc');if(sv)DB.servicio=sv.value;} function saveBKF(){var e=document.getElementById('f-email');if(e)BK.email=e.value;var n=document.getElementById('f-nac');if(n)BK.nac=n.value;var a=document.getElementById('f-alg');if(a)BK.alg=a.value;var f=document.getElementById('f-fecha');if(f)BK.fecha=f.value;var sv=document.getElementById('f-svc');if(sv)BK.servicio=sv.value;} /* ════════════════════════════════════════ SISTEMA DE RECORDATORIOS AUTOMÁTICOS Revisa cada minuto si hay turnos en la próxima hora y abre WhatsApp automático ════════════════════════════════════════ */ var reminderInterval = null; var sentReminders = {}; function loadSentReminders(){ try{var s=localStorage.getItem('meraki_sent_reminders');if(s)sentReminders=JSON.parse(s);}catch(e){} } function saveSentReminders(){ try{localStorage.setItem('meraki_sent_reminders',JSON.stringify(sentReminders));}catch(e){} } function checkReminders(){ if(!document.body.classList.contains('admin-activo')) return; var now = new Date(); var today = now.toISOString().slice(0,10); var nowMins = now.getHours()*60 + now.getMinutes(); // Buscar turnos que sean en exactamente 55-65 minutos (ventana de 10 min) var upcoming = [].concat(D.appts, D.depilAppts).filter(function(a){ if(!a.fecha || !a.hora) return false; if(a.fecha !== today) return false; var apptH = parseInt(a.hora.split(':')[0]); var apptM = parseInt(a.hora.split(':')[1]||'0'); var apptMins = apptH*60 + apptM; var diff = apptMins - nowMins; // Entre 55 y 65 minutos antes return diff >= 55 && diff <= 65; }); upcoming.forEach(function(a){ var key = a.id + '_' + today; if(sentReminders[key]) return; // Ya enviado hoy sentReminders[key] = true; saveSentReminders(); // Construir mensaje de recordatorio var esDep = a.tipo === 'depilacion'; var svcTxt = a.servicio && a.servicio !== 'A convenir' ? '\n✨ ' + a.servicio : ''; var msg = 'Hola ' + a.nombre.split(' ')[0] + '! 🌸\n\n' + 'Te recordamos que tenés un turno ' + (esDep ? 'de depilación ' : '') + 'en *Estética Meraki* en aproximadamente 1 hora:\n\n' + '📅 Hoy ' + fd(a.fecha) + '\n' + '⏰ A las ' + a.hora + ' hs' + svcTxt + '\n\n' + '¡Te esperamos! Si necesitás reprogramar respondé este mensaje. ✨\n— Meraki 🌸'; var waUrl = 'https://wa.me/' + a.telefono.replace(/\D/g,'').replace(/^0?(?!54)/,'54') + '?text=' + encodeURIComponent(msg); // Mostrar notificación visual showReminderAlert(a, waUrl); // Auto-abrir WhatsApp después de 2 segundos setTimeout(function(){ window.open(waUrl, '_blank'); }, 2000); }); } function showReminderAlert(appt, waUrl){ // Remover alerta anterior si existe var existing = document.getElementById('reminder-banner'); if(existing) existing.remove(); var banner = document.createElement('div'); banner.id = 'reminder-banner'; banner.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:9999;background:linear-gradient(135deg,#25d366,#1aaa50);color:white;padding:14px 20px;display:flex;align-items:center;justify-content:space-between;box-shadow:0 4px 20px rgba(0,0,0,.3);animation:slideDown .4s ease;font-family:Nunito,sans-serif;'; var esDep = appt.tipo === 'depilacion'; var svcTxt = appt.servicio && appt.servicio !== 'A convenir' ? ' — ' + appt.servicio : ''; banner.innerHTML = '
' + '
' + '
' + '
Recordatorio enviado automáticamente
' + '
' + appt.nombre + ' — ' + appt.hora + ' hs' + (esDep?' (Depilación)':'') + svcTxt + '
' + '
' + '
' + '💬 Reenviar WA' + '' + '
'; document.body.appendChild(banner); // Auto-cerrar después de 30 segundos setTimeout(function(){ var b = document.getElementById('reminder-banner'); if(b) b.style.animation = 'slideUp .3s ease forwards'; setTimeout(function(){ var b2 = document.getElementById('reminder-banner'); if(b2) b2.remove(); }, 300); }, 30000); // Notificación del navegador si tiene permiso if(window.Notification && Notification.permission === 'granted'){ new Notification('⏰ Recordatorio Meraki', { body: appt.nombre + ' tiene turno a las ' + appt.hora + ' hs', icon: 'data:image/svg+xml,🌸' }); } } function startReminderSystem(){ loadSentReminders(); // Limpiar recordatorios viejos (de días anteriores) var today = new Date().toISOString().slice(0,10); Object.keys(sentReminders).forEach(function(k){ if(k.indexOf(today) === -1) delete sentReminders[k]; }); saveSentReminders(); // Revisar cada 60 segundos if(reminderInterval) clearInterval(reminderInterval); reminderInterval = setInterval(checkReminders, 60000); // También revisar ahora mismo al cargar setTimeout(checkReminders, 3000); // Pedir permiso para notificaciones del navegador if(window.Notification && Notification.permission === 'default'){ Notification.requestPermission(); } } /* ════════════════════════════════════════ SISTEMA AGENDA HOY (MÓVIL) Muestra turnos del día con botones WA para recordatorios con un toque ════════════════════════════════════════ */ function abrirRegistroNotif(){ openMod('

🔔 Registrarme para novedades

' +'

Completá tus datos y te avisamos por WhatsApp cuando haya promos, turnos disponibles o novedades de Meraki. Sin spam, solo lo importante.

' +lbl('Tu nombre *','') +lbl('WhatsApp *','') +lbl('Email (opcional)','') +'
' +'' +'' +'
'); } function guardarRegistroNotif(){ var nom=document.getElementById('rn-nom').value.trim(); var tel=document.getElementById('rn-tel').value.trim(); var email=document.getElementById('rn-email').value.trim(); if(!nom||!tel){alert('Por favor completá tu nombre y WhatsApp.');return;} // Check if already exists var exists=D.clients.find(function(c){return c.telefono===tel;}); if(!exists){ D.clients.push({id:gid(),dni:'',nombre:nom,telefono:tel,email:email,nacimiento:'',alergias:'',isNew:true,visitas:0,puntos:0,notifSolo:true,creado:new Date().toISOString()}); save(); } // Send confirmation WA to admin closeMod(); // Show success openMod('
' +'
🎉
' +'

¡Te registraste!

' +'

Hola '+nom.split(' ')[0]+'! Ya estás en la lista de Meraki.
Te avisaremos por WhatsApp cuando haya promos y novedades. 🌸

' +'' +'
'); } function abrirAgendaHoy(){ var panel = document.getElementById('agenda-hoy-panel'); var lista = document.getElementById('agenda-hoy-lista'); var fechaEl = document.getElementById('agenda-fecha-hoy'); if(!panel || !lista) return; var today = new Date().toISOString().slice(0,10); var fechaLinda = new Date().toLocaleDateString('es-AR',{weekday:'long',day:'numeric',month:'long'}); if(fechaEl) fechaEl.textContent = fechaLinda; var turnos = [].concat( D.appts.map(function(a){return Object.assign({},a,{_tipo:'tratamiento'});}), D.depilAppts.map(function(a){return Object.assign({},a,{_tipo:'depilacion'});}) ).filter(function(a){ return a.fecha === today; }) .sort(function(a,b){ return a.hora.localeCompare(b.hora); }); if(!turnos.length){ lista.innerHTML = '
' + '
🌸
' + '

Sin turnos para hoy

' + '
'; } else { var now = new Date(); var nowMins = now.getHours()*60 + now.getMinutes(); lista.innerHTML = turnos.map(function(a){ var dep = a._tipo === 'depilacion'; var apptMins = parseInt(a.hora.split(':')[0])*60 + parseInt((a.hora.split(':')[1]||'0')); var diff = apptMins - nowMins; var urgente = diff >= 50 && diff <= 70; var pasado = diff < 0; var msg = 'Hola ' + a.nombre.split(' ')[0] + '! 🌸\n\n' + 'Te recordamos que tenés un turno ' + (dep ? 'de depilación ' : '') + 'en *Estética Meraki* ' + (urgente ? 'en aproximadamente 1 hora:\n\n' : 'hoy:\n\n') + '📅 ' + fd(a.fecha) + '\n' + '⏰ A las ' + a.hora + ' hs' + (a.servicio && a.servicio !== 'A convenir' ? '\n✨ ' + a.servicio : '') + '\n\n¡Te esperamos! — Meraki 🌸'; var waUrl = 'https://wa.me/' + a.telefono.replace(/\D/g,'').replace(/^0?(?!54)/,'54') + '?text=' + encodeURIComponent(msg); var borderColor = urgente ? '#ffd54f' : pasado ? '#eee' : 'var(--border)'; var bgColor = urgente ? '#fff8e1' : 'white'; return '
' + '
' + a.hora + '
' + '
' + ''+(dep?'⚡ Depilación':'🌸 Tratamiento')+'' + '
' + a.nombre + '
' + (a.servicio && a.servicio !== 'A convenir' ? '
✨ ' + a.servicio + '
' : '') + (urgente ? '
⏰ ¡EN 1 HORA! Enviá el recordatorio
' : '') + (pasado ? '
Turno pasado
' : '') + '
' + '' + '💬' + (urgente ? 'Recordar' : 'WA') + '' + '
'; }).join(''); } panel.classList.remove('hidden'); } function cerrarAgendaHoy(){ var panel = document.getElementById('agenda-hoy-panel'); if(panel) panel.classList.add('hidden'); } /* Revisar turnos urgentes en móvil */ function checkMobileReminders(){ if(!document.body.classList.contains('admin-activo')) return; var today = new Date().toISOString().slice(0,10); var nowMins = new Date().getHours()*60 + new Date().getMinutes(); var urgentes = [].concat(D.appts, D.depilAppts).filter(function(a){ if(a.fecha !== today) return false; var apptMins = parseInt(a.hora.split(':')[0])*60 + parseInt((a.hora.split(':')[1]||'0')); var diff = apptMins - nowMins; return diff >= 55 && diff <= 65; }); var btn = document.getElementById('agenda-hoy-btn'); if(urgentes.length > 0){ if(btn) btn.style.background = '#ff6b35'; if(btn) btn.innerHTML = '⏰'; if(btn) btn.classList.add('reminder-pulse'); // Notificación nativa del navegador/celular if(window.Notification && Notification.permission === 'granted'){ urgentes.forEach(function(a){ var key = a.id + '_' + today + '_mob'; if(sentReminders[key]) return; sentReminders[key] = true; saveSentReminders(); new Notification('⏰ Turno en 1 hora — Meraki', { body: a.nombre + ' a las ' + a.hora + ' hs' + (a.servicio && a.servicio !== 'A convenir' ? ' — ' + a.servicio : ''), icon: 'data:image/svg+xml,🌸', tag: a.id, requireInteraction: true }); }); } } else { if(btn){ btn.style.background = 'var(--rose)'; btn.innerHTML = '📋'; btn.classList.remove('reminder-pulse'); } } } function pedirPermisoNotificaciones(){ // Solo pedir permisos si el admin está activo if(!document.body.classList.contains('admin-activo')) return; if(window.Notification && Notification.permission === 'default'){ Notification.requestPermission(); } } function startMobileReminderSystem(){ loadSentReminders(); pedirPermisoNotificaciones(); // Revisar cada 60 segundos setInterval(checkMobileReminders, 60000); // Revisar al abrir setTimeout(checkMobileReminders, 2000); // Mostrar agenda solo si el admin está logueado setTimeout(function(){ var today = new Date().toISOString().slice(0,10); var hayTurnos = [].concat(D.appts, D.depilAppts).some(function(a){ return a.fecha===today; }); var adminActivo = document.body.classList.contains('admin-activo'); if(hayTurnos && adminActivo) abrirAgendaHoy(); }, 1500); } /* ══════════════════════════════════════ SISTEMA DE EXPORTACIÓN A EXCEL Genera un .xlsx con 3 hojas: Clientes / Tratamientos / Depilación ══════════════════════════════════════ */ function exportarExcel(mostrarAlert){ if(typeof XLSX === 'undefined'){ alert('Cargando librería Excel, intentá en 3 segundos...'); return; } var wb = XLSX.utils.book_new(); // ── Hoja 1: CLIENTES ── var clHeaders = ['Nombre','DNI','Teléfono','Email','Nacimiento','Puntos','Visitas','Alergias/Notas','Tipo','Fecha Alta']; var clRows = D.clients.map(function(c){ return [ c.nombre||'', c.dni||'', c.telefono||'', c.email||'', c.nacimiento?fd(c.nacimiento):'', c.puntos||0, c.visitas||0, c.alergias||'', c.notifSolo?'Solo notif.':(c.isNew?'Nueva':'Habitual'), c.creado?fd(c.creado.slice(0,10)):'' ]; }); var wsClientes = XLSX.utils.aoa_to_sheet([clHeaders].concat(clRows)); // Column widths wsClientes['!cols'] = [{wch:22},{wch:14},{wch:16},{wch:24},{wch:14},{wch:8},{wch:8},{wch:28},{wch:12},{wch:14}]; XLSX.utils.book_append_sheet(wb, wsClientes, 'Clientes'); // ── Hoja 2: AGENDA TRATAMIENTOS ── var tHeaders = ['Nombre','DNI','Teléfono','Tratamiento','Fecha','Hora','Tipo Cliente','Email','Alergias','Fecha Reserva']; var tRows = D.appts.map(function(a){ return [ a.nombre||'', a.dni||'', a.telefono||'', a.servicio||'A convenir', a.fecha?fd(a.fecha):'', a.hora||'', a.isNew?'Nueva':'Habitual', a.email||'', a.alergias||'', a.creado?fd(a.creado.slice(0,10)):'' ]; }).sort(function(a,b){return a[4].localeCompare(b[4])||a[5].localeCompare(b[5]);}); var wsTrat = XLSX.utils.aoa_to_sheet([tHeaders].concat(tRows)); wsTrat['!cols'] = [{wch:22},{wch:14},{wch:16},{wch:24},{wch:12},{wch:8},{wch:12},{wch:22},{wch:22},{wch:14}]; XLSX.utils.book_append_sheet(wb, wsTrat, 'Agenda Tratamientos'); // ── Hoja 3: AGENDA DEPILACIÓN ── var dHeaders = ['Nombre','DNI','Teléfono','Zona/Servicio','Fecha','Hora','Seña','Fecha Reserva']; var dRows = D.depilAppts.map(function(a){ return [ a.nombre||'', a.dni||'', a.telefono||'', a.servicio||'A convenir', a.fecha?fd(a.fecha):'', a.hora||'', a.senal||'pendiente', a.creado?fd(a.creado.slice(0,10)):'' ]; }).sort(function(a,b){return a[4].localeCompare(b[4])||a[5].localeCompare(b[5]);}); var wsDep = XLSX.utils.aoa_to_sheet([dHeaders].concat(dRows)); wsDep['!cols'] = [{wch:22},{wch:14},{wch:16},{wch:22},{wch:12},{wch:8},{wch:14},{wch:14}]; XLSX.utils.book_append_sheet(wb, wsDep, 'Agenda Depilación'); // ── Hoja 4: FINANZAS ── if(D.finanzas && (D.finanzas.ingresos.length || D.finanzas.gastos.length)){ var fHeaders = ['Tipo','Descripción','Monto','Fecha']; var fRows = []; D.finanzas.ingresos.forEach(function(r){ fRows.push(['INGRESO', r.desc||'', r.monto||0, r.fecha?fd(r.fecha.slice(0,10)):'']); }); D.finanzas.gastos.forEach(function(r){ fRows.push(['GASTO', r.desc||'', r.monto||0, r.fecha?fd(r.fecha.slice(0,10)):'']); }); fRows.sort(function(a,b){return a[3].localeCompare(b[3]);}); var wsFin = XLSX.utils.aoa_to_sheet([fHeaders].concat(fRows)); wsFin['!cols'] = [{wch:10},{wch:30},{wch:12},{wch:14}]; XLSX.utils.book_append_sheet(wb, wsFin, 'Finanzas'); } // ── Generar nombre con fecha ── var hoy = new Date(); var fechaStr = hoy.getDate()+'_'+(hoy.getMonth()+1)+'_'+hoy.getFullYear(); var fileName = 'Meraki_Backup_'+fechaStr+'.xlsx'; XLSX.writeFile(wb, fileName); if(mostrarAlert) alert('✅ Planilla exportada:\n'+fileName+'\n\nTenés '+D.clients.length+' clientes, '+D.appts.length+' turnos de tratamientos y '+D.depilAppts.length+' turnos de depilación.'); } function autoExport(){ // Auto-export silently (no alert) after every save try { exportarExcel(false); } catch(e) { /* silent fail */ } } /* ══════════════════════════════════════ SISTEMA DE IMPORTACIÓN DESDE EXCEL Lee el .xlsx exportado y restaura todos los datos en la app ══════════════════════════════════════ */ function abrirImportador(){ openMod( '

📤 Importar datos desde Excel

' +'
' +'⚠️ Importante: La importación agrega los datos del Excel a los que ya hay en la app. No borra lo que tenés. Si querés restaurar desde cero, primero borrá los datos existentes.' +'
' +'

Seleccioná el archivo Meraki_Backup_... que exportaste antes. La app reconocerá automáticamente las pestañas de Clientes, Agenda Tratamientos, Agenda Depilación y Finanzas.

' +lbl('Seleccionar archivo Excel (.xlsx)','') +'
' +'' +'' +'
' ); } function procesarImport(){ var fileInput = document.getElementById('import-file'); if(!fileInput || !fileInput.files || !fileInput.files[0]){ alert('Por favor seleccioná un archivo Excel primero.'); return; } if(typeof XLSX === 'undefined'){ alert('La librería Excel no cargó aún. Verificá tu conexión y reintentá.'); return; } var file = fileInput.files[0]; var reader = new FileReader(); reader.onload = function(e){ try { var data = new Uint8Array(e.target.result); var wb = XLSX.read(data, {type:'array'}); var imported = {clientes:0, tratamientos:0, depilacion:0, finanzas:0, errores:[]}; // ── Importar CLIENTES ── var wsC = wb.Sheets['Clientes']; if(wsC){ var rows = XLSX.utils.sheet_to_json(wsC, {header:1, defval:''}); // Skip header row for(var i=1; i=0, notifSolo: String(r[8]||'').indexOf('notif')>=0, creado: new Date().toISOString() }); imported.clientes++; } } } // ── Importar AGENDA TRATAMIENTOS ── var wsT = wb.Sheets['Agenda Tratamientos']; if(wsT){ var rowsT = XLSX.utils.sheet_to_json(wsT, {header:1, defval:''}); for(var j=1; j=0){ var fp = fechaT.split('/'); if(fp.length===3) fechaISO = fp[2]+'-'+fp[1].padStart(2,'0')+'-'+fp[0].padStart(2,'0'); } // Check duplicate var dupT = D.appts.find(function(a){ return a.nombre===nomT && a.fecha===fechaISO && a.hora===horaT; }); if(!dupT){ D.appts.push({ id: gid(), tipo: 'tratamiento', nombre: nomT, dni: String(rt[1]||'').trim(), telefono: String(rt[2]||'').trim(), servicio: String(rt[3]||'A convenir').trim(), fecha: fechaISO, hora: horaT, isNew: String(rt[6]||'').indexOf('Nueva')>=0, email: String(rt[7]||'').trim(), alergias: String(rt[8]||'').trim(), nacimiento: '', creado: new Date().toISOString() }); imported.tratamientos++; } } } // ── Importar AGENDA DEPILACIÓN ── var wsD = wb.Sheets['Agenda Depilación']; if(wsD){ var rowsD = XLSX.utils.sheet_to_json(wsD, {header:1, defval:''}); for(var k=1; k=0){ var dp = fechaD.split('/'); if(dp.length===3) fechaDISO = dp[2]+'-'+dp[1].padStart(2,'0')+'-'+dp[0].padStart(2,'0'); } var dupD = D.depilAppts.find(function(a){ return a.nombre===nomD && a.fecha===fechaDISO && a.hora===horaD; }); if(!dupD){ D.depilAppts.push({ id: gid(), tipo: 'depilacion', nombre: nomD, dni: String(rd[1]||'').trim(), telefono: String(rd[2]||'').trim(), servicio: String(rd[3]||'A convenir').trim(), fecha: fechaDISO, hora: horaD, senal: String(rd[6]||'pendiente').trim(), creado: new Date().toISOString() }); imported.depilacion++; } } } // ── Importar FINANZAS ── var wsF = wb.Sheets['Finanzas']; if(wsF){ if(!D.finanzas||Array.isArray(D.finanzas))D.finanzas={ingresos:[],gastos:[]}; var rowsF = XLSX.utils.sheet_to_json(wsF, {header:1, defval:''}); for(var m=1; m=0){ var fpp = fechaF.split('/'); if(fpp.length===3) fechaFISO = fpp[2]+'-'+fpp[1].padStart(2,'0')+'-'+fpp[0].padStart(2,'0')+'T12:00:00.000Z'; } if(tipo === 'INGRESO'){ D.finanzas.ingresos.push({id:gid(), desc:desc, monto:monto, fecha:fechaFISO}); imported.finanzas++; } else if(tipo === 'GASTO'){ D.finanzas.gastos.push({id:gid(), desc:desc, monto:monto, fecha:fechaFISO}); imported.finanzas++; } } } save(); closeMod(); // Show result var msg = '✅ Importación completada!\n\n'; msg += '👥 Clientes importados: '+imported.clientes+'\n'; msg += '🌸 Turnos tratamientos: '+imported.tratamientos+'\n'; msg += '⚡ Turnos depilación: '+imported.depilacion+'\n'; msg += '💰 Registros financieros: '+imported.finanzas+'\n'; msg += '\nTotal en la app ahora:\n'; msg += ' • '+D.clients.length+' clientes\n'; msg += ' • '+D.appts.length+' turnos tratamientos\n'; msg += ' • '+D.depilAppts.length+' turnos depilación'; alert(msg); // Refresh dashboard showS('dash', document.querySelector('.sb-item')); } catch(err) { alert('❌ Error al importar: '+err.message+'\n\nVerificá que el archivo sea un Meraki_Backup exportado desde esta app.'); } }; reader.readAsArrayBuffer(file); } function recargarAgendaTrat(){recargarAgenda();setTimeout(function(){showS('ag_t',null);},1500);} function confirmarTurnoWA(id, tipo){ var list = tipo==='dep' ? D.depilAppts : D.appts; var a = list.find(function(x){return x.id===id;}); if(!a)return; var servTxt = a.servicio&&a.servicio!='A convenir' ? '\n✨ '+a.servicio : ''; var msg = 'Hola '+a.nombre.split(' ')[0]+'! 🌸\n\n' +'¡Tu turno en *Estética Meraki* está *CONFIRMADO*! ✅\n\n' +'📅 '+fd(a.fecha)+'\n' +'⏰ '+a.hora+' hs' +servTxt+'\n\n' +'¡Te esperamos! Si necesitás cancelar o reprogramar respondé este mensaje. 💛\n— Meraki 🌸'; // Marcar como confirmado a.confirmado = true; save(); // Abrir WA waO(a.telefono, msg); // Refrescar la sección actual setTimeout(function(){ var activo = document.querySelector('.sb-item.active'); if(activo){ var oc = activo.getAttribute('onclick')||''; var match = oc.match(/showS\('([^']+)'/); if(match) showS(match[1], activo); } }, 300); } function recargarAgenda(){ mostrarSync('guardando'); // Mostrar loading en la pantalla inmediatamente var cont = document.getElementById('adm-cont'); if(cont) cont.innerHTML = '
🔄

Cargando datos desde la nube...

'; fetch(JBIN_URL,{method:'GET',headers:{'X-Master-Key':JBIN_KEY}}) .then(function(r){return r.json();}) .then(function(data){ if(data&&data.record&&!data.record.init){ var cloud=data.record; if(Array.isArray(cloud.appts)) D.appts = mergeById(D.appts,cloud.appts); if(Array.isArray(cloud.depilAppts)) D.depilAppts = mergeById(D.depilAppts,cloud.depilAppts); if(Array.isArray(cloud.clients)) D.clients = mergeById(D.clients,cloud.clients); sanitizarD(); try{localStorage.setItem('meraki_v3',JSON.stringify(D));}catch(e){} } mostrarSync('ok'); // Detectar sección activa y re-renderizar var activo = document.querySelector('.sb-item.active'); if(activo){ var oc = activo.getAttribute('onclick')||''; var match = oc.match(/showS\('([^']+)'/); if(match){ showS(match[1], activo); return; } } showS('ag_d', null); }) .catch(function(){ mostrarSync('error'); var activo = document.querySelector('.sb-item.active'); if(activo){ var oc2 = activo.getAttribute('onclick')||''; var m2 = oc2.match(/showS\('([^']+)'/); if(m2){ showS(m2[1], activo); return; } } showS('ag_d', null); }); } function forzarSync(){ if(!confirm('¿Subir todos los datos de este dispositivo a la nube?\n\nEsto reemplazará los datos que estén guardados en la nube con los de este dispositivo.'))return; mostrarSync('guardando'); fetch(JBIN_URL,{ method:'PUT', headers:{'Content-Type':'application/json','X-Master-Key':JBIN_KEY}, body:JSON.stringify(D) }) .then(function(r){ return r.json(); }) .then(function(){ mostrarSync('ok'); alert('✅ Datos subidos a la nube correctamente.\nAhora todos los dispositivos verán estos datos.'); }) .catch(function(){ mostrarSync('error'); alert('⚠️ Sin conexión. Intentá de nuevo.'); }); } function ocultarCarga(){ var el = document.getElementById('app-loading'); if(el){ el.style.opacity='0'; el.style.transition='opacity .4s'; setTimeout(function(){el.style.display='none';},400); } } function setLoadMsg(msg){ var el = document.getElementById('loading-msg'); if(el) el.textContent = msg; } function renderAll(){ applyAll(); renderSvcs('all'); renderDepDates(); renderStrip(); renderPop(); renderGol(); renderGfts(); renderCr(); renderBK(); } function init(){ var agPanel = document.getElementById('agenda-hoy-panel'); if(agPanel) agPanel.classList.add('hidden'); /* load() se encarga de todo: datos, render y recordatorios */ setTimeout(function(){document.getElementById('promo-popup').classList.remove('hidden');},5000); } document.addEventListener('DOMContentLoaded',function(){init();load();});