feat: sélecteur de famille (onglet Sheets) en sync et création

- GET /api/sheets/tabs : liste les onglets Google Sheets disponibles
- readSheetProducts(tab?) et fetchPendingProducts(set, tab?) acceptent un filtre
- /api/sync/preview?tab=xxx et /api/creation/preview?tab=xxx filtrent sur un onglet
- Composant FamilySelector : grille de boutons chargeant les onglets dynamiquement
- Page Sync : étape 0 de sélection famille avant l'analyse
- Page Création : étape famille avant analyse, badge de famille sélectionnée

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 23:31:19 +02:00
parent 1b07359415
commit 23aa78d3da
8 changed files with 180 additions and 30 deletions
+59
View File
@@ -0,0 +1,59 @@
'use client'
import { useEffect, useState } from 'react'
interface Props {
onSelect: (tab: string) => void
}
export function FamilySelector({ onSelect }: Props) {
const [tabs, setTabs] = useState<string[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
fetch('/api/sheets/tabs')
.then((r) => r.json())
.then((data) => {
if (data.error) throw new Error(data.error)
setTabs(data.tabs)
})
.catch((e: Error) => setError(e.message))
.finally(() => setLoading(false))
}, [])
if (loading) {
return (
<div className="flex items-center gap-2 text-slate-400 text-sm py-8 justify-center">
<span className="animate-spin"></span> Chargement des familles
</div>
)
}
if (error) {
return (
<div className="p-4 bg-red-900/30 border border-red-700 rounded-lg text-red-300 text-sm">
Impossible de charger les familles : {error}
</div>
)
}
return (
<div className="space-y-3">
<p className="text-slate-300 text-sm">
Choisissez une famille (onglet Google Sheets) pour travailler uniquement sur celle-ci.
</p>
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-2">
{tabs.map((tab) => (
<button
key={tab}
onClick={() => onSelect(tab)}
className="flex items-center gap-2 px-4 py-3 bg-slate-700 hover:bg-indigo-700 border border-slate-600 hover:border-indigo-500 rounded-xl text-sm text-slate-200 hover:text-white font-medium transition-all text-left group"
>
<span className="text-base group-hover:scale-110 transition-transform">📂</span>
<span className="truncate">{tab}</span>
</button>
))}
</div>
</div>
)
}