Enhance Pokémon data retrieval by optimizing SQL query, adding caching for images, and improving error handling in the frontend

This commit is contained in:
vista-man
2025-03-25 12:04:10 +01:00
parent da85c00da6
commit 326e4da1cb
3 changed files with 54 additions and 18 deletions

View File

@@ -10,13 +10,26 @@ if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
header("Cache-Control: max-age=3600"); // Cache for 1 hour
if (isset($_GET['id'])) {
$id = intval($_GET['id']);
$sql = "SELECT * FROM pokemon WHERE id = $id";
$sql = "SELECT p.*, s.flavor_text, GROUP_CONCAT(t.name) AS types, GROUP_CONCAT(a.name) AS abilities, st.hp, st.attack, st.defense, st.sp_attack, st.sp_defense, st.speed
FROM pokemon p
LEFT JOIN species s ON p.id = s.pokemon_id
LEFT JOIN pokemon_types pt ON p.id = pt.pokemon_id
LEFT JOIN types t ON pt.type_id = t.id
LEFT JOIN pokemon_abilities pa ON p.id = pa.pokemon_id
LEFT JOIN abilities a ON pa.ability_id = a.id
LEFT JOIN stats st ON p.id = st.pokemon_id
WHERE p.id = $id
GROUP BY p.id";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$pokemon = $result->fetch_assoc();
$pokemon['types'] = explode(',', $pokemon['types']);
$pokemon['abilities'] = explode(',', $pokemon['abilities']);
echo json_encode($pokemon);
} else {
echo json_encode(["error" => "No Pokémon found"]);

View File

@@ -56,7 +56,7 @@ async function loadPokemon(id) {
return true;
} catch (error) {
console.error("An error occurred while fetching Pokémon data:", error);
return false;
return (window.location.href = "./index.html");
}
}
@@ -101,7 +101,7 @@ function rgbaFromHex(hexColor) {
}
function setTypeBackgroundColor(pokemon) {
const mainType = pokemon.types[0].type.name;
const mainType = pokemon.types[0];
const color = typeColors[mainType];
if (!color) {
@@ -158,7 +158,7 @@ function createAndAppendElement(parent, tag, options = {}) {
}
function displayPokemonDetails(pokemon) {
const { name, id, types, weight, height, abilities, stats } = pokemon;
const { name, id, types, weight, height, abilities, hp, attack, defense, sp_attack, sp_defense, speed } = pokemon;
const capitalizePokemonName = capitalizeFirstLetter(name);
document.querySelector("title").textContent = capitalizePokemonName;
@@ -174,15 +174,15 @@ function displayPokemonDetails(pokemon) {
).textContent = `#${String(id).padStart(3, "0")}`;
const imageElement = document.querySelector(".detail-img-wrapper img");
imageElement.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/${id}.svg`;
imageElement.src = pokemon.image_url;
imageElement.alt = name;
const typeWrapper = document.querySelector(".power-wrapper");
typeWrapper.innerHTML = "";
types.forEach(({ type }) => {
types.forEach((type) => {
createAndAppendElement(typeWrapper, "p", {
className: `body3-fonts type ${type.name}`,
textContent: type.name,
className: `body3-fonts type ${type}`,
textContent: type,
});
});
@@ -196,10 +196,10 @@ function displayPokemonDetails(pokemon) {
const abilitiesWrapper = document.querySelector(
".pokemon-detail-wrap .pokemon-detail.move"
);
abilities.forEach(({ ability }) => {
abilities.forEach((ability) => {
createAndAppendElement(abilitiesWrapper, "p", {
className: "body3-fonts",
textContent: ability.name,
textContent: ability,
});
});
@@ -210,29 +210,31 @@ function displayPokemonDetails(pokemon) {
hp: "HP",
attack: "ATK",
defense: "DEF",
"special-attack": "SATK",
"special-defense": "SDEF",
sp_attack: "SATK",
sp_defense: "SDEF",
speed: "SPD",
};
stats.forEach(({ stat, base_stat }) => {
const stats = { hp, attack, defense, sp_attack, sp_defense, speed };
Object.keys(stats).forEach((stat) => {
const statDiv = document.createElement("div");
statDiv.className = "stats-wrap";
statsWrapper.appendChild(statDiv);
createAndAppendElement(statDiv, "p", {
className: "body3-fonts stats",
textContent: statNameMapping[stat.name],
textContent: statNameMapping[stat],
});
createAndAppendElement(statDiv, "p", {
className: "body3-fonts",
textContent: String(base_stat).padStart(3, "0"),
textContent: String(stats[stat]).padStart(3, "0"),
});
createAndAppendElement(statDiv, "progress", {
className: "progress-bar",
value: base_stat,
value: stats[stat],
max: 100,
});
});

View File

@@ -12,6 +12,7 @@ fetch(`./get-pokemon.php`)
.then((data) => {
if (Array.isArray(data)) {
allPokemons = data;
cacheImages(allPokemons);
displayPokemons(allPokemons);
} else {
console.error("Unexpected response format:", data);
@@ -30,14 +31,32 @@ async function fetchPokemonDataBeforeRedirect(id) {
return true;
} catch (error) {
console.error("Failed to fetch Pokémon data before redirect");
console.error("Failed to fetch Pokémon data before redirect:", error);
return false;
}
}
function cacheImages(pokemons) {
pokemons.forEach((pokemon) => {
const img = new Image();
img.src = pokemon.image_url;
img.onload = () => {
localStorage.setItem(`pokemon_image_${pokemon.id}`, pokemon.image_url);
};
});
}
function getCachedImageUrl(pokemonId) {
return localStorage.getItem(`pokemon_image_${pokemonId}`);
}
function displayPokemons(pokemons) {
listWrapper.innerHTML = "";
pokemons.forEach((pokemon) => {
const cachedImageUrl = getCachedImageUrl(pokemon.id);
const imageUrl = cachedImageUrl || pokemon.image_url;
const listItem = document.createElement("div");
listItem.className = "list-item";
listItem.innerHTML = `
@@ -45,7 +64,7 @@ function displayPokemons(pokemons) {
<p class="caption-fonts">#${pokemon.id}</p>
</div>
<div class="img-wrap">
<img src="${pokemon.image_url}" alt="${pokemon.name}" />
<img src="${imageUrl}" alt="${pokemon.name}" />
</div>
<div class="name-wrap">
<p class="body3-fonts">#${pokemon.name}</p>
@@ -56,6 +75,8 @@ function displayPokemons(pokemons) {
const success = await fetchPokemonDataBeforeRedirect(pokemon.id);
if (success) {
window.location.href = `./detail.html?id=${pokemon.id}`;
} else {
console.error(`Failed to fetch data for Pokémon ID: ${pokemon.id}`);
}
});