Skip to content

Commit e384333

Browse files
committed
feat:pokemon pages infra added.
1 parent 9954edf commit e384333

File tree

9 files changed

+156
-2
lines changed

9 files changed

+156
-2
lines changed

App.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {NavigationContainer} from '@react-navigation/native';
55
import UserDetailScreen from './src/presentation/pages/UserDetailScreen';
66
import CharacterScreen from './src/presentation/pages/CharacterScreen';
77
import {QueryClient, QueryClientProvider} from 'react-query';
8+
import PokemonScreen from './src/presentation/pages/PokemonScreen';
89

910
const Stack = createNativeStackNavigator();
1011
const queryClient = new QueryClient();
@@ -13,7 +14,8 @@ export default function MyStack() {
1314
return (
1415
<QueryClientProvider client={queryClient}>
1516
<NavigationContainer>
16-
<Stack.Navigator initialRouteName="Characters">
17+
<Stack.Navigator initialRouteName="Pokemon">
18+
<Stack.Screen name="Pokemon" component={PokemonScreen} />
1719
<Stack.Screen name="Characters" component={CharacterScreen} />
1820
<Stack.Screen name="User" component={UserScreen} />
1921
<Stack.Screen name="UserDetail" component={UserDetailScreen} />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {Pokemon} from '../../domain/entities/Pokemon';
2+
3+
export interface IPokemonRepository {
4+
getAllPokemons(limit: number, offset: number): Promise<Pokemon[]>;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {Pokemon} from '../../domain/entities/Pokemon';
2+
import {fetchPokemons} from '../../infrastructure/network/ApiClient';
3+
import {IPokemonRepository} from '../models/IPokemonRepository';
4+
5+
export class PokemonRepository implements IPokemonRepository {
6+
async getAllPokemons(limit: number, offset: number): Promise<Pokemon[]> {
7+
const data = await fetchPokemons(limit, offset);
8+
return data.results.map((poke: any) => new Pokemon(poke.name, poke.url));
9+
}
10+
}

src/domain/entities/Pokemon.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export class Pokemon {
2+
constructor(public name: string, public url: string) {}
3+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {IPokemonRepository} from '../../application/models/IPokemonRepository';
2+
import {Pokemon} from '../entities/Pokemon';
3+
4+
export class GetPokemonsUseCase {
5+
constructor(private pokemonRepository: IPokemonRepository) {}
6+
7+
async execute(limit: number, offset: number): Promise<Pokemon[]> {
8+
return await this.pokemonRepository.getAllPokemons(limit, offset);
9+
}
10+
}

src/infrastructure/network/ApiClient.ts

+7
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ export const fetchCharacters = async (page: number) => {
44
);
55
return await response.json();
66
};
7+
8+
export const fetchPokemons = async (limit: number, offset: number) => {
9+
const response = await fetch(
10+
`https://pokeapi.co/api/v2/pokemon?limit=${limit}&offset=${offset}`,
11+
);
12+
return await response.json();
13+
};
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import {
2+
View,
3+
Text,
4+
FlatList,
5+
ActivityIndicator,
6+
Image,
7+
StyleSheet,
8+
} from 'react-native';
9+
import React from 'react';
10+
import usePokemonViewModel from '../viewModels/PokemonViewModel';
11+
import {Pokemon} from '../../domain/entities/Pokemon';
12+
13+
const PokemonScreen: React.FC = () => {
14+
const {
15+
pokemons,
16+
error,
17+
isFetching,
18+
isFetchingNextPage,
19+
fetchNextPage,
20+
hasNextPage,
21+
} = usePokemonViewModel();
22+
23+
if (isFetching && !isFetchingNextPage) {
24+
return <ActivityIndicator size="large" />;
25+
}
26+
27+
if (error) {
28+
return <Text>Bir hata oluştu</Text>;
29+
}
30+
31+
return (
32+
<View style={styles.container}>
33+
<FlatList<Pokemon>
34+
data={pokemons}
35+
keyExtractor={item => item.name}
36+
renderItem={({item}) => (
37+
<View style={styles.cardContainer}>
38+
<Image
39+
source={{
40+
uri: `https://img.pokemondb.net/artwork/${item.name}.jpg`,
41+
}}
42+
style={styles.image}
43+
resizeMode="contain"
44+
/>
45+
<View style={styles.textContainer}>
46+
<Text style={styles.title}>{item.name}</Text>
47+
</View>
48+
</View>
49+
)}
50+
onEndReached={() => {
51+
if (hasNextPage) {
52+
fetchNextPage();
53+
}
54+
}}
55+
onEndReachedThreshold={0.8}
56+
ListFooterComponent={
57+
isFetchingNextPage ? <ActivityIndicator size="large" /> : null
58+
}
59+
/>
60+
</View>
61+
);
62+
};
63+
64+
const styles = StyleSheet.create({
65+
container: {flex: 1, padding: 20, backgroundColor: '#fff'},
66+
cardContainer: {
67+
padding: 10,
68+
borderBottomWidth: 1,
69+
borderBottomColor: '#ccc',
70+
flexDirection: 'row',
71+
alignItems: 'center',
72+
},
73+
image: {width: 100, height: 100, marginRight: 10},
74+
title: {fontSize: 20, fontWeight: '800', textTransform: 'capitalize'},
75+
textContainer: {gap: 5},
76+
});
77+
78+
export default PokemonScreen;

src/presentation/viewModels/CharacterViewModel.ts

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const characterRepository = new CharacterRepository();
66
const getCharactersUseCase = new GetCharactersUseCase(characterRepository);
77

88
const fetchCharacters = async ({pageParam = 1}: {pageParam: number}) => {
9-
console.log('PageParam', pageParam);
109
return await getCharactersUseCase.execute(pageParam);
1110
};
1211

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {useInfiniteQuery} from 'react-query';
2+
import {GetPokemonsUseCase} from '../../domain/usecases/GetPokemonsUseCase';
3+
import {PokemonRepository} from '../../application/repositories/PokemonRepository';
4+
5+
const pokemonRepository = new PokemonRepository();
6+
const getPokemonsUseCase = new GetPokemonsUseCase(pokemonRepository);
7+
8+
const fetchPokemons = async ({pageParam = 0}) => {
9+
const limit = 10;
10+
const offset = pageParam * limit;
11+
return await getPokemonsUseCase.execute(limit, offset);
12+
};
13+
14+
export default function usePokemonViewModel() {
15+
const {
16+
data,
17+
error,
18+
fetchNextPage,
19+
hasNextPage,
20+
isFetching,
21+
isFetchingNextPage,
22+
} = useInfiniteQuery(
23+
['pokemons'],
24+
({pageParam}) => fetchPokemons({pageParam}),
25+
{
26+
getNextPageParam: (lastPage, allPages) => {
27+
return allPages.length;
28+
},
29+
},
30+
);
31+
32+
return {
33+
pokemons: data ? data.pages.flat() : [],
34+
error,
35+
isFetching,
36+
isFetchingNextPage,
37+
fetchNextPage,
38+
hasNextPage,
39+
};
40+
}

0 commit comments

Comments
 (0)