Skip to content

Commit

Permalink
refactor: currency component and intro modal organization
Browse files Browse the repository at this point in the history
  • Loading branch information
atrincas committed Jan 9, 2025
1 parent b6707c6 commit 4b3fb93
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 104 deletions.
2 changes: 1 addition & 1 deletion client/src/components/ui/currency.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const Currency: FC<CurrencyProps> = ({
"inline-block": true,
"first-letter:align-top first-letter:text-xs first-letter:tracking-[0.1rem] first-letter:text-muted-foreground":
!plainSymbol,
"first-letter:pr-1": plainSymbol,
"first-letter:pr-0.5": plainSymbol,
},
className,
)}
Expand Down
40 changes: 20 additions & 20 deletions client/src/components/ui/graph.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC } from "react";

import { renderCurrency } from "@/lib/format";
import Currency from "@/components/ui/currency";

interface GraphProps {
/** The total value that represents 100% of the graph */
Expand Down Expand Up @@ -43,14 +43,14 @@ const Graph: FC<GraphProps> = ({ total, leftover, segments }) => {
>
<div className="absolute bottom-1 left-0 right-0 mx-1">
<div className="rounded-md bg-white/30 px-1.5 py-0.5 text-center text-xs font-semibold text-secondary-foreground">
{renderCurrency(
total,
{
<Currency
value={total}
options={{
notation: "compact",
maximumFractionDigits: 1,
},
"first-letter:text-secondary-foreground",
)}
}}
plainSymbol
/>
</div>
</div>
</div>
Expand All @@ -66,14 +66,14 @@ const Graph: FC<GraphProps> = ({ total, leftover, segments }) => {
>
<div className="absolute bottom-1 left-0 right-0 mx-1">
<div className="rounded-md bg-white/30 px-1.5 py-0.5 text-center text-xs font-semibold text-secondary-foreground">
{renderCurrency(
value,
{
<Currency
value={value}
options={{
notation: "compact",
maximumFractionDigits: 1,
},
"first-letter:text-secondary-foreground",
)}
}}
plainSymbol
/>
</div>
</div>
</div>
Expand Down Expand Up @@ -104,14 +104,14 @@ const Graph: FC<GraphProps> = ({ total, leftover, segments }) => {
>
<div className="absolute bottom-1 left-0 right-0 mx-1">
<div className="rounded-sm bg-white/50 px-1.5 py-0.5 text-center text-xs font-semibold text-big-stone-950">
{renderCurrency(
value,
{
<Currency
value={value}
options={{
notation: "compact",
maximumFractionDigits: 1,
},
"first-letter:text-secondary-foreground",
)}
}}
plainSymbol
/>
</div>
</div>
</div>
Expand Down Expand Up @@ -173,7 +173,7 @@ const GraphWithLegend: FC<GraphWithLegendProps> = ({
<div className="flex max-w-[148px] flex-1 flex-col justify-between">
<div>
<span className="text-xl font-normal">
{renderCurrency(leftover || total)}
<Currency value={leftover || total} />
</span>
</div>
<GraphLegend
Expand Down
41 changes: 6 additions & 35 deletions client/src/containers/intro-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@
import { useCallback, useState } from "react";

import {
ClipboardPenIcon,
FileQuestionIcon,
LayoutDashboardIcon,
UserIcon,
} from "lucide-react";

import { introModalManager } from "@/lib/utils";
introItems,
setHideIntroModal,
showIntroModal,
} from "@/containers/intro-modal/utils";

import { Button } from "@/components/ui/button";
import { CheckboxWrapper } from "@/components/ui/checkbox";
Expand All @@ -21,41 +18,15 @@ import {
DialogTitle,
} from "@/components/ui/dialog";

const introItems = [
{
title: "Project Overview",
description:
"Explore and compare over 400 project scenarios with ease. Apply filters for location, ecosystem type, activity, cost, abatement potential and project size. The global map visualizes project blue carbon potential across 9 countries, enabling comparisons based on cost-to-abatement ratios. Additionally, use the comparison table for detailed cost and score analyses, and select a project for additional details.",
icon: LayoutDashboardIcon,
},
{
title: "Create custom projects",
description:
"Design custom scenarios by modifying default parameters and exploring the resulting data in detail. Save your projects to revisit them anytime and quickly compare all the scenarios you’ve created.",
icon: ClipboardPenIcon,
},
{
title: "Methodology",
description:
"Explore for detailed information on model assumptions, estimations, and data sources.",
icon: FileQuestionIcon,
},
{
title: "Profile",
description: "Access information about your personal account.",
icon: UserIcon,
},
];

const IntroModal = () => {
const [isOpen, setIsOpen] = useState(introModalManager.showIntroModal());
const [isOpen, setIsOpen] = useState(showIntroModal());
const [dontShowAgain, setDontShowAgain] = useState(false);
const handleClose = useCallback(
(open = false) => {
setIsOpen(open);

if (dontShowAgain) {
introModalManager.setHideIntroModal();
setHideIntroModal();
}
},
[dontShowAgain],
Expand Down
48 changes: 48 additions & 0 deletions client/src/containers/intro-modal/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
ClipboardPenIcon,
FileQuestionIcon,
LayoutDashboardIcon,
UserIcon,
} from "lucide-react";

const isServer = typeof window === "undefined";

export const introItems = [
{
title: "Project Overview",
description:
"Explore and compare over 400 project scenarios with ease. Apply filters for location, ecosystem type, activity, cost, abatement potential and project size. The global map visualizes project blue carbon potential across 9 countries, enabling comparisons based on cost-to-abatement ratios. Additionally, use the comparison table for detailed cost and score analyses, and select a project for additional details.",
icon: LayoutDashboardIcon,
},
{
title: "Create custom projects",
description:
"Design custom scenarios by modifying default parameters and exploring the resulting data in detail. Save your projects to revisit them anytime and quickly compare all the scenarios you’ve created.",
icon: ClipboardPenIcon,
},
{
title: "Methodology",
description:
"Explore for detailed information on model assumptions, estimations, and data sources.",
icon: FileQuestionIcon,
},
{
title: "Profile",
description: "Access information about your personal account.",
icon: UserIcon,
},
];

export const showIntroModal = (): boolean => {
if (isServer) return false;

return (
!!process.env.HIDE_INTRO_MODAL || !localStorage.getItem("hideIntroModal")
);
};

export const setHideIntroModal = (): void => {
if (isServer) return;

localStorage.setItem("hideIntroModal", "true");
};
11 changes: 7 additions & 4 deletions client/src/containers/overview/map/popup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useAtomValue } from "jotai";

import { renderCurrency } from "@/lib/format";
import { formatNumber } from "@/lib/format";
import { cn } from "@/lib/utils";

import { popupAtom } from "@/app/(overview)/store";

import MapPopup from "@/components/map/popup";
import Currency from "@/components/ui/currency";

const HEADER_CLASSES = "py-0.5 text-left font-normal text-muted-foreground";
const CELL_CLASSES = "py-0.5 font-semibold";
Expand All @@ -30,16 +31,18 @@ export default function CostAbatementPopup() {
<tbody>
<tr>
<td className={cn(CELL_CLASSES, "pr-2")}>
{renderCurrency(popup?.features?.[0]?.properties?.cost)}
<Currency value={popup?.features?.[0]?.properties?.cost} />
</td>
<td className={cn(CELL_CLASSES, "px-2")}>
{popup?.features?.[0]?.properties?.abatementPotential}
{formatNumber(
popup?.features?.[0]?.properties?.abatementPotential,
)}
</td>
</tr>
</tbody>
</table>
<p className="mt-2 text-xs text-muted-foreground">
Values for the SUM of all projects.
Values for the SUM of all project combinations.
</p>
</MapPopup>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const columns = (filters: z.infer<typeof filtersSchema>) => [
filters.costRangeSelector === "npv" ? "costPerTCO2eNPV" : "costPerTCO2e",
{
enableSorting: true,
header: () => <HeaderText>Cost $(USD)/tCo2</HeaderText>,
header: () => <HeaderText>Cost $(USD)/tCO2e</HeaderText>,
cell: (props) => {
const value = props.getValue();
if (value === null || value === undefined) {
Expand Down
19 changes: 0 additions & 19 deletions client/src/lib/format.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { cn } from "@/lib/utils";

export const formatCurrency = (
value: number,
options: Intl.NumberFormatOptions = {},
Expand All @@ -23,23 +21,6 @@ export const formatNumber = (
}).format(value);
};

export function renderCurrency(
value: number,
options: Intl.NumberFormatOptions = {},
className?: HTMLSpanElement["className"],
) {
return (
<span
className={cn(
"inline-block first-letter:align-top first-letter:text-xs first-letter:tracking-[0.1rem] first-letter:text-muted-foreground",
className,
)}
>
{formatCurrency(value, options)}
</span>
);
}

/**
* Converts a large numeric value into a compact format with an "M" suffix
* representing millions.
Expand Down
24 changes: 0 additions & 24 deletions client/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,6 @@ export const parseTableData = <
value: formatCurrency(data[key as K], { maximumFractionDigits: 0 }),
}));
};
class IntroModalManager {
private static instance: IntroModalManager;
private isServer: boolean = typeof window === "undefined";

public static getInstance(): IntroModalManager {
if (!IntroModalManager.instance) {
IntroModalManager.instance = new IntroModalManager();
}
return IntroModalManager.instance;
}

public showIntroModal(): boolean {
if (this.isServer) return false;
return (
!!process.env.HIDE_INTRO_MODAL || !localStorage.getItem("hideIntroModal")
);
}

public setHideIntroModal(): void {
if (this.isServer) return;
localStorage.setItem("hideIntroModal", "true");
}
}
export const introModalManager = IntroModalManager.getInstance();

const PRIVATE_PAGES = /^(\/profile|\/my-projects)/;
export const isPrivatePath = (pathname: string) => {
Expand Down

0 comments on commit 4b3fb93

Please sign in to comment.