Update rsvp-tracker

This commit is contained in:
Anton Roslund
2025-09-28 13:31:03 +02:00
parent 6ca0c8a4c9
commit 0bda6dbb05
2 changed files with 144 additions and 8 deletions
+98 -3
View File
@@ -1,9 +1,104 @@
{
"messagePattern": "AW 1/10",
"description": "Meetup 1 Oktober - Sundbyberg",
"exportedAt": "2025-09-28T10:59:49.506Z",
"attendees": {
"yes": [],
"maybe": [],
"no": []
"yes": [
{
"nodeId": "2665944228",
"shortName": "TPH1",
"longName": "TPH-1 Täby",
"response": "yes",
"timestamp": "2025-09-27T11:18:40.725Z"
},
{
"nodeId": "1422344156",
"shortName": "TELE",
"longName": "MDG Telefonplan",
"response": "yes",
"timestamp": "2025-09-26T23:07:19.802Z"
},
{
"nodeId": "2718571204",
"shortName": "DXD3",
"longName": "DXD3 Ruggen",
"response": "yes",
"timestamp": "2025-09-26T20:14:58.613Z"
},
{
"nodeId": "2947306466",
"shortName": "CVK",
"longName": "SA0CVK Primary",
"response": "yes",
"timestamp": "2025-09-26T19:53:44.302Z"
},
{
"nodeId": "2879616005",
"shortName": "JlyT",
"longName": "Jelly Test",
"response": "yes",
"timestamp": "2025-09-26T14:25:11.116Z"
},
{
"nodeId": "1128157388",
"shortName": "varg",
"longName": "vargtastic",
"response": "yes",
"timestamp": "2025-09-25T16:47:09.777Z"
},
{
"nodeId": "3681979732",
"shortName": "Ros",
"longName": "Ros Mobil",
"response": "yes",
"timestamp": "2025-09-24T16:02:08.895Z"
},
{
"nodeId": "1978245180",
"shortName": "CVK",
"longName": "SA0CVK 0 (Ny Router)",
"response": "yes",
"timestamp": "2025-09-22T17:06:11.296Z"
},
{
"nodeId": "3677336824",
"shortName": "Chip",
"longName": "Chip",
"response": "yes",
"timestamp": "2025-09-22T17:00:53.857Z"
},
{
"nodeId": "3655315140",
"shortName": "Ros9",
"longName": "Roslund9",
"response": "yes",
"timestamp": "2025-09-22T05:37:43.576Z"
},
{
"nodeId": "1222480744",
"shortName": "JwKL",
"longName": "JwK LF",
"response": "yes",
"timestamp": "2025-09-21T20:54:17.235Z"
}
],
"maybe": [
{
"nodeId": "364861217",
"shortName": "KAKd",
"longName": "Kladdkakd",
"response": "maybe",
"timestamp": "2025-09-22T22:00:55.197Z"
}
],
"no": [
{
"nodeId": "3946133666",
"shortName": "phPi",
"longName": "ph Raspberry Pi",
"response": "no",
"timestamp": "2025-09-26T20:11:29.025Z"
}
]
}
}
+46 -5
View File
@@ -24,7 +24,7 @@ function parseRSVPMessage(messageText, messagePattern) {
}
async function fetchMessages() {
const response = await fetch('https://map.sthlm-mesh.se/api/v1/text-messages?order=desc&count=1000');
const response = await fetch('https://map.sthlm-mesh.se/api/v1/text-messages?order=desc&count=3000');
const data = await response.json();
return data.text_messages;
}
@@ -159,6 +159,49 @@ function generateRSVPHTML(summary) {
}
function mergeRSVPSummaries(primarySummary, manualAttendees) {
const latestByNode = new Map();
const addFrom = (collection, fallbackType) => {
if (!Array.isArray(collection)) return;
for (const attendee of collection) {
const nodeId = attendee.nodeId ?? attendee.node_id ?? attendee.id;
if (!nodeId) continue;
const responseType = attendee.response ?? fallbackType;
if (!responseType) continue;
const timestampString = attendee.timestamp ?? null;
const ts = timestampString ? new Date(timestampString).getTime() : -Infinity;
const existing = latestByNode.get(nodeId);
if (!existing || ts > existing.ts) {
latestByNode.set(nodeId, {
nodeId: nodeId,
shortName: attendee.shortName ?? attendee.short_name ?? '?',
longName: attendee.longName ?? attendee.long_name ?? `!${parseInt(nodeId).toString(16)}`,
response: responseType,
timestamp: timestampString ?? existing?.timestamp ?? new Date(0).toISOString(),
ts
});
}
}
};
['yes', 'maybe', 'no'].forEach(type => addFrom(primarySummary?.[type], type));
['yes', 'maybe', 'no'].forEach(type => addFrom(manualAttendees?.[type], type));
const merged = { yes: [], maybe: [], no: [] };
for (const { ts, ...attendee } of latestByNode.values()) {
if (merged[attendee.response]) merged[attendee.response].push(attendee);
}
Object.values(merged).forEach(arr =>
arr.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
);
return merged;
}
/**
* Initialize RSVP tracking for a specific event
* Supports both active events (parse messages + JSON) and archived events (JSON only)
@@ -192,10 +235,8 @@ async function initRSVPTracker(eventId) {
const responses = parseRSVPResponses(messages, eventData.messagePattern);
summary = createRSVPSummary(responses);
// Add manual attendees
Object.entries(eventData.attendees).forEach(([type, attendees]) => {
summary[type].push(...attendees);
});
// Merge manual attendees with message-derived ones, keeping the latest response per attendee
summary = mergeRSVPSummaries(summary, eventData.attendees);
}
// Display results