@schukai/monster 3.112.0 → 3.112.1

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.
@@ -1,6 +1,6 @@
1
1
  // Constants for possible appointment types
2
- import {ID} from "../../../types/id.mjs";
3
- import {isArray} from "../../../types/is.mjs";
2
+ import { ID } from "../../../types/id.mjs";
3
+ import { isArray } from "../../../types/is.mjs";
4
4
 
5
5
  /**
6
6
  * Helper function: Check if two dates are on the same day (ignoring time)
@@ -8,198 +8,211 @@ import {isArray} from "../../../types/is.mjs";
8
8
  * @param {string|Date} date1 - First date
9
9
  * @param {string|Date} date2 - Second date
10
10
  * @returns {boolean} True if the dates are on the same day, false otherwise
11
- */
11
+ */
12
12
  function isSameDay(date1, date2) {
13
- const d1 = new Date(date1);
14
- const d2 = new Date(date2);
15
- return d1.getFullYear() === d2.getFullYear() &&
16
- d1.getMonth() === d2.getMonth() &&
17
- d1.getDate() === d2.getDate();
13
+ const d1 = new Date(date1);
14
+ const d2 = new Date(date2);
15
+ return (
16
+ d1.getFullYear() === d2.getFullYear() &&
17
+ d1.getMonth() === d2.getMonth() &&
18
+ d1.getDate() === d2.getDate()
19
+ );
18
20
  }
19
21
 
