chore: update app version and enhance UI components
- Bumped NEXT_PUBLIC_APP_VERSION to 2.0.3 for the latest release. - Improved Cypress test for customer feedback page to handle delayed route transitions. - Refactored CompanyDetailsPage to enhance layout and added new components for better structure. - Updated TenderDetails to conditionally render location and currency information based on validity checks. - Added data-cy attributes to various form elements and tables for improved testing capabilities.
This commit is contained in:
@@ -22,6 +22,8 @@ interface IProps {
|
||||
}>;
|
||||
}
|
||||
|
||||
const isValidDisplayCountryCode = (code: string) => /^[A-Za-z]{2,3}$/.test(code);
|
||||
|
||||
function SectionHeading({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="mb-4 flex items-center gap-3">
|
||||
@@ -65,9 +67,11 @@ const TenderDetails = ({ params }: IProps) => {
|
||||
const { data, isLoading, isError } = useTenderDetailQuery(details);
|
||||
const countryCodeNormalized =
|
||||
data?.data.country_code?.trim().toUpperCase() ?? "";
|
||||
const countryCodeValid = isValidAlpha2CountryCode(countryCodeNormalized);
|
||||
const hasValidCountryCodeForDisplay =
|
||||
isValidDisplayCountryCode(countryCodeNormalized);
|
||||
const canLoadCountryFlag = isValidAlpha2CountryCode(countryCodeNormalized);
|
||||
const { data: flagData } = useGetFlagQuery(countryCodeNormalized, {
|
||||
enabled: countryCodeValid,
|
||||
enabled: canLoadCountryFlag,
|
||||
});
|
||||
const breadcrumbItems = [
|
||||
{ name: "Dashboard", href: "/" },
|
||||
@@ -103,6 +107,14 @@ const TenderDetails = ({ params }: IProps) => {
|
||||
|
||||
const tender = data!.data;
|
||||
const submissionUrl = tender.submission_url?.trim();
|
||||
const currencyCode = tender.currency?.trim().toUpperCase() ?? "";
|
||||
const hasValidCurrency = Boolean(currencyCode);
|
||||
const hasValidEstimatedValue =
|
||||
typeof tender.estimated_value === "number" &&
|
||||
Number.isFinite(tender.estimated_value) &&
|
||||
tender.estimated_value > 0;
|
||||
const hasValidLocationCurrencyOrValue =
|
||||
hasValidCountryCodeForDisplay || hasValidCurrency || hasValidEstimatedValue;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -252,50 +264,73 @@ const TenderDetails = ({ params }: IProps) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<SectionHeading>Location & currency</SectionHeading>
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:max-w-3xl">
|
||||
<div className="shadow-theme-xs relative overflow-hidden rounded-2xl border border-stroke/70 bg-gradient-to-br from-white via-gray-2/30 to-primary/[0.06] p-5 dark:border-dark-3 dark:from-gray-dark dark:via-gray-dark dark:to-primary/[0.12]">
|
||||
<div className="pointer-events-none absolute -right-8 top-0 h-24 w-24 rounded-full bg-primary/15 blur-2xl dark:bg-primary/25" />
|
||||
<h3 className="mb-4 text-xs font-semibold uppercase tracking-wide text-dark-5 dark:text-dark-6">
|
||||
Country
|
||||
</h3>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex h-11 w-11 items-center justify-center rounded-xl bg-white/80 text-primary shadow-inner dark:bg-dark-2/80">
|
||||
<LocationIcon />
|
||||
</span>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="text-sm font-semibold uppercase tracking-wide text-dark dark:text-white">
|
||||
{tender.country_code}
|
||||
</span>
|
||||
{flagData && (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: flagData }}
|
||||
className="flex h-8 w-11 items-center justify-center overflow-hidden rounded-lg border border-stroke/60 shadow-sm dark:border-dark-3"
|
||||
/>
|
||||
)}
|
||||
{hasValidLocationCurrencyOrValue && (
|
||||
<div>
|
||||
<SectionHeading>Location & currency</SectionHeading>
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 lg:max-w-5xl">
|
||||
{hasValidCountryCodeForDisplay && (
|
||||
<div className="shadow-theme-xs relative overflow-hidden rounded-2xl border border-stroke/70 bg-gradient-to-br from-white via-gray-2/30 to-primary/[0.06] p-5 dark:border-dark-3 dark:from-gray-dark dark:via-gray-dark dark:to-primary/[0.12]">
|
||||
<div className="pointer-events-none absolute -right-8 top-0 h-24 w-24 rounded-full bg-primary/15 blur-2xl dark:bg-primary/25" />
|
||||
<h3 className="mb-4 text-xs font-semibold uppercase tracking-wide text-dark-5 dark:text-dark-6">
|
||||
Country
|
||||
</h3>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex h-11 w-11 items-center justify-center rounded-xl bg-white/80 text-primary shadow-inner dark:bg-dark-2/80">
|
||||
<LocationIcon />
|
||||
</span>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="text-sm font-semibold uppercase tracking-wide text-dark dark:text-white">
|
||||
{countryCodeNormalized}
|
||||
</span>
|
||||
{flagData && (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: flagData }}
|
||||
className="flex h-8 w-11 items-center justify-center overflow-hidden rounded-lg border border-stroke/60 shadow-sm dark:border-dark-3"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tender.currency && (
|
||||
<div className="shadow-theme-xs relative overflow-hidden rounded-2xl border border-stroke/70 bg-gradient-to-br from-white via-gray-2/30 to-purple-500/[0.06] p-5 dark:border-dark-3 dark:from-gray-dark dark:via-gray-dark dark:to-purple-500/[0.12]">
|
||||
<div className="pointer-events-none absolute -left-6 bottom-0 h-20 w-20 rounded-full bg-purple-500/15 blur-2xl dark:bg-purple-500/25" />
|
||||
<h3 className="mb-4 text-xs font-semibold uppercase tracking-wide text-dark-5 dark:text-dark-6">
|
||||
Currency
|
||||
</h3>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-2xl font-bold tabular-nums text-dark dark:text-white">
|
||||
{tender.currency}
|
||||
</span>
|
||||
<span className="text-lg font-medium text-dark-5 dark:text-dark-6">
|
||||
{getSymbolFromCurrency(tender.currency ?? "USD")}
|
||||
</span>
|
||||
{hasValidCurrency && (
|
||||
<div className="shadow-theme-xs relative overflow-hidden rounded-2xl border border-stroke/70 bg-gradient-to-br from-white via-gray-2/30 to-blue/[0.06] p-5 dark:border-dark-3 dark:from-gray-dark dark:via-gray-dark dark:to-blue/[0.12]">
|
||||
<div className="pointer-events-none absolute -left-6 bottom-0 h-20 w-20 rounded-full bg-blue/15 blur-2xl dark:bg-blue/25" />
|
||||
<h3 className="mb-4 text-xs font-semibold uppercase tracking-wide text-dark-5 dark:text-dark-6">
|
||||
Currency
|
||||
</h3>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-2xl font-bold tabular-nums text-dark dark:text-white">
|
||||
{currencyCode}
|
||||
</span>
|
||||
<span className="text-lg font-medium text-dark-5 dark:text-dark-6">
|
||||
{getSymbolFromCurrency(currencyCode || "USD")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
|
||||
{hasValidEstimatedValue && (
|
||||
<div className="shadow-theme-xs relative overflow-hidden rounded-2xl border border-stroke/70 bg-gradient-to-br from-white via-gray-2/30 to-green/[0.06] p-5 dark:border-dark-3 dark:from-gray-dark dark:via-gray-dark dark:to-green/[0.12]">
|
||||
<div className="pointer-events-none absolute -right-6 bottom-0 h-20 w-20 rounded-full bg-green/15 blur-2xl dark:bg-green/25" />
|
||||
<h3 className="mb-4 text-xs font-semibold uppercase tracking-wide text-dark-5 dark:text-dark-6">
|
||||
Estimated value
|
||||
</h3>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-2xl font-bold tabular-nums text-dark dark:text-white">
|
||||
{new Intl.NumberFormat().format(tender.estimated_value)}
|
||||
</span>
|
||||
{hasValidCurrency && (
|
||||
<span className="text-sm font-medium uppercase text-dark-5 dark:text-dark-6">
|
||||
{currencyCode}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<SectionHeading>Description</SectionHeading>
|
||||
|
||||
Reference in New Issue
Block a user