Skip to content

Commit

Permalink
Merge pull request #88 from openimis/feature/OM-329
Browse files Browse the repository at this point in the history
OM-329: dashboard init
  • Loading branch information
lruzicki authored Nov 5, 2024
2 parents 8770ad6 + 785fbc3 commit 20dfc8a
Show file tree
Hide file tree
Showing 8 changed files with 408 additions and 1 deletion.
49 changes: 49 additions & 0 deletions src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,52 @@ export function deleteVoucherDraftForm(economicUnit, clientMutationLabel, typeOf
},
);
}

export function fetchSystemData(economicUnit) {
const query = `
query fetchSystemData($economicUnitCode: String!, $economicUnitUuid: String!) {
totalNumber: worker(economicUnitCode: $economicUnitCode) {
totalCount
}
activeNumber: workerVoucher(
policyholder_Code: $economicUnitCode
status: ASSIGNED
assignedDate_Gte: "2024-11-04T00:00:00"
) {
totalCount
}
pending: workerVoucher(
policyholder_Code: $economicUnitCode
status: AWAITING_PAYMENT
) {
totalCount
}
unassigned: workerVoucher(
policyholder_Code: $economicUnitCode
status: UNASSIGNED
) {
totalCount
}
assigned: workerVoucher(policyholder_Code: $economicUnitCode, status: ASSIGNED) {
totalCount
}
expired: workerVoucher(policyholder_Code: $economicUnitCode, status: EXPIRED) {
totalCount
}
cancelled: workerVoucher(policyholder_Code: $economicUnitCode, status: CANCELED) {
totalCount
}
paid: bill(subjectId: $economicUnitUuid, status: A_2) {
totalCount
}
unpaid: bill(subjectId: $economicUnitUuid, status: A_1) {
totalCount
}
}
`;

return graphqlWithVariables(query, {
economicUnitCode: economicUnit.code,
economicUnitUuid: decodeId(economicUnit.id),
});
}
119 changes: 119 additions & 0 deletions src/components/dashboard/StepsToFollow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React from 'react';

import { Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';

import { useTranslations } from '@openimis/fe-core';
import { MODULE_NAME } from '../../constants';

export const useStyles = makeStyles((theme) => ({
stepsToFollowTitle: {
fontSize: '24px',
fontWeight: '600',
lineHeight: '29px',
marginBottom: '24px',
},
stepsToFollowContainer: {
display: 'flex',
flexDirection: 'row',
gap: '32px',
},
stepTitle: {
fontSize: '18px',
fontWeight: '400',
lineHeight: '22px',
},
stepContainer: {
display: 'flex',
flexDirection: 'column',
gap: '8px',
},
stepPrimary: {
height: '116px',
width: '257px',
padding: '16px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: theme.palette.primary.main,
color: theme.palette.secondary.main,
fontSize: '18px',
fontWeight: '700',
lineHeight: '22px',
},
stepSecondary: {
height: '116px',
width: '257px',
padding: '16px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
border: `1px solid ${theme.palette.primary.main}`,
color: theme.palette.primary.main,
fontSize: '18px',
fontWeight: '700',
lineHeight: '22px',
},
}));

const STEPS_TO_FOLLOW = [
{
stepOrder: 1,
title: 'workerVoucher.StepsToFollow.title.step1',
description: 'workerVoucher.StepsToFollow.description.step1',
},
{
stepOrder: 2,
title: 'workerVoucher.StepsToFollow.title.step2',
description: 'workerVoucher.StepsToFollow.description.step2',
},
{
stepOrder: 3,
title: 'workerVoucher.StepsToFollow.title.step3',
description: 'workerVoucher.StepsToFollow.description.step3',
},
{
stepOrder: 4,
title: 'workerVoucher.StepsToFollow.title.step4',
description: 'workerVoucher.StepsToFollow.description.step4',
isSecondary: true,
},
];

function Step({
isSecondary = false, stepOrder, title, description,
}) {
const classes = useStyles();
const { formatMessage } = useTranslations(MODULE_NAME);

return (
<div className={classes.stepContainer}>
<Typography className={classes.stepTitle}>{`${stepOrder}. ${formatMessage(title)}`}</Typography>
<div className={isSecondary ? classes.stepSecondary : classes.stepPrimary}>{formatMessage(description)}</div>
</div>
);
}

function StepsToFollow() {
const classes = useStyles();
const { formatMessage } = useTranslations(MODULE_NAME);

return (
<div>
<Typography className={classes.stepsToFollowTitle}>{formatMessage('DashboardPage.stepsToFollow')}</Typography>
<div className={classes.stepsToFollowContainer}>
{STEPS_TO_FOLLOW.map((step) => (
<Step
key={step.stepOrder}
stepOrder={step.stepOrder}
title={step.title}
description={step.description}
isSecondary={step.isSecondary}
/>
))}
</div>
</div>
);
}

export default StepsToFollow;
98 changes: 98 additions & 0 deletions src/components/dashboard/SystemData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React from 'react';

import { Typography, CircularProgress } from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';

import { useTranslations } from '@openimis/fe-core';
import { MODULE_NAME } from '../../constants';

const useStyles = makeStyles(() => ({
dataTitle: {
fontSize: '24px',
fontWeight: '600',
lineHeight: '29px',
marginBottom: '12px',
},
dataSubtitle: {
fontSize: '18px',
fontWeight: '500',
lineHeight: '22px',
},
dataCount: {
fontSize: '48px',
fontWeight: '600',
lineHeight: '58px',
},
workerDataContainer: {
display: 'flex',
flexDirection: 'row',
gap: '128px',
},
voucherDataContainer: {
display: 'flex',
flexDirection: 'column',
gap: '24px',
},
paymentDataContainer: {
display: 'flex',
flexDirection: 'column',
gap: '24px',
},
withSubtitleContainer: {
display: 'flex',
flexDirection: 'row',
gap: '64px',
},
}));

function SystemData({ systemData, isLoading }) {
const classes = useStyles();
const { formatMessage } = useTranslations(MODULE_NAME);

if (isLoading) {
return <CircularProgress />;
}

const { worker, voucher, payment } = systemData;

return (
<>
<div className={classes.workerDataContainer}>
{Object.entries(worker).map(([key, value]) => (
<div key={key}>
<Typography className={classes.dataTitle}>{formatMessage(`SystemData.worker.${key}`)}</Typography>
<Typography className={classes.dataCount}>{value}</Typography>
</div>
))}
</div>
<div className={classes.voucherDataContainer}>
<div>
<Typography className={classes.dataTitle}>{formatMessage('SystemData.voucher.title')}</Typography>
<div className={classes.withSubtitleContainer}>
{Object.entries(voucher).map(([key, value]) => (
<div key={key}>
<Typography className={classes.dataSubtitle}>{formatMessage(`SystemData.voucher.${key}`)}</Typography>
<Typography className={classes.dataCount}>{value}</Typography>
</div>
))}
</div>
</div>
</div>
<div className={classes.paymentDataContainer}>
<div>
<Typography className={classes.dataTitle}>{formatMessage('SystemData.payment.title')}</Typography>
<div className={classes.withSubtitleContainer}>
{Object.entries(payment).map(([key, value]) => (
<div key={key}>
<Typography className={classes.dataSubtitle}>{formatMessage(`SystemData.payment.${key}`)}</Typography>
<Typography className={classes.dataCount}>{value}</Typography>
</div>
))}
</div>
</div>
</div>
</>
);
}

export default SystemData;
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export const REF_ROUTE_GROUP_LIST = 'workerVoucher.route.groups';
export const REF_ROUTE_WORKER_VOUCHER = 'workerVoucher.route.workerVoucher';
export const REF_ROUTE_WORKER_VOUCHERS = 'workerVoucher.route.workerVouchers';
export const REF_ROUTE_BILL = 'bill.route.bill';
export const REF_ROUTE_WORKER_ADD = 'workerVoucher.route.worker';
export const REF_ROUTE_ASSIGN_VOUCHER = 'workerVoucher.route.assignVoucher';
export const REF_ROUTE_ACQUIRE_VOUCHER = 'workerVoucher.route.acquireVoucher';
export const REF_GET_BILL_LINE_ITEM = 'bill.action.fetchBillLineItems';
export const ECONOMIC_UNIT_STORAGE_KEY = 'userEconomicUnit';

Expand Down
63 changes: 63 additions & 0 deletions src/hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-disable import/prefer-default-export */
import { useEffect, useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import _ from 'lodash';

import { fetchSystemData } from './actions';

export const useSystemData = (economicUnit) => {
const dispatch = useDispatch();
const prevEconomicUnitRef = useRef();
const [isLoading, setIsLoading] = useState(false);
const [systemData, setSystemData] = useState({
worker: { totalNumber: 0, activeNumber: 0 },
voucher: {
pending: 0,
unassigned: 0,
assigned: 0,
expired: 0,
cancelled: 0,
},
payment: { paid: 0, unpaid: 0 },
});

useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
try {
const response = await dispatch(fetchSystemData(economicUnit));
const payload = response.payload.data;

setSystemData({
worker: {
totalNumber: payload.totalNumber.totalCount,
activeNumber: payload.activeNumber.totalCount,
},
voucher: {
pending: payload.pending.totalCount,
unassigned: payload.unassigned.totalCount,
assigned: payload.assigned.totalCount,
expired: payload.expired.totalCount,
cancelled: payload.cancelled.totalCount,
},
payment: {
paid: payload.paid.totalCount,
unpaid: payload.unpaid.totalCount,
},
});
} catch (error) {
// eslint-disable-next-line no-console
console.error('[USE_SYSTEM_DATA_HOOK]: Error fetching system data.', error);
} finally {
setIsLoading(false);
}
};

if (!_.isEqual(economicUnit, prevEconomicUnitRef.current)) {
fetchData();
prevEconomicUnitRef.current = economicUnit;
}
}, [economicUnit, dispatch]);

