"use client"; import { useEffect, useRef, useState } from "react"; // ALTCHA کپچای خودمیزبان روی بک‌اند clinicpro. widget فقط وقتی رندر می‌شود که // سرور کپچا را فعال کرده باشد (/api/v1/altcha/config). چون nobat724 روی دامنه‌ی // جدا از API است، آدرس challenge باید absolute باشد. const API = process.env.NEXT_PUBLIC_API_URL; export default function Altcha({ onVerified }) { const ref = useRef(null); // null=در حال بررسی، true/false=فعال/غیرفعال بودن کپچا در سرور const [enabled, setEnabled] = useState(null); useEffect(() => { let alive = true; fetch(`${API}/api/v1/altcha/config`) .then((r) => r.json()) .then((c) => { if (!alive) return; setEnabled(!!c.enabled); if (!c.enabled) onVerified(""); // کپچا خاموش → فرم بدون مانع ارسال شود }) .catch(() => { if (alive) setEnabled(false); }); return () => { alive = false; }; }, [onVerified]); // ثبت custom element + ست‌کردن config به‌صورت attribute واقعی. در React 18 // پراپ‌های JSX روی custom element ممکن است به‌جای attribute به‌شکل property ست // شوند و widget آن‌ها را نخواند (strings/theme اعمال نمی‌شد)؛ با setAttribute // مطمئن می‌شویم درست خوانده می‌شوند. auto را آخر ست می‌کنیم تا بعد از config حل شود. useEffect(() => { if (enabled !== true) return; const onStateChange = (e) => { if (e.detail?.state === "verified" && e.detail.payload) { onVerified(e.detail.payload); } }; // attributeها را قبل از import (قبل از upgrade شدن element) ست می‌کنیم تا // widget از همان ابتدا با تم روشن و متن فارسی init شود. locale رسمی fa با // import ماژول i18n ثبت و با language="fa" فعال می‌شود (RTL هم خودکار است). const el = ref.current; if (el) { el.setAttribute("challengeurl", `${API}/api/v1/altcha/challenge`); el.setAttribute("language", "fa"); el.setAttribute("theme", "light"); el.setAttribute("auto", "onload"); el.addEventListener("statechange", onStateChange); } Promise.all([import("altcha/i18n/fa"), import("altcha")]); return () => { el?.removeEventListener("statechange", onStateChange); }; }, [enabled, onVerified]); if (enabled !== true) return null; return ( ); }