-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TM-1605] site landing page progress goals (#858)
* [TM-1605] add component to progress and goals pie chart * [TM-1605] add mapping to data charts * [TM-1605] add params to chartData component * [TM-1605] add external component to progress and goals site * [TM-1605] update name chartData * [TM-1605] update styles to tooltip text * [TM-1605] add total trees restored const * [TM-1605] add GoalsAndProgressSiteTab component to overview tab * [TM-1605] update snapshots * [TM-1605] update mapping param * [TM-1605] update ProgressGoalsDoughnutChart component * [TM-1605] change ChartData => ProgressDataCard * [TM-1605] change terrafund => framework
- Loading branch information
1 parent
b3803ec
commit ee9362e
Showing
6 changed files
with
302 additions
and
130 deletions.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
src/admin/components/ResourceTabs/MonitoredTab/components/ProgressGoalsDoughnutChart.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,92 @@ | ||
import React from "react"; | ||
import { Cell, Label, Pie, PieChart, ResponsiveContainer } from "recharts"; | ||
|
||
interface ChartDataItem { | ||
name: string; | ||
value: number; | ||
} | ||
|
||
export interface ProgressGoalsData { | ||
chartData: ChartDataItem[]; | ||
} | ||
|
||
interface ProgressGoalsDoughnutChartProps { | ||
data?: ProgressGoalsData; | ||
} | ||
const percentage = (current: number, total: number) => { | ||
const percentValue = Math.min((current / total) * 100, 100); | ||
return percentValue.toFixed(0); | ||
}; | ||
|
||
const ProgressGoalsDoughnutChart: React.FC<ProgressGoalsDoughnutChartProps> = ({ data }) => { | ||
const { chartData } = data as any; | ||
|
||
const currentValue = chartData[0]?.value || 0; | ||
const totalValue = chartData[1]?.value || 0; | ||
|
||
const remainingValue = Math.max(totalValue - currentValue, 0); | ||
|
||
const transformedData = | ||
currentValue > totalValue | ||
? [{ value: 1, isProgress: true }] | ||
: [ | ||
{ value: currentValue, isProgress: true }, | ||
{ value: remainingValue, isProgress: false } | ||
]; | ||
const COLORS = ["#27A9E0", "#DFF2FB"]; | ||
|
||
return ( | ||
<div className="relative flex h-[180px] w-full flex-col items-center justify-center pt-0"> | ||
<ResponsiveContainer width="100%" height="100%"> | ||
<PieChart> | ||
<Pie | ||
data={transformedData} | ||
cx="50%" | ||
cy="50%" | ||
innerRadius={45} | ||
outerRadius={75} | ||
paddingAngle={0} | ||
dataKey="value" | ||
startAngle={90} | ||
endAngle={-270} | ||
> | ||
{totalValue > 0 && ( | ||
<Label | ||
position="center" | ||
content={(props: any) => { | ||
const { viewBox } = props; | ||
const { cx, cy } = viewBox; | ||
return ( | ||
<text | ||
x={cx} | ||
y={cy} | ||
textAnchor="middle" | ||
dominantBaseline="middle" | ||
className="text-20-semibold !font-semibold !text-darkCustom" | ||
> | ||
<tspan x={cx} dy="-4" className="text-16 !font-bold !text-blueCustom-700"> | ||
{currentValue > totalValue ? "100+" : percentage(currentValue, totalValue)}% | ||
</tspan> | ||
<tspan x={cx} dy="16" className="text-12-light !text-darkCustom"> | ||
complete | ||
</tspan> | ||
</text> | ||
); | ||
}} | ||
/> | ||
)} | ||
{transformedData.map((entry: any, index: any) => ( | ||
<Cell | ||
key={`cell-${index}`} | ||
fill={COLORS[index % COLORS.length]} | ||
className={currentValue > totalValue ? "opacity-80" : ""} | ||
/> | ||
))} | ||
</Pie> | ||
</PieChart> | ||
</ResponsiveContainer> | ||
</div> | ||
); | ||
}; | ||
|
||
export default ProgressGoalsDoughnutChart; |
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
190 changes: 190 additions & 0 deletions
190
src/pages/site/[uuid]/components/GoalsAndProgressSiteTab.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,190 @@ | ||
import { useT } from "@transifex/react"; | ||
import React from "react"; | ||
|
||
import ProgressGoalsDoughnutChart from "@/admin/components/ResourceTabs/MonitoredTab/components/ProgressGoalsDoughnutChart"; | ||
import GoalProgressCard from "@/components/elements/Cards/GoalProgressCard/GoalProgressCard"; | ||
import { IconNames } from "@/components/extensive/Icon/Icon"; | ||
import { ALL_TF, Framework } from "@/context/framework.provider"; | ||
|
||
interface GoalsAndProgressSiteTabProps { | ||
site: any; | ||
} | ||
interface ProgressDataCardItem { | ||
cardValues: { | ||
label: string; | ||
value: number; | ||
totalName?: string; | ||
totalValue?: number; | ||
}; | ||
chartData: any; | ||
graph?: boolean; | ||
hectares?: boolean; | ||
} | ||
|
||
type ChartsData = { | ||
terrafund: JSX.Element[]; | ||
ppc: JSX.Element[]; | ||
hbf: JSX.Element[]; | ||
}; | ||
|
||
const ProgressDataCard = (values: ProgressDataCardItem) => { | ||
return ( | ||
<GoalProgressCard | ||
label={values.cardValues.label} | ||
value={values.cardValues.value} | ||
totalValue={values.cardValues.totalValue} | ||
hectares={values.hectares} | ||
graph={values.graph} | ||
classNameLabel="text-neutral-650 uppercase mb-3" | ||
labelVariant="text-14" | ||
classNameCard="text-center flex flex-col items-center" | ||
classNameLabelValue="justify-center" | ||
chart={<ProgressGoalsDoughnutChart key={"items"} data={values.chartData} />} | ||
/> | ||
); | ||
}; | ||
|
||
const GoalsAndProgressSiteTab = ({ site }: GoalsAndProgressSiteTabProps) => { | ||
const t = useT(); | ||
const totaTreesRestoredCount = site?.trees_planted_count + site?.regenerated_trees_count + site?.seeds_planted_count; | ||
const chartDataHectares = { | ||
chartData: [ | ||
{ name: t("HECTARES RESTORED"), value: site.total_hectares_restored_sum }, | ||
site.framework_key !== Framework.PPC | ||
? { | ||
name: t("TOTAL HECTARES RESTORED"), | ||
value: parseFloat(site.hectares_to_restore_goal) | ||
} | ||
: {} | ||
], | ||
cardValues: { | ||
label: t("HECTARES RESTORED"), | ||
value: site.total_hectares_restored_sum, | ||
totalName: t("TOTAL HECTARES RESTORED"), | ||
totalValue: parseFloat(site.hectares_to_restore_goal) | ||
} | ||
}; | ||
const chartDataTreesRestored = { | ||
chartData: [{ name: t("TREES RESTORED"), value: totaTreesRestoredCount }], | ||
cardValues: { | ||
label: t("TREES RESTORED"), | ||
value: totaTreesRestoredCount | ||
} | ||
}; | ||
const chartDataWorkdays = { | ||
chartData: [ | ||
{ | ||
name: t("WORKDAYS CREATED"), | ||
value: site.framework_key == Framework.PPC ? site.combined_workday_count : site.workday_count | ||
} | ||
], | ||
cardValues: { | ||
label: t("WORKDAYS CREATED"), | ||
value: site.framework_key == Framework.PPC ? site.combined_workday_count : site.workday_count | ||
} | ||
}; | ||
const chartDataSaplings = { | ||
chartData: [{ name: t("SAPLINGS RESTORED"), value: totaTreesRestoredCount }], | ||
cardValues: { | ||
label: t("SAPLINGS RESTORED"), | ||
value: totaTreesRestoredCount | ||
} | ||
}; | ||
|
||
const chartsDataMapping: ChartsData = { | ||
terrafund: [ | ||
<ProgressDataCard | ||
key={"terrafund-1"} | ||
cardValues={chartDataHectares.cardValues} | ||
chartData={chartDataHectares} | ||
hectares={true} | ||
/>, | ||
<ProgressDataCard | ||
key={"terrafund-2"} | ||
cardValues={chartDataTreesRestored.cardValues} | ||
chartData={chartDataTreesRestored} | ||
graph={false} | ||
/> | ||
], | ||
ppc: [ | ||
<ProgressDataCard | ||
key={"ppc-1"} | ||
cardValues={chartDataHectares.cardValues} | ||
chartData={chartDataHectares} | ||
graph={false} | ||
hectares={true} | ||
/>, | ||
<ProgressDataCard | ||
key={"ppc-2"} | ||
cardValues={chartDataTreesRestored.cardValues} | ||
chartData={chartDataTreesRestored} | ||
graph={false} | ||
/>, | ||
<ProgressDataCard | ||
key={"ppc-3"} | ||
cardValues={chartDataWorkdays.cardValues} | ||
chartData={chartDataWorkdays} | ||
graph={false} | ||
/> | ||
], | ||
hbf: [ | ||
<ProgressDataCard | ||
key={"hbf-1"} | ||
cardValues={chartDataWorkdays.cardValues} | ||
chartData={chartDataWorkdays} | ||
graph={false} | ||
/>, | ||
<ProgressDataCard | ||
key={"hbf-2"} | ||
cardValues={chartDataHectares.cardValues} | ||
chartData={chartDataHectares} | ||
hectares={true} | ||
/>, | ||
<ProgressDataCard | ||
key={"hbf-3"} | ||
cardValues={chartDataSaplings.cardValues} | ||
chartData={chartDataSaplings} | ||
graph={false} | ||
/> | ||
] | ||
}; | ||
const framework = ALL_TF.includes(site.framework_key as Framework) ? "terrafund" : site.framework_key; | ||
return ( | ||
<div className="flex w-full flex-wrap items-start justify-between gap-8"> | ||
{chartsDataMapping[framework as keyof ChartsData]?.map((chart, index) => ( | ||
<React.Fragment key={index}>{chart}</React.Fragment> | ||
))} | ||
<GoalProgressCard | ||
label={t("Trees restored")} | ||
value={totaTreesRestoredCount} | ||
limit={site.trees_grown_goal} | ||
hasProgress={false} | ||
items={[ | ||
{ | ||
iconName: IconNames.TREE_CIRCLE_PD, | ||
label: t("Trees Planted:"), | ||
variantLabel: "text-14", | ||
classNameLabel: " text-neutral-650 uppercase", | ||
value: site.trees_planted_count | ||
}, | ||
{ | ||
iconName: IconNames.LEAF_CIRCLE_PD, | ||
label: t("Seeds Planted:"), | ||
variantLabel: "text-14", | ||
classNameLabel: " text-neutral-650 uppercase", | ||
value: site.seeds_planted_count | ||
}, | ||
{ | ||
iconName: IconNames.REFRESH_CIRCLE_PD, | ||
label: t("Trees Regenerating:"), | ||
variantLabel: "text-14", | ||
classNameLabel: " text-neutral-650 uppercase", | ||
value: site.regenerated_trees_count | ||
} | ||
]} | ||
className="pr-[41px] lg:pr-[150px]" | ||
/> | ||
</div> | ||
); | ||
}; | ||
export default GoalsAndProgressSiteTab; |
Oops, something went wrong.