#26 - Loading animation + success message fix

This commit was merged in pull request #31.
This commit is contained in:
Martin Slachta
2026-06-22 11:20:28 +02:00
parent c754e18a82
commit 97ee8fc991
32 changed files with 597 additions and 175 deletions
+70 -4
View File
@@ -1,6 +1,7 @@
<?php
use Reservair\Forms\RsvFormBuilder;
use Reservair\Forms\RsvCodeEditor;
use Reservair\Layout\RsvColumnLayout;
class RsvFormsPage extends RsvAdminPage {
@@ -127,7 +128,20 @@ class RsvFormsPage extends RsvAdminPage {
echo RsvFormBuilder::create('edit_form_definition', get_rest_url(null, 'reservations/v1/form-definition/' . $id), 'PUT', 'Form definition updated.')
->text('name', 'Name', '', true, $form_def['name'])
->select('definition.email_key', 'Email Key', $email_key_options, "Form field that holds the submitter's email address.", true, $definition['email_key'] ?? '')
->code('definition.success_message', 'Success message', 'Shown to the visitor after a successful submission. HTML is allowed. Use <reservation-summary></reservation-summary> to display the selected reservations. Leave blank for the default message.', $definition['success_message'] ?? '')
->custom('Success message', function () use ($definition) {
$editor = RsvCodeEditor::render('definition.success_message', [
'value' => $definition['success_message'] ?? '',
'mode' => 'text/html',
'rows' => 8,
]);
$hint = esc_html('Shown to the visitor after a successful submission. HTML is allowed. Use <reservation-summary></reservation-summary> to display the selected reservations. Leave blank for the default message.');
return '<div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap;">'
. '<div style="flex:1 1 320px;min-width:0;">' . $editor . '<p class="description">' . $hint . '</p></div>'
. '<div style="flex:1 1 320px;min-width:0;">'
. '<span style="display:block;font-weight:600;margin-bottom:8px;">Live preview</span>'
. '<div id="rsv_success_preview" class="rsv-form-preview rsv-success-msg"></div>'
. '</div></div>';
})
->render();
?>
@@ -169,11 +183,11 @@ class RsvFormsPage extends RsvAdminPage {
->output();
?>
<?php $this->elements_table_script($elements_with_ids, $next_id, 'edit_form_definition', $element_types, $timetables, $programs, $bindings); ?>
<?php $this->elements_table_script($elements_with_ids, $next_id, 'edit_form_definition', $element_types, $timetables, $programs, $bindings, $id); ?>
<?php
}
private function elements_table_script(array $elements_with_ids, int $next_id, string $form_id, array $element_types, array $timetables = [], array $programs = [], array $bindings = []): void {
private function elements_table_script(array $elements_with_ids, int $next_id, string $form_id, array $element_types, array $timetables = [], array $programs = [], array $bindings = [], int $definition_id = 0): void {
$elements_json = json_encode($elements_with_ids);
$types_json = json_encode(array_values($element_types));
$timetables_json = json_encode(array_values($timetables));
@@ -365,6 +379,54 @@ class RsvFormsPage extends RsvAdminPage {
// The preview form is inert: block submission (capture so it works after re-render).
rsv_preview_el?.addEventListener('submit', (e) => e.preventDefault(), true);
// --- Success message live preview ----------------------------------
// Rendered with the same template engine the front-end uses after a real
// submission. The data comes from this form's most recent submission, so
// {{ tokens }} and <reservation-summary> mirror a genuine confirmation;
// the message text itself updates live as it is edited.
const rsv_success_preview_el = document.getElementById('rsv_success_preview');
let rsv_success_preview_timer = null;
let rsv_success_preview_data = {};
function rsv_schedule_success_preview() {
if (!rsv_success_preview_el) return;
clearTimeout(rsv_success_preview_timer);
rsv_success_preview_timer = setTimeout(rsv_render_success_preview, 300);
}
function rsv_render_success_preview() {
if (!rsv_success_preview_el) return;
const form = document.getElementById('<?= $form_id ?>');
const tpl = (form?.querySelector('[name="definition.success_message"]')?.value ?? '').trim();
if (tpl === '') {
rsv_success_preview_el.innerHTML = '<p class="rsv-preview-empty">Leave blank to show the default confirmation message.</p>';
return;
}
try {
rsv_success_preview_el.innerHTML = RsvFormSender.render_template(tpl, rsv_success_preview_data);
} catch (e) {
console.log(e);
rsv_success_preview_el.innerHTML = '<p class="rsv-preview-empty">Preview unavailable.</p>';
}
}
// Buttons rendered into the preview (e.g. <reset-form-button>) live inside
// the edit form — keep them from submitting it.
rsv_success_preview_el?.addEventListener('click', (e) => {
if (e.target.closest('button, input[type="submit"], input[type="image"]')) e.preventDefault();
}, true);
if (rsv_success_preview_el) {
rsv_render_success_preview();
fetch('<?= get_rest_url(null, 'reservations/v1/form-definition/' . $definition_id . '/submission/latest') ?>', {
credentials: 'same-origin',
headers: { 'Accept': 'application/json', 'X-WP-Nonce': ReservairServiceAPI.nonce },
})
.then(r => r.ok ? r.json() : null)
.then(res => { rsv_success_preview_data = res?.data ?? {}; rsv_render_success_preview(); })
.catch(() => {});
}
function rsv_render_element_inline_form(dt, row, data) {
const builder = RsvInlineFormBuilder.create(rsv_elements_source)
.fieldset('Element', '50%')
@@ -620,11 +682,15 @@ class RsvFormsPage extends RsvAdminPage {
}
const rsv_meta_form = document.getElementById('<?= $form_id ?>');
['name', 'definition.email_key', 'definition.success_message', 'definition.membership_combine'].forEach((n) => {
['name', 'definition.email_key', 'definition.membership_combine'].forEach((n) => {
const el = rsv_meta_form?.querySelector(`[name="${n}"]`);
el?.addEventListener('input', rsv_schedule_preview);
el?.addEventListener('change', rsv_schedule_preview);
});
// The success message drives its own preview only.
const rsv_success_input = rsv_meta_form?.querySelector('[name="definition.success_message"]');
rsv_success_input?.addEventListener('input', rsv_schedule_success_preview);
rsv_success_input?.addEventListener('change', rsv_schedule_success_preview);
RsvAdminForm.bind(document.getElementById('<?= $form_id ?>'), {
transform: () => rsv_collect_definition(),