Skip to content

Commit 37816a3

Browse files
🐛 fix(duplicate-event): fix event duplication - web (#1001)
1 parent f63e6a2 commit 37816a3

File tree

8 files changed

+127
-97
lines changed

8 files changed

+127
-97
lines changed

packages/core/src/mappers/map.event.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,20 @@ export namespace MapEvent {
3838

3939
export const removeProviderData = (
4040
event: WithId<Omit<Schema_Event, "_id">> | Schema_Event,
41-
): Omit<Schema_Event, "_id" | "gEventId" | "gRecurringEventId"> => {
41+
): Omit<
42+
WithId<Omit<Schema_Event, "_id">> | Schema_Event,
43+
"gEventId" | "gRecurringEventId"
44+
> => {
4245
const {
4346
gEventId, // eslint-disable-line @typescript-eslint/no-unused-vars
4447
gRecurringEventId, // eslint-disable-line @typescript-eslint/no-unused-vars
48+
recurrence, // eslint-disable-line @typescript-eslint/no-unused-vars
4549
...coreEvent
4650
} = event;
4751

48-
delete coreEvent.recurrence?.eventId;
52+
if (event.recurrence?.rule) {
53+
Object.assign(coreEvent, { recurrence: { rule: event.recurrence.rule } });
54+
}
4955

5056
return coreEvent;
5157
};

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

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,7 @@ export const EventUpdateSchema = z.object({
185185
description: z.string().nullable().optional(),
186186
priority: z.nativeEnum(Priorities).optional(),
187187
recurrence: z.union([
188-
CompassEventRecurrence.omit({ rule: true }).extend({
189-
rule: z.null(),
190-
}),
188+
CompassEventRecurrence.extend({ rule: z.null() }),
191189
CompassEventRecurrence,
192190
]),
193191
startDate: eventDateSchema.optional(),
@@ -196,15 +194,11 @@ export const EventUpdateSchema = z.object({
196194
isSomeday: z.boolean().optional(),
197195
});
198196

199-
export const CompassCoreEventSchema = CoreEventSchema.omit({
200-
recurrence: true,
201-
}).extend({
197+
export const CompassCoreEventSchema = CoreEventSchema.extend({
202198
_id: idSchema,
203-
recurrence: CompassEventRecurrence.omit({ rule: true })
204-
.extend({
205-
rule: z.union([z.null(), z.array(z.string())]),
206-
})
207-
.optional(),
199+
recurrence: CompassEventRecurrence.extend({
200+
rule: z.union([z.null(), z.array(z.string())]),
201+
}).optional(),
208202
});
209203

210204
export const CompassCoreCalendarEventSchema = CompassCoreEventSchema.extend({
@@ -230,9 +224,7 @@ export const CompassThisEventSchema = BaseCompassEventSchema.merge(
230224
z.object({
231225
recurrence: z
232226
.union([
233-
CompassEventRecurrence.omit({ rule: true }).extend({
234-
rule: z.null(),
235-
}),
227+
CompassEventRecurrence.extend({ rule: z.null() }),
236228
CompassEventRecurrence,
237229
])
238230
.optional(),
@@ -247,9 +239,7 @@ export const CompassThisAndFollowingEventSchema = BaseCompassEventSchema.merge(
247239
applyTo: z.literal(RecurringEventUpdateScope.THIS_AND_FOLLOWING_EVENTS),
248240
payload: CompassCoreEventSchema.merge(
249241
z.object({ recurrence: CompassEventRecurrence }),
250-
)
251-
.omit({ isSomeday: true })
252-
.extend({ isSomeday: z.literal(false) }),
242+
).extend({ isSomeday: z.literal(false) }),
253243
}),
254244
);
255245

@@ -258,9 +248,7 @@ export const CompassAllEventsSchema = BaseCompassEventSchema.merge(
258248
applyTo: z.literal(RecurringEventUpdateScope.ALL_EVENTS),
259249
payload: CompassCoreEventSchema.merge(
260250
z.object({ recurrence: CompassEventRecurrence }),
261-
)
262-
.omit({ isSomeday: true })
263-
.extend({ isSomeday: z.literal(false) }),
251+
).extend({ isSomeday: z.literal(false) }),
264252
}),
265253
);
266254

packages/web/src/common/types/web.event.types.ts

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ import {
99
} from "@core/types/event.types";
1010
import { SelectOption } from "@web/common/types/component.types";
1111

12-
export enum Recurrence_Selection {
13-
NONE = "none",
14-
WEEK = "week",
15-
MONTH = "month",
16-
}
17-
1812
export const optimisticIdSchema = z
1913
.string()
2014
.refine(
@@ -29,41 +23,37 @@ const WebEventRecurrence = z.union([
2923
CompassEventRecurrence,
3024
]);
3125

32-
const WebCoreEventSchema = CompassCoreEventSchema.omit({
33-
recurrence: true,
34-
}).extend({
26+
const WebCoreEventSchema = CompassCoreEventSchema.extend({
27+
_id: z.union([idSchema, optimisticIdSchema]),
3528
recurrence: WebEventRecurrence,
29+
order: z.number().optional(),
3630
});
3731

3832
export const GridEventSchema = WebCoreEventSchema.extend({
3933
hasFlipped: z.boolean().optional(),
4034
isOpen: z.boolean().optional(),
4135
row: z.number().optional(),
4236
order: z.number().optional(), // allow carry over from Someday events
37+
position: z.object({
38+
isOverlapping: z.boolean(),
39+
widthMultiplier: z.number(), // EG: 0.5 for half width
40+
horizontalOrder: z.number(),
41+
dragOffset: z.object({ y: z.number() }),
42+
initialX: z.number().nullable(),
43+
initialY: z.number().nullable(),
44+
}),
4345
});
4446

4547
export const SomedayEventSchema = WebCoreEventSchema.extend({
46-
_id: z.union([idSchema, optimisticIdSchema]),
4748
isSomeday: z.literal(true),
4849
order: z.number(),
4950
});
5051

5152
export type Schema_WebEvent = z.infer<typeof WebCoreEventSchema>;
53+
5254
export type Schema_SomedayEvent = z.infer<typeof SomedayEventSchema>;
5355

54-
export interface Schema_GridEvent extends Schema_Event {
55-
hasFlipped?: boolean;
56-
isOpen?: boolean;
57-
row?: number;
58-
position: {
59-
isOverlapping: boolean;
60-
widthMultiplier: number; // EG: 0.5 for half width
61-
horizontalOrder: number;
62-
dragOffset: { y: number };
63-
initialX: number | null;
64-
initialY: number | null;
65-
};
66-
}
56+
export type Schema_GridEvent = z.infer<typeof GridEventSchema>;
6757

6858
export interface Schema_OptimisticEvent extends Schema_GridEvent {
6959
_id: string; // We guarantee that we have an _id for optimistic events, unlike `Schema_Event`

packages/web/src/common/utils/event.util.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@ import {
77
} from "@core/constants/core.constants";
88
import { YEAR_MONTH_DAY_COMPACT_FORMAT } from "@core/constants/date.constants";
99
import { Status } from "@core/errors/status.codes";
10-
import { Categories_Event, Schema_Event } from "@core/types/event.types";
10+
import {
11+
Categories_Event,
12+
Schema_Event,
13+
Schema_Event_Recur_Base,
14+
} from "@core/types/event.types";
1115
import dayjs, { Dayjs } from "@core/util/date/dayjs";
12-
import { validateEvent } from "@core/validators/event.validator";
1316
import { getUserId } from "@web/auth/auth.util";
1417
import { DATA_EVENT_ELEMENT_ID } from "@web/common/constants/web.constants";
1518
import { PartialMouseEvent } from "@web/common/types/util.types";
1619
import {
1720
Schema_GridEvent,
1821
Schema_OptimisticEvent,
22+
Schema_WebEvent,
1923
} from "@web/common/types/web.event.types";
2024
import { validateSomedayEvent } from "@web/common/validators/someday.event.validator";
25+
import { validateGridEvent } from "../validators/grid.event.validator";
2126

2227
const gridEventDefaultPosition = {
2328
isOverlapping: false,
@@ -63,11 +68,17 @@ export const assembleDefaultEvent = async (
6368
case Categories_Event.TIMED: {
6469
const defaultTimed: Schema_GridEvent = {
6570
...baseEvent,
71+
_id: baseEvent._id!,
6672
isAllDay: false,
6773
isSomeday: false,
68-
startDate,
69-
endDate,
74+
startDate: startDate!,
75+
endDate: endDate!,
7076
position: gridEventDefaultPosition,
77+
origin: baseEvent.origin ?? Origin.COMPASS,
78+
priority: baseEvent.priority ?? Priorities.UNASSIGNED,
79+
user: baseEvent.user!,
80+
recurrence:
81+
baseEvent.recurrence as Schema_Event_Recur_Base["recurrence"],
7182
};
7283
return defaultTimed;
7384
}
@@ -77,10 +88,18 @@ export const assembleDefaultEvent = async (
7788
};
7889

7990
export const assembleGridEvent = (event: Schema_Event): Schema_GridEvent => {
80-
const gridEvent = {
91+
const gridEvent: Schema_GridEvent = {
8192
...event,
8293
position: gridEventDefaultPosition,
94+
_id: event._id!,
95+
startDate: event.startDate!,
96+
endDate: event.endDate!,
97+
origin: event.origin ?? Origin.COMPASS,
98+
priority: event.priority ?? Priorities.UNASSIGNED,
99+
user: event.user!,
100+
recurrence: event.recurrence as Schema_Event_Recur_Base["recurrence"],
83101
};
102+
84103
return gridEvent;
85104
};
86105

@@ -188,27 +207,36 @@ export const prepEvtBeforeSubmit = (
188207
draft: Schema_Event | Schema_GridEvent,
189208
userId: string,
190209
) => {
191-
const _event = {
210+
const _event: Omit<Schema_Event | Schema_GridEvent, "recurrence"> = {
192211
...draft,
193212
origin: Origin.COMPASS,
194213
user: userId,
195214
};
196215

197-
const event = validateEvent(_event);
216+
if (draft.recurrence) Object.assign(_event, { recurrence: draft.recurrence });
217+
218+
const event = validateGridEvent(_event);
198219
return event;
199220
};
200221

201222
export const prepSomedayEventBeforeSubmit = (
202223
draft: Schema_Event | Schema_GridEvent,
203224
userId: string,
204225
) => {
205-
const _event = {
226+
const _event: Omit<Schema_WebEvent, "recurrence"> = {
206227
...draft,
207228
origin: Origin.COMPASS,
208229
user: userId,
230+
_id: draft._id!,
231+
startDate: draft.startDate!,
232+
endDate: draft.endDate!,
233+
priority: draft.priority ?? Priorities.UNASSIGNED,
209234
};
210235

236+
if (draft.recurrence) Object.assign(_event, { recurrence: draft.recurrence });
237+
211238
const event = validateSomedayEvent(_event);
239+
212240
return event;
213241
};
214242

@@ -229,8 +257,8 @@ const _assembleBaseEvent = (
229257
): Schema_Event => {
230258
const baseEvent = {
231259
_id: event._id,
232-
title: event.title || "",
233-
description: event.description || "",
260+
title: event.title ?? "",
261+
description: event.description ?? "",
234262
startDate: event.startDate,
235263
endDate: event.endDate,
236264
user: userId,

packages/web/src/common/utils/web.date.util.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import dayjs, { Dayjs } from "dayjs";
2-
import { RRULE } from "@core/constants/core.constants";
32
import {
43
HOURS_AM_FORMAT,
54
HOURS_AM_SHORT_FORMAT,
@@ -13,10 +12,7 @@ import { GRID_TIME_STEP } from "@web/views/Calendar/layout.constants";
1312
import { roundToNext } from ".";
1413
import { ACCEPTED_TIMES } from "../constants/web.constants";
1514
import { theme } from "../styles/theme";
16-
import {
17-
Recurrence_Selection,
18-
Schema_SelectedDates,
19-
} from "../types/web.event.types";
15+
import { Schema_SelectedDates } from "../types/web.event.types";
2016

2117
export const dateIsValid = (date: string) => {
2218
const notNaN = !Number.isNaN(new Date(date).getTime());
@@ -121,19 +117,6 @@ export const getNextIntervalTimes = () => {
121117
return { startDate, endDate };
122118
};
123119

124-
export const getRecurrenceRule = (selection: Recurrence_Selection) => {
125-
switch (selection) {
126-
case Recurrence_Selection.WEEK:
127-
return [RRULE.WEEK];
128-
break;
129-
case Recurrence_Selection.MONTH:
130-
return [RRULE.MONTH];
131-
break;
132-
default:
133-
throw Error("Invalid selection");
134-
}
135-
};
136-
137120
export const getTimeLabel = (value: string) => value.replace(":00", "");
138121

139122
export const getTimeOptionByValue = (date: Dayjs): Option_Time => {

packages/web/src/common/validators/grid.event.validator.test.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,22 @@ describe("validateGridEvent", () => {
1313
priority: Priorities.RELATIONS,
1414
user: "user123",
1515
unexpectedProperty: "unexpectedValue",
16+
position: {
17+
dragOffset: { y: 0 },
18+
horizontalOrder: 0,
19+
initialX: 0,
20+
initialY: 0,
21+
isOverlapping: false,
22+
widthMultiplier: 1,
23+
},
1624
};
1725

1826
const parsedEvent = validateGridEvent(event);
1927
expect(parsedEvent).not.toHaveProperty("unexpectedProperty");
2028
});
29+
2130
it("validates a correct event", () => {
22-
const event: Schema_GridEvent = {
31+
const event: Omit<Schema_GridEvent, "recurrence"> = {
2332
_id: new ObjectId().toString(),
2433
endDate: "2023-01-02",
2534
hasFlipped: true,
@@ -29,21 +38,37 @@ describe("validateGridEvent", () => {
2938
origin: Origin.COMPASS,
3039
priority: Priorities.RELATIONS,
3140
user: "user123",
41+
position: {
42+
dragOffset: { y: 0 },
43+
horizontalOrder: 0,
44+
initialX: 0,
45+
initialY: 0,
46+
isOverlapping: false,
47+
widthMultiplier: 1,
48+
},
3249
};
3350

3451
const parsedEvent = validateGridEvent(event);
3552
expect(parsedEvent).toEqual(event);
3653
});
3754

3855
it("invalidates when types are incorrect", () => {
39-
const event = {
56+
const event: Omit<Partial<Schema_GridEvent>, "recurrence"> = {
4057
startDate: "2022-10-22",
4158
endDate: "2023-01-02",
4259
origin: Origin.UNSURE,
4360
priority: Priorities.SELF,
4461
user: "user1",
45-
hasFlipped: "true", // invalid
46-
} as unknown as Schema_GridEvent;
62+
hasFlipped: "true" as unknown as boolean, // invalid
63+
position: {
64+
dragOffset: { y: 0 },
65+
horizontalOrder: 0,
66+
initialX: 0,
67+
initialY: 0,
68+
isOverlapping: false,
69+
widthMultiplier: 1,
70+
},
71+
};
4772

4873
expect(() => validateGridEvent(event)).toThrow();
4974
});

0 commit comments

Comments
 (0)