// main.js (FULL REPLACE)
// 목적: 프론트에서 /api/* 호출 테스트 + 결과 화면 출력
// - 같은 도메인(예: https://api.myarchi3.xyz)에서 서빙되면 CORS 없이 상대경로로 동작함.
const API_BASE = ""; // ""이면 same-origin. 필요하면 "https://api.myarchi3.xyz" 처럼 고정 가능.
function $(sel) {
return document.querySelector(sel);
}
function apiUrl(path) {
// path는 "/api/..." 형태로 넣기
if (!API_BASE) return path;
return API_BASE.replace(/\/$/, "") + path;
}
async function fetchJson(url, opts = {}) {
const res = await fetch(url, {
...opts,
headers: {
"Content-Type": "application/json",
...(opts.headers || {}),
},
});
const ct = res.headers.get("content-type") || "";
const isJson = ct.includes("application/json");
let body;
if (isJson) body = await res.json();
else body = await res.text();
if (!res.ok) {
const msg =
typeof body === "string"
? body
: JSON.stringify(body, null, 2) || `${res.status} ${res.statusText}`;
throw new Error(`HTTP ${res.status} ${res.statusText}\n\n${msg}`);
}
return body;
}
function renderApp() {
// 기존 Hello world UI는 유지해도 되지만, 여기서는 앱 UI로 교체
document.body.innerHTML = `
my-archi-3 테스트 콘솔
현재 페이지 오리진: ${location.origin} /
API_BASE: ${API_BASE || "(same-origin)"}
대기중
응답
`;
// 버튼 기본 스타일(간단)
document.querySelectorAll("button").forEach((b) => {
b.style.padding = "10px 12px";
b.style.borderRadius = "10px";
b.style.border = "1px solid rgba(0,0,0,.2)";
b.style.cursor = "pointer";
b.style.background = "white";
});
}
function getPayload() {
return {
use_main: $("#use_main").value.trim(),
gross_floor_area_m2: Number($("#gfa").value || 0),
floors_above: Number($("#floors").value || 0),
parking_planned: $("#parking").checked,
notes: $("#notes").value.trim(),
};
}
function setStatus(msg) {
$("#status").textContent = msg;
}
function print(obj) {
const out = $("#out");
if (typeof obj === "string") out.textContent = obj;
else out.textContent = JSON.stringify(obj, null, 2);
}
async function handle(action) {
try {
setStatus("요청 중...");
print("");
if (action === "catalog") {
const data = await fetchJson(apiUrl("/api/catalog"), { method: "GET" });
print(data);
setStatus("완료: catalog");
return;
}
const payload = getPayload();
if (action === "recommend") {
const data = await fetchJson(apiUrl("/api/recommend"), {
method: "POST",
body: JSON.stringify(payload),
});
print(data);
setStatus("완료: recommend");
return;
}
if (action === "seed") {
const data = await fetchJson(apiUrl("/api/report/seed"), {
method: "POST",
body: JSON.stringify(payload),
});
print(data);
setStatus("완료: report/seed");
return;
}
if (action === "html") {
// HTML은 JSON이 아닐 가능성이 있어 text로 받는 방식도 대비
const res = await fetch(apiUrl("/api/report/html"), {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const text = await res.text();
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}\n\n${text}`);
// 새 탭으로 HTML 보기
const blob = new Blob([text], { type: "text/html; charset=utf-8" });
const url = URL.createObjectURL(blob);
window.open(url, "_blank", "noopener,noreferrer");
print(text.slice(0, 2000) + (text.length > 2000 ? "\n\n...(생략)" : ""));
setStatus("완료: report/html (새 탭 열림)");
return;
}
} catch (e) {
setStatus("에러");
print(String(e?.stack || e?.message || e));
}
}
document.addEventListener("DOMContentLoaded", () => {
renderApp();
$("#btnCatalog").addEventListener("click", () => handle("catalog"));
$("#btnRecommend").addEventListener("click", () => handle("recommend"));
$("#btnSeed").addEventListener("click", () => handle("seed"));
$("#btnHtml").addEventListener("click", () => handle("html"));
});