/* ===================================================================== QuoteResult.jsx — pantalla de resultado de la cotización. ===================================================================== */ const QR = window.Cotizador; function StatBig({ label, value, sub }) { return (
{label}
{value}
{sub &&
{sub}
}
); } function IncludedChip({ icon, label }) { return ( {label} ); } function QuoteResult({ state, quoteId, shareUrl, onEditStep, onRestart, readOnly }) { const quote = QR.calculateQuote(state); const time = QR.calculateTime(state); const breakdown = QR.buildBreakdown(state); const [openBreakdown, setOpenBreakdown] = useStateUI(!readOnly ? false : true); const [showCal, setShowCal] = useStateUI(false); const [showStripe, setShowStripe] = useStateUI(false); const [showEmail, setShowEmail] = useStateUI(false); const [copied, setCopied] = useStateUI(false); if (!quote || time == null) { return
Cotización incompleta.
; } const platform = QR.PLATFORMS[state.platform]; const rec = QR.recommendPlatform(state.projectType, state.scale); const wasRecommended = state.platform === rec.platform; const deposit = Math.round(quote.mid * 0.5); const internal = QR.internalEstimate(state, quote.mid); const buildSubtotal = breakdown.filter(it => it.kind === "base" || it.kind === "platform").reduce((a, it) => a + it.amount, 0); const extrasSubtotal = breakdown.filter(it => !it.kind && it.amount !== 0).reduce((a, it) => a + it.amount, 0); // semanas hábiles aprox const weeks = Math.max(1, Math.round(time / 5)); function copyShare() { const url = shareUrl || (location.origin + location.pathname + "?cotizacion=" + quoteId); const done = () => { setCopied(true); setTimeout(() => setCopied(false), 2000); }; try { if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(url).then(done, done); } else { const ta = document.createElement("textarea"); ta.value = url; document.body.appendChild(ta); ta.select(); try { document.execCommand("copy"); } catch (e) {} document.body.removeChild(ta); done(); } } catch (e) { done(); } } return (
{/* Cabecera */}
{readOnly ? "Cotización guardada" : "Tu estimado está listo"}

{QR.PROJECT_TYPES[state.projectType].label} en {platform ? platform.label : "—"}

Folio {quoteId}
{/* HERO precio + tiempo (banda navy) */}
1 ? "s" : "") + " de trabajo"} />
{/* Split construcción vs. extras — evita leer el total como "precio de la página" */} {extrasSubtotal > 0 && (
Construcción del sitio {QR.fmtUSD(buildSubtotal)}
Servicios adicionales {QR.fmtUSD(extrasSubtotal)}
)} {/* Plataforma recomendada y por qué */}
Plataforma: {platform ? platform.label : "—"} {wasRecommended && Recomendada}

{rec.reason}

{!readOnly && ( )}
{/* Desglose colapsable */}
{openBreakdown && (() => { const buildItems = breakdown.filter(it => it.kind === "base" || it.kind === "platform"); const extraItems = breakdown.filter(it => !it.kind && it.amount !== 0); const includedItems = breakdown.filter(it => it.kind === "included"); const buildSubtotal = buildItems.reduce((a, it) => a + it.amount, 0); const extraSubtotal = extraItems.reduce((a, it) => a + it.amount, 0); const Row = ({ item }) => (
{item.kind === "included" ? : } {item.label} {item.amount === 0 ? "Incluido" : (item.amount > 0 ? "+" : "−") + QR.fmtUSD(Math.abs(item.amount))}
); const GroupHead = ({ children, subtotal }) => (
{children} {subtotal != null && {QR.fmtUSD(subtotal)}}
); return (
Construcción del sitio {buildItems.map((item, i) => )} {extraItems.length > 0 && ( Servicios adicionales (opcionales) {extraItems.map((item, i) => )} )} Incluido sin costo {includedItems.map((item, i) => )}
Estimado central {QR.fmtUSD(quote.mid)} USD
); })()}
{/* Compliance / siempre incluido */}
Compliance legal incluido en toda cotización
{/* Vista interna — SOLO equipo Sell-U, nunca en la vista compartida del cliente */} {!readOnly && (
Vista interna · equipo Sell-U No visible para el cliente
{[ { k: "Horas de producción", v: internal.hours + " h", s: "Fijas para " + QR.PROJECT_TYPES[state.projectType].label.toLowerCase() }, { k: "Costo de producción", v: QR.fmtUSD(internal.cost), s: internal.hours + " h × " + QR.fmtUSD(internal.rate) + "/h" }, { k: "Margen estimado", v: QR.fmtUSD(internal.margin), s: "≈ " + internal.marginPct + "% sobre " + QR.fmtUSD(quote.mid), pos: internal.margin >= 0 }, ].map((m, i) => (
{m.k}
{m.v}
{m.s}
))}
)} {/* CTAs */} {!readOnly && (
)} {readOnly && (
)} {!readOnly && (
)} setShowCal(false)} /> setShowStripe(false)} deposit={deposit} /> setShowEmail(false)} />
); } Object.assign(window, { QuoteResult });