import { useEffect, useState } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { Plus, Facebook, Instagram, Trash2, RefreshCw, Edit, Bug, Code, AlertTriangle } from "lucide-react"; import { SiTiktok } from "react-icons/si"; import Sidebar from "@/components/sidebar"; import TopBar from "@/components/topbar"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useToast } from "@/hooks/use-toast"; import { apiRequest, queryClient } from "@/lib/queryClient"; import type { ClientSocialPage } from "@shared/schema"; import { ConnectFacebookButton, RefreshTokenButton, TokenAlertBanner, TokenHealthPanel, } from "@/components/facebook-token-status"; export default function PagesManagement() { const [sidebarOpen, setSidebarOpen] = useState(false); const [dialogOpen, setDialogOpen] = useState(false); const [editingPage, setEditingPage] = useState(null); const { toast } = useToast(); // Retour des flux d'autorisation (/api/tiktok/callback et /api/facebook/callback // redirigent ici avec le résultat en paramètre) useEffect(() => { const params = new URLSearchParams(window.location.search); const network = params.get('tiktok') ? 'tiktok' : params.get('facebook') ? 'facebook' : null; if (!network) return; const result = params.get(network); const label = network === 'tiktok' ? 'TikTok' : 'Facebook'; toast({ title: result === 'success' ? `${label} connecté` : `Connexion ${label} impossible`, description: params.get('message') || undefined, variant: result === 'success' ? undefined : 'destructive', }); queryClient.invalidateQueries({ queryKey: ['/api/pages'] }); window.history.replaceState({}, '', window.location.pathname); }, [toast]); const { data: pages = [], isLoading } = useQuery({ queryKey: ['/api/pages'], }); const deleteMutation = useMutation({ mutationFn: (pageId: string) => apiRequest('DELETE', `/api/pages/${pageId}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/pages'] }); toast({ title: "Page supprimée", description: "La page a été retirée avec succès", }); }, onError: () => { toast({ title: "Erreur", description: "Impossible de supprimer la page", variant: "destructive", }); }, }); return (
{sidebarOpen && (
setSidebarOpen(false)} /> )}
setSidebarOpen(false)} />
setSidebarOpen(!sidebarOpen)} />

Pages gérées

Connectez et gérez vos pages Facebook, Instagram et vos comptes TikTok

!open && setEditingPage(null)} />
{/* Permissions required notice */}

Connectez vos pages plutôt que de coller un jeton

« Connecter des pages Facebook » récupère les jetons de page via l'autorisation Facebook : ils n'expirent pas et SocialFlow les régénère seul en cas de révocation. Un jeton collé à la main expire au bout de 60 jours et devra être remplacé manuellement.

Le jeton doit couvrir : pages_manage_posts{" "} pages_read_engagement{" "} publish_video

{isLoading ? (
{[1, 2, 3].map((i) => (
))}
) : pages.length === 0 ? (

Aucune page connectée

Commencez par connecter vos pages Facebook et Instagram

) : (
{pages.map((page) => (
{page.platform === 'facebook' ? (
) : page.platform === 'tiktok' ? (
) : (
)}
{page.pageName} {page.platform}
ID: {page.pageId}
{/* État du jeton, tel que constaté par le dernier contrôle serveur */}
{page.platform !== 'tiktok' && } {page.platform === 'tiktok' ? ( // Un token TikTok ne se saisit pas : on repasse par l'autorisation ) : ( )}
))}
)}
); } /** * Lance l'autorisation TikTok. La connexion se fait par navigation complète du * navigateur (et non en fetch) puisqu'elle passe par le site de TikTok. */ function ConnectTiktokButton() { const { toast } = useToast(); const { data: config } = useQuery<{ configured: boolean }>({ queryKey: ['/api/tiktok/config'], }); const handleClick = () => { if (config && !config.configured) { toast({ title: "TikTok n'est pas configuré", description: "Renseignez le client key et le client secret de votre application TikTok dans les paramètres.", variant: "destructive", }); return; } window.location.href = '/api/tiktok/connect'; }; return ( ); } function AddPageDialog({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) { const [platform, setPlatform] = useState<'facebook' | 'instagram'>('facebook'); const [pageName, setPageName] = useState(''); const [pageId, setPageId] = useState(''); const [accessToken, setAccessToken] = useState(''); const { toast } = useToast(); const addMutation = useMutation({ mutationFn: (data: any) => apiRequest('POST', '/api/pages', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/pages'] }); toast({ title: "Page ajoutée", description: "La page a été connectée avec succès", }); onOpenChange(false); setPlatform('facebook'); setPageName(''); setPageId(''); setAccessToken(''); }, onError: () => { toast({ title: "Erreur", description: "Impossible d'ajouter la page", variant: "destructive", }); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); addMutation.mutate({ platform, pageName, pageId, accessToken, }); }; return ( Ajouter une page Connectez une page Facebook ou Instagram pour commencer à publier
setPageName(e.target.value)} placeholder="Mon entreprise" required data-testid="input-page-name" />
setPageId(e.target.value)} placeholder="123456789" required data-testid="input-page-id" />
setAccessToken(e.target.value)} placeholder="EAAxxxxxxxxxxxxx" required data-testid="input-access-token" />

Obtenez votre jeton d'accès depuis{' '} Facebook Graph API Explorer

); } function EditPageDialog({ page, onOpenChange }: { page: ClientSocialPage | null; onOpenChange: (open: boolean) => void }) { const [accessToken, setAccessToken] = useState(''); const { toast } = useToast(); const editMutation = useMutation({ mutationFn: (data: any) => apiRequest('PUT', `/api/pages/${page?.id}`, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['/api/pages'] }); toast({ title: "Page modifiée", description: "Le jeton d'accès a été mis à jour avec succès", }); onOpenChange(false); setAccessToken(''); }, onError: () => { toast({ title: "Erreur", description: "Impossible de modifier la page", variant: "destructive", }); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!page) return; editMutation.mutate({ accessToken, }); }; if (!page) return null; return ( Modifier le jeton d'accès Mettez à jour le jeton d'accès pour {page.pageName}
setAccessToken(e.target.value)} placeholder="EAAxxxxxxxxxxxxx" required data-testid="input-edit-access-token" />

Obtenez un nouveau jeton depuis{' '} Facebook Graph API Explorer

); }