@blazeo.com/appointment-client 1.0.10 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blazeo.com-appointment-client-1.0.11.tgz +0 -0
- package/dist/calendar/buildUnifiedCalendarView.js +19 -4
- package/dist/calendar/calendarCreation.js +8 -1
- package/package.json +1 -1
- package/src/calendar/buildUnifiedCalendarView.ts +22 -4
- package/src/calendar/calendarCreation.ts +9 -1
- package/blazeo.com-appointment-client-1.0.10.tgz +0 -0
|
Binary file
|
|
@@ -63,18 +63,33 @@ function dayOrderIndex(d) {
|
|
|
63
63
|
const i = DAY_NAMES.indexOf(u);
|
|
64
64
|
return i >= 0 ? i : 999;
|
|
65
65
|
}
|
|
66
|
-
/** Merge rows that share participant + time span
|
|
66
|
+
/** Merge rows that share participant + time span into one row with combined active `days`. */
|
|
67
67
|
function mergeOpeningHoursBySlot(rows) {
|
|
68
68
|
const map = new Map();
|
|
69
69
|
for (const r of rows) {
|
|
70
|
-
|
|
70
|
+
// Key excludes 'off' because we want to merge ON and OFF records for the same time slot
|
|
71
|
+
const key = [r.member, r.startHour, r.startMinute, r.endHour, r.endMinute].join("|");
|
|
71
72
|
const existing = map.get(key);
|
|
73
|
+
// We only want to add the day to the 'days' array if it is NOT marked as OFF.
|
|
74
|
+
// If the whole record was marked as OFF, we still process it to establish the slot,
|
|
75
|
+
// but its days won't be listed as 'active'.
|
|
76
|
+
const activeDaysFromThisRow = r.off ? [] : r.days;
|
|
72
77
|
if (!existing) {
|
|
73
|
-
map.set(key, { ...r, days: [...
|
|
78
|
+
map.set(key, { ...r, days: [...activeDaysFromThisRow], off: false });
|
|
74
79
|
}
|
|
75
80
|
else {
|
|
76
|
-
const set = new Set([...existing.days, ...
|
|
81
|
+
const set = new Set([...existing.days, ...activeDaysFromThisRow]);
|
|
77
82
|
existing.days = Array.from(set).sort((a, b) => dayOrderIndex(a) - dayOrderIndex(b));
|
|
83
|
+
// If we encounter any record that is NOT off, the whole merged slot is NOT off.
|
|
84
|
+
if (!r.off)
|
|
85
|
+
existing.off = false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Final Pass: If a slot has NO active days, it should be marked as off: true
|
|
89
|
+
// (though in Plan V2, these usually just disappear from the UI's 'days' list)
|
|
90
|
+
for (const group of map.values()) {
|
|
91
|
+
if (group.days.length === 0) {
|
|
92
|
+
group.off = true;
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
95
|
rows.length = 0;
|
|
@@ -120,7 +120,10 @@ async function runMembersAndOpeningHoursAfterCalendarSave(calendar, calendarNode
|
|
|
120
120
|
endHour: oh.endHour,
|
|
121
121
|
endMinute: oh.endMinute,
|
|
122
122
|
off: isOff,
|
|
123
|
-
|
|
123
|
+
// Plan V2 Optimization: Generate a unique ID for EVERY day record.
|
|
124
|
+
// This prevents the backend from deduplicating/overwriting when multiple
|
|
125
|
+
// records for the same participant + slot are sent in one batch.
|
|
126
|
+
openingHourId: newOpeningHourId(),
|
|
124
127
|
});
|
|
125
128
|
}
|
|
126
129
|
}
|
|
@@ -128,6 +131,10 @@ async function runMembersAndOpeningHoursAfterCalendarSave(calendar, calendarNode
|
|
|
128
131
|
for (const [participantId, payload] of hoursByParticipant.entries()) {
|
|
129
132
|
if (payload.length === 0)
|
|
130
133
|
continue;
|
|
134
|
+
// Plan V2 Optimization: Clear existing records for this participant first.
|
|
135
|
+
// This ensures that when we save the new batch (with unique per-day IDs),
|
|
136
|
+
// we don't leak orphaned records or create duplicates during updates.
|
|
137
|
+
await calendarNode.removeParticipantOpeningHours(participantId);
|
|
131
138
|
// Use the batch save method (plural)
|
|
132
139
|
const res = await saveCalendarOpeningHoursBatch(calendarNode, payload);
|
|
133
140
|
if (isFailureStatus(res)) {
|
package/package.json
CHANGED
|
@@ -91,19 +91,37 @@ function dayOrderIndex(d: string): number {
|
|
|
91
91
|
return i >= 0 ? i : 999;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/** Merge rows that share participant + time span
|
|
94
|
+
/** Merge rows that share participant + time span into one row with combined active `days`. */
|
|
95
95
|
function mergeOpeningHoursBySlot(rows: UnifiedOpeningHourRow[]) {
|
|
96
96
|
const map = new Map<string, UnifiedOpeningHourRow>();
|
|
97
97
|
for (const r of rows) {
|
|
98
|
-
|
|
98
|
+
// Key excludes 'off' because we want to merge ON and OFF records for the same time slot
|
|
99
|
+
const key = [r.member, r.startHour, r.startMinute, r.endHour, r.endMinute].join("|");
|
|
99
100
|
const existing = map.get(key);
|
|
101
|
+
|
|
102
|
+
// We only want to add the day to the 'days' array if it is NOT marked as OFF.
|
|
103
|
+
// If the whole record was marked as OFF, we still process it to establish the slot,
|
|
104
|
+
// but its days won't be listed as 'active'.
|
|
105
|
+
const activeDaysFromThisRow = r.off ? [] : r.days;
|
|
106
|
+
|
|
100
107
|
if (!existing) {
|
|
101
|
-
map.set(key, { ...r, days: [...
|
|
108
|
+
map.set(key, { ...r, days: [...activeDaysFromThisRow], off: false });
|
|
102
109
|
} else {
|
|
103
|
-
const set = new Set([...existing.days, ...
|
|
110
|
+
const set = new Set([...existing.days, ...activeDaysFromThisRow]);
|
|
104
111
|
existing.days = Array.from(set).sort((a, b) => dayOrderIndex(a) - dayOrderIndex(b));
|
|
112
|
+
// If we encounter any record that is NOT off, the whole merged slot is NOT off.
|
|
113
|
+
if (!r.off) existing.off = false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Final Pass: If a slot has NO active days, it should be marked as off: true
|
|
118
|
+
// (though in Plan V2, these usually just disappear from the UI's 'days' list)
|
|
119
|
+
for (const group of map.values()) {
|
|
120
|
+
if (group.days.length === 0) {
|
|
121
|
+
group.off = true;
|
|
105
122
|
}
|
|
106
123
|
}
|
|
124
|
+
|
|
107
125
|
rows.length = 0;
|
|
108
126
|
rows.push(...map.values());
|
|
109
127
|
}
|
|
@@ -132,7 +132,10 @@ async function runMembersAndOpeningHoursAfterCalendarSave(calendar: any, calenda
|
|
|
132
132
|
endHour: oh.endHour,
|
|
133
133
|
endMinute: oh.endMinute,
|
|
134
134
|
off: isOff,
|
|
135
|
-
|
|
135
|
+
// Plan V2 Optimization: Generate a unique ID for EVERY day record.
|
|
136
|
+
// This prevents the backend from deduplicating/overwriting when multiple
|
|
137
|
+
// records for the same participant + slot are sent in one batch.
|
|
138
|
+
openingHourId: newOpeningHourId(),
|
|
136
139
|
});
|
|
137
140
|
}
|
|
138
141
|
}
|
|
@@ -141,6 +144,11 @@ async function runMembersAndOpeningHoursAfterCalendarSave(calendar: any, calenda
|
|
|
141
144
|
for (const [participantId, payload] of hoursByParticipant.entries()) {
|
|
142
145
|
if (payload.length === 0) continue;
|
|
143
146
|
|
|
147
|
+
// Plan V2 Optimization: Clear existing records for this participant first.
|
|
148
|
+
// This ensures that when we save the new batch (with unique per-day IDs),
|
|
149
|
+
// we don't leak orphaned records or create duplicates during updates.
|
|
150
|
+
await (calendarNode as any).removeParticipantOpeningHours(participantId);
|
|
151
|
+
|
|
144
152
|
// Use the batch save method (plural)
|
|
145
153
|
const res = await saveCalendarOpeningHoursBatch(calendarNode, payload);
|
|
146
154
|
|
|
Binary file
|