diff --git a/src/app/tenders/[details]/page.tsx b/src/app/tenders/[details]/page.tsx
index 20febc8..91171b2 100644
--- a/src/app/tenders/[details]/page.tsx
+++ b/src/app/tenders/[details]/page.tsx
@@ -6,7 +6,8 @@ import Loading from "@/components/loading";
import Status from "@/components/ui/Status";
import { useTenderDetailQuery } from "@/hooks/queries";
import { useGetFlagQuery } from "@/hooks/queries/useFlagsQueries";
-import { isValidAlpha2CountryCode, msToDate } from "@/utils/shared";
+import { cn } from "@/lib/utils";
+import { isValidAlpha2CountryCode, msToDate, truncateString } from "@/utils/shared";
import getSymbolFromCurrency from "currency-symbol-map";
import Link from "next/link";
import { use } from "react";
@@ -17,6 +18,43 @@ interface IProps {
}>;
}
+function SectionHeading({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
+
+function ExternalLinkIcon({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+/** Grid row stretch: center value vertically under the title */
+const TIMELINE_SHOWCASE = {
+ rootClassName: "flex h-full min-h-0 flex-col",
+ className: "flex min-h-0 flex-1 flex-col justify-center",
+} as const;
+
const TenderDetails = ({ params }: IProps) => {
const { details } = use(params);
const { data, isLoading, isError } = useTenderDetailQuery(details);
@@ -31,86 +69,187 @@ const TenderDetails = ({ params }: IProps) => {
{ name: "Tenders", href: "/tenders" },
{ name: "Tender details", href: `/tenders/${details}` },
];
+
if (isLoading) return ;
- if (isError) return Error
;
+ if (isError) {
+ return (
+ <>
+
+
+
+
+ We couldn't load this tender
+
+
+ Check your connection or try again. You can go back to the tender list anytime.
+
+
+ Back to tenders
+
+
+
+ >
+ );
+ }
+
+ const tender = data!.data;
+ const submissionUrl = tender.submission_url?.trim();
+
return (
<>
-
-
-
{data?.data.title}
-
- {data?.data.status}
-
-
-
-
- {data?.data.tender_id}
-
-
- {data?.data.buyer_organization.name}
-
-
- {data?.data.notice_publication_id}
-
-
- {data?.data.procedure_code}
-
-
- {data?.data.procurement_type_code}
-
-
-
-
- {msToDate(data?.data.application_deadline ?? 0)}
-
- {data?.data.submission_url && (
-
-
- {data?.data.submission_url}
-
-
- )}
-
-
- {msToDate(data?.data.publication_date ?? 0)}
-
-
- {msToDate(data?.data.submission_deadline ?? 0)}
-
-
- {msToDate(data?.data.tender_deadline ?? 0)}
-
-
-
-
-
Country
-
-
-
{data?.data.country_code}
- {flagData && (
-
+
+
+
+ Tender
+
+
+ {tender.title}
+
+
+
+ {tender.status}
+ {submissionUrl && (
+
+ Open submission
+
+
)}
- {data?.data.currency && (
-
-
Currency
-
-
{data?.data.currency}
-
{getSymbolFromCurrency(data?.data.currency ?? "USD")}
-
+ }
+ className="!p-0"
+ >
+
+
+
Procurement
+
+
+ {tender.tender_id}
+
+
+
+ {tender.buyer_organization.name}
+
+
+
+
+ {tender.notice_publication_id}
+
+
+
+ {tender.procedure_code}
+
+
+
+ {tender.procurement_type_code}
+
+
- )}
+
-
-
-
-
Description
-
{data?.data.description}
+
+
Timeline
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {submissionUrl && (
+
+
+
+ {truncateString(submissionUrl, 42)}
+
+
+ )}
+
+
+
+
+
Location & currency
+
+
+
+
+ Country
+
+
+
+
+
+
+
+ {tender.country_code}
+
+ {flagData && (
+
+ )}
+
+
+
+
+ {tender.currency && (
+
+
+
+ Currency
+
+
+
+ {tender.currency}
+
+
+ {getSymbolFromCurrency(tender.currency ?? "USD")}
+
+
+
+ )}
+
+
+
+
+
Description
+
+
+ {tender.description || "—"}
+
+
+
>
diff --git a/src/components/Layouts/showcase-section.tsx b/src/components/Layouts/showcase-section.tsx
index afc9e3c..994a016 100644
--- a/src/components/Layouts/showcase-section.tsx
+++ b/src/components/Layouts/showcase-section.tsx
@@ -4,16 +4,24 @@ import type { ReactNode } from "react";
type PropsType = {
title?: string | ReactNode;
children: ReactNode;
+ /** Merges into the padded content wrapper below the title */
className?: string;
+ /** Merges into the outer card (e.g. `h-full flex flex-col` for grid rows) */
+ rootClassName?: string;
};
-export function ShowcaseSection({ title, children, className }: PropsType) {
+export function ShowcaseSection({ title, children, className, rootClassName }: PropsType) {
return (
-
+
{title && (
-
+
{title}
)}
diff --git a/src/components/Tables/tenders/index.tsx b/src/components/Tables/tenders/index.tsx
index a751708..23bf297 100644
--- a/src/components/Tables/tenders/index.tsx
+++ b/src/components/Tables/tenders/index.tsx
@@ -24,7 +24,6 @@ import TableSkeleton from "@/components/ui/TableSkeleton";
import { _TooltipDefaultParams } from "@/constants/tooltip";
import { cn } from "@/lib/utils";
import { getPaginatedRowNumber } from "@/utils/shared";
-import Link from "next/link";
import TenderListFilters from "./TenderListFilters";
const TendersTable = () => {
const {
@@ -89,49 +88,39 @@ const TendersTable = () => {
{item.country_code}
-
- {item.submission_url ? (
-
- {item.submission_url}
-
- ) : (
- "-"
- )}
-
{item.status}
-
-
-
+
+
+
+
+
))}
diff --git a/src/components/Tables/tenders/useTenderListPresenter.ts b/src/components/Tables/tenders/useTenderListPresenter.ts
index 29a7b03..b12f67b 100644
--- a/src/components/Tables/tenders/useTenderListPresenter.ts
+++ b/src/components/Tables/tenders/useTenderListPresenter.ts
@@ -57,7 +57,6 @@ const useTenderListPresenter = () => {
"row",
"title",
"country code",
- "submission url",
"status",
"actions",
];