Skip to content

Commit

Permalink
feat:pokemon pages infra added.
Browse files Browse the repository at this point in the history
  • Loading branch information
fturkyilmaz committed Jul 14, 2024
1 parent 9954edf commit e384333
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 2 deletions.
4 changes: 3 additions & 1 deletion App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {NavigationContainer} from '@react-navigation/native';
import UserDetailScreen from './src/presentation/pages/UserDetailScreen';
import CharacterScreen from './src/presentation/pages/CharacterScreen';
import {QueryClient, QueryClientProvider} from 'react-query';
import PokemonScreen from './src/presentation/pages/PokemonScreen';

const Stack = createNativeStackNavigator();
const queryClient = new QueryClient();
Expand All @@ -13,7 +14,8 @@ export default function MyStack() {
return (
<QueryClientProvider client={queryClient}>
<NavigationContainer>
<Stack.Navigator initialRouteName="Characters">
<Stack.Navigator initialRouteName="Pokemon">
<Stack.Screen name="Pokemon" component={PokemonScreen} />
<Stack.Screen name="Characters" component={CharacterScreen} />
<Stack.Screen name="User" component={UserScreen} />
<Stack.Screen name="UserDetail" component={UserDetailScreen} />
Expand Down
5 changes: 5 additions & 0 deletions src/application/models/IPokemonRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {Pokemon} from '../../domain/entities/Pokemon';

export interface IPokemonRepository {
getAllPokemons(limit: number, offset: number): Promise<Pokemon[]>;
}
10 changes: 10 additions & 0 deletions src/application/repositories/PokemonRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {Pokemon} from '../../domain/entities/Pokemon';
import {fetchPokemons} from '../../infrastructure/network/ApiClient';
import {IPokemonRepository} from '../models/IPokemonRepository';

export class PokemonRepository implements IPokemonRepository {
async getAllPokemons(limit: number, offset: number): Promise<Pokemon[]> {
const data = await fetchPokemons(limit, offset);
return data.results.map((poke: any) => new Pokemon(poke.name, poke.url));
}
}
3 changes: 3 additions & 0 deletions src/domain/entities/Pokemon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class Pokemon {
constructor(public name: string, public url: string) {}
}
10 changes: 10 additions & 0 deletions src/domain/usecases/GetPokemonsUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {IPokemonRepository} from '../../application/models/IPokemonRepository';
import {Pokemon} from '../entities/Pokemon';

export class GetPokemonsUseCase {
constructor(private pokemonRepository: IPokemonRepository) {}

async execute(limit: number, offset: number): Promise<Pokemon[]> {
return await this.pokemonRepository.getAllPokemons(limit, offset);
}
}
7 changes: 7 additions & 0 deletions src/infrastructure/network/ApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ export const fetchCharacters = async (page: number) => {
);
return await response.json();
};

export const fetchPokemons = async (limit: number, offset: number) => {
const response = await fetch(
`https://pokeapi.co/api/v2/pokemon?limit=${limit}&offset=${offset}`,
);
return await response.json();
};
78 changes: 78 additions & 0 deletions src/presentation/pages/PokemonScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
View,
Text,
FlatList,
ActivityIndicator,
Image,
StyleSheet,
} from 'react-native';
import React from 'react';
import usePokemonViewModel from '../viewModels/PokemonViewModel';
import {Pokemon} from '../../domain/entities/Pokemon';

const PokemonScreen: React.FC = () => {
const {
pokemons,
error,
isFetching,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
} = usePokemonViewModel();

if (isFetching && !isFetchingNextPage) {
return <ActivityIndicator size="large" />;
}

if (error) {
return <Text>Bir hata oluştu</Text>;
}

return (
<View style={styles.container}>
<FlatList<Pokemon>
data={pokemons}
keyExtractor={item => item.name}
renderItem={({item}) => (
<View style={styles.cardContainer}>
<Image
source={{
uri: `https://img.pokemondb.net/artwork/${item.name}.jpg`,
}}
style={styles.image}
resizeMode="contain"
/>
<View style={styles.textContainer}>
<Text style={styles.title}>{item.name}</Text>
</View>
</View>
)}
onEndReached={() => {
if (hasNextPage) {
fetchNextPage();
}
}}
onEndReachedThreshold={0.8}
ListFooterComponent={
isFetchingNextPage ? <ActivityIndicator size="large" /> : null
}
/>
</View>
);
};

const styles = StyleSheet.create({
container: {flex: 1, padding: 20, backgroundColor: '#fff'},
cardContainer: {
padding: 10,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
flexDirection: 'row',
alignItems: 'center',
},
image: {width: 100, height: 100, marginRight: 10},
title: {fontSize: 20, fontWeight: '800', textTransform: 'capitalize'},
textContainer: {gap: 5},
});

export default PokemonScreen;
1 change: 0 additions & 1 deletion src/presentation/viewModels/CharacterViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const characterRepository = new CharacterRepository();
const getCharactersUseCase = new GetCharactersUseCase(characterRepository);

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

Expand Down
40 changes: 40 additions & 0 deletions src/presentation/viewModels/PokemonViewModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {useInfiniteQuery} from 'react-query';
import {GetPokemonsUseCase} from '../../domain/usecases/GetPokemonsUseCase';
import {PokemonRepository} from '../../application/repositories/PokemonRepository';

const pokemonRepository = new PokemonRepository();
const getPokemonsUseCase = new GetPokemonsUseCase(pokemonRepository);

const fetchPokemons = async ({pageParam = 0}) => {
const limit = 10;
const offset = pageParam * limit;
return await getPokemonsUseCase.execute(limit, offset);
};

export default function usePokemonViewModel() {
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
} = useInfiniteQuery(
['pokemons'],
({pageParam}) => fetchPokemons({pageParam}),
{
getNextPageParam: (lastPage, allPages) => {
return allPages.length;
},
},
);

return {
pokemons: data ? data.pages.flat() : [],
error,
isFetching,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
};
}

0 comments on commit e384333

Please sign in to comment.