diff --git a/assets/icons.tsx b/assets/icons.tsx index 7a5ed2ea..54d18bab 100644 --- a/assets/icons.tsx +++ b/assets/icons.tsx @@ -4,6 +4,7 @@ import { SvgXml } from 'react-native-svg'; export type IconType = | 'home_outline' + | 'back_icon' | 'document_outline' | 'search_outline' | 'settings_gear' @@ -11,6 +12,7 @@ export type IconType = const IconSvgs: Record = { home_outline: , + back_icon: , search_outline: , document_outline: , settings_gear: , diff --git a/package-lock.json b/package-lock.json index 36bbe3af..55331f68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "dom-parser": "^0.1.6", "expo": "~49.0.11", "expo-constants": "~14.4.2", + "expo-font": "~11.4.0", "expo-linking": "~5.0.2", "expo-router": "^2.0.0", "expo-status-bar": "~1.6.0", diff --git a/package.json b/package.json index 2d951965..0adf9e77 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,8 @@ "react-native-svg": "13.9.0", "react-native-url-polyfill": "^2.0.0", "react-native-vector-icons": "^10.0.0", - "react-scroll-to-top": "^3.0.0" + "react-scroll-to-top": "^3.0.0", + "expo-font": "~11.4.0" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/src/app/(tabs)/_layout.tsx b/src/app/(tabs)/_layout.tsx index 9a5f56bf..60ee9389 100644 --- a/src/app/(tabs)/_layout.tsx +++ b/src/app/(tabs)/_layout.tsx @@ -37,6 +37,13 @@ function TabNav() { tabBarIcon: SearchIcon, }} /> + + + + ); +} + +export default StackLayout; diff --git a/src/app/(tabs)/author/index.tsx b/src/app/(tabs)/author/index.tsx new file mode 100644 index 00000000..d98f9c57 --- /dev/null +++ b/src/app/(tabs)/author/index.tsx @@ -0,0 +1,146 @@ +import { useLocalSearchParams, router } from 'expo-router'; +import React, { useEffect, useState } from 'react'; +import { + ActivityIndicator, + ScrollView, + View, + Text, + Image, + TouchableOpacity, +} from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; + +import styles from './styles'; +import Icon from '../../../../assets/icons'; +import HorizontalLine from '../../../components/HorizontalLine/HorizontalLine'; +import PreviewCard from '../../../components/PreviewCard/PreviewCard'; +import { + fetchAuthor, + fetchAuthorStoryPreviews, +} from '../../../queries/authors'; +import { Author, StoryPreview } from '../../../queries/types'; +import globalStyles from '../../../styles/globalStyles'; + +function AuthorScreen() { + const [authorInfo, setAuthorInfo] = useState(); + const [authorStoryPreview, setAuthorStoryPreview] = + useState(); + const [isLoading, setLoading] = useState(true); + const params = useLocalSearchParams<{ author: string }>(); + const { author } = params; + + useEffect(() => { + (async () => { + const storyData: StoryPreview[] = await fetchAuthorStoryPreviews( + parseInt(author as string, 10), + ); + const authorData: Author = await fetchAuthor( + parseInt(author as string, 10), + ); + try { + setAuthorInfo(authorData); + console.log('TESTING AUTHOR INFO QUERY OUTPUT:', authorInfo); + } catch (error) { + console.log( + `There was an error while trying to output authorinfo ${error}`, + ); + } + try { + setAuthorStoryPreview(storyData); + console.log('TESTING STORY PREVIEW INFO QUERY OUTPUT:', storyData); + } catch (error) { + console.log( + `There was an error while trying to output author story preview info ${error}`, + ); + } + setLoading(false); + })(); + }, [author]); + + return ( + + {isLoading ? ( + + ) : ( + + + + { + router.back(); + }} + > + BACK + + + + + + + + {authorInfo ? authorInfo.name : ''} + + + {authorInfo ? authorInfo.pronouns : ' '} + + + + + + {authorInfo ? authorInfo.bio : ''} + + + + + + + Artist's Statement + + + {authorInfo ? authorInfo.artist_statement : ''} + + + + + + + + {authorStoryPreview?.length + ' '} + {authorStoryPreview + ? authorStoryPreview?.length > 1 + ? 'Stories' + : 'Story' + : ''} + + + {authorStoryPreview + ? authorStoryPreview.map(story => ( + + router.push({ + pathname: '/story', + params: { storyId: story.id.toString() }, + }) + } + /> + )) + : ''} + + )} + + ); +} + +export default AuthorScreen; diff --git a/src/app/(tabs)/author/styles.tsx b/src/app/(tabs)/author/styles.tsx new file mode 100644 index 00000000..13f419bc --- /dev/null +++ b/src/app/(tabs)/author/styles.tsx @@ -0,0 +1,80 @@ +import { StyleSheet } from 'react-native'; + +import colors from '../../../styles/colors'; + +const styles = StyleSheet.create({ + authorCardContainer: { + marginRight: 20, + flexDirection: 'row', + justifyContent: 'flex-start', + flexWrap: 'wrap', + }, + name: { + paddingTop: 15, + fontWeight: 'bold', + fontSize: 25, + fontFamily: 'Avenir', + marginLeft: -10, + }, + image: { + height: 68, + width: 68, + backgroundColor: colors.darkGrey, + borderRadius: 4, + marginBottom: 12, + marginTop: 12, + }, + bioText: { + paddingTop: 15, + paddingBottom: 15, + color: 'black', + fontFamily: 'Avenir', + fontSize: 14, + width: 324, + }, + authorStatementContainer: { + paddingTop: 15, + paddingBottom: 5, + fontWeight: 'bold', + fontSize: 20, + }, + authorStatement: { + paddingBottom: 15, + fontSize: 14, + color: 'black', + fontWeight: '400', + fontFamily: 'Avenir', + width: 324, + }, + authorTextContainer: { + paddingLeft: 20, + }, + line: { + borderTopColor: 'black', + borderTopWidth: 20, + }, + authorStatementTitle: { + fontWeight: 'bold', + fontFamily: 'Avenir', + fontSize: 17, + paddingBottom: 2, + }, + backButton: { + paddingTop: 20, + paddingBottom: 15, + flexDirection: 'row', + justifyContent: 'flex-start', + color: colors.lightGrey, + }, + storyCountText: { + paddingTop: 10, + paddingBottom: 10, + fontWeight: 'bold', + }, + pronouns: { + color: '#797979', + marginLeft: -10, + }, +}); + +export default styles; diff --git a/src/app/(tabs)/search/index.tsx b/src/app/(tabs)/search/index.tsx index 8ee38ffd..c55bf17a 100644 --- a/src/app/(tabs)/search/index.tsx +++ b/src/app/(tabs)/search/index.tsx @@ -1,21 +1,36 @@ import { SearchBar } from '@rneui/themed'; import { Link, router } from 'expo-router'; import React, { useEffect, useState } from 'react'; -import { Button, FlatList, View } from 'react-native'; +import { + Button, + FlatList, + View, + TouchableOpacity, + Text, + ScrollView, +} from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import styles from './styles'; import FilterModal from '../../../components/FilterModal/FilterModal'; +import LandingCard from '../../../components/LandingCard/LandingCard'; import SearchCard from '../../../components/PreviewCard/PreviewCard'; +import { fetchGenres } from '../../../queries/genres'; import { fetchAllStoryPreviews } from '../../../queries/stories'; -import { StoryPreview } from '../../../queries/types'; -import globalStyles from '../../../styles/globalStyles'; +import { StoryPreview, Genre } from '../../../queries/types'; function SearchScreen() { const [allStories, setAllStories] = useState([]); + const [allGenres, setAllGenres] = useState([]); const [searchResults, setSearchResults] = useState([]); const [search, setSearch] = useState(''); const [filterVisible, setFilterVisible] = useState(false); + const [showGenreCarousals, setShowGenreCarousals] = useState(true); + + const getColor = (index: number) => { + const genreColors = ['#E66E3F', '#ACC073', '#B49BC6']; + return genreColors[index % genreColors.length]; + }; const searchFunction = (text: string) => { if (text === '') { @@ -31,20 +46,30 @@ function SearchScreen() { }); setSearch(text); setSearchResults(updatedData); + setShowGenreCarousals(false); }; useEffect(() => { (async () => { const data: StoryPreview[] = await fetchAllStoryPreviews(); setAllStories(data); + const genreData: Genre[] = await fetchGenres(); + console.log('testing use effect fetch of genre data:', genreData); + setAllGenres(genreData); })(); }, []); + const handleCancelButtonPress = () => { + setSearchResults([]); + setShowGenreCarousals(true); + }; + return ( handleCancelButtonPress()} searchIcon={false} clearIcon containerStyle={styles.searchContainer} @@ -52,44 +77,75 @@ function SearchScreen() { inputStyle={{ color: 'black' }} leftIconContainerStyle={{}} rightIconContainerStyle={{}} - lightTheme + // lightTheme loadingProps={{}} placeholder="Search" placeholderTextColor="black" onChangeText={text => searchFunction(text)} value={search} /> -