return { systemData, isLoading };
};
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import WorkerSearcherSelectActions from './components/WorkerSearcherSelectAction
import GroupsPage from './pages/GroupsPage';
import GroupDetailsPage from './pages/GroupDetailsPage';
import PublicVoucherDetailsPage from './pages/PublicVoucherDetailsPage';
import DashboardPage from './pages/DashboardPage';

const ROUTE_PUBLIC_WORKER_VOUCHER_PAGE = 'voucher/check';
const ROUTE_WORKER_VOUCHERS_LIST = 'voucher/vouchers';
Expand All @@ -67,6 +68,8 @@ const DEFAULT_CONFIG = {
{ key: 'workerVoucher.route.worker', ref: ROUTE_WORKER_VOUCHER_WORKER },
{ key: 'workerVoucher.route.groups', ref: ROUTE_GROUP_LIST },
{ key: 'workerVoucher.route.group', ref: ROUTE_GROUP },
{ key: 'workerVoucher.route.assignVoucher', ref: ROUTE_WORKER_VOUCHER_ASSIGNMENT },
{ key: 'workerVoucher.route.acquireVoucher', ref: ROUTE_WORKER_VOUCHER_ACQUIREMENT },
{ key: 'workerVoucher.WorkerVoucherStatusPicker', ref: WorkerVoucherStatusPicker },
{ key: 'workerVoucher.VoucherAcquirementMethodPicker', ref: VoucherAcquirementMethodPicker },
{ key: 'workerVoucher.WorkerMultiplePicker', ref: WorkerMultiplePicker },
Expand Down Expand Up @@ -183,6 +186,7 @@ const DEFAULT_CONFIG = {
],
'workerVoucher.VoucherHeadPanel': [BillVoucherHeadPanel],
'workerVoucher.WorkerSearcherAction.select': WorkerSearcherSelectActions,
'home.HomePage.customDashboard': DashboardPage,
};

export const WorkerVoucherModule = (cfg) => ({ ...DEFAULT_CONFIG, ...cfg });
Loading

0 comments on commit 20dfc8a

Please sign in to comment.