| 135 | }; |
| 136 | |
| 137 | export function Chart({ data }: { data: SankeyData }) { |
| 138 | const number = useNumber(); |
| 139 | const containerRef = useRef<HTMLDivElement>(null); |
| 140 | const { appTheme } = useTheme(); |
| 141 | |
| 142 | // Process data for Sankey |
| 143 | const sankeyData = useMemo(() => { |
| 144 | if (!data) return { nodes: [], links: [] }; |
| 145 | |
| 146 | return { |
| 147 | nodes: data.nodes.map((node) => ({ |
| 148 | ...node, |
| 149 | label: node.label || node.id, |
| 150 | data: { |
| 151 | percentage: node.percentage, |
| 152 | value: node.value, |
| 153 | step: node.step, |
| 154 | label: node.label || node.id, |
| 155 | }, |
| 156 | })), |
| 157 | links: data.links, |
| 158 | }; |
| 159 | }, [data]); |
| 160 | |
| 161 | const totalSessions = useMemo(() => { |
| 162 | if (!sankeyData.nodes || sankeyData.nodes.length === 0) return 0; |
| 163 | const step1 = sankeyData.nodes.filter((n: any) => n.data?.step === 1); |
| 164 | const base = step1.length > 0 ? step1 : sankeyData.nodes; |
| 165 | return base.reduce((sum: number, n: any) => sum + (n.data?.value ?? 0), 0); |
| 166 | }, [sankeyData.nodes]); |
| 167 | |
| 168 | return ( |
| 169 | <AspectContainer> |
| 170 | <div |
| 171 | ref={containerRef} |
| 172 | className="w-full relative aspect-square md:aspect-[2]" |
| 173 | > |
| 174 | <ResponsiveSankey |
| 175 | margin={{ top: 20, right: 20, bottom: 20, left: 20 }} |
| 176 | data={sankeyData} |
| 177 | colors={(node: any) => node.nodeColor} |
| 178 | nodeBorderRadius={2} |
| 179 | animate={false} |
| 180 | nodeBorderWidth={0} |
| 181 | nodeOpacity={0.8} |
| 182 | linkContract={1} |
| 183 | linkOpacity={0.3} |
| 184 | linkBlendMode={'normal'} |
| 185 | nodeTooltip={({ node }: any) => { |
| 186 | const label = node?.data?.label ?? node?.label ?? node?.id; |
| 187 | const value = node?.data?.value ?? node?.value ?? 0; |
| 188 | const step = node?.data?.step; |
| 189 | const pct = |
| 190 | typeof node?.data?.percentage === 'number' |
| 191 | ? node.data.percentage |
| 192 | : totalSessions > 0 |
| 193 | ? (value / totalSessions) * 100 |
| 194 | : 0; |