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:
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user