20
22
  class AppointmentCollection {
21
- constructor() {
22
- this.appointments = [];
23
- }
24
-
25
- // Add an appointment to the collection
26
- addAppointment(appointment) {
27
- if (!(appointment instanceof TimelineItem)) {
28
- throw new Error("Only instances of Appointment can be added");
29
- }
30
- this.appointments.push(appointment);
31
- }
32
-
33
- // Get all appointments that overlap with the given date range
34
- getAppointmentsInRange(rangeStart, rangeEnd) {
35
- const start = new Date(rangeStart);
36
- const end = new Date(rangeEnd);
37
- if (isNaN(start.getTime()) || isNaN(end.getTime())) {
38
- throw new Error("Invalid date range");
39
- }
40
- return this.appointments.filter(app =>
41
- app.endDate >= start && app.startDate <= end
42
- );
43
- }
44
-
45
- // Get appointments that start on a specific day
46
- getAppointmentsStartingOn(date) {
47
- return this.appointments.filter(app => isSameDay(app.startDate, date));
48
- }
49
-
50
- // Get appointments that end on a specific day
51
- getAppointmentsEndingOn(date) {
52
- return this.appointments.filter(app => isSameDay(app.endDate, date));
53
- }
54
-
55
- // Get appointments active on a specific day (the day falls between startDate and endDate, inclusive)
56
- getAppointmentsForDay(date) {
57
- const d = new Date(date);
58
- return this.appointments.filter(app =>
59
- app.startDate <= d && app.endDate >= d
60
- );
61
- }
62
-
63
- // Get appointments where the specified date is strictly between the start and end dates
64
- getAppointmentsWithDateAsMiddleDay(date) {
65
- const d = new Date(date);
66
- return this.appointments.filter(app =>
67
- app.startDate < d && app.endDate > d && !isSameDay(app.startDate, d) && !isSameDay(app.endDate, d)
68
- );
69
- }
70
-
71
- // Get appointments filtered by type (e.g., all milestones)
72
- getAppointmentsByType(type) {
73
- return this.appointments.filter(app => app.type === type);
74
- }
75
-
76
- // Export the entire collection as JSON
77
- toJSON() {
78
- return this.appointments.map(app => app.toJSON());
79
- }
80
-
81
- /**
82
- * Splits an appointment into slices of a specified duration (in days).
83
- * If the appointment is provided as an ID, it will be looked up in the collection.
84
- * Each slice is returned as an object with the original appointment's properties,
85
- * plus sliceIndex and the new startDate/endDate for the slice.
86
- *
87
- * @param {TimelineItem|string} appointmentOrId - The appointment instance or its ID.
88
- * @param {number} sliceDurationDays - Duration of each slice in days.
89
- * @returns {Array} Array of slice objects.
90
- */
91
- splitAppointment(appointmentOrId, sliceDurationDays) {
92
- if (typeof sliceDurationDays !== "number" || sliceDurationDays <= 0) {
93
- throw new Error("Slice duration must be a positive number");
94
- }
95
-
96
- let appointment;
97
- if (appointmentOrId instanceof TimelineItem) {
98
- appointment = appointmentOrId;
99
- } else {
100
- appointment = this.appointments.find(app => app.id === appointmentOrId);
101
- if (!appointment) {
102
- throw new Error("Appointment not found");
103
- }
104
- }
105
-
106
- const slices = [];
107
- let currentStart = new Date(appointment.startDate);
108
- let sliceIndex = 0;
109
-
110
- while (currentStart < appointment.endDate) {
111
- const currentEnd = new Date(currentStart);
112
- currentEnd.setDate(currentEnd.getDate() + sliceDurationDays);
113
- if (currentEnd > appointment.endDate) {
114
- currentEnd.setTime(appointment.endDate.getTime());
115
- }
116
-
117
- const slice = {
118
- parentId: appointment.id,
119
- sliceIndex: sliceIndex,
120
- title: appointment.title,
121
- type: appointment.type,
122
- description: appointment.description,
123
- userIds: appointment.userIds,
124
- startDate: currentStart.toISOString(),
125
- endDate: currentEnd.toISOString()
126
- };
127
- slices.push(slice);
128
-
129
- // Prepare for next slice
130
- currentStart = currentEnd;
131
- sliceIndex++;
132
- }
133
-
134
- return slices;
135
- }
23
+ constructor() {
24
+ this.appointments = [];
25
+ }
26
+
27
+ // Add an appointment to the collection
28
+ addAppointment(appointment) {
29
+ if (!(appointment instanceof TimelineItem)) {
30
+ throw new Error("Only instances of Appointment can be added");
31
+ }
32
+ this.appointments.push(appointment);
33
+ }
34
+
35
+ // Get all appointments that overlap with the given date range
36
+ getAppointmentsInRange(rangeStart, rangeEnd) {
37
+ const start = new Date(rangeStart);
38
+ const end = new Date(rangeEnd);
39
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
40
+ throw new Error("Invalid date range");
41
+ }
42
+ return this.appointments.filter(
43
+ (app) => app.endDate >= start && app.startDate <= end,
44
+ );
45
+ }
46
+
47
+ // Get appointments that start on a specific day
48
+ getAppointmentsStartingOn(date) {
49
+ return this.appointments.filter((app) => isSameDay(app.startDate, date));
50
+ }
51
+
52
+ // Get appointments that end on a specific day
53
+ getAppointmentsEndingOn(date) {
54
+ return this.appointments.filter((app) => isSameDay(app.endDate, date));
55
+ }
56
+
57
+ // Get appointments active on a specific day (the day falls between startDate and endDate, inclusive)
58
+ getAppointmentsForDay(date) {
59
+ const d = new Date(date);
60
+ return this.appointments.filter(
61
+ (app) => app.startDate <= d && app.endDate >= d,
62
+ );
63
+ }
64
+
65
+ // Get appointments where the specified date is strictly between the start and end dates
66
+ getAppointmentsWithDateAsMiddleDay(date) {
67
+ const d = new Date(date);
68
+ return this.appointments.filter(
69
+ (app) =>
70
+ app.startDate < d &&
71
+ app.endDate > d &&
72
+ !isSameDay(app.startDate, d) &&
73
+ !isSameDay(app.endDate, d),
74
+ );
75
+ }
76
+
77
+ // Get appointments filtered by type (e.g., all milestones)
78
+ getAppointmentsByType(type) {
79
+ return this.appointments.filter((app) => app.type === type);
80
+ }
81
+
82
+ // Export the entire collection as JSON
83
+ toJSON() {
84
+ return this.appointments.map((app) => app.toJSON());
85
+ }
86
+
87
+ /**
88
+ * Splits an appointment into slices of a specified duration (in days).
89
+ * If the appointment is provided as an ID, it will be looked up in the collection.
90
+ * Each slice is returned as an object with the original appointment's properties,
91
+ * plus sliceIndex and the new startDate/endDate for the slice.
92
+ *
93
+ * @param {TimelineItem|string} appointmentOrId - The appointment instance or its ID.
94
+ * @param {number} sliceDurationDays - Duration of each slice in days.
95
+ * @returns {Array} Array of slice objects.
96
+ */
97
+ splitAppointment(appointmentOrId, sliceDurationDays) {
98
+ if (typeof sliceDurationDays !== "number" || sliceDurationDays <= 0) {
99
+ throw new Error("Slice duration must be a positive number");
100
+ }
101
+
102
+ let appointment;
103
+ if (appointmentOrId instanceof TimelineItem) {
104
+ appointment = appointmentOrId;
105
+ } else {
106
+ appointment = this.appointments.find((app) => app.id === appointmentOrId);
107
+ if (!appointment) {
108
+ throw new Error("Appointment not found");
109
+ }
110
+ }
111
+
112
+ const slices = [];
113
+ let currentStart = new Date(appointment.startDate);
114
+ let sliceIndex = 0;
115
+
116
+ while (currentStart < appointment.endDate) {
117
+ const currentEnd = new Date(currentStart);
118
+ currentEnd.setDate(currentEnd.getDate() + sliceDurationDays);
119
+ if (currentEnd > appointment.endDate) {
120
+ currentEnd.setTime(appointment.endDate.getTime());
121
+ }
122
+
123
+ const slice = {
124
+ parentId: appointment.id,
125
+ sliceIndex: sliceIndex,
126
+ title: appointment.title,
127
+ type: appointment.type,
128
+ description: appointment.description,
129
+ userIds: appointment.userIds,
130
+ startDate: currentStart.toISOString(),
131
+ endDate: currentEnd.toISOString(),
132
+ };
133
+ slices.push(slice);
134
+
135
+ // Prepare for next slice
136
+ currentStart = currentEnd;
137
+ sliceIndex++;
138
+ }
139
+
140
+ return slices;
141
+ }
136
142
  }
