Skip to content

Commit

Permalink
[#391] Render household income bar chart
Browse files Browse the repository at this point in the history
  • Loading branch information
wayangalihpratama committed Jan 16, 2025
1 parent aceb28f commit 4486f47
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 16 deletions.
4 changes: 1 addition & 3 deletions frontend/src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,7 @@
border-radius: 40px;

&:hover {
background: #01625f;
border: 1px solid #fff;
color: #fff;
border: 2px solid #01625f;
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/chart/options/ColumnBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Legend,
thousandFormatter,
LabelStyle,
formatNumberToString,
} from "./common";
import { sortBy, isEmpty, groupBy, orderBy } from "lodash";

Expand Down Expand Up @@ -148,6 +149,9 @@ const ColumnBar = ({
axisLabel: {
...TextStyle,
color: "#9292ab",
formatter: function (value) {
return formatNumberToString(value);
},
},
},
[horizontal ? "yAxis" : "xAxis"]: {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/cases/Case.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const SegmentTabsWrapper = ({ children, setbackfunction, setnextfunction }) => {

return (
<Row id="steps" gutter={[20, 20]}>
<Col span={childrenCount === 1 ? 24 : 17}>
<Col span={childrenCount === 1 ? 24 : 16}>
<Tabs
className="step-segment-tabs-container"
type="card"
Expand All @@ -127,7 +127,7 @@ const SegmentTabsWrapper = ({ children, setbackfunction, setnextfunction }) => {
React.Children.map(children, (child, index) =>
child.key === "right" ? (
React.isValidElement(child) ? (
<Col key={index} span={7}>
<Col key={index} span={8}>
{child}
</Col>
) : null
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/pages/cases/components/EnterIncomeDataForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,10 @@ const EnterIncomeDataDriver = ({
return "Other Diversified Income";
}, [group.commodity_type, group.commodity_name]);

const flattenQuestionList = useMemo(
() => (!group ? [] : flatten(group.questions)),
[group]
);
const flattenQuestionList = useMemo(() => {
const questions = !group ? [] : flatten(group.questions);
return questions;
}, [group]);

const updateCurrentSegmentState = (updatedSegmentValue) => {
CurrentCaseState.update((s) => {
Expand Down
56 changes: 52 additions & 4 deletions frontend/src/pages/cases/components/EnterIncomeDataVisual.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import React, { useMemo } from "react";
import { Card, Row, Col, Space } from "antd";
import { CaseUIState, CurrentCaseState } from "../store";
import { Card, Row, Col, Space, Tag } from "antd";
import { CaseUIState, CurrentCaseState, CaseVisualState } from "../store";
import { thousandFormatter } from "../../../components/chart/options/common";
import { VisualCardWrapper } from ".";
import Chart from "../../../components/chart";

const EnterIncomeDataVisual = () => {
const { activeSegmentId } = CaseUIState.useState((s) => s.general);
const currentCase = CurrentCaseState.useState((s) => s);
const totalIncomeQuestions = CaseVisualState.useState(
(s) => s.totalIncomeQuestions
);

const currentSegment = useMemo(
() =>
Expand All @@ -15,8 +19,41 @@ const EnterIncomeDataVisual = () => {
[currentCase.segments, activeSegmentId]
);

const chartData = useMemo(() => {
if (!currentCase.segments.length) {
return [];
}
const res = currentCase.segments.map((item) => {
const answers = item.answers || {};
const current = totalIncomeQuestions
.map((qs) => answers?.[`current-${qs}`] || 0)
.filter((a) => a)
.reduce((acc, a) => acc + a, 0);
const feasible = totalIncomeQuestions
.map((qs) => answers?.[`feasible-${qs}`] || 0)
.filter((a) => a)
.reduce((acc, a) => acc + a, 0);
return {
name: item.name,
data: [
{
name: "Current Income",
value: Math.round(current),
color: "#03625f",
},
{
name: "Feasible Income",
value: Math.round(feasible),
color: "#82b2b2",
},
],
};
});
return res;
}, [totalIncomeQuestions, currentCase.segments]);

if (!currentSegment) {
return <div>Failed to load current segment data</div>;
return <Tag color="error">Failed to load current segment data</Tag>;
}

return (
Expand All @@ -36,7 +73,18 @@ const EnterIncomeDataVisual = () => {
</Col>
<Col span={24}>
<VisualCardWrapper title="Household Income">
Household Income Bar Chart
<Chart
wrapper={false}
type="COLUMN-BAR"
data={chartData}
loading={!chartData.length}
height={window.innerHeight * 0.4}
extra={{
axisTitle: { y: `Income (${currentCase.currency})` },
}}
grid={{ bottom: 60, right: 5, left: 90 }}
// showLabel={showChartLabel}
/>
</VisualCardWrapper>
</Col>
<Col span={24}>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/cases/components/VisualCardWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ const VisualCardWrapper = ({ children, title }) => {
className="visual-card-wrapper"
title={
<Row align="middle" gutter={[8, 8]}>
<Col span={19}>
<Col span={18}>
<Space align="center">
<div className="title">{title}</div>
<div>
<InfoCircleOutlined />
</div>
</Space>
</Col>
<Col span={5} align="end">
<Col span={6} align="end">
<Button size="small" className="button-export">
Export
</Button>
Expand Down
22 changes: 21 additions & 1 deletion frontend/src/pages/cases/steps/EnterIncomeData.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
CurrentCaseState,
PrevCaseState,
CaseUIState,
CaseVisualState,
} from "../store";
import {
api,
calculateIncomePercentage,
determineDecimalRound,
renderPercentageTag,
removeUndefinedObjectValue,
flatten,
} from "../../../lib";
import { Row, Col, Space, message } from "antd";
import { EnterIncomeDataForm } from "../components";
Expand Down Expand Up @@ -250,7 +252,7 @@ const EnterIncomeData = ({ segment, setbackfunction, setnextfunction }) => {
const dataTmp = [];
const diversifiedGroupTmp = [];
// regroup the questions to follow new design format
reorderedCaseCommodities.forEach((cc) => {
const questionGroupsTmp = reorderedCaseCommodities.map((cc) => {
const tmp = data.find((d) => d.commodity_id === cc.commodity);
tmp["currency"] = currentCase.currency;
tmp["questions"] = addLevelIntoQuestions({
Expand All @@ -264,13 +266,31 @@ const EnterIncomeData = ({ segment, setbackfunction, setnextfunction }) => {
} else {
diversifiedGroupTmp.push({ ...cc, ...tmp });
}
return { ...cc, ...tmp };
});
// add diversified group
dataTmp.push({
groupName: "Diversified Income",
questionGroups: diversifiedGroupTmp,
});
setIncomeDataDrivers(dataTmp);
// eol

// get totalIncomeQuestion
const qs = questionGroupsTmp.flatMap((group) => {
if (!group) {
return [];
}
const questions = flatten(group.questions).filter((q) => !q.parent);
// group id is case commodity id
return questions.map((q) => `${group.id}-${q.id}`);
});
CaseVisualState.update((s) => ({
...s,
questionGroups: questionGroupsTmp,
totalIncomeQuestions: qs,
}));
// eol
});
}
}, [currentCase.id, currentCase.case_commodities, currentCase.currency]);
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/pages/cases/store/case_visual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Store } from "pullstate";

const defaultCaseVisualState = {
questionGroups: [],
totalIncomeQuestions: [],
};

const CaseVisualState = new Store(defaultCaseVisualState);

export default CaseVisualState;
1 change: 1 addition & 0 deletions frontend/src/pages/cases/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export const stepPath = {
export { default as CurrentCaseState } from "./current_case";
export { default as CaseUIState } from "./case_ui";
export { default as PrevCaseState } from "./prev_case";
export { default as CaseVisualState } from "./case_visual";

0 comments on commit 4486f47

Please sign in to comment.