Change: user sets date of previous calibration, not upcoming expire dates.

- seismograph list page enhanced with better visabilty, filtering, sorting, and calibration dates color coded.
This commit is contained in:
serversdwn
2026-02-06 21:17:14 +00:00
parent eb0a99796d
commit 89662d2fa5
8 changed files with 408 additions and 86 deletions

View File

@@ -144,12 +144,12 @@
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Seismograph Information</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Last Calibrated</label>
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Date of Last Calibration</label>
<p id="viewLastCalibrated" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
</div>
<div>
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Next Calibration Due</label>
<p id="viewNextCalibrationDue" class="mt-1 text-gray-900 dark:text-white font-medium">--</p>
<p id="viewNextCalibrationDue" class="mt-1 text-gray-900 dark:text-white font-medium inline-flex items-center gap-2">--</p>
</div>
<div>
<label class="text-sm font-medium text-gray-500 dark:text-gray-400">Deployed With Modem</label>
@@ -378,15 +378,12 @@
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Seismograph Information</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Last Calibrated</label>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Date of Last Calibration</label>
<input type="date" name="last_calibrated" id="lastCalibrated"
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Next calibration due date will be calculated automatically</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Next Calibration Due</label>
<input type="date" name="next_calibration_due" id="nextCalibrationDue"
class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-seismo-orange">
</div>
<input type="hidden" name="next_calibration_due" id="nextCalibrationDue">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Deployed With Modem</label>
<div class="flex gap-2">
@@ -589,6 +586,42 @@ let currentSnapshot = null;
let unitMap = null;
let mapMarker = null;
// Calibration interval in days (default 365, will be loaded from preferences)
let calibrationIntervalDays = 365;
// Load calibration interval from preferences
async function loadCalibrationInterval() {
try {
const response = await fetch('/api/settings/preferences');
if (response.ok) {
const prefs = await response.json();
calibrationIntervalDays = prefs.calibration_interval_days || 365;
}
} catch (e) {
console.error('Failed to load calibration interval:', e);
}
}
// Calculate next calibration due date from last calibrated date
function calculateNextCalibrationDue(lastCalibratedStr) {
if (!lastCalibratedStr) return '';
const lastCalibrated = new Date(lastCalibratedStr);
const nextDue = new Date(lastCalibrated);
nextDue.setDate(nextDue.getDate() + calibrationIntervalDays);
return nextDue.toISOString().split('T')[0];
}
// Setup auto-calculation for calibration fields
function setupCalibrationAutoCalc() {
const lastCal = document.getElementById('lastCalibrated');
const nextCal = document.getElementById('nextCalibrationDue');
if (lastCal && nextCal) {
lastCal.addEventListener('change', function() {
nextCal.value = calculateNextCalibrationDue(this.value);
});
}
}
// Fetch project display name (combines project_number, client_name, name)
async function fetchProjectDisplay(projectId) {
if (!projectId) return '';
@@ -819,7 +852,28 @@ function populateViewMode() {
// Seismograph fields
document.getElementById('viewLastCalibrated').textContent = currentUnit.last_calibrated || '--';
document.getElementById('viewNextCalibrationDue').textContent = currentUnit.next_calibration_due || '--';
// Calculate next calibration due and show with status indicator
const nextCalDueEl = document.getElementById('viewNextCalibrationDue');
if (currentUnit.last_calibrated) {
const nextDue = calculateNextCalibrationDue(currentUnit.last_calibrated);
const today = new Date().toISOString().split('T')[0];
const daysUntil = Math.floor((new Date(nextDue) - new Date(today)) / (1000 * 60 * 60 * 24));
let dotColor = 'bg-green-500';
let tooltip = `Calibration valid (${daysUntil} days remaining)`;
if (daysUntil < 0) {
dotColor = 'bg-red-500';
tooltip = `Calibration expired ${-daysUntil} days ago`;
} else if (daysUntil <= 14) {
dotColor = 'bg-yellow-500';
tooltip = `Calibration expires in ${daysUntil} days`;
}
nextCalDueEl.innerHTML = `<span class="w-2 h-2 rounded-full ${dotColor}" title="${tooltip}"></span>${nextDue}`;
} else {
nextCalDueEl.textContent = '--';
}
// Deployed with modem - show as clickable link
const modemLink = document.getElementById('viewDeployedWithModemLink');
@@ -960,7 +1014,10 @@ function populateEditForm() {
// Seismograph fields
document.getElementById('lastCalibrated').value = currentUnit.last_calibrated || '';
document.getElementById('nextCalibrationDue').value = currentUnit.next_calibration_due || '';
// Calculate next calibration due from last calibrated
document.getElementById('nextCalibrationDue').value = currentUnit.last_calibrated
? calculateNextCalibrationDue(currentUnit.last_calibrated)
: '';
// Populate modem picker for seismograph (uses -detail-seismo suffix)
const modemPickerValue = document.getElementById('modem-picker-value-detail-seismo');
@@ -1535,6 +1592,8 @@ async function pingModem() {
}
// Load data when page loads
loadCalibrationInterval();
setupCalibrationAutoCalc();
loadUnitData().then(() => {
loadPhotos();
loadUnitHistory();