/* ============================================================ RESTO SUITE — SHELL One Rail hosting all modules over the shared plan (resto.plan.v1). Three steps: Business Model → Financial Feasibility → Pitch Summary. (plan.market / plan.location / plan.validation stay reserved in the schema but have no UI — their key checks are folded into step 01.) ============================================================ */ function useModules(t) { return [ { key: "idea", n: "01", label: t("shell.navIdea"), live: true }, { key: "financials", n: "02", label: t("shell.navFinancials"), live: true }, { key: "pitch", n: "03", label: t("shell.navPitch"), live: true }, ]; } function moduleSub(key, plan, finLive, ideaCheck, t) { if (key === "idea") return ideaCheck.readiness > 0 ? `${ideaCheck.readiness}/100 ${t("shell.ready")}` : t("shell.startHere"); if (key === "financials") return finLive.sales > 0 ? `${finLive.netProfit < 0 ? "−" : ""}${fmtBaht(Math.abs(finLive.netProfit))}${t("shell.afterTaxMo")}` : "—"; if (key === "pitch") return finLive.sales > 0 && finLive.verdict.key !== "none" ? finLive.verdict.label : "—"; return "—"; } function PetalMark({ size = 40, ring = true }) { const c = 50, petal = "M50,50 C57,41 57,28 50,20 C43,28 43,41 50,50 Z"; return ( ); } function SuiteBrand({ dark, compact }) { const { t } = useLang(); return (
BlueprintSense
{!compact &&
{t("shell.tagline")}
}
); } function SuiteRail({ active, setActive, plan, finLive, ideaCheck, openIE }) { const { t } = useLang(); const MODULES = useModules(t); const heroProfit = finLive.netProfit; return ( ); } function SuiteTopBar({ active, setActive, finLive }) { const { t } = useLang(); const MODULES = useModules(t); return (
{t("shell.profitMoAfterTax")}
{finLive.netProfit < 0 ? "−" : ""}{fmtBaht(Math.abs(finLive.netProfit))}
{MODULES.map((m) => ( ))}
); } const SUITE_TWEAKS = /*EDITMODE-BEGIN*/{ "accent": "#1B3B5F", "coaching": true, "summary": true }/*EDITMODE-END*/; const SUITE_ACCENTS = { "#1B3B5F": { tint: "#EAF0F6", name: "Navy" }, "#2F6F4F": { tint: "#E6F1EB", name: "Green" }, "#1F1B16": { tint: "#EFEDEA", name: "Ink" }, "#9A5B3B": { tint: "#F4EBE4", name: "Clay" }, }; function SuiteApp() { const { t, lang } = useLang(); const [tweaks, setTweak] = useTweaks(SUITE_TWEAKS); const narrow = useMedia("(max-width: 920px)"); const { plan, setNS, replacePlan } = usePlan(); const MODULES = useModules(t); const [active, setActive] = React.useState(() => { try { const a = localStorage.getItem("resto.suite.active") || "idea"; return ["idea", "financials", "pitch"].includes(a) ? a : "idea"; } catch (e) { return "idea"; } }); const [showIE, setShowIE] = React.useState(false); React.useEffect(() => { try { localStorage.setItem("resto.suite.active", active); } catch (e) {} }, [active]); React.useEffect(() => { const r = document.documentElement.style; r.setProperty("--accent", tweaks.accent); r.setProperty("--accent-tint", (SUITE_ACCENTS[tweaks.accent] || {}).tint || "#EAF0F6"); }, [tweaks.accent]); const finLive = React.useMemo(() => computeFin(plan.financials, t), [plan.financials, t]); const ideaCheck = React.useMemo(() => computeIdea(plan.idea, t, lang), [plan.idea, t, lang]); const setIdea = (patch) => setNS("idea", patch); const setFin = (patch) => setNS("financials", patch); /* hand-off: pre-fill plan.financials from the idea — only fields still at their defaults */ const goFinancialsPrefilled = () => { const idea = plan.idea, fin = plan.financials; const patch = {}; const d = { ...fin.detailed }; const band = idea.priceBand ? PRICE_BANDS[idea.priceBand] : null; if (idea.format.seats > 0 && d.seats === FIN_DEFAULTS.detailed.seats) d.seats = idea.format.seats; if (band && d.avgCheck === FIN_DEFAULTS.detailed.avgCheck) d.avgCheck = band.mid; patch.detailed = d; if (idea.format.sqm > 0 && !((fin.space || {}).shopSqm > 0)) patch.space = { ...(fin.space || {}), shopSqm: idea.format.sqm }; if (idea.rentExpectation > 0 && fin.rent === FIN_DEFAULTS.rent && !((fin.costItems || {}).rent || []).length) patch.rent = idea.rentExpectation; if (idea.format.seats > 0 && fin.revMode === FIN_DEFAULTS.revMode) patch.revMode = "detailed"; setNS("financials", patch); setActive("financials"); }; return (
{narrow ? : setShowIE(true)} />}
{active === "idea" && } {active === "financials" && ( )} {active !== "idea" && active !== "financials" && setShowIE(true)} />}
{narrow && (
)}
{showIE && setShowIE(false)} />} setTweak("accent", v)} /> setTweak("summary", v)} /> setTweak("coaching", v)} />
); } function SuiteRoot() { return ( ); } ReactDOM.createRoot(document.getElementById("root")).render();