텍스트 스타일 및 프리뷰 렌더링 정리
This commit is contained in:
@@ -1,14 +1,105 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import type { FormBlockProps } from "@/features/editor/state/editorStore";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const formData = await req.formData();
|
||||
|
||||
// 기본 필드(name/email/message)는 그대로 읽어둔다.
|
||||
const name = formData.get("name");
|
||||
const email = formData.get("email");
|
||||
const message = formData.get("message");
|
||||
|
||||
// TODO: 이곳에서 DB 저장이나 이메일 전송 등 실제 처리를 수행한다.
|
||||
console.log("[forms/submit]", { name, email, message });
|
||||
// 에디터에서 넘겨준 폼 설정(JSON) 읽기
|
||||
const rawConfig = formData.get("__config");
|
||||
let config: FormBlockProps | null = null;
|
||||
if (typeof rawConfig === "string") {
|
||||
try {
|
||||
config = JSON.parse(rawConfig) as FormBlockProps;
|
||||
} catch {
|
||||
config = null;
|
||||
}
|
||||
}
|
||||
|
||||
const submitTarget = config?.submitTarget ?? "internal";
|
||||
|
||||
// 1) internal: 우리 서버에서 직접 처리하는 기본 모드
|
||||
if (submitTarget === "internal") {
|
||||
// TODO: 이곳에서 DB 저장이나 이메일 전송 등 실제 처리를 수행한다.
|
||||
console.log("[forms/submit][internal]", { name, email, message });
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
// 2) webhook: destinationUrl 로 서버에서 POST (Google Sheets 등 포함)
|
||||
if (submitTarget === "webhook") {
|
||||
const destinationUrl = config?.destinationUrl;
|
||||
if (!destinationUrl) {
|
||||
return NextResponse.json({ ok: false, error: "destinationUrl_missing" }, { status: 400 });
|
||||
}
|
||||
|
||||
const payloadFormat = config?.payloadFormat ?? "form";
|
||||
|
||||
let body: string;
|
||||
const headers: Record<string, string> = {
|
||||
...(config?.headers ?? {}),
|
||||
};
|
||||
|
||||
if (payloadFormat === "json") {
|
||||
const jsonPayload: Record<string, string> = {};
|
||||
formData.forEach((value, key) => {
|
||||
if (key !== "__config") {
|
||||
jsonPayload[key] = String(value);
|
||||
}
|
||||
});
|
||||
|
||||
if (config?.extraParams) {
|
||||
Object.entries(config.extraParams).forEach(([k, v]) => {
|
||||
jsonPayload[k] = v;
|
||||
});
|
||||
}
|
||||
|
||||
headers["Content-Type"] = "application/json";
|
||||
body = JSON.stringify(jsonPayload);
|
||||
} else {
|
||||
// 기본 동작: FormData -> x-www-form-urlencoded 로 변환 (많은 webhook/Apps Script가 이 형식을 사용)
|
||||
const payload = new URLSearchParams();
|
||||
formData.forEach((value, key) => {
|
||||
if (key !== "__config") {
|
||||
payload.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
if (config?.extraParams) {
|
||||
Object.entries(config.extraParams).forEach(([k, v]) => {
|
||||
payload.append(k, v);
|
||||
});
|
||||
}
|
||||
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
||||
body = payload.toString();
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(destinationUrl, {
|
||||
method: config?.method ?? "POST",
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
console.error("[forms/submit][webhook] remote error", res.status, await res.text().catch(() => ""));
|
||||
return NextResponse.json({ ok: false, error: "webhook_failed" }, { status: 502 });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[forms/submit][webhook] fetch error", error);
|
||||
return NextResponse.json({ ok: false, error: "webhook_exception" }, { status: 500 });
|
||||
}
|
||||
|
||||
console.log("[forms/submit][webhook] forwarded", { name, email, message, destinationUrl });
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
// 그 외 알 수 없는 모드는 internal 과 동일하게 처리
|
||||
console.warn("[forms/submit] unknown submitTarget, fallback to internal", submitTarget);
|
||||
console.log("[forms/submit][internal]", { name, email, message });
|
||||
return NextResponse.json({ ok: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user