-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Issue #2036] Opportunity Page Design Implementation (navapbc#196)
Fixes #2036 > What was added, updated, or removed in this PR. > Testing instructions, background context, more in-depth details of the implementation, and anything else you'd like to call out or ask reviewers. Explain how the changes were verified. > Screenshots, GIF demos, code examples or output to help show the changes working as expected. --------- Co-authored-by: Aaron Couch <[email protected]> Co-authored-by: Aaron Couch <[email protected]>
- Loading branch information
1 parent
ff5a432
commit 444fa7a
Showing
30 changed files
with
10,945 additions
and
16,826 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
frontend/src/components/opportunity/OpportunityAwardGridRow.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useTranslations } from "next-intl"; | ||
type Props = { | ||
title: string | number; | ||
content: string | number; | ||
}; | ||
|
||
type TranslationKeys = | ||
| "program_funding" | ||
| "expected_awards" | ||
| "award_ceiling" | ||
| "award_floor"; | ||
|
||
const OpportunityAwardGridRow = ({ title, content }: Props) => { | ||
const t = useTranslations("OpportunityListing.award_info"); | ||
|
||
return ( | ||
<div className="border radius-md border-base-lighter padding-x-2 "> | ||
<p className="font-sans-sm text-bold margin-bottom-0">{content}</p> | ||
<p className="desktop-lg:font-sans-sm margin-top-0"> | ||
{t(`${title as TranslationKeys}`)} | ||
</p> | ||
</div> | ||
); | ||
}; | ||
|
||
export default OpportunityAwardGridRow; |
105 changes: 105 additions & 0 deletions
105
frontend/src/components/opportunity/OpportunityAwardInfo.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { Grid } from "@trussworks/react-uswds"; | ||
import { Opportunity } from "src/types/opportunity/opportunityResponseTypes"; | ||
import OpportunityAwardGridRow from "./OpportunityAwardGridRow"; | ||
import { useTranslations } from "next-intl"; | ||
|
||
type Props = { | ||
opportunityData: Opportunity; | ||
}; | ||
|
||
type TranslationKeys = | ||
| "cost_sharing" | ||
| "funding_instrument" | ||
| "opportunity_category" | ||
| "opportunity_category_explanation" | ||
| "funding_activity" | ||
| "category_explanation"; | ||
|
||
const OpportunityAwardInfo = ({ opportunityData }: Props) => { | ||
const t = useTranslations("OpportunityListing.award_info"); | ||
|
||
const formatCurrency = (number: number) => { | ||
return new Intl.NumberFormat("en-US", { | ||
style: "currency", | ||
currency: "USD", | ||
minimumFractionDigits: 0, | ||
}).format(number); | ||
}; | ||
|
||
const formatSubContent = (content: boolean | string | null | string[]) => { | ||
function formatStringReturnValue(str: string): string { | ||
const formattedStr = str.replace(/_/g, " "); | ||
return formattedStr.charAt(0).toUpperCase() + formattedStr.slice(1); | ||
} | ||
switch (typeof content) { | ||
case "boolean": | ||
return content ? t("yes") : t("no"); | ||
case "string": | ||
return ( | ||
<p className="line-height-sans-1"> | ||
{formatStringReturnValue(content)} | ||
</p> | ||
); | ||
case "object": | ||
if (Array.isArray(content)) { | ||
return content.length | ||
? content.map((content, index) => ( | ||
<p className="line-height-sans-1" key={`contentList-${index}`}> | ||
{formatStringReturnValue(content)} | ||
</p> | ||
)) | ||
: "--"; | ||
} | ||
return "--"; | ||
default: | ||
return "--"; | ||
} | ||
}; | ||
|
||
const awardGridInfo = { | ||
program_funding: formatCurrency( | ||
opportunityData.summary.estimated_total_program_funding, | ||
), | ||
expected_awards: opportunityData.summary.expected_number_of_awards, | ||
award_ceiling: formatCurrency(opportunityData.summary.award_ceiling), | ||
award_floor: formatCurrency(opportunityData.summary.award_floor), | ||
}; | ||
|
||
const awardSubInfo = { | ||
cost_sharing: opportunityData.summary.is_cost_sharing, | ||
funding_instrument: opportunityData.summary.funding_instruments, | ||
opportunity_category: opportunityData.category, | ||
opportunity_category_explanation: opportunityData.category_explanation, | ||
funding_activity: opportunityData.summary.funding_categories, | ||
category_explanation: opportunityData.summary.funding_category_description, | ||
}; | ||
|
||
return ( | ||
<div className="usa-prose margin-top-2"> | ||
<h2>Award</h2> | ||
<Grid row className="margin-top-2 grid-gap-2"> | ||
{Object.entries(awardGridInfo).map(([title, content], index) => ( | ||
<Grid | ||
className="margin-bottom-2" | ||
key={`category ${index}`} | ||
tabletLg={{ col: 6 }} | ||
> | ||
<OpportunityAwardGridRow content={content} title={title} /> | ||
</Grid> | ||
))} | ||
</Grid> | ||
|
||
{Object.entries(awardSubInfo).map(([title, content], index) => ( | ||
<div key={`awardInfo-${index}`}> | ||
<p className={"text-bold"}> | ||
{t(`${title as TranslationKeys}`)} | ||
{":"} | ||
</p> | ||
<div className={"margin-top-0"}>{formatSubContent(content)}</div> | ||
</div> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
export default OpportunityAwardInfo; |
Oops, something went wrong.