|
1 | 1 | <!DOCTYPE html> |
2 | | -<htmllang='es'><head><metacharset='UTF-8'><metaname='viewport' content='width=device-width, initial-scale=1.0'><title>Vidrieria Tucuman Pro - Completo</title><scriptsrc='https://cdn.tailwindcss.com'></script></head><bodyclass='bg-slate-50'><divid='app'>Cargando...</div><scripttype='module'> |
3 | | -import{createElementash,useState,useEffect}from'https://esm.sh/[email protected]'; |
4 | | -import{createRoot}from'https://esm.sh/[email protected]/client'; |
5 | | -constVIDRIOS=[{id:'float3',nombre:'float de 3 mm',precio:45000},{id:'float4',nombre:'float de 4 mm',precio:55000},{id:'laminado33',nombre:'laminado 3+3',precio:98000},{id:'templado6',nombre:'templado de 6 mm',precio:120000},{id:'templado10',nombre:'templado de 10 mm',precio:175000},{id:'espejo4',nombre:'espejo de 4 mm',precio:70000},{id:'espejoBis',nombre:'espejo de 4 mm biselado',precio:95000},{id:'fantasia4',nombre:'fantasia de 4 mm',precio:62000}]; |
6 | | -constLOCALIDADES=['San Miguel de Tucuman','Yerba Buena','Banda del Rio Sali','Tafi Viejo','Las Talitas','Alderetes']; |
7 | | -constESTADOS=['Pedido recibido','Medicion pendiente','Presupuestada','Aprobada','En corte','Lista para colocar','Colocada','Rechazada']; |
8 | | -functioncalcM2(a,b){return+(a*b/10000).toFixed(2);}functionfmt(n){return'$ '+n.toLocaleString('es-AR');} |
9 | | -functionApp(){ |
10 | | -const[ordenes,setOrdenes]=useState(()=>{consts=localStorage.getItem('vt_ordenes');returns?JSON.parse(s):[]}); |
11 | | -const[config,setConfig]=useState(()=>{consts=localStorage.getItem('vt_config');returns?JSON.parse(s):{minimo:0.25,colocacionCosto:30000,claveAdmin:'tucuman2024'}}); |
12 | | -const[vista,setVista]=useState('lista');const[selId,setSelId]=useState(null);const[filtroUrg,setFiltroUrg]=useState(false); |
13 | | -const[isAdmin,setIsAdmin]=useState(window.location.hash.includes('admin')); |
14 | | -useEffect(()=>{localStorage.setItem('vt_ordenes',JSON.stringify(ordenes));},[ordenes]); |
15 | | -useEffect(()=>{localStorage.setItem('vt_config',JSON.stringify(config));},[config]); |
16 | | -useEffect(()=>{constfn=()=>setIsAdmin(window.location.hash.includes('admin'));window.addEventListener('hashchange',fn);return()=>window.removeEventListener('hashchange',fn);},[]); |
17 | | -constcargarDemo=()=>{constDEMO=[{cliente:'Kiosco El Sol',loc:'Yerba Buena',mot:'frente de 180 por 220',urg:true,est:'Medicion pendiente',pan:[{a:180,b:220,c:1,t:'float4'}]},{cliente:'Mariela Diaz',loc:'Tafi Viejo',mot:'2 ventanas de 80 por 110 en float de 4 mm',urg:true,est:'Pedido recibido',pan:[{a:80,b:110,c:2,t:'float4'}]},{cliente:'Roberto Sal',loc:'San Miguel de Tucuman',mot:'puerta balcon de 90 por 210',urg:true,est:'Presupuestada',pan:[{a:90,b:210,c:1,t:'templado10'}]},{cliente:'Paola Vega',loc:'Yerba Buena',mot:'espejo biselado de 120 por 80',urg:false,est:'Aprobada',pan:[{a:120,b:80,c:1,t:'espejoBis'}]},{cliente:'Farmacia Central',loc:'San Miguel de Tucuman',mot:'vidriera de 150 por 200 en laminado, urgente',urg:true,est:'En corte',pan:[{a:150,b:200,c:1,t:'laminado33'}]},{cliente:'Marta Rios',loc:'San Miguel de Tucuman',mot:'ventana en float',urg:false,est:'Colocada',pan:[{a:100,b:100,c:1,t:'float4'}]}]; |
18 | | -constnuevas=DEMO.map((d,i)=>{constm2=calcM2(d.pan[0].a,d.pan[0].b);constmf=Math.max(m2,config.minimo);constv=VIDRIOS.find(x=>x.id===d.pan[0].t);return{id:Date.now()+i,numero:1000+i,cliente:d.cliente,celular:'381 400000'+i,localidad:d.loc,direccion:'Calle '+i,motivo:d.mot,urgente:d.urg,fechaMedicion:newDate().toISOString().slice(0,10),panos:[{id:i,ancho:d.pan[0].a,alto:d.pan[0].b,cantidad:d.pan[0].c,tipoVidrio:d.pan[0].t,m2,m2Fact:mf,subtotal:Math.round(mf*v.precio*d.pan[0].c)}],colocacion:false,descuento:0,notas:'',estado:d.est,motivoRechazo:'',colocacionProvisoria:false};});setOrdenes(nuevas);}; |
19 | | -if(isAdmin){returnh('div',{className:'max-w-3xl mx-auto p-4'},h('h1',{className:'text-2xl font-bold'},'Admin'),h('div',{className:'bg-white p-4 rounded shadow mt-4 space-y-4'},h('div',null,'Minimo m2: ',h('input',{type:'number',step:'0.01',value:config.minimo,onChange:e=>setConfig({...config,minimo:parseFloat(e.target.value)||0.25}),className:'border p-1 rounded'})),h('div',null,'Costo colocacion: ',h('input',{type:'number',value:config.colocacionCosto,onChange:e=>setConfig({...config,colocacionCosto:parseInt(e.target.value)||0}),className:'border p-1 rounded'})),h('a',{href:'#',onClick:()=>{window.location.hash='';setIsAdmin(false);},className:'text-blue-600'},'Volver')));} |
20 | | -constlista=filtroUrg?ordenes.filter(o=>o.urgente&&o.estado!=='Colocada'&&o.estado!=='Rechazada'):ordenes; |
21 | | -constsel=ordenes.find(o=>o.id===selId); |
22 | | -if(vista==='detalle'&&sel){returnh(Detalle,{orden:sel,config,setOrdenes,ordenes,setVista,VIDRIOS,LOCALIDADES,ESTADOS});} |
23 | | -returnh('div',{className:'min-h-screen'},h('header',{className:'bg-slate-900 text-white p-3 flex justify-between'},h('div',{className:'font-bold'},'VIDRIERIA TUCUMAN PRO'),h('a',{href:'#admin',className:'text-sm bg-white/20 px-2 py-1 rounded'},'/admin')),h('div',{className:'max-w-6xl mx-auto p-3'},h('div',{className:'flex gap-2 mb-3 flex-wrap'},h('button',{onClick:()=>{constn={id:Date.now(),numero:1000+ordenes.length,cliente:'Nuevo Cliente',celular:'381',localidad:LOCALIDADES[0],direccion:'',motivo:'',urgente:false,fechaMedicion:newDate().toISOString().slice(0,10),panos:[],colocacion:false,descuento:0,notas:'',estado:'Pedido recibido',motivoRechazo:'',colocacionProvisoria:false};setOrdenes([...ordenes,n]);setSelId(n.id);setVista('detalle');},className:'bg-blue-600 text-white px-4 py-2 rounded'},'+ Nuevo Pedido'),h('button',{onClick:cargarDemo,className:'bg-slate-200 px-3 py-2 rounded text-sm'},'Cargar pedidos demo'),h('button',{onClick:()=>setFiltroUrg(!filtroUrg),className:(filtroUrg?'bg-orange-500 text-white':'bg-white border')+' px-3 py-2 rounded text-sm'},filtroUrg?'Ver todos':'Cola urgencias')),filtroUrg?h('div',{className:'space-y-4'},h('h2',{className:'font-bold text-orange-600'},'Cola urgencias por localidad'),(()=>{constg={};lista.filter(o=>o.urgente).forEach(o=>{(g[o.localidad]=g[o.localidad]||[]).push(o);});returnObject.entries(g).map(([loc,arr])=>h('div',{key:loc,className:'bg-white rounded shadow p-3'},h('h3',{className:'font-bold'},loc+' ('+arr.length+')'),arr.sort((a,b)=>(a.colocacionProvisoria?1:0)-(b.colocacionProvisoria?1:0)).map(o=>h('div',{key:o.id,className:'flex justify-between border-b py-2 cursor-pointer'+(o.colocacionProvisoria?' opacity-50':''),onClick:()=>{setSelId(o.id);setVista('detalle');}},h('span',{className:'text-sm'},'#'+o.numero+' '+o.cliente+' '+(o.colocacionProvisoria?'(provisoria)':'')),h('span',{className:'text-orange-600 font-bold text-xs'},'URGENTE')))));})()):h('div',{className:'bg-white rounded shadow divide-y'},h('div',{className:'p-2 text-xs text-slate-500'},'Guardado en localStorage - queda despues de recargar - Total: '+ordenes.length),ordenes.map(o=>h('div',{key:o.id,className:'p-3 flex justify-between hover:bg-slate-50 cursor-pointer'+(o.estado==='Colocada'?' bg-slate-100':'')+(o.urgente?' border-l-4 border-orange-500':''),onClick:()=>{setSelId(o.id);setVista('detalle');}},h('div',null,h('div',{className:'font-bold text-sm'},'#'+o.numero+' '+o.cliente+' - '+o.localidad),h('div',{className:'text-xs text-slate-500'},o.motivo+' | '+o.estado+(o.urgente?' | URGENTE':''))),h('div',{className:'text-sm font-bold'},fmt((o.panos||[]).reduce((s,p)=>s+(p.subtotal||0),0)+(o.colocacion?config.colocacionCosto:0)-(o.descuento||0))))))))); |
24 | | -} |
25 | | -functionDetalle({orden,config,setOrdenes,ordenes,setVista,VIDRIOS,LOCALIDADES,ESTADOS}){ |
26 | | -const[form,setForm]=useState(orden);const[pForm,setPForm]=useState({ancho:'',alto:'',cantidad:1,tipoVidrio:'float4'});const[wa,setWa]=useState(''); |
27 | | -constisRO=form.estado==='Colocada'; |
28 | | -useEffect(()=>{consttot=(form.panos||[]).reduce((s,p)=>s+p.subtotal,0)+(form.colocacion?config.colocacionCosto:0)-(form.descuento||0);consttf=Math.max(0,tot);if(form.panos&&form.panos.length>0){constp0=form.panos[0];constv=VIDRIOS.find(x=>x.id===p0.tipoVidrio);setWa(`Hola ${form.cliente}, tu presupuesto: ${form.panos.length}${v?v.nombre:'paño'} de ${p0.ancho} por ${p0.alto} cm. Total: ${fmt(tf)}`);}},[form.panos,form.colocacion,form.descuento,form.cliente]); |
29 | | -constupd=(p)=>{if(isRO)return;setForm({...form,...p});}; |
30 | | -constaddPano=()=>{constan=parseFloat(pForm.ancho),al=parseFloat(pForm.alto),ca=parseInt(pForm.cantidad);if(!an||!al){alert('Medidas fuera de rango: ingresa ancho y alto');return;}if(an<10||an>300||al<10||al>300){alert('Medidas fuera de rango (10-300 cm) y no se guardan');return;}constm2=calcM2(an,al);constmf=Math.max(m2,config.minimo);constvid=VIDRIOS.find(v=>v.id===pForm.tipoVidrio);constsub=Math.round(mf*vid.precio*ca);constesTL=pForm.tipoVidrio.includes('templado')||pForm.tipoVidrio.includes('laminado');if((an>150||al>150)&&!esTL){alert('Conviene templado o laminado para este tamaño');}setForm({...form,panos:[...(form.panos||[]),{id:Date.now(),ancho:an,alto:al,cantidad:ca,tipoVidrio:pForm.tipoVidrio,m2,m2Fact:mf,subtotal:sub}]});setPForm({ancho:'',alto:'',cantidad:1,tipoVidrio:pForm.tipoVidrio});}; |
31 | | -constguardar=()=>{constidx=ordenes.findIndex(o=>o.id===form.id);constn=[...ordenes];n[idx]=form;setOrdenes(n);setVista('lista');}; |
32 | | -constcambiarEst=(ne)=>{if(ne==='Aprobada'&&(!form.panos||form.panos.length===0)){alert('No se puede pasar de Presupuestada a Aprobada sin al menos un paño cargado');return;}if(ne==='Rechazada'){constmot=prompt('Motivo de rechazo:');if(!mot)return;upd({estado:ne,motivoRechazo:mot});}else{upd({estado:ne});}}; |
33 | | -consttotal=(form.panos||[]).reduce((s,p)=>s+p.subtotal,0)+(form.colocacion?config.colocacionCosto:0)-(form.descuento||0);consttotalF=Math.max(0,total); |
34 | | -constdescargarICS=()=>{constdt=(form.fechaMedicion||'').replace(/-/g,'');constics=`BEGIN:VCALENDAR\nVERSION:2.0\nBEGIN:VEVENT\nSUMMARY:Medicion ${form.cliente}\nDTSTART:${dt}T100000\nEND:VEVENT\nEND:VCALENDAR`;constb=newBlob([ics],{type:'text/calendar'});constu=URL.createObjectURL(b);consta=document.createElement('a');a.href=u;a.download='medicion-'+form.cliente+'.ics';a.click();}; |
35 | | -returnh('div',{className:'max-w-5xl mx-auto p-3'},h('button',{onClick:()=>setVista('lista'),className:'mb-2 bg-slate-200 px-2 py-1 rounded text-sm'},'← Volver'),h('div',{className:'bg-white rounded shadow p-4 grid md:grid-cols-2 gap-4'},h('div',{className:'space-y-2'},h('h2',{className:'font-bold'},'Ficha #'+form.numero+(isRO?' (solo lectura)':'')),h('input',{placeholder:'Cliente',value:form.cliente,onChange:e=>upd({cliente:e.target.value}),disabled:isRO,className:'border p-1 rounded w-full'}),h('input',{placeholder:'Celular',value:form.celular,onChange:e=>upd({celular:e.target.value}),disabled:isRO,className:'border p-1 rounded w-full'}),h('select',{value:form.localidad,onChange:e=>upd({localidad:e.target.value}),disabled:isRO,className:'border p-1 rounded w-full'},LOCALIDADES.map(l=>h('option',{key:l,value:l},l))),h('input',{placeholder:'Direccion',value:form.direccion,onChange:e=>upd({direccion:e.target.value}),disabled:isRO,className:'border p-1 rounded w-full'}),h('input',{placeholder:'Motivo',value:form.motivo,onChange:e=>upd({motivo:e.target.value}),disabled:isRO,className:'border p-1 rounded w-full'}),h('label',{className:'flex gap-2 text-sm'},h('input',{type:'checkbox',checked:form.urgente,onChange:e=>upd({urgente:e.target.checked}),disabled:isRO}),' Urgente'),h('label',{className:'flex gap-2 text-sm'},h('input',{type:'checkbox',checked:form.colocacionProvisoria,onChange:e=>upd({colocacionProvisoria:e.target.checked}),disabled:isRO}),' Colocacion provisoria hecha'),h('div',{className:'flex gap-2'},h('input',{type:'date',value:form.fechaMedicion,onChange:e=>upd({fechaMedicion:e.target.value}),disabled:isRO,className:'border p-1 rounded'}),h('button',{onClick:()=>upd({estado:'Presupuestada'}),className:'bg-blue-100 text-xs px-2 rounded'},'Ya tengo las medidas')),h('label',{className:'flex gap-2 text-sm'},h('input',{type:'checkbox',checked:form.colocacion,onChange:e=>upd({colocacion:e.target.checked}),disabled:isRO}),' Colocacion (+$'+config.colocacionCosto+')'),h('input',{type:'number',placeholder:'Descuento en pesos',value:form.descuento,onChange:e=>upd({descuento:parseInt(e.target.value)||0}),disabled:isRO,className:'border p-1 rounded w-full'}),h('textarea',{placeholder:'Notas',value:form.notas,onChange:e=>upd({notas:e.target.value}),disabled:isRO,className:'border p-1 rounded w-full'}),h('div',{className:'flex flex-wrap gap-1'},ESTADOS.map(es=>h('button',{key:es,onClick:()=>cambiarEst(es),disabled:isRO,className:(form.estado===es?'bg-blue-600 text-white':'bg-slate-100')+' px-2 py-1 rounded text-xs'},es))),form.estado==='Rechazada'&&h('div',{className:'text-sm text-red-600'},'Motivo: '+form.motivoRechazo)),h('div',null,h('h3',{className:'font-bold'},'Paños'),h('div',{className:'text-xs text-slate-500'},'Ancho x Alto / 10000 = m2. Si < '+config.minimo+' m2 se cobra minimo.'),h('div',{className:'border rounded p-2 mt-2'},h('div',{className:'grid grid-cols-2 gap-1'},h('input',{placeholder:'Ancho cm',type:'number',value:pForm.ancho,onChange:e=>setPForm({...pForm,ancho:e.target.value}),className:'border p-1 rounded'}),h('input',{placeholder:'Alto cm',type:'number',value:pForm.alto,onChange:e=>setPForm({...pForm,alto:e.target.value}),className:'border p-1 rounded'}),h('input',{placeholder:'Cant',type:'number',value:pForm.cantidad,onChange:e=>setPForm({...pForm,cantidad:e.target.value}),className:'border p-1 rounded'}),h('select',{value:pForm.tipoVidrio,onChange:e=>setPForm({...pForm,tipoVidrio:e.target.value}),className:'border p-1 rounded text-xs'},VIDRIOS.map(v=>h('option',{key:v.id,value:v.id},v.nombre+' $'+v.precio)))),h('button',{onClick:addPano,className:'w-full bg-blue-600 text-white py-1 rounded text-sm mt-1'},'+ Agregar paño (queda abierto, conserva tipo)')),h('div',{className:'mt-3 divide-y'},(form.panos||[]).map((p,i)=>h('div',{key:p.id,className:'py-1 text-sm flex justify-between'},h('span',null,(i+1)+'. '+p.ancho+'x'+p.alto+' x'+p.cantidad+' '+p.tipoVidrio+' = '+p.m2+'m2 fact '+p.m2Fact+' '+fmt(p.subtotal)),h('button',{onClick:()=>{if(isRO)return;setForm({...form,panos:form.panos.filter(x=>x.id!==p.id)});},className:'text-red-500'},'x')))),h('div',{className:'mt-3 font-bold border-t pt-2'},'TOTAL: '+fmt(totalF)),h('div',{className:'mt-4 space-y-2'},h('h4',{className:'font-bold text-sm'},'WhatsApp (editable)'),h('textarea',{value:wa,onChange:e=>setWa(e.target.value),className:'border p-1 rounded w-full text-sm'}),h('a',{href:'https://wa.me/'+(form.celular||'').replace(/\D/g,'')+'?text='+encodeURIComponent(wa),target:'_blank',className:'block bg-green-500 text-white text-center py-1 rounded text-sm'},'Compartir por WhatsApp'),h('button',{onClick:descargarICS,className:'w-full bg-slate-800 text-white py-1 rounded text-sm'},'Descargar visita .ics'),h('button',{onClick:guardar,disabled:isRO,className:'w-full bg-slate-900 text-white py-2 rounded mt-2'},'Guardar (queda en localStorage)')))))); |
36 | | -} |
37 | | -constroot=createRoot(document.getElementById('app'));root.render(h(App)); |
38 | | -</script></body></html> |
| 2 | +<htmllang="es"> |
| 3 | +<head> |
| 4 | +<metacharset="UTF-8"> |
| 5 | +<metaname="viewport" content="width=device-width, initial-scale=1.0"> |
| 6 | +<title>Vidrieria Tucuman Pro</title> |
| 7 | +<scriptsrc="https://cdn.tailwindcss.com"></script> |
| 8 | +<scriptsrc="https://unpkg.com/react@18/umd/react.production.min.js"></script> |
| 9 | +<scriptsrc="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script> |
| 10 | +<scriptsrc="https://unpkg.com/@babel/standalone/babel.min.js"></script> |
| 11 | +</head> |
| 12 | +<bodyclass="bg-slate-50"> |
| 13 | +<divid="root"></div> |
| 14 | +<scripttype="text/babel"> |
| 15 | +... (todoelcódigodearriba)... |
| 16 | +</script> |
| 17 | +</body> |
| 18 | +</html> |
0 commit comments