Skip to content

Commit 440d3b2

Browse files
committed
✨ feat(edit-recurrence): add ability to edit recurrence
1 parent 50ba7cb commit 440d3b2

File tree

5 files changed

+387
-224
lines changed

5 files changed

+387
-224
lines changed

packages/backend/src/event/classes/compass.event.rrule.test.ts renamed to packages/core/src/util/event/compass.event.rrule.test.ts

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import { ObjectId } from "mongodb";
21
import { faker } from "@faker-js/faker";
32
import { GCAL_MAX_RECURRENCES } from "@core/constants/core.constants";
43
import dayjs from "@core/util/date/dayjs";
4+
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
55
import { parseCompassEventDate } from "@core/util/event/event.util";
66
import {
77
createMockBaseEvent,
88
generateCompassEventDates,
99
} from "@core/util/test/ccal.event.factory";
10-
import { CompassEventRRule } from "@backend/event/classes/compass.event.rrule";
1110

1211
describe("CompassEventRRule: ", () => {
1312
it(`should return the correct number of events based on rrule count`, () => {
@@ -18,10 +17,7 @@ describe("CompassEventRRule: ", () => {
1817
recurrence: { rule: [rruleString] },
1918
});
2019

21-
const rrule = new CompassEventRRule({
22-
...baseEvent,
23-
_id: new ObjectId(baseEvent._id),
24-
});
20+
const rrule = new CompassEventRRule(baseEvent);
2521

2622
expect(rrule.toString()).toContain("RRULE:FREQ=DAILY");
2723
expect(rrule.toString()).toContain(`COUNT=${count}`);
@@ -36,10 +32,7 @@ describe("CompassEventRRule: ", () => {
3632
recurrence: { rule: [rruleString] },
3733
});
3834

39-
const rrule = new CompassEventRRule({
40-
...baseEvent,
41-
_id: new ObjectId(baseEvent._id),
42-
});
35+
const rrule = new CompassEventRRule(baseEvent);
4336

4437
expect(rrule.toString()).toContain("RRULE:FREQ=DAILY");
4538
expect(rrule.toString()).toContain(`COUNT=${GCAL_MAX_RECURRENCES}`);
@@ -49,10 +42,7 @@ describe("CompassEventRRule: ", () => {
4942

5043
it("should return the rrule in system timezone", () => {
5144
const baseEvent = createMockBaseEvent();
52-
const rrule = new CompassEventRRule({
53-
...baseEvent,
54-
_id: new ObjectId(baseEvent._id),
55-
});
45+
const rrule = new CompassEventRRule(baseEvent);
5646
const startDate = parseCompassEventDate(baseEvent.startDate!);
5747
const events = rrule.all();
5848

@@ -65,13 +55,7 @@ describe("CompassEventRRule: ", () => {
6555

6656
it("should return the rrule without DTSTART and DTEND", () => {
6757
const baseEvent = createMockBaseEvent();
68-
const rrule = new CompassEventRRule({
69-
...baseEvent,
70-
_id: new ObjectId(baseEvent._id),
71-
});
72-
73-
expect(rrule.toString().includes("DTSTART")).toEqual(false);
74-
expect(rrule.toString().includes("DTEND")).toEqual(false);
58+
const rrule = new CompassEventRRule(baseEvent);
7559

7660
expect(
7761
rrule.toRecurrence().some((rule) => rule.includes("DTSTART")),
@@ -85,10 +69,7 @@ describe("CompassEventRRule: ", () => {
8569
describe("base", () => {
8670
it("should return the recurrence string as an array", () => {
8771
const baseEvent = createMockBaseEvent();
88-
const rrule = new CompassEventRRule({
89-
...baseEvent,
90-
_id: new ObjectId(baseEvent._id),
91-
});
72+
const rrule = new CompassEventRRule(baseEvent);
9273
const recurrence = rrule.toRecurrence();
9374

9475
expect(recurrence).toBeInstanceOf(Array);
@@ -104,10 +85,7 @@ describe("CompassEventRRule: ", () => {
10485
it(`should return a maximum of ${GCAL_MAX_RECURRENCES} compass instances if no count is supplied in the recurrence`, () => {
10586
const rule = ["RRULE:FREQ=DAILY"];
10687
const baseEvent = createMockBaseEvent({ recurrence: { rule } });
107-
const rrule = new CompassEventRRule({
108-
...baseEvent,
109-
_id: new ObjectId(baseEvent._id),
110-
});
88+
const rrule = new CompassEventRRule(baseEvent);
11189
const instances = rrule.instances();
11290

11391
expect(instances).toBeInstanceOf(Array);
@@ -117,10 +95,7 @@ describe("CompassEventRRule: ", () => {
11795
it(`should return a maximum of ${GCAL_MAX_RECURRENCES} compass instances if count exceeds maximum recurrence`, () => {
11896
const rule = ["RRULE:FREQ=DAILY;COUNT=1000"];
11997
const baseEvent = createMockBaseEvent({ recurrence: { rule } });
120-
const rrule = new CompassEventRRule({
121-
...baseEvent,
122-
_id: new ObjectId(baseEvent._id),
123-
});
98+
const rrule = new CompassEventRRule(baseEvent);
12499
const instances = rrule.instances();
125100

126101
expect(instances).toBeInstanceOf(Array);
@@ -131,10 +106,7 @@ describe("CompassEventRRule: ", () => {
131106
const count = faker.number.int({ min: 1, max: GCAL_MAX_RECURRENCES });
132107
const rule = [`RRULE:FREQ=DAILY;COUNT=${count}`];
133108
const baseEvent = createMockBaseEvent({ recurrence: { rule } });
134-
const rrule = new CompassEventRRule({
135-
...baseEvent,
136-
_id: new ObjectId(baseEvent._id),
137-
});
109+
const rrule = new CompassEventRRule(baseEvent);
138110
const instances = rrule.instances();
139111

140112
expect(instances).toBeInstanceOf(Array);
@@ -146,10 +118,7 @@ describe("CompassEventRRule: ", () => {
146118
const date = dayjs().startOf("year"); // specific date for testing
147119
const dates = generateCompassEventDates({ date, allDay: true });
148120
const baseEvent = createMockBaseEvent({ ...dates, recurrence: { rule } });
149-
const rrule = new CompassEventRRule({
150-
...baseEvent,
151-
_id: new ObjectId(baseEvent._id),
152-
});
121+
const rrule = new CompassEventRRule(baseEvent);
153122
const instances = rrule.instances();
154123
const startDate = parseCompassEventDate(baseEvent.startDate!);
155124
const endDate = parseCompassEventDate(baseEvent.endDate!);
@@ -174,10 +143,7 @@ describe("CompassEventRRule: ", () => {
174143
const date = dayjs().startOf("year"); // specific date for testing
175144
const dates = generateCompassEventDates({ date });
176145
const baseEvent = createMockBaseEvent({ ...dates, recurrence: { rule } });
177-
const rrule = new CompassEventRRule({
178-
...baseEvent,
179-
_id: new ObjectId(baseEvent._id),
180-
});
146+
const rrule = new CompassEventRRule(baseEvent);
181147
const instances = rrule.instances();
182148
const startDate = parseCompassEventDate(baseEvent.startDate!);
183149
const endDate = parseCompassEventDate(baseEvent.endDate!);

packages/backend/src/event/classes/compass.event.rrule.ts renamed to packages/core/src/util/event/compass.event.rrule.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { ObjectId, WithId } from "mongodb";
21
import { Options, RRule, RRuleStrOptions, rrulestr } from "rrule";
32
import { GCAL_MAX_RECURRENCES } from "@core/constants/core.constants";
43
import {
5-
Schema_Event,
4+
Schema_Event_Recur_Base,
65
Schema_Event_Recur_Instance,
76
} from "@core/types/event.types";
87
import dayjs from "@core/util/date/dayjs";
@@ -12,14 +11,11 @@ import {
1211
} from "@core/util/event/event.util";
1312

1413
export class CompassEventRRule extends RRule {
15-
#event: WithId<Omit<Schema_Event, "_id">>;
14+
#event: Schema_Event_Recur_Base;
1615
#dateFormat: string;
1716
#durationMs!: number;
1817

19-
constructor(
20-
event: WithId<Omit<Schema_Event, "_id">>,
21-
options: Partial<Options> = {},
22-
) {
18+
constructor(event: Schema_Event_Recur_Base, options: Partial<Options> = {}) {
2319
super(CompassEventRRule.#initOptions(event, options));
2420

2521
this.#event = event;
@@ -32,11 +28,14 @@ export class CompassEventRRule extends RRule {
3228
}
3329

3430
static #initOptions(
35-
event: WithId<Omit<Schema_Event, "_id">>,
31+
event: Schema_Event_Recur_Base,
3632
options: Partial<Options> = {},
3733
): Partial<Options> {
3834
const startDate = parseCompassEventDate(event.startDate!);
3935
const dtstart = startDate.local().toDate();
36+
const wkst = RRule.SU;
37+
const freq = RRule.WEEKLY;
38+
const interval = 1;
4039
const tzid = dayjs.tz.guess();
4140
const opts: Partial<RRuleStrOptions> = { dtstart, tzid };
4241
const recurrence = event.recurrence?.rule?.join("\n").trim();
@@ -46,15 +45,7 @@ export class CompassEventRRule extends RRule {
4645
const rawCount = rruleOptions.count ?? GCAL_MAX_RECURRENCES;
4746
const count = Math.min(rawCount, GCAL_MAX_RECURRENCES);
4847

49-
return { ...rruleOptions, count, dtstart, tzid };
50-
}
51-
52-
toString(): string {
53-
return super
54-
.toString()
55-
.split("\n")
56-
.filter((r) => !(r.startsWith("DTSTART") || r.startsWith("DTEND")))
57-
.join("\n");
48+
return { wkst, freq, interval, ...rruleOptions, count, dtstart, tzid };
5849
}
5950

6051
toRecurrence(): string[] {
@@ -64,10 +55,9 @@ export class CompassEventRRule extends RRule {
6455
.filter((r) => !(r.startsWith("DTSTART") || r.startsWith("DTEND")));
6556
}
6657

67-
base(): WithId<Omit<Schema_Event, "_id">> {
58+
base(): Schema_Event_Recur_Base {
6859
return {
6960
...this.#event,
70-
_id: this.#event._id ?? new ObjectId(),
7161
recurrence: { rule: this.toRecurrence() },
7262
};
7363
}
@@ -79,7 +69,7 @@ export class CompassEventRRule extends RRule {
7969
* @description Returns all instances of the event based on the recurrence rule.
8070
* @note **This is a test-only method for now, it is not to be used in production.**
8171
*/
82-
instances(): WithId<Omit<Schema_Event_Recur_Instance, "_id">>[] {
72+
instances(): Array<Omit<Schema_Event_Recur_Instance, "_id">> {
8373
return this.all().map((date) => {
8474
const timezone = dayjs.tz.guess();
8575
const startDate = dayjs(date).tz(timezone);
@@ -89,10 +79,9 @@ export class CompassEventRRule extends RRule {
8979

9080
return {
9181
...baseData,
92-
_id: new ObjectId(),
9382
startDate: startDate.format(this.#dateFormat),
9483
endDate: endDate.format(this.#dateFormat),
95-
recurrence: { eventId: this.base()._id.toString() },
84+
recurrence: { eventId: this.base()._id! },
9685
};
9786
});
9887
}

0 commit comments

Comments
 (0)