Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 72 additions & 49 deletions hooks/use-bounty-mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,39 @@ import {
} from "@/lib/graphql/generated";
import { bountyKeys } from "@/lib/query/query-keys";

/**
* Type aliases for cleaner mutation option signatures
*/
type CreateBountyMutateOptions = MutateOptions<
CreateBountyMutation,
unknown,
CreateBountyMutationVariables,
unknown
>;

type UpdateBountyMutateOptions = MutateOptions<
UpdateBountyMutation,
unknown,
UpdateBountyMutationVariables,
unknown
>;

type DeleteBountyMutateOptions = MutateOptions<
DeleteBountyMutation,
unknown,
DeleteBountyMutationVariables,
unknown
>;

/**
* Hook to create a new bounty
* Handles GraphQL mutation and cache invalidation for bounty lists
*
* @returns Mutation object with mutate/mutateAsync methods
* @example
* const { mutate, isPending } = useCreateBounty();
* mutate({ title: "Fix bug", description: "...", ... });
*/
export function useCreateBounty() {
const queryClient = useQueryClient();
const mutation = useCreateBountyMutation({
Expand All @@ -28,25 +61,25 @@ export function useCreateBounty() {
...mutation,
mutate: (
input: CreateBountyInput,
options?: MutateOptions<
CreateBountyMutation,
unknown,
CreateBountyMutationVariables,
unknown
>,
options?: CreateBountyMutateOptions,
) => mutation.mutate({ input }, options),
mutateAsync: (
input: CreateBountyInput,
options?: MutateOptions<
CreateBountyMutation,
unknown,
CreateBountyMutationVariables,
unknown
>,
options?: CreateBountyMutateOptions,
) => mutation.mutateAsync({ input }, options),
};
}

/**
* Hook to update an existing bounty
* Implements optimistic updates with rollback on error
* Filters undefined/null values to send only changed fields
*
* @returns Mutation object with mutate/mutateAsync methods
* @example
* const { mutate } = useUpdateBounty();
* mutate({ id: "123", data: { status: "CLOSED" } });
*/
export function useUpdateBounty() {
const queryClient = useQueryClient();
const mutation = useUpdateBountyMutation({
Expand Down Expand Up @@ -96,22 +129,12 @@ export function useUpdateBounty() {
...mutation,
mutate: (
{ id, data }: { id: string; data: Omit<UpdateBountyInput, "id"> },
options?: MutateOptions<
UpdateBountyMutation,
unknown,
UpdateBountyMutationVariables,
unknown
>,
options?: UpdateBountyMutateOptions,
) =>
mutation.mutate({ input: { ...data, id } as UpdateBountyInput }, options),
mutateAsync: (
{ id, data }: { id: string; data: Omit<UpdateBountyInput, "id"> },
options?: MutateOptions<
UpdateBountyMutation,
unknown,
UpdateBountyMutationVariables,
unknown
>,
options?: UpdateBountyMutateOptions,
) =>
mutation.mutateAsync(
{ input: { ...data, id } as UpdateBountyInput },
Expand All @@ -120,6 +143,16 @@ export function useUpdateBounty() {
};
}

/**
* Hook to delete a bounty
* Removes the bounty from list cache optimistically
* Updates total count on deletion
*
* @returns Mutation object with mutate/mutateAsync methods
* @example
* const { mutate } = useDeleteBounty();
* mutate("bounty-id-123");
*/
export function useDeleteBounty() {
const queryClient = useQueryClient();
const mutation = useDeleteBountyMutation({
Expand Down Expand Up @@ -162,28 +195,28 @@ export function useDeleteBounty() {
...mutation,
mutate: (
id: string,
options?: MutateOptions<
DeleteBountyMutation,
unknown,
DeleteBountyMutationVariables,
unknown
>,
options?: DeleteBountyMutateOptions,
) => mutation.mutate({ id }, options),
mutateAsync: (
id: string,
options?: MutateOptions<
DeleteBountyMutation,
unknown,
DeleteBountyMutationVariables,
unknown
>,
options?: DeleteBountyMutateOptions,
) => mutation.mutateAsync({ id }, options),
};
}

/**
* Hook to claim a bounty
* Implemented as updateBounty mutation with status: "IN_PROGRESS"
* Awaiting backend implementation of dedicated claimBounty mutation
*
* @returns Mutation object with mutate/mutateAsync methods
* @example
* const { mutate } = useClaimBounty();
* mutate("bounty-id-123");
*/
export function useClaimBounty() {
const queryClient = useQueryClient();
// Claim is treated as an update the status to IN_PROGRESS
// Claim is treated as updating the bounty status to IN_PROGRESS
const mutation = useUpdateBountyMutation({
onSuccess: (data, variables) => {
queryClient.setQueryData<BountyQuery>(
Expand All @@ -198,21 +231,11 @@ export function useClaimBounty() {
...mutation,
mutate: (
id: string,
options?: MutateOptions<
UpdateBountyMutation,
unknown,
UpdateBountyMutationVariables,
unknown
>,
options?: UpdateBountyMutateOptions,
) => mutation.mutate({ input: { id, status: "IN_PROGRESS" } }, options),
mutateAsync: (
id: string,
options?: MutateOptions<
UpdateBountyMutation,
unknown,
UpdateBountyMutationVariables,
unknown
>,
options?: UpdateBountyMutateOptions,
) =>
mutation.mutateAsync({ input: { id, status: "IN_PROGRESS" } }, options),
};
Expand Down