({
return (
{actions.map((action) => {
+ if (action.hidden?.(item)) return null;
+
const label =
typeof action.label === 'function'
? action.label(item)
@@ -212,37 +215,41 @@ function DataTableContent({
manualSorting: isManualSorting,
pageCount: pagination
? Math.ceil((pagination.totalItems ?? data.length) / pagination.limit)
- : -1,
+ : undefined,
state: {
rowSelection,
columnVisibility,
columnPinning,
columnSizing,
sorting,
- pagination: pagination
+ ...(pagination
? {
+ pagination: {
+ pageIndex: Math.floor(pagination.skip / pagination.limit),
+ pageSize: pagination.limit,
+ },
+ }
+ : {}),
+ },
+ onPaginationChange: pagination
+ ? (updater) => {
+ const currentState = {
pageIndex: Math.floor(pagination.skip / pagination.limit),
pageSize: pagination.limit,
+ };
+ const newState =
+ typeof updater === 'function' ? updater(currentState) : updater;
+ const pageSizeChanged = newState.pageSize !== pagination.limit;
+
+ if (pageSizeChanged) {
+ pagination.onLimitChange(newState.pageSize);
+ pagination.onPageChange(0);
+ return;
}
- : undefined,
- },
- onPaginationChange: (updater) => {
- if (typeof updater === 'function' && pagination) {
- const newState = updater({
- pageIndex: Math.floor(pagination.skip / pagination.limit),
- pageSize: pagination.limit,
- });
- const pageSizeChanged = newState.pageSize !== pagination.limit;
- if (pageSizeChanged) {
- pagination.onLimitChange(newState.pageSize);
- pagination.onPageChange(0);
- return;
+ pagination.onPageChange(newState.pageIndex * newState.pageSize);
}
-
- pagination.onPageChange(newState.pageIndex * newState.pageSize);
- }
- },
+ : undefined,
});
return (
diff --git a/src/config/menu.config.ts b/src/config/menu.config.ts
index 9cafbf9..7d7f609 100644
--- a/src/config/menu.config.ts
+++ b/src/config/menu.config.ts
@@ -9,6 +9,7 @@ import {
Users,
Building2,
BadgeIndianRupee,
+ CalendarClock,
Globe,
} from 'lucide-react';
import type { ComponentType, SVGProps } from 'react';
@@ -37,6 +38,12 @@ export const menuItems: MenuItem[] = [
icon: Ticket,
permission: PERMISSIONS.TICKET.READ,
},
+ {
+ title: 'Extension Requests',
+ path: ROUTES.EXTENSION_REQUESTS,
+ icon: CalendarClock,
+ permission: PERMISSIONS.TICKET.ASSIGN,
+ },
{
title: 'Project',
path: ROUTES.PROJECT,
diff --git a/src/constants/apiRoutes.ts b/src/constants/apiRoutes.ts
index 8278e02..3458f44 100644
--- a/src/constants/apiRoutes.ts
+++ b/src/constants/apiRoutes.ts
@@ -70,7 +70,8 @@ export const API_ROUTES = {
ASSIGNMENTS: (id: string) => `/biz/api/v1/tickets/${id}/assignments`,
REQUEST_EXTENSION: (ticketId: string, assignmentId: number) =>
`/biz/api/v1/tickets/${ticketId}/assignments/${assignmentId}/extension-requests`,
- EXTENSION_REQUESTS: (ticketId: string) =>
+ EXTENSION_REQUESTS: '/biz/api/v1/tickets/extension-requests',
+ TICKET_EXTENSION_REQUESTS: (ticketId: string) =>
`/biz/api/v1/tickets/${ticketId}/extension-requests`,
REVIEW_EXTENSION_REQUEST: (ticketId: string, assignmentId: number) =>
`/biz/api/v1/tickets/${ticketId}/assignments/${assignmentId}/extension-request/decision`,
diff --git a/src/services/api/ticket.service.ts b/src/services/api/ticket.service.ts
index 1ade1d6..4cc879e 100644
--- a/src/services/api/ticket.service.ts
+++ b/src/services/api/ticket.service.ts
@@ -11,6 +11,7 @@ import type {
TicketAssignmentSummary,
TicketAssignmentsResponse,
TicketExtensionRequestsResponse,
+ TicketExtensionRequestsParams,
TicketOverviewDetail,
TicketDefectClassesResponse,
TicketListParams,
@@ -136,7 +137,7 @@ export const ticketService = {
assignmentId: number,
): Promise => {
const response = await axiosClient.get(
- API_ROUTES.TICKETS.EXTENSION_REQUESTS(ticketId),
+ API_ROUTES.TICKETS.TICKET_EXTENSION_REQUESTS(ticketId),
{
params: { assignment_id: assignmentId },
},
@@ -144,6 +145,16 @@ export const ticketService = {
return response.data;
},
+ getTicketExtensionRequests: async (
+ params: TicketExtensionRequestsParams,
+ ): Promise => {
+ const response = await axiosClient.get(
+ API_ROUTES.TICKETS.EXTENSION_REQUESTS,
+ { params },
+ );
+ return response.data;
+ },
+
reviewTicketExtension: async (
ticketId: string,
assignmentId: number,
diff --git a/src/types/ticket/actions.ts b/src/types/ticket/actions.ts
index 940be53..00b1d2c 100644
--- a/src/types/ticket/actions.ts
+++ b/src/types/ticket/actions.ts
@@ -58,19 +58,33 @@ export interface TicketExtensionRequestActor {
};
}
+export type TicketExtensionRequestStatus =
+ | 'pending'
+ | 'approved'
+ | 'rejected'
+ | 'cancelled';
+
export interface TicketExtensionRequest {
id: number;
ticket_id: string;
+ ticket_name: string;
assignment_id: number;
- defect_class: string;
+ defect_class?: string | null;
current_due_at: string;
requested_due_at: string;
reason: string;
- status: 'pending' | 'approved' | 'rejected' | 'cancelled';
+ status: TicketExtensionRequestStatus;
requested_by: TicketExtensionRequestActor | null;
requested_at: string;
resolved_by: TicketExtensionRequestActor | null;
resolved_at: string | null;
+ decision_note: string | null;
+ history_meta: {
+ previous_request_count: number;
+ previous_approved_count: number;
+ previous_rejected_count: number;
+ previous_cancelled_count: number;
+ };
}
export interface TicketExtensionRequestsResponse {
@@ -78,6 +92,11 @@ export interface TicketExtensionRequestsResponse {
total: number;
}
+export interface TicketExtensionRequestsParams extends PaginationParams {
+ ticket_name?: string;
+ status?: TicketExtensionRequestStatus;
+}
+
export interface CloseTicketPayload {
defect_class: string;
}
diff --git a/src/utils/routes.ts b/src/utils/routes.ts
index 89f2d1e..97738fc 100644
--- a/src/utils/routes.ts
+++ b/src/utils/routes.ts
@@ -15,6 +15,7 @@ export const ROUTES = {
ACCOUNT: '/account',
UPLOAD: '/upload',
TICKET: '/ticket',
+ EXTENSION_REQUESTS: '/extension-requests',
TICKET_DETAIL: (ticketId: string) => `/ticket/${ticketId}`,
TICKET_ASSIGN: (ticketId: string) => `/ticket/${ticketId}/assign`,
TICKET_REVIEW: (ticketId: string) => `/ticket/${ticketId}/review`,