diff --git a/src/app/(modules)/ticket/[ticketId]/components/TicketDetailHeader.tsx b/src/app/(modules)/ticket/[ticketId]/components/TicketDetailHeader.tsx
index 5825408..e0a260a 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/TicketDetailHeader.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/TicketDetailHeader.tsx
@@ -6,14 +6,17 @@ import { useRouter } from 'next/navigation';
import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards';
-import type { TicketOverviewDetail } from '@/types';
+import type { TicketDetail, TicketOverviewDetail } from '@/types';
import { AssignTicketAction } from './actions/AssignTicketAction';
+import { OpenRepairReviewAction } from './actions/OpenRepairReviewAction';
export function TicketDetailHeader({
ticket,
+ classDetail,
}: {
ticket: TicketOverviewDetail;
+ classDetail?: TicketDetail;
}) {
const router = useRouter();
const ticketLabel = ticket.ticket_name || ticket.id;
@@ -26,6 +29,11 @@ export function TicketDetailHeader({
+ {classDetail?.assignment_status === 'under_review' ? (
+
+
+
+ ) : null}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/TicketStatusActions.tsx b/src/app/(modules)/ticket/[ticketId]/components/TicketStatusActions.tsx
index 8b3d8e9..a8d691a 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/TicketStatusActions.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/TicketStatusActions.tsx
@@ -2,25 +2,24 @@
import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards';
-import type { TicketDetail } from '@/types';
+import type { TicketAssignmentSummary, TicketDetail } from '@/types';
import { AssignedContractorAction } from './actions/AssignedContractorAction';
import { ClosedTicketAction } from './actions/ClosedTicketAction';
import { NoTicketAction } from './actions/NoTicketAction';
-import { OpenRepairReviewAction } from './actions/OpenRepairReviewAction';
import { RequestExtensionAction } from './actions/RequestExtensionAction';
import { ReviewExtensionRequestAction } from './actions/ReviewExtensionRequestAction';
interface TicketStatusActionsProps {
ticket: TicketDetail;
+ assignment?: TicketAssignmentSummary;
}
-function getTicketAction(ticket: TicketDetail) {
- if (ticket.assignment_status === 'unassigned') {
- return null;
- }
-
- if (ticket.assignment_status === 'assigned') {
+function getTicketAction(
+ ticket: TicketDetail,
+ assignment?: TicketAssignmentSummary,
+) {
+ if (assignment && !assignment.is_complete) {
return (
}
>
-
+
}
>
<>
-
-
+ {ticket.assignment_status === 'assigned' ? (
+
+ ) : null}
+
>
);
}
- if (ticket.assignment_status === 'under_review') {
+ if (ticket.assignment_status === 'unassigned') {
+ return null;
+ }
+
+ if (ticket.assignment_status === 'assigned') {
return (
}
>
-
+
);
}
+ if (ticket.assignment_status === 'under_review') {
+ return null;
+ }
+
if (
ticket.assignment_status === 'approved' ||
ticket.assignment_status === 'rejected'
@@ -62,8 +78,11 @@ function getTicketAction(ticket: TicketDetail) {
return
;
}
-export function TicketStatusActions({ ticket }: TicketStatusActionsProps) {
- const action = getTicketAction(ticket);
+export function TicketStatusActions({
+ ticket,
+ assignment,
+}: TicketStatusActionsProps) {
+ const action = getTicketAction(ticket, assignment);
return action ?
{action}
: null;
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/OpenRepairReviewAction.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/OpenRepairReviewAction.tsx
index 24963d5..72ae0a1 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/actions/OpenRepairReviewAction.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/actions/OpenRepairReviewAction.tsx
@@ -1,37 +1,24 @@
'use client';
import { useRouter } from 'next/navigation';
-import { ArrowRight, ClipboardCheck } from 'lucide-react';
+import { ClipboardCheck } from 'lucide-react';
import { Button } from '@/components/ui/button';
import type { TicketDetail } from '@/types';
import { ROUTES } from '@/utils/routes';
-import { TicketActionCard } from './TicketActionCard';
-
export function OpenRepairReviewAction({ ticket }: { ticket: TicketDetail }) {
const router = useRouter();
return (
-
-
-
- Review every submitted repair separately using its detection image,
- location, and repair proof.
-
-
-
-
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionAction.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionAction.tsx
index 9ffe907..48ba9a8 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionAction.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionAction.tsx
@@ -5,10 +5,22 @@ import type { TicketDetail } from '@/types';
import { TicketActionCard } from './TicketActionCard';
import { TicketExtensionRequestPanel } from './TicketExtensionRequestPanel';
-export function RequestExtensionAction({ ticket }: { ticket: TicketDetail }) {
+export function RequestExtensionAction({
+ ticket,
+ assignmentId,
+ dueAt,
+}: {
+ ticket: TicketDetail;
+ assignmentId: number;
+ dueAt: string | null;
+}) {
return (
-
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionForm.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionForm.tsx
index 0bc0c88..3324992 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionForm.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/actions/RequestExtensionForm.tsx
@@ -16,10 +16,15 @@ const MAX_REASON_LENGTH = 300;
interface RequestExtensionFormProps {
ticket: TicketDetail;
+ assignmentId: number;
+ currentDueAt: string | null;
}
-export function RequestExtensionForm({ ticket }: RequestExtensionFormProps) {
- const currentDueAt = ticket.worker?.due_at;
+export function RequestExtensionForm({
+ ticket,
+ assignmentId,
+ currentDueAt,
+}: RequestExtensionFormProps) {
const currentDueDate = useMemo(
() => (currentDueAt ? new Date(currentDueAt) : undefined),
[currentDueAt],
@@ -36,7 +41,6 @@ export function RequestExtensionForm({ ticket }: RequestExtensionFormProps) {
);
const [requestedDueDate, setRequestedDueDate] = useState
();
const [reason, setReason] = useState('');
- const assignmentId = ticket.worker?.assignment_id;
const requestExtensionMutation = useRequestTicketExtensionMutation(
ticket.id,
assignmentId,
@@ -48,10 +52,7 @@ export function RequestExtensionForm({ ticket }: RequestExtensionFormProps) {
(!currentDueDate || requestedDueDate.getTime() > currentDueDate.getTime()),
);
const canSubmit =
- Boolean(assignmentId) &&
- isRequestedDateValid &&
- Boolean(reason.trim()) &&
- !isPending;
+ isRequestedDateValid && Boolean(reason.trim()) && !isPending;
const handleSubmit = async () => {
if (!requestedDueDate || !canSubmit) return;
diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/ReviewExtensionRequestAction.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/ReviewExtensionRequestAction.tsx
index fa18c36..9da0b5b 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/actions/ReviewExtensionRequestAction.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/actions/ReviewExtensionRequestAction.tsx
@@ -77,16 +77,17 @@ function Requester({ request }: { request: TicketExtensionRequest }) {
function ExtensionReviewForm({
ticket,
+ assignmentId,
request,
}: {
ticket: TicketDetail;
+ assignmentId: number;
request: TicketExtensionRequest;
}) {
const [note, setNote] = useState('');
const [selectedAction, setSelectedAction] = useState<
'approve' | 'reject' | null
>(null);
- const assignmentId = ticket.worker?.assignment_id as number;
const reviewMutation = useReviewTicketExtensionMutation(
ticket.id,
assignmentId,
@@ -197,16 +198,17 @@ function ExtensionReviewForm({
export function ReviewExtensionRequestAction({
ticket,
+ assignmentId,
}: {
ticket: TicketDetail;
+ assignmentId: number;
}) {
- const assignmentId = ticket.worker?.assignment_id;
const extensionRequestQuery = useTicketExtensionRequestQuery(
ticket.id,
assignmentId,
);
- if (!assignmentId || extensionRequestQuery.isError) {
+ if (extensionRequestQuery.isError) {
return null;
}
@@ -227,5 +229,11 @@ export function ReviewExtensionRequestAction({
if (!pendingRequest) return null;
- return ;
+ return (
+
+ );
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/TicketExtensionRequestPanel.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/TicketExtensionRequestPanel.tsx
index 6c3d392..9e48ef2 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/actions/TicketExtensionRequestPanel.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/actions/TicketExtensionRequestPanel.tsx
@@ -187,23 +187,18 @@ function ExtensionRequestDetails({
export function TicketExtensionRequestPanel({
ticket,
+ assignmentId,
+ dueAt,
}: {
ticket: TicketDetail;
+ assignmentId: number;
+ dueAt: string | null;
}) {
- const assignmentId = ticket.worker?.assignment_id;
const extensionRequestQuery = useTicketExtensionRequestQuery(
ticket.id,
assignmentId,
);
- if (!assignmentId) {
- return (
-
- No active assignment is available for this ticket.
-
- );
- }
-
if (extensionRequestQuery.isLoading) {
return (
@@ -237,7 +232,13 @@ export function TicketExtensionRequestPanel({
: null;
if (!latestRequest) {
- return
;
+ return (
+
+ );
}
return
;
diff --git a/src/app/(modules)/ticket/[ticketId]/page.tsx b/src/app/(modules)/ticket/[ticketId]/page.tsx
index 6f39459..bec3a99 100644
--- a/src/app/(modules)/ticket/[ticketId]/page.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/page.tsx
@@ -23,6 +23,7 @@ import { TicketStatusActions } from './components/TicketStatusActions';
import { TicketDefectClassTabs } from './components/TicketDefectClassTabs';
import { useTicketDetailEvents } from '../hooks/useTicketDetailEvents';
import {
+ useTicketAssignmentsQuery,
useTicketClassDetailQuery,
useTicketOverviewQuery,
} from '../hooks/useTicketQueries';
@@ -35,11 +36,18 @@ export default function TicketDetailPage() {
const [selectedAssignmentId, setSelectedAssignmentId] = useState
();
const overviewQuery = useTicketOverviewQuery(ticketId);
- const classDetailQuery = useTicketClassDetailQuery(ticketId, defectClass);
const overview = overviewQuery.data;
+ const assignmentsQuery = useTicketAssignmentsQuery(
+ ticketId,
+ overview?.assignments,
+ );
+ const classDetailQuery = useTicketClassDetailQuery(ticketId, defectClass);
const classDetail = classDetailQuery.data;
- const activeAssignmentId =
- selectedAssignmentId ?? overview?.assignments?.[0]?.id;
+ const assignments = assignmentsQuery.data?.items ?? [];
+ const activeAssignmentId = selectedAssignmentId ?? assignments[0]?.id;
+ const activeAssignment = assignments.find(
+ (assignment) => assignment.id === activeAssignmentId,
+ );
const isClassDetailLoading = Boolean(
defectClass && classDetailQuery.isLoading,
);
@@ -66,7 +74,7 @@ export default function TicketDetailPage() {
{overview ? (
-
+
) : (
)}
@@ -101,7 +109,10 @@ export default function TicketDetailPage() {
{isClassDetailLoading ? : null}
{!isClassDetailLoading && classDetail ? (
-
+
) : null}
diff --git a/src/app/(modules)/ticket/hooks/useTicketQueries.ts b/src/app/(modules)/ticket/hooks/useTicketQueries.ts
index f9c8e16..0cb5ee4 100644
--- a/src/app/(modules)/ticket/hooks/useTicketQueries.ts
+++ b/src/app/(modules)/ticket/hooks/useTicketQueries.ts
@@ -405,6 +405,9 @@ export function useRequestTicketExtensionMutation(
queryClient.invalidateQueries({
queryKey: ticketKeys.classDetail(ticketId, defectClass),
});
+ queryClient.invalidateQueries({
+ queryKey: ticketKeys.assignments(ticketId),
+ });
queryClient.invalidateQueries({ queryKey: ticketKeys.lists() });
},
onError: () => toast.error('Failed to request an extension'),
@@ -432,6 +435,9 @@ export function useReviewTicketExtensionMutation(
queryClient.invalidateQueries({
queryKey: ticketKeys.classDetail(ticketId, defectClass),
});
+ queryClient.invalidateQueries({
+ queryKey: ticketKeys.assignments(ticketId),
+ });
queryClient.invalidateQueries({ queryKey: ticketKeys.lists() });
},
onError: () => toast.error('Failed to review extension request'),