feat: add autocomplete search with Zustand store and API layer

- Add PokemonAutoComplete atom component using Ant Design
- Implement API layer with axios for Pokémon data fetching
- Create Zustand store for centralized state management
- Add autocomplete suggestions with real-time filtering
- Update SearchBar molecule to use autocomplete functionality
- Load all Pokémon names on app initialization
- Add path aliases for cleaner imports (@api, @stores)
- Remove old service layer in favor of API layer
- Maintain intentional bugs for debugging practice
- Update project structure and documentation
This commit is contained in:
Carlos
2025-08-03 15:31:55 -04:00
commit e61b8c58fd
31 changed files with 6129 additions and 0 deletions

37
src/api/config.ts Normal file
View File

@@ -0,0 +1,37 @@
import axios from 'axios';
const BASE_URL = 'https://pokeapi.co/api/v2';
const api = axios.create({
baseURL: BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// Request interceptor
api.interceptors.request.use(
(config) => {
console.log(`Making ${config.method?.toUpperCase()} request to: ${config.url}`);
return config;
},
(error) => {
console.error('Request error:', error);
return Promise.reject(error);
}
);
// Response interceptor
api.interceptors.response.use(
(response) => {
console.log(`Response received from: ${response.config.url}`, response.status);
return response;
},
(error) => {
console.error('Response error:', error);
return Promise.reject(error);
}
);
export default api;

34
src/api/get/pokemon.ts Normal file
View File

@@ -0,0 +1,34 @@
import api from '../config';
import type { Pokemon } from '@pokemonTypes/pokemon';
export const getPokemon = async (name: string): Promise<Pokemon> => {
try {
const response = await api.get<Pokemon>(`/pokemon/${name.toLowerCase()}`);
return response.data;
} catch (error) {
// Intentional bug #1: No proper error handling for non-existent Pokémon
console.error('Error fetching Pokémon:', error);
throw error;
}
};
export const getPokemonList = async (limit: number = 20, offset: number = 0) => {
try {
const response = await api.get(`/pokemon?limit=${limit}&offset=${offset}`);
return response.data;
} catch (error) {
console.error('Error fetching Pokémon list:', error);
throw error;
}
};
export const getAllPokemonNames = async (): Promise<string[]> => {
try {
// Fetch all Pokémon names (151 total in the original Pokédex)
const response = await api.get('/pokemon?limit=151&offset=0');
return response.data.results.map((pokemon: { name: string }) => pokemon.name);
} catch (error) {
console.error('Error fetching all Pokémon names:', error);
return [];
}
};

14
src/api/index.ts Normal file
View File

@@ -0,0 +1,14 @@
// API configuration
export { default as api } from './config';
// GET requests
export * from './get/pokemon';
// POST requests (for future use)
// export * from './post/';
// PUT requests (for future use)
// export * from './put/';
// DELETE requests (for future use)
// export * from './delete/';