229 lines
7.9 KiB
JavaScript
229 lines
7.9 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
// --- ELEMENTS ---
|
|
const createAlarmForm = document.getElementById('createAlarmForm');
|
|
const alarmList = document.getElementById('alarmList');
|
|
const noAlarmsMessage = document.getElementById('noAlarmsMessage');
|
|
const alarmModalEl = document.getElementById('alarmModal');
|
|
const alarmModal = new bootstrap.Modal(alarmModalEl);
|
|
const dismissAlarmBtn = document.getElementById('dismissAlarmBtn');
|
|
const alarmSound = document.getElementById('alarmSound');
|
|
const alarmModalMessage = document.getElementById('alarmModalMessage');
|
|
|
|
// --- STATE ---
|
|
let isAlarmModalShown = false;
|
|
|
|
// --- FUNCTIONS ---
|
|
|
|
/**
|
|
* Handles the submission of the create alarm form.
|
|
*/
|
|
const handleCreateAlarm = async (e) => {
|
|
e.preventDefault();
|
|
const timeInput = document.getElementById('alarmTime');
|
|
const labelInput = document.getElementById('alarmLabel');
|
|
|
|
const formData = new FormData();
|
|
formData.append('action', 'create');
|
|
formData.append('alarm_time', timeInput.value);
|
|
formData.append('label', labelInput.value);
|
|
|
|
try {
|
|
const response = await fetch('api/alarms.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
addAlarmToList(result.id, timeInput.value, labelInput.value);
|
|
timeInput.value = '';
|
|
labelInput.value = '';
|
|
if (noAlarmsMessage) {
|
|
noAlarmsMessage.style.display = 'none';
|
|
}
|
|
} else {
|
|
alert('Error: ' + result.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to create alarm:', error);
|
|
alert('An error occurred while creating the alarm.');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handles the click on a delete alarm form.
|
|
*/
|
|
const handleDeleteAlarm = async (e) => {
|
|
if (!e.target.closest('.delete-alarm-form')) return;
|
|
e.preventDefault();
|
|
|
|
const form = e.target.closest('.delete-alarm-form');
|
|
const alarmId = form.querySelector('input[name="alarm_id"]').value;
|
|
|
|
if (!confirm('Are you sure you want to delete this alarm?')) return;
|
|
|
|
const formData = new FormData(form);
|
|
|
|
try {
|
|
const response = await fetch('api/alarms.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
const listItem = form.closest('li');
|
|
listItem.remove();
|
|
if (!alarmList.querySelector('li')) {
|
|
if (noAlarmsMessage) {
|
|
noAlarmsMessage.style.display = 'block';
|
|
}
|
|
}
|
|
} else {
|
|
alert('Error: ' + result.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to delete alarm:', error);
|
|
alert('An error occurred while deleting the alarm.');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Adds a new alarm item to the DOM.
|
|
*/
|
|
const addAlarmToList = (id, time, label, isActive = true) => {
|
|
const date = new Date(`1970-01-01T${time}`);
|
|
const formattedTime = date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
|
|
|
|
const li = document.createElement('li');
|
|
li.className = 'list-group-item d-flex justify-content-between align-items-center';
|
|
li.dataset.id = id;
|
|
li.innerHTML = `
|
|
<div class="d-flex align-items-center">
|
|
<div class="form-check form-switch me-3">
|
|
<input class="form-check-input toggle-alarm-switch" type="checkbox" role="switch" id="toggle-${id}" ${isActive ? 'checked' : ''}>
|
|
<label class="form-check-label" for="toggle-${id}"></label>
|
|
</div>
|
|
<div>
|
|
<span class="fw-bold fs-5">${formattedTime}</span>
|
|
<span class="text-muted ms-2">${escapeHTML(label)}</span>
|
|
</div>
|
|
</div>
|
|
<form class="delete-alarm-form">
|
|
<input type="hidden" name="action" value="delete">
|
|
<input type="hidden" name="alarm_id" value="${id}">
|
|
<button type="submit" class="btn btn-sm btn-outline-danger">
|
|
<i data-feather="trash-2" class="align-text-bottom"></i>
|
|
</button>
|
|
</form>
|
|
`;
|
|
alarmList.appendChild(li);
|
|
feather.replace();
|
|
};
|
|
|
|
/**
|
|
* Handles toggling the active state of an alarm.
|
|
*/
|
|
const handleToggleAlarm = async (e) => {
|
|
if (!e.target.classList.contains('toggle-alarm-switch')) return;
|
|
|
|
const switchEl = e.target;
|
|
const listItem = switchEl.closest('li');
|
|
const alarmId = listItem.dataset.id;
|
|
const isActive = switchEl.checked ? 1 : 0;
|
|
|
|
const formData = new FormData();
|
|
formData.append('action', 'toggle');
|
|
formData.append('alarm_id', alarmId);
|
|
formData.append('is_active', isActive);
|
|
|
|
try {
|
|
const response = await fetch('api/alarms.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
const result = await response.json();
|
|
|
|
if (!result.success) {
|
|
alert('Error: ' + result.message);
|
|
// Revert the switch on failure
|
|
switchEl.checked = !switchEl.checked;
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to toggle alarm:', error);
|
|
alert('An error occurred while updating the alarm.');
|
|
// Revert the switch on failure
|
|
switchEl.checked = !switchEl.checked;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Checks the server for any due alarms.
|
|
*/
|
|
const checkAlarms = async () => {
|
|
if (isAlarmModalShown) return; // Don't check if an alarm is already ringing
|
|
|
|
try {
|
|
const response = await fetch('api/alarms.php?action=check');
|
|
const result = await response.json();
|
|
|
|
if (result.success && result.alarms.length > 0) {
|
|
const alarm = result.alarms[0];
|
|
triggerAlarm(alarm);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error checking alarms:', error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Triggers the visual and audible alarm.
|
|
*/
|
|
const triggerAlarm = (alarm) => {
|
|
isAlarmModalShown = true;
|
|
if (alarm.label) {
|
|
alarmModalMessage.textContent = alarm.label;
|
|
} else {
|
|
alarmModalMessage.textContent = 'Time to write your notes.';
|
|
}
|
|
alarmModal.show();
|
|
alarmSound.play().catch(e => console.error("Audio play failed:", e));
|
|
};
|
|
|
|
/**
|
|
* Dismisses the alarm and redirects to the note page.
|
|
*/
|
|
const dismissAlarm = () => {
|
|
alarmSound.pause();
|
|
alarmSound.currentTime = 0;
|
|
alarmModal.hide();
|
|
isAlarmModalShown = false;
|
|
|
|
const today = new Date();
|
|
const dateString = today.getFullYear() + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0');
|
|
window.location.href = `note.php?date=${dateString}`;
|
|
};
|
|
|
|
const escapeHTML = (str) => {
|
|
const p = document.createElement('p');
|
|
p.appendChild(document.createTextNode(str));
|
|
return p.innerHTML;
|
|
}
|
|
|
|
// --- EVENT LISTENERS ---
|
|
if (createAlarmForm) {
|
|
createAlarmForm.addEventListener('submit', handleCreateAlarm);
|
|
}
|
|
|
|
if (alarmList) {
|
|
alarmList.addEventListener('click', handleDeleteAlarm);
|
|
alarmList.addEventListener('change', handleToggleAlarm);
|
|
}
|
|
|
|
if (dismissAlarmBtn) {
|
|
dismissAlarmBtn.addEventListener('click', dismissAlarm);
|
|
}
|
|
|
|
// --- INITIALIZATION ---
|
|
setInterval(checkAlarms, 5000); // Check for alarms every 5 seconds
|
|
}); |