diff --git a/components/FilterPane.tsx b/components/FilterPane.tsx index fc2a681d631570cc16b70d67f6ea4d47c46b2b68..713e55cdd08cfd24f04fea61425648e0571caafb 100644 --- a/components/FilterPane.tsx +++ b/components/FilterPane.tsx @@ -1,15 +1,15 @@ -import React from 'react'; -import { StyleSheet, TextInput } from 'react-native'; -import { View } from '../components/Themed'; +import React from "react"; +import { StyleSheet } from "react-native"; +import { View } from "../components/Themed"; import { FilterKeys, FilterValues, SortDirection, SortKeys, -} from '../constants/filterOptions/interface'; -import { genres, sortDirections, sortValues } from '../constants/filterOptions'; -import SelectInput from './SelectInput'; -import SearchInput from './SearchInput'; +} from "../constants/filterOptions/interface"; +import { genres, sortDirections, sortValues } from "../constants/filterOptions"; +import SelectInput from "./SelectInput"; +import SearchInput from "./SearchInput"; export type FilterPaneProps = { onSearchChange: (value: string) => void; @@ -29,20 +29,21 @@ const FilterPane: React.FC = ({ onFilterChange('genres', value ? [value] : [])} + onChange={(value) => onFilterChange("genres", value ? [value] : [])} /> onSortChange(value ? value : 'title')} + onChange={(value) => onSortChange(value ? value : "title")} /> onSortDirectionChange(value ? value : 'asc')} + style={{ marginRight: 4 }} + onChange={(value) => onSortDirectionChange(value ? value : "asc")} /> @@ -59,22 +60,19 @@ const FilterPane: React.FC = ({ const styles = StyleSheet.create({ container: { - marginTop: 8, - marginHorizontal: 16, - width: '95%', - display: 'flex', + width: "100%", + paddingVertical: "2%", }, row: { - flex: 1, - display: 'flex', - flexDirection: 'row', - paddingVertical: 4, - alignItems: 'center', - justifyContent: 'space-between', + flexDirection: "row", + paddingVertical: 5, + justifyContent: "space-between", }, inlineRow: { - display: 'flex', - flexDirection: 'row', + flexShrink: 1, + flexGrow: 0, + flexDirection: "row", + justifyContent: "flex-end", }, }); diff --git a/components/MovieCard.tsx b/components/MovieCard.tsx index fb7472405ab498e6061f6c28a59ba111d5d9e2f7..92455bd6ba5a9fe33369402931f21802efc1ca89 100644 --- a/components/MovieCard.tsx +++ b/components/MovieCard.tsx @@ -1,15 +1,16 @@ -import React, { useEffect, useState } from 'react'; -import { Image, StyleSheet, Text, View } from 'react-native'; -import { AirbnbRating } from 'react-native-ratings'; -import { MovieEntity } from '../store/ducks/movies/types'; -import { Dimensions } from 'react-native'; +import React, { useEffect, useState } from "react"; +import { Image, StyleSheet, Text, View } from "react-native"; +import { AirbnbRating } from "react-native-ratings"; +import { MovieEntity } from "../store/ducks/movies/types"; +import { Dimensions } from "react-native"; +import { useThemeColor } from "./Themed"; interface MovieCardProps { movie: MovieEntity; } -const window = Dimensions.get('window'); -const screen = Dimensions.get('screen'); +const window = Dimensions.get("window"); +const screen = Dimensions.get("screen"); /** * Movie Card component */ @@ -26,13 +27,15 @@ const MovieCard = (props: MovieCardProps): JSX.Element => { }; useEffect(() => { - Dimensions.addEventListener('change', ({ window, screen }) => { + Dimensions.addEventListener("change", ({ window, screen }) => { setDimensions({ window, screen }); }); }, []); return ( - + { style={[styles.poster, { width: iw(), height: ih() }]} /> - {movie.title} + + {movie.title} + = ({ const { documentCount } = useSelector( ({ movies }: ApplicationState) => movies ); + // Fetch theme color for the spinner + const color = useThemeColor({}, "inputText"); const [isFull, setIsfull] = useState(false); @@ -43,7 +46,7 @@ const MovieTable: React.FC = ({ {movies.length > 0 || moviesLoading ? ( = ({ <> {!isFull ? ( <> - Loading... + Loading... ) : ( <> {movies.length > 4 && ( - --- No more movies --- + + --- No more movies --- + )} )} @@ -82,7 +87,7 @@ const MovieTable: React.FC = ({ )} /> ) : ( - No Movies Found + No Movies Found )} ); @@ -90,29 +95,27 @@ const MovieTable: React.FC = ({ const styles = StyleSheet.create({ movieItems: { - justifyContent: 'center', + justifyContent: "center", flexGrow: 1 / 2, - backgroundColor: 'white', }, movieFlatList: { - width: '100%', - height: '100%', + width: "100%", + height: "100%", marginBottom: 4, }, movieList: { marginTop: 4, - width: '95%', - height: '95%', - alignItems: 'center', - textAlign: 'center', + height: "95%", + alignItems: "center", + textAlign: "center", flex: 1, }, loading: { flex: 1, - fontSize: 20, - fontWeight: 'bold', + fontSize: 16, + fontWeight: "bold", marginBottom: 16, - textAlign: 'center', + textAlign: "center", }, }); diff --git a/components/SearchInput.tsx b/components/SearchInput.tsx index 5194f276c07853bf4fc006ee7191f110789d971e..ceadaf048fb3ba7b5dcdc51c35b8fa469cdc8f78 100644 --- a/components/SearchInput.tsx +++ b/components/SearchInput.tsx @@ -1,5 +1,6 @@ -import React from 'react'; -import { StyleSheet, TextInput } from 'react-native'; +import React from "react"; +import { StyleSheet, TextInput } from "react-native"; +import { useThemeColor } from "./Themed"; type IProps = { searchThreshold: number; placeholder: string; @@ -11,11 +12,18 @@ const SearchInput: React.FC = (props: IProps) => { // Return string value if the string's length is above the set threshold // else, return an empty string function handleChange(value: string) { - onChange(value.length >= searchThreshold ? value : ''); + onChange(value.length >= searchThreshold ? value : ""); } return ( @@ -24,12 +32,11 @@ const SearchInput: React.FC = (props: IProps) => { const styles = StyleSheet.create({ input: { + height: 40, + fontSize: 18, + borderWidth: 1, borderRadius: 15, - borderColor: '#333', - width: '100%', - marginLeft: 4, - marginRight: 4, - paddingVertical: 4, + width: "100%", paddingHorizontal: 12, }, }); diff --git a/components/SelectInput.tsx b/components/SelectInput.tsx index c30a047f1abe20b9961fbe90feb41786ec156752..898ad06e608dd916bd7a5ef62706813512710926 100644 --- a/components/SelectInput.tsx +++ b/components/SelectInput.tsx @@ -1,46 +1,75 @@ -import React from 'react'; -import { StyleProp, StyleSheet, TextStyle } from 'react-native'; -import { Picker } from '@react-native-picker/picker'; -import { capitalize } from '../utils/textTransform'; - +import React from "react"; +import { + StyleProp, + StyleSheet, + TextStyle, + View, + ViewStyle, +} from "react-native"; +import { capitalize } from "../utils/textTransform"; +import SelectDowndown from "react-native-select-dropdown"; +import { useThemeColor } from "./Themed"; +import { useTheme } from "react-native-elements"; type IProps = { data: T[]; + style?: ViewStyle; defaultValue?: string; onChange?: (value: T | null) => void; }; function SelectInput(props: IProps) { - const { data, defaultValue, onChange } = props; + const { defaultValue, onChange } = props; + let { data } = props; + + // Append default value if it's defined + if (defaultValue) { + data = [defaultValue as T, ...data]; + } // Return 'null' if default value is selected function dispatchValue(value: T | string) { if (onChange) { - onChange(value === defaultValue ? null : (value as T)); + onChange(value === defaultValue ? null : (value.toLowerCase() as T)); } } return ( - style={styles.input} onValueChange={dispatchValue}> - {defaultValue && } - {data.length > 0 && - data.map((item) => ( - - ))} - + dispatchValue(selected)} + defaultValueByIndex={0} + buttonTextAfterSelection={(selected, index) => capitalize(selected)} + rowTextForSelection={(item) => capitalize(item)} + /> ); } const styles = StyleSheet.create({ - input: { - minWidth: 100, + button: { + height: 40, + maxWidth: 100, + borderWidth: 1, borderRadius: 15, - marginLeft: 4, - marginRight: 4, - padding: 4, + padding: 0, + }, + text: { + paddingVertical: 0, + marginVertical: 0, + fontSize: 14, }, }); diff --git a/components/Themed.tsx b/components/Themed.tsx index 2fc1306483f7559646487ac6afe12518ff5c31b2..1c1f77ea7c4c9abe763a8b12ffb958a9bab8e64e 100644 --- a/components/Themed.tsx +++ b/components/Themed.tsx @@ -44,6 +44,7 @@ export function View(props: ViewProps) { { light: lightColor, dark: darkColor }, "background" ); + //const color = useThemeColor({ light: lightColor, dark: darkColor }, "text"); return ; } diff --git a/constants/Colors.ts b/constants/Colors.ts index 1c706c7bb4a586e5911f4242d3d1158b97e7b658..31cdfd5b590951fca60801f4676e4a664ade3a54 100644 --- a/constants/Colors.ts +++ b/constants/Colors.ts @@ -1,19 +1,25 @@ -const tintColorLight = '#2f95dc'; -const tintColorDark = '#fff'; +const tintColorLight = "#2f95dc"; +const tintColorDark = "#fff"; export default { light: { - text: '#000', - background: '#fff', + text: "#000", + inputText: "#333", + background: "#fff", + component: "rgb(240, 240, 240)", + border: "rgb(221, 221, 221)", tint: tintColorLight, - tabIconDefault: '#ccc', + tabIconDefault: "#ccc", tabIconSelected: tintColorLight, }, dark: { - text: '#fff', - background: '#000', + text: "#fff", + inputText: "rgb(220, 220, 220)", + background: "#000", + component: "rgb(18, 18, 18)", + border: "rgb(39, 39, 41)", tint: tintColorDark, - tabIconDefault: '#ccc', + tabIconDefault: "#ccc", tabIconSelected: tintColorDark, }, }; diff --git a/constants/filterOptions/index.ts b/constants/filterOptions/index.ts index 799c90fe0b57933301b6527b6a09dcffad26c5f3..e8a548da91de0554dd1c727394d6c007ba39dc61 100644 --- a/constants/filterOptions/index.ts +++ b/constants/filterOptions/index.ts @@ -2,17 +2,17 @@ import { Genre } from "../../store/ducks/movies/types"; import { SortDirection, SortKeys } from "./interface"; export const genres: Genre[] = [ - "Action", - "Adventure", - "Comedy", - "Drama", - "Fantasy", - "Horror", - "Mystery", - "Romance", - "Science Fiction", - "Thriller", - "Western", + "action", + "adventure", + "comedy", + "drama", + "fantasy", + "horror", + "mystery", + "romance", + "science fiction", + "thriller", + "western", ]; type DefaultValue = [string]; export const sortValues: SortKeys[] = ["title", "year", "rating"]; diff --git a/navigation/index.tsx b/navigation/index.tsx index 09bb7090c1dc925929ed88a2ddd8771f5c1889ab..9745d1cc00af12d33b65713117696a48d40301b5 100644 --- a/navigation/index.tsx +++ b/navigation/index.tsx @@ -3,26 +3,26 @@ * https://reactnavigation.org/docs/getting-started * */ -import { FontAwesome, MaterialIcons } from '@expo/vector-icons'; -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { FontAwesome, MaterialIcons } from "@expo/vector-icons"; +import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { DarkTheme, DefaultTheme, NavigationContainer, -} from '@react-navigation/native'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import * as React from 'react'; -import { ColorSchemeName, Pressable } from 'react-native'; -import { useDispatch } from 'react-redux'; -import Colors from '../constants/Colors'; -import useColorScheme from '../hooks/useColorScheme'; -import ModalScreen from '../screens/ModalScreen'; -import MovieTableScreen from '../screens/MovieTableScreen'; -import NotFoundScreen from '../screens/NotFoundScreen'; -import Profile from '../screens/Profile'; -import { signOut } from '../store/ducks/auth/actions'; -import { RootStackParamList, RootTabParamList } from '../types'; -import LinkingConfiguration from './LinkingConfiguration'; +} from "@react-navigation/native"; +import { createNativeStackNavigator } from "@react-navigation/native-stack"; +import * as React from "react"; +import { ColorSchemeName, Pressable } from "react-native"; +import { useDispatch } from "react-redux"; +import Colors from "../constants/Colors"; +import useColorScheme from "../hooks/useColorScheme"; +import ModalScreen from "../screens/ModalScreen"; +import MovieTableScreen from "../screens/MovieTableScreen"; +import NotFoundScreen from "../screens/NotFoundScreen"; +import Profile from "../screens/Profile"; +import { signOut } from "../store/ducks/auth/actions"; +import { RootStackParamList, RootTabParamList } from "../types"; +import LinkingConfiguration from "./LinkingConfiguration"; export default function Navigation({ colorScheme, @@ -32,7 +32,7 @@ export default function Navigation({ return ( @@ -53,12 +53,12 @@ function RootNavigator() { component={BottomTabNavigator} options={{ headerShown: false }} /> - - + /> */} + @@ -86,7 +86,7 @@ const BottomTabNavigator = () => { name="Movies" component={MovieTableScreen} options={{ - title: 'Movies', + title: "Movies", tabBarIcon: ({ color }) => ( { name="Profile" component={Profile} options={{ - title: 'Profile', + title: "Profile", tabBarIcon: ({ color }) => ( ) { +}: RootTabScreenProps<"Movies">) { const dispatch = useDispatch(); const [currentPage, setCurrentPage] = useState(1); const [movies, setMovies] = useState([]); @@ -120,7 +120,7 @@ export default function MovieTableScreen({ // Map properties to the movie table component const mapStateToMovieTableProps: MovieTableProps = { - path: '/screens/TabOneScreen.tsx', + path: "/screens/TabOneScreen.tsx", query, movies, currentPage, @@ -139,18 +139,8 @@ export default function MovieTableScreen({ const styles = StyleSheet.create({ container: { flex: 1, - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - }, - title: { - fontSize: 20, - fontWeight: 'bold', - }, - separator: { - marginVertical: 30, - height: 1, - width: '90%', + flexDirection: "column", + width: "96%", + marginHorizontal: "2%", }, }); diff --git a/store/ducks/movies/types.ts b/store/ducks/movies/types.ts index f8203db93e42bbb9b44a37f137f220fe28b71ca8..3ed1e9fe5cdbbc264d805a0dec14aa16efff0604 100644 --- a/store/ducks/movies/types.ts +++ b/store/ducks/movies/types.ts @@ -74,17 +74,17 @@ export type FetchMovieByIdParams = { id: string }; export type UpdateMovieRatingParams = { data: MovieRating }; export type Genre = - | "Action" - | "Comedy" - | "Drama" - | "Fantasy" - | "Horror" - | "Mystery" - | "Romance" - | "Thriller" - | "Western" - | "Science Fiction" - | "Adventure"; + | "action" + | "comedy" + | "drama" + | "fantasy" + | "horror" + | "mystery" + | "romance" + | "thriller" + | "western" + | "science fiction" + | "adventure"; export const initialQuery: FetchMovieParams = { perPage: 20, diff --git a/yarn.lock b/yarn.lock index 373a51d72aeb1930a1a352177c9f97b76a0932c9..2826ac1fec55685030e77ce69e20dacf4a2a287a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1727,11 +1727,6 @@ sudo-prompt "^9.0.0" wcwidth "^1.0.1" -"@react-native-picker/picker@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@react-native-picker/picker/-/picker-2.2.0.tgz#e96ecc0808bdf2a706a263b422864bee5a0e6b76" - integrity sha512-zhzXsppY9t6TU39WMx/x1L1PyP3dPgGhtav7Yo8nlfihNGIAFwHnNcNuyC8CLdWxKj9n2+Z6+ZR6r/Kda82JnA== - "@react-native/assets@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e" @@ -6912,6 +6907,11 @@ react-native-screens@~3.8.0: dependencies: warn-once "^0.1.0" +react-native-select-dropdown@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/react-native-select-dropdown/-/react-native-select-dropdown-1.4.0.tgz#34cc2d305950e3dd26a5bc761db5f439ee0b6b17" + integrity sha512-CeiFQ8F3lI7SAB9l/uMbGUeJmslUkyz9Vv8DHutOjO1bJpP1/Kfu9lH6QYjJ41DXFGQzT1bw8EGHe8rz/eTC/A== + react-native-size-matters@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz#24d0cfc335a2c730f6d58bd7b43ea5a41be4b49f"