|
@@ -0,0 +1,334 @@
|
|
|
+import {
|
|
|
+ StyleSheet,
|
|
|
+ Text,
|
|
|
+ View,
|
|
|
+ TouchableWithoutFeedback,
|
|
|
+ ScrollView,
|
|
|
+ Image,
|
|
|
+} from 'react-native';
|
|
|
+import React, {useCallback} from 'react';
|
|
|
+import NewscoutTitleHeader from '../../components/molecules/Header/NewscoutTitleHeader';
|
|
|
+import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
|
|
+import colors from '../../constants/colors';
|
|
|
+import {
|
|
|
+ horizontalScale,
|
|
|
+ moderateScale,
|
|
|
+ verticalScale,
|
|
|
+} from '../../constants/metrics';
|
|
|
+import {
|
|
|
+ getArticleBySlug,
|
|
|
+ getCommentByArticleID,
|
|
|
+ getRecommendationByArticleID,
|
|
|
+} from '../../api/data';
|
|
|
+import LoadingScreen from '../../components/organisms/Sections/LoadingScreen';
|
|
|
+import {getTimestamp, navigateToArticle, useConstructor} from '../../constants/functions';
|
|
|
+import fonts from '../../constants/fonts';
|
|
|
+import BookmarkButton from '../../components/atoms/Buttons/BookmarkButton';
|
|
|
+import ShareButton from '../../components/atoms/Buttons/ShareButton';
|
|
|
+import IonIcon from 'react-native-vector-icons/Ionicons';
|
|
|
+import {
|
|
|
+ BottomSheetModal,
|
|
|
+ BottomSheetModalProvider,
|
|
|
+ BottomSheetView,
|
|
|
+ BottomSheetScrollView,
|
|
|
+} from '@gorhom/bottom-sheet';
|
|
|
+import ButtonWrapper from '../../components/atoms/Buttons/ButtonWrapper';
|
|
|
+import images from '../../assets/images/images';
|
|
|
+import SectionHeader from '../../components/molecules/Header/SectionHeader';
|
|
|
+import VerticalNewsCard from '../../components/molecules/Cards/VerticalNewsCard';
|
|
|
+
|
|
|
+const NewsDetailPage = props => {
|
|
|
+ const {navigation, route} = props;
|
|
|
+ const {id, slug} = route.params;
|
|
|
+
|
|
|
+ const [isLoading, setLoading] = React.useState(true);
|
|
|
+ const [article, setArticle] = React.useState({});
|
|
|
+ const [comments, setComments] = React.useState({
|
|
|
+ total_article_likes: 0,
|
|
|
+ results: [],
|
|
|
+ });
|
|
|
+ const [recommendations, setRecommendations] = React.useState([]);
|
|
|
+
|
|
|
+ const mainPageRef = React.useRef(null);
|
|
|
+ const bottomSheetModalRef = React.useRef('');
|
|
|
+
|
|
|
+ // Comments Modal
|
|
|
+ const snapPoints = React.useMemo(() => ['70%', '100%'], []);
|
|
|
+ const handlePresentModalPress = useCallback(() => {
|
|
|
+ bottomSheetModalRef.current?.present();
|
|
|
+ }, []);
|
|
|
+ const handleCloseModalPress = () => bottomSheetModalRef.current.close();
|
|
|
+ const handleSheetChanges = useCallback(index => {
|
|
|
+ console.log('handleSheetChanges', index);
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const fetchArticle = slug => {
|
|
|
+ getArticleBySlug(slug)
|
|
|
+ .then(res => {
|
|
|
+ console.log(res.data);
|
|
|
+ setArticle(res.data.body.article);
|
|
|
+ setLoading(false);
|
|
|
+ })
|
|
|
+ .catch(error => console.log(error));
|
|
|
+ };
|
|
|
+
|
|
|
+ const fetchComments = id => {
|
|
|
+ getCommentByArticleID(id)
|
|
|
+ .then(res => {
|
|
|
+ console.log(res.data.body);
|
|
|
+ setComments(res.data.body);
|
|
|
+ })
|
|
|
+ .catch(err => console.log(err));
|
|
|
+ };
|
|
|
+
|
|
|
+ const fetchRecommendations = id => {
|
|
|
+ getRecommendationByArticleID(id)
|
|
|
+ .then(res => setRecommendations(res.data.body.results))
|
|
|
+ .catch(err => console.log(err));
|
|
|
+ };
|
|
|
+
|
|
|
+ useConstructor(function () {
|
|
|
+ fetchArticle(slug);
|
|
|
+ fetchComments(id);
|
|
|
+ fetchRecommendations(id);
|
|
|
+ });
|
|
|
+
|
|
|
+ const styles = StyleSheet.create({
|
|
|
+ container: {backgroundColor: colors().dominant, minHeight: '100%'},
|
|
|
+ newsContainer: {paddingHorizontal: horizontalScale(16)},
|
|
|
+ newsTitle: {
|
|
|
+ fontFamily: fonts.type.semibold,
|
|
|
+ color: colors().recessive,
|
|
|
+ fontSize: moderateScale(16),
|
|
|
+ },
|
|
|
+ newsTagline: {
|
|
|
+ color: colors().recessive_variant,
|
|
|
+ fontFamily: fonts.type.regular,
|
|
|
+ paddingVertical: verticalScale(12),
|
|
|
+ },
|
|
|
+ newsDescriptorContainer: {
|
|
|
+ flexDirection: 'row',
|
|
|
+ gap: horizontalScale(8),
|
|
|
+ },
|
|
|
+ newsDescriptor: {
|
|
|
+ color: colors().recessive,
|
|
|
+ fontFamily: fonts.type.semibold,
|
|
|
+ fontSize: moderateScale(12),
|
|
|
+ },
|
|
|
+ imagesContainer: {
|
|
|
+ width: 'auto',
|
|
|
+ height: verticalScale(200),
|
|
|
+ marginTop: verticalScale(16),
|
|
|
+ },
|
|
|
+ image: {
|
|
|
+ borderRadius: moderateScale(4),
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ },
|
|
|
+ buttonStyle: {
|
|
|
+ padding: moderateScale(8),
|
|
|
+ },
|
|
|
+ commentSection: {
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ flexDirection: 'row',
|
|
|
+ gap: moderateScale(8),
|
|
|
+ paddingLeft: horizontalScale(4),
|
|
|
+ },
|
|
|
+ commentText: {
|
|
|
+ fontFamily: fonts.type.regular,
|
|
|
+ color: colors().grayShade_200,
|
|
|
+ },
|
|
|
+ commentInputContainer: {
|
|
|
+ flexDirection: 'row',
|
|
|
+ justifyContent: 'space-between',
|
|
|
+ alignItems: 'center',
|
|
|
+ paddingVertical: verticalScale(4),
|
|
|
+ },
|
|
|
+ profileImage: {
|
|
|
+ height: 42,
|
|
|
+ width: 42,
|
|
|
+ borderRadius: 32,
|
|
|
+ marginRight: horizontalScale(16),
|
|
|
+ },
|
|
|
+ commentInput: {
|
|
|
+ paddingVertical: verticalScale(16),
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'flex-start',
|
|
|
+ flexDirection: 'row',
|
|
|
+ },
|
|
|
+ utilButtons: {
|
|
|
+ flexDirection: 'row',
|
|
|
+ justifyContent: 'space-between',
|
|
|
+ paddingVertical: verticalScale(4),
|
|
|
+ },
|
|
|
+ newsText: {
|
|
|
+ color: colors().grayShade_200,
|
|
|
+ fontFamily: fonts.type.regular,
|
|
|
+ lineHeight: verticalScale(24),
|
|
|
+ paddingVertical: verticalScale(4),
|
|
|
+ },
|
|
|
+ backToTop: {
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ paddingTop: verticalScale(16),
|
|
|
+ paddingBottom: verticalScale(8),
|
|
|
+ },
|
|
|
+ backToTopText: {
|
|
|
+ color: colors().primaryColor,
|
|
|
+ fontFamily: fonts.type.medium,
|
|
|
+ textDecorationLine: 'underline',
|
|
|
+ fontSize: moderateScale(16),
|
|
|
+ },
|
|
|
+ recommendationContainer: {
|
|
|
+ paddingHorizontal: horizontalScale(16),
|
|
|
+ gap: moderateScale(4),
|
|
|
+ paddingBottom: verticalScale(16),
|
|
|
+ backgroundColor: colors().dominant,
|
|
|
+ flexDirection: 'row',
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ return (
|
|
|
+ <BottomSheetModalProvider>
|
|
|
+ <ScrollView ref={mainPageRef} contentContainerStyle={styles.container}>
|
|
|
+ <NewscoutTitleHeader
|
|
|
+ backButtonShown
|
|
|
+ onBackClick={() => navigation.goBack()}>
|
|
|
+ <TouchableWithoutFeedback onPress={() => navigation.toggleDrawer()}>
|
|
|
+ <MaterialIcon name="list" color={colors().primaryColor} size={30} />
|
|
|
+ </TouchableWithoutFeedback>
|
|
|
+ </NewscoutTitleHeader>
|
|
|
+ {isLoading === true ? (
|
|
|
+ <LoadingScreen />
|
|
|
+ ) : (
|
|
|
+ <View style={styles.newsContainer}>
|
|
|
+ <Text style={styles.newsTitle}>{article.title}</Text>
|
|
|
+ <Text style={styles.newsTagline}>{'No Tagline'}</Text>
|
|
|
+ <View style={styles.newsDescriptorContainer}>
|
|
|
+ <Text style={styles.newsDescriptor}>
|
|
|
+ {getTimestamp(article.published_on)}
|
|
|
+ </Text>
|
|
|
+ {(article.author !== undefined || article.author.length <= 0) ?? (
|
|
|
+ <Text style={styles.newsDescriptor}>By {article.author}</Text>
|
|
|
+ )}
|
|
|
+ <Text style={styles.newsDescriptor}>{article.source}</Text>
|
|
|
+ </View>
|
|
|
+ <View style={styles.imagesContainer}>
|
|
|
+ <Image source={{uri: article.cover_image}} style={styles.image} />
|
|
|
+ </View>
|
|
|
+ <View style={styles.utilButtons}>
|
|
|
+ <TouchableWithoutFeedback onPress={handlePresentModalPress}>
|
|
|
+ <View style={styles.commentSection}>
|
|
|
+ <IonIcon
|
|
|
+ name="chatbubble-outline"
|
|
|
+ size={moderateScale(20)}
|
|
|
+ color={colors().primaryColor}
|
|
|
+ />
|
|
|
+ <Text style={styles.commentText}>
|
|
|
+ {comments.results.length ?? 123} COMMENTS
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ </TouchableWithoutFeedback>
|
|
|
+ <View style={{flexDirection: 'row'}}>
|
|
|
+ <BookmarkButton
|
|
|
+ buttonStyle={styles.buttonStyle}
|
|
|
+ iconSize={20}
|
|
|
+ onPress={true}
|
|
|
+ />
|
|
|
+ <ShareButton
|
|
|
+ buttonStyle={styles.buttonStyle}
|
|
|
+ iconSize={20}
|
|
|
+ onPress={true}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ <Text style={styles.newsText}>{article.blurb}</Text>
|
|
|
+ <View style={styles.backToTop}>
|
|
|
+ <TouchableWithoutFeedback
|
|
|
+ onPress={() =>
|
|
|
+ mainPageRef.current.scrollTo({
|
|
|
+ y: 0,
|
|
|
+ })
|
|
|
+ }>
|
|
|
+ <Text style={styles.backToTopText}>Back To Top</Text>
|
|
|
+ </TouchableWithoutFeedback>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <>
|
|
|
+ <BottomSheetModal
|
|
|
+ ref={bottomSheetModalRef}
|
|
|
+ index={1}
|
|
|
+ snapPoints={snapPoints}
|
|
|
+ onChange={handleSheetChanges}>
|
|
|
+ <BottomSheetScrollView>
|
|
|
+ <BottomSheetView
|
|
|
+ style={{paddingHorizontal: horizontalScale(24)}}>
|
|
|
+ <BottomSheetView style={styles.commentInputContainer}>
|
|
|
+ <Text
|
|
|
+ style={{
|
|
|
+ fontFamily: fonts.type.semibold,
|
|
|
+ color: colors.black,
|
|
|
+ fontSize: moderateScale(16),
|
|
|
+ }}>
|
|
|
+ Comments
|
|
|
+ </Text>
|
|
|
+ <ButtonWrapper onPress={handleCloseModalPress}>
|
|
|
+ <IonIcon
|
|
|
+ name="close-sharp"
|
|
|
+ size={moderateScale(20)}
|
|
|
+ color={colors().recessive}
|
|
|
+ />
|
|
|
+ </ButtonWrapper>
|
|
|
+ </BottomSheetView>
|
|
|
+ <View style={styles.commentInput}>
|
|
|
+ <Image
|
|
|
+ source={images.imageCard}
|
|
|
+ style={[styles.profileImage]}
|
|
|
+ />
|
|
|
+ <Text>Comment Text Input</Text>
|
|
|
+ </View>
|
|
|
+ <>
|
|
|
+ <Text
|
|
|
+ style={{
|
|
|
+ fontFamily: fonts.type.medium,
|
|
|
+ color: colors().recessive,
|
|
|
+ paddingBottom: verticalScale(8),
|
|
|
+ }}>
|
|
|
+ View all Comments({comments.results.length})
|
|
|
+ </Text>
|
|
|
+ </>
|
|
|
+ <BottomSheetView style={{gap: moderateScale(16)}}>
|
|
|
+ {comments.results.length <= 0 ? (
|
|
|
+ <LoadingScreen />
|
|
|
+ ) : (
|
|
|
+ comments.results.map(() => <CommentCard />)
|
|
|
+ )}
|
|
|
+ </BottomSheetView>
|
|
|
+ </BottomSheetView>
|
|
|
+ </BottomSheetScrollView>
|
|
|
+ </BottomSheetModal>
|
|
|
+ </>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+ <SectionHeader label={'Recommendations'} />
|
|
|
+ <ScrollView
|
|
|
+ horizontal
|
|
|
+ contentContainerStyle={styles.recommendationContainer}
|
|
|
+ style={{flexDirection: 'row'}}
|
|
|
+ showsHorizontalScrollIndicator={false}>
|
|
|
+ {recommendations.map(item => (
|
|
|
+ <VerticalNewsCard
|
|
|
+ image={{uri: item.cover_image}}
|
|
|
+ headline={item.title}
|
|
|
+ onPress={() => navigateToArticle(navigation, item.id, item.slug)}
|
|
|
+
|
|
|
+ />
|
|
|
+ ))}
|
|
|
+ </ScrollView>
|
|
|
+ </ScrollView>
|
|
|
+ </BottomSheetModalProvider>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default NewsDetailPage;
|