Refactor Skills component: improve data loading logic with useCallback, add error handling, update UI styles, and enhance state management.

This commit is contained in:
2025-07-13 02:28:15 +02:00
parent fbd5b2cfb6
commit 81b365d8a2

View File

@@ -1,53 +1,72 @@
import {useEffect, useState} from 'react'; import {useCallback, useEffect, useState} from 'react';
import type {CharacterData} from '@/types/CharacterJson.ts'; import type {CharacterData} from '@/types/CharacterJson.ts';
import {loadSkillsWithValues, type SkillWithValue} from '@/utils/loaders.ts'; import {loadSkillsWithValues, type SkillWithValue} from '@/utils/loaders.ts';
export default function Skills({jsonData}: { jsonData: CharacterData }) { export default function Skills({jsonData}: { jsonData: CharacterData }) {
const [skills, setSkills] = useState<SkillWithValue[]>([]); const [skills, setSkills] = useState<SkillWithValue[]>([]);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
useEffect(() => { const resetToDefaults = useCallback(() => {
let isMounted = true; setSkills([]);
}, []);
const loadData = useCallback(async (signal: AbortSignal) => {
setLoading(true);
setError(null);
const loadData = async () => { try {
try { // Load skills with their values using the new loader function
setLoading(true); const loadedSkills = await loadSkillsWithValues(jsonData.talents);
// Load skills with their values using the new loader function
const loadedSkills = await loadSkillsWithValues(jsonData.talents); // Check if component is still mounted and request wasn't cancelled
if (signal.aborted) return;
if (isMounted) {
setSkills(loadedSkills); setSkills(loadedSkills);
setLoading(false); } catch (err) {
} if (signal.aborted) return;
} catch (error) {
console.error('Error loading skills:', error); const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
if (isMounted) { console.error('Error loading skills:', errorMessage);
setError('Failed to load skills. Please try again.'); setError('Failed to load skills. Please try again.');
setLoading(false);
} // Reset to default values on error
resetToDefaults();
} finally {
if (!signal.aborted) {
setLoading(false);
} }
}; }
}, [jsonData.talents, resetToDefaults]);
useEffect(() => {
const abortController = new AbortController();
loadData(); loadData(abortController.signal);
return () => { return () => {
isMounted = false; abortController.abort();
}; };
}, [jsonData.talents]); }, [loadData]);
if (loading) { if (loading) {
return <div>Loading skills...</div>; return <div className="animate-pulse">Loading skills...</div>;
} }
if (error) { if (error) {
return <div className="text-red-500">{error}</div>; return (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
Error loading skills: {error}
</div>
);
} }
if (skills.length === 0) { if (skills.length === 0) {
return <div>No skills found.</div>; return <div>No skills found.</div>;
} }
console.log(jsonData);
return ( return (
<div className="p-4"> <div className="p-4">
<h1 className="text-2xl font-bold mb-4">Skills</h1> <h1 className="text-2xl font-bold mb-4">Skills</h1>
@@ -56,7 +75,9 @@ export default function Skills({jsonData}: { jsonData: CharacterData }) {
<div key={skill.id} className="border p-3 rounded shadow"> <div key={skill.id} className="border p-3 rounded shadow">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h2 className="text-lg font-semibold">{skill.name}</h2> <h2 className="text-lg font-semibold">{skill.name}</h2>
<span className="bg-blue-100 text-blue-800 font-bold px-2 py-1 rounded"> <span
className="bg-blue-100 text-blue-800 font-bold px-2 py-1 rounded flex items-center justify-center"
style={{width: '2.5em'}}>
{skill.value} {skill.value}
</span> </span>
</div> </div>
@@ -70,12 +91,12 @@ export default function Skills({jsonData}: { jsonData: CharacterData }) {
{/* </ul>*/} {/* </ul>*/}
{/* </div>*/} {/* </div>*/}
{/*)}*/} {/*)}*/}
{/*{skill.tools && (*/} {skill.tools && (
{/* <div className="mt-2">*/} <div className="mt-2">
{/* <h3 className="font-medium">Tools:</h3>*/} <h3 className="font-medium">Tools:</h3>
{/* <p className="text-sm">{skill.tools}</p>*/} <p className="text-sm">{skill.tools}</p>
{/* </div>*/} </div>
{/*)}*/} )}
</div> </div>
))} ))}
</div> </div>