Initial commit: Plane
Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Some checks failed
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Admin Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Sync Repositories / sync_changes (push) Has been cancelled
Synced from upstream: 8853637e981ed7d8a6cff32bd98e7afe20f54362
This commit is contained in:
131
apps/web/core/components/gantt-chart/views/helpers.ts
Normal file
131
apps/web/core/components/gantt-chart/views/helpers.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import type { ChartDataType, IGanttBlock } from "@plane/types";
|
||||
import { addDaysToDate, findTotalDaysInRange, getDate } from "@plane/utils";
|
||||
import { DEFAULT_BLOCK_WIDTH } from "../constants";
|
||||
|
||||
/**
|
||||
* Generates Date by using Day, month and Year
|
||||
* @param day
|
||||
* @param month
|
||||
* @param year
|
||||
* @returns
|
||||
*/
|
||||
export const generateDate = (day: number, month: number, year: number) => new Date(year, month, day);
|
||||
|
||||
/**
|
||||
* Returns number of days in month
|
||||
* @param month
|
||||
* @param year
|
||||
* @returns
|
||||
*/
|
||||
export const getNumberOfDaysInMonth = (month: number, year: number) => {
|
||||
const date = new Date(year, month + 1, 0);
|
||||
|
||||
return date.getDate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns week number from date
|
||||
* @param date
|
||||
* @returns
|
||||
*/
|
||||
export const getWeekNumberByDate = (date: Date) => {
|
||||
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
|
||||
const daysOffset = firstDayOfYear.getDay();
|
||||
|
||||
const firstWeekStart = firstDayOfYear.getTime() - daysOffset * 24 * 60 * 60 * 1000;
|
||||
const weekStart = new Date(firstWeekStart);
|
||||
|
||||
const weekNumber = Math.floor((date.getTime() - weekStart.getTime()) / (7 * 24 * 60 * 60 * 1000)) + 1;
|
||||
|
||||
return weekNumber;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns number of days between two dates
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @returns
|
||||
*/
|
||||
export const getNumberOfDaysBetweenTwoDates = (startDate: Date, endDate: Date) => {
|
||||
let daysDifference: number = 0;
|
||||
startDate.setHours(0, 0, 0, 0);
|
||||
endDate.setHours(0, 0, 0, 0);
|
||||
|
||||
const timeDifference: number = startDate.getTime() - endDate.getTime();
|
||||
daysDifference = Math.round(timeDifference / (1000 * 60 * 60 * 24));
|
||||
|
||||
return daysDifference;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns a date corresponding to the position on the timeline chart
|
||||
* @param position
|
||||
* @param chartData
|
||||
* @param offsetDays
|
||||
* @returns
|
||||
*/
|
||||
export const getDateFromPositionOnGantt = (position: number, chartData: ChartDataType, offsetDays = 0) => {
|
||||
const numberOfDaysSinceStart = Math.round(position / chartData.data.dayWidth) + offsetDays;
|
||||
|
||||
const newDate = addDaysToDate(chartData.data.startDate, numberOfDaysSinceStart);
|
||||
|
||||
if (!newDate) undefined;
|
||||
|
||||
return newDate;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns the position and width of the block on the timeline chart from startDate and EndDate
|
||||
* @param chartData
|
||||
* @param itemData
|
||||
* @returns
|
||||
*/
|
||||
export const getItemPositionWidth = (chartData: ChartDataType, itemData: IGanttBlock) => {
|
||||
let scrollPosition: number = 0;
|
||||
let scrollWidth: number = DEFAULT_BLOCK_WIDTH;
|
||||
|
||||
const { startDate: chartStartDate } = chartData.data;
|
||||
const { start_date, target_date } = itemData;
|
||||
|
||||
const itemStartDate = getDate(start_date);
|
||||
const itemTargetDate = getDate(target_date);
|
||||
|
||||
chartStartDate.setHours(0, 0, 0, 0);
|
||||
itemStartDate?.setHours(0, 0, 0, 0);
|
||||
itemTargetDate?.setHours(0, 0, 0, 0);
|
||||
|
||||
if (!itemStartDate && !itemTargetDate) return;
|
||||
|
||||
// get scroll position from the number of days and width of each day
|
||||
scrollPosition = itemStartDate
|
||||
? getPositionFromDate(chartData, itemStartDate, 0)
|
||||
: getPositionFromDate(chartData, itemTargetDate!, -1 * DEFAULT_BLOCK_WIDTH + chartData.data.dayWidth);
|
||||
|
||||
if (itemStartDate && itemTargetDate) {
|
||||
// get width of block
|
||||
const widthTimeDifference: number = itemStartDate.getTime() - itemTargetDate.getTime();
|
||||
const widthDaysDifference: number = Math.abs(Math.floor(widthTimeDifference / (1000 * 60 * 60 * 24)));
|
||||
scrollWidth = (widthDaysDifference + 1) * chartData.data.dayWidth;
|
||||
}
|
||||
|
||||
return { marginLeft: scrollPosition, width: scrollWidth };
|
||||
};
|
||||
|
||||
export const getPositionFromDate = (chartData: ChartDataType, date: string | Date, offsetWidth: number) => {
|
||||
const currDate = getDate(date);
|
||||
|
||||
const { startDate: chartStartDate } = chartData.data;
|
||||
|
||||
if (!currDate || !chartStartDate) return 0;
|
||||
|
||||
chartStartDate.setHours(0, 0, 0, 0);
|
||||
currDate.setHours(0, 0, 0, 0);
|
||||
|
||||
// get number of days from chart start date to block's start date
|
||||
const positionDaysDifference = Math.round(findTotalDaysInRange(chartStartDate, currDate, false) ?? 0);
|
||||
|
||||
if (!positionDaysDifference) return 0;
|
||||
|
||||
// get scroll position from the number of days and width of each day
|
||||
return positionDaysDifference * chartData.data.dayWidth + offsetWidth;
|
||||
};
|
||||
4
apps/web/core/components/gantt-chart/views/index.ts
Normal file
4
apps/web/core/components/gantt-chart/views/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./week-view";
|
||||
export * from "./month-view";
|
||||
export * from "./quarter-view";
|
||||
export * from "./helpers";
|
||||
171
apps/web/core/components/gantt-chart/views/month-view.ts
Normal file
171
apps/web/core/components/gantt-chart/views/month-view.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { cloneDeep, uniqBy } from "lodash-es";
|
||||
// plane imports
|
||||
import type { ChartDataType } from "@plane/types";
|
||||
// local imports
|
||||
import { months } from "../data";
|
||||
import { getNumberOfDaysBetweenTwoDates, getNumberOfDaysInMonth } from "./helpers";
|
||||
import type { IWeekBlock } from "./week-view";
|
||||
import { getWeeksBetweenTwoDates } from "./week-view";
|
||||
|
||||
export interface IMonthBlock {
|
||||
today: boolean;
|
||||
month: number;
|
||||
days: number;
|
||||
monthData: {
|
||||
key: number;
|
||||
shortTitle: string;
|
||||
title: string;
|
||||
};
|
||||
title: string;
|
||||
year: number;
|
||||
}
|
||||
|
||||
export interface IMonthView {
|
||||
months: IMonthBlock[];
|
||||
weeks: IWeekBlock[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Month Chart data
|
||||
* @param monthPayload
|
||||
* @param side
|
||||
* @returns
|
||||
*/
|
||||
const generateMonthChart = (monthPayload: ChartDataType, side: null | "left" | "right", targetDate?: Date) => {
|
||||
let renderState = cloneDeep(monthPayload);
|
||||
|
||||
const range: number = renderState.data.approxFilterRange || 6;
|
||||
let filteredDates: IMonthView = { months: [], weeks: [] };
|
||||
let minusDate: Date = new Date();
|
||||
let plusDate: Date = new Date();
|
||||
|
||||
let startDate = new Date();
|
||||
let endDate = new Date();
|
||||
|
||||
// if side is null generate months on both side of current date
|
||||
if (side === null) {
|
||||
const currentDate = renderState.data.currentDate;
|
||||
|
||||
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range, currentDate.getDate());
|
||||
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range, currentDate.getDate());
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate);
|
||||
|
||||
startDate = filteredDates.weeks[0]?.startDate;
|
||||
endDate = filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate;
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: {
|
||||
...renderState.data,
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
};
|
||||
}
|
||||
// When side is left, generate more months on the left side of the start date
|
||||
else if (side === "left") {
|
||||
const chartStartDate = renderState.data.startDate;
|
||||
const currentDate = targetDate ? targetDate : chartStartDate;
|
||||
|
||||
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range, 1);
|
||||
plusDate = new Date(chartStartDate.getFullYear(), chartStartDate.getMonth(), chartStartDate.getDate() - 1);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate);
|
||||
|
||||
startDate = filteredDates.weeks[0]?.startDate;
|
||||
endDate = new Date(chartStartDate.getFullYear(), chartStartDate.getMonth(), chartStartDate.getDate() - 1);
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: { ...renderState.data, startDate },
|
||||
};
|
||||
}
|
||||
// When side is right, generate more months on the right side of the end date
|
||||
else if (side === "right") {
|
||||
const chartEndDate = renderState.data.endDate;
|
||||
const currentDate = targetDate ? targetDate : chartEndDate;
|
||||
|
||||
minusDate = new Date(chartEndDate.getFullYear(), chartEndDate.getMonth(), chartEndDate.getDate() + 1);
|
||||
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range, 1);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate);
|
||||
|
||||
startDate = new Date(chartEndDate.getFullYear(), chartEndDate.getMonth(), chartEndDate.getDate() + 1);
|
||||
endDate = filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate;
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: { ...renderState.data, endDate: filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate },
|
||||
};
|
||||
}
|
||||
|
||||
const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate)) + 1;
|
||||
const scrollWidth = days * monthPayload.data.dayWidth;
|
||||
|
||||
return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth };
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Month View data between two dates, i.e., Months and Weeks between two dates
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @returns
|
||||
*/
|
||||
const getMonthsViewBetweenTwoDates = (startDate: Date, endDate: Date): IMonthView => ({
|
||||
months: getMonthsBetweenTwoDates(startDate, endDate),
|
||||
weeks: getWeeksBetweenTwoDates(startDate, endDate, false),
|
||||
});
|
||||
|
||||
/**
|
||||
* generate array of months between two dates
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @returns
|
||||
*/
|
||||
export const getMonthsBetweenTwoDates = (startDate: Date, endDate: Date): IMonthBlock[] => {
|
||||
const monthBlocks = [];
|
||||
|
||||
const startYear = startDate.getFullYear();
|
||||
const startMonth = startDate.getMonth();
|
||||
|
||||
const today = new Date();
|
||||
const todayMonth = today.getMonth();
|
||||
const todayYear = today.getFullYear();
|
||||
|
||||
const currentDate = new Date(startYear, startMonth);
|
||||
|
||||
while (currentDate <= endDate) {
|
||||
const currentYear = currentDate.getFullYear();
|
||||
const currentMonth = currentDate.getMonth();
|
||||
|
||||
monthBlocks.push({
|
||||
year: currentYear,
|
||||
month: currentMonth,
|
||||
monthData: months[currentMonth],
|
||||
title: `${months[currentMonth].title} ${currentYear}`,
|
||||
days: getNumberOfDaysInMonth(currentMonth, currentYear),
|
||||
today: todayMonth === currentMonth && todayYear === currentYear,
|
||||
});
|
||||
|
||||
currentDate.setMonth(currentDate.getMonth() + 1);
|
||||
}
|
||||
|
||||
return monthBlocks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge two MonthView data payloads
|
||||
* @param a
|
||||
* @param b
|
||||
* @returns
|
||||
*/
|
||||
const mergeMonthRenderPayloads = (a: IMonthView, b: IMonthView): IMonthView => ({
|
||||
months: uniqBy([...a.months, ...b.months], (monthBlock) => `${monthBlock.month}_${monthBlock.year}`),
|
||||
weeks: uniqBy(
|
||||
[...a.weeks, ...b.weeks],
|
||||
(weekBlock) => `${weekBlock.startDate.getTime()}_${weekBlock.endDate.getTime()}`
|
||||
),
|
||||
});
|
||||
|
||||
export const monthView = {
|
||||
generateChart: generateMonthChart,
|
||||
mergeRenderPayloads: mergeMonthRenderPayloads,
|
||||
};
|
||||
148
apps/web/core/components/gantt-chart/views/quarter-view.ts
Normal file
148
apps/web/core/components/gantt-chart/views/quarter-view.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
import type { ChartDataType } from "@plane/types";
|
||||
import { quarters } from "../data";
|
||||
import { getNumberOfDaysBetweenTwoDates } from "./helpers";
|
||||
import type { IMonthBlock } from "./month-view";
|
||||
import { getMonthsBetweenTwoDates } from "./month-view";
|
||||
|
||||
export interface IQuarterMonthBlock {
|
||||
children: IMonthBlock[];
|
||||
quarterNumber: number;
|
||||
shortTitle: string;
|
||||
title: string;
|
||||
year: number;
|
||||
today: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Quarter Chart data, which in turn are months in an array
|
||||
* @param quarterPayload
|
||||
* @param side
|
||||
* @returns
|
||||
*/
|
||||
const generateQuarterChart = (quarterPayload: ChartDataType, side: null | "left" | "right", targetDate?: Date) => {
|
||||
let renderState = quarterPayload;
|
||||
|
||||
const range: number = renderState.data.approxFilterRange || 12;
|
||||
let filteredDates: IMonthBlock[] = [];
|
||||
let minusDate: Date = new Date();
|
||||
let plusDate: Date = new Date();
|
||||
|
||||
let startDate = new Date();
|
||||
let endDate = new Date();
|
||||
|
||||
// if side is null generate months on both side of current date
|
||||
if (side === null) {
|
||||
const currentDate = renderState.data.currentDate;
|
||||
|
||||
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range, 1);
|
||||
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range, 0);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate);
|
||||
|
||||
const startMonthBlock = filteredDates[0];
|
||||
const endMonthBlock = filteredDates[filteredDates.length - 1];
|
||||
startDate = new Date(startMonthBlock.year, startMonthBlock.month, 1);
|
||||
endDate = new Date(endMonthBlock.year, endMonthBlock.month + 1, 0);
|
||||
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: {
|
||||
...renderState.data,
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
};
|
||||
}
|
||||
// When side is left, generate more months on the left side of the start date
|
||||
else if (side === "left") {
|
||||
const chartStartDate = renderState.data.startDate;
|
||||
const currentDate = targetDate ? targetDate : chartStartDate;
|
||||
|
||||
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range / 2, 1);
|
||||
plusDate = new Date(chartStartDate.getFullYear(), chartStartDate.getMonth() - 1, 1);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate);
|
||||
|
||||
const startMonthBlock = filteredDates[0];
|
||||
startDate = new Date(startMonthBlock.year, startMonthBlock.month, 1);
|
||||
endDate = new Date(chartStartDate.getFullYear(), chartStartDate.getMonth(), chartStartDate.getDate() - 1);
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: { ...renderState.data, startDate },
|
||||
};
|
||||
}
|
||||
// When side is right, generate more months on the right side of the end date
|
||||
else if (side === "right") {
|
||||
const chartEndDate = renderState.data.endDate;
|
||||
const currentDate = targetDate ? targetDate : chartEndDate;
|
||||
|
||||
minusDate = new Date(chartEndDate.getFullYear(), chartEndDate.getMonth() + 1, 1);
|
||||
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range / 2, 1);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate);
|
||||
|
||||
const endMonthBlock = filteredDates[filteredDates.length - 1];
|
||||
startDate = new Date(chartEndDate.getFullYear(), chartEndDate.getMonth(), chartEndDate.getDate() + 1);
|
||||
endDate = new Date(endMonthBlock.year, endMonthBlock.month + 1, 0);
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: { ...renderState.data, endDate },
|
||||
};
|
||||
}
|
||||
|
||||
const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate)) + 1;
|
||||
const scrollWidth = days * quarterPayload.data.dayWidth;
|
||||
|
||||
return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth };
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge two Quarter data payloads
|
||||
* @param a
|
||||
* @param b
|
||||
* @returns
|
||||
*/
|
||||
const mergeQuarterRenderPayloads = (a: IMonthBlock[], b: IMonthBlock[]) => [...a, ...b];
|
||||
|
||||
/**
|
||||
* Group array of Months into Quarters, returns an array og Quarters and it's children Months
|
||||
* @param monthBlocks
|
||||
* @returns
|
||||
*/
|
||||
export const groupMonthsToQuarters = (monthBlocks: IMonthBlock[]): IQuarterMonthBlock[] => {
|
||||
const quartersMap: { [key: string]: IQuarterMonthBlock } = {};
|
||||
|
||||
const today = new Date();
|
||||
const todayQuarterNumber = Math.floor(today.getMonth() / 3);
|
||||
const todayYear = today.getFullYear();
|
||||
|
||||
for (const monthBlock of monthBlocks) {
|
||||
const { month, year } = monthBlock;
|
||||
|
||||
const quarterNumber = Math.floor(month / 3);
|
||||
|
||||
const quarterKey = `Q${quarterNumber}-${year}`;
|
||||
|
||||
if (quartersMap[quarterKey]) {
|
||||
quartersMap[quarterKey].children.push(monthBlock);
|
||||
} else {
|
||||
const quarterData = quarters[quarterNumber];
|
||||
quartersMap[quarterKey] = {
|
||||
children: [monthBlock],
|
||||
quarterNumber,
|
||||
shortTitle: quarterData.shortTitle,
|
||||
title: `${quarterData.title} ${year}`,
|
||||
year,
|
||||
today: todayQuarterNumber === quarterNumber && todayYear === year,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(quartersMap);
|
||||
};
|
||||
|
||||
export const quarterView = {
|
||||
generateChart: generateQuarterChart,
|
||||
mergeRenderPayloads: mergeQuarterRenderPayloads,
|
||||
};
|
||||
214
apps/web/core/components/gantt-chart/views/week-view.ts
Normal file
214
apps/web/core/components/gantt-chart/views/week-view.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
//
|
||||
import type { ChartDataType } from "@plane/types";
|
||||
import { EStartOfTheWeek } from "@plane/types";
|
||||
import { months, generateWeeks } from "../data";
|
||||
import { getNumberOfDaysBetweenTwoDates, getWeekNumberByDate } from "./helpers";
|
||||
export interface IDayBlock {
|
||||
date: Date;
|
||||
day: number;
|
||||
dayData: {
|
||||
key: number;
|
||||
shortTitle: string;
|
||||
title: string;
|
||||
abbreviation: string;
|
||||
};
|
||||
title: string;
|
||||
today: boolean;
|
||||
}
|
||||
|
||||
export interface IWeekBlock {
|
||||
children?: IDayBlock[];
|
||||
weekNumber: number;
|
||||
weekData: {
|
||||
shortTitle: string;
|
||||
title: string;
|
||||
};
|
||||
title: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
startMonth: number;
|
||||
startYear: number;
|
||||
endMonth: number;
|
||||
endYear: number;
|
||||
today: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Week Chart data
|
||||
* @param weekPayload
|
||||
* @param side
|
||||
* @returns
|
||||
*/
|
||||
const generateWeekChart = (
|
||||
weekPayload: ChartDataType,
|
||||
side: null | "left" | "right",
|
||||
targetDate?: Date,
|
||||
startOfWeek: EStartOfTheWeek = EStartOfTheWeek.SUNDAY
|
||||
) => {
|
||||
let renderState = weekPayload;
|
||||
|
||||
const range: number = renderState.data.approxFilterRange || 6;
|
||||
let filteredDates: IWeekBlock[] = [];
|
||||
let minusDate: Date = new Date();
|
||||
let plusDate: Date = new Date();
|
||||
|
||||
let startDate = new Date();
|
||||
let endDate = new Date();
|
||||
|
||||
// if side is null generate weeks on both side of current date
|
||||
if (side === null) {
|
||||
const currentDate = renderState.data.currentDate;
|
||||
|
||||
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range, currentDate.getDate());
|
||||
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range, currentDate.getDate());
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate, true, startOfWeek);
|
||||
|
||||
startDate = filteredDates[0].startDate;
|
||||
endDate = filteredDates[filteredDates.length - 1].endDate;
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: {
|
||||
...renderState.data,
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
};
|
||||
}
|
||||
// When side is left, generate more weeks on the left side of the start date
|
||||
else if (side === "left") {
|
||||
const chartStartDate = renderState.data.startDate;
|
||||
const currentDate = targetDate ? targetDate : chartStartDate;
|
||||
|
||||
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range, 1);
|
||||
plusDate = new Date(chartStartDate.getFullYear(), chartStartDate.getMonth(), chartStartDate.getDate() - 1);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate, true, startOfWeek);
|
||||
|
||||
startDate = filteredDates[0].startDate;
|
||||
endDate = new Date(chartStartDate.getFullYear(), chartStartDate.getMonth(), chartStartDate.getDate() - 1);
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: { ...renderState.data, startDate },
|
||||
};
|
||||
}
|
||||
// When side is right, generate more weeks on the right side of the end date
|
||||
else if (side === "right") {
|
||||
const chartEndDate = renderState.data.endDate;
|
||||
const currentDate = targetDate ? targetDate : chartEndDate;
|
||||
|
||||
minusDate = new Date(chartEndDate.getFullYear(), chartEndDate.getMonth(), chartEndDate.getDate() + 1);
|
||||
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range, 1);
|
||||
|
||||
if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate, true, startOfWeek);
|
||||
|
||||
startDate = new Date(chartEndDate.getFullYear(), chartEndDate.getMonth(), chartEndDate.getDate() + 1);
|
||||
endDate = filteredDates[filteredDates.length - 1].endDate;
|
||||
renderState = {
|
||||
...renderState,
|
||||
data: { ...renderState.data, endDate },
|
||||
};
|
||||
}
|
||||
|
||||
const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate)) + 1;
|
||||
const scrollWidth = days * weekPayload.data.dayWidth;
|
||||
|
||||
return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth };
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate weeks array between two dates
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @param shouldPopulateDaysForWeek
|
||||
* @returns
|
||||
*/
|
||||
export const getWeeksBetweenTwoDates = (
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
shouldPopulateDaysForWeek: boolean = true,
|
||||
startOfWeek: EStartOfTheWeek = EStartOfTheWeek.SUNDAY
|
||||
): IWeekBlock[] => {
|
||||
const weeks: IWeekBlock[] = [];
|
||||
|
||||
const currentDate = new Date(startDate.getTime());
|
||||
const today = new Date();
|
||||
|
||||
// Adjust the current date to the start of the week
|
||||
const day = currentDate.getDay();
|
||||
const diff = (day + 7 - startOfWeek) % 7; // Calculate days to subtract to get to startOfWeek
|
||||
currentDate.setDate(currentDate.getDate() - diff);
|
||||
|
||||
while (currentDate <= endDate) {
|
||||
const weekStartDate = new Date(currentDate.getTime());
|
||||
const weekEndDate = new Date(currentDate.getTime() + 6 * 24 * 60 * 60 * 1000);
|
||||
|
||||
const monthAtStartOfTheWeek = weekStartDate.getMonth();
|
||||
const yearAtStartOfTheWeek = weekStartDate.getFullYear();
|
||||
const monthAtEndOfTheWeek = weekEndDate.getMonth();
|
||||
const yearAtEndOfTheWeek = weekEndDate.getFullYear();
|
||||
|
||||
const weekNumber = getWeekNumberByDate(currentDate);
|
||||
|
||||
weeks.push({
|
||||
children: shouldPopulateDaysForWeek ? populateDaysForWeek(weekStartDate, startOfWeek) : undefined,
|
||||
weekNumber,
|
||||
weekData: {
|
||||
shortTitle: `w${weekNumber}`,
|
||||
title: `Week ${weekNumber}`,
|
||||
},
|
||||
title:
|
||||
monthAtStartOfTheWeek === monthAtEndOfTheWeek
|
||||
? `${months[monthAtStartOfTheWeek].abbreviation} ${yearAtStartOfTheWeek}`
|
||||
: `${months[monthAtStartOfTheWeek].abbreviation} ${yearAtStartOfTheWeek} - ${months[monthAtEndOfTheWeek].abbreviation} ${yearAtEndOfTheWeek}`,
|
||||
startMonth: monthAtStartOfTheWeek,
|
||||
startYear: yearAtStartOfTheWeek,
|
||||
endMonth: monthAtEndOfTheWeek,
|
||||
endYear: yearAtEndOfTheWeek,
|
||||
startDate: weekStartDate,
|
||||
endDate: weekEndDate,
|
||||
today: today >= weekStartDate && today <= weekEndDate ? true : false,
|
||||
});
|
||||
|
||||
currentDate.setDate(currentDate.getDate() + 7);
|
||||
}
|
||||
|
||||
return weeks;
|
||||
};
|
||||
|
||||
/**
|
||||
* return back array of 7 days from the date provided
|
||||
* @param startDate
|
||||
* @returns
|
||||
*/
|
||||
const populateDaysForWeek = (startDate: Date, startOfWeek: EStartOfTheWeek = EStartOfTheWeek.SUNDAY): IDayBlock[] => {
|
||||
const currentDate = new Date(startDate);
|
||||
const days: IDayBlock[] = [];
|
||||
const today = new Date();
|
||||
const weekDays = generateWeeks(startOfWeek);
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
days.push({
|
||||
date: new Date(currentDate),
|
||||
day: currentDate.getDay(),
|
||||
dayData: weekDays[i],
|
||||
title: `${weekDays[i].abbreviation} ${currentDate.getDate()}`,
|
||||
today: today.setHours(0, 0, 0, 0) == currentDate.setHours(0, 0, 0, 0),
|
||||
});
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
return days;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge two Week data payloads
|
||||
* @param a
|
||||
* @param b
|
||||
* @returns
|
||||
*/
|
||||
const mergeWeekRenderPayloads = (a: IWeekBlock[], b: IWeekBlock[]) => [...a, ...b];
|
||||
|
||||
export const weekView = {
|
||||
generateChart: generateWeekChart,
|
||||
mergeRenderPayloads: mergeWeekRenderPayloads,
|
||||
};
|
||||
Reference in New Issue
Block a user