Commit ffef5ee4 authored by Mithunan Sivakumar's avatar Mithunan Sivakumar
Browse files
parents 636f4fa8 3e4dd3ba
import React from 'react';
import { Image, StyleSheet, Text, View } from 'react-native';
import { AirbnbRating } from 'react-native-ratings';
import { MovieEntity } from '../store/ducks/movies/types';
interface MovieCardProps {
movie: MovieEntity;
}
/**
* Movie Card component
*/
const MovieCard = (props: MovieCardProps): JSX.Element => {
const { movie } = props;
return (
<View style={styles.card}>
<Image
source={{
uri: movie.poster,
}}
style={styles.poster}
resizeMode="contain"
/>
<View style={styles.cardInfo}>
<Text style={styles.titleText}>{movie.title}</Text>
<AirbnbRating
count={5}
defaultRating={movie.rating}
showRating={false}
isDisabled={true}
size={20}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
poster: {
flex: 1,
minWidth: undefined,
height: undefined,
aspectRatio: 300 / 443,
borderTopLeftRadius: 5,
borderTopRightRadius: 5,
},
card: {
flex: 1,
marginHorizontal: 4,
minWidth: 175,
boxShadow: '0 2px 4px 0 rgba(0,0,0,0.2)',
borderRadius: 5,
textAlign: 'center',
},
titleText: {
fontWeight: 'bold',
},
cardInfo: {
padding: 4,
textAlign: 'center',
maxWidth: 175,
minHeight: 75,
},
rating: {
// maxWidth: 150,
},
});
export default MovieCard;
import React, { useEffect, useState } from 'react';
import { FlatList, StyleSheet, Text } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useDispatch, useSelector } from 'react-redux';
import { fetchMovies } from '../store/ducks/movies/actions';
import { FetchMovieParams, MovieEntity } from '../store/ducks/movies/types';
import { ApplicationState } from '../store/interface';
import MovieCard from './MovieCard';
const baseQuery: FetchMovieParams = {
perPage: 12,
page: 0,
orderBy: 'title',
order: 'desc',
filters: {
title: 'Al',
},
};
const MovieTable = ({ path }: { path: string }): JSX.Element => {
const dispatch = useDispatch();
const { data, documentCount, loading, error } = useSelector(
({ movies }: ApplicationState) => movies
);
const [movies, setMovies] = useState<MovieEntity[]>([]);
const [prevPageLoaded, setPageLoaded] = useState(0);
const fetchByPage = (page: number) => {
dispatch(fetchMovies({ ...baseQuery, page }));
};
// Fetch movies on mount
useEffect(() => {
dispatch(fetchMovies(baseQuery));
setPageLoaded(baseQuery.page);
}, []);
// Fetch movies on page change
useEffect(() => {
if (!error && !loading) {
console.log(movies);
setMovies([...movies, ...data]);
}
}, [data]);
return (
<FlatList
contentContainerStyle={styles.movieList}
data={movies}
numColumns={2}
keyExtractor={(movie) => movie.id}
onEndReached={({ distanceFromEnd }) => {
// Prevent bug where onEndReached is called multiple times
if (distanceFromEnd < 0) return;
// Prevent fetching if all movies are loaded
if (prevPageLoaded + 1 >= Math.ceil(documentCount / baseQuery.perPage))
return;
fetchByPage(prevPageLoaded + 1);
setPageLoaded(prevPageLoaded + 1);
}}
onEndReachedThreshold={0.5}
initialNumToRender={baseQuery.perPage}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => <MovieCard movie={item} />}
ListFooterComponent={() => (
<>{loading && <Text style={styles.loading}>Loading...</Text>}</>
)}
/>
);
};
const styles = StyleSheet.create({
movieList: {
marginTop: 8,
textAlign: 'center',
// justifyContent: 'center',
display: 'flex',
flex: 1,
flexDirection: 'column',
gap: 8,
},
loading: {
fontWeight: 'bold',
marginBottom: 8,
},
});
export default MovieTable;
......@@ -25,6 +25,11 @@ const linking: LinkingOptions<RootStackParamList> = {
TabTwoScreen: 'two',
},
},
MovieTableTab: {
screens: {
MovieTableTabScreen: 'movieTable',
},
},
},
},
Modal: 'modal',
......
......@@ -5,7 +5,11 @@
*/
import { FontAwesome } from '@expo/vector-icons';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
import {
NavigationContainer,
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import * as React from 'react';
import { ColorSchemeName, Pressable } from 'react-native';
......@@ -13,17 +17,27 @@ import { ColorSchemeName, Pressable } from 'react-native';
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 TabOneScreen from '../screens/TabOneScreen';
import Profile from '../screens/Profile';
import { RootStackParamList, RootTabParamList, RootTabScreenProps } from '../types';
import {
RootStackParamList,
RootTabParamList,
RootTabScreenProps,
} from '../types';
import LinkingConfiguration from './LinkingConfiguration';
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
export default function Navigation({
colorScheme,
}: {
colorScheme: ColorSchemeName;
}) {
return (
<NavigationContainer
linking={LinkingConfiguration}
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
>
<RootNavigator />
</NavigationContainer>
);
......@@ -38,8 +52,16 @@ const Stack = createNativeStackNavigator<RootStackParamList>();
function RootNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Root" component={BottomTabNavigator} options={{ headerShown: false }} />
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
<Stack.Screen
name="Root"
component={BottomTabNavigator}
options={{ headerShown: false }}
/>
<Stack.Screen
name="NotFound"
component={NotFoundScreen}
options={{ title: 'Oops!' }}
/>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Modal" component={ModalScreen} />
</Stack.Group>
......@@ -61,7 +83,8 @@ function BottomTabNavigator() {
initialRouteName="TabOne"
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme].tint,
}}>
}}
>
<BottomTab.Screen
name="TabOne"
component={TabOneScreen}
......@@ -73,7 +96,8 @@ function BottomTabNavigator() {
onPress={() => navigation.navigate('Modal')}
style={({ pressed }) => ({
opacity: pressed ? 0.5 : 1,
})}>
})}
>
<FontAwesome
name="info-circle"
size={25}
......@@ -92,10 +116,11 @@ function BottomTabNavigator() {
tabBarIcon: ({ color }) => <TabBarIcon name="user" color={color} />,
headerRight: () => (
<Pressable
onPress={() => logout()}
onPress={() => 0}
style={({ pressed }) => ({
opacity: pressed ? 0.5 : 1,
})}>
})}
>
<FontAwesome
name="sign-out"
size={25}
......@@ -106,6 +131,14 @@ function BottomTabNavigator() {
),
}}
/>
<BottomTab.Screen
name="MovieTableTab"
component={MovieTableScreen}
options={{
title: 'Movie Table Tab',
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
}}
/>
</BottomTab.Navigator>
);
}
......
......@@ -9,8 +9,12 @@ export default function ModalScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Modal</Text>
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
<EditScreenInfo path="/screens/ModalScreen.tsx" />
<View
style={styles.separator}
lightColor="#eee"
darkColor="rgba(255,255,255,0.1)"
/>
{/* <EditScreenInfo path="/screens/ModalScreen.tsx" /> */}
{/* Use a light status bar on iOS to account for the black space above the modal */}
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
......
import * as React from 'react';
import { StyleSheet } from 'react-native';
import MovieTable from '../components/MovieTable';
import { Text, View } from '../components/Themed';
import { RootTabScreenProps } from '../types';
export default function MovieTableScreen({
navigation,
}: RootTabScreenProps<'MovieTableTab'>) {
return (
<View style={styles.container}>
<MovieTable path="/screens/TabOneScreen.tsx" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '90%',
},
});
......@@ -4,7 +4,10 @@
*/
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
import {
CompositeScreenProps,
NavigatorScreenParams,
} from '@react-navigation/native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
declare global {
......@@ -19,17 +22,18 @@ export type RootStackParamList = {
NotFound: undefined;
};
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
RootStackParamList,
Screen
>;
export type RootStackScreenProps<Screen extends keyof RootStackParamList> =
NativeStackScreenProps<RootStackParamList, Screen>;
export type RootTabParamList = {
TabOne: undefined;
TabTwo: undefined;
MovieTableTab: undefined;
Profile: undefined;
};
export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
BottomTabScreenProps<RootTabParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>;
export type RootTabScreenProps<Screen extends keyof RootTabParamList> =
CompositeScreenProps<
BottomTabScreenProps<RootTabParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>;
......@@ -1961,6 +1961,21 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
"@types/react-native-vector-icons@^6.4.6":
version "6.4.10"
resolved "https://registry.yarnpkg.com/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.10.tgz#9bfd6e64dd37b8119425496b5e53ff91d034efa9"
integrity sha512-z4sexbuZ7nmYsp7Z9YB5fSQoN3KFn6nZA3QsCkQLOYnVmVlxX4U22v/bM9Xx/6dOA1vClxoRZo2CFDX16uryXQ==
dependencies:
"@types/react" "*"
"@types/react-native" "*"
"@types/react-native@*":
version "0.66.4"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.66.4.tgz#075d9521de1ee53a4f3eff729133d897039c0d7f"
integrity sha512-Aby37oZ0S8LS4abOVWbBgChfHLZsx3skcj2QJU9ZHPhA1h6+yBbdBH2wJLxIUXfYT1Ejkwuv8n5u+/VxLzzcmA==
dependencies:
"@types/react" "*"
"@types/react-native@~0.64.12":
version "0.64.19"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.64.19.tgz#2b888c082ad293fa0fa6ae34c5e9457cfb38e50a"
......@@ -2911,7 +2926,7 @@ color-string@^1.5.3, color-string@^1.6.0:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^3.1.3:
color@^3.1.2, color@^3.1.3:
version "3.2.1"
resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164"
integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
......@@ -6053,6 +6068,11 @@ open@^6.2.0:
dependencies:
is-wsl "^1.1.0"
opencollective-postinstall@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==
optimism@^0.16.1:
version "0.16.1"
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d"
......@@ -6801,6 +6821,20 @@ react-native-collapsible@^1.6.0:
resolved "https://registry.yarnpkg.com/react-native-collapsible/-/react-native-collapsible-1.6.0.tgz#ca261ffff16914f872059bb0972e3a78c4b37f9c"
integrity sha512-beZjdgbT9Y/Pg591Xy5XkKG20HffJiVad4n9bfcUF/f783A+tvOVXnqvbS58Lkaym93mi4jcDPMuW9Vc1t6rqg==
react-native-elements@^3.4.2:
version "3.4.2"
resolved "https://registry.yarnpkg.com/react-native-elements/-/react-native-elements-3.4.2.tgz#66602be9c5e0e0a2a831913adec80ff6518d1ee2"
integrity sha512-m0eAWOn7JuR1wNTNY0WHuaqst4LI/gFE4N5Bbyfsc4DiryWsMST7aAg5w/Gos4IexWIzhLKCIkPxthND1m/8Xg==
dependencies:
"@types/react-native-vector-icons" "^6.4.6"
color "^3.1.2"
deepmerge "^4.2.2"
hoist-non-react-statics "^3.3.2"
lodash.isequal "^4.5.0"
opencollective-postinstall "^2.0.3"
react-native-ratings "8.0.4"
react-native-size-matters "^0.3.1"
react-native-modal-popover@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-native-modal-popover/-/react-native-modal-popover-2.1.0.tgz#45a2060012796f29184e6c41b787f14336d3b435"
......@@ -6809,6 +6843,20 @@ react-native-modal-popover@^2.0.1:
lodash "^4.17.21"
prop-types "^15.7.2"
react-native-ratings@8.0.4:
version "8.0.4"
resolved "https://registry.yarnpkg.com/react-native-ratings/-/react-native-ratings-8.0.4.tgz#efd5ebad8acc08bf98d34d39b18fb7a6813ef991"
integrity sha512-Xczu5lskIIRD6BEdz9A0jDRpEck/SFxRqiglkXi0u67yAtI1/pcJC76P4MukCbT8K4BPVl+42w83YqXBoBRl7A==
dependencies:
lodash "^4.17.15"
react-native-ratings@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/react-native-ratings/-/react-native-ratings-8.1.0.tgz#3fa9ad29128dc3a88e59518ba151e61c59dd0647"
integrity sha512-+QOJ4G3NjVkI1D+tk4EGx1dCvVfbD2nQdkrj9cXrcAoEiwmbep4z4bZbCKmWMpQ5h2dqbxABU8/eBnbDmvAc3g==
dependencies:
lodash "^4.17.15"
react-native-safe-area-context@3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz#9549a2ce580f2374edb05e49d661258d1b8bcaed"
......@@ -6821,6 +6869,11 @@ react-native-screens@~3.8.0:
dependencies:
warn-once "^0.1.0"
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"
integrity sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw==
react-native-web@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.17.1.tgz#90d473c89dd99b88bc9830b2a9fcdd2fc5f04902"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment