import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { z } from 'zod' import { api } from '../client' import type { Environment, EnvironmentWithLatest, Deployment, DeployStatus } from '../../types/api' // ── Schemas ─────────────────────────────────────────────────────────────────── const deployStatusSchema = z.enum(['pending', 'in_progress', 'success', 'failure', 'cancelled']) const deploymentSchema = z.object({ id: z.number(), envId: z.number(), repoId: z.number(), sha: z.string(), ref: z.string(), status: deployStatusSchema, triggeredBy: z.string(), description: z.string(), runId: z.number().nullable(), startedAt: z.string().nullable(), finishedAt: z.string().nullable(), createdAt: z.string(), }) const environmentSchema = z.object({ id: z.number(), repoId: z.number(), name: z.string(), url: z.string(), protectionRules: z.string(), createdAt: z.string(), updatedAt: z.string(), }) const environmentWithLatestSchema = environmentSchema.extend({ latestDeployment: deploymentSchema.nullable(), }) // ── Queries ─────────────────────────────────────────────────────────────────── export function useEnvironments(owner: string, repo: string) { return useQuery({ queryKey: ['repos', owner, repo, 'environments'], queryFn: () => api.get( `/api/v1/repos/${owner}/${repo}/environments`, z.array(environmentWithLatestSchema), ), enabled: Boolean(owner && repo), refetchInterval: 15_000, }) } export function useEnvironment(owner: string, repo: string, envName: string) { return useQuery({ queryKey: ['repos', owner, repo, 'environments', envName], queryFn: () => api.get( `/api/v1/repos/${owner}/${repo}/environments/${envName}`, environmentWithLatestSchema, ), enabled: Boolean(owner && repo && envName), refetchInterval: 10_000, }) } export function useDeployments(owner: string, repo: string, envName: string, limit = 30) { return useQuery({ queryKey: ['repos', owner, repo, 'environments', envName, 'deployments', limit], queryFn: () => api.get( `/api/v1/repos/${owner}/${repo}/environments/${envName}/deployments?limit=${limit}`, z.array(deploymentSchema), ), enabled: Boolean(owner && repo && envName), refetchInterval: 10_000, }) } // ── Mutations ───────────────────────────────────────────────────────────────── export function useCreateEnvironment(owner: string, repo: string) { const qc = useQueryClient() return useMutation({ mutationFn: (body: { name: string; url?: string; protectionRules?: string }) => api.post( `/api/v1/repos/${owner}/${repo}/environments`, environmentSchema, body, ), onSuccess: () => { qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] }) }, }) } export function useUpdateEnvironment(owner: string, repo: string, envName: string) { const qc = useQueryClient() return useMutation({ mutationFn: (body: { url?: string; protectionRules?: string }) => api.patch( `/api/v1/repos/${owner}/${repo}/environments/${envName}`, environmentSchema, body, ), onSuccess: () => { qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] }) qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments', envName] }) }, }) } export function useDeleteEnvironment(owner: string, repo: string) { const qc = useQueryClient() return useMutation({ mutationFn: (envName: string) => api.delete( `/api/v1/repos/${owner}/${repo}/environments/${envName}`, z.unknown() as z.ZodType, ), onSuccess: () => { qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] }) }, }) } export function useCreateDeployment(owner: string, repo: string, envName: string) { const qc = useQueryClient() return useMutation({ mutationFn: (body: { sha: string; ref?: string; description?: string; runId?: number }) => api.post( `/api/v1/repos/${owner}/${repo}/environments/${envName}/deployments`, deploymentSchema, body, ), onSuccess: () => { qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] }) qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments', envName] }) }, }) } export function useUpdateDeploymentStatus(owner: string, repo: string, envName: string) { const qc = useQueryClient() return useMutation({ mutationFn: ({ deployId, status, description }: { deployId: number; status: DeployStatus; description?: string }) => api.patch( `/api/v1/repos/${owner}/${repo}/environments/${envName}/deployments/${deployId}/status`, deploymentSchema, { status, description }, ), onSuccess: () => { qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] }) qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments', envName] }) }, }) }