Skip to content

Commit

Permalink
feat: opti event group-by algo (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaiJi authored Dec 31, 2023
1 parent 904501f commit 27b6873
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 102 deletions.
110 changes: 8 additions & 102 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,112 +6,18 @@ import { useMemo, useState } from "react";
import { EventScale, EventStatus } from "@/types/event";
import { Switch } from "@headlessui/react";
import { sendTrack } from "@/utils/track";

enum DurationType {
Passed = "passed", //already done.
Now = "now", // in the duration of event.
Soon = "soon", // in the same month of event start date.
Next = "next", // not start yet but plan in this year.
NextYear = "nextYear", // in the next year
}
import { DurationType } from "@/types/list";
import { filteringEvents, groupByCustomDurationEvent } from "@/utils/event";

export default function Home(props: { events: Event[] }) {
const [selectedFilter, setFilter] = useState({
onlyAvailable: false,
eventScale: ["All"],
});
const filteredEvents = props.events.filter((event) => {
const now = Date.now();
const endTime = event.endDate
? new Date(new Date(event.endDate).setHours(23, 59, 59, 999)).getTime()
: null;
if (selectedFilter.onlyAvailable) {
if (event.status === EventStatus.EventCancelled) {
return false;
}
if (endTime && now > endTime) {
return false;
}
}

if (
selectedFilter.eventScale[0] !== "All" &&
!selectedFilter.eventScale.includes(event.scale)
) {
return false;
}
return true;
});
const groupByCustomDurationEvent = useMemo(() => {
const currentMonth = new Date().getUTCMonth() + 1;
const now = Date.now();

const durationObject: { [x in DurationType]: Event[] } = {
now: [],
soon: [],
next: [],
nextYear: [],
passed: [],
};

filteredEvents.forEach((event) => {
const startTime = event.startDate
? new Date(new Date(event.startDate).setHours(0, 0, 0, 0)).getTime()
: null;
const endTime = event.endDate
? new Date(new Date(event.endDate).setHours(23, 59, 59, 999)).getTime()
: null;

// if a event end date is next year, then count it in next year not in current year.
const isNextYear =
event.startDate && event.endDate
? new Date(event.startDate).getUTCFullYear() >
new Date().getUTCFullYear() ||
new Date(event.endDate).getUTCFullYear() >
new Date().getUTCFullYear()
: false;

const startMonth = event.startDate
? new Date(event.startDate).getUTCMonth() + 1 + (isNextYear ? 12 : 0)
: null;
const endMonth = event.endDate
? new Date(event.endDate).getUTCMonth() + 1 + (isNextYear ? 12 : 0)
: null;

if (
startTime === null ||
endTime === null ||
startMonth === null ||
endMonth === null
) {
return durationObject.next.push(event);
}
//Passed events
if (now > endTime) {
return durationObject.passed.push(event);
}

if (startMonth <= currentMonth) {
//Now events
if (now > startTime && now < endTime) {
return durationObject.now.push(event);
} else {
//Soon events
return durationObject.soon.push(event);
}
}

//Next events
if (startMonth > currentMonth) {
if (startMonth > 12) {
return durationObject.nextYear.push(event);
}
return durationObject.next.push(event);
}
});

return durationObject;
}, [filteredEvents]);
const filteredEvents = filteringEvents(props.events, selectedFilter);
const groupByCustomDurationEvents =
groupByCustomDurationEvent(filteredEvents);

return (
<>
Expand All @@ -131,12 +37,12 @@ export default function Home(props: { events: Event[] }) {
</p>
</div>
)}
{Object.keys(groupByCustomDurationEvent).map((type) =>
groupByCustomDurationEvent[type as DurationType].length ? (
{Object.keys(groupByCustomDurationEvents).map((type) =>
groupByCustomDurationEvents[type as DurationType].length ? (
<DurationSection
key={type}
durationType={type}
events={groupByCustomDurationEvent[type as DurationType]}
events={groupByCustomDurationEvents[type as DurationType]}
/>
) : null
)}
Expand Down
14 changes: 14 additions & 0 deletions src/types/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { EventScale } from "./event";

export enum DurationType {
Passed = "passed", //already done.
Now = "now", // in the duration of event.
Soon = "soon", // in the same month of event start date.
Next = "next", // not start yet but plan in this year.
NextYear = "nextYear", // in the next year
}

export type SelectedFilterType = {
onlyAvailable: boolean;
eventScale: (typeof EventScale)[keyof typeof EventScale][];
};
113 changes: 113 additions & 0 deletions src/utils/event.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { EventStatus } from "@/types/event";
import { DurationType, SelectedFilterType } from "@/types/list";
import { Event } from "@/xata/xata";
import groupBy from "lodash-es/groupBy";
import {
isBefore,
isAfter,
endOfDay,
startOfDay,
endOfToday,
startOfToday,
} from "date-fns";

export function sortByStartDateDesc(data: Event[]) {
const groupByStartDate = groupBy(data, (e) =>
Expand All @@ -21,3 +31,106 @@ export function sortByStartDateDesc(data: Event[]) {

return years.map((year) => ({ year, events: groupByStartDate[year] }));
}

export function filteringEvents(
events: Event[],
selectedFilter: SelectedFilterType
) {
return events.filter((event) => {
const now = Date.now();
const endTime = event.endDate
? new Date(new Date(event.endDate).setHours(23, 59, 59, 999)).getTime()
: null;
if (selectedFilter.onlyAvailable) {
// for now, if event is cancelled, the data willn't include it at all.
// if (event.status === EventStatus.EventCancelled) {
// return false;
// }
if (endTime && now > endTime) {
return false;
}
}

if (
selectedFilter.eventScale[0] !== "All" &&
!selectedFilter.eventScale.includes(event.scale)
) {
return false;
}
return true;
});
}

function isDateBelongNextYear(testDate: string) {
return new Date(testDate).getUTCFullYear() > new Date().getUTCFullYear();
}

function getDateMonth(testDate: string) {
const isNextYear = isDateBelongNextYear(testDate);
const dateBelongMonth = new Date(testDate).getUTCMonth() + 1;
return isNextYear ? dateBelongMonth + 12 : dateBelongMonth;
}

export function groupByCustomDurationEvent(events: Event[]) {
const currentMonth = new Date().getUTCMonth() + 1;
const now = Date.now();

const durationObject: { [x in DurationType]: Event[] } = {
now: [],
soon: [],
next: [],
nextYear: [],
passed: [],
};

events.forEach((event) => {
const startTime = event.startDate
? new Date(new Date(event.startDate).setHours(0, 0, 0, 0)).getTime()
: null;
const endTime = event.endDate
? new Date(new Date(event.endDate).setHours(23, 59, 59, 999)).getTime()
: null;

const startMonth = event.startDate
? getDateMonth(event.startDate.toString())
: null;
const endMonth = event.endDate
? getDateMonth(event.endDate.toString())
: null;

//next events
if (
startTime === null ||
endTime === null ||
startMonth === null ||
endMonth === null
) {
return durationObject.next.push(event);
}

//Passed events
if (isAfter(now, endTime)) {
return durationObject.passed.push(event);
}

//Now events
if (isAfter(now, startTime) && isBefore(now, endTime)) {
return durationObject.now.push(event);
}

//Soon events
if (startMonth === currentMonth && isBefore(now, startTime)) {
return durationObject.soon.push(event);
}

//Next events
if (startMonth > currentMonth) {
if (startMonth > 12) {
return durationObject.nextYear.push(event);
}
return durationObject.next.push(event);
}
});

return durationObject;
}

0 comments on commit 27b6873

Please sign in to comment.