v0.10.24: /contact-us/ 一比一复刻(CF7 604 表单/通栏 hero/列宽修复)+ PG 连接池 HMR 泄漏修复

This commit is contained in:
bigcode
2026-11-03 01:31:31 +08:00
parent 864a737c58
commit 7559977ae1
9 changed files with 321 additions and 222 deletions
+71 -13
View File
@@ -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>
);
}
+1
View File
@@ -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",
+196
View File
@@ -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>
);
}
+4 -164
View File
@@ -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>