@times-components/ts-components 1.21.0 → 1.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/components/article-flag/ArticleFlag.stories.js +21 -3
  3. package/dist/components/article-flag/LiveArticleFlag.js +13 -6
  4. package/dist/components/article-flag/styles.d.ts +1 -0
  5. package/dist/components/article-flag/styles.js +6 -1
  6. package/dist/components/in-article-puff/InArticlePuff.d.ts +1 -1
  7. package/dist/components/in-article-puff/InArticlePuff.js +6 -6
  8. package/dist/components/in-article-puff/InArticlePuff.stories.js +3 -3
  9. package/dist/components/updated-timestamp/UpdatedTimestamp.d.ts +4 -0
  10. package/dist/components/updated-timestamp/UpdatedTimestamp.js +21 -0
  11. package/dist/components/updated-timestamp/UpdatedTimestamp.stories.d.ts +1 -0
  12. package/dist/components/updated-timestamp/UpdatedTimestamp.stories.js +13 -0
  13. package/dist/components/updated-timestamp/__tests__/UpdatedTimestamp.test.d.ts +1 -0
  14. package/dist/components/updated-timestamp/__tests__/UpdatedTimestamp.test.js +34 -0
  15. package/dist/components/updated-timestamp/styles.d.ts +2 -0
  16. package/dist/components/updated-timestamp/styles.js +14 -0
  17. package/dist/helpers/time/UpdatedTimeProvider.d.ts +5 -0
  18. package/dist/helpers/time/UpdatedTimeProvider.js +9 -0
  19. package/dist/helpers/time/__tests__/UpdatedTimeProvider.test.d.ts +1 -0
  20. package/dist/helpers/time/__tests__/UpdatedTimeProvider.test.js +17 -0
  21. package/dist/helpers/tracking/TrackingContextProvider.js +11 -1
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +3 -1
  24. package/package.json +5 -5
  25. package/rnw.js +1 -1
  26. package/src/components/article-flag/ArticleFlag.stories.tsx +28 -2
  27. package/src/components/article-flag/LiveArticleFlag.tsx +19 -9
  28. package/src/components/article-flag/__tests__/__snapshots__/ArticleFlag.test.tsx.snap +73 -73
  29. package/src/components/article-flag/__tests__/__snapshots__/LiveArticleFlag.test.tsx.snap +39 -27
  30. package/src/components/article-flag/styles.ts +6 -0
  31. package/src/components/article-header/__tests__/__snapshots__/ArticleHeader.test.tsx.snap +13 -9
  32. package/src/components/in-article-puff/InArticlePuff.stories.tsx +2 -2
  33. package/src/components/in-article-puff/InArticlePuff.tsx +6 -6
  34. package/src/components/updated-timestamp/UpdatedTimestamp.stories.tsx +18 -0
  35. package/src/components/updated-timestamp/UpdatedTimestamp.tsx +38 -0
  36. package/src/components/updated-timestamp/__tests__/UpdatedTimestamp.test.tsx +50 -0
  37. package/src/components/updated-timestamp/__tests__/__snapshots__/UpdatedTimestamp.test.tsx.snap +11 -0
  38. package/src/components/updated-timestamp/styles.ts +15 -0
  39. package/src/helpers/time/UpdatedTimeProvider.tsx +17 -0
  40. package/src/helpers/time/__tests__/UpdatedTimeProvider.test.tsx +23 -0
  41. package/src/helpers/tracking/TrackingContextProvider.tsx +14 -0
  42. package/src/index.ts +6 -0
