Skip to content

Commit

Permalink
modify updateSingleEvent.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
meetulr committed Feb 22, 2024
1 parent 81a3625 commit dd05c08
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 67 deletions.
9 changes: 8 additions & 1 deletion schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ type Mutation {
updateActionItemCategory(data: UpdateActionItemCategoryInput!, id: ID!): ActionItemCategory
updateAdvertisement(input: UpdateAdvertisementInput!): UpdateAdvertisementPayload
updateAgendaCategory(id: ID!, input: UpdateAgendaCategoryInput!): AgendaCategory
updateEvent(data: UpdateEventInput, id: ID!): Event!
updateEvent(data: UpdateEventInput, id: ID!, recurrenceRuleData: RecurrenceRuleInput, recurringEventUpdateType: RecurringEventUpdateType): Event!
updateEventVolunteer(data: UpdateEventVolunteerInput, id: ID!): EventVolunteer!
updateLanguage(languageCode: String!): User!
updateOrganization(data: UpdateOrganizationInput, file: String, id: ID!): Organization!
Expand Down Expand Up @@ -986,6 +986,12 @@ input RecurrenceRuleInput {
weekDays: [WeekDays]
}

enum RecurringEventUpdateType {
AllInstances
ThisAndFollowingInstances
ThisInstance
}

enum Status {
ACTIVE
BLOCKED
Expand Down Expand Up @@ -1066,6 +1072,7 @@ input UpdateEventInput {
endDate: Date
endTime: Time
isPublic: Boolean
isRecurringEventException: Boolean
isRegisterable: Boolean
latitude: Latitude
location: String
Expand Down
2 changes: 0 additions & 2 deletions src/helpers/event/createEventHelpers/createRecurringEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export const createRecurringEvent = async (
organizationId: string,
session: mongoose.ClientSession,
baseRecurringEventId: string | null = null,
generateAhead: boolean = false,
): Promise<InterfaceEvent> => {
const { data } = args;
let { recurrenceRuleData } = args;
Expand Down Expand Up @@ -78,7 +77,6 @@ export const createRecurringEvent = async (
recurrenceRuleString,
data.startDate,
data.endDate,
generateAhead,
);

// get the date for the latest created instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ export const createRecurringEventInstancesDuringQuery = async (
recurrenceRuleString,
currentRecurrenceStartDate,
recurrenceEndDate,
false,
queryUptoDate,
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addDays, addYears } from "date-fns";
import { addYears } from "date-fns";
import { Frequency, rrulestr } from "rrule";
import type { RRule } from "rrule";
import {
Expand All @@ -25,7 +25,6 @@ export function getRecurringInstanceDates(
recurrenceRuleString: string,
recurrenceStartDate: Date,
eventEndDate: Date | null,
generateAhead: boolean,
queryUptoDate: Date = recurrenceStartDate,
): Date[] {
// get the rrule object
Expand Down Expand Up @@ -67,11 +66,6 @@ export function getRecurringInstanceDates(
Math.min(eventEndDate.getTime(), limitEndDate.getTime()),
);

// generate ahead in case a single event is made recurring to avoid ovarlap
if (generateAhead) {
recurrenceStartDate = addDays(recurrenceStartDate, 1);
}

// get the dates of recurrence
const recurringInstanceDates = recurrenceRuleObject.between(
recurrenceStartDate,
Expand Down
50 changes: 50 additions & 0 deletions src/helpers/event/updateEventHelpers/getEventData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { InterfaceEvent } from "../../../models";
import type {
Recurrance,
UpdateEventInput,
} from "../../../types/generatedGraphQLTypes";
import type { InterfaceRecurringEvent } from "../recurringEventHelpers/generateRecurringEventInstances";

export const getEventData = (
updateEventInputData: UpdateEventInput,
event: InterfaceEvent,
): InterfaceRecurringEvent => {
// get the event's current data
const eventCurrentData = {
title: event.title,
description: event.description,
startDate: event.startDate,
endDate: event.endDate,
startTime: event.startTime,
endTime: event.endTime,
allDay: event.allDay,
recurring: event.recurring,
recurrance: event.recurrance,
isPublic: event.isPublic,
isRegisterable: event.isRegisterable,
admins: event.admins,
location: event.location,
latitude: event.latitude,
longitude: event.longitude,
creatorId: event.creatorId,
organizationId: event.organization,
};

// get the updated event data
const updatedEventData: InterfaceRecurringEvent = {
...eventCurrentData,
recurrance: eventCurrentData.recurrance as Recurrance,
...Object.fromEntries(
Object.entries(updateEventInputData ?? {}).filter(
([value]) => value !== null,
),
),
};

// // if the event is made infinitly recurring (i.e. endDate is null), remove it from the data
// if (!updatedEventData.endDate) {
// delete updatedEventData.endDate;
// }

return updatedEventData;
};
7 changes: 4 additions & 3 deletions src/helpers/event/updateEventHelpers/updateAllInstances.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type mongoose from "mongoose";
import { Event, InterfaceEvent } from "../../../models";
import { MutationUpdateEventArgs } from "../../../types/generatedGraphQLTypes";
import type { InterfaceEvent } from "../../../models";
import { Event } from "../../../models";
import type { MutationUpdateEventArgs } from "../../../types/generatedGraphQLTypes";
import { RecurrenceRule } from "../../../models/RecurrenceRule";

export const updateAllInstances = async (
Expand All @@ -23,7 +24,7 @@ export const updateAllInstances = async (
}

if (
(recurrenceRule.endDate === null && baseRecurringEvent.endDate === null) ||
(!recurrenceRule.endDate && !baseRecurringEvent.endDate) ||
(recurrenceRule.endDate &&
baseRecurringEvent.endDate &&
recurrenceRule.endDate.toString() ===
Expand Down
135 changes: 86 additions & 49 deletions src/helpers/event/updateEventHelpers/updateSingleEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import type mongoose from "mongoose";
import type { InterfaceEvent } from "../../../models";
import { Event } from "../../../models";
import { cacheEvents } from "../../../services/EventCache/cacheEvents";
import type {
EventInput,
MutationCreateEventArgs,
MutationUpdateEventArgs,
Recurrance,
} from "../../../types/generatedGraphQLTypes";
import { createRecurringEvent } from "../createEventHelpers";
import type { MutationUpdateEventArgs } from "../../../types/generatedGraphQLTypes";
import { getEventData } from "./getEventData";
import {
createRecurrenceRule,
generateRecurrenceRuleString,
generateRecurringEventInstances,
getRecurringInstanceDates,
} from "../recurringEventHelpers";
import { addDays } from "date-fns";

/**
* This function generates a single non-recurring event.
Expand All @@ -32,58 +34,93 @@ export const updateSingleEvent = async (
let updatedEvent: InterfaceEvent = event;

if (args.data?.recurring) {
// if the single event is made recurring

// get the current event data
const {
_id: eventId,
recurrance,
creatorId,
organization: organizationId,
...eventData
} = event;

// get the data from the update event input args
const { data: updateEventInputData, recurrenceRuleData } = args;

// get the data based on which the baseRecurringEvent and recurring instances would be generated
// i.e. take the current event data, and the update it based on the update event input
const updatedEventData: EventInput = {
...eventData,
...Object.fromEntries(
Object.entries(updateEventInputData).filter(
([value]) => value !== null,
),
),
recurrance: recurrance as Recurrance,
organizationId,
};

// get the "args" argument for the createRecurringEvent function
const createRecurringEventArgs: MutationCreateEventArgs = {
data: updatedEventData,
// get the data from args
const { data: updateEventInputData } = args;
let { recurrenceRuleData } = args;

// get latest eventData to be used for baseRecurringEvent and recurring instances
const eventData = getEventData(updateEventInputData, event);

if (!recurrenceRuleData) {
// create a default weekly recurrence rule
recurrenceRuleData = {
frequency: "WEEKLY",
};
}

// get the recurrence startDate, if provided, else, use event startDate
const startDateString = eventData.startDate || event.startDate;
const startDate = new Date(startDateString);

// get the recurrence endDate, if provided or made null (infinitely recurring)
// else, use event endDate
const endDateString =
eventData.endDate || eventData.endDate === null
? eventData.endDate
: event.endDate;
const endDate = endDateString ? new Date(endDateString) : null;

// generate a recurrence rule string which would be used to generate rrule object
const recurrenceRuleString = generateRecurrenceRuleString(
recurrenceRuleData,
};
startDate,
endDate ? endDate : undefined,
);

// convert the single event into a recurring event
updatedEvent = await createRecurringEvent(
createRecurringEventArgs,
creatorId,
organizationId,
// create a baseRecurringEvent
const baseRecurringEvent = await Event.create(
[
{
...eventData,
organization: eventData.organizationId,
recurring: true,
isBaseRecurringEvent: true,
},
],
{ session },
);

// get recurrence dates
const recurringInstanceDates = getRecurringInstanceDates(
recurrenceRuleString,
addDays(event.startDate, 1), // generate instances ahead of current event date to avoid overlap
endDate,
);

// get the startDate of the latest instance following the recurrence
const latestInstanceDate =
recurringInstanceDates[recurringInstanceDates.length - 1];

// create the recurrencerule
const recurrenceRule = await createRecurrenceRule(
recurrenceRuleString,
startDate,
endDate,
eventData.organizationId,
baseRecurringEvent[0]._id.toString(),
latestInstanceDate,
session,
null,
true,
);

// add the baseRecurringEventId to the current event to make it a part of the recurrence
// generate the recurring instances and get an instance back
const recurringEventInstance = await generateRecurringEventInstances({
data: eventData,
baseRecurringEventId: baseRecurringEvent[0]._id.toString(),
recurrenceRuleId: recurrenceRule?._id.toString(),
recurringInstanceDates,
creatorId: event.creatorId,
organizationId: eventData.organizationId,
session,
});

// add the baseRecurringEventId to the current event to connect it with recurring instances
await Event.updateOne(
{
_id: eventId,
_id: event._id,
},
{
...(args.data as Partial<InterfaceEvent>),
recurrenceRuleId: updatedEvent.recurrenceRuleId,
baseRecurringEventId: updatedEvent.baseRecurringEventId,
baseRecurringEventId: recurringEventInstance.baseRecurringEventId,
},
{ session },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export const updateThisAndFollowingInstances = async (
// update the baseRecurringEvent if it is the latest recurrence rule that the instances are following
if (
recurrenceRule &&
((recurrenceRule.endDate === null && baseRecurringEvent.endDate === null) ||
((!recurrenceRule.endDate && !baseRecurringEvent.endDate) ||
(recurrenceRule.endDate &&
baseRecurringEvent.endDate &&
recurrenceRule.endDate.toString() ===
Expand Down
4 changes: 1 addition & 3 deletions src/models/Event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,7 @@ const eventSchema = new Schema(
},
endDate: {
type: Date,
required: function (this: InterfaceEvent): boolean {
return !this.allDay;
},
required: false,
},
startTime: {
type: Date,
Expand Down

0 comments on commit dd05c08

Please sign in to comment.