feat(ui): add cv application frontend and configuration
This commit is contained in:
132
src/admin/hooks/CVContext.jsx
Normal file
132
src/admin/hooks/CVContext.jsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
||||
import { fetchCV as apiFetchCV, updateCV as apiUpdateCV, exportCV as apiExportCV, importCV as apiImportCV } from '../../lib/api';
|
||||
import { DEFAULT_DATA, validateCV } from '../../lib/cv-data';
|
||||
|
||||
const CVContext = createContext(null);
|
||||
|
||||
export function CVProvider({ children }) {
|
||||
const [data, setData] = useState(DEFAULT_DATA);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
apiFetchCV()
|
||||
.then(data => {
|
||||
setData(data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to fetch CV:', err);
|
||||
setError(err.message);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const updatePersonal = useCallback(async (personal) => {
|
||||
const newData = { ...data, personal };
|
||||
setData(newData);
|
||||
await apiUpdateCV(newData);
|
||||
}, [data]);
|
||||
|
||||
const updateExperience = useCallback(async (experience) => {
|
||||
const newData = { ...data, experience };
|
||||
setData(newData);
|
||||
await apiUpdateCV(newData);
|
||||
}, [data]);
|
||||
|
||||
const updateSkills = useCallback(async (skills) => {
|
||||
const newData = { ...data, skills };
|
||||
setData(newData);
|
||||
await apiUpdateCV(newData);
|
||||
}, [data]);
|
||||
|
||||
const updateEducation = useCallback(async (education) => {
|
||||
const newData = { ...data, education };
|
||||
setData(newData);
|
||||
await apiUpdateCV(newData);
|
||||
}, [data]);
|
||||
|
||||
const updateProjects = useCallback(async (projects) => {
|
||||
const newData = { ...data, projects };
|
||||
setData(newData);
|
||||
await apiUpdateCV(newData);
|
||||
}, [data]);
|
||||
|
||||
const exportJSON = useCallback(async () => {
|
||||
const validation = validateCV(data);
|
||||
if (!validation.valid) {
|
||||
console.warn('Exporting CV with validation warnings:', validation.errors);
|
||||
}
|
||||
|
||||
const blob = await apiExportCV();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'cv.json';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}, [data]);
|
||||
|
||||
const importJSON = useCallback(async (jsonString) => {
|
||||
try {
|
||||
const parsed = JSON.parse(jsonString);
|
||||
const validation = validateCV(parsed);
|
||||
if (!validation.valid) {
|
||||
return { success: false, errors: validation.errors };
|
||||
}
|
||||
await apiImportCV(parsed);
|
||||
setData(parsed);
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
return { success: false, errors: [`JSON parse error: ${e.message}`] };
|
||||
}
|
||||
}, []);
|
||||
|
||||
const resetToDefault = useCallback(async () => {
|
||||
await apiUpdateCV(DEFAULT_DATA);
|
||||
setData(DEFAULT_DATA);
|
||||
}, []);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await apiFetchCV();
|
||||
setData(data);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<CVContext.Provider value={{
|
||||
data,
|
||||
loading,
|
||||
error,
|
||||
updatePersonal,
|
||||
updateExperience,
|
||||
updateSkills,
|
||||
updateEducation,
|
||||
updateProjects,
|
||||
exportJSON,
|
||||
importJSON,
|
||||
resetToDefault,
|
||||
refresh
|
||||
}}>
|
||||
{children}
|
||||
</CVContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export function useCVData() {
|
||||
const context = useContext(CVContext);
|
||||
if (!context) {
|
||||
throw new Error('useCVData must be used within a CVProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
Reference in New Issue
Block a user