@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.
- package/CHANGELOG.md +30 -0
- package/dist/components/article-flag/ArticleFlag.stories.js +21 -3
- package/dist/components/article-flag/LiveArticleFlag.js +13 -6
- package/dist/components/article-flag/styles.d.ts +1 -0
- package/dist/components/article-flag/styles.js +6 -1
- package/dist/components/in-article-puff/InArticlePuff.d.ts +1 -1
- package/dist/components/in-article-puff/InArticlePuff.js +6 -6
- package/dist/components/in-article-puff/InArticlePuff.stories.js +3 -3
- package/dist/components/updated-timestamp/UpdatedTimestamp.d.ts +4 -0
- package/dist/components/updated-timestamp/UpdatedTimestamp.js +21 -0
- package/dist/components/updated-timestamp/UpdatedTimestamp.stories.d.ts +1 -0
- package/dist/components/updated-timestamp/UpdatedTimestamp.stories.js +13 -0
- package/dist/components/updated-timestamp/__tests__/UpdatedTimestamp.test.d.ts +1 -0
- package/dist/components/updated-timestamp/__tests__/UpdatedTimestamp.test.js +34 -0
- package/dist/components/updated-timestamp/styles.d.ts +2 -0
- package/dist/components/updated-timestamp/styles.js +14 -0
- package/dist/helpers/time/UpdatedTimeProvider.d.ts +5 -0
- package/dist/helpers/time/UpdatedTimeProvider.js +9 -0
- package/dist/helpers/time/__tests__/UpdatedTimeProvider.test.d.ts +1 -0
- package/dist/helpers/time/__tests__/UpdatedTimeProvider.test.js +17 -0
- package/dist/helpers/tracking/TrackingContextProvider.js +11 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/package.json +5 -5
- package/rnw.js +1 -1
- package/src/components/article-flag/ArticleFlag.stories.tsx +28 -2
- package/src/components/article-flag/LiveArticleFlag.tsx +19 -9
- package/src/components/article-flag/__tests__/__snapshots__/ArticleFlag.test.tsx.snap +73 -73
- package/src/components/article-flag/__tests__/__snapshots__/LiveArticleFlag.test.tsx.snap +39 -27
- package/src/components/article-flag/styles.ts +6 -0
- package/src/components/article-header/__tests__/__snapshots__/ArticleHeader.test.tsx.snap +13 -9
- package/src/components/in-article-puff/InArticlePuff.stories.tsx +2 -2
- package/src/components/in-article-puff/InArticlePuff.tsx +6 -6
- package/src/components/updated-timestamp/UpdatedTimestamp.stories.tsx +18 -0
- package/src/components/updated-timestamp/UpdatedTimestamp.tsx +38 -0
- package/src/components/updated-timestamp/__tests__/UpdatedTimestamp.test.tsx +50 -0
- package/src/components/updated-timestamp/__tests__/__snapshots__/UpdatedTimestamp.test.tsx.snap +11 -0
- package/src/components/updated-timestamp/styles.ts +15 -0
- package/src/helpers/time/UpdatedTimeProvider.tsx +17 -0
- package/src/helpers/time/__tests__/UpdatedTimeProvider.test.tsx +23 -0
- package/src/helpers/tracking/TrackingContextProvider.tsx +14 -0
- 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
|
|
19
|
+
class="sc-gZMcBi erfHmy"
|
|
20
20
|
>
|
|
21
21
|
<div
|
|
22
|
-
class="sc-
|
|
22
|
+
class="sc-gqjmRU fwGLTx"
|
|
23
23
|
>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<div>
|
|
27
|
-
<span
|
|
28
|
-
class="sc-fjdhpX cvtGYv"
|
|
24
|
+
<div
|
|
25
|
+
class="sc-jTzLTM bTqqzd"
|
|
29
26
|
>
|
|
30
|
-
|
|
31
|
-
</
|
|
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
|
-
|
|
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"
|
|
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,
|
|
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:
|
|
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
|
-
|
|
59
|
-
}> = ({ sectionColour, forceImageAspectRatio,
|
|
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,
|
|
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:
|
|
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,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';
|