VendeeDocs
Frontend

Estado

Zustand stores e TanStack Query

O app separa estado em duas camadas:

  • Zustand — Estado global do cliente (auth, workspace, UI)
  • TanStack Query — Estado do servidor (dados do Supabase)

Zustand Stores

Localizados em src/stores/:

useAuthStore

interface AuthState {
  user: User | null;
  session: Session | null;
  loading: boolean;
  setAuth: (user: User | null, session: Session | null) => void;
  setLoading: (loading: boolean) => void;
}

Gerencia o estado de autenticação do Supabase.

useWorkspaceStore

interface WorkspaceState {
  workspace: Workspace | null;
  member: Member | null;
  members: Member[];
  impersonatedWorkspaceId: string | null;
  setWorkspace: (workspace, member, members) => void;
  enterAsAdmin: (target, syntheticMember, targetMembers) => void;
  exitImpersonation: () => void;
  clear: () => void;
}

Armazena o workspace ativo, o membro atual e a lista de membros.

Quando o super admin entra em um workspace como suporte, impersonatedWorkspaceId armazena o ID do workspace alvo. O store mantém o workspace ativo como se fosse um admin daquele cliente. exitImpersonation() restaura o estado anterior.

useFeedbackStore

Estado do widget de feedback (reportar bug / sugerir melhoria), que pode ser aberto de qualquer tela — por isso vive no shell, não na página.

useOttoChatStore

Estado do chat do Otto: aberto/fechado, o contexto da tela atual e a ponte para quando o Otto sugere um rascunho de e-mail. Também é acessível de qualquer tela.

TanStack Query

Toda interação com o Supabase usa useQuery para leitura e useMutation para escrita.

// Leitura
const { data, isLoading } = useDeals(pipelineId);

// Escrita
const createDeal = useCreateDeal();
createDeal.mutate({ name: "Novo negócio", ... });

Query keys

Padrão: ["entidade", workspaceId, ...filtros]

queryKey: ["deals", workspace?.id, pipelineId]
queryKey: ["deal", workspace?.id, dealId]
queryKey: ["contacts", workspace?.id]

Invalidação

Mutations invalidam queries relacionadas em onSuccess:

onSuccess: () =>
  qc.invalidateQueries({ queryKey: ["deals", workspace?.id] })

☠️ Toda query key leva workspace?.id como segundo elemento — inclusive as de item único (["deal", workspace?.id, id]). Sem isso, trocar de workspace serve dado em cache do workspace anterior.

O workspace-store é persistido (zustand/middleware), para o modo de impersonação do super admin sobreviver ao reload. A chave é versionada — se o formato do que é persistido mudar, o número da versão sobe junto.

Nesta página