From 4607de567779b5659da1d4095b216e9580d9f79b Mon Sep 17 00:00:00 2001 From: AmirReza Jamali Date: Sat, 23 May 2026 09:12:52 +0330 Subject: [PATCH] feat(tender-details): normalize tender documents extraction logic - Added a new function to handle varying document payload structures from the backend, ensuring consistent extraction of tender documents. - Updated the TenderDetails component to utilize the new extraction logic, improving reliability in document handling. - Refactored related imports and removed unused code for better clarity and maintainability. --- .../components/tender-details-content.tsx | 4 +- src/app/tenders/[details]/page.tsx | 43 +++++++++++++++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/app/tenders/[details]/components/tender-details-content.tsx b/src/app/tenders/[details]/components/tender-details-content.tsx index 40db137..2134b1b 100644 --- a/src/app/tenders/[details]/components/tender-details-content.tsx +++ b/src/app/tenders/[details]/components/tender-details-content.tsx @@ -2,10 +2,10 @@ import type { TTenderDetails, TTenderDocumentsResponse, } from "@/lib/api/types/Tenders"; -import { shouldShowLocationSection } from "../tender-nav-utils"; -import type { TenderNavItem } from "../types"; import { scrollToTenderSection } from "../scroll-to-section"; import { shouldShowLotsSection } from "../tender-display-utils"; +import { shouldShowLocationSection } from "../tender-nav-utils"; +import type { TenderNavItem } from "../types"; import { TenderAiSummarySection } from "./tender-ai-summary-section"; import { TenderDescriptionSection } from "./tender-description-section"; import { TenderDocumentsSection } from "./tender-documents-section"; diff --git a/src/app/tenders/[details]/page.tsx b/src/app/tenders/[details]/page.tsx index 7af2307..518f514 100644 --- a/src/app/tenders/[details]/page.tsx +++ b/src/app/tenders/[details]/page.tsx @@ -8,7 +8,10 @@ import { useTenderDetailQuery, useTranslateTenderMutation, } from "@/hooks/queries"; -import type { TTenderDetails } from "@/lib/api/types/Tenders"; +import type { + TTenderDetails, + TTenderDocumentsResponse, +} from "@/lib/api/types/Tenders"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { use, useCallback, useEffect, useMemo, useRef } from "react"; import { TenderDetailsContent } from "./components/tender-details-content"; @@ -16,7 +19,6 @@ import { TenderDetailsError } from "./components/tender-details-error"; import { TenderDetailsHeader } from "./components/tender-details-header"; import { useTenderSectionScrollSpy } from "./hooks/use-tender-section-scroll-spy"; import { getTenderNavItems } from "./tender-nav-utils"; -import { shouldShowAiSummarySection } from "./tender-display-utils"; interface IProps { params: Promise<{ @@ -24,6 +26,33 @@ interface IProps { }>; } +// Backend has shipped the documents payload as a bare array, an `ApiResponse` +// wrapper, and a `{ data: { documents: [...] } }` wrapper at different times. +// Normalize so a real list is never dropped because of a wrapper mismatch. +function extractTenderDocuments( + payload: unknown, +): TTenderDocumentsResponse[] { + if (!payload) return []; + if (Array.isArray(payload)) return payload as TTenderDocumentsResponse[]; + + const wrapper = payload as { + data?: unknown; + documents?: unknown; + }; + + if (Array.isArray(wrapper.documents)) { + return wrapper.documents as TTenderDocumentsResponse[]; + } + if (Array.isArray(wrapper.data)) { + return wrapper.data as TTenderDocumentsResponse[]; + } + if (wrapper.data && typeof wrapper.data === "object") { + const inner = (wrapper.data as { documents?: unknown }).documents; + if (Array.isArray(inner)) return inner as TTenderDocumentsResponse[]; + } + return []; +} + const TenderDetails = ({ params }: IProps) => { const { details } = use(params); const router = useRouter(); @@ -44,14 +73,12 @@ const TenderDetails = ({ params }: IProps) => { ]; const tenderForNav = data?.data; - const hasValidAiSummary = tenderForNav - ? shouldShowAiSummarySection(tenderForNav) - : false; const { data: documentsResponse, isPending: isDocumentsLoading } = - useGetTenderDocumentsQuery(details, { enabled: hasValidAiSummary }); - const documents = documentsResponse?.data ?? []; + useGetTenderDocumentsQuery(details, { enabled: Boolean(tenderForNav) }); + const documents = extractTenderDocuments(documentsResponse); + const showDocumentsSection = - hasValidAiSummary && (isDocumentsLoading || documents.length > 0); + Boolean(tenderForNav) && !isDocumentsLoading && documents.length > 0; const tenderNavItems = useMemo( () =>