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 {loadSkillsWithValues, type SkillWithValue} from '@/utils/loaders.ts';
export default function Skills({jsonData}: { jsonData: CharacterData }) {
const [skills, setSkills] = useState<SkillWithValue[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let isMounted = true;
const resetToDefaults = useCallback(() => {
setSkills([]);
}, []);
const loadData = useCallback(async (signal: AbortSignal) => {
setLoading(true);
setError(null);
const loadData = async () => {
try {
setLoading(true);
// Load skills with their values using the new loader function
const loadedSkills = await loadSkillsWithValues(jsonData.talents);
if (isMounted) {
setSkills(loadedSkills);
setLoading(false);
}
} catch (error) {
console.error('Error loading skills:', error);
if (isMounted) {
setError('Failed to load skills. Please try again.');
setLoading(false);
}
try {
// 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;
setSkills(loadedSkills);
} catch (err) {
if (signal.aborted) return;
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
console.error('Error loading skills:', errorMessage);
setError('Failed to load skills. Please try again.');
// 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 () => {
isMounted = false;
abortController.abort();
};
}, [jsonData.talents]);
}, [loadData]);
if (loading) {
return <div>Loading skills...</div>;
return <div className="animate-pulse">Loading skills...</div>;
}
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) {
return <div>No skills found.</div>;
}
console.log(jsonData);
return (
<div className="p-4">
<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 className="flex justify-between items-center">
<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}
</span>
</div>
@@ -70,12 +91,12 @@ export default function Skills({jsonData}: { jsonData: CharacterData }) {
{/* </ul>*/}
{/* </div>*/}
{/*)}*/}
{/*{skill.tools && (*/}
{/* <div className="mt-2">*/}
{/* <h3 className="font-medium">Tools:</h3>*/}
{/* <p className="text-sm">{skill.tools}</p>*/}
{/* </div>*/}
{/*)}*/}
{skill.tools && (
<div className="mt-2">
<h3 className="font-medium">Tools:</h3>
<p className="text-sm">{skill.tools}</p>
</div>
)}
</div>
))}
</div>