import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { z } from 'zod' import { api } from '../client' import type { PullRequest } from '../../types/api' const prReviewerSchema = z.object({ userId: z.number(), username: z.string(), avatarUrl: z.string(), }) const prSchema = z.object({ id: z.number(), repoId: z.number(), authorId: z.number(), title: z.string(), body: z.string(), sourceBranch: z.string(), targetBranch: z.string(), status: z.enum(['open', 'merged', 'closed']), createdAt: z.string(), updatedAt: z.string(), reviewers: z.array(prReviewerSchema).default([]), }) const prsSchema = z.array(prSchema) const mergeResponseSchema = z.object({ status: z.string() }) export function usePRs(owner: string, repo: string) { return useQuery({ queryKey: ['repos', owner, repo, 'pulls'], queryFn: () => api.get(`/api/v1/repos/${owner}/${repo}/pulls`, prsSchema), enabled: Boolean(owner && repo), }) } export function usePR(owner: string, repo: string, prId: number) { return useQuery({ queryKey: ['repos', owner, repo, 'pulls', prId], queryFn: () => api.get(`/api/v1/repos/${owner}/${repo}/pulls/${prId}`, prSchema), enabled: Boolean(owner && repo && prId), }) } export function useUpdatePR(owner: string, repo: string, prId: number) { const queryClient = useQueryClient() return useMutation({ mutationFn: (data: { title?: string; body?: string }) => api.patch(`/api/v1/repos/${owner}/${repo}/pulls/${prId}`, prSchema, data), onSuccess: (updated) => { queryClient.setQueryData(['repos', owner, repo, 'pulls', prId], updated) queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'pulls'] }) }, }) } export function useReopenPR(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (prId: number) => api.post(`/api/v1/repos/${owner}/${repo}/pulls/${prId}/reopen`, prSchema, {}), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'pulls'] }) queryClient.invalidateQueries({ queryKey: ['dashboard'] }) }, }) } export function useCreatePR(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (data: { title: string; body: string; sourceBranch: string; targetBranch: string }) => api.post(`/api/v1/repos/${owner}/${repo}/pulls`, prSchema, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'pulls'] }) queryClient.invalidateQueries({ queryKey: ['dashboard'] }) }, }) } export function useMergePR(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: ({ prId, strategy }: { prId: number; strategy: string }) => api.post(`/api/v1/repos/${owner}/${repo}/pulls/${prId}/merge`, mergeResponseSchema, { strategy }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'pulls'] }) queryClient.invalidateQueries({ queryKey: ['dashboard'] }) }, }) } export function useClosePR(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (prId: number) => api.post(`/api/v1/repos/${owner}/${repo}/pulls/${prId}/close`, prSchema, {}), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'pulls'] }) queryClient.invalidateQueries({ queryKey: ['dashboard'] }) }, }) } // ─── PR settings ────────────────────────────────────────────────────────────── export interface DefaultReviewer { userId: number username: string avatarUrl: string } const reviewerSchema = z.object({ userId: z.number(), username: z.string(), avatarUrl: z.string(), }) const reviewersSchema = z.array(reviewerSchema) const descriptionSchema = z.object({ template: z.string() }) const excludedFilesSchema = z.object({ patterns: z.string() }) export function useDefaultReviewers(owner: string, repo: string) { return useQuery({ queryKey: ['repos', owner, repo, 'default-reviewers'], queryFn: () => api.get(`/api/v1/repos/${owner}/${repo}/default-reviewers`, reviewersSchema), enabled: Boolean(owner && repo), }) } export function useAddDefaultReviewer(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (username: string) => api.post(`/api/v1/repos/${owner}/${repo}/default-reviewers`, reviewerSchema, { username }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'default-reviewers'] }) }, }) } export function useRemoveDefaultReviewer(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (username: string) => api.delete(`/api/v1/repos/${owner}/${repo}/default-reviewers/${encodeURIComponent(username)}`, z.any()), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'default-reviewers'] }) }, }) } export function useDefaultDescription(owner: string, repo: string) { return useQuery({ queryKey: ['repos', owner, repo, 'default-description'], queryFn: () => api.get<{ template: string }>(`/api/v1/repos/${owner}/${repo}/default-description`, descriptionSchema), enabled: Boolean(owner && repo), }) } export function useUpdateDefaultDescription(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (template: string) => api.put<{ template: string }>(`/api/v1/repos/${owner}/${repo}/default-description`, descriptionSchema, { template }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'default-description'] }) }, }) } export function useExcludedFiles(owner: string, repo: string) { return useQuery({ queryKey: ['repos', owner, repo, 'excluded-files'], queryFn: () => api.get<{ patterns: string }>(`/api/v1/repos/${owner}/${repo}/excluded-files`, excludedFilesSchema), enabled: Boolean(owner && repo), }) } export function useUpdateExcludedFiles(owner: string, repo: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: (patterns: string) => api.put<{ patterns: string }>(`/api/v1/repos/${owner}/${repo}/excluded-files`, excludedFilesSchema, { patterns }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['repos', owner, repo, 'excluded-files'] }) }, }) }