feat: persist metafield resolutions across sessions
Les associations colonne→métachamp sont sauvegardées dans data/metafield-resolutions.json et rechargées automatiquement à la prochaine création de produits. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,25 +18,28 @@ export function MetafieldResolver({ specificColumns, onResolved }: Props) {
|
||||
const [searches, setSearches] = useState<Record<string, string>>({})
|
||||
const [openDropdown, setOpenDropdown] = useState<string | null>(null)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
const saveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (specificColumns.length === 0) { setLoading(false); onResolved([]); return }
|
||||
const params = specificColumns.map(c => encodeURIComponent(c)).join(',')
|
||||
fetch(`/api/creation/metafields?columns=${params}`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
Promise.all([
|
||||
fetch(`/api/creation/metafields?columns=${params}`).then(r => r.json()),
|
||||
fetch('/api/creation/resolutions').then(r => r.json()),
|
||||
])
|
||||
.then(([data, cache]: [{ error?: string; definitions: MetafieldDefinition[]; matched: Record<string, MetafieldResolution>; unmatched: string[] }, Record<string, MetafieldResolution>]) => {
|
||||
if (data.error) throw new Error(data.error)
|
||||
setDefinitions(data.definitions)
|
||||
setMatched(data.matched)
|
||||
setUnmatched(data.unmatched)
|
||||
const init: Record<string, MetafieldResolution> = { ...data.matched }
|
||||
// Défaut : 'skip' — l'utilisateur choisit explicitement ce qu'il veut créer
|
||||
data.unmatched.forEach((col: string) => {
|
||||
init[col] = { columnHeader: col, action: 'skip', namespace: 'custom', key: normalizeMetafieldKey(col) }
|
||||
// Utilise le cache persisté si disponible, sinon 'skip' par défaut
|
||||
init[col] = cache[col] ?? { columnHeader: col, action: 'skip', namespace: 'custom', key: normalizeMetafieldKey(col) }
|
||||
})
|
||||
setResolutions(init)
|
||||
})
|
||||
.catch(e => setError(e.message))
|
||||
.catch(e => setError((e as Error).message))
|
||||
.finally(() => setLoading(false))
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [specificColumns.join(',')])
|
||||
@@ -47,7 +50,19 @@ export function MetafieldResolver({ specificColumns, onResolved }: Props) {
|
||||
}, [resolutions, loading])
|
||||
|
||||
const updateResolution = (col: string, partial: Partial<MetafieldResolution>) => {
|
||||
setResolutions(prev => ({ ...prev, [col]: { ...prev[col], ...partial } }))
|
||||
setResolutions(prev => {
|
||||
const next = { ...prev, [col]: { ...prev[col], ...partial } }
|
||||
// Sauvegarde en différé pour éviter un appel par frappe
|
||||
if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)
|
||||
saveTimeoutRef.current = setTimeout(() => {
|
||||
fetch('/api/creation/resolutions', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(next),
|
||||
}).catch(() => null)
|
||||
}, 800)
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
const filteredDefs = (col: string) => {
|
||||
|
||||
Reference in New Issue
Block a user