import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { issueAssigneeList, issueAssigneeAdd, issueAssigneeRemove, issueClose, issueDelete as apiIssueDelete, issueReopen, issueUpdate, issueLabelList, issueLabelAdd, issueLabelAddBulk, issueLabelRemove, issuePullRequestList, issuePullRequestLink, issuePullRequestUnlink, issueReactionList, issueRepoList, issueRepoLink, issueRepoUnlink, issueSubscriberList, issueSubscribe, issueUnsubscribe, projectLabels, labelCreate, labelList as apiLabelList, labelDelete as apiLabelDelete, } from "@/client/api"; import type { IssueAssigneeResponse, IssueLabelResponse, IssuePullRequestResponse, IssueRepoResponse, IssueSubscriberResponse, ReactionListResponse, LabelResponse, CreateLabelRequest, IssueUpdateRequest, } from "@/client/model"; const ISSUE_QUERY_KEY = "issue"; interface IssueParams { projectName: string; issueNumber: number; } // Assignees export function useIssueAssigneesQuery({ projectName, issueNumber }: IssueParams) { return useQuery({ queryKey: [ISSUE_QUERY_KEY, projectName, issueNumber, "assignees"], queryFn: async (): Promise => { const res = await issueAssigneeList(projectName, issueNumber); return res.data.data ?? []; }, enabled: !!projectName && !!issueNumber, }); } export function useAddAssigneeMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, userId }: IssueParams & { userId: string }) => { await issueAssigneeAdd(projectName, issueNumber, { user_id: userId }); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "assignees"] }); }, }); } export function useRemoveAssigneeMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, userId }: IssueParams & { userId: string }) => { await issueAssigneeRemove(projectName, issueNumber, userId); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "assignees"] }); }, }); } // Labels export function useIssueLabelsQuery({ projectName, issueNumber }: IssueParams) { return useQuery({ queryKey: [ISSUE_QUERY_KEY, projectName, issueNumber, "labels"], queryFn: async (): Promise => { const res = await issueLabelList(projectName, issueNumber); return res.data.data ?? []; }, enabled: !!projectName && !!issueNumber, }); } export function useAddIssueLabelMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, labelId }: IssueParams & { labelId: number }) => { await issueLabelAdd(projectName, issueNumber, { label_id: labelId }); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "labels"] }); }, }); } export function useRemoveIssueLabelMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, labelId }: IssueParams & { labelId: number }) => { await issueLabelRemove(projectName, issueNumber, labelId); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "labels"] }); }, }); } // Project Labels export function useProjectLabelsQuery(projectName: string) { return useQuery({ queryKey: ["project", projectName, "labels"], queryFn: async (): Promise => { const res = await projectLabels(projectName); return res.data.data?.labels ?? []; }, enabled: !!projectName, }); } export function useCreateLabelMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, req }: { projectName: string, req: CreateLabelRequest }) => { await labelCreate(projectName, req); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ["project", variables.projectName, "labels"] }); }, }); } // Reactions export function useIssueReactionsQuery({ projectName, issueNumber }: IssueParams) { return useQuery({ queryKey: [ISSUE_QUERY_KEY, projectName, issueNumber, "reactions"], queryFn: async (): Promise => { const res = await issueReactionList(projectName, issueNumber); return res.data.data ?? null; }, enabled: !!projectName && !!issueNumber, }); } // Subscribers export function useIssueSubscribersQuery({ projectName, issueNumber }: IssueParams) { return useQuery({ queryKey: [ISSUE_QUERY_KEY, projectName, issueNumber, "subscribers"], queryFn: async (): Promise => { const res = await issueSubscriberList(projectName, issueNumber); return res.data.data ?? []; }, enabled: !!projectName && !!issueNumber, }); } export function useIssueSubscribeMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber }: IssueParams) => { await issueSubscribe(projectName, issueNumber); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "subscribers"] }); }, }); } // PRs & Repos export function useIssuePRsQuery({ projectName, issueNumber }: IssueParams) { return useQuery({ queryKey: [ISSUE_QUERY_KEY, projectName, issueNumber, "prs"], queryFn: async (): Promise => { const res = await issuePullRequestList(projectName, issueNumber); return res.data.data ?? []; }, enabled: !!projectName && !!issueNumber, }); } export function useIssueReposQuery({ projectName, issueNumber }: IssueParams) { return useQuery({ queryKey: [ISSUE_QUERY_KEY, projectName, issueNumber, "repos"], queryFn: async (): Promise => { const res = await issueRepoList(projectName, issueNumber); return res.data.data ?? []; }, enabled: !!projectName && !!issueNumber, }); } // Close/Reopen/Update/Delete export function useCloseIssueMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber }: IssueParams) => { await issueClose(projectName, issueNumber); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber] }); }, }); } export function useReopenIssueMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber }: IssueParams) => { await issueReopen(projectName, issueNumber); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber] }); }, }); } export function useUpdateIssueMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, req }: IssueParams & { req: IssueUpdateRequest }) => { await issueUpdate(projectName, issueNumber, req); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber] }); }, }); } export function useDeleteIssueMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber }: IssueParams) => { await apiIssueDelete(projectName, issueNumber); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber] }); }, }); } // Bulk Label Add export function useAddIssueLabelsBulkMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, labelNames }: IssueParams & { labelNames: string[] }) => { await issueLabelAddBulk(projectName, issueNumber, { names: labelNames }); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "labels"] }); }, }); } // PR Link/Unlink export function useLinkPRMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, repo, prNumber }: IssueParams & { repo: string; prNumber: number }) => { await issuePullRequestLink(projectName, issueNumber, { repo, number: prNumber }); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "prs"] }); }, }); } export function useUnlinkPRMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, repo, prNumber }: IssueParams & { repo: string; prNumber: number }) => { await issuePullRequestUnlink(projectName, issueNumber, repo, prNumber); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "prs"] }); }, }); } // Repo Link/Unlink export function useLinkRepoMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, repo }: IssueParams & { repo: string }) => { await issueRepoLink(projectName, issueNumber, { repo }); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "repos"] }); }, }); } export function useUnlinkRepoMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber, repoId }: IssueParams & { repoId: string }) => { await issueRepoUnlink(projectName, issueNumber, repoId); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "repos"] }); }, }); } // Unsubscribe export function useIssueUnsubscribeMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, issueNumber }: IssueParams) => { await issueUnsubscribe(projectName, issueNumber); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: [ISSUE_QUERY_KEY, variables.projectName, variables.issueNumber, "subscribers"] }); }, }); } // Label List/Delete (project level) export function useLabelsQuery(projectName: string) { return useQuery({ queryKey: ["project", projectName, "labels"], queryFn: async () => { const res = await apiLabelList(projectName); return res.data.data ?? []; }, enabled: !!projectName, }); } export function useDeleteLabelMutation() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ projectName, labelId }: { projectName: string; labelId: number }) => { await apiLabelDelete(projectName, labelId); }, onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ["project", variables.projectName, "labels"] }); }, }); }