Skip to content

Commit

Permalink
Merge pull request Expensify#31641 from barros001/calendar-fix
Browse files Browse the repository at this point in the history
fix: align days and week days on calendar
  • Loading branch information
MonilBhavsar authored Dec 28, 2023
2 parents 376bb95 + 5fb6e98 commit 573f6b7
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,7 @@ const CONST = {
MAX_PENDING_TIME_MS: 10 * 1000,
MAX_REQUEST_RETRIES: 10,
},
WEEK_STARTS_ON: 1, // Monday
DEFAULT_TIME_ZONE: {automatic: true, selected: 'America/Los_Angeles'},
DEFAULT_ACCOUNT_DATA: {errors: null, success: '', isLoading: false},
DEFAULT_CLOSE_ACCOUNT_DATA: {errors: null, success: '', isLoading: false},
Expand Down
17 changes: 11 additions & 6 deletions src/components/DatePicker/CalendarPicker/generateMonthMatrix.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {addDays, format, getDay, getDaysInMonth, startOfMonth} from 'date-fns';
import DateUtils from '@libs/DateUtils';

/**
* Generates a matrix representation of a month's calendar given the year and month.
Expand All @@ -24,6 +25,9 @@ export default function generateMonthMatrix(year, month) {
throw new Error('Month cannot be greater than 11');
}

// Get the week day for the end of week
const weekEndsOn = DateUtils.getWeekEndsOn();

// Get the number of days in the month and the first day of the month
const firstDayOfMonth = startOfMonth(new Date(year, month, 1));
const daysInMonth = getDaysInMonth(firstDayOfMonth);
Expand All @@ -32,18 +36,13 @@ export default function generateMonthMatrix(year, month) {
const matrix = [];
let currentWeek = [];

// Add null values for days before the first day of the month
for (let i = 0; i < getDay(firstDayOfMonth); i++) {
currentWeek.push(null);
}

// Add calendar days to the matrix
for (let i = 1; i <= daysInMonth; i++) {
const currentDate = addDays(firstDayOfMonth, i - 1);
currentWeek.push(Number(format(currentDate, 'd')));

// Start a new row when the current week is full
if (getDay(currentDate) === 6) {
if (getDay(currentDate) === weekEndsOn) {
matrix.push(currentWeek);
currentWeek = [];
}
Expand All @@ -56,5 +55,11 @@ export default function generateMonthMatrix(year, month) {
}
matrix.push(currentWeek);
}

// Add null values for days before the first day of the month
for (let i = matrix[0].length; i < 7; i++) {
matrix[0].unshift(null);
}

return matrix;
}
29 changes: 25 additions & 4 deletions src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import Log from './Log';
type CustomStatusTypes = (typeof CONST.CUSTOM_STATUS_TYPES)[keyof typeof CONST.CUSTOM_STATUS_TYPES];
type TimePeriod = 'AM' | 'PM';
type Locale = ValueOf<typeof CONST.LOCALES>;
type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6;

let currentUserAccountID: number | undefined;
Onyx.connect({
Expand Down Expand Up @@ -69,6 +70,22 @@ Onyx.connect({
},
});

/**
* Get the day of the week that the week starts on
*/
function getWeekStartsOn(): WeekDay {
return CONST.WEEK_STARTS_ON;
}

/**
* Get the day of the week that the week ends on
*/
function getWeekEndsOn(): WeekDay {
const weekStartsOn = getWeekStartsOn();

return weekStartsOn === 0 ? 6 : ((weekStartsOn - 1) as WeekDay);
}

