@quintype/native-components 2.20.26 → 2.20.28-beta.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 +6 -0
- package/bin-dev-scripts/standard-version-release.sh +11 -11
- package/package.json +6 -5
- package/src/components/Rating/index.js +44 -0
- package/src/components/Rating/styles.js +23 -0
- package/src/components/SecondaryStoryCardNew/index.js +9 -0
- package/src/components/Story/index.js +4 -11
- package/src/components/Story/styles.js +0 -9
- package/src/components/StoryHeader/index.js +4 -1
- package/src/components/YouTubePlayer/index.js +39 -1
- package/src/utils/colorUtils.js +1 -0
- package/src/utils/story.js +2 -24
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [2.20.28](https://github.com/quintype/native-components/compare/v2.20.27...v2.20.28) (2024-05-17)
|
|
6
|
+
|
|
7
|
+
### [2.20.27](https://github.com/quintype/native-components/compare/v2.20.26...v2.20.27) (2024-05-17)
|
|
8
|
+
|
|
9
|
+
### [2.20.26](https://github.com/quintype/native-components/compare/v2.20.25...v2.20.26) (2024-05-17)
|
|
10
|
+
|
|
5
11
|
### [2.20.25](https://github.com/quintype/native-components/compare/v2.20.24...v2.20.25) (2024-03-14)
|
|
6
12
|
|
|
7
13
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
#!/bin/bash -e
|
|
1
|
+
# #!/bin/bash -e
|
|
2
2
|
|
|
3
|
-
npm install
|
|
4
|
-
git diff --quiet
|
|
3
|
+
# npm install
|
|
4
|
+
# git diff --quiet
|
|
5
5
|
|
|
6
|
-
BRANCH=$(git symbolic-ref --short HEAD)
|
|
6
|
+
# BRANCH=$(git symbolic-ref --short HEAD)
|
|
7
7
|
|
|
8
|
-
if [ "$BRANCH" == 'master' ]
|
|
9
|
-
then
|
|
10
|
-
|
|
11
|
-
else
|
|
12
|
-
|
|
13
|
-
fi
|
|
8
|
+
# if [ "$BRANCH" == 'master' ]
|
|
9
|
+
# then
|
|
10
|
+
# npx standard-version
|
|
11
|
+
# else
|
|
12
|
+
# npx standard-version --prerelease "$(git symbolic-ref --short HEAD | sed s:/:-:g )" --skip.changelog=true
|
|
13
|
+
# fi
|
|
14
14
|
|
|
15
|
-
git push --follow-tags origin "$BRANCH"
|
|
15
|
+
# git push --follow-tags origin "$BRANCH"
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quintype/native-components",
|
|
3
|
-
"version": "2.20.
|
|
3
|
+
"version": "2.20.28-beta.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "jest --detectOpenHandles",
|
|
8
8
|
"lint": "npx eslint './src/**/*.{js,jsx}'",
|
|
9
|
-
"lint:ci": "npx eslint $(git diff --pretty='' --diff-filter=d --name-only origin/master..HEAD -- '*.js' '*.jsx') ./start.js"
|
|
9
|
+
"lint:ci": "npx eslint $(git diff --pretty='' --diff-filter=d --name-only origin/master..HEAD -- '*.js' '*.jsx') ./start.js",
|
|
10
|
+
"prepublishOnly": "./bin-dev-scripts/standard-version-release.sh"
|
|
10
11
|
},
|
|
11
12
|
"dependencies": {
|
|
12
13
|
"atob": "^2.1.2",
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
"react-native-pdf": "^5.1.4",
|
|
23
24
|
"react-native-render-html": "^4.2.3",
|
|
24
25
|
"react-native-share": "^8.1.0",
|
|
25
|
-
"rn-fetch-blob": "^0.10.16"
|
|
26
|
+
"rn-fetch-blob": "^0.10.16",
|
|
27
|
+
"react-native-star-rating-widget": "^1.7.3"
|
|
26
28
|
},
|
|
27
29
|
"peerDependencies": {
|
|
28
30
|
"@react-navigation/native": ">=5.7.3",
|
|
@@ -33,8 +35,7 @@
|
|
|
33
35
|
"react-native-pdf": ">=6.2.0",
|
|
34
36
|
"react-native-webview": ">=11.0.0",
|
|
35
37
|
"rn-fetch-blob": ">=0.12.0",
|
|
36
|
-
"react-native-vector-icons": "^10.0.0"
|
|
37
|
-
"react-native-linear-gradient": "^2.8.3"
|
|
38
|
+
"react-native-vector-icons": "^10.0.0"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@babel/core": "^7.11.1",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import PropTypes from "prop-types";
|
|
2
|
+
import React, { useContext } from "react";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { Text } from "../Text";
|
|
5
|
+
import {ratingStyles} from './styles'
|
|
6
|
+
import { AppTheme } from "../../utils";
|
|
7
|
+
|
|
8
|
+
export const RatingLayout = ({ reviewTitle, ratingValue, ratingLabel }) => {
|
|
9
|
+
const { theme } = useContext(AppTheme);
|
|
10
|
+
const {
|
|
11
|
+
COLORS, FONT_FAMILY, FONT_SIZE
|
|
12
|
+
} = theme;
|
|
13
|
+
const styles = ratingStyles(COLORS, FONT_SIZE, FONT_FAMILY);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<View style={styles.container}>
|
|
17
|
+
{reviewTitle && <Text
|
|
18
|
+
style={styles.reviewTitle}
|
|
19
|
+
>
|
|
20
|
+
{reviewTitle}
|
|
21
|
+
</Text>}
|
|
22
|
+
{ratingValue && <View style={styles.child}>
|
|
23
|
+
<Text
|
|
24
|
+
style={styles.ratingLable}
|
|
25
|
+
>
|
|
26
|
+
{`${ratingLabel}/5`}
|
|
27
|
+
</Text>
|
|
28
|
+
<StarRatingDisplay
|
|
29
|
+
rating={ratingValue}
|
|
30
|
+
starSize={FONT_SIZE.title}
|
|
31
|
+
color={COLORS.REVIEW_STAR_COLOR ?? '#F5A623'}
|
|
32
|
+
style={styles.starContiner}
|
|
33
|
+
starStyle={styles.starStyle}
|
|
34
|
+
/>
|
|
35
|
+
</View>}
|
|
36
|
+
</View>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
RatingLayout.propTypes = {
|
|
41
|
+
reviewTitle: PropTypes.string.isRequired,
|
|
42
|
+
ratingValue: PropTypes.number.isRequired,
|
|
43
|
+
ratingLabel: PropTypes.string.isRequired
|
|
44
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export const ratingStyles = (COLORS, FONT_SIZE, FONT_FAMILY) => StyleSheet.create({
|
|
4
|
+
container: { marginLeft: 10, marginTop: 10 },
|
|
5
|
+
reviewTitle: {
|
|
6
|
+
fontSize: FONT_SIZE.h2,
|
|
7
|
+
fontWeight: "700",
|
|
8
|
+
lineHeight: 24,
|
|
9
|
+
fontFamily: FONT_FAMILY.primary,
|
|
10
|
+
color: COLORS.BRAND_BLACK,
|
|
11
|
+
marginBottom:7
|
|
12
|
+
},
|
|
13
|
+
child: { display: "flex", flexDirection: "row", alignItems: "center"},
|
|
14
|
+
ratingLabel: {
|
|
15
|
+
fontSize: FONT_SIZE.h2,
|
|
16
|
+
fontWeight: "700",
|
|
17
|
+
lineHeight: 24,
|
|
18
|
+
fontFamily: FONT_FAMILY.secondary,
|
|
19
|
+
color: COLORS.BRAND_BLACK,
|
|
20
|
+
},
|
|
21
|
+
starContainer: { marginLeft: 10 },
|
|
22
|
+
starStyle: { marginHorizontal: 0 }
|
|
23
|
+
});
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
TouchableOpacityProps,
|
|
10
10
|
} from 'react-native';
|
|
11
11
|
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
12
|
+
import MaterialIcon from 'react-native-vector-icons/MaterialCommunityIcons'
|
|
12
13
|
import {
|
|
13
14
|
AppTheme,
|
|
14
15
|
getImageMetadata,
|
|
@@ -74,6 +75,12 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
74
75
|
</View>
|
|
75
76
|
);
|
|
76
77
|
|
|
78
|
+
const showMaterialIcon = (name) => (
|
|
79
|
+
<View style={styles.storyType}>
|
|
80
|
+
<MaterialIcon name={name} size={14} color={COLORS.MONO7}/>
|
|
81
|
+
</View>
|
|
82
|
+
)
|
|
83
|
+
|
|
77
84
|
const showStoryType = () => {
|
|
78
85
|
switch (story['story-template']) {
|
|
79
86
|
case 'text':
|
|
@@ -84,6 +91,8 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
84
91
|
return showIcon('play');
|
|
85
92
|
case 'live-blog':
|
|
86
93
|
return showLiveBlogIcon();
|
|
94
|
+
case 'review':
|
|
95
|
+
return showMaterialIcon('star-face')
|
|
87
96
|
default:
|
|
88
97
|
null;
|
|
89
98
|
}
|
|
@@ -15,8 +15,6 @@ import { storyStyles } from './styles';
|
|
|
15
15
|
import { isStoryFree, mutateDataBeforeAccess, getFirstVideoElement } from '../../utils/story';
|
|
16
16
|
import { isMiddleIndexOfArray } from '../../utils/arrayUtils';
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
18
|
const getLiveBlogTimeStamp = (card, DATE_FORMAT, share, styles, locale) => {
|
|
21
19
|
const slug = `?cardId=${card.id}`;
|
|
22
20
|
return (
|
|
@@ -78,9 +76,8 @@ const getStoryCards = (
|
|
|
78
76
|
currentLayout,
|
|
79
77
|
getAd,
|
|
80
78
|
locale,
|
|
81
|
-
) => cards.map((card, index, source) =>
|
|
82
|
-
|
|
83
|
-
return <View key={card?.id}>
|
|
79
|
+
) => cards.map((card, index, source) => (
|
|
80
|
+
<View key={card?.id}>
|
|
84
81
|
{isLiveBlog
|
|
85
82
|
&& getLiveBlogTimeStamp(card, DATE_FORMAT, share, styles, locale)}
|
|
86
83
|
|
|
@@ -110,6 +107,7 @@ const getStoryCards = (
|
|
|
110
107
|
{/* ^ In the case of a story having just 1 card,
|
|
111
108
|
requesting mid-content-Ad if there are > 1 story-elements in that card
|
|
112
109
|
(> 2 story-elements in case of video story since the 1st story-element gets rendered in header). */}
|
|
110
|
+
|
|
113
111
|
<StoryContent
|
|
114
112
|
testID={contentTestID}
|
|
115
113
|
key={storyElement?.id}
|
|
@@ -126,7 +124,7 @@ const getStoryCards = (
|
|
|
126
124
|
);
|
|
127
125
|
})}
|
|
128
126
|
</View>
|
|
129
|
-
|
|
127
|
+
));
|
|
130
128
|
|
|
131
129
|
export const Story = ({
|
|
132
130
|
cdn,
|
|
@@ -189,7 +187,6 @@ export const Story = ({
|
|
|
189
187
|
|
|
190
188
|
return (
|
|
191
189
|
<>
|
|
192
|
-
<View>
|
|
193
190
|
<StoryHeader
|
|
194
191
|
firstVideoElement={firstVideoElement}
|
|
195
192
|
testID={headerTestID}
|
|
@@ -221,10 +218,6 @@ export const Story = ({
|
|
|
221
218
|
getAd,
|
|
222
219
|
locale,
|
|
223
220
|
)}
|
|
224
|
-
<View style={styles.overlay} />
|
|
225
|
-
</View>
|
|
226
|
-
|
|
227
|
-
|
|
228
221
|
|
|
229
222
|
{accessComponent(story, storyHasAccess)}
|
|
230
223
|
|
|
@@ -37,13 +37,4 @@ export const storyStyles = (COLORS, FONT_SIZE) => StyleSheet.create({
|
|
|
37
37
|
color: COLORS.BRAND_1,
|
|
38
38
|
fontSize: FONT_SIZE.title,
|
|
39
39
|
},
|
|
40
|
-
overlay: {
|
|
41
|
-
position: 'absolute',
|
|
42
|
-
bottom: -10,
|
|
43
|
-
left: 0,
|
|
44
|
-
right: 0,
|
|
45
|
-
height: 180, // Adjust the height as needed
|
|
46
|
-
backgroundColor: 'rgba(150, 0, 0, 0.2)',
|
|
47
|
-
marginHorizontal:10
|
|
48
|
-
},
|
|
49
40
|
});
|
|
@@ -18,6 +18,7 @@ import { storyHeaderStyles } from './styles';
|
|
|
18
18
|
import { COMP_CONTENT_CONSTANTS } from '../../constants/component-constants/content-constants/constants';
|
|
19
19
|
|
|
20
20
|
import { DailyMotionPlayer } from '../DailyMotionPlayer';
|
|
21
|
+
import { RatingLayout } from '../Rating';
|
|
21
22
|
const getHeroImage = (cdn, story) => {
|
|
22
23
|
const imageSlug = story['hero-image-s3-key'];
|
|
23
24
|
if (!imageSlug) return null;
|
|
@@ -73,7 +74,8 @@ export const StoryHeader = (props) => {
|
|
|
73
74
|
const caption = story['hero-image-caption'];
|
|
74
75
|
const attribution = story['hero-image-attribution'];
|
|
75
76
|
const isPremiumStory = story['access'] === 'subscription';
|
|
76
|
-
|
|
77
|
+
const reviewTitle = story['metadata'] && story['metadata']['review-title'];
|
|
78
|
+
const reviewData = story['metadata'] && story['metadata']['review-rating'];
|
|
77
79
|
|
|
78
80
|
const showAttribution = () => {
|
|
79
81
|
if (!caption && !attribution) {
|
|
@@ -128,6 +130,7 @@ export const StoryHeader = (props) => {
|
|
|
128
130
|
cdn={props.cdn}
|
|
129
131
|
readtime={story['read-time']}
|
|
130
132
|
/>
|
|
133
|
+
{reviewTitle && <RatingLayout reviewTitle={reviewTitle} ratingValue={reviewData?.value} ratingLabel={reviewData?.label}/>}
|
|
131
134
|
</View>
|
|
132
135
|
);
|
|
133
136
|
};
|
|
@@ -10,12 +10,50 @@ export const YouTubePlayer = ({ card = {} }) => {
|
|
|
10
10
|
const windowWidth = Dimensions.get("window").width;
|
|
11
11
|
const styles = webviewStyles(windowWidth);
|
|
12
12
|
|
|
13
|
+
const getYoutubeIframe = (ytEmbedURL) => {
|
|
14
|
+
const videoId = ytEmbedURL.split('/').pop();
|
|
15
|
+
const width = windowWidth - 20;
|
|
16
|
+
const height = (9/16)*(windowWidth - 20);
|
|
17
|
+
const htmlContent = `
|
|
18
|
+
<iframe
|
|
19
|
+
width="1280"
|
|
20
|
+
height="720"
|
|
21
|
+
src="https://www.youtube.com/embed/${videoId}"
|
|
22
|
+
frameborder="0"
|
|
23
|
+
allow="accelerometer;
|
|
24
|
+
autoplay;
|
|
25
|
+
clipboard-write;
|
|
26
|
+
encrypted-media;
|
|
27
|
+
gyroscope;
|
|
28
|
+
picture-in-picture;
|
|
29
|
+
web-share"
|
|
30
|
+
referrerpolicy="strict-origin-when-cross-origin"
|
|
31
|
+
allowfullscreen
|
|
32
|
+
></iframe>`;
|
|
33
|
+
|
|
34
|
+
return `
|
|
35
|
+
<html>
|
|
36
|
+
<head>
|
|
37
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
38
|
+
<style>
|
|
39
|
+
iframe{
|
|
40
|
+
width:${width}px;
|
|
41
|
+
height:${height}px;
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
${htmlContent}
|
|
47
|
+
</body>
|
|
48
|
+
</html>`;
|
|
49
|
+
}
|
|
50
|
+
|
|
13
51
|
return (
|
|
14
52
|
<View style={styles.container} testID="youtube-player-id">
|
|
15
53
|
<WebView
|
|
16
54
|
mediaPlaybackRequiresUserAction
|
|
17
55
|
style={styles.webViewContainer}
|
|
18
|
-
source={{
|
|
56
|
+
source={{ html: getYoutubeIframe(ytEmbedURL), baseUrl:'https://www.youtube.com'}}
|
|
19
57
|
javaScriptEnabled
|
|
20
58
|
domStorageEnabled
|
|
21
59
|
startInLoadingState
|
package/src/utils/colorUtils.js
CHANGED
|
@@ -2,6 +2,7 @@ export const hexToRgb = (hex, alpha=1) => {
|
|
|
2
2
|
let rgbCode = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(m, r, g, b) => '#' + r + r + g + g + b + b)
|
|
3
3
|
.substring(1).match(/.{2}/g)
|
|
4
4
|
.map(x => parseInt(x, 16));
|
|
5
|
+
console.log('risi - color', `rgb(${rgbCode[0]}, ${rgbCode[1]}, ${rgbCode[2]}, ${alpha})`)
|
|
5
6
|
return `rgba(${rgbCode[0]}, ${rgbCode[1]}, ${rgbCode[2]}, ${alpha})`;
|
|
6
7
|
}
|
|
7
8
|
|
package/src/utils/story.js
CHANGED
|
@@ -50,35 +50,13 @@ export const mutateDataBeforeAccess = (item, storyHasAccess) => {
|
|
|
50
50
|
return item;
|
|
51
51
|
}
|
|
52
52
|
/* The following steps are necessary to keep argument mutation at bay */
|
|
53
|
-
|
|
54
|
-
const firstCardObject = get(item, ['cards', 2], {});
|
|
53
|
+
const firstCardObject = get(item, ['cards', 0], {});
|
|
55
54
|
const firstCardElement = get(firstCardObject, !STORY_TYPES.VIDEO_STORY && ['story-elements', 0], {});
|
|
56
|
-
let visibleContentsForBlockedStory = [];
|
|
57
|
-
let textStoryFound = false;
|
|
58
|
-
if(item.cards && item.cards.length > 0){
|
|
59
|
-
for(let i = 0; i < Math.min(item.cards.length, 2); i++){
|
|
60
|
-
let storyElement = [];
|
|
61
|
-
for(let j=0; j<item.cards[i]['story-elements'].length; j++){
|
|
62
|
-
let tempStoryElement = item.cards[i]['story-elements'][j];
|
|
63
|
-
if(tempStoryElement?.type !== 'text'){
|
|
64
|
-
storyElement.push(tempStoryElement);
|
|
65
|
-
} else {
|
|
66
|
-
textStoryFound = true;
|
|
67
|
-
storyElement.push(tempStoryElement);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// console.log('risi - temp - item', item.cards[i])
|
|
72
|
-
visibleContentsForBlockedStory.push({...item.cards[i],'story-elements' : storyElement});
|
|
73
|
-
if(textStoryFound) break;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
55
|
|
|
78
56
|
return {
|
|
79
57
|
...item,
|
|
80
58
|
...{
|
|
81
|
-
cards:
|
|
59
|
+
cards: [{ ...firstCardObject, 'story-elements': [firstCardElement] }],
|
|
82
60
|
},
|
|
83
61
|
};
|
|
84
62
|
};
|