@quintype/native-components 2.20.0-fix-rtl-issues.0 → 2.20.1-temp-fast-image-constraint.0
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 +46 -0
- package/package.json +2 -2
- package/src/Icons/ClockIcon/index.js +9 -5
- package/src/components/ActionText/ActionText.js +7 -9
- package/src/components/ActionText/ActionText.test.js +5 -12
- package/src/components/AlsoRead/index.js +1 -1
- package/src/components/AlsoRead/styles.js +2 -0
- package/src/components/AuthorRow/AuthorRow.test.js +4 -9
- package/src/components/AuthorRow/index.js +23 -21
- package/src/components/BackNavigator/styles.js +2 -0
- package/src/components/Button/index.js +13 -9
- package/src/components/CustomSwitch/index.js +16 -10
- package/src/components/Header/index.js +13 -9
- package/src/components/PrimaryStoryCard/index.js +46 -21
- package/src/components/PrimaryStoryCard/styles.js +29 -5
- package/src/components/PrimaryStoryCardNew/index.js +64 -26
- package/src/components/PrimaryStoryCardNew/styles.js +29 -5
- package/src/components/RadioButton/index.js +24 -9
- package/src/components/SecondaryStoryCard/index.js +48 -19
- package/src/components/SecondaryStoryCard/styles.js +29 -4
- package/src/components/SecondaryStoryCardNew/index.js +68 -26
- package/src/components/SecondaryStoryCardNew/styles.js +28 -4
- package/src/components/ShareButton/index.js +18 -14
- package/src/components/StoryHeader/index.js +9 -11
- package/src/components/StoryHeader/styles.js +1 -1
- package/src/components/StoryImage/index.js +1 -1
- package/src/components/StoryText/index.js +3 -1
- package/src/components/Table/index.js +1 -1
- package/src/components/Table/styles.js +5 -2
- package/src/components/TextQandA/styles.js +3 -3
- package/src/constants/component-constants/content-constants/constants.js +7 -5
- package/src/constants/component-constants/general-constants/constants.js +22 -14
- package/src/constants/renderHTML.js +10 -0
- package/src/utils/timeUtils.js +2 -2
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import { throttle } from
|
|
2
|
-
import PropTypes from
|
|
3
|
-
import React, { useContext, memo } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
} from 'react-native';
|
|
1
|
+
import { get, throttle } from "lodash";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import React, { useContext, memo } from "react";
|
|
4
|
+
import { StyleSheet, TouchableOpacity, View } from "react-native";
|
|
5
|
+
import Icon from "react-native-vector-icons/FontAwesome";
|
|
7
6
|
import {
|
|
8
7
|
AppTheme,
|
|
9
8
|
getImageMetadata,
|
|
10
9
|
getImageSlug,
|
|
11
10
|
getTimeForStoryCards,
|
|
12
|
-
} from
|
|
13
|
-
import { getStoryHeadline } from
|
|
14
|
-
import { ResponsiveImage, Text } from
|
|
15
|
-
import { storyStyles } from
|
|
11
|
+
} from "../../utils";
|
|
12
|
+
import { getStoryHeadline } from "../../utils/story";
|
|
13
|
+
import { ResponsiveImage, Text } from "../index";
|
|
14
|
+
import { storyStyles } from "./styles";
|
|
15
|
+
import { COMP_GENERAL_CONSTANTS } from "../../constants/component-constants/general-constants/constants";
|
|
16
16
|
|
|
17
17
|
const PrimaryStoryCardNewBase = (props) => {
|
|
18
18
|
const { story = {} } = props;
|
|
19
19
|
const { theme } = useContext(AppTheme);
|
|
20
|
-
const { COLORS, FONT_SIZE, locale } = theme || {};
|
|
20
|
+
const { COLORS, FONT_SIZE, locale, DARK_MODE } = theme || {};
|
|
21
|
+
|
|
22
|
+
const translate = get(theme, ["translate"], (word) => word);
|
|
21
23
|
|
|
22
|
-
const styles = storyStyles(COLORS, FONT_SIZE);
|
|
24
|
+
const styles = storyStyles(COLORS, FONT_SIZE, DARK_MODE);
|
|
23
25
|
const containerStyle = StyleSheet.flatten([
|
|
24
26
|
styles.container,
|
|
25
27
|
{ paddingHorizontal: props.horizontalPadding },
|
|
@@ -33,14 +35,43 @@ const PrimaryStoryCardNewBase = (props) => {
|
|
|
33
35
|
props.timestampStyle,
|
|
34
36
|
]);
|
|
35
37
|
|
|
36
|
-
const DATE_FORMAT =
|
|
37
|
-
const readTime = story[
|
|
38
|
+
const DATE_FORMAT = "d MMM, yyyy";
|
|
39
|
+
const readTime = story["read-time"]
|
|
40
|
+
? `${story["read-time"]} ${translate("min read")} · `
|
|
41
|
+
: "";
|
|
38
42
|
|
|
39
43
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
40
44
|
|
|
45
|
+
const showIcon = (name) => (
|
|
46
|
+
<View style={styles.storyType}>
|
|
47
|
+
<Icon name={name} size={22} color={COLORS.BRAND_BLACK} />
|
|
48
|
+
</View>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const showLiveBlogIcon = () => (
|
|
52
|
+
<View style={styles.storyType}>
|
|
53
|
+
<View style={styles.liveBlogIcon} />
|
|
54
|
+
<Text style={styles.liveBlogText}>LIVE</Text>
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
const showStoryType = () => {
|
|
58
|
+
switch (story["story-template"]) {
|
|
59
|
+
case "text":
|
|
60
|
+
return null;
|
|
61
|
+
case "photo":
|
|
62
|
+
return showIcon("photo");
|
|
63
|
+
case "video":
|
|
64
|
+
return showIcon("play");
|
|
65
|
+
case "live-blog":
|
|
66
|
+
return showLiveBlogIcon();
|
|
67
|
+
default:
|
|
68
|
+
null;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
41
72
|
return (
|
|
42
73
|
<TouchableOpacity
|
|
43
|
-
testID=
|
|
74
|
+
testID={COMP_GENERAL_CONSTANTS.primaryStoryCard}
|
|
44
75
|
onPress={throttledOnpress}
|
|
45
76
|
activeOpacity={0.8}
|
|
46
77
|
style={containerStyle}
|
|
@@ -50,7 +81,9 @@ const PrimaryStoryCardNewBase = (props) => {
|
|
|
50
81
|
slug={getImageSlug(story)}
|
|
51
82
|
cdn={props.cdn}
|
|
52
83
|
imageWidth={props.imageWidth}
|
|
53
|
-
|
|
84
|
+
>
|
|
85
|
+
<View style={styles.storyTypeContainer}>{showStoryType()}</View>
|
|
86
|
+
</ResponsiveImage>
|
|
54
87
|
<View style={styles.contentContainer}>
|
|
55
88
|
<View style={styles.headlineAndTimestampContainer}>
|
|
56
89
|
<Text
|
|
@@ -58,18 +91,23 @@ const PrimaryStoryCardNewBase = (props) => {
|
|
|
58
91
|
numberOfLines={3}
|
|
59
92
|
ellipsizeMode="tail"
|
|
60
93
|
style={headlineStyle}
|
|
61
|
-
testID=
|
|
94
|
+
testID={COMP_GENERAL_CONSTANTS.primaryStoryHeadline}
|
|
62
95
|
>
|
|
63
96
|
{getStoryHeadline(story)}
|
|
64
97
|
</Text>
|
|
65
|
-
<
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
98
|
+
<Text
|
|
99
|
+
style={timestampStyle}
|
|
100
|
+
numberOfLines={2}
|
|
101
|
+
// TODO: Add corrected testID here
|
|
102
|
+
>
|
|
103
|
+
{readTime +
|
|
104
|
+
getTimeForStoryCards(
|
|
105
|
+
story["published-at"],
|
|
106
|
+
DATE_FORMAT,
|
|
107
|
+
locale,
|
|
108
|
+
translate
|
|
109
|
+
)}
|
|
110
|
+
</Text>
|
|
73
111
|
</View>
|
|
74
112
|
<View style={styles.icon}>{props.iconComponent}</View>
|
|
75
113
|
</View>
|
|
@@ -89,7 +127,7 @@ PrimaryStoryCardNewBase.propTypes = {
|
|
|
89
127
|
};
|
|
90
128
|
|
|
91
129
|
PrimaryStoryCardNewBase.defaultProps = {
|
|
92
|
-
cdn:
|
|
130
|
+
cdn: "",
|
|
93
131
|
horizontalPadding: 12,
|
|
94
132
|
};
|
|
95
133
|
|
|
@@ -12,16 +12,12 @@ export const storyStyles = (COLORS = {}, FONT_SIZE = {}) => ({
|
|
|
12
12
|
flexShrink: 1,
|
|
13
13
|
flex: 1,
|
|
14
14
|
},
|
|
15
|
-
timestampContainer: {
|
|
16
|
-
alignItems: 'center',
|
|
17
|
-
flexDirection: 'row',
|
|
18
|
-
marginTop: 4,
|
|
19
|
-
},
|
|
20
15
|
timestamp: {
|
|
21
16
|
color: COLORS?.BRAND_BLACK,
|
|
22
17
|
fontSize: FONT_SIZE.h5,
|
|
23
18
|
lineHeight: FONT_SIZE.h5 * 1.2,
|
|
24
19
|
opacity: 0.6,
|
|
20
|
+
marginTop: 4,
|
|
25
21
|
},
|
|
26
22
|
headline: {
|
|
27
23
|
fontSize: FONT_SIZE.title,
|
|
@@ -33,4 +29,32 @@ export const storyStyles = (COLORS = {}, FONT_SIZE = {}) => ({
|
|
|
33
29
|
icon: {
|
|
34
30
|
marginLeft: 8,
|
|
35
31
|
},
|
|
32
|
+
storyTypeContainer: {
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
bottom: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
},
|
|
37
|
+
storyType: {
|
|
38
|
+
backgroundColor: COLORS.MONO1,
|
|
39
|
+
padding: 8,
|
|
40
|
+
justifyContent: 'space-between',
|
|
41
|
+
alignItems: 'space-between',
|
|
42
|
+
flexDirection: 'row',
|
|
43
|
+
},
|
|
44
|
+
storyTypeText: {
|
|
45
|
+
color: COLORS.MONO7,
|
|
46
|
+
fontSize: FONT_SIZE.h5,
|
|
47
|
+
},
|
|
48
|
+
liveBlogText: {
|
|
49
|
+
color: COLORS.MONO7,
|
|
50
|
+
fontSize: FONT_SIZE.h4,
|
|
51
|
+
marginLeft: 10,
|
|
52
|
+
fontWeight: 'bold',
|
|
53
|
+
},
|
|
54
|
+
liveBlogIcon: {
|
|
55
|
+
height: 15,
|
|
56
|
+
width: 15,
|
|
57
|
+
borderRadius: 50,
|
|
58
|
+
backgroundColor: COLORS.BRAND_3,
|
|
59
|
+
},
|
|
36
60
|
});
|
|
@@ -1,22 +1,37 @@
|
|
|
1
|
-
import React, { useContext } from
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
2
|
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
StyleSheet,
|
|
4
|
+
View,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
ViewPropTypes,
|
|
7
|
+
} from "react-native";
|
|
8
|
+
import PropTypes from "prop-types";
|
|
9
|
+
import { radioButtonStyles } from "./styles";
|
|
10
|
+
import { AppTheme } from "../../utils";
|
|
11
|
+
|
|
12
|
+
import { COMP_GENERAL_CONSTANTS } from "../../constants/component-constants";
|
|
8
13
|
|
|
9
14
|
export const RadioButton = ({
|
|
10
|
-
onPress,
|
|
15
|
+
onPress,
|
|
16
|
+
isChecked,
|
|
17
|
+
circleStyle,
|
|
18
|
+
checkedCircleStyle,
|
|
11
19
|
}) => {
|
|
12
20
|
const { theme } = useContext(AppTheme);
|
|
13
21
|
const styles = radioButtonStyles(theme);
|
|
14
22
|
const circleBorderStyle = StyleSheet.flatten([styles.circle, circleStyle]);
|
|
15
|
-
const checkedStyle = StyleSheet.flatten([
|
|
23
|
+
const checkedStyle = StyleSheet.flatten([
|
|
24
|
+
styles.checkedCircle,
|
|
25
|
+
checkedCircleStyle,
|
|
26
|
+
]);
|
|
16
27
|
|
|
17
28
|
return (
|
|
18
29
|
<View>
|
|
19
|
-
<TouchableOpacity
|
|
30
|
+
<TouchableOpacity
|
|
31
|
+
style={circleBorderStyle}
|
|
32
|
+
onPress={onPress}
|
|
33
|
+
testID={COMP_GENERAL_CONSTANTS.radioButtonTouch}
|
|
34
|
+
>
|
|
20
35
|
{isChecked && <View style={checkedStyle} />}
|
|
21
36
|
</TouchableOpacity>
|
|
22
37
|
</View>
|
|
@@ -3,7 +3,6 @@ import get from 'lodash/get';
|
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import React, { useContext } from 'react';
|
|
5
5
|
import {
|
|
6
|
-
I18nManager,
|
|
7
6
|
Image,
|
|
8
7
|
StyleSheet,
|
|
9
8
|
TouchableOpacity,
|
|
@@ -11,11 +10,12 @@ import {
|
|
|
11
10
|
TextStyle,
|
|
12
11
|
TouchableOpacityProps,
|
|
13
12
|
} from 'react-native';
|
|
13
|
+
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
14
14
|
import {
|
|
15
15
|
AppTheme,
|
|
16
16
|
getImageMetadata,
|
|
17
17
|
getImageSlug,
|
|
18
|
-
|
|
18
|
+
getTimeForStoryCards,
|
|
19
19
|
} from '../../utils';
|
|
20
20
|
import { getStoryHeadline } from '../../utils/story';
|
|
21
21
|
import { ResponsiveImage, Text } from '../index';
|
|
@@ -26,11 +26,11 @@ export const SecondaryStoryCard = (props) => {
|
|
|
26
26
|
const { theme } = useContext(AppTheme);
|
|
27
27
|
const translate = get(theme, ['translate'], (word) => word);
|
|
28
28
|
|
|
29
|
-
const { locale } = theme;
|
|
29
|
+
const { locale, COLORS } = theme;
|
|
30
30
|
const styles = secStoryCardStyles(theme);
|
|
31
31
|
const { story = {} } = props;
|
|
32
32
|
|
|
33
|
-
const DATE_FORMAT =
|
|
33
|
+
const DATE_FORMAT = 'd MMM, yyyy';
|
|
34
34
|
|
|
35
35
|
const containerStyle = StyleSheet.flatten([
|
|
36
36
|
styles.container,
|
|
@@ -51,9 +51,38 @@ export const SecondaryStoryCard = (props) => {
|
|
|
51
51
|
]);
|
|
52
52
|
const name = get(story.authors, [0, 'name']);
|
|
53
53
|
const authorName = name ? `${translate('By')} ${name} | ` : '';
|
|
54
|
-
const readTime = story['read-time'] ? `${story['read-time']} ${translate(
|
|
54
|
+
const readTime = story['read-time'] ? `${story['read-time']} ${translate('min read')}` : '';
|
|
55
55
|
|
|
56
56
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
57
|
+
|
|
58
|
+
const showIcon = (name) => (
|
|
59
|
+
<View style={styles.storyType}>
|
|
60
|
+
<Icon name={name} size={14} color={COLORS.MONO7} />
|
|
61
|
+
</View>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const showLiveBlogIcon = () => (
|
|
65
|
+
<View style={styles.storyType}>
|
|
66
|
+
<View style={styles.liveBlogIcon} />
|
|
67
|
+
<Text style={styles.liveBlogText}>LIVE</Text>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const showStoryType = () => {
|
|
72
|
+
switch (story['story-template']) {
|
|
73
|
+
case 'text':
|
|
74
|
+
return null;
|
|
75
|
+
case 'photo':
|
|
76
|
+
return showIcon('photo');
|
|
77
|
+
case 'video':
|
|
78
|
+
return showIcon('play');
|
|
79
|
+
case 'live-blog':
|
|
80
|
+
return showLiveBlogIcon();
|
|
81
|
+
default:
|
|
82
|
+
null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
57
86
|
return (
|
|
58
87
|
<TouchableOpacity
|
|
59
88
|
testID={COMP_GENERAL_CONSTANTS.secondaryStoryCard}
|
|
@@ -74,6 +103,7 @@ export const SecondaryStoryCard = (props) => {
|
|
|
74
103
|
</View>
|
|
75
104
|
)}
|
|
76
105
|
</Text>
|
|
106
|
+
<View style={styles.storyTypeContainer}>{showStoryType()}</View>
|
|
77
107
|
</ResponsiveImage>
|
|
78
108
|
<View style={styles.headlineAndAuthorBlockContainer}>
|
|
79
109
|
<Text
|
|
@@ -86,20 +116,19 @@ export const SecondaryStoryCard = (props) => {
|
|
|
86
116
|
{getStoryHeadline(story)?.trim()}
|
|
87
117
|
</Text>
|
|
88
118
|
<View style={styles.authorAndIconContainer}>
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
</View>
|
|
119
|
+
<Text
|
|
120
|
+
style={authorTextStyle}
|
|
121
|
+
numberOfLines={2}
|
|
122
|
+
// TODO: Add corrected testID here
|
|
123
|
+
>
|
|
124
|
+
{authorName +
|
|
125
|
+
getTimeForStoryCards(
|
|
126
|
+
story["published-at"],
|
|
127
|
+
DATE_FORMAT,
|
|
128
|
+
locale,
|
|
129
|
+
translate
|
|
130
|
+
)}
|
|
131
|
+
</Text>
|
|
103
132
|
<View style={iconStyles}>{props.iconComponent}</View>
|
|
104
133
|
</View>
|
|
105
134
|
</View>
|
|
@@ -22,10 +22,7 @@ export const secStoryCardStyles = ({ COLORS, FONT_SIZE, DARK_MODE }) => StyleShe
|
|
|
22
22
|
lineHeight: FONT_SIZE.h6 * 1.3,
|
|
23
23
|
opacity: 0.5,
|
|
24
24
|
fontWeight: '500',
|
|
25
|
-
|
|
26
|
-
authorTextContainer: {
|
|
27
|
-
alignItems: 'center',
|
|
28
|
-
flexDirection: 'row',
|
|
25
|
+
paddingTop: 8,
|
|
29
26
|
},
|
|
30
27
|
headline: {
|
|
31
28
|
color: COLORS.BRAND_BLACK,
|
|
@@ -51,4 +48,32 @@ export const secStoryCardStyles = ({ COLORS, FONT_SIZE, DARK_MODE }) => StyleShe
|
|
|
51
48
|
color: COLORS.BRAND_BLACK,
|
|
52
49
|
fontSize: FONT_SIZE.h5,
|
|
53
50
|
},
|
|
51
|
+
storyTypeContainer: {
|
|
52
|
+
position: 'absolute',
|
|
53
|
+
backgroundColor: COLORS.MONO1,
|
|
54
|
+
bottom: 0,
|
|
55
|
+
left: 0,
|
|
56
|
+
},
|
|
57
|
+
storyType: {
|
|
58
|
+
padding: 5,
|
|
59
|
+
justifyContent: 'space-between',
|
|
60
|
+
alignItems: 'center',
|
|
61
|
+
flexDirection: 'row',
|
|
62
|
+
},
|
|
63
|
+
storyTypeText: {
|
|
64
|
+
color: COLORS.MONO7,
|
|
65
|
+
fontSize: FONT_SIZE.h5,
|
|
66
|
+
},
|
|
67
|
+
liveBlogText: {
|
|
68
|
+
color: COLORS.MONO7,
|
|
69
|
+
fontSize: FONT_SIZE.h5,
|
|
70
|
+
marginLeft: 4,
|
|
71
|
+
fontWeight: 'bold',
|
|
72
|
+
},
|
|
73
|
+
liveBlogIcon: {
|
|
74
|
+
height: 12,
|
|
75
|
+
width: 12,
|
|
76
|
+
borderRadius: 50,
|
|
77
|
+
backgroundColor: COLORS.BRAND_3,
|
|
78
|
+
},
|
|
54
79
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { throttle } from
|
|
2
|
-
import PropTypes from
|
|
3
|
-
import React, { useContext, memo } from
|
|
1
|
+
import { get, throttle } from "lodash";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import React, { useContext, memo } from "react";
|
|
4
4
|
import {
|
|
5
5
|
I18nManager,
|
|
6
6
|
StyleSheet,
|
|
@@ -8,23 +8,27 @@ import {
|
|
|
8
8
|
View,
|
|
9
9
|
TextStyle,
|
|
10
10
|
TouchableOpacityProps,
|
|
11
|
-
} from
|
|
11
|
+
} from "react-native";
|
|
12
|
+
import Icon from "react-native-vector-icons/FontAwesome";
|
|
12
13
|
import {
|
|
13
14
|
AppTheme,
|
|
14
15
|
getImageMetadata,
|
|
15
16
|
getImageSlug,
|
|
16
17
|
getTimeForStoryCards,
|
|
17
|
-
} from
|
|
18
|
-
import { getStoryHeadline } from
|
|
19
|
-
import { ResponsiveImage, Text } from
|
|
20
|
-
import { storyStyles } from
|
|
18
|
+
} from "../../utils";
|
|
19
|
+
import { getStoryHeadline } from "../../utils/story";
|
|
20
|
+
import { ResponsiveImage, Text } from "../index";
|
|
21
|
+
import { storyStyles } from "./styles";
|
|
22
|
+
import { COMP_GENERAL_CONSTANTS } from "../../constants/component-constants/general-constants/constants";
|
|
21
23
|
|
|
22
24
|
const SecondaryStoryCardNewBase = (props) => {
|
|
23
25
|
const { story = {} } = props;
|
|
24
26
|
const { theme } = useContext(AppTheme);
|
|
25
|
-
const { locale } = theme;
|
|
27
|
+
const { locale, DARK_MODE, COLORS } = theme;
|
|
26
28
|
|
|
27
|
-
const
|
|
29
|
+
const translate = get(theme, ["translate"], (word) => word);
|
|
30
|
+
|
|
31
|
+
const styles = storyStyles(theme, DARK_MODE);
|
|
28
32
|
const containerStyle = StyleSheet.flatten([
|
|
29
33
|
styles.container,
|
|
30
34
|
{ paddingHorizontal: props.horizontalPadding },
|
|
@@ -38,41 +42,79 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
38
42
|
props.timestampStyle,
|
|
39
43
|
]);
|
|
40
44
|
|
|
41
|
-
const DATE_FORMAT =
|
|
42
|
-
const readTime = story[
|
|
45
|
+
const DATE_FORMAT = "d MMM, yyyy";
|
|
46
|
+
const readTime = story["read-time"]
|
|
47
|
+
? `${story["read-time"]} ${translate("min read")} · `
|
|
48
|
+
: "";
|
|
43
49
|
|
|
44
50
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
51
|
+
|
|
52
|
+
const showIcon = (name) => (
|
|
53
|
+
<View style={styles.storyType}>
|
|
54
|
+
<Icon name={name} size={14} color={COLORS.MONO7} />
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const showLiveBlogIcon = () => (
|
|
59
|
+
<View style={styles.storyType}>
|
|
60
|
+
<View style={styles.liveBlogIcon} />
|
|
61
|
+
<Text style={styles.liveBlogText}>LIVE</Text>
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const showStoryType = () => {
|
|
66
|
+
switch (story["story-template"]) {
|
|
67
|
+
case "text":
|
|
68
|
+
return null;
|
|
69
|
+
case "photo":
|
|
70
|
+
return showIcon("photo");
|
|
71
|
+
case "video":
|
|
72
|
+
return showIcon("play");
|
|
73
|
+
case "live-blog":
|
|
74
|
+
return showLiveBlogIcon();
|
|
75
|
+
default:
|
|
76
|
+
null;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
45
80
|
return (
|
|
46
81
|
<TouchableOpacity
|
|
47
|
-
testID={
|
|
82
|
+
testID={COMP_GENERAL_CONSTANTS.secondaryStoryCard}
|
|
48
83
|
onPress={throttledOnpress}
|
|
49
84
|
activeOpacity={0.8}
|
|
50
85
|
style={containerStyle}
|
|
51
86
|
>
|
|
52
87
|
<ResponsiveImage
|
|
53
88
|
metaData={getImageMetadata(story)}
|
|
54
|
-
slug={getImageSlug(story) ||
|
|
55
|
-
cdn={props.cdn ||
|
|
89
|
+
slug={getImageSlug(story) || ""}
|
|
90
|
+
cdn={props.cdn || ""}
|
|
56
91
|
imageWidth={props.imageWidth}
|
|
57
|
-
|
|
92
|
+
>
|
|
93
|
+
<View style={styles.storyTypeContainer}>{showStoryType()}</View>
|
|
94
|
+
</ResponsiveImage>
|
|
58
95
|
<View style={styles.headlineAndTimestampBlockContainer}>
|
|
59
96
|
<Text
|
|
60
97
|
primary
|
|
61
98
|
numberOfLines={2}
|
|
62
99
|
ellipsizeMode="tail"
|
|
63
100
|
style={headlineStyle}
|
|
64
|
-
testID=
|
|
101
|
+
testID={COMP_GENERAL_CONSTANTS.secondaryStoryHeadline}
|
|
65
102
|
>
|
|
66
103
|
{getStoryHeadline(story)?.trim()}
|
|
67
104
|
</Text>
|
|
68
|
-
<
|
|
69
|
-
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
105
|
+
<Text
|
|
106
|
+
style={timestampStyle}
|
|
107
|
+
numberOfLines={2}
|
|
108
|
+
// TODO: Add corrected testID here
|
|
109
|
+
>
|
|
110
|
+
{readTime +
|
|
111
|
+
getTimeForStoryCards(
|
|
112
|
+
story["published-at"],
|
|
113
|
+
DATE_FORMAT,
|
|
114
|
+
locale,
|
|
115
|
+
translate
|
|
116
|
+
)}
|
|
117
|
+
</Text>
|
|
76
118
|
</View>
|
|
77
119
|
<View style={styles.icon}>{props.iconComponent}</View>
|
|
78
120
|
</TouchableOpacity>
|
|
@@ -91,7 +133,7 @@ SecondaryStoryCardNewBase.propTypes = TouchableOpacityProps && {
|
|
|
91
133
|
};
|
|
92
134
|
|
|
93
135
|
SecondaryStoryCardNewBase.defaultProps = {
|
|
94
|
-
cdn:
|
|
136
|
+
cdn: "",
|
|
95
137
|
horizontalPadding: 12,
|
|
96
138
|
};
|
|
97
139
|
|
|
@@ -18,10 +18,6 @@ export const storyStyles = ({ COLORS, FONT_SIZE }) => StyleSheet.create({
|
|
|
18
18
|
fontSize: FONT_SIZE.h5,
|
|
19
19
|
lineHeight: FONT_SIZE.h5 * 1.2,
|
|
20
20
|
opacity: 0.6,
|
|
21
|
-
},
|
|
22
|
-
timestampContainer: {
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
flexDirection: 'row',
|
|
25
21
|
marginTop: 4,
|
|
26
22
|
},
|
|
27
23
|
headline: {
|
|
@@ -33,4 +29,32 @@ export const storyStyles = ({ COLORS, FONT_SIZE }) => StyleSheet.create({
|
|
|
33
29
|
icon: {
|
|
34
30
|
marginLeft: 8,
|
|
35
31
|
},
|
|
32
|
+
storyTypeContainer: {
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
backgroundColor: COLORS.MONO1,
|
|
35
|
+
bottom: 0,
|
|
36
|
+
left: 0,
|
|
37
|
+
},
|
|
38
|
+
storyType: {
|
|
39
|
+
padding: 5,
|
|
40
|
+
justifyContent: 'space-between',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
flexDirection: 'row',
|
|
43
|
+
},
|
|
44
|
+
storyTypeText: {
|
|
45
|
+
color: COLORS.MONO7,
|
|
46
|
+
fontSize: FONT_SIZE.h5,
|
|
47
|
+
},
|
|
48
|
+
liveBlogText: {
|
|
49
|
+
color: COLORS.MONO7,
|
|
50
|
+
fontSize: FONT_SIZE.h5,
|
|
51
|
+
marginLeft: 4,
|
|
52
|
+
fontWeight: 'bold',
|
|
53
|
+
},
|
|
54
|
+
liveBlogIcon: {
|
|
55
|
+
height: 12,
|
|
56
|
+
width: 12,
|
|
57
|
+
borderRadius: 50,
|
|
58
|
+
backgroundColor: COLORS.BRAND_3,
|
|
59
|
+
},
|
|
36
60
|
});
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import React, { useContext, memo } from
|
|
2
|
-
import { TouchableOpacity } from
|
|
3
|
-
import PropTypes from
|
|
4
|
-
import Icon from
|
|
5
|
-
import Share from
|
|
6
|
-
import { AppTheme } from
|
|
7
|
-
import { shareButtonStyles } from
|
|
8
|
-
import { getStoryHeadline } from
|
|
1
|
+
import React, { useContext, memo } from "react";
|
|
2
|
+
import { TouchableOpacity } from "react-native";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import Icon from "react-native-vector-icons/Ionicons";
|
|
5
|
+
import Share from "react-native-share";
|
|
6
|
+
import { AppTheme } from "../../utils";
|
|
7
|
+
import { shareButtonStyles } from "./styles";
|
|
8
|
+
import { getStoryHeadline } from "../../utils/story";
|
|
9
|
+
import { COMP_GENERAL_CONSTANTS } from "../../constants/component-constants";
|
|
9
10
|
|
|
10
11
|
const ShareButtonBase = (props) => {
|
|
11
12
|
const { theme } = useContext(AppTheme);
|
|
12
13
|
const styles = shareButtonStyles(theme);
|
|
13
|
-
const { story, type =
|
|
14
|
+
const { story, type = "story", slug } = props;
|
|
14
15
|
|
|
15
16
|
const getShareURL = () => {
|
|
16
17
|
const { url } = story || {};
|
|
17
18
|
switch (type) {
|
|
18
|
-
case
|
|
19
|
+
case "story":
|
|
19
20
|
return url;
|
|
20
|
-
case
|
|
21
|
+
case "card":
|
|
21
22
|
return `${url}${slug}`;
|
|
22
|
-
case
|
|
23
|
+
case "image":
|
|
23
24
|
return `${url}${slug}`;
|
|
24
|
-
case
|
|
25
|
+
case "attachment":
|
|
25
26
|
return slug;
|
|
26
27
|
default:
|
|
27
28
|
return url || slug;
|
|
@@ -43,7 +44,10 @@ const ShareButtonBase = (props) => {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
return (
|
|
46
|
-
<TouchableOpacity
|
|
47
|
+
<TouchableOpacity
|
|
48
|
+
onPress={share}
|
|
49
|
+
testID={COMP_GENERAL_CONSTANTS.shareButtonTouch}
|
|
50
|
+
>
|
|
47
51
|
<Icon style={styles.iconStyle} name="share-social-outline" size={20} />
|
|
48
52
|
</TouchableOpacity>
|
|
49
53
|
);
|