v0.10.24: /contact-us/ 一比一复刻(CF7 604 表单/通栏 hero/列宽修复)+ PG 连接池 HMR 泄漏修复
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
import { Component, createContext, useContext, Fragment, useEffect, useState, type CSSProperties, type ReactNode } from "react";
|
||||
import { getLatestPosts, getLatestProducts, type LatestItem, type PostCardItem } from "~/server/data";
|
||||
import TickerBar from "~/components/website/TickerBar";
|
||||
import { InquiryForm } from "~/components/website/InquiryForm";
|
||||
import { Cf7Form604 } from "~/components/website/Cf7Form604";
|
||||
import { localSiteUrl } from "~/utils/media";
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "~/components/ui/accordion";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
|
||||
@@ -384,14 +384,22 @@ function collectResponsiveCss(elements: ElElement[]): string {
|
||||
if (fsM) css += `@media (max-width:767px){${sel} .el-heading-title{font-size:${fsM} !important;}}\n`;
|
||||
}
|
||||
}
|
||||
// 列响应式宽度(_inline_size_tablet / _inline_size_mobile;页脚内层四列 43%/100%)
|
||||
const tw = st._inline_size_tablet;
|
||||
const mw = st._inline_size_mobile;
|
||||
if (typeof tw === "number" && tw > 0) {
|
||||
// 列响应式宽度(_inline_size_tablet / _inline_size_mobile;页脚内层四列 43%/100%)。
|
||||
// Elementor 语义:桌面 _inline_size 仅 ≥768 生效(原站 post-840.css 的 min-width:768 门),
|
||||
// 未设 _inline_size_mobile 的列在 ≤767 回退 100%(Elementor frontend.css 的
|
||||
// @media(max-width:767px){.elementor-column{width:100%}})——联系页 60/40 两列移动端堆叠。
|
||||
// 值既有数字也有字符串(联系页 _inline_size="60"),统一转数值。
|
||||
const num = (v: unknown) => (typeof v === "number" ? v : v != null && v !== "" ? Number(v) : NaN);
|
||||
const tw = num(st._inline_size_tablet);
|
||||
const mw = num(st._inline_size_mobile);
|
||||
const dw = num(st._inline_size);
|
||||
if (Number.isFinite(tw) && tw > 0) {
|
||||
css += `@media (max-width:1024px){${sel}{flex:0 0 ${tw}% !important;max-width:${tw}% !important;}}\n`;
|
||||
}
|
||||
if (typeof mw === "number" && mw > 0) {
|
||||
if (Number.isFinite(mw) && mw > 0) {
|
||||
css += `@media (max-width:767px){${sel}{flex:0 0 ${mw}% !important;max-width:${mw}% !important;}}\n`;
|
||||
} else if (Number.isFinite(dw) && dw > 0) {
|
||||
css += `@media (max-width:767px){${sel}{flex:0 0 100% !important;max-width:100% !important;}}\n`;
|
||||
}
|
||||
// icon-list 响应式项间距(space_between_tablet/mobile:页脚社交 10 → 7px)
|
||||
if (s(el.widgetType) === "icon-list") {
|
||||
@@ -404,6 +412,11 @@ function collectResponsiveCss(elements: ElElement[]): string {
|
||||
if (smHalf) {
|
||||
css += `@media (max-width:767px){${inlineItems}{margin-inline:-${smHalf} !important;}${inlineItems} > .elementor-icon-list-item{margin-inline:${smHalf} !important;}}\n`;
|
||||
}
|
||||
// 移动端行高(icon_typography_line_height_mobile:联系页地址列 1.25rem,post-840.css 生成规则)
|
||||
const lhM = sizeCss(st.icon_typography_line_height_mobile);
|
||||
if (lhM) {
|
||||
css += `@media (max-width:767px){${sel} .elementor-icon-list-item > .elementor-icon-list-text,${sel} .elementor-icon-list-item > a{line-height:${lhM} !important;}}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
function walk(els: ElElement[]) {
|
||||
@@ -501,6 +514,11 @@ function SectionNode({ el }: { el: ElElement }) {
|
||||
const bc = s(settings.border_color);
|
||||
if (bc) style.borderColor = bc;
|
||||
}
|
||||
// section 阴影(Elementor box_shadow 控件;联系页 5ed2d55 = 0 10px 50px rgba(71,77,255,.2))
|
||||
const sh = settings.box_shadow_box_shadow as { horizontal?: number; vertical?: number; blur?: number; spread?: number; color?: string } | undefined;
|
||||
if (sh && (sh.blur || sh.spread || sh.horizontal || sh.vertical)) {
|
||||
style.boxShadow = `${sh.horizontal || 0}px ${sh.vertical || 0}px ${sh.blur || 0}px ${sh.spread || 0}px ${sh.color || "rgba(0,0,0,0.5)"}`;
|
||||
}
|
||||
// 列内容垂直对齐(content_position=middle → align-items:center;页脚 d834160 实测)
|
||||
const contentPos = s(settings.content_position);
|
||||
if (contentPos === "middle") inner.alignItems = "center";
|
||||
@@ -547,8 +565,10 @@ function boxNonZero(v: unknown): boolean {
|
||||
function ColumnNode({ el, gapPad, contentPos }: { el: ElElement; gapPad?: string; contentPos?: string }) {
|
||||
const settings = resolveGlobals(el.settings || {});
|
||||
const outer: CSSProperties = { minWidth: 0, flex: "1 1 0" };
|
||||
const inline = settings._inline_size;
|
||||
if (typeof inline === "number" && inline > 0) {
|
||||
// _inline_size 既有数字也有字符串(联系页 ec3c8ff = "60",原站生成 width:60%),统一转数值
|
||||
const inlineRaw = settings._inline_size;
|
||||
const inline = typeof inlineRaw === "number" ? inlineRaw : inlineRaw != null && inlineRaw !== "" ? Number(inlineRaw) : NaN;
|
||||
if (Number.isFinite(inline) && inline > 0) {
|
||||
outer.flex = `0 0 ${inline}%`;
|
||||
outer.maxWidth = `${inline}%`;
|
||||
}
|
||||
@@ -753,7 +773,7 @@ function WidgetNodeInner({ el }: { el: ElElement }) {
|
||||
case "social-icons":
|
||||
return <SocialIconsWidget settings={settings} />;
|
||||
case "eael-contact-form-7":
|
||||
return <ContactFormWidget settings={settings} />;
|
||||
return <ContactFormWidget el={el} settings={settings} />;
|
||||
case "video":
|
||||
return <VideoWidget settings={settings} />;
|
||||
case "counter":
|
||||
@@ -1133,11 +1153,49 @@ function SocialIconsWidget({ settings }: { settings: Record<string, unknown> })
|
||||
}
|
||||
|
||||
|
||||
/** # 组件 eael-contact-form-7(EAEL Contact Form 7 皮肤):渲染内置询盘表单 */
|
||||
function ContactFormWidget({ settings }: { settings: Record<string, unknown> }) {
|
||||
/** # 组件 eael-contact-form-7(EAEL Contact Form 7 皮肤):渲染 CF7 604 忠实表单
|
||||
* DOM 层级仿 EAEL 输出:eael-contact-form-7-wrapper > eael-contact-form.eael-contact-form-7 > wpcf7 > form。
|
||||
* 控件样式按原站 post-840.css 生成规则 + widget 设置生成节点级 <style>
|
||||
* (字段 1px #C9CEE8 边框/圆角 3、textarea 134px、select #efefef/#757575、提交 #ED6C00→#FFA11B)。
|
||||
* 基础规则用 :where() 降特异性(0,0,0),保证页面注入的 custom_css
|
||||
* (.ele-new-form4-dif 的 p 两列浮动布局、submit 全宽等)与响应式规则优先生效。
|
||||
*/
|
||||
function ContactFormWidget({ el, settings }: { el: ElElement; settings: Record<string, unknown> }) {
|
||||
const sid = el.id;
|
||||
const fieldBorder = s(settings.field_border_color) || "#C9CEE8";
|
||||
const taH = sizeCss(settings.textarea_height) || "134px";
|
||||
const btnRadius = paddingCss(settings.button_border_radius) || "3px";
|
||||
const css = `
|
||||
[data-el="${sid}"] :where(.wpcf7-form p){margin:0 0 20px}
|
||||
[data-el="${sid}"] :where(.wpcf7-form label){display:block;margin-bottom:0;line-height:1;font-size:16px;color:#333}
|
||||
[data-el="${sid}"] :where(.wpcf7-form-control-wrap){display:block}
|
||||
[data-el="${sid}"] :where(.wpcf7-text,.wpcf7-email,.wpcf7-tel,.wpcf7-select,.wpcf7-textarea){width:100%;height:42px;padding:8px 16px;margin:0;border:1px solid ${fieldBorder};border-radius:3px;background:#fff;color:#000;font-size:16px;line-height:24px;font-family:inherit}
|
||||
[data-el="${sid}"] :where(.wpcf7-select){padding:10px 12px 9px;background:#efefef;color:#757575}
|
||||
[data-el="${sid}"] :where(.wpcf7-textarea){height:${taH};line-height:1.5;resize:vertical}
|
||||
[data-el="${sid}"] :where(input[type=submit]){width:100%;height:44px;margin:10px 0 0;padding:10px 20px;border:0;border-radius:${btnRadius};background:#ED6C00;color:#fff;font-size:16px;line-height:24px;cursor:pointer;transition:background .25s linear}
|
||||
[data-el="${sid}"] :where(input[type=submit]:hover){background:#FFA11B}
|
||||
[data-el="${sid}"] :where(.wpcf7-list-item){display:inline-block;margin:0 !important}
|
||||
[data-el="${sid}"] :where(.wpcf7-list-item > label){display:block;font-size:14px}
|
||||
[data-el="${sid}"] :where(.wpcf7-list-item input[type=checkbox]){margin:0 0 3px;vertical-align:middle}
|
||||
[data-el="${sid}"] :where(.wpcf7-list-item-label){color:#9396A1;font-size:0.875rem;line-height:1}
|
||||
[data-el="${sid}"] :where(.wpcf7-list-item-label a){color:#9396A1}
|
||||
[data-el="${sid}"] :where(.ds-recaptcha-note){color:#9396A1;font-size:0.875rem}
|
||||
[data-el="${sid}"] :where(.ds-recaptcha-note a){color:#9396A1}
|
||||
[data-el="${sid}"] :where(.ds-submit-p){margin:0 !important}
|
||||
[data-el="${sid}"] :where(.wpcf7-spinner){display:inline-block;position:relative;visibility:hidden;opacity:0.75;width:24px;height:24px;margin:0 24px;border:none;border-radius:100%;background-color:#23282d}
|
||||
[data-el="${sid}"] :where(.wpcf7-response-output){margin:0 0.5em 2em;padding:0.2em 1em;border:2px solid transparent;font-size:16px}
|
||||
[data-el="${sid}"] :where(.wpcf7-response-output.ds-ok){border-color:#46b450}
|
||||
[data-el="${sid}"] :where(.wpcf7-response-output.ds-err){border-color:#dc3232}
|
||||
[data-el="${sid}"] :where(.wpcf7-response-output[aria-hidden="true"]){display:none}
|
||||
`;
|
||||
return (
|
||||
<div className="mb-[18px] rounded-md bg-white px-7 py-[26px]">
|
||||
<InquiryForm formKey="contact-us-form" title={undefined} />
|
||||
<div className="eael-contact-form-7-wrapper">
|
||||
<style>{css}</style>
|
||||
<div className="eael-contact-form eael-contact-form-7">
|
||||
<div className="wpcf7">
|
||||
<Cf7Form604 formKey="contact-form-1" spinner />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ const SETTING_KEYS = new Set([
|
||||
"icon_typography_typography",
|
||||
"icon_typography_font_size",
|
||||
"icon_typography_font_size_tablet",
|
||||
"icon_typography_line_height_mobile",
|
||||
"icon_typography_font_weight",
|
||||
"gradient_angle",
|
||||
"color_a",
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* # 组件 CF7 表单 604(Contact Us Form)忠实复刻
|
||||
* 字段与 DOM 结构取自 legacy dump `wpcf7_contact_form` 604 的 post_content 与原站渲染 HTML:
|
||||
* Name / Company / Business email / Phone number / Product / Interest / Annual Demand(下拉)/
|
||||
* Message*(textarea)+ 6 个 UTM 隐藏字段 + acceptance 勾选 + reCAPTCHA 声明 + Submit。
|
||||
* 提交走 submitInquiry(form_key=contact-form-1);成功/失败显示 wpcf7-response-output。
|
||||
* 字段两列/三列/全宽布局由外层样式域(.ele-new-form4-dif,页面 custom_css)提供,
|
||||
* 本组件只输出 CF7 的 form 层,外层由调用方包 .eael-contact-form-7 / .wpcf7 结构。
|
||||
*/
|
||||
import { useState, type FormEvent } from "react";
|
||||
import { submitInquiry } from "~/server/inquiries";
|
||||
|
||||
/** # 常量 产品线下拉(CF7 表单 604 原文) **/
|
||||
export const CF7_PRODUCT_OPTIONS = ["IoT Gateway", "System on Module", "Development Board", "Remote Control", "Voice Recognition Module", "Control Board", "Beacon & Sensor", "Other"];
|
||||
/** # 常量 合作意向下拉(CF7 表单 604 原文) **/
|
||||
export const CF7_INTEREST_OPTIONS = ["Sales", "Distribution", "ODM", "OEM", "Technical support", "Other"];
|
||||
/** # 常量 年需求量下拉(CF7 表单 604 原文) **/
|
||||
export const CF7_DEMAND_OPTIONS = ["1-50", "51-200", "201-1000", "1001-5000", "5000+"];
|
||||
|
||||
/** # 组件 CF7 604 表单(form 层)
|
||||
* spinner:联系页 CF7 渲染了 spinner 占位(submit 段高 74),弹窗 1129 无(44)——按调用方开关。
|
||||
*/
|
||||
export function Cf7Form604(props: { formKey?: string; spinner?: boolean }) {
|
||||
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
|
||||
/** # 函数 表单提交:映射到 submitInquiry(form_key=contact-form-1,legacy 604) */
|
||||
async function handleSubmit(e: FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
// currentTarget 在 await 之后会被 React 置空,先留引用
|
||||
const formEl = e.currentTarget;
|
||||
const fd = new FormData(formEl);
|
||||
setStatus("submitting");
|
||||
setErrorMsg("");
|
||||
try {
|
||||
const res = await submitInquiry({
|
||||
data: {
|
||||
formKey: props.formKey || "contact-form-1",
|
||||
name: String(fd.get("your-name") || ""),
|
||||
email: String(fd.get("your-email") || ""),
|
||||
phone: String(fd.get("Phone") || ""),
|
||||
company: String(fd.get("Company") || ""),
|
||||
country: "",
|
||||
message: String(fd.get("your-message") || ""),
|
||||
productInterest: String(fd.get("Product") || ""),
|
||||
_gotcha: String(fd.get("_gotcha") || ""),
|
||||
extra: {
|
||||
interest: String(fd.get("Interest") || ""),
|
||||
annualdemand: String(fd.get("AnnualDemand") || ""),
|
||||
consent: fd.get("acceptance-918") ? "1" : "",
|
||||
},
|
||||
},
|
||||
});
|
||||
if (res.ok) {
|
||||
setStatus("success");
|
||||
formEl.reset();
|
||||
} else {
|
||||
setStatus("error");
|
||||
setErrorMsg(res.error || "提交失败,请稍后重试");
|
||||
}
|
||||
} catch (err) {
|
||||
setStatus("error");
|
||||
setErrorMsg(err instanceof Error ? err.message : "网络异常,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="wpcf7-form init" noValidate onSubmit={handleSubmit}>
|
||||
{/* 蜜罐字段:隐藏,机器人填写即视为垃圾提交(原站无此字段) */}
|
||||
<input type="text" name="_gotcha" tabIndex={-1} autoComplete="off" className="hidden" aria-hidden="true" />
|
||||
<p>
|
||||
<label>
|
||||
Name*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="your-name">
|
||||
<input type="text" name="your-name" required className="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Company*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Company">
|
||||
<input type="text" name="Company" required className="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Business email*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="your-email">
|
||||
<input type="email" name="your-email" required className="wpcf7-form-control wpcf7-email wpcf7-validates-as-required wpcf7-text" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Phone number
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Phone">
|
||||
<input type="tel" name="Phone" className="wpcf7-form-control wpcf7-tel wpcf7-text" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Product*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Product">
|
||||
<select name="Product" required className="wpcf7-form-control wpcf7-select wpcf7-validates-as-required">
|
||||
<option value="">—Please choose an option—</option>
|
||||
{CF7_PRODUCT_OPTIONS.map((o) => (
|
||||
<option key={o} value={o}>{o}</option>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Interest*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Interest">
|
||||
<select name="Interest" required className="wpcf7-form-control wpcf7-select wpcf7-validates-as-required">
|
||||
<option value="">—Please choose an option—</option>
|
||||
{CF7_INTEREST_OPTIONS.map((o) => (
|
||||
<option key={o} value={o}>{o}</option>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Annual Demand*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="AnnualDemand">
|
||||
<select name="AnnualDemand" required className="wpcf7-form-control wpcf7-select wpcf7-validates-as-required">
|
||||
<option value="">—Please choose an option—</option>
|
||||
{CF7_DEMAND_OPTIONS.map((o) => (
|
||||
<option key={o} value={o}>{o}</option>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Message*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="your-message">
|
||||
<textarea name="your-message" required className="wpcf7-form-control wpcf7-textarea" rows={6} maxLength={2000} placeholder="Leave us a message about your project or product needs" />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
{/* UTM 隐藏字段(CF7 604 原文,跨度归因用) */}
|
||||
<p><input type="hidden" name="utm_campaign" defaultValue="" /></p>
|
||||
<p><input type="hidden" name="utm_source" defaultValue="" /></p>
|
||||
<p><input type="hidden" name="utm_medium" defaultValue="" /></p>
|
||||
<p><input type="hidden" name="utm_term" defaultValue="" /></p>
|
||||
<p><input type="hidden" name="utm_content" defaultValue="" /></p>
|
||||
<p><input type="hidden" name="gclid" defaultValue="" /></p>
|
||||
<p>
|
||||
<span className="wpcf7-form-control-wrap" data-name="acceptance-918">
|
||||
<span className="wpcf7-form-control wpcf7-acceptance optional">
|
||||
<span className="wpcf7-list-item">
|
||||
<label>
|
||||
<input type="checkbox" name="acceptance-918" value="1" defaultChecked />
|
||||
{/* 原站 checkbox 与文本为行内流式排版(非 flex),文本占满整行宽(608px)换 3 行 */}
|
||||
{" "}
|
||||
<span className="wpcf7-list-item-label">
|
||||
By checking this box, you consent to receive commercial messages such as newsletters, event invitations, promotional and educational content,
|
||||
product updates, transaction-related emails, and customer service emails, from DusunIoT, in accordance with our{" "}
|
||||
<a href="/privacy-policy/">Privacy Policy</a>. You may withdraw your consent at any time.
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<p className="ds-recaptcha-note">
|
||||
This site is protected by reCAPTCHA and the Google <a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Privacy Policy</a> and{" "}
|
||||
<a href="https://policies.google.com/terms" target="_blank" rel="noopener noreferrer">Terms of Service</a> apply.
|
||||
</p>
|
||||
<p className="ds-submit-p">
|
||||
<input className="wpcf7-form-control wpcf7-submit" type="submit" value={status === "submitting" ? "Submitting…" : "Submit"} disabled={status === "submitting"} />
|
||||
{props.spinner ? <span className="wpcf7-spinner" aria-hidden="true" /> : null}
|
||||
</p>
|
||||
<div className={"wpcf7-response-output" + (status === "success" ? " ds-ok" : status === "error" ? " ds-err" : "")} aria-hidden={status === "idle"}>
|
||||
{status === "success" ? "Thank you for your message. It has been sent." : status === "error" ? errorMsg : ""}
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
* + acceptance 勾选 + reCAPTCHA 声明 + Submit)
|
||||
* - popup 1129 生成 CSS(字段 48%/31.3% 两列三列布局、边框 #C9CEE8、按钮 #ED6C00→#FFA11B)
|
||||
*/
|
||||
import { useEffect, useRef, useState, type FormEvent } from "react";
|
||||
import { submitInquiry } from "~/server/inquiries";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Cf7Form604 } from "~/components/website/Cf7Form604";
|
||||
|
||||
/** # 常量 展开的弹窗 id(原站 popup 1129) **/
|
||||
const POPUP_ID = "1129";
|
||||
@@ -25,19 +25,11 @@ const POPUP_SOCIALS = [
|
||||
{ icon: "fa-twitter", label: "Twitter", href: "https://twitter.com/Dusunelectron", color: "#1DA1F2" },
|
||||
];
|
||||
|
||||
/** # 常量 产品线下拉(CF7 表单 604 原文) **/
|
||||
const PRODUCT_OPTIONS = ["IoT Gateway", "System on Module", "Development Board", "Remote Control", "Voice Recognition Module", "Control Board", "Beacon & Sensor", "Other"];
|
||||
/** # 常量 合作意向下拉 **/
|
||||
const INTEREST_OPTIONS = ["Sales", "Distribution", "ODM", "OEM", "Technical support", "Other"];
|
||||
/** # 常量 年需求量下拉 **/
|
||||
const DEMAND_OPTIONS = ["1-50", "51-200", "201-1000", "1001-5000", "5000+"];
|
||||
/** # 常量 产品线下拉/合作意向/年需求量改由 Cf7Form604 提供(CF7 表单 604 原文) **/
|
||||
|
||||
/** # 组件 询价弹窗(全局挂载于 Layout,监听 Elementor popup 链接) */
|
||||
export function InquiryPopup() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
// 全局委托:拦截任意指向 popup 1129 的 Elementor 动作链接
|
||||
useEffect(() => {
|
||||
@@ -57,8 +49,6 @@ export function InquiryPopup() {
|
||||
}
|
||||
if (id !== POPUP_ID) return;
|
||||
e.preventDefault();
|
||||
setStatus("idle");
|
||||
setErrorMsg("");
|
||||
setOpen(true);
|
||||
};
|
||||
document.addEventListener("click", onClick);
|
||||
@@ -81,44 +71,6 @@ export function InquiryPopup() {
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
/** # 函数 表单提交:映射到 submitInquiry(form_key=contact-form-1,legacy 604) */
|
||||
async function handleSubmit(e: FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
const fd = new FormData(e.currentTarget);
|
||||
setStatus("submitting");
|
||||
setErrorMsg("");
|
||||
try {
|
||||
const res = await submitInquiry({
|
||||
data: {
|
||||
formKey: "contact-form-1",
|
||||
name: String(fd.get("your-name") || ""),
|
||||
email: String(fd.get("your-email") || ""),
|
||||
phone: String(fd.get("Phone") || ""),
|
||||
company: String(fd.get("Company") || ""),
|
||||
country: "",
|
||||
message: String(fd.get("your-message") || ""),
|
||||
productInterest: String(fd.get("Product") || ""),
|
||||
_gotcha: String(fd.get("_gotcha") || ""),
|
||||
extra: {
|
||||
interest: String(fd.get("Interest") || ""),
|
||||
annualdemand: String(fd.get("AnnualDemand") || ""),
|
||||
consent: fd.get("acceptance-918") ? "1" : "",
|
||||
},
|
||||
},
|
||||
});
|
||||
if (res.ok) {
|
||||
setStatus("success");
|
||||
formRef.current?.reset();
|
||||
} else {
|
||||
setStatus("error");
|
||||
setErrorMsg(res.error || "提交失败,请稍后重试");
|
||||
}
|
||||
} catch (err) {
|
||||
setStatus("error");
|
||||
setErrorMsg(err instanceof Error ? err.message : "网络异常,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="ds-inquiry-popup elementor-popup-modal dialog-type-lightbox"
|
||||
@@ -144,119 +96,7 @@ export function InquiryPopup() {
|
||||
<h3 className="eael-contact-form-title">CONTACT US</h3>
|
||||
</div>
|
||||
<div className="wpcf7">
|
||||
<form ref={formRef} className="wpcf7-form init" onSubmit={handleSubmit}>
|
||||
<p>
|
||||
<label>
|
||||
Name*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="your-name">
|
||||
<input type="text" name="your-name" required className="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Company*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Company">
|
||||
<input type="text" name="Company" required className="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Business email*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="your-email">
|
||||
<input type="email" name="your-email" required className="wpcf7-form-control wpcf7-text wpcf7-email wpcf7-validates-as-required" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Phone number
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Phone">
|
||||
<input type="tel" name="Phone" className="wpcf7-form-control wpcf7-text wpcf7-tel" maxLength={400} />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Product*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Product">
|
||||
<select name="Product" required className="wpcf7-form-control wpcf7-select wpcf7-validates-as-required">
|
||||
<option value="">—Please choose an option—</option>
|
||||
{PRODUCT_OPTIONS.map((o) => (
|
||||
<option key={o} value={o}>{o}</option>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Interest*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="Interest">
|
||||
<select name="Interest" required className="wpcf7-form-control wpcf7-select wpcf7-validates-as-required">
|
||||
<option value="">—Please choose an option—</option>
|
||||
{INTEREST_OPTIONS.map((o) => (
|
||||
<option key={o} value={o}>{o}</option>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Annual Demand*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="AnnualDemand">
|
||||
<select name="AnnualDemand" required className="wpcf7-form-control wpcf7-select wpcf7-validates-as-required">
|
||||
<option value="">—Please choose an option—</option>
|
||||
{DEMAND_OPTIONS.map((o) => (
|
||||
<option key={o} value={o}>{o}</option>
|
||||
))}
|
||||
</select>
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Message*
|
||||
<br />
|
||||
<span className="wpcf7-form-control-wrap" data-name="your-message">
|
||||
<textarea name="your-message" required className="wpcf7-form-control wpcf7-textarea" rows={6} maxLength={2000} placeholder="Leave us a message about your project or product needs" />
|
||||
</span>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<span className="wpcf7-form-control-wrap" data-name="acceptance-918">
|
||||
<span className="wpcf7-list-item">
|
||||
<label>
|
||||
<input type="checkbox" name="acceptance-918" value="1" defaultChecked />
|
||||
<span className="wpcf7-list-item-label">
|
||||
By checking this box, you consent to receive commercial messages such as newsletters, event invitations, promotional and educational content,
|
||||
product updates, transaction-related emails, and customer service emails, from DusunIoT, in accordance with our{" "}
|
||||
<a href="/privacy-policy/">Privacy Policy</a>. You may withdraw your consent at any time.
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<p className="ds-recaptcha-note">
|
||||
This site is protected by reCAPTCHA and the Google <a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Privacy Policy</a> and{" "}
|
||||
<a href="https://policies.google.com/terms" target="_blank" rel="noopener noreferrer">Terms of Service</a> apply.
|
||||
</p>
|
||||
<p>
|
||||
<input className="wpcf7-form-control wpcf7-submit" type="submit" value={status === "submitting" ? "Submitting…" : "Submit"} disabled={status === "submitting"} />
|
||||
</p>
|
||||
<div className={"wpcf7-response-output" + (status === "success" ? " ds-ok" : status === "error" ? " ds-err" : "")} aria-hidden={status === "idle"}>
|
||||
{status === "success" ? "Thank you for your message. It has been sent." : status === "error" ? errorMsg : ""}
|
||||
</div>
|
||||
</form>
|
||||
<Cf7Form604 formKey="contact-form-1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user