From 32db96c9ad74f44b748ad260fa7a203b304b0772 Mon Sep 17 00:00:00 2001 From: Franco Speziali Date: Wed, 16 Mar 2022 08:55:00 +0100 Subject: [PATCH] Added grouping logic --- src/EventGrouping/index.test.ts | 59 +++++++++++++++++ src/EventGrouping/index.ts | 112 ++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 src/EventGrouping/index.test.ts create mode 100644 src/EventGrouping/index.ts diff --git a/src/EventGrouping/index.test.ts b/src/EventGrouping/index.test.ts new file mode 100644 index 0000000..7399ff5 --- /dev/null +++ b/src/EventGrouping/index.test.ts @@ -0,0 +1,59 @@ +const EventGrouping = require("./index").default; +const { Scale } = require("../types"); + +const mockSortedEvents = [ + { + date: new Date(2022, 3, 20), + title: "first day of spring", + }, + { + date: new Date(2022, 3, 25), + title: "my birthday", + }, + { + date: new Date(2022, 3, 25), + title: "buy cake for 27th", + }, + { + date: new Date(2022, 3, 27), + title: "d's birthday", + }, +]; + +console.log(EventGrouping); + +describe("groupEventsByDay should", () => { + const eventGrouping = new EventGrouping(mockSortedEvents, Scale.Day); + + test("generate the correct number of groups", () => { + expect(eventGrouping.groups.length).toEqual(8); + }); + + test("place into the same group, events that occur on the same day", () => { + expect(eventGrouping.groups[5].length).toEqual(2); + }); +}); + +describe("groupEventsByWeek should", () => { + const eventGrouping = new EventGrouping(mockSortedEvents, Scale.Week); + + test("generate the correct number of groups", () => { + expect(eventGrouping.groups.length).toEqual(2); + }); + + test("place into the same group, events that occur on the same week", () => { + expect(eventGrouping.groups[1].length).toEqual(3); + }); +}); + +describe("groupEventsByMonth should", () => { + const eventGrouping = new EventGrouping(mockSortedEvents, Scale.Month); + + test("generate the correct number of groups", () => { + expect(eventGrouping.groups.length).toEqual(1); + }); + + test("place into the same group, events that occur on the same month", () => { + expect(eventGrouping.groups[0].length).toEqual(4); + }); +}); diff --git a/src/EventGrouping/index.ts b/src/EventGrouping/index.ts new file mode 100644 index 0000000..0d53144 --- /dev/null +++ b/src/EventGrouping/index.ts @@ -0,0 +1,112 @@ +import { + add, + differenceInCalendarDays, + differenceInCalendarWeeks, + differenceInCalendarMonths, +} from "date-fns"; + +import { Event, Groups, Scale } from "../types"; + +export default class EventGrouping { + private readonly sortedEvents: Event[]; + private readonly firstEvent: Event; + private readonly lastEvent: Event; + public readonly scale: Scale; + public readonly groups: Groups; + + public static generateEmptyGroups(length: number): Groups { + const groups = []; + + for (let i = 0; i <= length; i += 1) { + groups.push([]); + } + + return groups; + } + + constructor(sortedEvents: Event[], scale: Scale) { + this.sortedEvents = sortedEvents; + this.firstEvent = this.sortedEvents[0]; + this.lastEvent = this.sortedEvents[this.sortedEvents.length - 1]; + this.scale = scale; + this.groups = this.group(scale); + } + + private group(scale: Scale): Groups { + switch (scale) { + case Scale.Day: + return this.byDay(); + case Scale.Week: + return this.byWeek(); + case Scale.Month: + return this.byMonth(); + } + } + + private byDay(): Groups { + const numberOfGroups = differenceInCalendarDays( + this.lastEvent.date, + this.firstEvent.date + ); + + return this.sortedEvents.reduce((prev, event) => { + const groupNumber = differenceInCalendarDays( + event.date, + this.firstEvent.date + ); + + prev[groupNumber].push(event); + + return prev; + }, EventGrouping.generateEmptyGroups(numberOfGroups)); + } + + private byWeek(): Groups { + const numberOfGroups = differenceInCalendarWeeks( + this.lastEvent.date, + this.firstEvent.date + ); + + return this.sortedEvents.reduce((prev, event) => { + const groupNumber = differenceInCalendarWeeks( + event.date, + this.firstEvent.date + ); + + prev[groupNumber].push(event); + + return prev; + }, EventGrouping.generateEmptyGroups(numberOfGroups)); + } + + private byMonth(): Groups { + const numberOfGroups = differenceInCalendarMonths( + this.lastEvent.date, + this.firstEvent.date + ); + + return this.sortedEvents.reduce((prev, event) => { + const groupNumber = differenceInCalendarMonths( + event.date, + this.firstEvent.date + ); + + prev[groupNumber].push(event); + + return prev; + }, EventGrouping.generateEmptyGroups(numberOfGroups)); + } + + public getDateFromGroupIndex(index: number): Date { + const startDate = this.firstEvent.date; + + switch (this.scale) { + case Scale.Day: + return add(startDate, { days: index }); + case Scale.Week: + return add(startDate, { weeks: index }); + case Scale.Month: + return add(startDate, { months: index }); + } + } +}