Skip to content

Commit 68114df

Browse files
Look ma, no momentjs! (#2910)
* WIP * More developments * Enable the format prop; add FormattedI18nDate story * WIP on adding relative formatted date * Rename to FormattedDate, move date utils to helpers/Utils/Date * Add impl and test for formatRelativeDate * Add support for the style * Rename to FormattedRelativeDate * Upgrade jest * Update History snapshot as it is now more correct * Add support for classNames; update snapshots; no need to mock momentjs * Allow passing the locale to date formatting utils * Try to fix problem on CI * Remove intl hack * Remove intl hack * Avoid platform differences * Add full-icu * Avoid platform differences * WIP Add support for formatToParts * Add Splitparts story * Add FormattedRelativeDate story * Add relative to date story * Add live refresh to relative date * Fix display of relative date in ContentsUploadModal * Fix display of relative date in ModerateComments * Add some test for parseDateTime * Lazyload momentjs in dates display * Use lazyload moment in RecurrenceWidget and Occurences * More lazyload momentjs * More lazyload momentjs * Update changelog * Fix use of moment lib * Update yarn.lock * Testing CI build, remove full-icu from test command * Bring back full-icu env option to make it build for node v12 Co-authored-by: Tiberiu Ichim <[email protected]>
1 parent 023b85e commit 68114df

39 files changed

+2090
-158
lines changed

Diff for: CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66

77
### Feature
88

9+
- Add `<FormattedDate>` and `<FormattedRelativeDate>` components. Check their Storybook stories for details. This is part of ongoing work to minimize the use of 'deprecated' momentjs. @sneridagh @tiberiuichim
10+
911
### Bugfix
1012

1113
### Internal
1214

15+
- Upgrade jest to latest release, 27 major. @tiberiuichim
16+
- Lazyload momentjs. `parseDateTime` helper now requires passing the momentjs library @tiberiuichim
17+
18+
- Lazyload react-beautiful-dnd @tiberiuichim
1319
## 14.6.0 (2022-01-27)
1420

1521
### Feature

Diff for: package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"build": "razzle build",
3636
"build-spa": "razzle build --type=spa",
3737
"test": "razzle test --env=jest-environment-jsdom-sixteen --maxWorkers=50%",
38-
"test:ci": "CI=true razzle test --env=jest-environment-jsdom-sixteen",
38+
"test:ci": "CI=true NODE_ICU_DATA=node_modules/full-icu razzle test --env=jest-environment-jsdom-sixteen",
3939
"test:husky": "CI=true yarn test --bail --findRelatedTests",
4040
"test:debug": "node --inspect node_modules/.bin/jest --runInBand",
4141
"start:prod": "NODE_ENV=production node build/server.js",
@@ -414,7 +414,9 @@
414414
"@storybook/react": "^6.3.0",
415415
"babel-loader": "^8.1.0",
416416
"crypto-random-string": "3.2.0",
417+
"full-icu": "1.4.0",
417418
"identity-obj-proxy": "3.0.0",
419+
"jest": "27.4.5",
418420
"jest-environment-jsdom-sixteen": "1.0.3",
419421
"react-is": "^16.13.1",
420422
"tmp": "0.2.1",

Diff for: src/components/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,7 @@ export ToCSettingsSchema from '@plone/volto/components/manage/Blocks/ToC/Schema'
198198

199199
export MaybeWrap from '@plone/volto/components/manage/MaybeWrap/MaybeWrap';
200200
export ContentMetadataTags from '@plone/volto/components/theme/ContentMetadataTags/ContentMetadataTags';
201+
export FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
202+
export FormattedRelativeDate from '@plone/volto/components/theme/FormattedDate/FormattedRelativeDate';
201203

202204
export App from '@plone/volto/components/theme/App/App';

Diff for: src/components/manage/Contents/Contents.test.jsx

-7
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,6 @@ jest.mock('./ContentsUploadModal', () =>
2424
jest.fn(() => <div className="UploadModal" />),
2525
);
2626

27-
jest.mock('moment', () =>
28-
jest.fn(() => ({
29-
format: jest.fn(() => 'Sunday, April 23, 2017 3:38 AM'),
30-
fromNow: jest.fn(() => 'a few seconds ago'),
31-
})),
32-
);
33-
3427
describe('Contents', () => {
3528
it('renders a folder contents view component', () => {
3629
const store = mockStore({

Diff for: src/components/manage/Contents/ContentsItem.jsx

+9-14
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import { Button, Dropdown, Table } from 'semantic-ui-react';
88
import { Link } from 'react-router-dom';
99
import PropTypes from 'prop-types';
1010
import { map } from 'lodash';
11-
import moment from 'moment';
1211
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
13-
import { Icon, Circle } from '@plone/volto/components';
12+
import { Circle, FormattedDate, Icon } from '@plone/volto/components';
1413
import { getContentIcon } from '@plone/volto/helpers';
1514
import moreSVG from '@plone/volto/icons/more.svg';
1615
import checkboxUncheckedSVG from '@plone/volto/icons/checkbox-unchecked.svg';
@@ -48,6 +47,10 @@ const messages = defineMessages({
4847
id: 'no workflow state',
4948
defaultMessage: 'No workflow state',
5049
},
50+
none: {
51+
id: 'None',
52+
defaultMessage: 'None',
53+
},
5154
});
5255

5356
function getColor(string) {
@@ -187,21 +190,13 @@ export const ContentsItemComponent = ({
187190
</div>
188191
)}
189192
{index.type === 'date' && (
190-
<span
191-
title={
192-
item[index.id] !== 'None' ? (
193-
moment(item[index.id]).format('LLLL')
194-
) : (
195-
<FormattedMessage id="None" defaultMessage="None" />
196-
)
197-
}
198-
>
193+
<>
199194
{item[index.id] !== 'None' ? (
200-
moment(item[index.id]).format('L')
195+
<FormattedDate date={item[index.id]} />
201196
) : (
202-
<FormattedMessage id="None" defaultMessage="None" />
197+
intl.formatMessage(messages.none)
203198
)}
204-
</span>
199+
</>
205200
)}
206201
{index.type === 'array' && (
207202
<span>{item[index.id]?.join(', ')}</span>

Diff for: src/components/manage/Contents/ContentsUploadModal.jsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ import {
2020
} from 'semantic-ui-react';
2121
import loadable from '@loadable/component';
2222
import { concat, filter, map } from 'lodash';
23-
import moment from 'moment';
2423
import filesize from 'filesize';
2524
import { readAsDataURL } from 'promise-file-reader';
2625
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
26+
import { FormattedRelativeDate } from '@plone/volto/components';
2727
import { createContent } from '@plone/volto/actions';
2828

2929
const Dropzone = loadable(() => import('react-dropzone'));
@@ -180,8 +180,6 @@ class ContentsUploadModal extends Component {
180180
* @returns {string} Markup for the component.
181181
*/
182182
render() {
183-
moment.locale(this.props.intl.locale);
184-
185183
return (
186184
this.props.open && (
187185
<Modal open={this.props.open}>
@@ -269,7 +267,7 @@ class ContentsUploadModal extends Component {
269267
<Table.Row className="upload-row" key={file.name}>
270268
<Table.Cell>{file.name}</Table.Cell>
271269
<Table.Cell>
272-
{moment(file.lastModifiedDate).fromNow()}
270+
<FormattedRelativeDate date={file.lastModifiedDate} />
273271
</Table.Cell>
274272
<Table.Cell>
275273
{filesize(file.size, { round: 0 })}

Diff for: src/components/manage/Controlpanels/ModerateComments.jsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ import { Link } from 'react-router-dom';
1111
import { getParentUrl, Helmet } from '@plone/volto/helpers';
1212
import { Portal } from 'react-portal';
1313
import { Container, Button, Table } from 'semantic-ui-react';
14-
import moment from 'moment';
1514
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
1615

1716
import { deleteComment, searchContent } from '@plone/volto/actions';
18-
import { CommentEditModal, Icon, Toolbar } from '@plone/volto/components';
17+
import {
18+
CommentEditModal,
19+
FormattedRelativeDate,
20+
Icon,
21+
Toolbar,
22+
} from '@plone/volto/components';
1923

2024
import backSVG from '@plone/volto/icons/back.svg';
2125

@@ -230,9 +234,7 @@ class ModerateComments extends Component {
230234
<Table.Row key={item['@id']}>
231235
<Table.Cell>{item.author_name}</Table.Cell>
232236
<Table.Cell>
233-
<span title={moment(item.creation_date).format('LLLL')}>
234-
{moment(item.creation_date).fromNow()}
235-
</span>
237+
<FormattedRelativeDate date={item.creation_date} />
236238
</Table.Cell>
237239
<Table.Cell>{item.text.data}</Table.Cell>
238240
<Table.Cell>

Diff for: src/components/manage/Diff/Diff.jsx

+13-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { filter, isEqual, map } from 'lodash';
1212
import { Container, Button, Dropdown, Grid, Table } from 'semantic-ui-react';
1313
import { Link, withRouter } from 'react-router-dom';
1414
import { Portal } from 'react-portal';
15-
import moment from 'moment';
1615
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
1716
import qs from 'query-string';
1817

@@ -23,7 +22,12 @@ import {
2322
getBlocksLayoutFieldname,
2423
hasBlocksData,
2524
} from '@plone/volto/helpers';
26-
import { DiffField, Icon, Toolbar } from '@plone/volto/components';
25+
import {
26+
DiffField,
27+
FormattedDate,
28+
Icon,
29+
Toolbar,
30+
} from '@plone/volto/components';
2731

2832
import backSVG from '@plone/volto/icons/back.svg';
2933

@@ -189,9 +193,13 @@ class Diff extends Component {
189193
const versions = map(
190194
filter(this.props.historyEntries, (entry) => 'version' in entry),
191195
(entry, index) => ({
192-
text: `${index === 0 ? 'Current' : entry.version} (${moment(
193-
entry.time,
194-
).format('LLLL')}, ${entry.actor.fullname})`,
196+
text: (
197+
<>
198+
{index === 0 ? 'Current' : entry.version}&nbsp;(
199+
<FormattedDate date={entry.time} long className="text" />, &nbsp;
200+
{entry.actor.fullname})
201+
</>
202+
),
195203
value: `${entry.version}`,
196204
key: `${entry.version}`,
197205
}),

Diff for: src/components/manage/Diff/Diff.test.jsx

-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from 'react';
2-
// import renderer from 'react-test-renderer';
32
import configureStore from 'redux-mock-store';
43
import { Provider } from 'react-intl-redux';
54
import { MemoryRouter } from 'react-router-dom';
@@ -12,11 +11,6 @@ const mockStore = configureStore();
1211
jest.mock('react-portal', () => ({
1312
Portal: jest.fn(() => <div id="Portal" />),
1413
}));
15-
jest.mock('moment', () =>
16-
jest.fn(() => ({
17-
format: jest.fn(() => 'Sunday, April 23, 2017 3:38 AM'),
18-
})),
19-
);
2014

2115
jest.mock('@plone/volto/helpers/Loadable/Loadable');
2216
beforeAll(

Diff for: src/components/manage/Diff/DiffField.jsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import React from 'react';
88
import { join, map } from 'lodash';
99
import PropTypes from 'prop-types';
1010
import { Table } from 'semantic-ui-react';
11-
import moment from 'moment';
1211
import ReactDOMServer from 'react-dom/server';
1312
import { Provider } from 'react-intl-redux';
1413
import { createBrowserHistory } from 'history';
1514
import { ConnectedRouter } from 'connected-react-router';
15+
import { useSelector } from 'react-redux';
1616

1717
import { Api } from '@plone/volto/helpers';
1818
import configureStore from '@plone/volto/store';
@@ -44,6 +44,11 @@ const DiffField = ({
4444
schema,
4545
diffLib,
4646
}) => {
47+
const language = useSelector((state) => state.intl.locale);
48+
const readable_date_format = {
49+
dateStyle: 'full',
50+
timeStyle: 'short',
51+
};
4752
const diffWords = (oneStr, twoStr) => {
4853
return diffLib.diffWords(String(oneStr), String(twoStr));
4954
};
@@ -56,8 +61,12 @@ const DiffField = ({
5661
break;
5762
case 'datetime':
5863
parts = diffWords(
59-
moment(one).format('LLLL'),
60-
moment(two).format('LLLL'),
64+
new Intl.DateTimeFormat(language, readable_date_format).format(
65+
new Date(one),
66+
),
67+
new Intl.DateTimeFormat(language, readable_date_format).format(
68+
new Date(two),
69+
),
6170
);
6271
break;
6372
case 'json':

Diff for: src/components/manage/Diff/DiffField.test.jsx

-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ import { waitFor, render, screen } from '@testing-library/react';
55

66
import DiffField from './DiffField';
77

8-
jest.mock('moment', () =>
9-
jest.fn(() => ({
10-
format: jest.fn(() => 'Sunday, April 23, 2017 3:38 AM'),
11-
})),
12-
);
13-
148
jest.mock('@plone/volto/helpers/Loadable/Loadable');
159
beforeAll(
1610
async () =>

0 commit comments

Comments
 (0)