123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- import { ScrollView, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native'
- import React, { useState } from 'react'
- import { SafeAreaView } from 'react-native-safe-area-context'
- import NewscoutTitleHeader from '../../components/molecules/Header/NewscoutTitleHeader'
- import colors from '../../constants/colors'
- import { Checkbox, IconButton, List, Modal, PaperProvider, Portal, TextInput, ToggleButton } from 'react-native-paper'
- import { horizontalScale, moderateScale, screenWidth, verticalScale } from '../../constants/metrics'
- import IonIcon from 'react-native-vector-icons/Ionicons'
- import fonts from '../../constants/fonts'
- import { navigateToArticle, navigateToListViewPage, useConstructor } from '../../constants/functions'
- import { getArticlesBySearch, getCategories, getMenus } from '../../api/data'
- import LoadingScreen from '../../components/organisms/Sections/LoadingScreen'
- import { PAGINATE_BY } from '../../api/urls'
- import HorizontalNewsCardVariant from '../../components/molecules/Cards/HorizontalNewsCardVariant'
- import ThemedTextButton from '../../components/molecules/Buttons/ThemeTextButton'
- const SearchPage = props => {
- const {
- navigation,
- route
- } = props
- const [isSearching, setSearching] = useState(false)
- const [categories, setCategories] = useState([])
- const [searchText, setSearchText] = useState("")
- const [suggestedNews, setSuggestedNews] = useState([])
- const [filtersData, setFiltersData] = useState({})
- const [currentFilter, setCurrentFilter] = useState("Category")
- // * Filters Modal
- const [isFiltersVisible, setFiltersVisible] = useState(false);
- const showFilters = () => setFiltersVisible(true);
- const hideFilters = () => setFiltersVisible(false);
- const styles = StyleSheet.create({
- container: {
- backgroundColor: colors().dominant,
- minHeight: '100%',
- maxHeight: 'auto'
- },
- inputTextContainer: {
- backgroundColor: colors().dominant,
- paddingHorizontal: horizontalScale(16),
- paddingBottom: verticalScale(16),
- flexDirection: 'row',
- alignItems: 'center',
- // gap: horizontalScale(16),
- maxWidth: '100%'
- },
- categoryContainer: {
- padding: verticalScale(16),
- flexDirection: 'row',
- flexWrap: 'wrap',
- gap: moderateScale(16),
- },
- category: {
- height: 170,
- width: 170,
- backgroundColor: colors().secondaryColor,
- borderRadius: moderateScale(8),
- padding: moderateScale(11),
- justifyContent: 'flex-end',
- },
- categoryText: {
- fontFamily: fonts.type.semibold,
- alignSelf: 'flex-end',
- color: colors().white,
- fontSize: moderateScale(14),
- maxWidth: "80%",
- textAlign: 'right'
- },
- filtersButton: {
- backgroundColor: colors().dominant,
- paddingRight: horizontalScale(8),
- paddingLeft: horizontalScale(16),
- alignItems: 'center',
- justifyContent: 'center',
- },
- 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(16),
- backgroundColor: colors().primaryColor,
- borderRadius: moderateScale(18),
- width: 'auto',
- },
- selectedPillText: {
- fontFamily: fonts.type.semibold,
- fontSize: moderateScale(12),
- color: colors().white,
- },
- pillText: {
- fontFamily: fonts.type.semibold,
- fontSize: moderateScale(12),
- color: colors().recessive,
- },
- filterCheckboxes: {
- alignItems: 'flex-start'
- },
- listItemText:{
- fontFamily: fonts.type.medium,
- fontSize: moderateScale(14)
- },
- listItem:{
- paddingVertical: verticalScale(0)
- }
- })
- const fetchCategories = () => {
- getCategories().then(res => setCategories(res.data.body.results)).catch(err => console.log(err))
- }
- const fetchSuggestions = (search_text) => {
- getArticlesBySearch(search_text)
- .then(res => setSuggestedNews(res.data.body.results.slice(0, PAGINATE_BY)))
- .catch(err => console.log(err))
- }
- const fetchFilters = () => {
- getMenus()
- .then(res => {
- let filtersPayload = res.data.body.results
- //Reduce Submenus into a object
- setFiltersData(prev => ({ ...prev, "Category": filtersPayload.flatMap(item => item.heading.submenu.map(category => category.name)).reduce((current,value) => ({...current,[value]:false}),{})}))
- setFiltersData(prev => ({ ...prev, "Source": filtersPayload.flatMap(item => item.heading.submenu.map(category => category.name)).reduce((current,value) => ({...current,[value]:false}),{})}))
- setFiltersData(prev => ({ ...prev, "Hash Tags": filtersPayload.flatMap(item => item.heading.submenu.map(category => category.hash_tags.map(tag => tag.name))).reduce((current,value) => ({...current,[value]:false}),{})}))
-
- })
- }
- useConstructor(() => {
- fetchCategories()
- fetchFilters()
- })
- const onChangeText = (text) => {
- if (text.length > 0) {
- console.warn(text)
- setSearching(true)
- setSearchText(text)
- setSuggestedNews([])
- fetchSuggestions(text)
- } else {
- console.warn(text)
- setSearching(false)
- setSearchText(text)
- setSuggestedNews([])
- }
- }
- return (
- <PaperProvider>
- <SafeAreaView style={styles.container}>
- <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) }} />
- <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,
- ]}>
- {item}
- </Text>
- )}
- style={[
- item === currentFilter
- ? styles.selectedFilterPill
- : styles.filterPill,
- { marginHorizontal: horizontalScale(4) },
- ]}
- value={item}
- />)
- }
- </ToggleButton.Group>
- </ScrollView>
- </View>
- <ScrollView contentContainerStyle={styles.filterCheckboxes} showsVerticalScrollIndicator={false}>
- {
- // filtersData[currentFilter]
- Object.keys(filtersData).length <= 0 ? <LoadingScreen />
- : Object.entries(filtersData[currentFilter]).map(item => {
- return (<List.Item
- style={styles.listItem}
- titleStyle={styles.listItemText}
- title={item[0]}
- left={props => <Checkbox
- status={filtersData[currentFilter][item[0]] === true ? 'checked' : 'unchecked'}
- onPress={() =>
- setFiltersData({ ...filtersData, [currentFilter]: { ...filtersData[currentFilter], [item[0]]: !filtersData[currentFilter][item[0]] } })}
- // setSelectedTopics({...filtersData,[item.heading.name]: !selectedTopics[item.heading.name]})}
- color={colors().secondaryColor}
- />}
- />)
- }
- )
- }
- </ScrollView>
- </Modal>
- </Portal>
- <ScrollView>
- <NewscoutTitleHeader title={"Search"} />
- <View style={styles.inputTextContainer}>
- <TextInput
- editable
- mode='outlined'
- placeholder='Search Text'
- placeholderTextColor={colors().grayShade_300}
- dense
- style={{
- backgroundColor: colors().grayShade_500,
- paddingVertical: moderateScale(4),
- // width: '100%',
- flex: 1
- }}
- contentStyle={{
- fontSize: moderateScale(16),
- fontFamily: fonts.type.medium,
- // height: moderateScale(16),
- }}
- outlineStyle={{
- borderColor: colors().dominant_variant,
- borderRadius: moderateScale(8),
- borderWidth: moderateScale(1),
- }}
- // underlineStyle={{backgroundColor: colors().dominant}}
- left={() => <Text>fdsfdss</Text>}
- right={() => <TouchableOpacity onPress={() => navigateToListViewPage(navigation, 'search', searchText)}><IonIcon name="search" color={colors().grayShade_200} size={moderateScale(8)} /></TouchableOpacity>}
- onChangeText={onChangeText}
- />
- <TouchableOpacity style={styles.filtersButton} onPress={showFilters}>
- <IonIcon name="filter" color={colors().recessive_variant} size={moderateScale(24)} />
- </TouchableOpacity>
- </View>
- {
- isSearching === false ?
- <View style={styles.categoryContainer}>
- {categories.map((item) =>
- <TouchableOpacity onPress={() => navigateToListViewPage(navigation, "category", item.heading.name)}>
- <View style={styles.category}>
- <Text style={styles.categoryText}>{item.heading.name}</Text>
- </View>
- </TouchableOpacity>
- )}
- </View>
- : suggestedNews.length <= 0 ?
- <View style={{ alignItems: 'center', justifyContent: 'center', }}><LoadingScreen containerHeight={600} /></View> : <View style={styles.categoryContainer}>
- {suggestedNews.map((item) =>
- <HorizontalNewsCardVariant
- onPress={() => navigateToArticle(navigation, item.id, item.slug)}
- timestamp={item.published_on}
- headline={item.title}
- image={{ uri: item.cover_image }}
- category={item.category}
- tagline={item.id}
- />
- )}
- </View>
- }
- </ScrollView>
- </SafeAreaView>
- </PaperProvider>
- )
- }
- export default SearchPage
|