137
143
 
138
144
  // Example usage
139
145
  try {
140
- // Create some appointments with user associations
141
- const appointment1 = new TimelineItem({
142
- title: "Team Meeting",
143
- type: AppointmentType.TASK,
144
- startDate: "2025-03-05T09:00:00",
145
- endDate: "2025-03-05T10:00:00",
146
- description: "Weekly team meeting",
147
- userIds: ["user1", "user2"]
148
- });
149
-
150
- const appointment2 = new TimelineItem({
151
- title: "Project Kickoff",
152
- type: AppointmentType.MILESTONE,
153
- startDate: "2025-03-06T08:00:00",
154
- endDate: "2025-03-06T12:00:00",
155
- description: "Kickoff for the new project",
156
- userIds: "user3" // single user id; will be converted to an array
157
- });
158
-
159
- // An appointment spanning over 30 days
160
- const appointment3 = new TimelineItem({
161
- title: "Long Term Project",
162
- type: AppointmentType.TASK,
163
- startDate: "2025-04-01T09:00:00",
164
- endDate: "2025-05-15T17:00:00",
165
- description: "Project spanning multiple weeks",
166
- userIds: ["user4"]
167
- });
168
-
169
- // Create an appointment collection and add appointments
170
- const collection = new AppointmentCollection();
171
- collection.addAppointment(appointment1);
172
- collection.addAppointment(appointment2);
173
- collection.addAppointment(appointment3);
174
-
175
- console.log("Appointments on 2025-03-05:");
176
- collection.getAppointmentsForDay("2025-03-05").forEach(app => console.log(app.toString()));
177
-
178
- console.log("\nAppointments in range 2025-03-05 to 2025-03-06:");
179
- collection.getAppointmentsInRange("2025-03-05T00:00:00", "2025-03-06T23:59:59")
180
- .forEach(app => console.log(app.toString()));
181
-
182
- console.log("\nAll milestones:");
183
- collection.getAppointmentsByType(AppointmentType.MILESTONE)
184
- .forEach(app => console.log(app.toString()));
185
-
186
- // Split appointment3 into weekly slices (7-day slices)
187
- console.log("\nWeekly slices for Long Term Project:");
188
- const weeklySlices = collection.splitAppointment(appointment3, 7);
189
- weeklySlices.forEach(slice => {
190
- console.log(`Slice ${slice.sliceIndex}: ${slice.startDate} to ${slice.endDate}`);
191
- });
192
-
193
- // Split appointment3 into 14-day slices
194
- console.log("\n14-day slices for Long Term Project:");
195
- const biweeklySlices = collection.splitAppointment(appointment3, 14);
196
- biweeklySlices.forEach(slice => {
197
- console.log(`Slice ${slice.sliceIndex}: ${slice.startDate} to ${slice.endDate}`);
198
- });
199
-
200
- console.log("\nJSON Export of the collection:");
201
- console.log(JSON.stringify(collection.toJSON(), null, 2));
202
-
146
+ // Create some appointments with user associations
147
+ const appointment1 = new TimelineItem({
148
+ title: "Team Meeting",
149
+ type: AppointmentType.TASK,
150
+ startDate: "2025-03-05T09:00:00",
151
+ endDate: "2025-03-05T10:00:00",
152
+ description: "Weekly team meeting",
153
+ userIds: ["user1", "user2"],
154
+ });
155
+
156
+ const appointment2 = new TimelineItem({
157
+ title: "Project Kickoff",
158
+ type: AppointmentType.MILESTONE,
159
+ startDate: "2025-03-06T08:00:00",
160
+ endDate: "2025-03-06T12:00:00",
161
+ description: "Kickoff for the new project",
162
+ userIds: "user3", // single user id; will be converted to an array
163
+ });
164
+
165
+ // An appointment spanning over 30 days
166
+ const appointment3 = new TimelineItem({
167
+ title: "Long Term Project",
168
+ type: AppointmentType.TASK,
169
+ startDate: "2025-04-01T09:00:00",
170
+ endDate: "2025-05-15T17:00:00",
171
+ description: "Project spanning multiple weeks",
172
+ userIds: ["user4"],
173
+ });
174
+
175
+ // Create an appointment collection and add appointments
176
+ const collection = new AppointmentCollection();
177
+ collection.addAppointment(appointment1);
178
+ collection.addAppointment(appointment2);
179
+ collection.addAppointment(appointment3);
180
+
181
+ console.log("Appointments on 2025-03-05:");
182
+ collection
183
+ .getAppointmentsForDay("2025-03-05")
184
+ .forEach((app) => console.log(app.toString()));
185
+
186
+ console.log("\nAppointments in range 2025-03-05 to 2025-03-06:");
187
+ collection
188
+ .getAppointmentsInRange("2025-03-05T00:00:00", "2025-03-06T23:59:59")
189
+ .forEach((app) => console.log(app.toString()));
190
+
191
+ console.log("\nAll milestones:");
192
+ collection
193
+ .getAppointmentsByType(AppointmentType.MILESTONE)
194
+ .forEach((app) => console.log(app.toString()));
195
+
196
+ // Split appointment3 into weekly slices (7-day slices)
197
+ console.log("\nWeekly slices for Long Term Project:");
198
+ const weeklySlices = collection.splitAppointment(appointment3, 7);
199
+ weeklySlices.forEach((slice) => {
200
+ console.log(
201
+ `Slice ${slice.sliceIndex}: ${slice.startDate} to ${slice.endDate}`,
202
+ );
203
+ });
204
+
205
+ // Split appointment3 into 14-day slices
206
+ console.log("\n14-day slices for Long Term Project:");
207
+ const biweeklySlices = collection.splitAppointment(appointment3, 14);
208
+ biweeklySlices.forEach((slice) => {
209
+ console.log(
210
+ `Slice ${slice.sliceIndex}: ${slice.startDate} to ${slice.endDate}`,
211
+ );
212
+ });
213
+
214
+ console.log("\nJSON Export of the collection:");
215
+ console.log(JSON.stringify(collection.toJSON(), null, 2));
203
216
  } catch (error) {
204
- console.error("Error:", error.message);
217
+ console.error("Error:", error.message);
205
218
  }