diff --git a/playbook/.eslintrc.json b/playbook/.eslintrc.json index 87602ed03e..01ea8d86b0 100644 --- a/playbook/.eslintrc.json +++ b/playbook/.eslintrc.json @@ -35,7 +35,7 @@ "rules": { "jsx-control-statements/jsx-jcs-no-undef": 1, "no-console": 1, - "no-restricted-globals": [1, { "name": "moment" }], + "no-restricted-globals": 1, "no-use-before-define": [1, { "functions": true, "classes": true }], "react/forbid-prop-types": 2, "react/jsx-boolean-value": 2, diff --git a/playbook/app/pb_kits/playbook/pb_date_picker/date_picker.test.js b/playbook/app/pb_kits/playbook/pb_date_picker/date_picker.test.js index fcf0155431..2c3b7393c4 100644 --- a/playbook/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +++ b/playbook/app/pb_kits/playbook/pb_date_picker/date_picker.test.js @@ -1,16 +1,26 @@ /* eslint-disable no-console */ import React from 'react' -import moment from 'moment' import { fireEvent, render, screen, waitFor, within } from '../utilities/test-utils' import DatePicker from './_date_picker' +import DateTime from "../pb_kit/dateTime.ts" import { getTimezoneText } from './plugins/timeSelect' - - jest.setSystemTime(new Date('01/01/2020')); const DEFAULT_DATE = new Date() +const formatDate = (date) => { + const month = (date.getMonth() + 1).toString().padStart(2, "0") + const day = (date.getDate()).toString().padStart(2, "0") + const year = date.getFullYear() + + return `${month}/${day}/${year}` +} + +Date.prototype.formatDate = function () { + return formatDate(this) +} + describe('DatePicker Kit', () => { beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => { }); @@ -158,6 +168,7 @@ describe('DatePicker Kit', () => { expect(input).toHaveValue('01/01/2020 at 12:00 PM') }) }) + test('shows DatePicker QuickPick dropdown and adds correct date to input', async () => { const testId = 'datepicker-quick-pick' render( @@ -197,10 +208,10 @@ describe('DatePicker Kit', () => { ) await waitFor(() => { - expect(input).toHaveValue(moment().startOf('year').format('MM/DD/YYYY') + " to " + moment().endOf('year').format('MM/DD/YYYY')) + expect(input).toHaveValue(DateTime.getYearStartDate(new Date()).formatDate() + " to " + DateTime.getYearEndDate(new Date()).formatDate()) }) - }) + test('shows DatePicker QuickPick ranges ending today', async () => { const testId = 'datepicker-quick-pick-ends-today' render( @@ -225,7 +236,7 @@ describe('DatePicker Kit', () => { cancelable: true, }), ) - + const thisYear = within(kit).getByText('This year') fireEvent( @@ -237,8 +248,7 @@ describe('DatePicker Kit', () => { ) await waitFor(() => { - expect(input).toHaveValue(moment().startOf('year').format('MM/DD/YYYY') + " to " + moment().format('MM/DD/YYYY')) + expect(input).toHaveValue(DateTime.getYearStartDate(new Date()).formatDate() + " to " + new Date().formatDate()) }) - }) }) diff --git a/playbook/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx b/playbook/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx index 286e035d87..718e175c6d 100644 --- a/playbook/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +++ b/playbook/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx @@ -1,4 +1,4 @@ -import moment from 'moment' +import DateTime from '../../pb_kit/dateTime'; type FpTypes = { setDate: (arg0: any, arg1: boolean) => void, @@ -23,37 +23,44 @@ let activeLabel = "" const quickPickPlugin = (thisRangesEndToday: boolean) => { return function (fp: FpTypes & any): any { - const thisWeekEndDate = thisRangesEndToday ? new Date() : moment().endOf('isoWeek').toDate() - const thisMonthEndDate = thisRangesEndToday ? new Date() : moment().endOf('month').toDate() - const thisQuarterEndDate = thisRangesEndToday ? new Date() : moment().endOf('quarter').toDate() - const thisYearEndDate = thisRangesEndToday ? new Date() : moment().endOf('year').toDate() + const today = new Date() + const yesterday = DateTime.getYesterdayDate(new Date()) + + const thisWeekStartDate = DateTime.getFirstDayOfWeek(new Date()) + const thisWeekEndDate = thisRangesEndToday ? new Date() : DateTime.getLastDayOfWeek(new Date()) + const lastWeekStartDate = DateTime.getPreviousWeekStartDate(new Date()) + const lastWeekEndDate = DateTime.getPreviousWeekEndDate(new Date()) + + const thisMonthStartDate = DateTime.getMonthStartDate(new Date()) + const thisMonthEndDate = thisRangesEndToday ? new Date() : DateTime.getMonthEndDate(new Date()) + const lastMonthStartDate = DateTime.getPreviousMonthStartDate(new Date()) + const lastMonthEndDate = DateTime.getPreviousMonthEndDate(new Date()) + + const thisQuarterStartDate = DateTime.getQuarterStartDate(new Date()) + const thisQuarterEndDate = thisRangesEndToday ? new Date() : DateTime.getQuarterEndDate(new Date()) + const lastQuarterStartDate = DateTime.getPreviousQuarterStartDate(new Date()) + const lastQuarterEndDate = DateTime.getPreviousQuarterEndDate(new Date()) + + const thisYearStartDate = DateTime.getYearStartDate(new Date()) + const thisYearEndDate = thisRangesEndToday ? new Date() : DateTime.getYearEndDate(new Date()) + const lastYearStartDate = DateTime.getPreviousYearStartDate(new Date()) + const lastYearEndDate = DateTime.getPreviousYearEndDate(new Date()) // variable that holds the ranges available const ranges = { - 'Today': [new Date(), new Date()], - 'Yesterday': [moment().subtract(1, 'days').toDate(), moment().subtract(1, 'days').toDate()], - 'This week': [moment().startOf('isoWeek').toDate(), thisWeekEndDate], - 'This month': [moment().startOf('month').toDate(), thisMonthEndDate], - 'This quarter': [moment().startOf('quarter').toDate(), thisQuarterEndDate], - 'This year': [moment().startOf('year').toDate(), thisYearEndDate], - 'Last week': [ - moment().subtract(1, 'week').startOf('isoWeek').toDate(), - moment().subtract(1, 'week').endOf('isoWeek').toDate() - ], - 'Last month': [ - moment().subtract(1, 'month').startOf('month').toDate(), - moment().subtract(1, 'month').endOf('month').toDate() - ], - 'Last quarter': [ - moment().subtract(1, 'quarter').startOf('quarter').toDate(), - moment().subtract(1, 'quarter').endOf('quarter').toDate() - ], - 'Last year': [ - moment().subtract(1, 'year').startOf('year').toDate(), - moment().subtract(1, 'year').endOf('year').toDate() - ] + 'Today': [today, today], + 'Yesterday': [yesterday, yesterday], + 'This week': [thisWeekStartDate, thisWeekEndDate], + 'This month': [thisMonthStartDate, thisMonthEndDate], + 'This quarter': [thisQuarterStartDate, thisQuarterEndDate], + 'This year': [thisYearStartDate, thisYearEndDate], + 'Last week': [lastWeekStartDate, lastWeekEndDate], + 'Last month': [lastMonthStartDate, lastMonthEndDate], + 'Last quarter': [lastQuarterStartDate, lastQuarterEndDate], + 'Last year': [lastYearStartDate, lastYearEndDate] } - //creating the ul element for the nav dropdown and giving it classnames + + // creating the ul element for the nav dropdown and giving it classnames const rangesNav = document.createElement('ul'); // creating the pluginData object that will hold the properties of this plugin @@ -64,11 +71,11 @@ const quickPickPlugin = (thisRangesEndToday: boolean) => { }; /** - * @param {string} label - * @returns HTML Element - */ + * @param {string} label + * @returns HTML Element + */ - //function for creating the range buttons in the nav + // function for creating the range buttons in the nav const addRangeButton = (label: string) => { // creating new elements to mimick selectable card component @@ -88,7 +95,7 @@ const quickPickPlugin = (thisRangesEndToday: boolean) => { // append the li item to the ul rangeNav prop pluginData.rangesNav.appendChild(item); - // return the ranges buton prop + // return the ranges button prop return pluginData.rangesButtons[label]; }; @@ -98,7 +105,7 @@ const quickPickPlugin = (thisRangesEndToday: boolean) => { if (current) { current.classList.remove('active'); } - + if (selectedDates.length > 0 && activeLabel) { pluginData.rangesButtons[activeLabel].classList.add('active'); } @@ -109,16 +116,15 @@ const quickPickPlugin = (thisRangesEndToday: boolean) => { selectedDates[1].toDateString() === pluginData.ranges[activeLabel][1].toDateString() } - return { - // onReady is a hook from flatpickr that runs when calender is in a ready state + // onReady is a hook from flatpickr that runs when calendar is in a ready state onReady(selectedDates: Array) { // loop through the ranges and create an anchor tag for each range and add an event listener to set the date when user clicks on a date range for (const [label, range] of Object.entries(pluginData.ranges)) { addRangeButton(label).addEventListener('click', function () { - const start = moment(range[0]).toDate(); - const end = moment(range[1]).toDate(); + const start = new Date(range[0]); + const end = new Date(range[1]); if (!start) { fp.clear(); @@ -170,4 +176,4 @@ const quickPickPlugin = (thisRangesEndToday: boolean) => { }; } -export default quickPickPlugin; \ No newline at end of file +export default quickPickPlugin; diff --git a/playbook/app/pb_kits/playbook/pb_kit/dateTime.ts b/playbook/app/pb_kits/playbook/pb_kit/dateTime.ts index 12b79dc3e5..b6d8f39179 100644 --- a/playbook/app/pb_kits/playbook/pb_kit/dateTime.ts +++ b/playbook/app/pb_kits/playbook/pb_kit/dateTime.ts @@ -116,7 +116,6 @@ export const toIso = (newDate: Date | string): string => { } export const fromNow = (newDate: Date | string): string => { - const startDate = formatDate(newDate).getTime() const endDate = new Date().getTime() const elapsedTime = endDate - startDate @@ -154,6 +153,193 @@ export const toCustomFormat = (newDate: Date | string, format = 'month_day'): st } } +// For quickPick.tsx +// Yesterday +export const getYesterdayDate = (newDate: Date | string): Date => { + const today = formatDate(newDate) + const yesterday = new Date() + yesterday.setDate(today.getDate() - 1) + + return yesterday +} + +// Weeks +export const getFirstDayOfWeek = (newDate: Date | string): Date => { + const today = formatDate(newDate) + const dayOfWeek = today.getDay() + // Replicate Moment.js: Start of week (Monday) has a time of 00:00:00 + const firstDayOfWeek = new Date(today.setHours(0, 0, 0)) + const isSunday = dayOfWeek === 0 + + const daysToSubtract = isSunday ? 6 : (dayOfWeek - 1) + firstDayOfWeek.setDate(today.getDate() - daysToSubtract) + + return firstDayOfWeek +} + +export const getLastDayOfWeek = (newDate: Date | string): Date => { + const today = formatDate(newDate) + const dayOfWeek = today.getDay() + // Replicate Moment.js: End of week (Sunday) has a time of 23:59:59 + const lastDayOfWeek = new Date(today.setHours(23, 59, 59, 0)) + const isSunday = dayOfWeek === 0 + + const daysToAdd = isSunday ? 0 : (7 - dayOfWeek) + lastDayOfWeek.setDate(today.getDate() + daysToAdd) + + return lastDayOfWeek +} + +export const getPreviousWeekStartDate = (newDate: Date | string): Date => { + const firstDayOfWeek = getFirstDayOfWeek(newDate) + const firstDayOfPreviousWeek = new Date( + firstDayOfWeek.getFullYear(), + firstDayOfWeek.getMonth(), + firstDayOfWeek.getDate() - 7 + ) + + return firstDayOfPreviousWeek +} + +export const getPreviousWeekEndDate = (newDate: Date | string): Date => { + const lastDayOfWeek = getLastDayOfWeek(newDate) + const lastDayOfPreviousWeek = new Date( + lastDayOfWeek.getFullYear(), + lastDayOfWeek.getMonth(), + lastDayOfWeek.getDate() - 7, + lastDayOfWeek.getHours(), + lastDayOfWeek.getMinutes(), + lastDayOfWeek.getSeconds() + ) + + return lastDayOfPreviousWeek +} + +// Months +export const getMonthStartDate = (newDate: Date | string): Date => { + const date = formatDate(newDate) + const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1) + + return firstDayOfMonth +} + +export const getMonthEndDate = (newDate: Date | string): Date => { + const date = formatDate(newDate) + // Replicate Moment.js: End of month has a time of 23:59:59 + const lastDayOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59) + + return lastDayOfMonth +} + +export const getPreviousMonthStartDate = (newDate: Date | string): Date => { + const firstDayOfMonth = getMonthStartDate(newDate) + const firstDayOfPreviousMonth = new Date( + firstDayOfMonth.getFullYear(), + firstDayOfMonth.getMonth() - 1, + firstDayOfMonth.getDate() + ) + + return firstDayOfPreviousMonth +} + +export const getPreviousMonthEndDate = (newDate: Date | string): Date => { + const lastDayOfMonth = getMonthEndDate(newDate) + const lastDayOfPreviousMonth = new Date( + lastDayOfMonth.getFullYear(), + lastDayOfMonth.getMonth() - 1, + lastDayOfMonth.getDate(), + lastDayOfMonth.getHours(), + lastDayOfMonth.getMinutes(), + lastDayOfMonth.getSeconds() + ) + + return lastDayOfPreviousMonth +} + +// Quarters +export const getQuarterStartDate = (newDate: Date | string): Date => { + const date = formatDate(newDate) + const quarter = Math.floor(date.getMonth() / 3) + const startOfQuarter = new Date(date.getFullYear(), quarter * 3, 1) + + return startOfQuarter +} + +export const getQuarterEndDate = (newDate: Date | string): Date => { + const date = formatDate(newDate) + const quarter = Math.floor(date.getMonth() / 3) + const startOfNextQuarter = new Date(date.getFullYear(), (quarter + 1) * 3, 1) + // Replicate Moment.js: End of quarter has a time of 23:59:59 + const endOfQuarter = new Date(startOfNextQuarter.getTime() - 1) + + return endOfQuarter +} + +export const getPreviousQuarterStartDate = (newDate: Date | string): Date => { + const startOfQuarter = getQuarterStartDate(newDate) + const firstDayOfPreviousQuarter = new Date( + startOfQuarter.getFullYear(), + startOfQuarter.getMonth() - 3, + startOfQuarter.getDate() + ) + + return firstDayOfPreviousQuarter +} + +export const getPreviousQuarterEndDate = (newDate: Date | string): Date => { + const endOfQuarter = getQuarterEndDate(newDate) + const lastDayOfPreviousQuarter = new Date( + endOfQuarter.getFullYear(), + endOfQuarter.getMonth() - 3, + endOfQuarter.getDate(), + endOfQuarter.getHours(), + endOfQuarter.getMinutes(), + endOfQuarter.getSeconds() + ) + + return lastDayOfPreviousQuarter +} + +// Years +export const getYearStartDate = (newDate: Date | string): Date => { + const date = formatDate(newDate) + const startOfYear = new Date(date.getFullYear(), 0, 1) + + return startOfYear +} + +export const getYearEndDate = (newDate: Date | string): Date => { + const date = formatDate(newDate) + const endOfYear = new Date(date.getFullYear(), 11, 31, 23, 59, 59) + + return endOfYear +} + +export const getPreviousYearStartDate = (newDate: Date | string): Date => { + const startOfYear = getYearStartDate(newDate) + const firstDayOfPreviousYear = new Date( + startOfYear.getFullYear() - 1, + startOfYear.getMonth(), + startOfYear.getDate() + ) + + return firstDayOfPreviousYear +} + +export const getPreviousYearEndDate = (newDate: Date | string): Date => { + const endOfYear = getYearEndDate(newDate) + const lastDayOfPreviousYear = new Date( + endOfYear.getFullYear() - 1, + endOfYear.getMonth(), + endOfYear.getDate(), + endOfYear.getHours(), + endOfYear.getMinutes(), + endOfYear.getSeconds() + ) + + return lastDayOfPreviousYear +} + export default { toMinute, toHour, @@ -170,4 +356,21 @@ export default { toIso, fromNow, toCustomFormat, + getYesterdayDate, + getFirstDayOfWeek, + getLastDayOfWeek, + getPreviousWeekStartDate, + getPreviousWeekEndDate, + getMonthStartDate, + getMonthEndDate, + getPreviousMonthStartDate, + getPreviousMonthEndDate, + getQuarterStartDate, + getQuarterEndDate, + getPreviousQuarterStartDate, + getPreviousQuarterEndDate, + getYearStartDate, + getYearEndDate, + getPreviousYearStartDate, + getPreviousYearEndDate } diff --git a/playbook/package.json b/playbook/package.json index f15f5acf9a..6621184470 100644 --- a/playbook/package.json +++ b/playbook/package.json @@ -46,9 +46,6 @@ "intl-tel-input": "^17.0.19", "lazysizes": "^5.2.2", "lodash": "^4.17.19", - "moment": "^2.29.1", - "moment-strftime": "^0.5.0", - "moment-timezone": "^0.5.26", "react-animate-height": "^2.0.23", "react-dropzone": "^10.2.2", "react-highlight-words": "^0.20.0", diff --git a/yarn.lock b/yarn.lock index 5f8d747adb..b7fc51ccbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9247,25 +9247,6 @@ mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: dependencies: minimist "^1.2.6" -moment-strftime@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/moment-strftime/-/moment-strftime-0.5.0.tgz#0cd395058cfabb2cbdbf49a2d3758aa22093d65a" - integrity sha512-0gwXdJEY1nD1YMlH9nLbDl+HLMfprzfxT2+qDkl29jGgDlVHzPCdwBBN0DPgY+e3+ur7tfdngxweKYBiT80nEA== - dependencies: - moment "^2.11.2" - -moment-timezone@^0.5.26: - version "0.5.40" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.40.tgz#c148f5149fd91dd3e29bf481abc8830ecba16b89" - integrity sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg== - dependencies: - moment ">= 2.9.0" - -"moment@>= 2.9.0", moment@^2.11.2, moment@^2.29.1: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"