Finish implementation of Hazard list so it can handle when hazards end

This commit is contained in:
mrkmntal 2026-04-16 18:32:53 -04:00
commit 92822e2ddc
3 changed files with 21 additions and 11 deletions

View file

@ -307,17 +307,17 @@ if (!process.env?.STATIC) {
app.post('/api/hazard-history', async (req, res) => { app.post('/api/hazard-history', async (req, res) => {
try { try {
const { location, hazards } = req.body; const { location, locationKey, hazards } = req.body;
if (!location || !Array.isArray(hazards)) { if (!location || !locationKey || !Array.isArray(hazards)) {
res.status(400).json({ res.status(400).json({
success: false, success: false,
error: 'Missing or invalid location/hazards', error: 'Missing or invalid location/locationKey/hazards',
}); });
return; return;
} }
const history = await updateHistory({ location, hazards }); const history = await updateHistory({ location, locationKey, hazards });
res.json({ res.json({
success: true, success: true,
history, history,

View file

@ -274,9 +274,12 @@ class Hazards extends WeatherDisplay {
if (!this.weatherParameters) return; if (!this.weatherParameters) return;
// Format location // Format location
const { city, state, country, countryCode } = this.weatherParameters; const { city, state, country, countryCode, latitude, longitude } = this.weatherParameters;
const location = this.formatLocationLabel(city, state, country, countryCode); const location = this.formatLocationLabel(city, state, country, countryCode);
// Create stable location key from lat/lon (rounded to 3 decimal places ~111m precision)
const locationKey = `${parseFloat(latitude).toFixed(3)},${parseFloat(longitude).toFixed(3)}`;
// Normalize hazards for the API // Normalize hazards for the API
const hazards = (this.data || []).map((hazard) => ({ const hazards = (this.data || []).map((hazard) => ({
id: hazard.id, id: hazard.id,
@ -291,7 +294,7 @@ class Hazards extends WeatherDisplay {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ location, hazards }), body: JSON.stringify({ location, locationKey, hazards }),
}); });
} catch (error) { } catch (error) {
// Silently fail - hazard history is non-critical // Silently fail - hazard history is non-critical

View file

@ -83,28 +83,34 @@ const formatLocation = (city, state, country, countryCode) => {
/** /**
* Update hazard history with current active hazards for a location * Update hazard history with current active hazards for a location
* @param {Object} payload - Request payload * @param {Object} payload - Request payload
* @param {string} payload.location - Formatted location label * @param {string} payload.location - Formatted location label (for display)
* @param {string} payload.locationKey - Stable location key from lat/lon (for matching)
* @param {Array} payload.hazards - Array of active hazards * @param {Array} payload.hazards - Array of active hazards
* @returns {Array} Updated history * @returns {Array} Updated history
*/ */
const updateHistory = async (payload) => { const updateHistory = async (payload) => {
const { location, hazards = [] } = payload; const { location, locationKey, hazards = [] } = payload;
// Load existing history // Load existing history
let history = await loadHistory(); let history = await loadHistory();
const now = new Date().toISOString(); const now = new Date().toISOString();
// Use locationKey for matching if provided, fall back to location for backward compatibility
const matchKey = locationKey || location;
// Create a set of active hazard keys for this location // Create a set of active hazard keys for this location
const activeKeys = new Set(); const activeKeys = new Set();
hazards.forEach((hazard) => { hazards.forEach((hazard) => {
const key = generateKey(location, hazard.id); const key = generateKey(matchKey, hazard.id);
activeKeys.add(key); activeKeys.add(key);
}); });
// Mark previously ongoing hazards for this location as ended if no longer active // Mark previously ongoing hazards for this location as ended if no longer active
history = history.map((entry) => { history = history.map((entry) => {
// Only process entries for this location // Only process entries for this location
if (entry.location !== location) return entry; // Use locationKey for matching if available, fall back to location for backward compatibility
const entryMatchKey = entry.locationKey || entry.location;
if (entryMatchKey !== matchKey) return entry;
// If this entry is ongoing but not in the current active set, mark it as ended // If this entry is ongoing but not in the current active set, mark it as ended
if (entry.ongoing && !activeKeys.has(entry.key)) { if (entry.ongoing && !activeKeys.has(entry.key)) {
@ -119,7 +125,7 @@ const updateHistory = async (payload) => {
// Add or update active hazards // Add or update active hazards
hazards.forEach((hazard) => { hazards.forEach((hazard) => {
const key = generateKey(location, hazard.id); const key = generateKey(matchKey, hazard.id);
const existingIndex = history.findIndex((entry) => entry.key === key); const existingIndex = history.findIndex((entry) => entry.key === key);
if (existingIndex >= 0) { if (existingIndex >= 0) {
@ -136,6 +142,7 @@ const updateHistory = async (payload) => {
history.push({ history.push({
key, key,
location, location,
locationKey: matchKey,
hazardType: hazard.hazardType, hazardType: hazard.hazardType,
encounteredAt: now, encounteredAt: now,
lastSeenAt: now, lastSeenAt: now,