123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- import { FlatList, SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
- import React, { useState } from 'react'
- import colors from '../../constants/colors'
- import { horizontalScale, moderateScale, verticalScale } from '../../constants/metrics'
- import { navigateToArticle, useConstructor } from '../../utils/functions'
- import IonIcon from 'react-native-vector-icons/Ionicons'
- import { Checkbox, IconButton, List, Modal, PaperProvider, Portal, ToggleButton } from 'react-native-paper'
- import { getArticlesBySearch} from '../../api/data'
- import NewscoutCenteredTitleHeader from '../../components/molecules/Header/NewscoutCenteredTitleHeader'
- import LoadingScreen from '../../components/organisms/Sections/LoadingScreen'
- import ThemedTextButton from '../../components/molecules/Buttons/ThemeTextButton'
- import fonts from '../../constants/fonts'
- import HorizontalNewsCardVariant from '../../components/molecules/Cards/HorizontalNewsCardVariant'
- const SearchListPage = props => {
- const {
- navigation,
- route
- } = props
- const params = route.params
- const [filtersData, setFiltersData] = useState({})
- const [currentFilter, setCurrentFilter] = useState("Category")
- const [pagesLoaded, setPagesLoaded] = useState(0)
- const [news, setNews] = useState([])
- const [isFiltersVisible, setFiltersVisible] = useState(false);
- const showFilters = () => setFiltersVisible(true);
- const hideFilters = () => setFiltersVisible(false);
- const styles = StyleSheet.create({
- pageContainer: {
- backgroundColor: colors().dominant
- },
- newsContainer: {
- backgroundColor: colors().dominant,
- minHeight: "100%",
- height: 'auto',
- paddingHorizontal: horizontalScale(16),
- flexDirection: 'row',
- flexWrap: 'wrap',
- gap: moderateScale(8),
- paddingVertical: verticalScale(16),
- numColumns: 2
- },
- filtersModalContainer: {
- padding: moderateScale(16),
- width: '100%',
- height: '100%',
- // marginHorizontal: horizontalScale(32),
- justifyContent: 'flex-start',
- backgroundColor: colors().dominant,
- },
- filtersHeader: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between'
- },
- filterHeading: {
- fontFamily: fonts.type.semibold,
- color: colors().recessive,
- fontSize: moderateScale(20)
- },
- utilContainer: {
- flexDirection: 'row',
- gap: 8,
- alignItems: 'center'
- },
- filterPillContainer: {
- paddingVertical: verticalScale(8)
- },
- filterTitle: {
- fontFamily: fonts.type.semibold,
- color: colors().black,
- fontSize: moderateScale(16),
- paddingVertical: moderateScale(8)
- },
- filterPill: {
- borderRadius: moderateScale(18),
- paddingVertical: verticalScale(8),
- paddingHorizontal: horizontalScale(12),
- backgroundColor: colors().dominant,
- width: 'auto',
- },
- selectedFilterPill: {
- paddingVertical: verticalScale(8),
- paddingHorizontal: horizontalScale(8),
- // backgroundColor: colors().primaryColor,
- borderRadius: 0,
- width: 'auto',
- borderColor: colors().primaryColor,
- borderBottomWidth: 3
- },
- selectedPillText: {
- fontFamily: fonts.type.bold,
- fontSize: moderateScale(14),
- color: colors().recessive,
- },
- pillText: {
- fontFamily: fonts.type.semibold,
- fontSize: moderateScale(12),
- color: colors().recessive,
- },
- filterCheckboxes: {
- alignItems: 'flex-start',
- flexDirection:'column',
- gap: moderateScale(8),
-
- },
- listItemText: {
- fontFamily: fonts.type.medium,
- fontSize: moderateScale(14),
- color: colors().recessive
- },
- listItem: {
- paddingVertical: verticalScale(0)
- }
- })
- const applyFilters = () => {
- setNews([])
- hideFilters()
- setPagesLoaded(1)
- fetchSearchResults(params.query, 1, createFilters(filtersData))
- }
- const _clearFilters = (data) => setFiltersData(Object.entries(data).reduce((current,value) => ({...current,[value[0]]:value[1].reduce((prev,item) => ({...prev,[item.key]: false}),{})}),{}))
- const clearAllFilters = () => {
- _clearFilters(filtersData)
- }
- const fetchSearchResults = (search_text, page = 1, filters = "") => {
- getArticlesBySearch(search_text, page, filters)
- .then(res => {
- setNews(prev => [...prev, ...res.data.body.results])
- if (pagesLoaded <= 0){
- setCurrentFilter(Object.entries(res.data.body.filters)[0][0])
- _clearFilters(res.data.body.filters)
- setPagesLoaded(1)
- console.log(Object.entries(res.data.body.filters)[2][0])
-
- }
- })
- .catch(err => console.log(err))
- }
- const humanizeFilters = (text) => text.split("_").map(item => item[0].toUpperCase() + item.substring(1)).join(" ")
- const createFilters = (filterObject) => {
- let filterText = ""
- for (const obj of Object.entries(filterObject)) {
- for (const category of Object.entries(obj[1])) {
- if (category[1] === true) {
- filterText += `&${obj[0]}=${category[0]}`
- }
- }
- }
- return filterText
- }
- useConstructor(() => {
- fetchSearchResults(params.query, 1, createFilters(filtersData))
- })
- return (
- <PaperProvider>
- <SafeAreaView style={styles.pageContainer}>
- <Portal>
- <Modal visible={isFiltersVisible} onDismiss={hideFilters} contentContainerStyle={styles.filtersModalContainer}>
- <View style={styles.filtersHeader}>
- <Text style={styles.filterHeading}>Filters</Text>
- <View style={styles.utilContainer}>
- <ThemedTextButton theme={'primary-contained'} title={'Clear All'} buttonStyle={{ paddingVertical: verticalScale(6) }} onPress={clearAllFilters} />
- <IconButton
- icon="close"
- iconColor={colors().recessive}
- size={moderateScale(24)}
- onPress={hideFilters}
- style={{ alignSelf: 'flex-end' }}
- />
- </View>
- </View>
- <View>
- <ScrollView horizontal contentContainerStyle={styles.filterPillContainer}>
- <ToggleButton.Group
- onValueChange={value => {
- setCurrentFilter(value)
- }}
- >
- {
- Object.keys(filtersData).map(item =>
- <ToggleButton
- key={item}
- icon={() => (
- <Text
- style={[
- item === currentFilter
- ? styles.selectedPillText
- : styles.pillText,
- ]}>
- {humanizeFilters(item)}
- </Text>
- )}
- style={[
- item === currentFilter
- ? styles.selectedFilterPill
- : styles.filterPill,
- { marginHorizontal: horizontalScale(4) },
- ]}
- value={item}
- />)
- }
- </ToggleButton.Group>
- </ScrollView>
- </View>
- {
- Object.keys(filtersData).length <= 0 ? <LoadingScreen />
- :
- <FlatList
- contentContainerStyle={styles.filterCheckboxes}
- showsVerticalScrollIndicator={false}
- data={Object.entries(filtersData[currentFilter])}
- renderItem={filter => <List.Item
- key={filter.item[0]}
- style={styles.listItem}
- titleStyle={styles.listItemText}
- title={filter.item[0]}
- left={props => <Checkbox
- status={filtersData[currentFilter][filter.item[0]] === true ? 'checked' : 'unchecked'}
- onPress={() => {
- setFiltersData({ ...filtersData, [currentFilter]: { ...filtersData[currentFilter], [filter.item[0]]: !filtersData[currentFilter][filter.item[0]] } })
- console.log(filtersData[currentFilter][filter.item[0]])
- }}
- color={colors().secondaryColor}
- />}
- />}
- />}
- <ThemedTextButton onPress={applyFilters} theme={'secondary-contained'} title={'Apply'} buttonStyle={{ paddingVertical: verticalScale(8), marginTop: verticalScale(8) }} />
- </Modal>
- </Portal>
- <NewscoutCenteredTitleHeader title={"Search Results"} backButtonShown={true} onBackClick={() => navigation.goBack()}>
- <TouchableOpacity style={styles.filtersButton} onPress={showFilters}>
- <IonIcon name="filter" color={colors().primaryColor} size={moderateScale(24)} />
- </TouchableOpacity>
- </NewscoutCenteredTitleHeader>
- {
- news.length <= 0 ?
- <LoadingScreen />
- :
- <FlatList
- contentContainerStyle={styles.newsContainer}
- showsVerticalScrollIndicator={false}
- data={news}
- renderItem={(news) =>
- <HorizontalNewsCardVariant
- onPress={() => navigateToArticle(navigation, news.item.id, news.item.slug)}
- timestamp={news.item.published_on}
- headline={news.item.title}
- image={{ uri: news.item.cover_image }}
- category={news.item.category}
- tagline={news.item.id}
- />}
- keyExtractor={item => item.index}
- onEndReached={() => {
- setPagesLoaded(pagesLoaded + 1)
- fetchSearchResults(params.query,pagesLoaded + 1,createFilters(filtersData))
- }}
- onEndReachedThreshold={200}
- />
- }
- </SafeAreaView>
- </PaperProvider>
- )
- }
- export default SearchListPage
- const styles = StyleSheet.create({})
|