From 72fc5647fb9969f233acb66d56bc0c5cc599d1bb Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:22:16 -0500 Subject: [PATCH 1/6] extract hardcoded weekStartsOn into a method inside DateUtils --- .../CalendarPicker/generateMonthMatrix.js | 8 ++++-- src/libs/DateUtils.ts | 26 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js index a3497654feec..bb5a66c147a1 100644 --- a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js +++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js @@ -1,4 +1,5 @@ import {addDays, format, getDay, getDaysInMonth, startOfMonth} from 'date-fns'; +import {getWeekStartsAndEndsOn} from '@libs/DateUtils'; /** * Generates a matrix representation of a month's calendar given the year and month. @@ -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 start and end of week + const {weekStartsOn, weekEndsOn} = getWeekStartsAndEndsOn(); + // 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); @@ -33,7 +37,7 @@ export default function generateMonthMatrix(year, month) { let currentWeek = []; // Add null values for days before the first day of the month - for (let i = 0; i < getDay(firstDayOfMonth); i++) { + for (let i = weekStartsOn; i < getDay(firstDayOfMonth); i++) { currentWeek.push(null); } @@ -43,7 +47,7 @@ export default function generateMonthMatrix(year, month) { 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 = []; } diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 80eae24d9367..6dcfaf758725 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -29,6 +29,11 @@ import * as CurrentDate from './actions/CurrentDate'; import * as Localize from './Localize'; type Locale = ValueOf; +type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6; +type WeekStartsAndEndsOn = { + weekStartsOn: WeekDay; + weekEndsOn: WeekDay; +}; let currentUserAccountID: number | undefined; Onyx.connect({ @@ -60,6 +65,16 @@ Onyx.connect({ }, }); +/** + * Get the day of the week that the week starts and ends on + */ +function getWeekStartsAndEndsOn(): WeekStartsAndEndsOn { + return { + weekStartsOn: 1, // Assuming Monday is the start of the week + weekEndsOn: 0, // Assuming Sunday is the end of the week + }; +} + /** * Gets the locale string and setting default locale for date-fns */ @@ -145,9 +160,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} = getWeekStartsAndEndsOn(); - 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(); @@ -284,8 +300,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} = getWeekStartsAndEndsOn(); + 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 @@ -413,6 +430,7 @@ const DateUtils = { getMonthNames, getDaysOfWeek, formatWithUTCTimeZone, + weekStartsAndEndsOn: getWeekStartsAndEndsOn, }; export default DateUtils; From 3dd8f85bb79506399093a75a22e558f3d07f3aa7 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:26:56 -0500 Subject: [PATCH 2/6] fixed usage of DateUtils lib --- .../NewDatePicker/CalendarPicker/generateMonthMatrix.js | 4 ++-- src/libs/DateUtils.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js index bb5a66c147a1..600ac0b4fd21 100644 --- a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js +++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js @@ -1,5 +1,5 @@ import {addDays, format, getDay, getDaysInMonth, startOfMonth} from 'date-fns'; -import {getWeekStartsAndEndsOn} from '@libs/DateUtils'; +import DateUtils from '@libs/DateUtils'; /** * Generates a matrix representation of a month's calendar given the year and month. @@ -26,7 +26,7 @@ export default function generateMonthMatrix(year, month) { } // Get the week day for the start and end of week - const {weekStartsOn, weekEndsOn} = getWeekStartsAndEndsOn(); + const {weekStartsOn, weekEndsOn} = DateUtils.getWeekStartsAndEndsOn(); // Get the number of days in the month and the first day of the month const firstDayOfMonth = startOfMonth(new Date(year, month, 1)); diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 6dcfaf758725..d8803e301cee 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -430,7 +430,7 @@ const DateUtils = { getMonthNames, getDaysOfWeek, formatWithUTCTimeZone, - weekStartsAndEndsOn: getWeekStartsAndEndsOn, + getWeekStartsAndEndsOn, }; export default DateUtils; From a13abd6d8c1b3c954a02cfa3b3da6ce7fdd38bd4 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:42:50 -0500 Subject: [PATCH 3/6] moved week starts on into a constant --- src/CONST.ts | 1 + .../CalendarPicker/generateMonthMatrix.js | 3 +- src/libs/DateUtils.ts | 29 ++++++++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index c29a7c51e6ef..d1f0ed6a56c2 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -858,6 +858,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}, diff --git a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js index 600ac0b4fd21..9e2ae4195a7c 100644 --- a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js +++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js @@ -26,7 +26,8 @@ export default function generateMonthMatrix(year, month) { } // Get the week day for the start and end of week - const {weekStartsOn, weekEndsOn} = DateUtils.getWeekStartsAndEndsOn(); + const weekStartsOn = DateUtils.getWeekStartsOn(); + 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)); diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index d8803e301cee..d7b6d9132808 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -30,10 +30,6 @@ import * as Localize from './Localize'; type Locale = ValueOf; type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6; -type WeekStartsAndEndsOn = { - weekStartsOn: WeekDay; - weekEndsOn: WeekDay; -}; let currentUserAccountID: number | undefined; Onyx.connect({ @@ -66,13 +62,19 @@ Onyx.connect({ }); /** - * Get the day of the week that the week starts and ends on + * 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 getWeekStartsAndEndsOn(): WeekStartsAndEndsOn { - return { - weekStartsOn: 1, // Assuming Monday is the start of the week - weekEndsOn: 0, // Assuming Sunday is the end of the week - }; +function getWeekEndsOn(): WeekDay { + const weekStartsOn = getWeekStartsOn(); + + return weekStartsOn === 0 ? 6 : ((weekStartsOn - 1) as WeekDay); } /** @@ -160,7 +162,7 @@ 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} = getWeekStartsAndEndsOn(); + const weekStartsOn = getWeekStartsOn(); const startOfCurrentWeek = startOfWeek(new Date(), {weekStartsOn}); const endOfCurrentWeek = endOfWeek(new Date(), {weekStartsOn}); @@ -300,7 +302,7 @@ function getDaysOfWeek(preferredLocale: Locale): string[] { if (preferredLocale) { setLocale(preferredLocale); } - const {weekStartsOn} = getWeekStartsAndEndsOn(); + const weekStartsOn = getWeekStartsOn(); const startOfCurrentWeek = startOfWeek(new Date(), {weekStartsOn}); const endOfCurrentWeek = endOfWeek(new Date(), {weekStartsOn}); const daysOfWeek = eachDayOfInterval({start: startOfCurrentWeek, end: endOfCurrentWeek}); @@ -430,7 +432,8 @@ const DateUtils = { getMonthNames, getDaysOfWeek, formatWithUTCTimeZone, - getWeekStartsAndEndsOn, + getWeekStartsOn, + getWeekEndsOn, }; export default DateUtils; From 5b6b2ff667f574141215f26a87cb8db110a3d9e5 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:43:14 -0500 Subject: [PATCH 4/6] updated generateMonthMatrix test --- tests/unit/generateMonthMatrixTest.js | 62 +++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/tests/unit/generateMonthMatrixTest.js b/tests/unit/generateMonthMatrixTest.js index 9f565a6e3a78..dc3df145c0b5 100644 --- a/tests/unit/generateMonthMatrixTest.js +++ b/tests/unit/generateMonthMatrixTest.js @@ -3,67 +3,67 @@ import generateMonthMatrix from '../../src/components/NewDatePicker/CalendarPick 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, 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, 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, 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, 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, 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, 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); }); From aa015de65f6854c8c585464e7939bb9b33c52c39 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:23:54 -0500 Subject: [PATCH 5/6] updated how empty days are added at the beginning of the month --- .../CalendarPicker/generateMonthMatrix.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js index 9e2ae4195a7c..ecf338d36424 100644 --- a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js +++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js @@ -25,8 +25,7 @@ export default function generateMonthMatrix(year, month) { throw new Error('Month cannot be greater than 11'); } - // Get the week day for the start and end of week - const weekStartsOn = DateUtils.getWeekStartsOn(); + // 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 @@ -37,11 +36,6 @@ 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 = weekStartsOn; 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); @@ -61,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; } From 5fb6e98d1254e2b1e353faa4c9adbfc70854a8d1 Mon Sep 17 00:00:00 2001 From: Carlos Barros <765936+barros001@users.noreply.github.com> Date: Tue, 26 Dec 2023 12:27:18 -0300 Subject: [PATCH 6/6] add a few more tests --- tests/unit/generateMonthMatrixTest.js | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/unit/generateMonthMatrixTest.js b/tests/unit/generateMonthMatrixTest.js index be2615da6c64..67dd65e6b1fd 100644 --- a/tests/unit/generateMonthMatrixTest.js +++ b/tests/unit/generateMonthMatrixTest.js @@ -68,6 +68,51 @@ describe('generateMonthMatrix', () => { 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(2025, 0)).toEqual(expected); + }); + + 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, null, null], + ]; + expect(generateMonthMatrix(2025, 1)).toEqual(expected); + }); + + it('returns the correct matrix for June 2025', () => { + 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, null, null, null, null, null, null], + ]; + 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', () => { expect(() => generateMonthMatrix(2022, -1)).toThrow(); });