diff --git a/package.json b/package.json index b4120ab5..833c0e91 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "@testing-library/react-hooks": "^7.0.1", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", - "identity-obj-proxy": "^3.0.0" + "identity-obj-proxy": "^3.0.0", + "mockdate": "^3.0.5" }, "dependencies": { "@dhis2/app-runtime": "^2.8.0", diff --git a/src/top-bar/period-select/fixed-periods.js b/src/top-bar/period-select/fixed-periods.js index a9f3bf70..b21457b4 100644 --- a/src/top-bar/period-select/fixed-periods.js +++ b/src/top-bar/period-select/fixed-periods.js @@ -809,35 +809,55 @@ export const PERIOD_SHORTER = -1 * @returns {Int} */ export const compareFixedPeriodLength = (left, right) => { - const leftIndex = FIXED_PERIODS_BY_LENGTH.findIndex(types => types.includes(left)) - const rightIndex = FIXED_PERIODS_BY_LENGTH.findIndex(types => types.includes(right)) + const leftIndex = FIXED_PERIODS_BY_LENGTH.findIndex(types => + types.includes(left) + ) + const rightIndex = FIXED_PERIODS_BY_LENGTH.findIndex(types => + types.includes(right) + ) if (leftIndex === rightIndex) return PERIOD_EQUAL return leftIndex > rightIndex ? PERIOD_SHORTER : PERIOD_GREATER } -export const getLastSubPeriodForTypeAndPeriod = (type, period) => { - const fullPeriod = parsePeriodId(period.id) +export const getCurrentPeriodForType = type => { + const currentDate = new Date() + let year = currentDate.getFullYear() - if (!fullPeriod) { - throw new Error( - `Can't parse period with id "${period.id}"` - ) - } + // cover this and the next years as that + // should cover all existing period types + for (let i = 0; i < 2; ++i) { + const periods = getFixedPeriodsByTypeAndYear(type, year).reverse() + + for (const period of periods) { + const periodStart = new Date(period.startDate) + const periodEnd = new Date(period.endDate) + const endsBeforePeriodEnd = currentDate <= periodEnd + const startsAfterPeriodStart = currentDate >= periodStart - const { type: periodType } = parsePeriodId(period.id).periodType - if (compareFixedPeriodLength(type, periodType) !== PERIOD_GREATER) { - throw new Error( - `The sub-period type "${type}" is not shorter that the period's type ("${periodType}")` - ) + if (endsBeforePeriodEnd && startsAfterPeriodStart) { + return period + } + } + + ++year } - // .slice(-1) returns an array with the last item - const [lastSubPeriod] = getFixedPeriodsForTypeAndDateRange( - type, - period.startDate, - period.endDate - ).slice(-1) + return null +} - return lastSubPeriod +export const isGreaterPeriodTypeEndDateWithinShorterPeriod = ( + greaterPeriodType, + shorterPeriod +) => { + const greaterPeriod = getCurrentPeriodForType(greaterPeriodType) + const greaterPeriodEndDate = new Date(greaterPeriod.endDate) + const shorterPeriodEndDate = new Date(shorterPeriod.endDate) + const shorterPeriodStartDate = new Date(shorterPeriod.startDate) + const greaterEndsAfterShorterStarts = + greaterPeriodEndDate >= shorterPeriodStartDate + const greaterEndsBeforeShorterEnds = + greaterPeriodEndDate <= shorterPeriodEndDate + + return greaterEndsAfterShorterStarts && greaterEndsBeforeShorterEnds } diff --git a/src/top-bar/period-select/fixed-periods.test.js b/src/top-bar/period-select/fixed-periods.test.js index 187d058d..a2fc3d98 100644 --- a/src/top-bar/period-select/fixed-periods.test.js +++ b/src/top-bar/period-select/fixed-periods.test.js @@ -1,3 +1,4 @@ +import MockDate from 'mockdate' import { PERIOD_GREATER, PERIOD_EQUAL, @@ -20,13 +21,13 @@ import { FINANCIAL_OCT, FINANCIAL_NOV, compareFixedPeriodLength, - getFixedPeriodsForTypeAndDateRange, - getFixedPeriodsByTypeAndYear, + getCurrentPeriodForType, getFixedPeriodType, getFixedPeriodTypes, - getLastSubPeriodForTypeAndPeriod, - parsePeriodId, + getFixedPeriodsForTypeAndDateRange, getYearOffsetFromNow, + isGreaterPeriodTypeEndDateWithinShorterPeriod, + parsePeriodId, } from './fixed-periods.js' describe('fixedPeriods utils', () => { @@ -1111,36 +1112,118 @@ describe('fixedPeriods utils', () => { }) }) - describe('getLastSubPeriodForTypeAndPeriod', () => { - it("should throw an error if the period's type is equal to the type", () => { - expect(() => getLastSubPeriodForTypeAndPeriod(DAILY, DAILY)).toThrow() + describe('getCurrentPeriodForType', () => { + afterEach(() => { + MockDate.reset() }) - it("should throw an error if the period's type is shorter than the type", () => { - expect(() => getLastSubPeriodForTypeAndPeriod(WEEKLY, DAILY)).toThrow() - }) + it('should return the current period that ends in the current year', () => { + MockDate.set(new Date('2021-10-01').getTime()) - it('should return the last weekly period of the year 2021', () => { - const yearPeriod = { + const periodType = SIX_MONTHLY + const actual = getCurrentPeriodForType(periodType) + const expected = { + startDate: '2021-07-01', endDate: '2021-12-31', - startDate: '2021-01-01', - displayName: '2021', - iso: '2021', - id: '2021' + displayName: 'July - December 2021', + iso: '2021S2', + id: '2021S2', } - const lastWeeklyPeriod = getLastSubPeriodForTypeAndPeriod( - WEEKLY, - yearPeriod - ) + expect(actual).toEqual(expected) + }) + + it('should return the current period that ends in the next year', () => { + MockDate.set(new Date('2021-10-01').getTime()) + + const periodType = SIX_MONTHLY_APRIL + const actual = getCurrentPeriodForType(periodType) + const expected = { + startDate: '2021-10-01', + endDate: '2022-03-31', + displayName: 'October 2021 - March 2022', + iso: '2021AprilS2', + id: '2021AprilS2', + } + + expect(actual).toEqual(expected) + }) + + describe('yearly - edge case', () => { + it('should return the current period that ends in the current year', () => { + MockDate.set(new Date('2021-10-01').getTime()) + + const periodType = YEARLY + const actual = getCurrentPeriodForType(periodType) + const expected = { + endDate: '2021-12-31', + startDate: '2021-01-01', + displayName: '2021', + iso: '2021', + id: '2021', + } + + expect(actual).toEqual(expected) + }) + + it('should return the current period that ends in the next year', () => { + MockDate.set(new Date('2021-10-01').getTime()) - expect(lastWeeklyPeriod).toEqual({ - startDate: '2021-12-20', - iso: '2021W51', - id: '2021W51', - endDate: '2021-12-26', - displayName: 'Week 51 - 2021-12-20 - 2021-12-26' + const periodType = FINANCIAL_APRIL + const actual = getCurrentPeriodForType(periodType) + const expected = { + endDate: '2022-03-31', + startDate: '2021-04-01', + displayName: 'April 2021 - March 2022', + id: '2021April', + } + + expect(actual).toEqual(expected) }) }) }) + + describe('isGreaterPeriodTypeEndDateWithinShorterPeriod', () => { + it('should return true when the short period spans over the greater periods end date', () => { + MockDate.set(new Date('2021-10-01').getTime()) + + const greaterPeriodType = YEARLY + const shorterPeriod = parsePeriodId('2021Q4') + const expected = true + const actual = isGreaterPeriodTypeEndDateWithinShorterPeriod( + greaterPeriodType, + shorterPeriod + ) + + expect(actual).toBe(expected) + }) + + it('should return false when the short period spans over the greater periods end date', () => { + MockDate.set(new Date('2021-10-01').getTime()) + + const greaterPeriodType = YEARLY + const shorterPeriod = parsePeriodId('2021Q3') + const expected = false + const actual = isGreaterPeriodTypeEndDateWithinShorterPeriod( + greaterPeriodType, + shorterPeriod + ) + + expect(actual).toBe(expected) + }) + + it('should return true when a short period that ends in the following year spans over the greater periods end date', () => { + MockDate.set(new Date('2021-10-01').getTime()) + + const greaterPeriodType = YEARLY + const shorterPeriod = parsePeriodId('2021W52') + const expected = true + const actual = isGreaterPeriodTypeEndDateWithinShorterPeriod( + greaterPeriodType, + shorterPeriod + ) + + expect(actual).toBe(expected) + }) + }) }) diff --git a/yarn.lock b/yarn.lock index 2c72a810..e13f6fc3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10859,6 +10859,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mockdate@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" + integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== + moment@^2.24.0, moment@^2.29.1: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"