Files
page-builder/src/app/p/[slug]/PublicProjectPageClient.tsx
T
jaybe 7491dacba2
CI / test (push) Successful in 5m38s
CI / e2e (push) Has been skipped
CI / pr_and_merge (push) Successful in 1m12s
리팩터링
2025-12-16 17:49:25 +09:00

121 lines
3.5 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { getPublicPageRendererMessages } from "@/features/i18n/messages/publicPageRenderer";
interface PublicProjectPageClientProps {
html: string;
canSubmit?: boolean;
}
export default function PublicProjectPageClient({ html, canSubmit = true }: PublicProjectPageClientProps) {
const m = getPublicPageRendererMessages(null);
const [toastMessage, setToastMessage] = useState<string | null>(null);
useEffect(() => {
if (typeof document === "undefined" || typeof window === "undefined") return;
let toastTimeout: number | null = null;
const showToast = (message: string) => {
setToastMessage(message);
if (toastTimeout !== null) {
window.clearTimeout(toastTimeout);
}
toastTimeout = window.setTimeout(() => {
setToastMessage(null);
}, 4000);
};
const forms = document.querySelectorAll<HTMLFormElement>(
'form.pb-form-controller, form[action="/api/forms/submit"]',
);
if (!forms || forms.length === 0) return;
forms.forEach((form) => {
if (form.dataset.pbInitialized === "1") return;
form.dataset.pbInitialized = "1";
form.addEventListener("submit", (event) => {
if (!form) return;
if (event && typeof event.preventDefault === "function") {
event.preventDefault();
}
const formData = new FormData(form);
const configInput = form.querySelector<HTMLInputElement>('input[name="__config"]');
let config: any = null;
if (configInput && configInput.value) {
try {
config = JSON.parse(configInput.value);
} catch {
config = null;
}
}
if (!canSubmit) {
const errorMsg = (config && config.errorMessage) || m.submitErrorDefault;
showToast(errorMsg);
return;
}
const action = form.getAttribute("action") || "/api/forms/submit";
fetch(action, { method: "POST", body: formData })
.then((res) => res.json().catch(() => ({})))
.then((data: any) => {
const ok = data && data.ok;
const message = data && data.message;
if (ok) {
const success = message || (config && config.successMessage) || m.submitSuccessDefault;
showToast(success);
try {
form.reset();
} catch {}
} else {
const errorMsg = message || (config && config.errorMessage) || m.submitErrorDefault;
showToast(errorMsg);
}
})
.catch(() => {
const errorMsg = (config && config.errorMessage) || m.submitErrorDefault;
showToast(errorMsg);
});
});
});
return () => {
if (toastTimeout !== null) {
window.clearTimeout(toastTimeout);
}
};
}, []);
return (
<>
<div dangerouslySetInnerHTML={{ __html: html }} />
{toastMessage ? (
<div
style={{
position: "fixed",
right: "16px",
bottom: "16px",
zIndex: 50,
maxWidth: "320px",
padding: "12px 16px",
borderRadius: "8px",
backgroundColor: "rgba(15, 23, 42, 0.95)",
color: "#e5e7eb",
fontSize: "14px",
lineHeight: "1.4",
boxShadow: "0 10px 25px rgba(15, 23, 42, 0.6)",
pointerEvents: "none",
}}
>
{toastMessage}
</div>
) : null}
</>
);
}