diff --git a/.gitignore b/.gitignore index 4a23cb8..e611d8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store .next/ node_modules/ -.env.local \ No newline at end of file +.vscode/ +.env.local diff --git a/components/charts/category-bar.js b/components/charts/category-bar.js index e20b3e1..98b5620 100644 --- a/components/charts/category-bar.js +++ b/components/charts/category-bar.js @@ -1,14 +1,20 @@ -import { Badge, Expander } from '@carbonplan/components' +import { Badge, Row, Column, Expander } from '@carbonplan/components' import { useMemo } from 'react' import { Box, Flex } from 'theme-ui' -import AnimateHeight from 'react-animate-height' import { COLORS, LABELS } from '../constants' import { formatValue } from '../utils' -const CategoryBar = ({ label, total, mapping, expanded, showExpander }) => { +const CategoryBar = ({ + label, + total, + mapping, + issuedTotal, + expanded, + showExpander, +}) => { const background = useMemo(() => { - if (Object.keys(mapping).length === 0) { + if (Object.keys(mapping).length === 0 || total === 0) { return 'muted' } else { const colors = Object.keys(LABELS.category).map((key) => COLORS[key]) @@ -18,7 +24,7 @@ const CategoryBar = ({ label, total, mapping, expanded, showExpander }) => { if (typeof mapValue !== 'number') { mapValue = 0 } - let value = (mapValue / total) * 100 + let value = (mapValue / (issuedTotal ?? total)) * 100 if (accum[i - 1]) { value = value + accum[i - 1] } @@ -27,6 +33,10 @@ const CategoryBar = ({ label, total, mapping, expanded, showExpander }) => { }, [] ) + if (issuedTotal) { + colors.push('muted') + percentages.push(100) + } return (theme) => `linear-gradient(to right, ${percentages @@ -36,101 +46,73 @@ const CategoryBar = ({ label, total, mapping, expanded, showExpander }) => { }) .join(', ')})` } - }, [total, mapping]) + }, [total, issuedTotal, mapping]) const isEmpty = Object.keys(mapping).length === 0 return ( - - - + + + + + {label} + + + {isEmpty ? '-' : formatValue(total)} + + + + + + - {label} - - - {isEmpty ? '-' : formatValue(total)} - - - - - {showExpander && ( - + )} + - )} - - - - - - - {Object.keys(LABELS.category).map((l) => ( - - - - - {LABELS.category[l]} - - {isEmpty ? '-' : formatValue(mapping[l] ?? 0)} - - - `linear-gradient(to right, ${ - theme.colors[COLORS[l]] - } 0% ${((mapping[l] ?? 0) / total) * 100}%, ${ - theme.colors.muted - } ${((mapping[l] ?? 0) / total) * 100}% 100%)`, - }} - /> - - ))} - - - + + + ) } diff --git a/components/charts/detail-charts.js b/components/charts/detail-charts.js new file mode 100644 index 0000000..12e37ed --- /dev/null +++ b/components/charts/detail-charts.js @@ -0,0 +1,132 @@ +import { useState, useEffect } from 'react' +import { Box, Flex, Badge } from 'theme-ui' +import { Row, Column } from '@carbonplan/components' +import { alpha } from '@theme-ui/color' +import { COLORS, LABELS } from '../constants' +import { formatValue } from '../utils' + +const DetailCharts = ({ issued, retired, isLoading, error }) => { + const [previousCategories, setPreviousCategories] = useState([]) + + useEffect(() => { + if (!isLoading && !error) { + setPreviousCategories(Object.keys(issued.mapping)) + } + }, [isLoading, error]) + + const createGradient = (theme, l, isRetired) => { + const percent = ((issued.mapping[l] ?? 0) / issued.total) * 100 + const retiredPercent = isRetired + ? ((retired.mapping[l] ?? 0) / issued.total) * 100 + : percent + + if (isRetired) { + return `linear-gradient(to right, + ${theme.rawColors[COLORS[l]]} 0%, + ${theme.rawColors[COLORS[l]]} ${retiredPercent}%, + ${alpha( + theme.rawColors[COLORS[l]], + 0.3 + )(theme)} ${retiredPercent}%, + ${alpha(theme.rawColors[COLORS[l]], 0.3)(theme)} ${percent}%, + ${theme.colors.muted} ${percent}%, + ${theme.colors.muted} 100%)` + } else { + return `linear-gradient(to right, ${ + theme.colors[COLORS[l]] + } 0% ${percent}%, ${theme.colors.muted} ${percent}% 100%)` + } + } + const chartColumn = (isRetired) => { + const categoryKeys = + isLoading || error + ? previousCategories + : Object.keys(LABELS.category).filter((l) => Boolean(issued.mapping[l])) + + return ( + + {categoryKeys.map((l) => ( + + + {isLoading || error ? ( + + + ---- + + ) : ( + + + {LABELS.category[l]} + + )} + + + {isLoading || error + ? '-' + : formatValue( + isRetired ? retired.mapping[l] : issued.mapping[l] + ) ?? 0} + + + createGradient(theme, l, isRetired), + }} + /> + + ))} + + ) + } + + return ( + <> + + {chartColumn(false)} + {chartColumn(true)} + + + ) +} + +export default DetailCharts diff --git a/components/charts/project-charts.js b/components/charts/project-charts.js index 605c192..a7a3dab 100644 --- a/components/charts/project-charts.js +++ b/components/charts/project-charts.js @@ -1,9 +1,11 @@ -import { Column, Row } from '@carbonplan/components' +import { Row, Column } from '@carbonplan/components' import { useMemo, useState } from 'react' +import AnimateHeight from 'react-animate-height' import { LABELS } from '../constants' import useFetcher from '../use-fetcher' import CategoryBar from './category-bar' +import DetailCharts from './detail-charts' const ProjectCharts = () => { const [expanded, setExpanded] = useState(false) @@ -41,6 +43,7 @@ const ProjectCharts = () => { retired: { total: prevRetired.total + retired, mapping: prevRetired.mapping, + issuedTotal: prevIssued.total + issued, }, } }, @@ -48,33 +51,73 @@ const ProjectCharts = () => { ) }, [data]) + const issuedKeys = Object.keys(issued.mapping) + return ( - setExpanded(!expanded)} - columns={[6, 8, 8, 8]} - sx={{ - color: 'primary', - fontFamily: 'mono', - letterSpacing: 'mono', - textTransform: 'uppercase', - cursor: 'pointer', - '&:hover #expander': { - stroke: 'primary', - }, - }} - > - - - - - - - + <> + { + if (issuedKeys.length) { + setExpanded(!expanded) + } + }} + sx={{ + '&:hover #expander': { + stroke: 'primary', + }, + cursor: issuedKeys.length ? 'pointer' : null, + color: 'primary', + fontFamily: 'mono', + letterSpacing: 'mono', + textTransform: 'uppercase', + mt: [5, 5, 7, 7], + mb: 3, + }} + > + + 0} + /> + + + + + + + + + + + ) } diff --git a/components/layout.js b/components/layout.js index f8343a3..67ea15a 100644 --- a/components/layout.js +++ b/components/layout.js @@ -8,7 +8,7 @@ const Layout = ({ sidebar, children }) => { { return ( <> - - - - + +