diff --git a/frontend/src/hooks/api/approvalRequests/index.tsx b/frontend/src/hooks/api/approvalRequests/index.tsx new file mode 100644 index 000000000..1b44f713c --- /dev/null +++ b/frontend/src/hooks/api/approvalRequests/index.tsx @@ -0,0 +1,19 @@ +export { + useApproveApprovalRequest, + useCreateApprovalRequest, + useRejectApprovalRequest +} from "./mutations"; +export { approvalRequestQuery } from "./queries"; +export { + ApprovalRequestStatus, + ApprovalRequestStepStatus, + type ApprovalRequestApproval, + type ApprovalRequestStep, + type PamAccessRequestData, + type TApprovalRequest, + type TApproveApprovalRequestDTO, + type TCreateApprovalRequestDTO, + type TGetApprovalRequestByIdDTO, + type TListApprovalRequestsDTO, + type TRejectApprovalRequestDTO +} from "./types"; diff --git a/frontend/src/hooks/api/approvalRequests/mutations.tsx b/frontend/src/hooks/api/approvalRequests/mutations.tsx new file mode 100644 index 000000000..3afcd290a --- /dev/null +++ b/frontend/src/hooks/api/approvalRequests/mutations.tsx @@ -0,0 +1,59 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import { apiRequest } from "@app/config/request"; + +import { approvalRequestQuery } from "./queries"; +import { + TApprovalRequest, + TApproveApprovalRequestDTO, + TCreateApprovalRequestDTO, + TRejectApprovalRequestDTO +} from "./types"; + +export const useCreateApprovalRequest = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async ({ policyType, ...dto }: TCreateApprovalRequestDTO) => { + const { data } = await apiRequest.post<{ request: TApprovalRequest }>( + `/api/v1/approval-policies/${policyType}/requests`, + dto + ); + return data.request; + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: approvalRequestQuery.allKey() }); + } + }); +}; + +export const useApproveApprovalRequest = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async ({ policyType, requestId, comment }: TApproveApprovalRequestDTO) => { + const { data } = await apiRequest.post<{ request: TApprovalRequest }>( + `/api/v1/approval-policies/${policyType}/requests/${requestId}/approve`, + { comment } + ); + return data.request; + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: approvalRequestQuery.allKey() }); + } + }); +}; + +export const useRejectApprovalRequest = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async ({ policyType, requestId, comment }: TRejectApprovalRequestDTO) => { + const { data } = await apiRequest.post<{ request: TApprovalRequest }>( + `/api/v1/approval-policies/${policyType}/requests/${requestId}/reject`, + { comment } + ); + return data.request; + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: approvalRequestQuery.allKey() }); + } + }); +}; diff --git a/frontend/src/hooks/api/approvalRequests/queries.tsx b/frontend/src/hooks/api/approvalRequests/queries.tsx new file mode 100644 index 000000000..3b4abddcc --- /dev/null +++ b/frontend/src/hooks/api/approvalRequests/queries.tsx @@ -0,0 +1,37 @@ +import { queryOptions } from "@tanstack/react-query"; + +import { apiRequest } from "@app/config/request"; + +import { TApprovalRequest, TGetApprovalRequestByIdDTO, TListApprovalRequestsDTO } from "./types"; + +export const approvalRequestQuery = { + allKey: () => ["approval-requests"] as const, + getByIdKey: (params: TGetApprovalRequestByIdDTO) => + [...approvalRequestQuery.allKey(), "by-id", params] as const, + listKey: (params: TListApprovalRequestsDTO) => + [...approvalRequestQuery.allKey(), "list", params] as const, + getById: (params: TGetApprovalRequestByIdDTO) => + queryOptions({ + queryKey: approvalRequestQuery.getByIdKey(params), + queryFn: async () => { + const { data } = await apiRequest.get<{ request: TApprovalRequest }>( + `/api/v1/approval-policies/${params.policyType}/requests/${params.requestId}` + ); + return data.request; + } + }), + list: (params: TListApprovalRequestsDTO) => + queryOptions({ + queryKey: approvalRequestQuery.listKey(params), + queryFn: async () => { + const { data } = await apiRequest.get<{ + requests: TApprovalRequest[]; + }>(`/api/v1/approval-policies/${params.policyType}/requests`, { + params: { + projectId: params.projectId + } + }); + return data.requests; + } + }) +}; diff --git a/frontend/src/hooks/api/approvalRequests/types.ts b/frontend/src/hooks/api/approvalRequests/types.ts new file mode 100644 index 000000000..9d119a364 --- /dev/null +++ b/frontend/src/hooks/api/approvalRequests/types.ts @@ -0,0 +1,100 @@ +import { ApprovalPolicyType, ApproverType } from "../approvalPolicies"; + +export enum ApprovalRequestStatus { + Pending = "pending", + Approved = "approved", + Rejected = "rejected", + Expired = "expired" +} + +export enum ApprovalRequestStepStatus { + Pending = "pending", + InProgress = "in-progress", + Approved = "approved", + Rejected = "rejected" +} + +export type ApprovalRequestApproval = { + id: string; + requestStepId: string; + approverId: string; + approverType: ApproverType; + comment?: string | null; + createdAt: string; + updatedAt: string; +}; + +export type ApprovalRequestStep = { + id: string; + requestId: string; + name?: string | null; + requiredApprovals: number; + notifyApprovers?: boolean | null; + stepNumber: number; + status: ApprovalRequestStepStatus; + startedAt?: string | null; + completedAt?: string | null; + approvers: { + type: ApproverType; + id: string; + }[]; + approvals: ApprovalRequestApproval[]; + createdAt: string; + updatedAt: string; +}; + +export type PamAccessRequestData = { + resourceId: string; + accountPath: string; + requestDurationSeconds: number; +}; + +export type TApprovalRequest = { + id: string; + projectId: string; + policyId: string; + type: ApprovalPolicyType; + status: ApprovalRequestStatus; + requesterId: string; + requesterName: string; + requesterEmail: string; + justification?: string | null; + expiresAt?: string | null; + requestData: { + version: number; + requestData: PamAccessRequestData; + }; + steps: ApprovalRequestStep[]; + createdAt: string; + updatedAt: string; +}; + +export type TCreateApprovalRequestDTO = { + policyType: ApprovalPolicyType; + projectId: string; + justification?: string | null; + expiresAt?: Date | null; + requestData: PamAccessRequestData; +}; + +export type TGetApprovalRequestByIdDTO = { + policyType: ApprovalPolicyType; + requestId: string; +}; + +export type TListApprovalRequestsDTO = { + policyType: ApprovalPolicyType; + projectId: string; +}; + +export type TApproveApprovalRequestDTO = { + policyType: ApprovalPolicyType; + requestId: string; + comment?: string; +}; + +export type TRejectApprovalRequestDTO = { + policyType: ApprovalPolicyType; + requestId: string; + comment?: string; +};