@formsnip/embed 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,517 @@
1
+ import React, { useRef, useState, useEffect } from 'react';
2
+
3
+ const ALLOWED_FILE_EXTENSIONS = '.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.mp4,.mpeg,.mov,.avi,.webm,.mkv,.mp3,.wav,.ogg,.aac,.flac';
4
+ const MAX_TOTAL_FILE_SIZE = 15 * 1024 * 1024; // 15MB
5
+ /**
6
+ * Upload a file to R2 via presigned URL
7
+ */
8
+ async function uploadFile(file, formId, baseUrl) {
9
+ try {
10
+ // Step 1: Get presigned upload URL
11
+ const signResponse = await fetch(`${baseUrl}/uploads/sign`, {
12
+ method: 'POST',
13
+ headers: {
14
+ 'Content-Type': 'application/json',
15
+ },
16
+ credentials: 'include',
17
+ body: JSON.stringify({
18
+ filename: file.name,
19
+ contentType: file.type,
20
+ size: file.size,
21
+ formId,
22
+ }),
23
+ });
24
+ if (!signResponse.ok) {
25
+ return {
26
+ success: false,
27
+ error: 'Failed to get upload URL',
28
+ };
29
+ }
30
+ const signData = await signResponse.json();
31
+ if (!signData.success || !signData.data) {
32
+ return {
33
+ success: false,
34
+ error: signData.message || 'Invalid upload URL response',
35
+ };
36
+ }
37
+ const { uploadUrl, fileKey } = signData.data;
38
+ // Step 2: Upload file directly to R2
39
+ const uploadResponse = await fetch(uploadUrl, {
40
+ method: 'PUT',
41
+ body: file,
42
+ headers: {
43
+ 'Content-Type': file.type,
44
+ },
45
+ });
46
+ if (!uploadResponse.ok) {
47
+ return {
48
+ success: false,
49
+ error: `Upload failed: ${uploadResponse.statusText}`,
50
+ };
51
+ }
52
+ return {
53
+ success: true,
54
+ fileKey,
55
+ };
56
+ }
57
+ catch (error) {
58
+ return {
59
+ success: false,
60
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
61
+ };
62
+ }
63
+ }
64
+ /**
65
+ * Upload multiple files to R2
66
+ */
67
+ async function uploadFiles(files, formId, baseUrl) {
68
+ // Check total size
69
+ const totalSize = files.reduce((sum, file) => sum + file.size, 0);
70
+ if (totalSize > MAX_TOTAL_FILE_SIZE) {
71
+ return {
72
+ success: false,
73
+ errors: [`Total file size exceeds 15MB limit per submission`],
74
+ };
75
+ }
76
+ const results = await Promise.allSettled(files.map((file) => uploadFile(file, formId, baseUrl)));
77
+ const fileKeys = [];
78
+ const errors = [];
79
+ results.forEach((result, index) => {
80
+ if (result.status === 'fulfilled' && result.value.success && result.value.fileKey) {
81
+ fileKeys.push(result.value.fileKey);
82
+ }
83
+ else {
84
+ const error = result.status === 'fulfilled'
85
+ ? result.value.error || 'Upload failed'
86
+ : result.reason?.message || 'Upload failed';
87
+ errors.push(`${files[index].name}: ${error}`);
88
+ }
89
+ });
90
+ return {
91
+ success: fileKeys.length > 0,
92
+ fileKeys: fileKeys.length > 0 ? fileKeys : undefined,
93
+ errors: errors.length > 0 ? errors : undefined,
94
+ };
95
+ }
96
+
97
+ const FileUpload = ({ id, label, required = false, disabled = false, multiple = true, onFilesChange, uploadedFiles = [], uploading = false, error, className = '', }) => {
98
+ const fileInputRef = useRef(null);
99
+ const [selectedFiles, setSelectedFiles] = useState([]);
100
+ const handleFileSelect = (e) => {
101
+ const files = Array.from(e.target.files || []);
102
+ if (multiple) {
103
+ setSelectedFiles((prev) => [...prev, ...files]);
104
+ onFilesChange([...selectedFiles, ...files]);
105
+ }
106
+ else {
107
+ setSelectedFiles(files);
108
+ onFilesChange(files);
109
+ }
110
+ };
111
+ const removeFile = (index) => {
112
+ const newFiles = selectedFiles.filter((_, i) => i !== index);
113
+ setSelectedFiles(newFiles);
114
+ onFilesChange(newFiles);
115
+ if (fileInputRef.current) {
116
+ fileInputRef.current.value = '';
117
+ }
118
+ };
119
+ const formatFileSize = (bytes) => {
120
+ if (bytes === 0)
121
+ return '0 Bytes';
122
+ const k = 1024;
123
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
124
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
125
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
126
+ };
127
+ const handleDrop = (e) => {
128
+ e.preventDefault();
129
+ e.stopPropagation();
130
+ if (disabled || uploading)
131
+ return;
132
+ const files = Array.from(e.dataTransfer.files);
133
+ if (multiple) {
134
+ setSelectedFiles((prev) => [...prev, ...files]);
135
+ onFilesChange([...selectedFiles, ...files]);
136
+ }
137
+ else {
138
+ setSelectedFiles(files.slice(0, 1));
139
+ onFilesChange(files.slice(0, 1));
140
+ }
141
+ };
142
+ const handleDragOver = (e) => {
143
+ e.preventDefault();
144
+ e.stopPropagation();
145
+ };
146
+ return (React.createElement("div", { className: className },
147
+ label && (React.createElement("label", { className: "fs-text-sm fs-text-gray-700 fs-mb-1" },
148
+ label,
149
+ required && React.createElement("span", { className: "fs-text-red-500", style: { marginLeft: '0.25rem' } }, "*"))),
150
+ React.createElement("div", { onDrop: handleDrop, onDragOver: handleDragOver, className: `fs-border-2 fs-border-dashed fs-rounded-lg fs-p-6 fs-text-center ${disabled || uploading ? '' : 'fs-cursor-pointer fs-hover-border-blue-400 fs-hover-bg-blue-50'}`, style: {
151
+ borderColor: '#d1d5db',
152
+ backgroundColor: disabled || uploading ? '#f9fafb' : '#ffffff',
153
+ cursor: disabled || uploading ? 'not-allowed' : 'pointer',
154
+ }, onClick: () => !disabled && !uploading && fileInputRef.current?.click() },
155
+ React.createElement("input", { ref: fileInputRef, type: "file", id: id, multiple: multiple, onChange: handleFileSelect, className: "hidden", disabled: disabled || uploading, required: required && selectedFiles.length === 0 && uploadedFiles.length === 0, accept: ALLOWED_FILE_EXTENSIONS }),
156
+ React.createElement("div", { className: "fs-flex fs-flex-col fs-items-center" },
157
+ React.createElement("svg", { className: "fs-text-gray-400", style: { width: '3rem', height: '3rem', margin: '0 auto 0.5rem' }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
158
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" })),
159
+ React.createElement("p", { className: "fs-text-sm fs-text-gray-600 fs-mb-1" }, uploading ? (React.createElement("span", { className: "fs-text-blue-600" }, "Uploading files...")) : (React.createElement(React.Fragment, null,
160
+ React.createElement("span", { className: "fs-text-blue-600", style: { fontWeight: 500 } }, "Click to upload"),
161
+ ' or drag and drop'))),
162
+ React.createElement("p", { className: "fs-text-xs fs-text-gray-500" },
163
+ multiple ? 'Multiple files supported' : 'Single file only',
164
+ " (Images, PDFs, videos, audio - Max 15MB total)"))),
165
+ selectedFiles.length > 0 && (React.createElement("div", { className: "mt-3 space-y-2" }, selectedFiles.map((file, index) => (React.createElement("div", { key: `${file.name}-${index}`, className: "flex items-center justify-between p-2 bg-gray-50 rounded border border-gray-200" },
166
+ React.createElement("div", { className: "flex items-center space-x-2 flex-1 min-w-0" },
167
+ React.createElement("svg", { className: "w-5 h-5 text-gray-400 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
168
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" })),
169
+ React.createElement("div", { className: "flex-1 min-w-0" },
170
+ React.createElement("p", { className: "text-sm font-medium text-gray-700 truncate" }, file.name),
171
+ React.createElement("p", { className: "text-xs text-gray-500" }, formatFileSize(file.size)))),
172
+ !uploading && (React.createElement("button", { type: "button", onClick: (e) => {
173
+ e.stopPropagation();
174
+ removeFile(index);
175
+ }, className: "ml-2 text-red-500 hover:text-red-700 flex-shrink-0" },
176
+ React.createElement("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
177
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }))))))))),
178
+ uploadedFiles.length > 0 && (React.createElement("div", { className: "mt-3 space-y-2" }, uploadedFiles.map((fileKey, index) => {
179
+ const filename = fileKey.split('/').pop()?.split('-').slice(2).join('-') || fileKey;
180
+ return (React.createElement("div", { key: index, className: "flex items-center justify-between p-2 bg-green-50 rounded border border-green-200" },
181
+ React.createElement("div", { className: "flex items-center space-x-2 flex-1 min-w-0" },
182
+ React.createElement("svg", { className: "w-5 h-5 text-green-500 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
183
+ React.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })),
184
+ React.createElement("div", { className: "flex-1 min-w-0" },
185
+ React.createElement("p", { className: "text-sm font-medium text-green-700 truncate" }, filename),
186
+ React.createElement("p", { className: "text-xs text-green-600" }, "Uploaded")))));
187
+ }))),
188
+ error && React.createElement("p", { className: "mt-2 text-sm text-red-600" }, error)));
189
+ };
190
+
191
+ /**
192
+ * Inject base styles into the document head (same as embed script)
193
+ */
194
+ function injectBaseStyles() {
195
+ if (typeof document === 'undefined')
196
+ return;
197
+ if (document.getElementById('formsnip-base-styles'))
198
+ return;
199
+ const css = [
200
+ '.fs-flex{display:flex}',
201
+ '.fs-flex-col{flex-direction:column}',
202
+ '.fs-gap-5{gap:1.25rem}',
203
+ '.fs-relative{position:relative}',
204
+ '.fs-absolute{position:absolute}',
205
+ '.fs-right-5{right:1.25rem}',
206
+ '.fs-top-5{top:1.25rem}',
207
+ '.fs-top-half{top:50%}',
208
+ '.fs-translate-y-half{transform:translateY(-50%)}',
209
+ '.fs-w-full{width:100%}',
210
+ '.fs-p-5{padding:1.25rem}',
211
+ '.fs-pr-10{padding-right:2.5rem}',
212
+ '.fs-px-3{padding-left:0.75rem;padding-right:0.75rem}',
213
+ '.fs-py-2{padding-top:0.5rem;padding-bottom:0.5rem}',
214
+ '.fs-rounded-md{border-radius:0.375rem}',
215
+ '.fs-rounded-full{border-radius:9999px}',
216
+ '.fs-h-\\[180px\\]{height:180px}',
217
+ '.fs-resize-none{resize:none}',
218
+ '.fs-text-red-500{color:#ef4444}',
219
+ '.fs-pointer-events-none{pointer-events:none}',
220
+ '.fs-font-medium{font-weight:500}',
221
+ '.fs-text-lg{font-size:1.125rem;line-height:1.75rem}',
222
+ '.fs-border-2{border-width:2px}',
223
+ '.fs-border-dashed{border-style:dashed}',
224
+ '.fs-text-center{text-align:center}',
225
+ '.fs-cursor-pointer{cursor:pointer}',
226
+ '.fs-hover-border-blue-400:hover{border-color:#60a5fa}',
227
+ '.fs-hover-bg-blue-50:hover{background-color:#eff6ff}',
228
+ '.fs-mt-2{margin-top:0.5rem}',
229
+ '.fs-mb-1{margin-bottom:0.25rem}',
230
+ '.fs-text-xs{font-size:0.75rem;line-height:1rem}',
231
+ '.fs-text-sm{font-size:0.875rem;line-height:1.25rem}',
232
+ '.fs-text-gray-400{color:#9ca3af}',
233
+ '.fs-text-gray-500{color:#6b7280}',
234
+ '.fs-text-gray-600{color:#4b5563}',
235
+ '.fs-text-blue-600{color:#2563eb}',
236
+ '.fs-text-green-600{color:#16a34a}',
237
+ '.fs-text-red-600{color:#dc2626}',
238
+ '.fs-bg-gray-50{background-color:#f9fafb}',
239
+ '.fs-bg-green-50{background-color:#f0fdf4}',
240
+ '.fs-border-gray-200{border-color:#e5e7eb}',
241
+ '.fs-border-green-200{border-color:#bbf7d0}',
242
+ '.fs-rounded-lg{border-radius:0.5rem}',
243
+ '.fs-p-2{padding:0.5rem}',
244
+ '.fs-p-6{padding:1.5rem}',
245
+ '.fs-space-y-2>*+*{margin-top:0.5rem}',
246
+ '.fs-flex-1{flex:1 1 0%}',
247
+ '.fs-min-w-0{min-width:0}',
248
+ '.fs-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
249
+ '.fs-flex-shrink-0{flex-shrink:0}',
250
+ '.fs-items-center{align-items:center}',
251
+ '.fs-justify-between{justify-content:space-between}',
252
+ '.fs-space-x-2>*+*{margin-left:0.5rem}',
253
+ ].join('');
254
+ const style = document.createElement('style');
255
+ style.id = 'formsnip-base-styles';
256
+ style.type = 'text/css';
257
+ style.appendChild(document.createTextNode(css));
258
+ document.head.appendChild(style);
259
+ }
260
+ /**
261
+ * Apply embed styles to an element (same logic as embed script)
262
+ */
263
+ function applyStyles(styles, customStyles) {
264
+ if (!customStyles)
265
+ return styles;
266
+ const result = { ...styles };
267
+ if (customStyles.backgroundColor) {
268
+ result.backgroundColor = customStyles.backgroundColor;
269
+ }
270
+ if (customStyles.color) {
271
+ result.color = customStyles.color;
272
+ }
273
+ if (customStyles.borderColor) {
274
+ result.borderColor = customStyles.borderColor;
275
+ result.border = `1px solid ${customStyles.borderColor}`;
276
+ }
277
+ if (customStyles.borderRadius !== undefined) {
278
+ result.borderRadius = `${customStyles.borderRadius}px`;
279
+ }
280
+ if (customStyles.paddingX !== undefined || customStyles.paddingY !== undefined) {
281
+ const px = customStyles.paddingX !== undefined ? customStyles.paddingX : 0;
282
+ const py = customStyles.paddingY !== undefined ? customStyles.paddingY : 0;
283
+ result.padding = `${py}px ${px}px`;
284
+ }
285
+ return result;
286
+ }
287
+ /**
288
+ * CSS class names matching embed script
289
+ */
290
+ const CLASSES = {
291
+ form: 'fs-flex fs-flex-col fs-gap-5',
292
+ field: '',
293
+ inner: 'fs-relative',
294
+ input: 'fs-p-5 fs-pr-10 fs-w-full fs-rounded-md',
295
+ textarea: 'fs-p-5 fs-pr-10 fs-h-[180px] fs-w-full fs-rounded-md fs-resize-none',
296
+ button: 'fs-p-5 fs-rounded-full fs-font-medium fs-text-lg',
297
+ };
298
+
299
+ const DEFAULT_BASE_URL = 'https://api.formsnip.com';
300
+ const FormSnip = ({ formId, baseUrl = DEFAULT_BASE_URL, onSuccess, onError, className = '', }) => {
301
+ const [form, setForm] = useState(null);
302
+ const [formData, setFormData] = useState({});
303
+ const [selectedFiles, setSelectedFiles] = useState({});
304
+ const [uploadingFiles, setUploadingFiles] = useState({});
305
+ const [uploadErrors, setUploadErrors] = useState({});
306
+ const [loading, setLoading] = useState(true);
307
+ const [error, setError] = useState(null);
308
+ const [submitError, setSubmitError] = useState(null);
309
+ const [submitSuccess, setSubmitSuccess] = useState(false);
310
+ const [isSubmitting, setIsSubmitting] = useState(false);
311
+ useEffect(() => {
312
+ // Inject base styles on mount (same as embed script)
313
+ injectBaseStyles();
314
+ const fetchForm = async () => {
315
+ try {
316
+ const response = await fetch(`${baseUrl}/forms/get-form/${formId}`);
317
+ if (!response.ok) {
318
+ throw new Error('Failed to load form');
319
+ }
320
+ const json = await response.json();
321
+ if (json.success && json.data) {
322
+ // Form data includes embedStyles from the database
323
+ // These styles are set in the EmbedForm page and stored in the Form model
324
+ setForm(json.data);
325
+ // Initialize form data
326
+ const initialData = json.data.fields.reduce((acc, field) => {
327
+ acc[field.id] = field.type === 'file' ? [] : '';
328
+ return acc;
329
+ }, {});
330
+ setFormData(initialData);
331
+ setSelectedFiles({});
332
+ }
333
+ else {
334
+ setError(json.message || 'Failed to load form');
335
+ }
336
+ }
337
+ catch (err) {
338
+ setError(err.message || 'Failed to load form');
339
+ if (onError) {
340
+ onError(err.message || 'Failed to load form');
341
+ }
342
+ }
343
+ finally {
344
+ setLoading(false);
345
+ }
346
+ };
347
+ fetchForm();
348
+ }, [formId, baseUrl, onError]);
349
+ const handleInputChange = (fieldId, value) => {
350
+ setFormData((prev) => ({
351
+ ...prev,
352
+ [fieldId]: value,
353
+ }));
354
+ };
355
+ const handleFilesChange = async (fieldId, files) => {
356
+ if (files.length === 0) {
357
+ setSelectedFiles((prev) => ({ ...prev, [fieldId]: [] }));
358
+ setFormData((prev) => ({ ...prev, [fieldId]: [] }));
359
+ return;
360
+ }
361
+ setSelectedFiles((prev) => ({ ...prev, [fieldId]: files }));
362
+ setUploadingFiles((prev) => ({ ...prev, [fieldId]: true }));
363
+ setUploadErrors((prev) => {
364
+ const newErrors = { ...prev };
365
+ delete newErrors[fieldId];
366
+ return newErrors;
367
+ });
368
+ const result = await uploadFiles(files, formId, baseUrl);
369
+ setUploadingFiles((prev) => ({ ...prev, [fieldId]: false }));
370
+ if (result.success && result.fileKeys && result.fileKeys.length > 0) {
371
+ const existingFileKeys = Array.isArray(formData[fieldId])
372
+ ? formData[fieldId]
373
+ : [];
374
+ setFormData((prev) => ({
375
+ ...prev,
376
+ [fieldId]: [...existingFileKeys, ...result.fileKeys],
377
+ }));
378
+ }
379
+ else {
380
+ setUploadErrors((prev) => ({
381
+ ...prev,
382
+ [fieldId]: result.errors?.join(', ') || 'Upload failed',
383
+ }));
384
+ }
385
+ };
386
+ const handleSubmit = async (e) => {
387
+ e.preventDefault();
388
+ setSubmitError(null);
389
+ setSubmitSuccess(false);
390
+ setIsSubmitting(true);
391
+ try {
392
+ const response = await fetch(`${baseUrl}/submissions/create-submission/${formId}`, {
393
+ method: 'POST',
394
+ headers: {
395
+ 'Content-Type': 'application/json',
396
+ 'X-Requested-With': 'XMLHttpRequest',
397
+ },
398
+ credentials: 'include',
399
+ body: JSON.stringify(formData),
400
+ });
401
+ const json = await response.json();
402
+ if (response.ok && (json.success === undefined || json.success === true)) {
403
+ setSubmitSuccess(true);
404
+ if (onSuccess) {
405
+ onSuccess(json.data);
406
+ }
407
+ // Reset form
408
+ const emptyData = Object.keys(formData).reduce((acc, key) => {
409
+ const field = form?.fields.find((f) => f.id === key);
410
+ acc[key] = field?.type === 'file' ? [] : '';
411
+ return acc;
412
+ }, {});
413
+ setFormData(emptyData);
414
+ setSelectedFiles({});
415
+ setUploadErrors({});
416
+ }
417
+ else {
418
+ const errorMsg = json.message || 'Submission failed';
419
+ setSubmitError(errorMsg);
420
+ if (onError) {
421
+ onError(errorMsg);
422
+ }
423
+ }
424
+ }
425
+ catch (err) {
426
+ const errorMsg = err.message || 'Failed to submit form';
427
+ setSubmitError(errorMsg);
428
+ if (onError) {
429
+ onError(errorMsg);
430
+ }
431
+ }
432
+ finally {
433
+ setIsSubmitting(false);
434
+ }
435
+ };
436
+ const renderField = (field) => {
437
+ // Use embedStyles from database (set in EmbedForm page)
438
+ const fieldStyles = form?.embedStyles?.field || {};
439
+ const isRequired = field.required === true;
440
+ const commonProps = {
441
+ id: `field-${field.id}`,
442
+ name: field.id,
443
+ value: formData[field.id] || '',
444
+ onChange: (e) => handleInputChange(field.id, e.target.value),
445
+ placeholder: field.placeholder || '',
446
+ required: isRequired,
447
+ style: applyStyles({}, fieldStyles),
448
+ className: field.type === 'textarea' ? CLASSES.textarea : CLASSES.input,
449
+ };
450
+ const wrap = (React.createElement("div", { className: CLASSES.field },
451
+ field.type !== 'checkbox' && field.type !== 'radio' && (React.createElement("label", { htmlFor: `field-${field.id}`, className: "fs-text-sm fs-text-gray-700 fs-mb-1" },
452
+ field.label,
453
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))),
454
+ React.createElement("div", { className: CLASSES.inner }, field.type === 'checkbox' ? (React.createElement("label", { className: "fs-flex fs-items-center" },
455
+ React.createElement("input", { type: "checkbox", id: `field-${field.id}`, name: field.id, checked: String(formData[field.id]) === 'true' || formData[field.id] === 'on', onChange: (e) => handleInputChange(field.id, e.target.checked ? 'true' : 'false'), required: isRequired }),
456
+ React.createElement("span", { style: { marginLeft: '0.5rem' } }, field.label || field.placeholder || 'Check this box'),
457
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))) : field.type === 'radio' ? (React.createElement(React.Fragment, null,
458
+ React.createElement("label", { className: "fs-text-sm fs-text-gray-700 fs-mb-1" }, field.label),
459
+ React.createElement("label", { className: "fs-flex fs-items-center" },
460
+ React.createElement("input", { type: "radio", id: `field-${field.id}-yes`, name: field.id, value: "yes", checked: formData[field.id] === 'yes', onChange: (e) => handleInputChange(field.id, e.target.value), required: isRequired }),
461
+ React.createElement("span", { style: { marginLeft: '0.5rem' } }, " Yes")),
462
+ React.createElement("label", { className: "fs-flex fs-items-center" },
463
+ React.createElement("input", { type: "radio", id: `field-${field.id}-no`, name: field.id, value: "no", checked: formData[field.id] === 'no', onChange: (e) => handleInputChange(field.id, e.target.value), required: isRequired }),
464
+ React.createElement("span", { style: { marginLeft: '0.5rem' } }, " No")),
465
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))) : field.type === 'file' ? (React.createElement(React.Fragment, null,
466
+ React.createElement("label", { htmlFor: `field-${field.id}`, className: "fs-text-sm fs-text-gray-700 fs-mb-1" },
467
+ field.label,
468
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*"))),
469
+ (() => {
470
+ const uploadedFileKeys = Array.isArray(formData[field.id])
471
+ ? formData[field.id]
472
+ : formData[field.id]
473
+ ? [formData[field.id]]
474
+ : [];
475
+ return (React.createElement(FileUpload, { id: field.id, required: isRequired, disabled: uploadingFiles[field.id], multiple: true, onFilesChange: (files) => handleFilesChange(field.id, files), uploadedFiles: uploadedFileKeys, uploading: uploadingFiles[field.id], error: uploadErrors[field.id] }));
476
+ })())) : field.type === 'textarea' ? (React.createElement(React.Fragment, null,
477
+ React.createElement("textarea", { ...commonProps, rows: 4 }),
478
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-5 fs-text-red-500 fs-pointer-events-none" }, "*")))) : (React.createElement(React.Fragment, null,
479
+ React.createElement("input", { type: field.type || 'text', ...commonProps }),
480
+ isRequired && (React.createElement("span", { className: "fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none" }, "*")))))));
481
+ return wrap;
482
+ };
483
+ if (loading) {
484
+ return (React.createElement("div", { className: className },
485
+ React.createElement("div", { className: "fs-text-center", style: { padding: '2rem 0' } },
486
+ React.createElement("p", { className: "fs-text-gray-600" }, "Loading form..."))));
487
+ }
488
+ if (error || !form) {
489
+ return (React.createElement("div", { className: className },
490
+ React.createElement("div", { className: "fs-text-center", style: { padding: '2rem 0' } },
491
+ React.createElement("p", { className: "fs-text-red-600" }, error || 'Form not found'))));
492
+ }
493
+ // Use embedStyles from database (set in EmbedForm page)
494
+ const buttonStyles = form.embedStyles?.button || {};
495
+ return (React.createElement("div", { className: className },
496
+ React.createElement("div", { id: "formsnip-message" }),
497
+ submitError && (React.createElement("div", { className: "fs-px-3 fs-py-2 fs-rounded-md", style: {
498
+ color: '#991b1b',
499
+ background: '#fee2e2',
500
+ border: '1px solid #fecaca',
501
+ marginBottom: '1rem',
502
+ } }, submitError)),
503
+ submitSuccess && (React.createElement("div", { className: "fs-px-3 fs-py-2 fs-rounded-md", style: {
504
+ color: '#166534',
505
+ background: '#dcfce7',
506
+ border: '1px solid #bbf7d0',
507
+ marginBottom: '1rem',
508
+ } }, "Thank you! Your submission has been received.")),
509
+ React.createElement("form", { id: "formsnip-form", onSubmit: handleSubmit, className: CLASSES.form },
510
+ form.fields
511
+ .filter((field) => field.isActive !== false)
512
+ .map((field) => (React.createElement(React.Fragment, { key: field.id }, renderField(field)))),
513
+ React.createElement("button", { type: "submit", disabled: isSubmitting, className: CLASSES.button, style: applyStyles({}, buttonStyles) }, isSubmitting ? 'Submitting...' : form.submitButtonText || 'Submit'))));
514
+ };
515
+
516
+ export { ALLOWED_FILE_EXTENSIONS, FileUpload, FormSnip, MAX_TOTAL_FILE_SIZE, uploadFile, uploadFiles };
517
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/utils/upload.ts","../src/components/FileUpload.tsx","../src/utils/styles.ts","../src/FormSnip.tsx"],"sourcesContent":["const ALLOWED_FILE_EXTENSIONS = '.jpg,.jpeg,.png,.gif,.webp,.svg,.pdf,.mp4,.mpeg,.mov,.avi,.webm,.mkv,.mp3,.wav,.ogg,.aac,.flac';\nconst MAX_TOTAL_FILE_SIZE = 15 * 1024 * 1024; // 15MB\n\nexport interface UploadResult {\n success: boolean;\n fileKey?: string;\n error?: string;\n}\n\nexport interface UploadMultipleResult {\n success: boolean;\n fileKeys?: string[];\n errors?: string[];\n}\n\n/**\n * Upload a file to R2 via presigned URL\n */\nexport async function uploadFile(\n file: File,\n formId: string,\n baseUrl: string\n): Promise<UploadResult> {\n try {\n // Step 1: Get presigned upload URL\n const signResponse = await fetch(`${baseUrl}/uploads/sign`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n body: JSON.stringify({\n filename: file.name,\n contentType: file.type,\n size: file.size,\n formId,\n }),\n });\n\n if (!signResponse.ok) {\n return {\n success: false,\n error: 'Failed to get upload URL',\n };\n }\n\n const signData = await signResponse.json();\n if (!signData.success || !signData.data) {\n return {\n success: false,\n error: signData.message || 'Invalid upload URL response',\n };\n }\n\n const { uploadUrl, fileKey } = signData.data;\n\n // Step 2: Upload file directly to R2\n const uploadResponse = await fetch(uploadUrl, {\n method: 'PUT',\n body: file,\n headers: {\n 'Content-Type': file.type,\n },\n });\n\n if (!uploadResponse.ok) {\n return {\n success: false,\n error: `Upload failed: ${uploadResponse.statusText}`,\n };\n }\n\n return {\n success: true,\n fileKey,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n}\n\n/**\n * Upload multiple files to R2\n */\nexport async function uploadFiles(\n files: File[],\n formId: string,\n baseUrl: string\n): Promise<UploadMultipleResult> {\n // Check total size\n const totalSize = files.reduce((sum, file) => sum + file.size, 0);\n if (totalSize > MAX_TOTAL_FILE_SIZE) {\n return {\n success: false,\n errors: [`Total file size exceeds 15MB limit per submission`],\n };\n }\n\n const results = await Promise.allSettled(\n files.map((file) => uploadFile(file, formId, baseUrl))\n );\n\n const fileKeys: string[] = [];\n const errors: string[] = [];\n\n results.forEach((result, index) => {\n if (result.status === 'fulfilled' && result.value.success && result.value.fileKey) {\n fileKeys.push(result.value.fileKey);\n } else {\n const error =\n result.status === 'fulfilled'\n ? result.value.error || 'Upload failed'\n : result.reason?.message || 'Upload failed';\n errors.push(`${files[index].name}: ${error}`);\n }\n });\n\n return {\n success: fileKeys.length > 0,\n fileKeys: fileKeys.length > 0 ? fileKeys : undefined,\n errors: errors.length > 0 ? errors : undefined,\n };\n}\n\nexport { ALLOWED_FILE_EXTENSIONS, MAX_TOTAL_FILE_SIZE };\n","import React, { useRef, useState } from 'react';\nimport { ALLOWED_FILE_EXTENSIONS } from '../utils/upload';\nimport { CLASSES } from '../utils/styles';\n\ninterface FileUploadProps {\n id: string;\n label?: string;\n required?: boolean;\n disabled?: boolean;\n multiple?: boolean;\n onFilesChange: (files: File[]) => void;\n uploadedFiles?: string[];\n uploading?: boolean;\n error?: string;\n className?: string;\n}\n\nexport const FileUpload: React.FC<FileUploadProps> = ({\n id,\n label,\n required = false,\n disabled = false,\n multiple = true,\n onFilesChange,\n uploadedFiles = [],\n uploading = false,\n error,\n className = '',\n}) => {\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [selectedFiles, setSelectedFiles] = useState<File[]>([]);\n\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || []);\n\n if (multiple) {\n setSelectedFiles((prev) => [...prev, ...files]);\n onFilesChange([...selectedFiles, ...files]);\n } else {\n setSelectedFiles(files);\n onFilesChange(files);\n }\n };\n\n const removeFile = (index: number) => {\n const newFiles = selectedFiles.filter((_, i) => i !== index);\n setSelectedFiles(newFiles);\n onFilesChange(newFiles);\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n const formatFileSize = (bytes: number): string => {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];\n };\n\n const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n if (disabled || uploading) return;\n\n const files = Array.from(e.dataTransfer.files);\n\n if (multiple) {\n setSelectedFiles((prev) => [...prev, ...files]);\n onFilesChange([...selectedFiles, ...files]);\n } else {\n setSelectedFiles(files.slice(0, 1));\n onFilesChange(files.slice(0, 1));\n }\n };\n\n const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n return (\n <div className={className}>\n {label && (\n <label className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">\n {label}\n {required && <span className=\"fs-text-red-500\" style={{ marginLeft: '0.25rem' }}>*</span>}\n </label>\n )}\n\n <div\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n className={`fs-border-2 fs-border-dashed fs-rounded-lg fs-p-6 fs-text-center ${\n disabled || uploading ? '' : 'fs-cursor-pointer fs-hover-border-blue-400 fs-hover-bg-blue-50'\n }`}\n style={{\n borderColor: '#d1d5db',\n backgroundColor: disabled || uploading ? '#f9fafb' : '#ffffff',\n cursor: disabled || uploading ? 'not-allowed' : 'pointer',\n }}\n onClick={() => !disabled && !uploading && fileInputRef.current?.click()}\n >\n <input\n ref={fileInputRef}\n type=\"file\"\n id={id}\n multiple={multiple}\n onChange={handleFileSelect}\n className=\"hidden\"\n disabled={disabled || uploading}\n required={required && selectedFiles.length === 0 && uploadedFiles.length === 0}\n accept={ALLOWED_FILE_EXTENSIONS}\n />\n\n <div className=\"fs-flex fs-flex-col fs-items-center\">\n <svg\n className=\"fs-text-gray-400\"\n style={{ width: '3rem', height: '3rem', margin: '0 auto 0.5rem' }}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12\"\n />\n </svg>\n <p className=\"fs-text-sm fs-text-gray-600 fs-mb-1\">\n {uploading ? (\n <span className=\"fs-text-blue-600\">Uploading files...</span>\n ) : (\n <>\n <span className=\"fs-text-blue-600\" style={{ fontWeight: 500 }}>Click to upload</span>\n {' or drag and drop'}\n </>\n )}\n </p>\n <p className=\"fs-text-xs fs-text-gray-500\">\n {multiple ? 'Multiple files supported' : 'Single file only'} (Images, PDFs, videos,\n audio - Max 15MB total)\n </p>\n </div>\n </div>\n\n {selectedFiles.length > 0 && (\n <div className=\"mt-3 space-y-2\">\n {selectedFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center justify-between p-2 bg-gray-50 rounded border border-gray-200\"\n >\n <div className=\"flex items-center space-x-2 flex-1 min-w-0\">\n <svg\n className=\"w-5 h-5 text-gray-400 flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-gray-700 truncate\">{file.name}</p>\n <p className=\"text-xs text-gray-500\">{formatFileSize(file.size)}</p>\n </div>\n </div>\n {!uploading && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n removeFile(index);\n }}\n className=\"ml-2 text-red-500 hover:text-red-700 flex-shrink-0\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n\n {uploadedFiles.length > 0 && (\n <div className=\"mt-3 space-y-2\">\n {uploadedFiles.map((fileKey, index) => {\n const filename = fileKey.split('/').pop()?.split('-').slice(2).join('-') || fileKey;\n return (\n <div\n key={index}\n className=\"flex items-center justify-between p-2 bg-green-50 rounded border border-green-200\"\n >\n <div className=\"flex items-center space-x-2 flex-1 min-w-0\">\n <svg\n className=\"w-5 h-5 text-green-500 flex-shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-green-700 truncate\">{filename}</p>\n <p className=\"text-xs text-green-600\">Uploaded</p>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {error && <p className=\"mt-2 text-sm text-red-600\">{error}</p>}\n </div>\n );\n};\n","/**\n * Inject base styles into the document head (same as embed script)\n */\nexport function injectBaseStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.getElementById('formsnip-base-styles')) return;\n\n const css = [\n '.fs-flex{display:flex}',\n '.fs-flex-col{flex-direction:column}',\n '.fs-gap-5{gap:1.25rem}',\n '.fs-relative{position:relative}',\n '.fs-absolute{position:absolute}',\n '.fs-right-5{right:1.25rem}',\n '.fs-top-5{top:1.25rem}',\n '.fs-top-half{top:50%}',\n '.fs-translate-y-half{transform:translateY(-50%)}',\n '.fs-w-full{width:100%}',\n '.fs-p-5{padding:1.25rem}',\n '.fs-pr-10{padding-right:2.5rem}',\n '.fs-px-3{padding-left:0.75rem;padding-right:0.75rem}',\n '.fs-py-2{padding-top:0.5rem;padding-bottom:0.5rem}',\n '.fs-rounded-md{border-radius:0.375rem}',\n '.fs-rounded-full{border-radius:9999px}',\n '.fs-h-\\\\[180px\\\\]{height:180px}',\n '.fs-resize-none{resize:none}',\n '.fs-text-red-500{color:#ef4444}',\n '.fs-pointer-events-none{pointer-events:none}',\n '.fs-font-medium{font-weight:500}',\n '.fs-text-lg{font-size:1.125rem;line-height:1.75rem}',\n '.fs-border-2{border-width:2px}',\n '.fs-border-dashed{border-style:dashed}',\n '.fs-text-center{text-align:center}',\n '.fs-cursor-pointer{cursor:pointer}',\n '.fs-hover-border-blue-400:hover{border-color:#60a5fa}',\n '.fs-hover-bg-blue-50:hover{background-color:#eff6ff}',\n '.fs-mt-2{margin-top:0.5rem}',\n '.fs-mb-1{margin-bottom:0.25rem}',\n '.fs-text-xs{font-size:0.75rem;line-height:1rem}',\n '.fs-text-sm{font-size:0.875rem;line-height:1.25rem}',\n '.fs-text-gray-400{color:#9ca3af}',\n '.fs-text-gray-500{color:#6b7280}',\n '.fs-text-gray-600{color:#4b5563}',\n '.fs-text-blue-600{color:#2563eb}',\n '.fs-text-green-600{color:#16a34a}',\n '.fs-text-red-600{color:#dc2626}',\n '.fs-bg-gray-50{background-color:#f9fafb}',\n '.fs-bg-green-50{background-color:#f0fdf4}',\n '.fs-border-gray-200{border-color:#e5e7eb}',\n '.fs-border-green-200{border-color:#bbf7d0}',\n '.fs-rounded-lg{border-radius:0.5rem}',\n '.fs-p-2{padding:0.5rem}',\n '.fs-p-6{padding:1.5rem}',\n '.fs-space-y-2>*+*{margin-top:0.5rem}',\n '.fs-flex-1{flex:1 1 0%}',\n '.fs-min-w-0{min-width:0}',\n '.fs-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',\n '.fs-flex-shrink-0{flex-shrink:0}',\n '.fs-items-center{align-items:center}',\n '.fs-justify-between{justify-content:space-between}',\n '.fs-space-x-2>*+*{margin-left:0.5rem}',\n ].join('');\n\n const style = document.createElement('style');\n style.id = 'formsnip-base-styles';\n style.type = 'text/css';\n style.appendChild(document.createTextNode(css));\n document.head.appendChild(style);\n}\n\n/**\n * Apply embed styles to an element (same logic as embed script)\n */\nexport function applyStyles(\n styles: React.CSSProperties,\n customStyles?: {\n backgroundColor?: string;\n color?: string;\n borderColor?: string;\n borderRadius?: number;\n paddingX?: number;\n paddingY?: number;\n }\n): React.CSSProperties {\n if (!customStyles) return styles;\n\n const result = { ...styles };\n\n if (customStyles.backgroundColor) {\n result.backgroundColor = customStyles.backgroundColor;\n }\n if (customStyles.color) {\n result.color = customStyles.color;\n }\n if (customStyles.borderColor) {\n result.borderColor = customStyles.borderColor;\n result.border = `1px solid ${customStyles.borderColor}`;\n }\n if (customStyles.borderRadius !== undefined) {\n result.borderRadius = `${customStyles.borderRadius}px`;\n }\n if (customStyles.paddingX !== undefined || customStyles.paddingY !== undefined) {\n const px = customStyles.paddingX !== undefined ? customStyles.paddingX : 0;\n const py = customStyles.paddingY !== undefined ? customStyles.paddingY : 0;\n result.padding = `${py}px ${px}px`;\n }\n\n return result;\n}\n\n/**\n * CSS class names matching embed script\n */\nexport const CLASSES = {\n form: 'fs-flex fs-flex-col fs-gap-5',\n field: '',\n inner: 'fs-relative',\n input: 'fs-p-5 fs-pr-10 fs-w-full fs-rounded-md',\n textarea: 'fs-p-5 fs-pr-10 fs-h-[180px] fs-w-full fs-rounded-md fs-resize-none',\n button: 'fs-p-5 fs-rounded-full fs-font-medium fs-text-lg',\n};\n","import React, { useState, useEffect } from 'react';\nimport { Form, FormSnipProps, SubmissionResponse } from './types';\nimport { uploadFiles } from './utils/upload';\nimport { FileUpload } from './components/FileUpload';\nimport { injectBaseStyles, applyStyles, CLASSES } from './utils/styles';\n\nconst DEFAULT_BASE_URL = 'https://api.formsnip.com';\n\nexport const FormSnip: React.FC<FormSnipProps> = ({\n formId,\n baseUrl = DEFAULT_BASE_URL,\n onSuccess,\n onError,\n className = '',\n}) => {\n const [form, setForm] = useState<Form | null>(null);\n const [formData, setFormData] = useState<Record<string, string | string[]>>({});\n const [selectedFiles, setSelectedFiles] = useState<Record<string, File[]>>({});\n const [uploadingFiles, setUploadingFiles] = useState<Record<string, boolean>>({});\n const [uploadErrors, setUploadErrors] = useState<Record<string, string>>({});\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [submitSuccess, setSubmitSuccess] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n useEffect(() => {\n // Inject base styles on mount (same as embed script)\n injectBaseStyles();\n\n const fetchForm = async () => {\n try {\n const response = await fetch(`${baseUrl}/forms/get-form/${formId}`);\n if (!response.ok) {\n throw new Error('Failed to load form');\n }\n const json = await response.json();\n if (json.success && json.data) {\n // Form data includes embedStyles from the database\n // These styles are set in the EmbedForm page and stored in the Form model\n setForm(json.data);\n // Initialize form data\n const initialData = json.data.fields.reduce(\n (acc: Record<string, string | string[]>, field: Form['fields'][0]) => {\n acc[field.id] = field.type === 'file' ? [] : '';\n return acc;\n },\n {}\n );\n setFormData(initialData);\n setSelectedFiles({});\n } else {\n setError(json.message || 'Failed to load form');\n }\n } catch (err: any) {\n setError(err.message || 'Failed to load form');\n if (onError) {\n onError(err.message || 'Failed to load form');\n }\n } finally {\n setLoading(false);\n }\n };\n\n fetchForm();\n }, [formId, baseUrl, onError]);\n\n const handleInputChange = (fieldId: string, value: string) => {\n setFormData((prev) => ({\n ...prev,\n [fieldId]: value,\n }));\n };\n\n const handleFilesChange = async (fieldId: string, files: File[]) => {\n if (files.length === 0) {\n setSelectedFiles((prev) => ({ ...prev, [fieldId]: [] }));\n setFormData((prev) => ({ ...prev, [fieldId]: [] }));\n return;\n }\n\n setSelectedFiles((prev) => ({ ...prev, [fieldId]: files }));\n setUploadingFiles((prev) => ({ ...prev, [fieldId]: true }));\n setUploadErrors((prev) => {\n const newErrors = { ...prev };\n delete newErrors[fieldId];\n return newErrors;\n });\n\n const result = await uploadFiles(files, formId, baseUrl);\n\n setUploadingFiles((prev) => ({ ...prev, [fieldId]: false }));\n\n if (result.success && result.fileKeys && result.fileKeys.length > 0) {\n const existingFileKeys = Array.isArray(formData[fieldId])\n ? (formData[fieldId] as string[])\n : [];\n setFormData((prev) => ({\n ...prev,\n [fieldId]: [...existingFileKeys, ...result.fileKeys!],\n }));\n } else {\n setUploadErrors((prev) => ({\n ...prev,\n [fieldId]: result.errors?.join(', ') || 'Upload failed',\n }));\n }\n };\n\n const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitError(null);\n setSubmitSuccess(false);\n setIsSubmitting(true);\n\n try {\n const response = await fetch(`${baseUrl}/submissions/create-submission/${formId}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Requested-With': 'XMLHttpRequest',\n },\n credentials: 'include',\n body: JSON.stringify(formData),\n });\n\n const json: SubmissionResponse = await response.json();\n\n if (response.ok && (json.success === undefined || json.success === true)) {\n setSubmitSuccess(true);\n if (onSuccess) {\n onSuccess(json.data);\n }\n // Reset form\n const emptyData = Object.keys(formData).reduce(\n (acc: Record<string, string | string[]>, key) => {\n const field = form?.fields.find((f) => f.id === key);\n acc[key] = field?.type === 'file' ? [] : '';\n return acc;\n },\n {}\n );\n setFormData(emptyData);\n setSelectedFiles({});\n setUploadErrors({});\n } else {\n const errorMsg = json.message || 'Submission failed';\n setSubmitError(errorMsg);\n if (onError) {\n onError(errorMsg);\n }\n }\n } catch (err: any) {\n const errorMsg = err.message || 'Failed to submit form';\n setSubmitError(errorMsg);\n if (onError) {\n onError(errorMsg);\n }\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const renderField = (field: Form['fields'][0]) => {\n // Use embedStyles from database (set in EmbedForm page)\n const fieldStyles = form?.embedStyles?.field || {};\n const isRequired = field.required === true;\n\n const commonProps = {\n id: `field-${field.id}`,\n name: field.id,\n value: (formData[field.id] as string) || '',\n onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>\n handleInputChange(field.id, e.target.value),\n placeholder: field.placeholder || '',\n required: isRequired,\n style: applyStyles({}, fieldStyles),\n className: field.type === 'textarea' ? CLASSES.textarea : CLASSES.input,\n };\n\n const wrap = (\n <div className={CLASSES.field}>\n {field.type !== 'checkbox' && field.type !== 'radio' && (\n <label htmlFor={`field-${field.id}`} className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">\n {field.label}\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </label>\n )}\n <div className={CLASSES.inner}>\n {field.type === 'checkbox' ? (\n <label className=\"fs-flex fs-items-center\">\n <input\n type=\"checkbox\"\n id={`field-${field.id}`}\n name={field.id}\n checked={String(formData[field.id]) === 'true' || formData[field.id] === 'on'}\n onChange={(e) => handleInputChange(field.id, e.target.checked ? 'true' : 'false')}\n required={isRequired}\n />\n <span style={{ marginLeft: '0.5rem' }}>{field.label || field.placeholder || 'Check this box'}</span>\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </label>\n ) : field.type === 'radio' ? (\n <>\n <label className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">{field.label}</label>\n <label className=\"fs-flex fs-items-center\">\n <input\n type=\"radio\"\n id={`field-${field.id}-yes`}\n name={field.id}\n value=\"yes\"\n checked={formData[field.id] === 'yes'}\n onChange={(e) => handleInputChange(field.id, e.target.value)}\n required={isRequired}\n />\n <span style={{ marginLeft: '0.5rem' }}> Yes</span>\n </label>\n <label className=\"fs-flex fs-items-center\">\n <input\n type=\"radio\"\n id={`field-${field.id}-no`}\n name={field.id}\n value=\"no\"\n checked={formData[field.id] === 'no'}\n onChange={(e) => handleInputChange(field.id, e.target.value)}\n required={isRequired}\n />\n <span style={{ marginLeft: '0.5rem' }}> No</span>\n </label>\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </>\n ) : field.type === 'file' ? (\n <>\n <label htmlFor={`field-${field.id}`} className=\"fs-text-sm fs-text-gray-700 fs-mb-1\">\n {field.label}\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </label>\n {(() => {\n const uploadedFileKeys = Array.isArray(formData[field.id])\n ? (formData[field.id] as string[])\n : formData[field.id]\n ? [formData[field.id] as string]\n : [];\n\n return (\n <FileUpload\n id={field.id}\n required={isRequired}\n disabled={uploadingFiles[field.id]}\n multiple={true}\n onFilesChange={(files) => handleFilesChange(field.id, files)}\n uploadedFiles={uploadedFileKeys}\n uploading={uploadingFiles[field.id]}\n error={uploadErrors[field.id]}\n />\n );\n })()}\n </>\n ) : field.type === 'textarea' ? (\n <>\n <textarea {...commonProps} rows={4} />\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-5 fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </>\n ) : (\n <>\n <input type={field.type || 'text'} {...commonProps} />\n {isRequired && (\n <span className=\"fs-absolute fs-right-5 fs-top-half fs-translate-y-half fs-text-red-500 fs-pointer-events-none\">\n *\n </span>\n )}\n </>\n )}\n </div>\n </div>\n );\n\n return wrap;\n };\n\n if (loading) {\n return (\n <div className={className}>\n <div className=\"fs-text-center\" style={{ padding: '2rem 0' }}>\n <p className=\"fs-text-gray-600\">Loading form...</p>\n </div>\n </div>\n );\n }\n\n if (error || !form) {\n return (\n <div className={className}>\n <div className=\"fs-text-center\" style={{ padding: '2rem 0' }}>\n <p className=\"fs-text-red-600\">{error || 'Form not found'}</p>\n </div>\n </div>\n );\n }\n\n // Use embedStyles from database (set in EmbedForm page)\n const buttonStyles = form.embedStyles?.button || {};\n\n return (\n <div className={className}>\n <div id=\"formsnip-message\"></div>\n {submitError && (\n <div\n className=\"fs-px-3 fs-py-2 fs-rounded-md\"\n style={{\n color: '#991b1b',\n background: '#fee2e2',\n border: '1px solid #fecaca',\n marginBottom: '1rem',\n }}\n >\n {submitError}\n </div>\n )}\n\n {submitSuccess && (\n <div\n className=\"fs-px-3 fs-py-2 fs-rounded-md\"\n style={{\n color: '#166534',\n background: '#dcfce7',\n border: '1px solid #bbf7d0',\n marginBottom: '1rem',\n }}\n >\n Thank you! Your submission has been received.\n </div>\n )}\n\n <form id=\"formsnip-form\" onSubmit={handleSubmit} className={CLASSES.form}>\n {form.fields\n .filter((field) => field.isActive !== false)\n .map((field) => (\n <React.Fragment key={field.id}>{renderField(field)}</React.Fragment>\n ))}\n\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className={CLASSES.button}\n style={applyStyles({}, buttonStyles)}\n >\n {isSubmitting ? 'Submitting...' : form.submitButtonText || 'Submit'}\n </button>\n </form>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}