Skip to content

Commit 838108c

Browse files
authored
Merge branch 'develop' into record-form-calculated-fields
2 parents 42b84b4 + a81fc7e commit 838108c

File tree

81 files changed

+1727
-953
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1727
-953
lines changed

app/javascript/components/application/selectors.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ export const selectModule = (state, id) => selectUserModules(state).find(f => f.
5555
export const getWorkflowLabels = (state, id, recordType) =>
5656
selectModule(state, id).getIn(["workflows", recordType], []);
5757

58+
export const getConsentform = (state, id) => selectModule(state, id).getIn(["options", "consent_form"]);
59+
5860
export const selectUserIdle = state => state.getIn([NAMESPACE, "userIdle"], false);
5961

6062
export const getReportingLocationConfig = state => state.getIn([NAMESPACE, "reportingLocationConfig"], fromJS({}));
@@ -147,7 +149,7 @@ export const getCodesOfConduct = state => state.getIn([NAMESPACE, "codesOfConduc
147149
export const getOptionFromAppModule = (state, primeroModule, option) =>
148150
getAppModuleByUniqueId(state, primeroModule).getIn(
149151
["options", option],
150-
option === DATA_PROTECTION_FIELDS ? fromJS([]) : false
152+
option === DATA_PROTECTION_FIELDS ? [] : false
151153
);
152154

153155
export const getCodeOfConductEnabled = state =>

app/javascript/components/dashboard/badged-indicator/component.jsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ROUTES } from "../../../config";
1010
import { buildFilter } from "../utils";
1111
import LoadingIndicator from "../../loading-indicator";
1212
import NAMESPACE from "../../pages/dashboard/namespace";
13+
import dashboardsCss from "../styles.css";
1314

1415
import css from "./styles.css";
1516

@@ -56,7 +57,7 @@ function BadgedIndicator({ data, lookup, sectionTitle, indicator, loading, error
5657
return (
5758
<>
5859
<LoadingIndicator {...loadingIndicatorProps} data-testid="badged-indicator">
59-
<div className={css.sectionTitle}>{sectionTitle}</div>
60+
<div className={dashboardsCss.sectionTitle}>{sectionTitle}</div>
6061
<div className={css.content}>{dashboardChips}</div>
6162
</LoadingIndicator>
6263
</>

app/javascript/components/dashboard/badged-indicator/styles.css

-8
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,3 @@
2727
gap: var(--sp-1);
2828
margin-top: var(--sp-2);
2929
}
30-
31-
.sectionTitle {
32-
color: var(--c-warm-grey-4);
33-
text-transform: uppercase;
34-
font-weight: bold;
35-
margin-bottom: var(--sp-1);
36-
font-size: var(--fs-13);
37-
}

app/javascript/components/dashboard/dashboard-chip/styles.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
text-transform: uppercase;
77
width: 100%;
88
padding: var(--sp-1);
9-
border-radius: 0;
9+
border-radius: 6px;
1010

1111
&.high {
1212
background-color: var(--c-red);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2014 - 2023 UNICEF. All rights reserved.
2+
3+
import { Fragment } from "react";
4+
import PropTypes from "prop-types";
5+
import { cx } from "@emotion/css";
6+
7+
import Permission, { RESOURCES } from "../../permissions";
8+
import OptionsBox from "../options-box";
9+
import { dashboardType } from "../../pages/dashboard/utils";
10+
import css from "../../pages/dashboard/components/styles.css";
11+
12+
function DashboardColumns({ columns, keepRows }) {
13+
const classes = cx({ [css.container]: !keepRows, [css.keepRows]: keepRows });
14+
15+
return (
16+
<div className={classes} data-testid="dashboard-columns">
17+
{columns.map((dashboards, index) => (
18+
<Fragment key={`columns-${dashboards.flatMap(dashboard => dashboard.actions).join("-")}`}>
19+
<div className={css.optionsBox} data-testid="dashboard-column">
20+
<OptionsBox flat>
21+
{dashboards.map(dashboard => {
22+
const { type, actions, options } = dashboard;
23+
const Dashboard = dashboardType(type);
24+
25+
return (
26+
<Permission key={actions} resources={RESOURCES.dashboards} actions={actions}>
27+
<Dashboard {...options} />
28+
</Permission>
29+
);
30+
})}
31+
</OptionsBox>
32+
</div>
33+
{index === columns.length - 1 || <div className={css.divider} />}
34+
</Fragment>
35+
))}
36+
</div>
37+
);
38+
}
39+
40+
DashboardColumns.displayName = "DashboardColumns";
41+
42+
DashboardColumns.propTypes = {
43+
columns: PropTypes.array,
44+
keepRows: PropTypes.bool
45+
};
46+
47+
export default DashboardColumns;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from "./component";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* Copyright (c) 2014 - 2023 UNICEF. All rights reserved. */
2+
3+
.root {
4+
flex-grow: 1;
5+
padding: 15px;
6+
}

app/javascript/components/dashboard/dashboard-table/component.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ function DashboardTable({ columns, data, query, title, pathname }) {
2121
const dispatch = useDispatch();
2222
const options = {
2323
...defaultTableOptions({ simple: true, title }),
24+
tableBodyMaxHeight: "260px",
25+
fixedHeader: true,
2426
onCellClick: (colData, cellMeta) => {
2527
const { colIndex, rowIndex } = cellMeta;
2628
const columnName = columns[colIndex].name;

app/javascript/components/dashboard/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export { default as FlagBox } from "./flag-box";
77
export { default as LineChart } from "./line-chart";
88
export { default as OptionsBox } from "./options-box";
99
export { default as OverviewBox } from "./overview-box";
10+
export { default as TotalBox } from "./total-box";
1011
export { default as ActionMenu } from "./action-menu";
1112
export { default as DashboardChip } from "./dashboard-chip";
1213
export { default as PieChart } from "./pie-chart";

app/javascript/components/dashboard/index.unit.test.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@ describe("<Dashboard /> - index", () => {
1010
it("should have known properties", () => {
1111
expect(indexValues).to.be.an("object");
1212
[
13+
"ActionMenu",
1314
"BadgedIndicator",
15+
"DashboardChip",
1416
"DashboardTable",
1517
"DoughnutChart",
1618
"FlagBox",
1719
"LineChart",
1820
"OptionsBox",
1921
"OverviewBox",
20-
"ActionMenu",
21-
"DashboardChip",
22-
"PieChart"
22+
"PieChart",
23+
"TotalBox"
2324
].forEach(property => {
2425
expect(indexValues).to.have.property(property);
2526
delete indexValues[property];

app/javascript/components/dashboard/options-box/component.jsx

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) 2014 - 2023 UNICEF. All rights reserved.
22

3-
import { Card, CardHeader, CardContent } from "@mui/material";
3+
import { Card, CardHeader, CardContent, CardActions } from "@mui/material";
44
import { Link } from "react-router-dom";
55
import PropTypes from "prop-types";
66

@@ -10,7 +10,19 @@ import { ConditionalWrapper } from "../../../libs";
1010

1111
import css from "./styles.css";
1212

13-
function OptionsBox({ title, action, children, to, flat, overlay, type = "", loading, errors, hasData = true }) {
13+
function OptionsBox({
14+
title,
15+
action,
16+
children,
17+
to,
18+
flat,
19+
overlay,
20+
type = "",
21+
loading,
22+
errors,
23+
hasData = true,
24+
footer
25+
}) {
1426
const loadingIndicatorProps = {
1527
overlay,
1628
type,
@@ -42,6 +54,7 @@ function OptionsBox({ title, action, children, to, flat, overlay, type = "", loa
4254
{cardTitle}
4355
<LoadingIndicator {...loadingIndicatorProps}>
4456
<CardContent className={css.content}>{children}</CardContent>
57+
{footer && <CardActions>{footer}</CardActions>}
4558
</LoadingIndicator>
4659
</>
4760
</ConditionalWrapper>
@@ -56,6 +69,7 @@ OptionsBox.propTypes = {
5669
children: PropTypes.node,
5770
errors: PropTypes.bool,
5871
flat: PropTypes.bool,
72+
footer: PropTypes.node,
5973
hasData: PropTypes.bool,
6074
loading: PropTypes.bool,
6175
overlay: PropTypes.bool,

app/javascript/components/dashboard/options-box/styles.css

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
/* Copyright (c) 2014 - 2023 UNICEF. All rights reserved. */
22

33
.card {
4-
margin-bottom: 20px;
4+
margin-bottom: 24px;
5+
flex: 1 1 auto;
6+
7+
&:last-child {
8+
margin-bottom: 0;
9+
}
510
}
611

712
.content {

app/javascript/components/dashboard/overview-box/component.jsx

+26-108
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,46 @@
11
// Copyright (c) 2014 - 2023 UNICEF. All rights reserved.
22

3-
import { Fragment } from "react";
43
import { Grid } from "@mui/material";
54
import PropTypes from "prop-types";
65
import { fromJS } from "immutable";
7-
import { useDispatch } from "react-redux";
8-
import { push } from "connected-react-router";
96

10-
import { ROUTES } from "../../../config";
11-
import { buildFilter } from "../utils";
127
import DoughnutChart from "../doughnut-chart";
13-
import { useI18n } from "../../i18n";
14-
import LoadingIndicator from "../../loading-indicator";
15-
import NAMESPACE from "../../pages/dashboard/namespace";
16-
import { useApp } from "../../application";
17-
import ActionButton from "../../action-button";
188

199
import css from "./styles.css";
10+
import IndicatorSection from "./indicator-section";
2011

2112
function OverviewBox({ items, chartData, sumTitle, withTotal = true, loading, errors }) {
22-
const i18n = useI18n();
23-
const { approvalsLabels } = useApp();
24-
const dispatch = useDispatch();
2513
const indicators = items.get("indicators", fromJS({}));
26-
const indicatorsKeys = indicators.keySeq();
27-
28-
const loadingIndicatorProps = {
29-
overlay: true,
30-
hasData: indicators.size > 1,
31-
type: NAMESPACE,
32-
loading,
33-
errors
34-
};
35-
36-
const sum = () => {
37-
return indicatorsKeys.reduce((prev, current) => prev + (indicators.getIn([current, "count"]) || 0), 0);
38-
};
39-
40-
const handleClick = query => {
41-
dispatch(
42-
push({
43-
pathname: ROUTES.cases,
44-
search: buildFilter(query)
45-
})
46-
);
47-
};
48-
49-
const buildLabelItem = item => {
50-
switch (item) {
51-
case "approval_assessment_pending_group":
52-
return approvalsLabels.get("assessment");
53-
case "approval_case_plan_pending_group":
54-
return approvalsLabels.get("case_plan");
55-
case "approval_closure_pending_group":
56-
return approvalsLabels.get("closure");
57-
case "approval_action_plan_pending_group":
58-
return approvalsLabels.get("action_plan");
59-
case "approval_gbv_closure_pending_group":
60-
return approvalsLabels.get("gbv_closure");
61-
default:
62-
return i18n.t(`dashboard.${item}`);
63-
}
64-
};
65-
66-
const statItems = () => {
67-
const handleButtonClick = query => () => handleClick(query);
68-
69-
return indicators.keySeq().map(item => {
70-
return (
71-
<Fragment key={item}>
72-
<ActionButton
73-
id={`overview-${item}-number`}
74-
className={css.itemButtonNumber}
75-
type="link"
76-
text={indicators.getIn([item, "count"])}
77-
onClick={handleButtonClick(indicators.getIn([item, "query"], []))}
78-
noTranslate
79-
/>
80-
<ActionButton
81-
id={`overview-${item}-text`}
82-
className={css.itemButton}
83-
type="link"
84-
text={buildLabelItem(item)}
85-
onClick={handleButtonClick(indicators.getIn([item, "query"], []))}
86-
noTranslate
87-
/>
88-
</Fragment>
89-
);
90-
});
91-
};
92-
93-
const renderSum = () => {
94-
return withTotal ? `${sum()} ${sumTitle}` : sumTitle;
95-
};
96-
97-
// eslint-disable-next-line react/no-multi-comp, react/display-name
98-
const renderItems = () => (
99-
<LoadingIndicator {...loadingIndicatorProps}>
100-
<div className={css.overviewBox} data-testid="overview-box">
101-
<div className={css.sectionTitle}>{renderSum()}</div>
102-
<div className={css.overviewList}>{statItems()}</div>
103-
</div>
104-
</LoadingIndicator>
14+
const indicatorSection = (
15+
<>
16+
<IndicatorSection
17+
indicators={indicators}
18+
loading={loading}
19+
errors={errors}
20+
sumTitle={sumTitle}
21+
withTotal={withTotal}
22+
/>
23+
</>
10524
);
10625

107-
// eslint-disable-next-line react/no-multi-comp, react/display-name
108-
const renderWithChart = () => (
109-
<div className={css.root} data-testid="overview-box">
110-
<Grid container spacing={3}>
111-
{chartData && (
112-
<Grid item md={4} xs={12} className={css.dashboardChart}>
113-
<DoughnutChart chartData={chartData} />
26+
if (chartData) {
27+
return (
28+
<div className={css.root} data-testid="overview-box">
29+
<Grid container spacing={3}>
30+
{chartData && (
31+
<Grid item md={4} xs={12} className={css.dashboardChart}>
32+
<DoughnutChart chartData={chartData} />
33+
</Grid>
34+
)}
35+
<Grid item md={8} xs={12}>
36+
{indicatorSection}
11437
</Grid>
115-
)}
116-
<Grid item md={8} xs={12}>
117-
{renderItems()}
11838
</Grid>
119-
</Grid>
120-
</div>
121-
);
122-
123-
const renderOverviewBox = chartData ? renderWithChart() : renderItems();
39+
</div>
40+
);
41+
}
12442

125-
return <>{renderOverviewBox}</>;
43+
return indicatorSection;
12644
}
12745

12846
OverviewBox.displayName = "OverviewBox";

0 commit comments

Comments
 (0)