Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 82 additions & 80 deletions fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
import { format } from "date-fns/format"
import { useId, useMemo, useState } from "react"
import { nl } from "react-day-picker/locale"
import { Bar, BarChart, XAxis, YAxis } from "recharts"
import { Bar, BarChart, XAxis, YAxis, ZIndexLayer } from "recharts"
import { cn } from "@/app/lib/utils"
import { getCultivationColor } from "~/components/custom/cultivation-colors"
import { Card, CardContent, CardHeader } from "~/components/ui/card"
Expand Down Expand Up @@ -51,7 +51,8 @@ function buildChartDataAndLegend({
type === "farm"
? balanceData.emission.nitrate
: balanceData.emission.nitrate.total
const chartData: Record<string, number | undefined> = {
const chartData: Record<string, string | number | undefined> = {
name: "Balans", // Needed for chart to render at y-axis points called "Balans" - see the JSX below
deposition: Math.abs(
type === "farm"
? balanceData.supply.deposition
Expand Down Expand Up @@ -200,7 +201,7 @@ function buildChartDataAndLegend({
fa.p_app_id === applicationResult.id,
)
chartData[dataKey] = Math.abs(applicationResult.value)
;(chartConfig as ExtendedChartConfig)[dataKey] = application
chartConfig[dataKey] = application
? {
styleId: dataKeyPrefix,
label: label,
Expand Down Expand Up @@ -433,32 +434,17 @@ export function NitrogenBalanceChart(
},
) {
const { type, balanceData, fieldInput } = props
const [tooltipFocus, setTooltipFocus] = useState<string>()
const [barOutlineFocus, setBarOutlineFocus] = useState<
string | number | undefined
>()

// biome-ignore lint/correctness/useExhaustiveDependencies: each value in props is passed separately
const { legend, chartData, chartConfig, supplyBar, removalBar } = useMemo(
() => buildChartDataAndLegend(props),
[type, balanceData, fieldInput],
)
const svgId = useId()

type ChartMouseEvent = {
tooltipPayload: { dataKey: string }[]
}

const onTooltipFocus = (e: ChartMouseEvent) => {
const dataKey = e.tooltipPayload[0].dataKey
if (tooltipFocus !== dataKey) setTooltipFocus(dataKey)
}

const onTooltipBlur = (e: ChartMouseEvent) => {
const dataKey = e.tooltipPayload[0].dataKey
if (tooltipFocus === dataKey) setTooltipFocus(undefined)
}

const clearTooltipFocus = () => {
setTooltipFocus(undefined)
}

const barRadius = 5
const barRadiusStart: [number, number, number, number] = [
barRadius,
Expand Down Expand Up @@ -501,8 +487,12 @@ export function NitrogenBalanceChart(
radius={pickBarRadius(i, barItem)}
stackId={stackId}
fill={barStyle.color}
onMouseEnter={onTooltipFocus}
onMouseLeave={onTooltipBlur}
onMouseEnter={() => setBarOutlineFocus(dataKey)}
onMouseLeave={() => {
if (dataKey === barOutlineFocus) {
setBarOutlineFocus(undefined)
}
}}
/>
)
})
Expand All @@ -520,15 +510,24 @@ export function NitrogenBalanceChart(
radius={barRadius}
stackId={stackId}
fill={barStyle.color}
onMouseEnter={onTooltipFocus}
onMouseLeave={onTooltipBlur}
onMouseEnter={() => setBarOutlineFocus(dataKey)}
onMouseLeave={() => {
if (dataKey === barOutlineFocus) {
setBarOutlineFocus(undefined)
}
}}
/>
)
})
}

return (
<ChartContainer config={chartConfig} onMouseLeave={clearTooltipFocus}>
<ChartContainer
config={chartConfig}
onMouseLeave={() => {
setBarOutlineFocus(undefined)
}}
>
<BarChart
accessibilityLayer
data={[chartData]}
Expand All @@ -539,58 +538,58 @@ export function NitrogenBalanceChart(
>
<XAxis type="number" />
<YAxis
dataKey="primary"
dataKey="name"
type="category"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
tickFormatter={() => ""}
/>
<ChartTooltip
cursor={false}
content={({ active }) => {
if (active && tooltipFocus) {
const dataKey =
tooltipFocus as keyof typeof chartConfig
const itemConfig = chartConfig[dataKey]

return (
<Card>
<CardHeader className="p-4 pb-0">
<div>
<div
className="inline-block me-2 h-2 w-2 rounded-[2px]"
style={{
backgroundColor:
itemConfig.styleId
? chartConfig[
itemConfig
.styleId
].color
: itemConfig.color,
}}
/>
{itemConfig.label}
</div>
{itemConfig.detail?.map((detail, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: detail is constant
<div key={i}>
<div className="inline-block me-2 h-2 w-2 rounded-[2px]" />
{detail}
</div>
))}
</CardHeader>
<CardContent className="p-4">
<div className="font-bold">
shared={false}
content={({ payload }) => {
const validPayloadItem = payload.find(
(item) => item && item.type !== "none",
)
if (!validPayloadItem) return null
const { name } = validPayloadItem
if (!name) return null
const itemConfig = chartConfig[name]
if (!itemConfig) return null
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return (
<Card>
<CardHeader className="p-4 pb-0">
<div>
<div
className="inline-block me-2 h-2 w-2 rounded-[2px]"
style={{
backgroundColor:
itemConfig.styleId
? chartConfig[
itemConfig.styleId
].color
: itemConfig.color,
}}
/>
{itemConfig.label}
</div>
{itemConfig.detail?.map((detail, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: detail is constant
<div key={i}>
<div className="inline-block me-2 h-2 w-2 rounded-[2px]" />
{chartData[dataKey]}{" "}
{itemConfig.unit ?? "kg N / ha"}
{detail}
</div>
</CardContent>
</Card>
)
}
return null
))}
</CardHeader>
<CardContent className="p-4">
<div className="font-bold">
<div className="inline-block me-2 h-2 w-2 rounded-[2px]" />
{chartData[name]}{" "}
{itemConfig.unit ?? "kg N / ha"}
</div>
</CardContent>
</Card>
)
}}
/>
<ChartLegend
Expand Down Expand Up @@ -626,15 +625,18 @@ export function NitrogenBalanceChart(
/>
{renderBar("a", supplyBar)}
{renderBar("b", removalBar)}
{tooltipFocus && (
<use
href={`#${svgId}_${tooltipFocus}`}
fill="none"
stroke="black"
strokeWidth={5}
style={{ pointerEvents: "none" }}
/>
)}
<ZIndexLayer zIndex={2000}>
{barOutlineFocus && (
<use
className="recharts-zIndex-layer_2000"
href={`#${svgId}_${barOutlineFocus}`}
fill="none"
stroke="black"
strokeWidth={5}
style={{ pointerEvents: "none" }}
/>
)}
</ZIndexLayer>
</BarChart>
</ChartContainer>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ export function OrganicMatterBalanceChart({
const chartConfig = {
supply: {
label: "Aanvoer",
color: "hsl(var(--chart-1))",
color: "var(--color-chart-1)",
},
degradation: {
label: "Afbraak",
color: "hsl(var(--chart-2))",
color: "var(--color-chart-2)",
},
} satisfies ChartConfig

Expand Down
4 changes: 2 additions & 2 deletions fdm-app/app/components/ui/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Card = React.forwardRef<
<div
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow-sm",
"rounded-xl border bg-card text-card-foreground shadow",
className,
)}
{...props}
Expand Down Expand Up @@ -73,4 +73,4 @@ const CardFooter = React.forwardRef<
))
CardFooter.displayName = "CardFooter"

export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
Loading
Loading