@@ -16,19 +16,23 @@ exports[`ArticleHeader In one calendar day Within the first minute of update - B
16
16
  class="sc-dnqmqq bGasAc"
17
17
  >
18
18
  <div
19
- class="sc-gZMcBi bcfOTp"
19
+ class="sc-gZMcBi erfHmy"
20
20
  >
21
21
  <div
22
- class="sc-VigVT bvOrBW"
22
+ class="sc-gqjmRU fwGLTx"
23
23
  >
24
-
25
- </div>
26
- <div>
27
- <span
28
- class="sc-fjdhpX cvtGYv"
24
+ <div
25
+ class="sc-jTzLTM bTqqzd"
29
26
  >
30
- BREAKING
31
- </span>
27
+
28
+ </div>
29
+ <div>
30
+ <span
31
+ class="sc-jzJRlG erbwEj"
32
+ >
33
+ BREAKING
34
+ </span>
35
+ </div>
32
36
  </div>
33
37
  </div>
34
38
  </div>
@@ -34,12 +34,12 @@ storiesOf('Typescript Component/In Article/In Article Puff', module)
34
34
  <InArticlePuff
35
35
  sectionColour="#13354e"
36
36
  forceImageAspectRatio="3:2"
37
- isLiveOrBreakingFlag="breaking"
37
+ isLiveOrBreaking="breaking"
38
38
  />
39
39
  </FetchProvider>
40
40
  ))
41
41
  .add('No Image', () => (
42
42
  <FetchProvider previewData={previewData[41547]}>
43
- <InArticlePuff sectionColour="#184e13" isLiveOrBreakingFlag="live" />
43
+ <InArticlePuff sectionColour="#184e13" isLiveOrBreaking="live" />
44
44
  </FetchProvider>
45
45
  ));
@@ -43,26 +43,26 @@ const scrollEvent = {
43
43
  }
44
44
  };
45
45
 
46
- const clickEvent = (buttonLabel: string, isLiveOrBreakingFlag?: string) => ({
46
+ const clickEvent = (buttonLabel: string, isLiveOrBreaking?: string) => ({
47
47
  action: 'Clicked',
48
48
  attrs: {
49
49
  event_navigation_name: `button : ${buttonLabel}`,
50
50
  event_navigation_browsing_method: 'click',
51
- other_details: isLiveOrBreakingFlag
51
+ other_details: isLiveOrBreaking
52
52
  }
53
53
  });
54
54
 
55
55
  export const InArticlePuff: React.FC<{
56
56
  sectionColour: string;
57
57
  forceImageAspectRatio?: AspectRatios;
58
- isLiveOrBreakingFlag?: string;
59
- }> = ({ sectionColour, forceImageAspectRatio, isLiveOrBreakingFlag }) => {
58
+ isLiveOrBreaking?: string;
59
+ }> = ({ sectionColour, forceImageAspectRatio, isLiveOrBreaking }) => {
60
60
  const handleClick = (
61
61
  fireAnalyticsEvent: (evt: TrackingContext) => void,
62
62
  buttonLabel: string
63
63
  ) => {
64
64
  fireAnalyticsEvent &&
65
- fireAnalyticsEvent(clickEvent(buttonLabel, isLiveOrBreakingFlag));
65
+ fireAnalyticsEvent(clickEvent(buttonLabel, isLiveOrBreaking));
66
66
  };
67
67
 
68
68
  const { loading, error, data } = useFetch<InArticlePuffDeckData>();
@@ -98,7 +98,7 @@ export const InArticlePuff: React.FC<{
98
98
  component_type: 'in-article component : puff : interactive',
99
99
  event_navigation_action: 'navigation',
100
100
  component_name: `${headline}`,
101
- other_details: isLiveOrBreakingFlag
101
+ other_details: isLiveOrBreaking
102
102
  }
103
103
  }}
104
104
  scrolledEvent={scrollEvent}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { storiesOf } from '@storybook/react';
3
+ import { date } from '@storybook/addon-knobs';
4
+
5
+ import { UpdatedTimestamp } from './UpdatedTimestamp';
6
+
7
+ storiesOf('Typescript Component/Updated Timestamp', module).add(
8
+ 'Updated Timestamp',
9
+ () => {
10
+ const label = 'Updated Date/Time';
11
+ const defaultValue = new Date();
12
+ const groupId = 'Options';
13
+ const value = date(label, defaultValue, groupId);
14
+ const updated = new Date(value).toISOString();
15
+
16
+ return <UpdatedTimestamp updatedTime={updated} />;
17
+ }
18
+ );
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { differenceInSeconds, format, formatDistanceStrict } from 'date-fns';
3
+
4
+ import { Container, TimeSinceUpdate } from './styles';
5
+
6
+ export const UpdatedTimestamp: React.FC<{
7
+ updatedTime?: string;
8
+ }> = ({ updatedTime }) => {
9
+ if (!updatedTime) {
10
+ return null;
11
+ }
12
+ const currentDateTime = new Date();
13
+ const updatedDate = new Date(updatedTime);
14
+ const timeSincePublishing =
15
+ formatDistanceStrict(updatedDate, currentDateTime, {
16
+ roundingMethod: 'floor'
17
+ }) + ' ago';
18
+ const diffInSeconds = differenceInSeconds(currentDateTime, updatedDate);
19
+
20
+ const isLessThan1Minute = diffInSeconds < 60;
21
+ const isLessThan13Hours = diffInSeconds < 60 * 60 * 13;
22
+
23
+ return (
24
+ <Container>
25
+ {!isLessThan1Minute && isLessThan13Hours ? (
26
+ <TimeSinceUpdate data-testId="MinutesHoursSinceUpdate">
27
+ {`Updated ${timeSincePublishing}`}
28
+ </TimeSinceUpdate>
29
+ ) : !isLessThan13Hours ? (
30
+ <TimeSinceUpdate data-testId="DateTimeUpdated">
31
+ {`Updated `}
32
+ {format(updatedDate, 'MMMM d, ')}
33
+ {format(updatedDate, 'h.mmaaa')}
34
+ </TimeSinceUpdate>
35
+ ) : null}
36
+ </Container>
37
+ );
38
+ };
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+
5
+ import { UpdatedTimestamp } from '../UpdatedTimestamp';
6
+ import MockDate from 'mockdate';
7
+
8
+ describe('UpdatedTimestamp', () => {
9
+ const updated = '2022-02-28T09:00:00Z';
10
+ afterEach(() => MockDate.reset());
11
+
12
+ it('does not show the timestamp within the first minute after the last update', () => {
13
+ MockDate.set('2022-02-28T09:00:00Z');
14
+ const { baseElement, queryByTestId } = render(
15
+ <UpdatedTimestamp updatedTime={updated} />
16
+ );
17
+ expect(baseElement).toMatchSnapshot();
18
+ expect(queryByTestId('MinutesHoursSinceUpdate')).toBeFalsy();
19
+ });
20
+ it('appears one minute after the last update', () => {
21
+ MockDate.set('2022-02-28T09:01:00Z');
22
+ const { queryByTestId } = render(
23
+ <UpdatedTimestamp updatedTime={updated} />
24
+ );
25
+ expect(queryByTestId('MinutesHoursSinceUpdate')).toBeTruthy();
26
+ expect(queryByTestId('MinutesHoursSinceUpdate')!.textContent).toBe(
27
+ 'Updated 1 minute ago'
28
+ );
29
+ });
30
+ it('appears between 1 and 12 hours after the last update', () => {
31
+ MockDate.set('2022-02-28T11:30:00Z');
32
+ const { queryByTestId } = render(
33
+ <UpdatedTimestamp updatedTime={updated} />
34
+ );
35
+ expect(queryByTestId('MinutesHoursSinceUpdate')).toBeTruthy();
36
+ expect(queryByTestId('MinutesHoursSinceUpdate')!.textContent).toBe(
37
+ 'Updated 2 hours ago'
38
+ );
39
+ });
40
+ it('shows the date and time of update 13 hours or more after the last update', () => {
41
+ MockDate.set('2022-02-28T23:30:00Z');
42
+ const { queryByTestId } = render(
43
+ <UpdatedTimestamp updatedTime={updated} />
44
+ );
45
+ expect(queryByTestId('DateTimeUpdated')).toBeTruthy();
46
+ expect(queryByTestId('DateTimeUpdated')!.textContent).toBe(
47
+ 'Updated February 28, 9.00am'
48
+ );
49
+ });
50
+ });
@@ -0,0 +1,11 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`UpdatedTimestamp does not show the timestamp within the first minute after the last update 1`] = `
4
+ <body>
5
+ <div>
6
+ <div
7
+ class="sc-bdVaJa cSmEjS"
8
+ />
9
+ </div>
10
+ </body>
11
+ `;
@@ -0,0 +1,15 @@
1
+ import styled from 'styled-components';
2
+ import { colours, fonts } from '@times-components/styleguide';
3
+
4
+ export const Container = styled.div`
5
+ display: flex;
6
+ flex-direction: column;
7
+ padding: 3px 0 0 8px;
8
+ `;
9
+
10
+ export const TimeSinceUpdate = styled.div`
11
+ color: ${colours.functional.primary};
12
+ font-family: ${fonts.supporting};
13
+ font-size: 12px;
14
+ line-height: 16px;
15
+ `;
@@ -0,0 +1,17 @@
1
+ import React, { createContext, useContext } from 'react';
2
+
3
+ const UpdatedTimeProviderContext = createContext<string | undefined>(undefined);
4
+
5
+ export const UpdatedTimeProvider: React.FC<{
6
+ updatedTime: string;
7
+ }> = ({ updatedTime, children }) => {
8
+ return (
9
+ <UpdatedTimeProviderContext.Provider value={updatedTime}>
10
+ {children}
11
+ </UpdatedTimeProviderContext.Provider>
12
+ );
13
+ };
14
+
15
+ export const useUpdatedTime = () => {
16
+ return useContext(UpdatedTimeProviderContext);
17
+ };
@@ -0,0 +1,23 @@
1
+ import { render } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { useUpdatedTime, UpdatedTimeProvider } from '../UpdatedTimeProvider';
4
+ import 'regenerator-runtime';
5
+
6
+ const TestComponent = () => {
7
+ const updatedTime = useUpdatedTime();
8
+ return <>{updatedTime}</>;
9
+ };
10
+
11
+ describe('UpdatedTimeProvider', () => {
12
+ it('should pass the updated time to the context value', () => {
13
+ const updatedTime = '2022-03-01T09:00:00.000Z';
14
+
15
+ const { findByText } = render(
16
+ <UpdatedTimeProvider updatedTime={updatedTime}>
17
+ <TestComponent />
18
+ </UpdatedTimeProvider>
19
+ );
20
+
21
+ findByText(updatedTime);
22
+ });
23
+ });
@@ -45,21 +45,35 @@ export const TrackingContextProvider = ({
45
45
  context,
46
46
  scrolledEvent
47
47
  }: TrackingContextProps & TrackingContextChildren) => {
48
+ // tslint:disable-next-line:no-console
49
+ console.log('TC log: TCP: ==========');
50
+
48
51
  const parentTrackingContext = useContext(TrackingContext);
52
+ // tslint:disable-next-line:no-console
53
+ console.log('TC log: TCP: parent=', parentTrackingContext.context);
54
+
49
55
  const stream =
50
56
  analyticsStream !== undefined
51
57
  ? analyticsStream
52
58
  : parentTrackingContext.analyticsStream;
53
59
 
54
60
  const aggregatedContext = merge({}, parentTrackingContext.context, context);
61
+ // tslint:disable-next-line:no-console
62
+ console.log('TC log: TCP: aggregated=', aggregatedContext);
55
63
 
56
64
  const fireAnalyticsEvent = (event: TrackingContext) => {
65
+ // tslint:disable-next-line:no-console
66
+ console.log('TC log: TCP: fireEvent=', event);
67
+
57
68
  const aggregatedEvent = merge({}, aggregatedContext, event, {
58
69
  attrs: {
59
70
  eventTime: new Date().toISOString()
60
71
  }
61
72
  });
62
73
 
74
+ // tslint:disable-next-line:no-console
75
+ console.log('TC log: TCP: fireAggregated=', aggregatedEvent);
76
+
63
77
  stream
64
78
  ? stream(aggregatedEvent)
65
79
  : // tslint:disable-next-line:no-console
package/src/index.ts CHANGED
@@ -88,6 +88,12 @@ export {
88
88
  default as ArticleHeader
89
89
  } from './components/article-header/ArticleHeader';
90
90
 
91
+ export {
92
+ UpdatedTimestamp
93
+ } from './components/updated-timestamp/UpdatedTimestamp';
94
+
95
+ export { UpdatedTimeProvider } from './helpers/time/UpdatedTimeProvider';
96
+
91
97
  export {
92
98
  default as safeDecodeURIComponent
93
99
  } from './utils/safeDecodeURIComponent';