import React, { useState, useEffect, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { FlaskConical, // Outil de recherche/expérimentation BookOpen, // Outil de gestion bibliographique BarChart4, // Outil d'analyse statistique LayoutDashboard, // Dashboard Users, // Gestion des utilisateurs Settings, // Paramètres HelpCircle, // Aide/Documentation Plus, // Ajouter un outil Search, // Recherche GripVertical, // Pour le drag and drop ExternalLink, Loader2, CheckCircle, AlertTriangle, XCircle, List, Grid, UserPlus, // Pour l'inscription LogIn, // Pour la connexion LogOut, KeyRound } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { cn } from '@/lib/utils'; import { Separator } from '@/components/ui/separator'; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, } from "@/components/ui/sheet" import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import * as z from "zod" // =============================== // Types & Interfaces // =============================== interface Tool { id: string; name: string; description: string; category: string; url: string; icon: React.ReactNode; addedBy: string; // User ID dateAdded: Date; tags: string[]; ownedByCurrentUser: boolean; } interface User { id: string; name: string; role: 'admin' | 'user'; } type Layout = 'grid' | 'list'; // =============================== // Mock Data & Constants // =============================== const CATEGORIES = [ { name: 'Analyse de Données', value: 'data-analysis' }, { name: 'Gestion de Références', value: 'reference-management' }, { name: 'Visualisation', value: 'visualization' }, { name: 'Collaboration', value: 'collaboration' }, { name: 'Outils Généraux', value: 'general' }, { name: 'Bio-informatique', value: 'bioinformatics' }, { name: 'Chimie', value: 'chemistry' }, { name: 'Mathématiques', value: 'mathematics' }, { name: 'Physique', value: 'physics' }, { name: 'Sciences Sociales', value: 'social-sciences' }, { name: 'Humanités Numériques', value: 'digital-humanities' }, ]; const ICONS = { 'data-analysis': BarChart4, 'reference-management': BookOpen, 'visualization': BarChart4, // Réutiliser, ou créer une icône spécifique 'collaboration': Users, 'general': FlaskConical, 'bioinformatics': FlaskConical, // À remplacer si une icône plus spécifique existe 'chemistry': FlaskConical, // À remplacer 'mathematics': FlaskConical, // À remplacer 'physics': FlaskConical, // À remplacer 'social-sciences': BookOpen, // À remplacer 'digital-humanities': BookOpen, // À remplacer }; // =============================== // Helper Functions // =============================== const getCategoryIcon = (categoryValue: string) => { const category = CATEGORIES.find(c => c.value === categoryValue); return category ? ICONS[category.value] || FlaskConical : FlaskConical; }; // =============================== // Composants // =============================== // Composant pour afficher une seule carte d'outil const ToolCard = ({ tool, layout, onDelete }: { tool: Tool, layout: Layout, onDelete?: (id: string) => void }) => { const Icon = getCategoryIcon(tool.category); return ( {layout === 'grid' && } {tool.name} {CATEGORIES.find(c => c.value === tool.category)?.name || 'Non catégorisé'}

{tool.description}

{layout === 'list' && (
{tool.tags.map(tag => ( {tag} ))}
)}
{tool.ownedByCurrentUser && onDelete && (
)}
); }; // Composant pour la barre de navigation latérale const Sidebar = ({ onAddTool, onMyTools }: { onAddTool: () => void, onMyTools: () => void }) => { const [isSidebarOpen, setIsSidebarOpen] = useState(true); // État pour la visibilité sur mobile return ( <> {/* Bouton pour basculer la sidebar sur mobile */}
{/* Contenu de la sidebar */}

Recherche Tools

); }; // Form schema for adding a tool const addToolFormSchema = z.object({ name: z.string().min(2, { message: "Le nom doit contenir au moins 2 caractères.", }), description: z.string().min(10, { message: "La description doit contenir au moins 10 caractères.", }), url: z.string().url({ message: "URL invalide." }), category: z.string().nonempty("Veuillez sélectionner une catégorie."), tags: z.array(z.string()), }); // Composant pour ajouter un outil const AddToolSheet = ({ onAdd }: { onAdd: (tool: Tool) => void }) => { const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const form = useForm>({ resolver: zodResolver(addToolFormSchema), defaultValues: { name: "", description: "", url: "", category: "", tags: [], }, }) const handleAddTag = (newTag: string, tags: string[], setTags: (tags: string[]) => void) => { if (newTag.trim() && !tags.includes(newTag.trim())) { setTags([...tags, newTag.trim()]); } }; const handleRemoveTag = (tagToRemove: string, tags: string[], setTags: (tags: string[]) => void) => { setTags(tags.filter(tag => tag !== tagToRemove)); }; const onSubmit = async (values: z.infer) => { setIsLoading(true); setError(null); // Simuler un délai d'ajout try { await new Promise(resolve => setTimeout(resolve, 1000)); const newTool: Tool = { id: crypto.randomUUID(), name: values.name, description: values.description, category: values.category, url: values.url, icon: getCategoryIcon(values.category), // Utiliser la fonction pour obtenir l'icône addedBy: 'user123', // Remplacer par l'ID de l'utilisateur connecté dateAdded: new Date(), tags: values.tags, ownedByCurrentUser: true, // Marquer l'outil comme appartenant à l'utilisateur actuel }; onAdd(newTool); setIsLoading(false); form.reset(); // Réinitialiser le formulaire } catch (error: any) { setError(`Une erreur s'est produite : ${error.message}`); setIsLoading(false); } }; return ( Ajouter un nouvel outil Partagez un outil que vous utilisez ou que vous trouvez utile pour la recherche.
{/* Nom de l'outil */} ( Nom de l'outil * )} /> {/* Description de l'outil */} ( Description de l'outil *