/**
* Gets the locale string and setting default locale for date-fns
*/
Expand Down Expand Up @@ -163,9 +180,10 @@ function datetimeToCalendarTime(locale: Locale, datetime: string, includeTimeZon
let tomorrowAt = Localize.translate(locale, 'common.tomorrowAt');
let yesterdayAt = Localize.translate(locale, 'common.yesterdayAt');
const at = Localize.translate(locale, 'common.conjunctionAt');
const weekStartsOn = getWeekStartsOn();

const startOfCurrentWeek = startOfWeek(new Date(), {weekStartsOn: 1}); // Assuming Monday is the start of the week
const endOfCurrentWeek = endOfWeek(new Date(), {weekStartsOn: 1}); // Assuming Monday is the start of the week
const startOfCurrentWeek = startOfWeek(new Date(), {weekStartsOn});
const endOfCurrentWeek = endOfWeek(new Date(), {weekStartsOn});

if (isLowercase) {
todayAt = todayAt.toLowerCase();
Expand Down Expand Up @@ -302,8 +320,9 @@ function getDaysOfWeek(preferredLocale: Locale): string[] {
if (preferredLocale) {
setLocale(preferredLocale);
}
const startOfCurrentWeek = startOfWeek(new Date(), {weekStartsOn: 1}); // Assuming Monday is the start of the week
const endOfCurrentWeek = endOfWeek(new Date(), {weekStartsOn: 1}); // Assuming Monday is the start of the week
const weekStartsOn = getWeekStartsOn();
const startOfCurrentWeek = startOfWeek(new Date(), {weekStartsOn});
const endOfCurrentWeek = endOfWeek(new Date(), {weekStartsOn});
const daysOfWeek = eachDayOfInterval({start: startOfCurrentWeek, end: endOfCurrentWeek});

// eslint-disable-next-line rulesdir/prefer-underscore-method
Expand Down Expand Up @@ -717,6 +736,8 @@ const DateUtils = {
getMonthNames,
getDaysOfWeek,
formatWithUTCTimeZone,
getWeekStartsOn,
getWeekEndsOn,
isTimeAtLeastOneMinuteInFuture,
};

Expand Down
99 changes: 72 additions & 27 deletions tests/unit/generateMonthMatrixTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,114 @@ import generateMonthMatrix from '../../src/components/DatePicker/CalendarPicker/
describe('generateMonthMatrix', () => {
it('returns the correct matrix for January 2022', () => {
const expected = [
[null, null, null, null, null, null, 1],
[2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22],
[23, 24, 25, 26, 27, 28, 29],
[30, 31, null, null, null, null, null],
[null, null, null, null, null, 1, 2],
[3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30],
[31, null, null, null, null, null, null],
];
expect(generateMonthMatrix(2022, 0)).toEqual(expected);
});

it('returns the correct matrix for February 2022', () => {
const expected = [
[null, null, 1, 2, 3, 4, 5],
[6, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26],
[27, 28, null, null, null, null, null],
[null, 1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12, 13],
[14, 15, 16, 17, 18, 19, 20],
[21, 22, 23, 24, 25, 26, 27],
[28, null, null, null, null, null, null],
];
expect(generateMonthMatrix(2022, 1)).toEqual(expected);
});

it('returns the correct matrix for leap year February 2020', () => {
const expected = [
[null, null, null, null, null, null, 1],
[2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22],
[23, 24, 25, 26, 27, 28, 29],
[null, null, null, null, null, 1, 2],
[3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, null],
];
expect(generateMonthMatrix(2020, 1)).toEqual(expected);
});

it('returns the correct matrix for March 2022', () => {
const expected = [
[null, 1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12, 13],
[14, 15, 16, 17, 18, 19, 20],
[21, 22, 23, 24, 25, 26, 27],
[28, 29, 30, 31, null, null, null],
];
expect(generateMonthMatrix(2022, 2)).toEqual(expected);
});

it('returns the correct matrix for April 2022', () => {
const expected = [
[null, null, null, null, 1, 2, 3],
[4, 5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30, null],
];
expect(generateMonthMatrix(2022, 3)).toEqual(expected);
});

it('returns the correct matrix for December 2022', () => {
const expected = [
[null, null, null, 1, 2, 3, 4],
[5, 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24, 25],
[26, 27, 28, 29, 30, 31, null],
];
expect(generateMonthMatrix(2022, 11)).toEqual(expected);
});

it('returns the correct matrix for January 2025', () => {
const expected = [
[null, null, 1, 2, 3, 4, 5],
[6, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26],
[27, 28, 29, 30, 31, null, null],
];
expect(generateMonthMatrix(2022, 2)).toEqual(expected);
expect(generateMonthMatrix(2025, 0)).toEqual(expected);
});

it('returns the correct matrix for April 2022', () => {
it('returns the correct matrix for February 2025', () => {
const expected = [
[null, null, null, null, null, 1, 2],
[3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30],
[24, 25, 26, 27, 28, null, null],
];
expect(generateMonthMatrix(2022, 3)).toEqual(expected);
expect(generateMonthMatrix(2025, 1)).toEqual(expected);
});

it('returns the correct matrix for December 2022', () => {
it('returns the correct matrix for June 2025', () => {
const expected = [
[null, null, null, null, 1, 2, 3],
[4, 5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30, 31],
[null, null, null, null, null, null, 1],
[2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22],
[23, 24, 25, 26, 27, 28, 29],
[30, null, null, null, null, null, null],
];
expect(generateMonthMatrix(2022, 11)).toEqual(expected);
expect(generateMonthMatrix(2025, 5)).toEqual(expected);
});

it('returns the correct matrix for December 2025', () => {
const expected = [
[1, 2, 3, 4, 5, 6, 7],
[8, 9, 10, 11, 12, 13, 14],
[15, 16, 17, 18, 19, 20, 21],
[22, 23, 24, 25, 26, 27, 28],
[29, 30, 31, null, null, null, null],
];
expect(generateMonthMatrix(2025, 11)).toEqual(expected);
});

it('throws an error if month is less than 0', () => {
Expand Down

0 comments on commit 573f6b7

Please sign in to comment.