diff --git a/CHANGELOG.md b/CHANGELOG.md index d55f3ba38..dca21e3ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Improve HTML page titles for Assigned Users and Usage Consolidation Settings pages. (UIEH-1387) * Edit eholdings record (provider/package/title) > Cancel button does not work in same way as other apps Cancel button. (UIEH-1360) * Refactor CSS away from `color()` function. (UIEH-1402) +* Replace `moment` usage with `dayjs`. (UIEH-1407) ## [9.0.2] (https://github.com/folio-org/ui-eholdings/tree/v9.0.2) (2023-11-09) @@ -37,7 +38,7 @@ ## [8.0.3] (https://github.com/folio-org/ui-eholdings/tree/v8.0.3) (2023-03-30) -* Clear the last eholdings visited page flag after the user returns to the eholdings page form another plugin page. For proper work navigating through history. (UIEH-1366) +* Clear the last eholdings visited page flag after the user returns to the eholdings page form another plugin page. For proper work navigating through history. (UIEH-1366) ## [8.0.2] (https://github.com/folio-org/ui-eholdings/tree/v8.0.2) (2023-03-23) diff --git a/package.json b/package.json index 4ad87e704..1348afc59 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,6 @@ "husky": "^1.3.1", "identity-obj-proxy": "^3.0.0", "lodash": "^4.17.4", - "moment": "^2.24.0", - "moment-range": "^3.0.3", "qs": "^6.5.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/components/package/_fields/custom-coverage/package-coverage-fields.js b/src/components/package/_fields/custom-coverage/package-coverage-fields.js index af7a267c1..4675df454 100644 --- a/src/components/package/_fields/custom-coverage/package-coverage-fields.js +++ b/src/components/package/_fields/custom-coverage/package-coverage-fields.js @@ -7,7 +7,6 @@ import { injectIntl, } from 'react-intl'; -import moment from 'moment'; import isEqual from 'lodash/isEqual'; import { @@ -15,6 +14,8 @@ import { RepeatableField, Col, Row, + dayjs, + getLocaleDateFormat, } from '@folio/stripes/components'; import { BACKEND_DATE_STANDARD, @@ -32,7 +33,7 @@ class PackageCoverageFields extends Component { values?.forEach(({ beginCoverage, endCoverage }) => { const errors = {}; - if (endCoverage && !moment.utc(endCoverage).isAfter(moment.utc(beginCoverage))) { + if (endCoverage && !dayjs.utc(endCoverage).isAfter(dayjs.utc(beginCoverage))) { errors.beginCoverage = ; } @@ -44,11 +45,10 @@ class PackageCoverageFields extends Component { validateCoverageDate = (value) => { const { intl } = this.props; - moment.locale(intl.locale); - const dateFormat = moment.localeData()._longDateFormat.L; + const dateFormat = getLocaleDateFormat({ intl }); let errors; - if (value && !moment.utc(value).isValid()) { + if (value && !dayjs.utc(value).isValid()) { errors = ( { - moment.locale(locale); - const dateFormat = moment.localeData()._longDateFormat.L; + const dateFormat = getLocaleDateFormat({ intl: { locale } }); const message = ; - if (!dateRange.beginCoverage || !moment.utc(dateRange.beginCoverage).isValid()) { + if (!dateRange.beginCoverage || !dayjs.utc(dateRange.beginCoverage).isValid()) { return { beginCoverage: message }; } @@ -33,7 +31,7 @@ const validateDateFormat = (dateRange, locale) => { const validateStartDateBeforeEndDate = (dateRange) => { const message = ; - if (dateRange.endCoverage && moment.utc(dateRange.beginCoverage).isAfter(moment.utc(dateRange.endCoverage))) { + if (dateRange.endCoverage && dayjs.utc(dateRange.beginCoverage).isAfter(dayjs.utc(dateRange.endCoverage))) { return { beginCoverage: message }; } @@ -49,11 +47,11 @@ const validateStartDateBeforeEndDate = (dateRange) => { * @returns {} - an error object if errors are found, or `undefined` otherwise */ const validateNoRangeOverlaps = (dateRange, customCoverages, index) => { - const present = moment.utc('9999-09-09T05:00:00.000Z'); + const present = dayjs.utc('9999-09-09T05:00:00.000Z'); - const beginCoverageDate = moment.utc(dateRange.beginCoverage); - const endCoverageDate = dateRange.endCoverage ? moment.utc(dateRange.endCoverage) : present; - const coverageRange = moment.range(beginCoverageDate, endCoverageDate); + const beginCoverageDate = dayjs.utc(dateRange.beginCoverage); + const endCoverageDate = dateRange.endCoverage ? dayjs.utc(dateRange.endCoverage) : present; + const coverageRange = new DayRange(beginCoverageDate, endCoverageDate); for (let overlapIndex = 0, len = customCoverages.length; overlapIndex < len; overlapIndex++) { const overlapRange = customCoverages[overlapIndex]; @@ -63,9 +61,9 @@ const validateNoRangeOverlaps = (dateRange, customCoverages, index) => { continue; // eslint-disable-line no-continue } - const overlapCoverageBeginDate = moment.utc(overlapRange.beginCoverage); - const overlapCoverageEndDate = overlapRange.endCoverage ? moment.utc(overlapRange.endCoverage) : present; - const overlapCoverageRange = moment.range(overlapCoverageBeginDate, overlapCoverageEndDate); + const overlapCoverageBeginDate = dayjs.utc(overlapRange.beginCoverage); + const overlapCoverageEndDate = overlapRange.endCoverage ? dayjs.utc(overlapRange.endCoverage) : present; + const overlapCoverageRange = new DayRange(overlapCoverageBeginDate, overlapCoverageEndDate); const startDate = { const message = ; if (overlapCoverageRange.overlaps(coverageRange) - || overlapCoverageRange.isEqual(coverageRange) + || overlapCoverageRange.isSame(coverageRange) || overlapCoverageRange.contains(coverageRange)) { return { beginCoverage: message, endCoverage: message }; } @@ -109,16 +107,16 @@ const validateWithinPackageRange = (resourceDateRange, packageDateRange) => { beginCoverage: packageBeginCoverage, endCoverage: packageEndCoverage } = packageDateRange; - // javascript/moment has no mechanism for "infinite", so we + // javascript/dayjs has no mechanism for "infinite", so we // use an absurd future date to represent the concept of "present" - const present = moment.utc('9999-09-09T05:00:00.000Z'); + const present = dayjs.utc('9999-09-09T05:00:00.000Z'); if (packageBeginCoverage) { - const beginCoverageDate = moment.utc(resourceDateRange.beginCoverage); - const endCoverageDate = resourceDateRange.endCoverage ? moment.utc(resourceDateRange.endCoverage) : present; + const beginCoverageDate = dayjs.utc(resourceDateRange.beginCoverage); + const endCoverageDate = resourceDateRange.endCoverage ? dayjs.utc(resourceDateRange.endCoverage) : present; - const packageBeginCoverageDate = moment.utc(packageBeginCoverage); - const packageEndCoverageDate = packageEndCoverage ? moment.utc(packageEndCoverage) : moment.utc(); - const packageRange = moment.range(packageBeginCoverageDate, packageEndCoverageDate); + const packageBeginCoverageDate = dayjs.utc(packageBeginCoverage); + const packageEndCoverageDate = packageEndCoverage ? dayjs.utc(packageEndCoverage) : dayjs.utc(); + const packageRange = new DayRange(packageBeginCoverageDate, packageEndCoverageDate); const startDate = ({ value: month.toLowerCase().substring(0, 3), - label: moment.months()[index], + label: dayjs.months()[index], })); const parseUsageConsolidationId = value => { diff --git a/src/components/utilities.js b/src/components/utilities.js index c29d7d683..4bafac622 100644 --- a/src/components/utilities.js +++ b/src/components/utilities.js @@ -1,4 +1,3 @@ -import moment from 'moment'; import queryString from 'qs'; import { get, @@ -8,7 +7,10 @@ import { FormattedMessage, } from 'react-intl'; -import { FormattedDate } from '@folio/stripes/components'; +import { + FormattedDate, + dayjs, +} from '@folio/stripes/components'; import { searchTypes, @@ -68,7 +70,7 @@ export function formatCoverageYear({ beginCoverage, endCoverage }) { if (!startYear) { return endCoverage ? endYear : ''; - } else if ((moment.utc(beginCoverage).format('YYYY') === moment.utc(endCoverage).format('YYYY')) || (!endYear)) { + } else if ((dayjs.utc(beginCoverage).format('YYYY') === dayjs.utc(endCoverage).format('YYYY')) || (!endYear)) { return startYear; } else { return <>{startYear}{' - '}{endYear}; @@ -77,10 +79,10 @@ export function formatCoverageYear({ beginCoverage, endCoverage }) { export function isValidCoverage(coverageObj) { if (coverageObj.beginCoverage) { - if (!moment.utc(coverageObj.beginCoverage, 'YYYY-MM-DD').isValid()) { return false; } + if (!dayjs.utc(coverageObj.beginCoverage, 'YYYY-MM-DD').isValid()) { return false; } } if (coverageObj.endCoverage) { - if (!moment.utc(coverageObj.endCoverage, 'YYYY-MM-DD').isValid()) { return false; } + if (!dayjs.utc(coverageObj.endCoverage, 'YYYY-MM-DD').isValid()) { return false; } } return true; } @@ -274,7 +276,7 @@ export const getFullName = user => { export const parseDate = value => value; -export const formatDate = value => (value ? moment.utc(value) : ''); +export const formatDate = value => (value ? dayjs.utc(value) : ''); export const combineMCLProps = defaultProps => customProps => { return { diff --git a/src/features/usage-consolidation-accordion/usage-consolidation-accordion/usage-consolidation-accordion.js b/src/features/usage-consolidation-accordion/usage-consolidation-accordion/usage-consolidation-accordion.js index c847fee28..dd1d21ca7 100644 --- a/src/features/usage-consolidation-accordion/usage-consolidation-accordion/usage-consolidation-accordion.js +++ b/src/features/usage-consolidation-accordion/usage-consolidation-accordion/usage-consolidation-accordion.js @@ -4,7 +4,6 @@ import { } from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; -import moment from 'moment'; import noop from 'lodash/noop'; import { useStripes } from '@folio/stripes/core'; @@ -13,6 +12,7 @@ import { Headline, InfoPopover, Spinner, + dayjs, } from '@folio/stripes/components'; import Toaster from '../../../components/toaster'; @@ -67,7 +67,7 @@ const UsageConsolidationAccordion = ({ const { isLoading: isCostPerUseDataLoading } = costPerUseData; const filtersInitialState = { - year: moment().year(), + year: dayjs().year(), platformType: usageConsolidation.data.platformType, }; diff --git a/src/features/usage-consolidation-accordion/usage-consolidation-filters.js b/src/features/usage-consolidation-accordion/usage-consolidation-filters.js index 22417ed76..3420beca0 100644 --- a/src/features/usage-consolidation-accordion/usage-consolidation-filters.js +++ b/src/features/usage-consolidation-accordion/usage-consolidation-filters.js @@ -7,7 +7,6 @@ import { Form, Field, } from 'react-final-form'; -import moment from 'moment'; import { useIntl, FormattedMessage, @@ -19,6 +18,7 @@ import { Row, Col, Button, + dayjs, } from '@folio/stripes/components'; import { platformTypes } from '../../constants'; @@ -45,7 +45,7 @@ const UsageConsolidationFilters = ({ } }, [yearField]); - const currentYear = moment().year(); + const currentYear = dayjs().year(); const last5Years = new Array(5) .fill(currentYear) .map((year, index) => year - index); diff --git a/src/routes/package-create-route/package-create-route.js b/src/routes/package-create-route/package-create-route.js index 4a5635a52..22d3b5ffe 100644 --- a/src/routes/package-create-route/package-create-route.js +++ b/src/routes/package-create-route/package-create-route.js @@ -1,10 +1,11 @@ import { Component } from 'react'; import PropTypes from 'prop-types'; import ReactRouterPropTypes from 'react-router-prop-types'; -import moment from 'moment'; -import { TitleManager } from '@folio/stripes/core'; import { FormattedMessage } from 'react-intl'; +import { TitleManager } from '@folio/stripes/core'; +import { dayjs } from '@folio/stripes/components'; + import View from '../../components/package/create'; import { accessTypesReduxStateShape } from '../../constants'; @@ -41,9 +42,9 @@ export default class PackageCreateRoute extends Component { if (values?.customCoverages?.[0]) { attrs.customCoverage = { beginCoverage: !values.customCoverages[0].beginCoverage ? '' : - moment.utc(values.customCoverages[0].beginCoverage).format('YYYY-MM-DD'), + dayjs.utc(values.customCoverages[0].beginCoverage).format('YYYY-MM-DD'), endCoverage: !values.customCoverages[0].endCoverage ? '' : - moment.utc(values.customCoverages[0].endCoverage).format('YYYY-MM-DD') + dayjs.utc(values.customCoverages[0].endCoverage).format('YYYY-MM-DD') }; } diff --git a/src/routes/package-edit-route/package-edit-route.js b/src/routes/package-edit-route/package-edit-route.js index 97a2be45b..d9b8e49cf 100644 --- a/src/routes/package-edit-route/package-edit-route.js +++ b/src/routes/package-edit-route/package-edit-route.js @@ -2,10 +2,10 @@ import { Component } from 'react'; import PropTypes from 'prop-types'; import ReactRouterPropTypes from 'react-router-prop-types'; import isEqual from 'lodash/isEqual'; -import moment from 'moment'; import { FormattedMessage } from 'react-intl'; import { TitleManager } from '@folio/stripes/core'; +import { dayjs } from '@folio/stripes/components'; import View from '../../components/package/package-edit'; @@ -135,8 +135,8 @@ class PackageEditRoute extends Component { let endCoverage = ''; if (values.customCoverages[0]) { - beginCoverage = !values.customCoverages[0].beginCoverage ? '' : moment.utc(values.customCoverages[0].beginCoverage).format('YYYY-MM-DD'); - endCoverage = !values.customCoverages[0].endCoverage ? '' : moment.utc(values.customCoverages[0].endCoverage).format('YYYY-MM-DD'); + beginCoverage = !values.customCoverages[0].beginCoverage ? '' : dayjs.utc(values.customCoverages[0].beginCoverage).format('YYYY-MM-DD'); + endCoverage = !values.customCoverages[0].endCoverage ? '' : dayjs.utc(values.customCoverages[0].endCoverage).format('YYYY-MM-DD'); } model.customCoverage = { diff --git a/src/routes/resource-edit-route/resource-edit-route.js b/src/routes/resource-edit-route/resource-edit-route.js index 92fb71b9b..5dbe5cba1 100644 --- a/src/routes/resource-edit-route/resource-edit-route.js +++ b/src/routes/resource-edit-route/resource-edit-route.js @@ -2,10 +2,11 @@ import { Component } from 'react'; import PropTypes from 'prop-types'; import ReactRouterPropTypes from 'react-router-prop-types'; import isEqual from 'lodash/isEqual'; -import moment from 'moment'; -import { TitleManager } from '@folio/stripes/core'; import { FormattedMessage } from 'react-intl'; +import { TitleManager } from '@folio/stripes/core'; +import { dayjs } from '@folio/stripes/components'; + import View from '../../components/resource/resource-edit'; import { accessTypes, @@ -137,8 +138,8 @@ class ResourceEditRoute extends Component { })); } else { const newCustomCoverages = customCoverages.map((dateRange) => { - const beginCoverage = !dateRange.beginCoverage ? null : moment.utc(dateRange.beginCoverage).format('YYYY-MM-DD'); - const endCoverage = !dateRange.endCoverage ? null : moment.utc(dateRange.endCoverage).format('YYYY-MM-DD'); + const beginCoverage = !dateRange.beginCoverage ? null : dayjs.utc(dateRange.beginCoverage).format('YYYY-MM-DD'); + const endCoverage = !dateRange.endCoverage ? null : dayjs.utc(dateRange.endCoverage).format('YYYY-MM-DD'); return { beginCoverage, diff --git a/test/jest/__mock__/index.js b/test/jest/__mock__/index.js index adcd4bd96..b2feca12f 100644 --- a/test/jest/__mock__/index.js +++ b/test/jest/__mock__/index.js @@ -6,3 +6,4 @@ import './stripesCore.mock'; import './stripesIcon.mock'; import './stripesSmartComponent.mock'; import './matchMedia.mock'; +import './resizeObserver.mock'; diff --git a/test/jest/__mock__/reactIntl.mock.js b/test/jest/__mock__/reactIntl.mock.js index ce670ec7c..2c1aeb672 100644 --- a/test/jest/__mock__/reactIntl.mock.js +++ b/test/jest/__mock__/reactIntl.mock.js @@ -1,6 +1,7 @@ jest.mock('react-intl', () => { const intl = { formatMessage: ({ id }) => id, + locale: 'en' }; return { diff --git a/test/jest/__mock__/resizeObserver.mock.js b/test/jest/__mock__/resizeObserver.mock.js new file mode 100644 index 000000000..a7ac65db2 --- /dev/null +++ b/test/jest/__mock__/resizeObserver.mock.js @@ -0,0 +1,4 @@ +window.ResizeObserver = jest.fn(() => ({ + observe: jest.fn(), + unobserve: jest.fn(), +})); diff --git a/test/jest/helpers/harness.js b/test/jest/helpers/harness.js index dc017b5d4..3a963900d 100644 --- a/test/jest/helpers/harness.js +++ b/test/jest/helpers/harness.js @@ -50,7 +50,7 @@ const Harness = ({ - + {children}