mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 18:33:01 +00:00
replaced per-endpoint helpers with ts-rest contract and typed client
This commit is contained in:
@@ -7,12 +7,18 @@ import type {
|
||||
} from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { issueComment } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
export function useIssueComments(issueId?: number | null) {
|
||||
return useQuery<IssueCommentResponse[]>({
|
||||
queryKey: queryKeys.issueComments.byIssue(issueId ?? 0),
|
||||
queryFn: () => issueComment.byIssue(issueId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.issueCommentsByIssue({
|
||||
query: { issueId: issueId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as IssueCommentResponse[];
|
||||
},
|
||||
enabled: Boolean(issueId),
|
||||
});
|
||||
}
|
||||
@@ -22,7 +28,12 @@ export function useCreateIssueComment() {
|
||||
|
||||
return useMutation<IssueCommentRecord, Error, IssueCommentCreateRequest>({
|
||||
mutationKey: ["issue-comments", "create"],
|
||||
mutationFn: issueComment.create,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.issueCommentCreate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to create comment");
|
||||
return data as IssueCommentRecord;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.issueComments.byIssue(variables.issueId),
|
||||
@@ -36,7 +47,12 @@ export function useDeleteIssueComment() {
|
||||
|
||||
return useMutation<SuccessResponse, Error, IssueCommentDeleteRequest>({
|
||||
mutationKey: ["issue-comments", "delete"],
|
||||
mutationFn: issueComment.delete,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.issueCommentDelete({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to delete comment");
|
||||
return data as SuccessResponse;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.issueComments.all });
|
||||
},
|
||||
|
||||
@@ -12,12 +12,18 @@ import type {
|
||||
} from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { issue } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
export function useIssues(projectId?: number | null) {
|
||||
return useQuery<IssueResponse[]>({
|
||||
queryKey: queryKeys.issues.byProject(projectId ?? 0),
|
||||
queryFn: () => issue.byProject(projectId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.issuesByProject({
|
||||
query: { projectId: projectId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as IssueResponse[];
|
||||
},
|
||||
enabled: Boolean(projectId),
|
||||
});
|
||||
}
|
||||
@@ -25,7 +31,14 @@ export function useIssues(projectId?: number | null) {
|
||||
export function useIssueById(issueId?: IssueByIdQuery["issueId"] | null) {
|
||||
return useQuery<IssueResponse>({
|
||||
queryKey: queryKeys.issues.byId(issueId ?? 0),
|
||||
queryFn: () => issue.byId(issueId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.issueById({
|
||||
query: { issueId: issueId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("issue not found");
|
||||
return data as IssueResponse;
|
||||
},
|
||||
enabled: Boolean(issueId),
|
||||
});
|
||||
}
|
||||
@@ -33,7 +46,13 @@ export function useIssueById(issueId?: IssueByIdQuery["issueId"] | null) {
|
||||
export function useIssueStatusCount(organisationId?: number | null, status?: string | null) {
|
||||
return useQuery<StatusCountResponse>({
|
||||
queryKey: queryKeys.issues.statusCount(organisationId ?? 0, status ?? ""),
|
||||
queryFn: () => issue.statusCount(organisationId ?? 0, status ?? ""),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.issuesStatusCount({
|
||||
query: { organisationId: organisationId ?? 0, status: status ?? "" },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as StatusCountResponse;
|
||||
},
|
||||
enabled: Boolean(organisationId && status),
|
||||
});
|
||||
}
|
||||
@@ -43,7 +62,12 @@ export function useCreateIssue() {
|
||||
|
||||
return useMutation<IssueRecord, Error, IssueCreateRequest>({
|
||||
mutationKey: ["issues", "create"],
|
||||
mutationFn: issue.create,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.issueCreate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to create issue");
|
||||
return data as IssueRecord;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.issues.byProject(variables.projectId),
|
||||
@@ -57,7 +81,12 @@ export function useUpdateIssue() {
|
||||
|
||||
return useMutation<IssueRecord, Error, IssueUpdateRequest>({
|
||||
mutationKey: ["issues", "update"],
|
||||
mutationFn: issue.update,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.issueUpdate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to update issue");
|
||||
return data as IssueRecord;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.issues.all });
|
||||
},
|
||||
@@ -69,7 +98,12 @@ export function useDeleteIssue() {
|
||||
|
||||
return useMutation<SuccessResponse, Error, number>({
|
||||
mutationKey: ["issues", "delete"],
|
||||
mutationFn: issue.delete,
|
||||
mutationFn: async (issueId) => {
|
||||
const { data, error } = await apiClient.issueDelete({ body: { id: issueId } });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to delete issue");
|
||||
return data as SuccessResponse;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.issues.all });
|
||||
},
|
||||
@@ -81,7 +115,11 @@ export function useReplaceIssueStatus() {
|
||||
|
||||
return useMutation<unknown, Error, IssuesReplaceStatusRequest>({
|
||||
mutationKey: ["issues", "replace-status"],
|
||||
mutationFn: issue.replaceStatus,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.issuesReplaceStatus({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
return data as unknown;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.issues.all });
|
||||
},
|
||||
@@ -91,7 +129,14 @@ export function useReplaceIssueStatus() {
|
||||
export function useIssueTypeCount(organisationId?: number | null, type?: string | null) {
|
||||
return useQuery<TypeCountResponse>({
|
||||
queryKey: queryKeys.issues.typeCount(organisationId ?? 0, type ?? ""),
|
||||
queryFn: () => issue.typeCount(organisationId ?? 0, type ?? ""),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.issuesTypeCount({
|
||||
query: { organisationId: organisationId ?? 0, type: type ?? "" },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to get type count");
|
||||
return data as TypeCountResponse;
|
||||
},
|
||||
enabled: Boolean(organisationId && type),
|
||||
});
|
||||
}
|
||||
@@ -101,7 +146,11 @@ export function useReplaceIssueType() {
|
||||
|
||||
return useMutation<unknown, Error, IssuesReplaceTypeRequest>({
|
||||
mutationKey: ["issues", "replace-type"],
|
||||
mutationFn: issue.replaceType,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.issuesReplaceType({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
return data as unknown;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.issues.all });
|
||||
},
|
||||
|
||||
@@ -2,22 +2,39 @@ import type {
|
||||
OrgAddMemberRequest,
|
||||
OrganisationMemberRecord,
|
||||
OrganisationMemberResponse,
|
||||
OrganisationRecordType,
|
||||
OrganisationResponse,
|
||||
OrgCreateRequest,
|
||||
OrgRemoveMemberRequest,
|
||||
OrgUpdateMemberRoleRequest,
|
||||
OrgUpdateRequest,
|
||||
SuccessResponse,
|
||||
} from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { organisation } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
export function useOrganisations() {
|
||||
return useQuery({
|
||||
return useQuery<OrganisationResponse[]>({
|
||||
queryKey: queryKeys.organisations.byUser(),
|
||||
queryFn: organisation.byUser,
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.organisationsByUser();
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as OrganisationResponse[];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useOrganisationMembers(organisationId?: number | null) {
|
||||
return useQuery<OrganisationMemberResponse[]>({
|
||||
queryKey: queryKeys.organisations.members(organisationId ?? 0),
|
||||
queryFn: () => organisation.members(organisationId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.organisationMembers({
|
||||
query: { organisationId: organisationId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as OrganisationMemberResponse[];
|
||||
},
|
||||
enabled: Boolean(organisationId),
|
||||
});
|
||||
}
|
||||
@@ -25,9 +42,14 @@ export function useOrganisationMembers(organisationId?: number | null) {
|
||||
export function useCreateOrganisation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<OrganisationRecordType, Error, OrgCreateRequest>({
|
||||
mutationKey: ["organisations", "create"],
|
||||
mutationFn: organisation.create,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.organisationCreate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to create organisation");
|
||||
return data as OrganisationRecordType;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.organisations.byUser() });
|
||||
},
|
||||
@@ -37,9 +59,14 @@ export function useCreateOrganisation() {
|
||||
export function useUpdateOrganisation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<OrganisationRecordType, Error, OrgUpdateRequest>({
|
||||
mutationKey: ["organisations", "update"],
|
||||
mutationFn: organisation.update,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.organisationUpdate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to update organisation");
|
||||
return data as OrganisationRecordType;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.organisations.byUser() });
|
||||
},
|
||||
@@ -49,9 +76,14 @@ export function useUpdateOrganisation() {
|
||||
export function useDeleteOrganisation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<SuccessResponse, Error, number>({
|
||||
mutationKey: ["organisations", "delete"],
|
||||
mutationFn: organisation.remove,
|
||||
mutationFn: async (orgId) => {
|
||||
const { data, error } = await apiClient.organisationDelete({ body: { id: orgId } });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to delete organisation");
|
||||
return data as SuccessResponse;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.organisations.byUser() });
|
||||
},
|
||||
@@ -63,7 +95,12 @@ export function useAddOrganisationMember() {
|
||||
|
||||
return useMutation<OrganisationMemberRecord, Error, OrgAddMemberRequest>({
|
||||
mutationKey: ["organisations", "members", "add"],
|
||||
mutationFn: organisation.addMember,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.organisationAddMember({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to add member");
|
||||
return data as OrganisationMemberRecord;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.organisations.members(variables.organisationId),
|
||||
@@ -75,9 +112,14 @@ export function useAddOrganisationMember() {
|
||||
export function useRemoveOrganisationMember() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<SuccessResponse, Error, OrgRemoveMemberRequest>({
|
||||
mutationKey: ["organisations", "members", "remove"],
|
||||
mutationFn: organisation.removeMember,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.organisationRemoveMember({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to remove member");
|
||||
return data as SuccessResponse;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.organisations.members(variables.organisationId),
|
||||
@@ -89,9 +131,14 @@ export function useRemoveOrganisationMember() {
|
||||
export function useUpdateOrganisationMemberRole() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<OrganisationMemberRecord, Error, OrgUpdateMemberRoleRequest>({
|
||||
mutationKey: ["organisations", "members", "update-role"],
|
||||
mutationFn: organisation.updateMemberRole,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.organisationUpdateMemberRole({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to update member role");
|
||||
return data as OrganisationMemberRecord;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.organisations.members(variables.organisationId),
|
||||
@@ -105,7 +152,15 @@ export function useUploadOrganisationIcon() {
|
||||
|
||||
return useMutation<string, Error, { file: File; organisationId: number }>({
|
||||
mutationKey: ["organisations", "upload-icon"],
|
||||
mutationFn: ({ file, organisationId }) => organisation.uploadIcon(file, organisationId),
|
||||
mutationFn: async ({ file, organisationId }) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("organisationId", `${organisationId}`);
|
||||
const { data, error } = await apiClient.organisationUploadIcon({ body: formData });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to upload organisation icon");
|
||||
return (data as { iconURL: string }).iconURL;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.organisations.byUser() });
|
||||
},
|
||||
|
||||
@@ -3,15 +3,22 @@ import type {
|
||||
ProjectRecord,
|
||||
ProjectResponse,
|
||||
ProjectUpdateRequest,
|
||||
SuccessResponse,
|
||||
} from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { project } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
export function useProjects(organisationId?: number | null) {
|
||||
return useQuery<ProjectResponse[]>({
|
||||
queryKey: queryKeys.projects.byOrganisation(organisationId ?? 0),
|
||||
queryFn: () => project.byOrganisation(organisationId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.projectsByOrganisation({
|
||||
query: { organisationId: organisationId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as ProjectResponse[];
|
||||
},
|
||||
enabled: Boolean(organisationId),
|
||||
});
|
||||
}
|
||||
@@ -21,7 +28,12 @@ export function useCreateProject() {
|
||||
|
||||
return useMutation<ProjectRecord, Error, ProjectCreateRequest>({
|
||||
mutationKey: ["projects", "create"],
|
||||
mutationFn: project.create,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.projectCreate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to create project");
|
||||
return data as ProjectRecord;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: queryKeys.projects.byOrganisation(variables.organisationId),
|
||||
@@ -35,7 +47,12 @@ export function useUpdateProject() {
|
||||
|
||||
return useMutation<ProjectRecord, Error, ProjectUpdateRequest>({
|
||||
mutationKey: ["projects", "update"],
|
||||
mutationFn: project.update,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.projectUpdate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to update project");
|
||||
return data as ProjectRecord;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.projects.all });
|
||||
},
|
||||
@@ -45,9 +62,14 @@ export function useUpdateProject() {
|
||||
export function useDeleteProject() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<SuccessResponse, Error, number>({
|
||||
mutationKey: ["projects", "delete"],
|
||||
mutationFn: project.remove,
|
||||
mutationFn: async (projectId) => {
|
||||
const { data, error } = await apiClient.projectDelete({ body: { id: projectId } });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to delete project");
|
||||
return data as SuccessResponse;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.projects.all });
|
||||
},
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import type { SprintCreateRequest, SprintRecord, SprintUpdateRequest } from "@sprint/shared";
|
||||
import type { SprintCreateRequest, SprintRecord, SprintUpdateRequest, SuccessResponse } from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { sprint } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
export function useSprints(projectId?: number | null) {
|
||||
return useQuery<SprintRecord[]>({
|
||||
queryKey: queryKeys.sprints.byProject(projectId ?? 0),
|
||||
queryFn: () => sprint.byProject(projectId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.sprintsByProject({
|
||||
query: { projectId: projectId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as SprintRecord[];
|
||||
},
|
||||
enabled: Boolean(projectId),
|
||||
});
|
||||
}
|
||||
@@ -16,7 +22,12 @@ export function useCreateSprint() {
|
||||
|
||||
return useMutation<SprintRecord, Error, SprintCreateRequest>({
|
||||
mutationKey: ["sprints", "create"],
|
||||
mutationFn: sprint.create,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.sprintCreate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to create sprint");
|
||||
return data as SprintRecord;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.sprints.byProject(variables.projectId) });
|
||||
},
|
||||
@@ -28,7 +39,12 @@ export function useUpdateSprint() {
|
||||
|
||||
return useMutation<SprintRecord, Error, SprintUpdateRequest>({
|
||||
mutationKey: ["sprints", "update"],
|
||||
mutationFn: sprint.update,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.sprintUpdate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to update sprint");
|
||||
return data as SprintRecord;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.sprints.all });
|
||||
},
|
||||
@@ -38,9 +54,14 @@ export function useUpdateSprint() {
|
||||
export function useDeleteSprint() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
return useMutation<SuccessResponse, Error, number>({
|
||||
mutationKey: ["sprints", "delete"],
|
||||
mutationFn: sprint.remove,
|
||||
mutationFn: async (sprintId) => {
|
||||
const { data, error } = await apiClient.sprintDelete({ body: { id: sprintId } });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to delete sprint");
|
||||
return data as SuccessResponse;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.sprints.all });
|
||||
},
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import type { TimerEndRequest, TimerListItem, TimerState, TimerToggleRequest } from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { timer } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
const activeTimersQueryFn = () => timer.list({ activeOnly: true });
|
||||
const activeTimersQueryFn = async () => {
|
||||
const { data, error } = await apiClient.timers({ query: { activeOnly: true } });
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as TimerListItem[];
|
||||
};
|
||||
|
||||
export function useActiveTimers(options?: { refetchInterval?: number; enabled?: boolean }) {
|
||||
return useQuery<TimerListItem[]>({
|
||||
@@ -29,7 +33,13 @@ export function useTimerState(issueId?: number | null, options?: { refetchInterv
|
||||
export function useInactiveTimers(issueId?: number | null, options?: { refetchInterval?: number }) {
|
||||
return useQuery<TimerState[]>({
|
||||
queryKey: queryKeys.timers.inactive(issueId ?? 0),
|
||||
queryFn: () => timer.getInactive(issueId ?? 0),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.timerGetInactive({
|
||||
query: { issueId: issueId ?? 0 },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return (data ?? []) as TimerState[];
|
||||
},
|
||||
enabled: Boolean(issueId),
|
||||
refetchInterval: options?.refetchInterval,
|
||||
refetchIntervalInBackground: false,
|
||||
@@ -41,7 +51,12 @@ export function useToggleTimer() {
|
||||
|
||||
return useMutation<TimerState, Error, TimerToggleRequest>({
|
||||
mutationKey: ["timers", "toggle"],
|
||||
mutationFn: timer.toggle,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.timerToggle({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to toggle timer");
|
||||
return data as TimerState;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.timers.inactive(variables.issueId) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.timers.list() });
|
||||
@@ -54,7 +69,12 @@ export function useEndTimer() {
|
||||
|
||||
return useMutation<TimerState, Error, TimerEndRequest>({
|
||||
mutationKey: ["timers", "end"],
|
||||
mutationFn: timer.end,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.timerEnd({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to end timer");
|
||||
return data as TimerState;
|
||||
},
|
||||
onSuccess: (_data, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.timers.inactive(variables.issueId) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.timers.list() });
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import type { UserRecord, UserUpdateRequest } from "@sprint/shared";
|
||||
import type { UserResponse, UserUpdateRequest } from "@sprint/shared";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { queryKeys } from "@/lib/query/keys";
|
||||
import { user } from "@/lib/server";
|
||||
import { apiClient } from "@/lib/server";
|
||||
|
||||
export function useUserByUsername(username?: string | null) {
|
||||
return useQuery<UserRecord>({
|
||||
return useQuery<UserResponse>({
|
||||
queryKey: queryKeys.users.byUsername(username ?? ""),
|
||||
queryFn: () => user.byUsername(username ?? ""),
|
||||
queryFn: async () => {
|
||||
const { data, error } = await apiClient.userByUsername({
|
||||
query: { username: username ?? "" },
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("user not found");
|
||||
return data as UserResponse;
|
||||
},
|
||||
enabled: Boolean(username),
|
||||
});
|
||||
}
|
||||
@@ -14,9 +21,14 @@ export function useUserByUsername(username?: string | null) {
|
||||
export function useUpdateUser() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<UserRecord, Error, UserUpdateRequest>({
|
||||
return useMutation<UserResponse, Error, UserUpdateRequest>({
|
||||
mutationKey: ["users", "update"],
|
||||
mutationFn: user.update,
|
||||
mutationFn: async (input) => {
|
||||
const { data, error } = await apiClient.userUpdate({ body: input });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to update user");
|
||||
return data as UserResponse;
|
||||
},
|
||||
onSuccess: (_data) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.users.all });
|
||||
},
|
||||
@@ -28,7 +40,14 @@ export function useUploadAvatar() {
|
||||
|
||||
return useMutation<string, Error, File>({
|
||||
mutationKey: ["users", "upload-avatar"],
|
||||
mutationFn: user.uploadAvatar,
|
||||
mutationFn: async (file) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
const { data, error } = await apiClient.userUploadAvatar({ body: formData });
|
||||
if (error) throw new Error(error);
|
||||
if (!data) throw new Error("failed to upload avatar");
|
||||
return (data as { avatarURL: string }).avatarURL;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.users.all });
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user