Skip to content

Commit 37049be

Browse files
✨ feat(edit-recurrence): add ability to edit recurrence (#894)
* ✨ feat(edit-recurrence): add ability to edit recurrence * ✨ feat(edit-recurrence): add bson pkg to core * ✨ feat(edit-recurrence): parse ui payload with CompassCoreEventSchema * ✨ feat(edit-recurrence): enable recurrence edit * ✨ feat(edit-recurrence): add recurrence section tests * ✨ feat(edit-recurrence): add recurrence hook tests * ✨ feat(edit-recurrence): keep recurring someday events hidden * Update packages/web/src/views/Forms/EventForm/DateControlsSection/RecurrenceSection/utils.test.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 1511d04 commit 37049be

File tree

31 files changed

+957
-596
lines changed

31 files changed

+957
-596
lines changed

packages/backend/src/event/classes/compass.event.generator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import {
1414
Schema_Event_Recur_Base,
1515
Schema_Event_Recur_Instance,
1616
} from "@core/types/event.types";
17+
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
1718
import { isAllDay, parseCompassEventDate } from "@core/util/event/event.util";
1819
import mongoService from "@backend/common/services/mongo.service";
19-
import { CompassEventRRule } from "@backend/event/classes/compass.event.rrule";
2020

2121
export class CompassEventFactory {
2222
private static async findCompassEvent(

packages/backend/src/event/classes/compass.event.parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
TransitionStatus,
1313
WithCompassId,
1414
} from "@core/types/event.types";
15+
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
1516
import {
1617
isBase,
1718
isInstance,
@@ -20,7 +21,6 @@ import {
2021
import { GenericError } from "@backend/common/errors/generic/generic.errors";
2122
import { error } from "@backend/common/errors/handlers/error.handler";
2223
import mongoService from "@backend/common/services/mongo.service";
23-
import { CompassEventRRule } from "@backend/event/classes/compass.event.rrule";
2424
import {
2525
_createCompassEvent,
2626
_createGcal,

packages/backend/src/event/controllers/event.controller.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { SessionRequest } from "supertokens-node/framework/express";
33
import { Status } from "@core/errors/status.codes";
44
import { Logger } from "@core/logger/winston.logger";
55
import {
6+
CompassCoreEventSchema,
67
CompassEvent,
78
CompassEventStatus,
89
CompassCoreEventSchema as EventSchema,
@@ -11,7 +12,6 @@ import {
1112
RecurringEventUpdateScope,
1213
Schema_Event,
1314
} from "@core/types/event.types";
14-
import { validateEvent } from "@core/validators/event.validator";
1515
import { Res_Promise, SReqBody } from "@backend/common/types/express.types";
1616
import eventService from "@backend/event/services/event.service";
1717
import { CompassSyncProcessor } from "@backend/sync/services/sync/compass.sync.processor";
@@ -24,7 +24,7 @@ class EventController {
2424
status?: CompassEventStatus,
2525
applyTo: RecurringEventUpdateScope = RecurringEventUpdateScope.THIS_EVENT,
2626
) {
27-
const payload = validateEvent(_payload as Schema_Event);
27+
const payload = CompassCoreEventSchema.parse(_payload as Schema_Event);
2828

2929
const event = {
3030
status: status ?? CompassEventStatus.CONFIRMED,
@@ -134,10 +134,9 @@ class EventController {
134134
const { body, query, params, session } = req;
135135
const user = session?.getUserId() as string;
136136
const _id = params["id"] as string;
137-
const data = EventSchema.parse({ ...body, user, _id });
138137

139138
await this.processEvent(
140-
data as CompassEvent["payload"],
139+
{ ...body, user, _id } as CompassEvent["payload"],
141140
CompassEventStatus.CONFIRMED,
142141
(query["applyTo"] as RecurringEventUpdateScope) ??
143142
RecurringEventUpdateScope.THIS_EVENT,

packages/backend/src/event/services/event.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
} from "@core/types/event.types";
2929
import { gSchema$Event } from "@core/types/gcal";
3030
import { getCurrentRangeDates } from "@core/util/date/date.util";
31+
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
3132
import {
3233
isExistingInstance,
3334
parseCompassEventDate,
@@ -39,7 +40,6 @@ import { GenericError } from "@backend/common/errors/generic/generic.errors";
3940
import { error } from "@backend/common/errors/handlers/error.handler";
4041
import gcalService from "@backend/common/services/gcal/gcal.service";
4142
import mongoService from "@backend/common/services/mongo.service";
42-
import { CompassEventRRule } from "@backend/event/classes/compass.event.rrule";
4343
import { reorderEvents } from "@backend/event/queries/event.queries";
4444
import { getReadAllFilter } from "@backend/event/services/event.service.util";
4545
import { CompassSyncProcessor } from "@backend/sync/services/sync/compass.sync.processor";

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"typescript": "^5.1.6"
1212
},
1313
"dependencies": {
14+
"bson": "^6.10.4",
1415
"tinycolor2": "^1.6.0",
1516
"winston": "^3.8.1"
1617
}

packages/core/src/types/event.types.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
import { Query } from "express-serve-static-core";
1+
import type { ObjectId } from "bson";
2+
import type { Query } from "express-serve-static-core";
23
import { z } from "zod";
3-
import { Origin, Priorities, Priority } from "@core/constants/core.constants";
4+
import {
5+
Origin,
6+
Priorities,
7+
type Priority,
8+
} from "@core/constants/core.constants";
49

510
/**
611
* Event category, based on its display type
@@ -167,7 +172,7 @@ export const CoreEventSchema = z.object({
167172
user: z.string(),
168173
});
169174

170-
const CompassEventRecurrence = z.object({
175+
export const CompassEventRecurrence = z.object({
171176
rule: z.array(z.string()),
172177
eventId: z.string().optional(),
173178
});
@@ -187,8 +192,15 @@ export const EventUpdateSchema = z.object({
187192
isSomeday: z.boolean().optional(),
188193
});
189194

190-
export const CompassCoreEventSchema = CoreEventSchema.extend({
195+
export const CompassCoreEventSchema = CoreEventSchema.omit({
196+
recurrence: true,
197+
}).extend({
191198
_id: z.string(),
199+
recurrence: CompassEventRecurrence.omit({ rule: true })
200+
.extend({
201+
rule: z.union([z.null(), z.array(z.string())]),
202+
})
203+
.optional(),
192204
});
193205

194206
const BaseCompassEventSchema = z.object({
@@ -260,6 +272,7 @@ export type CompassEvent = z.infer<typeof CompassEventSchema>;
260272
export type EventUpdatePayload = z.infer<typeof EventUpdateSchema>;
261273

262274
export type WithCompassId<T> = T & { _id: string };
275+
export type WithMongoId<T> = T & { _id: ObjectId }; // same as WithId from the 'mongodb' package - but for ui use
263276
export type WithoutCompassId<T> = Omit<T, "_id">;
264277
export enum CalendarProvider {
265278
GOOGLE = "google",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
type Schema_Event_Recur_Base,
1010
} from "@core/types/event.types";
1111
import dayjs from "@core/util/date/dayjs";
12+
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
1213
import {
1314
isBase,
1415
isInstance,
@@ -19,7 +20,6 @@ import {
1920
createMockBaseEvent,
2021
generateCompassEventDates,
2122
} from "@core/util/test/ccal.event.factory";
22-
import { CompassEventRRule } from "@backend/event/classes/compass.event.rrule";
2323

2424
describe("CompassEventRRule: ", () => {
2525
it(`should return the correct number of events based on rrule count`, () => {

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { ObjectId, WithId } from "mongodb";
1+
import { ObjectId } from "bson";
2+
import type { WithId } from "mongodb";
23
import type { Options, RRuleStrOptions } from "rrule";
34
import { RRule, rrulestr } from "rrule";
45
import type { ParsedOptions } from "rrule/dist/esm/types";
@@ -22,7 +23,10 @@ export class CompassEventRRule extends RRule {
2223
#durationMs!: number;
2324

2425
constructor(
25-
event: WithId<Omit<Schema_Event_Recur_Base, "_id">>,
26+
event: Pick<
27+
WithId<Omit<Schema_Event_Recur_Base, "_id">>,
28+
"startDate" | "endDate" | "_id" | "recurrence"
29+
>,
2630
options: Partial<Options> = {},
2731
) {
2832
super(CompassEventRRule.#initOptions(event, options));

packages/web/src/__tests__/utils/test.util.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ interface Spies {
33
}
44
const spies: Spies = {};
55

6-
export const arraysAreEqual = (a: any[], b: any[]) => {
6+
export const arraysAreEqual = (a: unknown[], b: unknown[]) => {
77
return (
88
Array.isArray(a) &&
99
Array.isArray(b) &&
@@ -34,3 +34,13 @@ export const mockResizeObserver = () => {
3434
export const mockScroll = () => {
3535
window.HTMLElement.prototype.scroll = jest.fn();
3636
};
37+
38+
export const mockBSON = () => {
39+
jest.mock("bson", () => ({
40+
ObjectId: class ObjectId {
41+
toString() {
42+
return crypto.randomUUID();
43+
}
44+
},
45+
}));
46+
};

packages/web/src/__tests__/web.test.start.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { server } from "@web/__tests__/__mocks__/server/mock.server";
22
import {
33
clearLocalStorageMock,
4+
mockBSON,
45
mockResizeObserver,
56
mockScroll,
67
} from "@web/__tests__/utils/test.util";
78

9+
mockBSON();
10+
811
beforeAll(() => {
912
mockScroll();
1013
mockResizeObserver();

0 commit comments

Comments
 (0)