Skip to main content

Vue d’ensemble

Le dashboard admin offre une interface complète de gestion de contenu pour Kit’Asso. Accessible uniquement aux utilisateurs authentifiés via Nhost Auth, il permet de gérer l’intégralité du catalogue. Fonctionnalités principales :
  • 4 panels de gestion (Tools, Workflows, Packs, Quiz)
  • CRUD complet sur toutes les entités via GraphQL
  • Upload d’images vers Nhost Storage
  • Interface responsive avec recherche et filtres
  • Modals lazy-loaded pour meilleures performances
  • Notifications de succès/erreur (toast)
  • Preview avant publication

Architecture technique

Structure des fichiers

src/pages/Admin.tsx                    # Page principale (tabs)
src/features/
  ├── tools/modals/ToolModal/          # Modal de gestion d'outils
  │   ├── index.tsx                    # Container
  │   ├── ToolForm.tsx                 # Formulaire
  │   ├── ToolPreview.tsx              # Preview
  │   └── useToolModal.ts             # Logique métier
  ├── workflows/modals/WorkflowModal/  # Modal de workflows
  ├── tool-packs/modals/PackModal/     # Modal de packs
  └── quiz/admin/                      # Panel admin quiz
      ├── QuizManager.tsx
      ├── QuizBuilder.tsx
      └── QuizAnalytics.tsx

Sécurité et authentification

Route protégée :
// src/router.tsx
{
  path: '/admin',
  element: (
    <ProtectedRoute>
      <Admin />
    </ProtectedRoute>
  )
}
ProtectedRoute vérifie l’authentification via useAuth() (Nhost Auth). Si non connecté, redirection vers /login. Permissions Hasura :
  • Seuls les utilisateurs avec le rôle admin peuvent effectuer des INSERT/UPDATE/DELETE
  • Accès complet à tous les contenus (y compris drafts)

Panel 1 : Tools Management

Interface principale

function ToolsPanel() {
  const [tools, setTools] = useState<EnhancedTool[]>([]);

  const loadTools = async () => {
    try {
      const data = await toolsApi.list();
      setTools(data);
    } catch (error) {
      toast.error('Erreur lors du chargement des outils');
    }
  };

  // Filtrage local par recherche + catégorie
  const filteredTools = tools.filter(tool => {
    const matchesSearch = tool.name.toLowerCase().includes(searchQuery);
    const matchesCategory = selectedCategory === 'all' || tool.category_id === selectedCategory;
    return matchesSearch && matchesCategory;
  });
}

Upload de logo (Nhost Storage)

async function uploadLogo(file: File): Promise<string> {
  // Upload vers Nhost Storage
  const { error, fileMetadata } = await nhost.storage.upload({
    file,
    bucketId: 'default',
  });

  if (error) throw new Error('Erreur lors de l\'upload du logo');

  // Construire l'URL publique Nhost Storage
  const nhostSubdomain = import.meta.env.VITE_NHOST_SUBDOMAIN || 'gqvlmqwbsmkhlllmgbyw';
  const nhostRegion = import.meta.env.VITE_NHOST_REGION || 'eu-central-1';
  return `https://${nhostSubdomain}.storage.${nhostRegion}.nhost.run/v1/files/${fileMetadata.id}`;
}
Le formulaire utilise react-hook-form + zod pour la validation :
const toolSchema = z.object({
  name: z.string().min(1, 'Le nom est requis'),
  description: z.string().min(10, 'Description trop courte'),
  pricing_tier: z.enum(['Gratuit', 'Freemium', 'Payant', 'Entreprise']),
  category_id: z.string().uuid(),
  website_url: z.string().url().optional(),
  logo: z.instanceof(File).optional()
});

Panel 2 : Workflows Management

Gestion des parcours guidés avec filtrage par statut (active/draft). Chaque workflow est éditable via un modal avec un step editor pour gérer les étapes. Création de workflow : Le formulaire permet de définir les métadonnées (titre, difficulté, durée, icône) et d’ajouter/réordonner les étapes avec le StepEditor. Toggle de statut : Un workflow peut basculer entre active (visible publiquement) et draft (admin uniquement) via une mutation GraphQL update_workflows_by_pk avec _set.

Panel 3 : Tool Packs Management

Gestion des collections curées d’outils. Le PackForm permet de sélectionner les outils à inclure dans un pack via un système de checkboxes avec la liste complète des outils disponibles.

Panel 4 : Quiz Management

Le QuizBuilder permet de créer des quiz avec questions, options de réponse, et règles de recommandation. Le RecommendationRulesEditor configure la logique conditionnelle (voir page Quiz).

Bonnes pratiques

✅ À faire

Lazy loading des modals
const ToolModal = lazy(() => import('./features/tools/modals/ToolModal'));

<Suspense fallback={<LoadingSpinner />}>
  {isOpen && <ToolModal />}
</Suspense>
Charger uniquement l’onglet actif
useEffect(() => {
  if (activeTab === 'tools') loadTools();
  if (activeTab === 'workflows') loadWorkflows();
}, [activeTab]);
Confirmation avant suppression
const handleDelete = async (id: string) => {
  if (!confirm('Supprimer cet élément ?')) return;
  try {
    await toolsApi.delete(id);
    toast.success('Suppression réussie');
    reloadData();
  } catch (error) {
    toast.error('Erreur lors de la suppression');
  }
};

❌ À éviter

  • Charger toutes les données au mount (uniquement l’onglet actif)
  • Appeler nhost.graphql.request() directement (passer par l’API layer)
  • Oublier le cleanup des listeners

Ressources

Tools Feature

Documentation des outils

Workflows Feature

Documentation des parcours guidés

Tool Packs

Gestion des collections d’outils

Quiz System

Système de diagnostic interactif