PluginProbe
AI Builder – Generate pages, blocks, images & translate with AI / 2.1.3
AI Builder – Generate pages, blocks, images & translate with AI v2.1.3
2.8.0 2.7.10 2.7.9 2.7.8 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 All 123 releases
ai-builder / assets / js / src / editor-blocks / contact-form / index.js

index.js in AI Builder – Generate pages, blocks, images & translate with AI 2.1.3, at assets/js/src/editor-blocks/contact-form/index.js

213 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 const { registerBlockType } = wp.blocks;
2 const { __ } = wp.i18n;
3 const {
4 PanelBody,
5 TextControl,
6 Button,
7 SelectControl,
8 __experimentalNumberControl: NumberControl,
9 Notice,
10 } = wp.components;
11 const { InspectorControls, useBlockProps, RichText } =
12 wp.blockEditor || wp.editor;
13 const { useState } = wp.element;
14
15 import "./style.css";
16
17 const MAX_FIELDS = 5;
18
19 registerBlockType("ai-builder/aibui-contact-form", {
20 title: __("Contact Form (AI Builder)", "ai-builder"),
21 icon: "email",
22 category: "widgets",
23 supports: { align: ["wide", "full"], html: false },
24 attributes: {
25 recipientEmail: { type: "string", default: "" },
26 fromEmail: { type: "string", default: "" },
27 formTitle: { type: "string", default: "" },
28 description: { type: "string", default: "" },
29 fields: {
30 type: "array",
31 default: [{ id: 1, label: "", type: "text", required: false }],
32 },
33 buttonLabel: { type: "string", default: __("Send", "ai-builder") },
34 successMessage: {
35 type: "string",
36 default: __("Thank you, your message has been sent.", "ai-builder"),
37 },
38 },
39
40 edit: (props) => {
41 const { attributes, setAttributes } = props;
42 const {
43 recipientEmail,
44 formTitle,
45 description,
46 fields,
47 buttonLabel,
48 successMessage,
49 } = attributes;
50 const blockProps = useBlockProps({ className: "aibui-contact-form" });
51 const [notice, setNotice] = useState(null);
52
53 const updateField = (index, patch) => {
54 const next = fields.map((f, i) => (i === index ? { ...f, ...patch } : f));
55 setAttributes({ fields: next });
56 };
57
58 const addField = () => {
59 if (fields.length >= MAX_FIELDS) {
60 setNotice({
61 status: "warning",
62 message: __("Maximum fields reached", "ai-builder"),
63 });
64 return;
65 }
66 const nextId = Math.max(0, ...fields.map((f) => f.id || 0)) + 1;
67 setAttributes({
68 fields: [
69 ...fields,
70 { id: nextId, label: "", type: "text", required: false },
71 ],
72 });
73 };
74
75 const removeField = (index) => {
76 const next = fields.filter((_, i) => i !== index);
77 setAttributes({ fields: next });
78 };
79
80 return (
81 <div {...blockProps}>
82 <InspectorControls>
83 <PanelBody title={__("Settings", "ai-builder")} initialOpen>
84 <TextControl
85 label={__("Recipient email", "ai-builder")}
86 value={recipientEmail}
87 onChange={(val) => setAttributes({ recipientEmail: val })}
88 help={__("Where form submissions will be sent.", "ai-builder")}
89 />
90 <TextControl
91 label={__("From email (optional)", "ai-builder")}
92 value={attributes.fromEmail}
93 onChange={(val) => setAttributes({ fromEmail: val })}
94 help={__(
95 "Used as From header if matches site domain.",
96 "ai-builder"
97 )}
98 />
99 <TextControl
100 label={__("Button label", "ai-builder")}
101 value={buttonLabel}
102 onChange={(val) => setAttributes({ buttonLabel: val })}
103 help={__("Text displayed on the submit button.", "ai-builder")}
104 />
105 <TextControl
106 label={__("Success message", "ai-builder")}
107 value={successMessage}
108 onChange={(val) => setAttributes({ successMessage: val })}
109 help={__(
110 "Message shown when form is submitted successfully.",
111 "ai-builder"
112 )}
113 />
114 </PanelBody>
115 <PanelBody title={__("Fields", "ai-builder")} initialOpen>
116 {fields.map((field, index) => (
117 <div key={field.id} className="aibui-field-row">
118 <TextControl
119 label={__("Label", "ai-builder")}
120 value={field.label}
121 onChange={(val) => updateField(index, { label: val })}
122 />
123 <SelectControl
124 label={__("Type", "ai-builder")}
125 value={field.type}
126 options={[
127 { label: "Text", value: "text" },
128 { label: "Email", value: "email" },
129 { label: "Number", value: "number" },
130 { label: "Date", value: "date" },
131 { label: "Textarea", value: "textarea" },
132 ]}
133 onChange={(val) => updateField(index, { type: val })}
134 />
135 <SelectControl
136 label={__("Required", "ai-builder")}
137 value={field.required ? "1" : "0"}
138 options={[
139 { label: __("Yes", "ai-builder"), value: "1" },
140 { label: __("No", "ai-builder"), value: "0" },
141 ]}
142 onChange={(val) =>
143 updateField(index, { required: val === "1" })
144 }
145 />
146 <Button isDestructive onClick={() => removeField(index)}>
147 {__("Remove field", "ai-builder")}
148 </Button>
149 <hr />
150 </div>
151 ))}
152 <Button isSecondary onClick={addField}>
153 {__("Add field", "ai-builder")}
154 </Button>
155 </PanelBody>
156 </InspectorControls>
157
158 {notice && (
159 <Notice status={notice.status} onRemove={() => setNotice(null)}>
160 {notice.message}
161 </Notice>
162 )}
163
164 <div className="aibui-contact-form-preview">
165 <RichText
166 tagName="h3"
167 className="aibui-form-title"
168 value={formTitle}
169 onChange={(val) => setAttributes({ formTitle: val })}
170 placeholder={__("Form title", "ai-builder")}
171 />
172 <RichText
173 tagName="p"
174 className="aibui-form-description"
175 value={description}
176 onChange={(val) => setAttributes({ description: val })}
177 placeholder={__("Short description (optional)", "ai-builder")}
178 />
179 <div className="aibui-fields">
180 {fields.map((field) => (
181 <div key={field.id} className="aibui-field">
182 <label>
183 {field.label || __("Untitled field", "ai-builder")}
184 {field.required ? " *" : ""}
185 </label>
186 <div className="aibui-input-placeholder">{field.type}</div>
187 </div>
188 ))}
189 </div>
190 <Button variant="primary">{buttonLabel}</Button>
191 </div>
192 </div>
193 );
194 },
195
196 save: (props) => {
197 const { attributes } = props;
198 const blockProps = useBlockProps.save({ className: "aibui-contact-form" });
199 return (
200 <div
201 {...blockProps}
202 data-recipient={attributes.recipientEmail}
203 data-fields={encodeURIComponent(JSON.stringify(attributes.fields))}
204 data-title={attributes.formTitle}
205 data-description={attributes.description}
206 data-button={attributes.buttonLabel}
207 >
208 {/* Rendered via PHP render_callback for security */}
209 </div>
210 );
211 },
212 });
213