Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 55 additions & 9 deletions online_class_platform_v4/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,36 @@ function ensureSupabaseClient() {
}
ensureSupabaseClient();

// OTP 백엔드 API
// OTP 백엔드 API (HTTPS 환경에서도 강제로 HTTP를 섞지 않도록 보정)
function normalizeBaseUrl(url) {
if (!url) return "";
try {
const u = new URL(url, window?.location?.href || "");
// 페이지가 HTTPS라면 HTTP를 HTTPS로 자동 승격
const protocol = u.protocol === "http:" && window?.location?.protocol === "https:" ? "https:" : u.protocol;
return `${protocol}//${u.host}`;
} catch (_) {
return url;
}
}

const API_BASE_URL = (() => {
if (typeof window !== "undefined" && window.location) {
const origin = window.location.origin || "";
const hasWindow = typeof window !== "undefined";

if (hasWindow) {
// URL 쿼리(api_base)나 글로벌 변수로 API 주소를 강제 지정 가능 (테스트/배포 대응)
const search = new URLSearchParams(window.location.search || "");
const override = window.API_BASE_URL || window.__API_BASE_URL__ || search.get("api_base");
if (override) return normalizeBaseUrl(override);

const origin = window.location?.origin || "";
// 프로덕션(railway/custom 도메인)은 동일 origin 사용
if (origin.includes("railway.app") || origin.includes("lessonbay")) return origin;
if (origin.includes("railway.app") || origin.includes("lessonbay")) return normalizeBaseUrl(origin);
// 로컬 5500(정적)에서 백엔드 3000으로 우회
if (origin.includes("127.0.0.1:5500") || origin.includes("localhost:5500")) return "http://localhost:3000";
return origin || "http://localhost:3000";
if (origin.includes("127.0.0.1:5500") || origin.includes("localhost:5500")) return normalizeBaseUrl("http://localhost:3000");
return normalizeBaseUrl(origin || "http://localhost:3000");
}

return "http://localhost:3000";
})();

Expand Down Expand Up @@ -744,19 +764,43 @@ function normalizeCurrentUserInStorage() { /* no-op: localStorage 미사용 */ }
// ? SEED
// ---------------------------
async function loadLocalSampleClasses() {
const builtin = [
{
id: "c_demo_korean_1",
title: "영어 회화 입문",
teacher: "이승훈",
category: "영어",
description: "왕초보도 바로 따라올 수 있는 실전 표현과 발음 교정.",
weeklyPrice: 19000,
monthlyPrice: 59000,
thumb: "https://images.unsplash.com/photo-1523240795612-9a054b0db644?auto=format&fit=crop&w=1400&q=60",
},
{
id: "c_demo_math_1",
title: "고등 수학 확률과 통계",
teacher: "이승훈",
category: "수학",
description: "개념부터 기출, 모의고사까지 확률·통계 핵심 정리와 실전 연습.",
weeklyPrice: 25000,
monthlyPrice: 79000,
thumb: "https://images.unsplash.com/photo-1522202176988-66273c2fd55f?auto=format&fit=crop&w=1400&q=60",
},
];

try {
const res = await fetch("data/classes.json", { cache: "no-cache" });
if (!res.ok) return [];
if (!res.ok) return builtin;
const list = await res.json();
return (list || []).map(c => ({
const normalized = (list || []).map(c => ({
...c,
teacher: c.teacher || c.teacherName || "-",
teacherId: c.teacherId || "",
thumb: c.thumb || FALLBACK_THUMB,
}));
return normalized.length ? normalized : builtin;
} catch (err) {
console.warn("local sample classes load failed", err);
return [];
return builtin;
}
}

Expand All @@ -775,12 +819,14 @@ async function ensureSeedData() {
thumb: c.thumbUrl || c.thumb || FALLBACK_THUMB,
}));
if (normalized.length === 0) {
showToast("API 수업 목록이 비어 있어 데모 데이터를 표시합니다.", "warn", 4500);
setClasses(await loadLocalSampleClasses());
} else {
setClasses(normalized);
}
} catch (e) {
console.error("classes fetch failed", e);
showToast("HTTPS 환경에서 API 접근에 실패해 데모 데이터를 표시합니다.", "warn", 4500);
setClasses(await loadLocalSampleClasses());
}

Expand Down