/* ============================================================
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();