143 lines
4.3 KiB
JavaScript
143 lines
4.3 KiB
JavaScript
const RsvFormSender = {
|
|
get_form_url(form_id) {
|
|
return ReservairServiceAPI.restUrl + '/form/' + form_id;
|
|
},
|
|
|
|
clear_feedback(form) {
|
|
form.querySelectorAll('.rsv-field-error').forEach(el => el.remove());
|
|
form.querySelectorAll('.rsv-invalid').forEach(el => el.classList.remove('rsv-invalid'));
|
|
form.querySelector('.rsv-error-summary')?.remove();
|
|
},
|
|
|
|
show_errors(form, errors) {
|
|
this.clear_feedback(form);
|
|
|
|
const ul = document.createElement('ul');
|
|
for (const err of errors) {
|
|
const li = document.createElement('li');
|
|
li.textContent = err.message;
|
|
ul.appendChild(li);
|
|
|
|
if (err.element) {
|
|
const field = form.querySelector(`[name="${err.element}"]`);
|
|
if (field) {
|
|
field.classList.add('rsv-invalid');
|
|
const msg = document.createElement('span');
|
|
msg.classList.add('rsv-field-error');
|
|
msg.textContent = err.message;
|
|
field.insertAdjacentElement('afterend', msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
const summary = document.createElement('div');
|
|
summary.classList.add('rsv-error-summary');
|
|
summary.appendChild(ul);
|
|
form.prepend(summary);
|
|
},
|
|
|
|
show_success(form, _data) {
|
|
const s = ReservairStrings.form;
|
|
const wrapper = form.parentElement;
|
|
const existing = Array.from(wrapper.children);
|
|
|
|
const svgNS = 'http://www.w3.org/2000/svg';
|
|
const path = document.createElementNS(svgNS, 'path');
|
|
path.setAttribute('d', 'M6 14l6 6L22 8');
|
|
path.setAttribute('stroke', '#16a34a');
|
|
path.setAttribute('stroke-width', '2.5');
|
|
path.setAttribute('stroke-linecap', 'round');
|
|
path.setAttribute('stroke-linejoin', 'round');
|
|
const svg = document.createElementNS(svgNS, 'svg');
|
|
svg.setAttribute('width', '28');
|
|
svg.setAttribute('height', '28');
|
|
svg.setAttribute('viewBox', '0 0 28 28');
|
|
svg.setAttribute('fill', 'none');
|
|
svg.appendChild(path);
|
|
|
|
const icon = document.createElement('div');
|
|
icon.className = 'success-icon';
|
|
icon.appendChild(svg);
|
|
|
|
const title = document.createElement('div');
|
|
title.className = 'success-title';
|
|
title.textContent = s.success_title;
|
|
|
|
const subtitle = document.createElement('p');
|
|
subtitle.className = 'success-msg';
|
|
subtitle.textContent = s.success_subtitle;
|
|
|
|
const reset_btn = document.createElement('button');
|
|
reset_btn.className = 'reset-btn';
|
|
reset_btn.textContent = s.new_reservation;
|
|
|
|
const state = document.createElement('div');
|
|
state.className = 'success-state';
|
|
state.append(icon, title, subtitle, reset_btn);
|
|
|
|
const msg = document.createElement('div');
|
|
msg.appendChild(state);
|
|
|
|
existing.forEach(child => child.style.display = 'none');
|
|
wrapper.appendChild(msg);
|
|
|
|
reset_btn.addEventListener('click', () => {
|
|
msg.remove();
|
|
form.reset();
|
|
this.clear_feedback(form);
|
|
existing.forEach(child => child.style.display = '');
|
|
});
|
|
},
|
|
|
|
set_loading(form, is_loading) {
|
|
const btn = form.querySelector('button[type="submit"], button:not([type])');
|
|
if (!btn) return;
|
|
btn.disabled = is_loading;
|
|
btn.classList.toggle('rsv-loading', is_loading);
|
|
},
|
|
|
|
encode_to_json(form) {
|
|
const fields = form.querySelectorAll('.rsv-form-field');
|
|
const body = {};
|
|
fields.forEach(field => {
|
|
const name = field.name ?? field.getAttribute('name');
|
|
try {
|
|
body[name] = JSON.parse(field.value);
|
|
} catch {
|
|
body[name] = field.value;
|
|
}
|
|
});
|
|
return body;
|
|
},
|
|
|
|
send_form(event) {
|
|
event.preventDefault();
|
|
const form = event.target;
|
|
this.clear_feedback(form);
|
|
this.set_loading(form, true);
|
|
const body = this.encode_to_json(form);
|
|
|
|
fetch(this.get_form_url(form.id), {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
.then(async response => {
|
|
const data = await response.json().catch(() => null);
|
|
if (!response.ok) throw { status: response.status, body: data };
|
|
return data;
|
|
})
|
|
.then(data => {
|
|
this.show_success(form, data);
|
|
})
|
|
.catch(error => {
|
|
const errors = error?.body?.errors
|
|
?? [{ element: '', message: ReservairStrings.form.error_generic }];
|
|
this.show_errors(form, errors);
|
|
})
|
|
.finally(() => {
|
|
this.set_loading(form, false);
|
|
});
|
|
},
|
|
};
|