updated events to remove duplicates when edit reccurring
This commit is contained in:
@@ -199,14 +199,56 @@ router.get('/', authMiddleware, async (req, res) => {
|
|||||||
if (to) { sql += ` AND start_at <= $${pi++}`; params.push(to); }
|
if (to) { sql += ` AND start_at <= $${pi++}`; params.push(to); }
|
||||||
sql += ' ORDER BY start_at ASC';
|
sql += ' ORDER BY start_at ASC';
|
||||||
const rawEvents = await query(req.schema, sql, params);
|
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) {
|
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;
|
if (!(await canViewEvent(req.schema, e, req.user.id, itm))) continue;
|
||||||
await enrichEvent(req.schema, e);
|
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;
|
e.my_response = mine?.response || null;
|
||||||
events.push(e);
|
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 });
|
res.json({ events });
|
||||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||||
});
|
});
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -16,7 +16,7 @@ set -euo pipefail
|
|||||||
VERSION="${1:-0.12.37}"
|
VERSION="${1:-0.12.37}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="rosterchirp"
|
IMAGE_NAME="rosterchirp-dev"
|
||||||
|
|
||||||
# If a registry is set, prefix image name
|
# If a registry is set, prefix image name
|
||||||
if [[ -n "$REGISTRY" ]]; then
|
if [[ -n "$REGISTRY" ]]; then
|
||||||
|
|||||||
@@ -1125,14 +1125,57 @@ function expandRecurringEvent(ev, rangeStart, rangeEnd) {
|
|||||||
// Expand all recurring events in a list within a date range
|
// Expand all recurring events in a list within a date range
|
||||||
function expandEvents(events, rangeStart, rangeEnd) {
|
function expandEvents(events, rangeStart, rangeEnd) {
|
||||||
const result = [];
|
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) {
|
for (const ev of events) {
|
||||||
if (ev.recurrence_rule?.freq) {
|
if (ev.recurring_master_id) {
|
||||||
const expanded = expandRecurringEvent(ev, rangeStart, rangeEnd);
|
// This is an exception instance
|
||||||
result.push(...expanded);
|
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 {
|
} 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
|
// Sort by start_at
|
||||||
result.sort((a,b) => new Date(a.start_at) - new Date(b.start_at));
|
result.sort((a,b) => new Date(a.start_at) - new Date(b.start_at));
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
Reference in New Issue
Block a user