chore init
This commit is contained in:
1 parent
1b7406b1d3
commit
a0d312a884
60 files changed
+5046
-125
No files matched your search
@@ -0,0 +1,101 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback } from "react";
|
||||
import {
|
||||
createDefaultCVData,
|
||||
type CVCareerData,
|
||||
type CVTabId,
|
||||
type Experience,
|
||||
} from "@/lib/types/cv";
|
||||
import { localStorageAdapter } from "@/lib/storage";
|
||||
import { useLocalStorage } from "@/lib/hooks/useLocalStorage";
|
||||
|
||||
export interface UseCVDataReturn {
|
||||
data: CVCareerData;
|
||||
setText: (tab: CVTabId, value: string) => void;
|
||||
addExperience: (titre: string, contenu: string) => void;
|
||||
updateExperience: (id: string, titre: string, contenu: string) => void;
|
||||
removeExperience: (id: string) => void;
|
||||
resetCV: () => void;
|
||||
importCV: (value: CVCareerData) => void;
|
||||
}
|
||||
|
||||
const DEFAULT_TITLE = "Expérience";
|
||||
|
||||
export function useCVData(): UseCVDataReturn {
|
||||
const [data, setData] = useLocalStorage<CVCareerData>(
|
||||
localStorageAdapter,
|
||||
createDefaultCVData(),
|
||||
);
|
||||
|
||||
const setText = useCallback(
|
||||
(tab: CVTabId, value: string) => {
|
||||
setData((prev) => ({ ...prev, [tab]: value }));
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const addExperience = useCallback(
|
||||
(titre: string, contenu: string) => {
|
||||
setData((prev) => {
|
||||
const now = Date.now();
|
||||
const experience: Experience = {
|
||||
id: crypto.randomUUID(),
|
||||
titre: titre.trim() || DEFAULT_TITLE,
|
||||
contenu,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
return { ...prev, experiences: [...prev.experiences, experience] };
|
||||
});
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const updateExperience = useCallback(
|
||||
(id: string, titre: string, contenu: string) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
experiences: prev.experiences.map((exp) =>
|
||||
exp.id === id
|
||||
? {
|
||||
...exp,
|
||||
titre: titre.trim() || DEFAULT_TITLE,
|
||||
contenu,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
: exp,
|
||||
),
|
||||
}));
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const removeExperience = useCallback(
|
||||
(id: string) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
experiences: prev.experiences.filter((exp) => exp.id !== id),
|
||||
}));
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const resetCV = useCallback(() => {
|
||||
setData(createDefaultCVData());
|
||||
}, [setData]);
|
||||
|
||||
const importCV = useCallback((value: CVCareerData) => {
|
||||
setData(value);
|
||||
}, [setData]);
|
||||
|
||||
return {
|
||||
data,
|
||||
setText,
|
||||
addExperience,
|
||||
updateExperience,
|
||||
removeExperience,
|
||||
resetCV,
|
||||
importCV,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export interface StorageLike<T> {
|
||||
load(): T | null;
|
||||
save(value: T): void;
|
||||
}
|
||||
|
||||
const SAVE_DELAY_MS = 60;
|
||||
|
||||
export function useLocalStorage<T>(
|
||||
storage: StorageLike<T>,
|
||||
initialValue: T,
|
||||
enable = true,
|
||||
): [T, (value: T | ((prev: T) => T)) => void] {
|
||||
const [value, setValue] = useState<T>(initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enable) return;
|
||||
let disposed = false;
|
||||
const timer = window.setTimeout(() => {
|
||||
try {
|
||||
const stored = storage.load();
|
||||
if (disposed || stored === null || stored === undefined) return;
|
||||
setValue(stored);
|
||||
} catch (error) {
|
||||
console.warn("Échec du chargement localStorage", error);
|
||||
}
|
||||
}, 0);
|
||||
return () => {
|
||||
disposed = true;
|
||||
window.clearTimeout(timer);
|
||||
};
|
||||
}, [storage, enable]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enable) return;
|
||||
const timer = window.setTimeout(() => {
|
||||
try {
|
||||
storage.save(value);
|
||||
} catch (error) {
|
||||
console.warn("Échec de la sauvegarde localStorage", error);
|
||||
}
|
||||
}, SAVE_DELAY_MS);
|
||||
return () => {
|
||||
window.clearTimeout(timer);
|
||||
};
|
||||
}, [storage, value, enable]);
|
||||
|
||||
return [value, setValue];
|
||||
}
|
||||
Reference in new issue
Block a user