diff --git a/package.json b/package.json index c5f2d3c..6e4a7f3 100644 --- a/package.json +++ b/package.json @@ -43,5 +43,7 @@ "files": [ "dist" ], - "dependencies": {} + "dependencies": { + "react-to-print": "^2.15.1" + } } diff --git a/src/components/VoucherDetailsPanel.js b/src/components/VoucherDetailsPanel.js index 6430d90..ad59434 100644 --- a/src/components/VoucherDetailsPanel.js +++ b/src/components/VoucherDetailsPanel.js @@ -1,12 +1,22 @@ -import React from 'react'; +/* eslint-disable import/no-extraneous-dependencies */ +import React, { useRef } from 'react'; +import { useReactToPrint } from 'react-to-print'; -import { Divider, Grid, Typography } from '@material-ui/core'; +import { + Divider, Grid, Typography, Button, +} from '@material-ui/core'; import { makeStyles } from '@material-ui/styles'; +import PrintIcon from '@material-ui/icons/Print'; +import ReceiptIcon from '@material-ui/icons/Receipt'; -import { FormattedMessage } from '@openimis/fe-core'; +import { + FormattedMessage, useModulesManager, useHistory, historyPush, +} from '@openimis/fe-core'; +import { REF_ROUTE_BILL, VOUCHER_RIGHT_SEARCH } from '../constants'; import VoucherDetailsEmployer from './VoucherDetailsEmployer'; import VoucherDetailsVoucher from './VoucherDetailsVoucher'; import VoucherDetailsWorker from './VoucherDetailsWorker'; +import VoucherDetailsPrintTemplate from './VoucherDetailsPrintTemplate'; const useStyles = makeStyles((theme) => ({ tableTitle: theme.table.title, @@ -14,19 +24,35 @@ const useStyles = makeStyles((theme) => ({ fullHeight: { height: '100%', }, + actionButtons: { + display: 'flex', + flexDirection: 'row', + gap: '4px', + }, })); -function VoucherDetailsPanel({ workerVoucher, readOnly = true, formatMessage }) { +function VoucherDetailsPanel({ + workerVoucher, readOnly = true, formatMessage, rights, logo, +}) { + const modulesManager = useModulesManager(); + const history = useHistory(); + const voucherPrintTemplateRef = useRef(null); const classes = useStyles(); + const handlePrint = useReactToPrint({ + documentTitle: `${workerVoucher.code}`, + }); + + const redirectToTheLinkedBill = () => historyPush(modulesManager, history, REF_ROUTE_BILL, [workerVoucher.billId]); + return ( - <> +
@@ -34,6 +60,31 @@ function VoucherDetailsPanel({ workerVoucher, readOnly = true, formatMessage }) + {rights.includes(VOUCHER_RIGHT_SEARCH) && ( + + + + + )} @@ -43,17 +94,12 @@ function VoucherDetailsPanel({ workerVoucher, readOnly = true, formatMessage }) classes={classes} formatMessage={formatMessage} /> - - - + + +
+ +
+
); } diff --git a/src/components/VoucherDetailsPrintTemplate.js b/src/components/VoucherDetailsPrintTemplate.js new file mode 100644 index 0000000..9aaf458 --- /dev/null +++ b/src/components/VoucherDetailsPrintTemplate.js @@ -0,0 +1,140 @@ +import React, { + forwardRef, useState, useEffect, useMemo, +} from 'react'; +import { useDispatch } from 'react-redux'; + +import { Divider } from '@material-ui/core'; +import { makeStyles } from '@material-ui/styles'; + +import { useTranslations, useModulesManager, formatDateFromISO } from '@openimis/fe-core'; +import { MODULE_NAME, REF_GET_BILL_LINE_ITEM } from '../constants'; + +const useStyles = makeStyles(() => ({ + topHeader: { + display: 'flex', + justifyContent: 'start', + alignItems: 'center', + width: '100%', + + '& img': { + minWidth: '250px', + maxWidth: '300px', + width: 'auto', + height: 'auto', + }, + }, + printContainer: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: '20px', + fontWeight: '500', + }, + date: { + fontSize: '16px', + }, + detailsContainer: { + display: 'flex', + flexDirection: 'column', + padding: '12px', + width: '100%', + }, + detailRow: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + padding: '4px', + }, + detailName: { + fontWeight: '600', + fontSize: '16px', + textTransform: 'uppercase', + }, + detailValue: { + fontWeight: '500', + backgroundColor: '#f5f5f5', + padding: '6px', + borderRadius: '8px', + fontSize: '15px', + }, + containerPadding: { + padding: '32px', + }, + dividerMargin: { + margin: '12px 0', + }, +})); + +const VoucherDetailsPrintTemplate = forwardRef(({ workerVoucher, logo }, ref) => { + const dispatch = useDispatch(); + const classes = useStyles(); + const modulesManager = useModulesManager(); + const { formatMessage } = useTranslations(modulesManager, MODULE_NAME); + + const getBillLineItem = useMemo(() => modulesManager.getRef(REF_GET_BILL_LINE_ITEM), [modulesManager]); + const [voucherValue, setVoucherValue] = useState(null); + + useEffect(() => { + const fetchVoucherValue = async () => { + try { + const value = await dispatch(getBillLineItem([`lineId: "${workerVoucher.uuid}"`])).then( + (response) => response?.payload?.data?.billItem?.edges?.[0]?.node?.unitPrice, + ); + + setVoucherValue(value); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error fetching voucher value:', error); + } + }; + + fetchVoucherValue(); + }, [dispatch, getBillLineItem, workerVoucher.uuid]); + + return ( +
+
+ Logo of Ministerul Muncii și Protecţiei Sociale al Republicii Moldova +
+ +
+
+

{formatMessage('workerVoucher.template.voucherCode')}

+

{workerVoucher.code}

+
+
+

{formatMessage('workerVoucher.template.status')}

+

{workerVoucher.status}

+
+
+

{formatMessage('workerVoucher.template.worker')}

+

+ {`${workerVoucher.insuree?.otherNames} ${workerVoucher.insuree?.lastName}`} +

+
+
+

{formatMessage('workerVoucher.template.employer')}

+

+ {`${workerVoucher.policyholder?.code} ${workerVoucher.policyholder?.tradeName}`} +

+
+
+

{formatMessage('workerVoucher.template.createdDate')}

+

{formatDateFromISO(modulesManager, null, workerVoucher.dateCreated)}

+
+
+

{formatMessage('workerVoucher.template.assignedDate')}

+

{formatDateFromISO(modulesManager, null, workerVoucher.assignedDate)}

+
+
+

{formatMessage('workerVoucher.template.valueOfVoucher')}

+

{`${formatMessage('currency')} ${voucherValue}`}

+
+
+
+ ); +}); + +export default VoucherDetailsPrintTemplate; diff --git a/src/constants.js b/src/constants.js index 645b8c2..7355a3e 100644 --- a/src/constants.js +++ b/src/constants.js @@ -8,6 +8,7 @@ export const MODULE_NAME = 'workerVoucher'; 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_GET_BILL_LINE_ITEM = 'bill.action.fetchBillLineItems'; export const ECONOMIC_UNIT_STORAGE_KEY = 'userEconomicUnit'; export const MPAY_BILL_URL = '/msystems/mpay_payment/'; diff --git a/src/pages/VoucherDetailsPage.js b/src/pages/VoucherDetailsPage.js index 70426f8..971aff0 100644 --- a/src/pages/VoucherDetailsPage.js +++ b/src/pages/VoucherDetailsPage.js @@ -2,14 +2,13 @@ import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { makeStyles } from '@material-ui/styles'; -import ReceiptIcon from '@material-ui/icons/Receipt'; import { - Form, Helmet, useHistory, useModulesManager, useTranslations, historyPush, + Form, Helmet, useHistory, useModulesManager, useTranslations, } from '@openimis/fe-core'; import { clearWorkerVoucher, fetchWorkerVoucher } from '../actions'; import { - EMPTY_STRING, MODULE_NAME, REF_ROUTE_BILL, VOUCHER_RIGHT_SEARCH, + EMPTY_STRING, MODULE_NAME, VOUCHER_RIGHT_SEARCH, } from '../constants'; import VoucherDetailsPanel from '../components/VoucherDetailsPanel'; @@ -17,7 +16,7 @@ const useStyles = makeStyles((theme) => ({ page: theme.page, })); -function VoucherDetailsPage({ match }) { +function VoucherDetailsPage({ match, logo }) { const classes = useStyles(); const dispatch = useDispatch(); const modulesManager = useModulesManager(); @@ -44,17 +43,6 @@ function VoucherDetailsPage({ match }) { return () => dispatch(clearWorkerVoucher()); }, [workerVoucherUuid]); - const redirectToTheLinkedBill = () => historyPush(modulesManager, history, REF_ROUTE_BILL, [workerVoucher.billId]); - - const voucherActions = [ - { - doIt: redirectToTheLinkedBill, - icon: , - disabled: !workerVoucher?.billId, - tooltip: formatMessage('navigateToTheBill.tooltip'), - }, - ]; - return ( rights.includes(VOUCHER_RIGHT_SEARCH) && (
@@ -70,9 +58,9 @@ function VoucherDetailsPage({ match }) { back={() => history.goBack()} HeadPanel={VoucherDetailsPanel} readOnly + logo={logo} formatMessage={formatMessage} rights={rights} - actions={voucherActions} />
) diff --git a/src/translations/en.json b/src/translations/en.json index db8b5b8..702ee4a 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -93,5 +93,14 @@ "workerVoucher.filter.date": "Date", "business_config.validation.date_range_overlap": "Unable to create the voucher price for the specified period. There is an existing voucher price defined within the selected date range.", "workerVoucher.navigateToTheBill.tooltip": "Bill", - "workerVoucher.MPayBillButton": "Pay with MPay" + "workerVoucher.MPayBillButton": "Pay with MPay", + "workerVoucher.printVoucher": "Print", + "workerVoucher.printVoucher.title": "Voucher {voucherCode}", + "workerVoucher.template.voucherCode": "Voucher Code", + "workerVoucher.template.status": "Status", + "workerVoucher.template.worker": "Worker", + "workerVoucher.template.employer": "Employer", + "workerVoucher.template.createdDate": "Created Date", + "workerVoucher.template.assignedDate": "Assigned Date", + "workerVoucher.template.valueOfVoucher": "Value of voucher" }