feat: add form builder AJAX handlers (F2.11)

- Create FormBuilderAjax class for React form builder
- Add formipay_save_form_fields AJAX action
- Add formipay_load_form_fields AJAX action
- Sanitize field data on save
- Update FormBuilder to load fields on mount
- Add save status feedback (saving, saved, error)
- Register FormBuilderAjax singleton in main plugin file
This commit is contained in:
dwindown
2026-04-18 11:41:10 +07:00
parent ec1f01ef24
commit 7f50b27df3
3 changed files with 167 additions and 6 deletions

View File

@@ -3,7 +3,7 @@
*/
import { __ } from '@wordpress/i18n';
import { useState, useCallback } from '@wordpress/element';
import { useState, useCallback, useEffect } from '@wordpress/element';
import FormCanvas from './FormCanvas';
import FieldPalette from './FieldPalette';
import FieldSettingsPanel from './FieldSettingsPanel';
@@ -13,9 +13,36 @@ import './FormBuilder.css';
export default function FormBuilder({ formId, initialData = {} }) {
const [fields, setFields] = useState(initialData.fields || []);
const [selectedFieldId, setSelectedFieldId] = useState(null);
const [saveStatus, setSaveStatus] = useState(null);
const selectedField = fields.find(f => f.field_id === selectedFieldId) || null;
// Load existing fields on mount
useEffect(() => {
if (formId && !initialData.fields) {
loadFields();
}
}, [formId]);
const loadFields = useCallback(() => {
const params = new URLSearchParams({
action: 'formipay_load_form_fields',
post_id: formId,
_wpnonce: window.formipayAdmin?.nonce || '',
});
fetch(`${window.formipayAdmin?.ajaxUrl || '/wp-admin/admin-ajax.php'}?${params}`)
.then(response => response.json())
.then(result => {
if (result.success && result.data.fields) {
setFields(result.data.fields);
}
})
.catch(error => {
console.error('Load error:', error);
});
}, [formId]);
const handleDrop = useCallback((newField) => {
setFields([...fields, newField]);
setSelectedFieldId(newField.field_id);
@@ -42,7 +69,7 @@ export default function FormBuilder({ formId, initialData = {} }) {
}, [fields, selectedFieldId]);
const handleSave = useCallback(() => {
// Save form fields via AJAX
setSaveStatus('saving');
const formData = new FormData();
formData.append('action', 'formipay_save_form_fields');
formData.append('post_id', formId);
@@ -57,13 +84,15 @@ export default function FormBuilder({ formId, initialData = {} }) {
.then(response => response.json())
.then(result => {
if (result.success) {
// Show success message
console.log('Form saved successfully');
setSaveStatus('saved');
setTimeout(() => setSaveStatus(null), 2000);
} else {
setSaveStatus('error');
console.error('Failed to save form:', result.message);
}
})
.catch(error => {
setSaveStatus('error');
console.error('Save error:', error);
});
}, [fields, formId]);
@@ -82,10 +111,14 @@ export default function FormBuilder({ formId, initialData = {} }) {
</button>
<button
type="button"
className="button button-primary"
className={`button button-primary ${saveStatus === 'saving' ? 'is-busy' : ''}`}
onClick={handleSave}
disabled={saveStatus === 'saving'}
>
{ __('Save Form', 'formipay') }
{ saveStatus === 'saved' ? __('Saved!', 'formipay') :
saveStatus === 'error' ? __('Failed', 'formipay') :
saveStatus === 'saving' ? __('Saving...', 'formipay') :
__('Save Form', 'formipay') }
</button>
</div>
</div>