Files
Rosary/assets/js/setup.js
T
pguzman 663fde3909 Initial commit — Rosary Presenter App
Full source for loveandrosary.com: slide-based Rosary/novena/Divine Mercy
Chaplet presentation tool with multi-user roles, SVG bead ring, audio uploads,
donate strip, and public session profiles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 18:44:08 -07:00

187 lines
7.4 KiB
JavaScript

/**
* assets/js/setup.js
* Setup form interactivity: conditional field visibility + form submission.
*/
(function () {
'use strict';
const form = document.getElementById('session-form');
const occasionSel = document.getElementById('occasion');
const photoInput = document.getElementById('photo');
const uploadStatus = document.getElementById('upload-status');
const submitBtn = document.getElementById('submit-btn');
const msgBox = document.getElementById('form-message');
const nameHelp = document.getElementById('name-help');
// Are we editing an existing session?
const isEditMode = !!form.querySelector('[name="id"]');
// Fields to show/hide by occasion (field IDs without the "field-" prefix)
const OCCASION_FIELDS = {
novena_deceased: ['novena_day', 'novena_mystery_mode', 'subject_name', 'subject_pronoun', 'subject_dates'],
divine_mercy_novena:['novena_day'],
memorial: ['subject_name', 'subject_pronoun', 'subject_dates'],
general_rosary: [],
};
const mysteryStandardWrap = document.getElementById('field-mystery_set_standard');
function toggleFields() {
const occasion = occasionSel.value;
const show = OCCASION_FIELDS[occasion] || [];
const isNovenaDeceased = (occasion === 'novena_deceased');
const isDivineMercy = (occasion === 'divine_mercy_novena');
const isAnyNovena = isNovenaDeceased || isDivineMercy;
// Standard mystery dropdown: hide for both novena types
if (mysteryStandardWrap) {
mysteryStandardWrap.style.display = isAnyNovena ? 'none' : '';
const sel = document.getElementById('mystery_set');
if (sel) {
if (isAnyNovena) {
sel.removeAttribute('required');
if (!sel.value) sel.value = 'sorrowful';
} else {
sel.setAttribute('required', '');
}
}
}
// Show/hide conditional fields
document.querySelectorAll('.conditional-field').forEach(el => {
const fieldName = el.id.replace('field-', '');
// novena_mystery_mode only shows for novena_deceased, not divine_mercy_novena
if (fieldName === 'novena_mystery_mode' && !isNovenaDeceased) {
el.style.display = 'none';
el.querySelectorAll('input, select').forEach(input => input.removeAttribute('required'));
return;
}
const visible = show.includes(fieldName);
el.style.display = visible ? '' : 'none';
el.querySelectorAll('input, select').forEach(input => {
if (!visible) input.removeAttribute('required');
});
});
// Update submit button label
if (submitBtn) {
if (isNovenaDeceased) {
submitBtn.textContent = submitBtn.dataset.labelNovenaDeceased;
} else if (isDivineMercy) {
submitBtn.textContent = submitBtn.dataset.labelDivineMercy;
} else {
submitBtn.textContent = submitBtn.dataset.labelDefault;
}
}
// Update session name help text
if (nameHelp) {
nameHelp.style.display = isAnyNovena && !isEditMode ? '' : 'none';
}
}
occasionSel.addEventListener('change', toggleFields);
toggleFields(); // run on page load (handles edit mode pre-selection)
// ------------------------------------------------------------------
// Photo upload on file selection
// ------------------------------------------------------------------
var photoUploading = false;
if (photoInput) {
photoInput.addEventListener('change', async function () {
if (!this.files || !this.files[0]) return;
const file = this.files[0];
uploadStatus.style.display = '';
uploadStatus.className = 'upload-status uploading';
uploadStatus.textContent = 'Uploading\u2026';
// Disable submit while upload is in progress
photoUploading = true;
if (submitBtn) submitBtn.disabled = true;
const fd = new FormData();
fd.append('photo', file);
try {
const res = await fetch(BASE_URL + '/api/upload_photo.php', { method: 'POST', body: fd });
const data = await res.json();
if (data.error) {
uploadStatus.className = 'upload-status error';
uploadStatus.textContent = 'Upload failed: ' + data.error;
} else {
document.getElementById('photo_path').value = data.path;
// Clear the file input so the file is not re-sent with the main form
photoInput.value = '';
uploadStatus.className = 'upload-status success';
uploadStatus.textContent = 'Photo uploaded successfully.';
}
} catch (err) {
uploadStatus.className = 'upload-status error';
uploadStatus.textContent = 'Network error during upload.';
} finally {
photoUploading = false;
if (submitBtn) submitBtn.disabled = false;
}
});
}
// ------------------------------------------------------------------
// Form submission via fetch
// ------------------------------------------------------------------
form.addEventListener('submit', async function (e) {
e.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
submitBtn.disabled = true;
submitBtn.textContent = 'Saving\u2026';
showMessage('', '');
const fd = new FormData(form);
try {
const res = await fetch(BASE_URL + '/api/save_session.php', { method: 'POST', body: fd });
const data = await res.json();
if (data.error) {
showMessage('error', data.error);
submitBtn.disabled = false;
const occ = occasionSel.value;
submitBtn.textContent = isEditMode
? submitBtn.dataset.labelDefault
: (occ === 'novena_deceased' ? submitBtn.dataset.labelNovenaDeceased
: occ === 'divine_mercy_novena' ? submitBtn.dataset.labelDivineMercy
: submitBtn.dataset.labelDefault);
} else if (data.novena) {
// All 9 days created — go to admin dashboard
window.location.href = BASE_URL + '/admin/?novena_created=' + data.ids.length;
} else {
// Single session — go to presentation
window.location.href = BASE_URL + '/present.php?id=' + data.id;
}
} catch (err) {
showMessage('error', 'Network error. Please try again.');
submitBtn.disabled = false;
submitBtn.textContent = submitBtn.dataset.labelDefault;
}
});
function showMessage(type, text) {
if (!text) {
msgBox.style.display = 'none';
return;
}
msgBox.style.display = '';
msgBox.className = 'alert alert-' + type;
msgBox.textContent = text;
}
})();