updated events to remove duplicates when edit reccurring

This commit is contained in:
2026-03-29 12:01:51 -04:00
parent cfb351a251
commit 580ef1307c
3 changed files with 92 additions and 7 deletions

View File

@@ -199,14 +199,56 @@ router.get('/', authMiddleware, async (req, res) => {
if (to) { sql += ` AND start_at <= $${pi++}`; params.push(to); }
sql += ' ORDER BY start_at ASC';
const rawEvents = await query(req.schema, sql, params);
const events = [];
// Separate master events and exception instances
const masterEvents = [];
const exceptionInstances = [];
for (const e of rawEvents) {
if (e.recurring_master_id) {
exceptionInstances.push(e);
} else {
masterEvents.push(e);
}
}
// Build a map of exception dates by master event
const exceptionDatesByMaster = new Map();
for (const exc of exceptionInstances) {
if (!exceptionDatesByMaster.has(exc.recurring_master_id)) {
exceptionDatesByMaster.set(exc.recurring_master_id, new Set());
}
const dateStr = new Date(exc.original_start_at || exc.start_at).toISOString().split('T')[0];
exceptionDatesByMaster.get(exc.recurring_master_id).add(dateStr);
}
const events = [];
for (const e of masterEvents) {
// Skip master events if all their occurrences in range are replaced by exceptions
if (e.recurrence_rule && exceptionDatesByMaster.has(e.id)) {
const exceptions = exceptionDatesByMaster.get(e.id);
const rule = e.recurrence_rule;
// Check if this is a simple case where all occurrences are replaced
// For now, we'll include the master and let frontend handle filtering
// This is safer to avoid missing edge cases
}
if (!(await canViewEvent(req.schema, e, req.user.id, itm))) continue;
await enrichEvent(req.schema, e);
const mine = await queryOne(req.schema, 'SELECT response FROM event_availability WHERE event_id=$1 AND user_id=$2', [e.id, req.user.id]);
const mine = await queryOne(req.schema, 'SELECT response FROM event_availability WHERE event_id=$1 AND user_id=$2', [e.id]);
e.my_response = mine?.response || null;
events.push(e);
}
// Add exception instances (they're standalone events)
for (const e of exceptionInstances) {
if (!(await canViewEvent(req.schema, e, req.user.id, itm))) continue;
await enrichEvent(req.schema, e);
const mine = await queryOne(req.schema, 'SELECT response FROM event_availability WHERE event_id=$1 AND user_id=$2', [e.id]);
e.my_response = mine?.response || null;
events.push(e);
}
res.json({ events });
} catch (e) { res.status(500).json({ error: e.message }); }
});

View File

@@ -16,7 +16,7 @@ set -euo pipefail
VERSION="${1:-0.12.37}"
ACTION="${2:-}"
REGISTRY="${REGISTRY:-}"
IMAGE_NAME="rosterchirp"
IMAGE_NAME="rosterchirp-dev"
# If a registry is set, prefix image name
if [[ -n "$REGISTRY" ]]; then

View File

@@ -1125,14 +1125,57 @@ function expandRecurringEvent(ev, rangeStart, rangeEnd) {
// Expand all recurring events in a list within a date range
function expandEvents(events, rangeStart, rangeEnd) {
const result = [];
// First, collect all exception instances and their dates by master event
const exceptionDatesByMaster = new Map();
const masterEvents = [];
const standaloneEvents = [];
for (const ev of events) {
if (ev.recurrence_rule?.freq) {
const expanded = expandRecurringEvent(ev, rangeStart, rangeEnd);
result.push(...expanded);
if (ev.recurring_master_id) {
// This is an exception instance
if (!exceptionDatesByMaster.has(ev.recurring_master_id)) {
exceptionDatesByMaster.set(ev.recurring_master_id, new Set());
}
const dateStr = new Date(ev.original_start_at || ev.start_at).toISOString().split('T')[0];
exceptionDatesByMaster.get(ev.recurring_master_id).add(dateStr);
standaloneEvents.push(ev); // Exception instances are standalone events
} else if (ev.recurrence_rule?.freq) {
masterEvents.push(ev);
} else {
result.push(ev);
standaloneEvents.push(ev);
}
}
// Expand master events, skipping dates that have exception instances
for (const ev of masterEvents) {
const exceptions = exceptionDatesByMaster.get(ev.id);
if (exceptions) {
// Merge the rule's exceptions with the instance exceptions
const rule = ev.recurrence_rule || {};
const ruleExceptions = new Set(rule.exceptions || []);
for (const date of exceptions) {
ruleExceptions.add(date);
}
// Create a copy of the event with merged exceptions
const evWithMergedExceptions = {
...ev,
recurrence_rule: {
...rule,
exceptions: Array.from(ruleExceptions)
}
};
const expanded = expandRecurringEvent(evWithMergedExceptions, rangeStart, rangeEnd);
result.push(...expanded);
} else {
const expanded = expandRecurringEvent(ev, rangeStart, rangeEnd);
result.push(...expanded);
}
}
// Add all standalone events (non-recurring + exception instances)
result.push(...standaloneEvents);
// Sort by start_at
result.sort((a,b) => new Date(a.start_at) - new Date(b.start_at));
return result;