Dashboard

Hook headless

useInstaFixInbox — toute la logique de l'inbox, aucune interface. Construisez votre propre vue de tri.

Tout ce que fait InstaFixInbox — chargement, filtres, mutations optimistes, annulation, pagination — vit dans un hook que vous pouvez piloter depuis vos propres composants :

import { useInstaFixInbox } from "@instafix/dashboard";

const inbox = useInstaFixInbox({
  projects: "mon-projet",
  endpoint: "/api/instafix",
});

Options

Les options forment une union sur les trois modes de source : fournissez exactement un de source, store ou endpoint. N'en fournir aucun, en fournir deux, ou associer des options propres au mode endpoint (apiKey, headers) à store/source est une erreur de compilation — pas une exception à l'exécution, et pas une option ignorée en silence.

OptionTypeDéfautNotes
projectsstring ou string[]obligatoireUn tableau vide lève une erreur au rendu. La première entrée est sélectionnée au départ
endpointstringMode HTTP
storeInstaFixStoreMode store
sourceInboxSourceSource de données entièrement personnalisée ; voir Sources de données
apiKeystringMode endpoint uniquement. Authorization: Bearer sur chaque requête
headersobjet ou fonctionMode endpoint uniquement. Un Authorization explicite l'emporte sur apiKey. Lu en direct — le modifier ne reconstruit pas la source
pageSizenumber50Borné entre 1 et 100
onStatusChange(feedback, previousStatus) => voidAprès confirmation du serveur
onDelete(feedback) => voidAprès confirmation du serveur
onError(error) => voidChaque chargement ou mutation en échec

Chaque mode est exporté séparément — InboxEndpointOptions, InboxStoreOptions, InboxCustomSourceOptions, le socle commun InboxSharedOptions et l'union UseInstaFixInboxOptions — pour qu'un composant d'enrobage n'accepte que le mode qu'il gère. En JavaScript pur, le comportement d'avant demeure : aucune source du tout lève toujours au rendu.

Ce que vous récupérez

Donnéesitems (toutes les pages chargées), total (null jusqu'à l'arrivée de la première page), counts (totaux par statut, au mieux), loading, loadingMore, error, hasMore, loadMore(), refresh().

Filtresproject/setProject, status/setStatus (démarre sur "open"), type/setType, search/setSearch. La recherche met l'état à jour instantanément et temporise le rechargement de 250 ms ; les requêtes sont nettoyées et plafonnées à 200 caractères.

Focus et tiroirfocusedId, focus(id), focusNext(), focusPrev(), openedId, opened (le feedback ouvert — il reste disponible même si un filtre retire sa ligne), openFeedback(id), closeFeedback().

MutationschangeStatus(id, status), deleteFeedback(id), pendingUndo, undo().

view — l'algèbre des drapeaux en moins

Choisir entre un squelette, un état d'erreur, un état vide et la liste à partir de loading / error / items.length est délicat, et se tromper d'un cheveu, c'est ce qui fait qu'un rechargement vide l'écran. view est cette décision, déjà prise — exactement la valeur dont part le composant fourni :

viewSignification
"loading"La première page charge et il n'y a encore rien à afficher
"error"Le chargement a échoué et il n'y a rien à afficher
"empty"Le chargement a réussi et aucune ligne ne correspond aux filtres courants
"ready"Des lignes sont affichables
if (inbox.view === "loading") return <Skeleton />;
if (inbox.view === "error") return <ErrorState error={inbox.error} onRetry={inbox.refresh} />;
if (inbox.view === "empty") return <EmptyState />;
return <List items={inbox.items} />;

Les lignes l'emportent sur tout autre signal : pendant un rechargement, les lignes déjà chargées restent à l'écran et view reste "ready", donc la liste ne repasse jamais brutalement au squelette. Lisez loading quand vous voulez un indicateur plus fin par-dessus les lignes visibles.

Les mutations sont optimistes — et elles relèvent l'erreur

L'interface se met à jour immédiatement ; si le serveur refuse, le hook annule tout (items, compteurs, focus, feedback ouvert) puis relève l'erreur. Attachez toujours un catch :

<button
  onClick={() => {
    inbox.changeStatus(item.id, "resolved").catch(() => {
      // l'état est déjà revenu en arrière — affichez un toast ici
    });
  }}
>
  Résoudre
</button>

Seul le dernier changement de statut est annulable (pendingUndo + undo()) ; la suppression est définitive, alors protégez-la derrière votre propre confirmation.

Pagination

loadMore() est manuel — le composant fourni affiche un bouton « Charger plus », pas un défilement infini. Les pages sont dédoublonnées par id, et le numéro de page suivant est déduit de items.length, donc les suppressions optimistes ne font jamais sauter de lignes.

Modifier sur GitHub

Sur cette page