Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a4980aa
feat(event): introduce WithId type and addId utility function
tyler-dane Dec 30, 2025
f08107c
feat(event): implement pending event handling and cursor updates
tyler-dane Dec 30, 2025
2f58e22
refactor(event): replace optimistic event handling with pending state…
tyler-dane Dec 30, 2025
8cb3070
refactor(event): update pending event handling and improve state mana…
tyler-dane Dec 30, 2025
4f8d370
test(event): add unit tests for pending event handling and selectors
tyler-dane Dec 30, 2025
1440521
Apply suggestions from code review
tyler-dane Dec 30, 2025
305f4fe
test(SomedayEventForm): enhance hotkey functionality tests
tyler-dane Dec 30, 2025
2dc427c
test(draft): enhance setupDraftState for improved store handling
tyler-dane Dec 30, 2025
4051c08
test(draft): simplify setupDraftState and improve test integration
tyler-dane Dec 30, 2025
1889e22
test(context-menu): add tests for ContextMenuItems and enhance pendin…
tyler-dane Dec 30, 2025
65120bd
test(context-menu): refactor tests for ContextMenuItems to use centra…
tyler-dane Dec 30, 2025
16d3d0c
test(agenda-events): enhance tests for draggable all-day and timed ag…
tyler-dane Dec 30, 2025
dba0b68
test(agenda-events): add isDisabled prop to draggable agenda events
tyler-dane Dec 30, 2025
8c2b2b4
refactor(agenda-events): update AllDayAgendaEvents and TimedAgendaEve…
tyler-dane Dec 30, 2025
d3feba3
test(DND): add test for Draggable component's disabled prop behavior
tyler-dane Dec 31, 2025
b1fe67c
refactor(events): reorganize event slice utilities and update imports
tyler-dane Dec 31, 2025
7f08edd
refactor(context-menu): streamline action disabling logic in ContextM…
tyler-dane Dec 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/web/src/__tests__/utils/state/store.test.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ export const createInitialState = (
dateToResize: null,
},
},
pendingEvents: {
eventIds: [],
},
},
view: {
dates: {
Expand Down
18 changes: 7 additions & 11 deletions packages/web/src/common/types/web.event.types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ObjectId } from "bson";
import { z } from "zod";
import { ID_OPTIMISTIC_PREFIX } from "@core/constants/core.constants";
import {
CompassCoreEventSchema,
CompassEventRecurrence,
Expand All @@ -9,22 +7,14 @@ import {
import { IDSchema } from "@core/types/type.utils";
import { SelectOption } from "@web/common/types/component.types";

export const optimisticIdSchema = z
.string()
.refine(
(id) =>
id.startsWith(`${ID_OPTIMISTIC_PREFIX}-`) &&
ObjectId.isValid(id.replace(`${ID_OPTIMISTIC_PREFIX}-`, "")),
);

const WebEventRecurrence = z.union([
z.undefined(),
CompassEventRecurrence.omit({ rule: true }).extend({ rule: z.null() }),
CompassEventRecurrence,
]);

const WebCoreEventSchema = CompassCoreEventSchema.extend({
_id: z.union([IDSchema, optimisticIdSchema]).optional(),
_id: IDSchema.optional(),
recurrence: WebEventRecurrence,
order: z.number().optional(),
});
Expand Down Expand Up @@ -79,3 +69,9 @@ export interface Schema_SomedayEventsColumn {
[key: string]: Schema_Event;
};
}

/**
* Adds an _id property to an object shape
* @template TSchema - The base type to add _id to.
*/
export type WithId<TSchema> = TSchema & { _id: string };
13 changes: 12 additions & 1 deletion packages/web/src/common/utils/event/event.util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
Schema_GridEvent,
Schema_WebEvent,
} from "@web/common/types/web.event.types";
import { isEventInRange } from "@web/common/utils/event/event.util";
import { addId, isEventInRange } from "@web/common/utils/event/event.util";
import { _assembleGridEvent } from "@web/ducks/events/sagas/saga.util";

describe("isEventInRange", () => {
Expand Down Expand Up @@ -53,3 +53,14 @@ describe("_assembleGridEvent", () => {
expect(result.position.horizontalOrder).toBe(1);
});
});

describe("addId", () => {
it("should add a raw MongoID and set isOptimistic flag", () => {
const event = createMockStandaloneEvent() as Schema_GridEvent;
const result = addId(event);

expect(result._id).toBeDefined();
expect(result._id).not.toMatch(/^optimistic-/);
expect((result as any).isOptimistic).toBe(true);
});
});
47 changes: 21 additions & 26 deletions packages/web/src/common/utils/event/event.util.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { ObjectId } from "bson";
import { DropResult } from "@hello-pangea/dnd";
import {
ID_OPTIMISTIC_PREFIX,
Origin,
Priorities,
} from "@core/constants/core.constants";
import { Origin, Priorities } from "@core/constants/core.constants";
import { YEAR_MONTH_DAY_COMPACT_FORMAT } from "@core/constants/date.constants";
import { Status } from "@core/errors/status.codes";
import {
Expand All @@ -25,8 +21,8 @@ import { isElementInViewport } from "@web/common/context/pointer-position";
import { PartialMouseEvent } from "@web/common/types/util.types";
import {
Schema_GridEvent,
Schema_OptimisticEvent,
Schema_WebEvent,
WithId,
} from "@web/common/types/web.event.types";
import {
focusElement,
Expand All @@ -43,6 +39,21 @@ export const gridEventDefaultPosition: Schema_GridEvent["position"] = {
dragOffset: { x: 0, y: 0 },
};

export const addId = (event: Schema_GridEvent): WithId<Schema_GridEvent> => {
const _event = {
...event,
_id: new ObjectId().toString(),
} as WithId<Schema_GridEvent>;

Object.defineProperty(_event, "isOptimistic", {
value: true,
writable: true,
configurable: true,
enumerable: false,
});
return _event;
};

export const assembleDefaultEvent = async (
draftType?: Categories_Event | null,
startDate?: string,
Expand Down Expand Up @@ -248,26 +259,21 @@ export const isEventInRange = (
return isStartDateInRange || isEndDateInRange;
};

export const isOptimisticEvent = (event: Schema_Event) => {
const isOptimistic = event._id?.startsWith(ID_OPTIMISTIC_PREFIX) || false;
return isOptimistic;
};

export const getEventCursorStyle = (
isDragging: boolean,
isOptimistic: boolean,
isPending = false,
): string => {
if (isDragging) return "move";
if (isOptimistic) return "wait";
if (isPending) return "wait";
return "pointer";
};

export const getEventCursorClass = (
isDragging: boolean,
isOptimistic: boolean,
isPending = false,
): string => {
if (isDragging) return "cursor-move";
if (isOptimistic) return "cursor-wait";
if (isPending) return "cursor-wait";
return "cursor-pointer";
};

Expand All @@ -291,17 +297,6 @@ export const prepEvtAfterDraftDrop = (
return event;
};

export const replaceIdWithOptimisticId = (
event: Schema_GridEvent,
): Schema_OptimisticEvent => {
const _event = {
...event,
_id: `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`,
};

return _event;
};

const _assembleBaseEvent = (
userId: string,
event: Partial<Schema_Event>,
Expand Down
57 changes: 28 additions & 29 deletions packages/web/src/common/utils/event/someday.event.util.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ObjectId } from "bson";
import { faker } from "@faker-js/faker";
import {
ID_OPTIMISTIC_PREFIX,
Origin,
Priorities,
RRULE,
Expand Down Expand Up @@ -333,14 +332,14 @@ describe("computeRelativeEventDateRange", () => {
jest.useRealTimers();
});

describe("Optimistic Event IDs", () => {
it("should handle events with optimistic IDs", () => {
const optimisticId = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
describe("Event IDs", () => {
it("should handle events with IDs", () => {
const eventId = new ObjectId().toString();
// Add all required properties for Schema_SomedayEvent
const events = {
[optimisticId]: {
[eventId]: {
...baseEvent,
_id: optimisticId,
_id: eventId,
startDate: "2024-03-19",
endDate: "2024-03-20",
isSomeday: true,
Expand All @@ -358,20 +357,20 @@ describe("computeRelativeEventDateRange", () => {

const result = categorizeSomedayEvents(events, weekDates);

expect(result.columns[COLUMN_WEEK].eventIds).toContain(optimisticId);
expect(result.columns[COLUMN_MONTH].eventIds).not.toContain(optimisticId);
expect(result.columns[COLUMN_WEEK].eventIds).toContain(eventId);
expect(result.columns[COLUMN_MONTH].eventIds).not.toContain(eventId);
expect(result.columnOrder).toEqual([COLUMN_WEEK, COLUMN_MONTH]);
});

it("should maintain order for events with optimistic IDs", () => {
const optimisticIdA = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
const optimisticIdB = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
it("should maintain order for events with IDs", () => {
const eventIdA = new ObjectId().toString();
const eventIdB = new ObjectId().toString();

// Add all required properties for Schema_SomedayEvent
const events = {
[optimisticIdA]: {
[eventIdA]: {
...baseEvent,
_id: optimisticIdA,
_id: eventIdA,
startDate: "2024-03-19",
endDate: "2024-03-20",
order: 2,
Expand All @@ -380,9 +379,9 @@ describe("computeRelativeEventDateRange", () => {
priority: Priorities.UNASSIGNED,
user: "test-user",
},
[optimisticIdB]: {
[eventIdB]: {
...baseEvent,
_id: optimisticIdB,
_id: eventIdB,
startDate: "2024-03-19",
endDate: "2024-03-20",
order: 1,
Expand All @@ -401,27 +400,27 @@ describe("computeRelativeEventDateRange", () => {
const result = categorizeSomedayEvents(events, weekDates);

expect(result.columns[COLUMN_WEEK].eventIds).toEqual([
optimisticIdB,
optimisticIdA,
eventIdB,
eventIdA,
]);
});

it("should assign sequential orders for optimistic events without order", () => {
const optimisticIdA = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
const optimisticIdB = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
it("should assign sequential orders for events without order", () => {
const eventIdA = new ObjectId().toString();
const eventIdB = new ObjectId().toString();
// Add all required properties for Schema_Event
const events = [
{
...baseEvent,
_id: optimisticIdA,
_id: eventIdA,
isSomeday: true,
origin: Origin.COMPASS,
priority: Priorities.UNASSIGNED,
user: "test-user",
},
{
...baseEvent,
_id: optimisticIdB,
_id: eventIdB,
isSomeday: true,
origin: Origin.COMPASS,
priority: Priorities.UNASSIGNED,
Expand All @@ -437,15 +436,15 @@ describe("computeRelativeEventDateRange", () => {
]);
});

it("should fill gaps in order sequence for optimistic events", () => {
const optimisticIdA = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
const optimisticIdB = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
const optimisticIdC = `${ID_OPTIMISTIC_PREFIX}-${new ObjectId().toString()}`;
it("should fill gaps in order sequence for events", () => {
const eventIdA = new ObjectId().toString();
const eventIdB = new ObjectId().toString();
const eventIdC = new ObjectId().toString();
// Add all required properties for Schema_Event
const events = [
{
...baseEvent,
_id: optimisticIdA,
_id: eventIdA,
order: 0,
isSomeday: true,
origin: Origin.COMPASS,
Expand All @@ -454,15 +453,15 @@ describe("computeRelativeEventDateRange", () => {
},
{
...baseEvent,
_id: optimisticIdB,
_id: eventIdB,
isSomeday: true,
origin: Origin.COMPASS,
priority: Priorities.UNASSIGNED,
user: "test-user",
}, // Should get order 1
{
...baseEvent,
_id: optimisticIdC,
_id: eventIdC,
order: 3,
isSomeday: true,
origin: Origin.COMPASS,
Expand Down
Loading