diff --git a/package.json b/package.json index c3ac08c..c668984 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/actions.js b/src/actions.js index 1259ccc..ea07d23 100644 --- a/src/actions.js +++ b/src/actions.js @@ -1,3 +1,4 @@ +/* eslint-disable max-len */ import { decodeId, formatGQLString, @@ -54,7 +55,7 @@ const BENEFIT_CONSUMPTION_SUMMARY_PROJECTION = () => [ ]; const BENEFIT_ATTACHMENT_PROJECTION = () => [ - 'benefit{id, status, code, dateDue, receipt, individual {firstName, lastName}, jsonExt}', + 'benefit{id, status, code, dateDue, receipt, individual {firstName, lastName}, jsonExt, type, status, amount, receipt}', 'bill{id, code, terms, amountTotal, datePayed}', ]; diff --git a/src/components/PayrollBenefitPrintTemplate.js b/src/components/PayrollBenefitPrintTemplate.js new file mode 100644 index 0000000..e148176 --- /dev/null +++ b/src/components/PayrollBenefitPrintTemplate.js @@ -0,0 +1,145 @@ +/* eslint-disable max-len */ +/* eslint-disable react/no-array-index-key */ +/* eslint-disable no-nested-ternary */ +/* eslint-disable no-undef */ +import React, { + forwardRef, +} from 'react'; + +import { Divider } from '@material-ui/core'; +import { makeStyles } from '@material-ui/styles'; + +import { + useTranslations, useModulesManager, +} from '@openimis/fe-core'; +import { MODULE_NAME } 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', + }, + sectionTitle: { + fontWeight: '700', + fontSize: '18px', + textTransform: 'uppercase', + marginBottom: '12px', + }, +})); + +const PayrollBenefitPrintTemplate = forwardRef(({ benefitAttachments }, ref) => { + if (!benefitAttachments) return null; + const classes = useStyles(); + const modulesManager = useModulesManager(); + const { formatMessage } = useTranslations(modulesManager, MODULE_NAME); + + return ( +
+ {benefitAttachments.map((benefitAttachment, index) => ( +
+
+ {`Payment: ${benefitAttachment.benefit.code} - ${benefitAttachment.benefit.individual.firstName}, ${benefitAttachment.benefit.individual.lastName}`} +
+
+
{formatMessage('payroll.benefitConsumption.individual.firstName')}
+
{benefitAttachment.benefit.individual.firstName}
+
+
+
{formatMessage('payroll.benefitConsumption.individual.lastName')}
+
{benefitAttachment.benefit.individual.lastName}
+
+
+
{formatMessage('payroll.benefitConsumption.code')}
+
{benefitAttachment.benefit.code}
+
+
+
{formatMessage('payroll.benefitConsumption.dateDue')}
+
{benefitAttachment.benefit.dateDue}
+
+
+
{formatMessage('payroll.benefitConsumption.receipt')}
+
{benefitAttachment.benefit.receipt}
+
+
+
{formatMessage('payroll.benefitConsumption.amount')}
+
{benefitAttachment.benefit.amount}
+
+
+
{formatMessage('payroll.benefitConsumption.type')}
+
{benefitAttachment.benefit.type}
+
+
+
{formatMessage('payroll.benefitConsumption.status')}
+
{benefitAttachment.benefit.status}
+
+
+
{formatMessage('payroll.benefitConsumption.payedOnTime')}
+
{benefitAttachment.benefit.payedOnTime ? 'Yes' : 'No'}
+
+
+
{formatMessage('payroll.benefitConsumption.paymentDate')}
+
+ {!benefitAttachment.benefit.receipt + ? '' + : benefitAttachment?.bill?.datePayed} +
+
+ +
+ ))} +
+ ); +}); + +export default PayrollBenefitPrintTemplate; diff --git a/src/components/PayrollPrintTemplate.js b/src/components/PayrollPrintTemplate.js new file mode 100644 index 0000000..1355f27 --- /dev/null +++ b/src/components/PayrollPrintTemplate.js @@ -0,0 +1,141 @@ +/* eslint-disable max-len */ +/* eslint-disable react/no-array-index-key */ +/* eslint-disable no-nested-ternary */ +/* eslint-disable no-undef */ +import React, { + forwardRef, +} from 'react'; + +import { Divider } from '@material-ui/core'; +import { makeStyles } from '@material-ui/styles'; + +import { + useTranslations, useModulesManager, +} from '@openimis/fe-core'; +import { MODULE_NAME } 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', + }, + sectionTitle: { + fontWeight: '700', + fontSize: '18px', + textTransform: 'uppercase', + marginBottom: '12px', + }, +})); + +const PayrollPrintTemplate = forwardRef(({ benefitConsumptions }, ref) => { + if (!benefitConsumptions) return null; + const classes = useStyles(); + const modulesManager = useModulesManager(); + const { formatMessage } = useTranslations(modulesManager, MODULE_NAME); + + return ( +
+ {benefitConsumptions.map((benefitConsumption, index) => ( +
+
+ {`Payment: ${benefitConsumption.code} - ${benefitConsumption.individual.firstName}, ${benefitConsumption.individual.lastName}`} +
+
+
{formatMessage('payroll.benefitConsumption.individual.firstName')}
+
{benefitConsumption.individual.firstName}
+
+
+
{formatMessage('payroll.benefitConsumption.individual.lastName')}
+
{benefitConsumption.individual.lastName}
+
+
+
{formatMessage('payroll.benefitConsumption.code')}
+
{benefitConsumption.code}
+
+
+
{formatMessage('payroll.benefitConsumption.dateDue')}
+
{benefitConsumption.dateDue}
+
+
+
{formatMessage('payroll.benefitConsumption.receipt')}
+
{benefitConsumption.receipt}
+
+
+
{formatMessage('payroll.benefitConsumption.amount')}
+
{benefitConsumption.amount}
+
+
+
{formatMessage('payroll.benefitConsumption.type')}
+
{benefitConsumption.type}
+
+
+
{formatMessage('payroll.benefitConsumption.status')}
+
{benefitConsumption.status}
+
+
+
{formatMessage('payroll.benefitConsumption.paymentDate')}
+
+ {!benefitConsumption.receipt + ? '' + : benefitConsumption?.benefitAttachment[0]?.bill?.datePayed} +
+
+ +
+ ))} +
+ ); +}); + +export default PayrollPrintTemplate; diff --git a/src/components/payroll/BenefitConsumptionSearcher.js b/src/components/payroll/BenefitConsumptionSearcher.js index 7893ab6..8d32bbb 100644 --- a/src/components/payroll/BenefitConsumptionSearcher.js +++ b/src/components/payroll/BenefitConsumptionSearcher.js @@ -1,7 +1,14 @@ +/* eslint-disable max-len */ +/* eslint-disable no-return-assign */ /* eslint-disable no-param-reassign */ -import React from 'react'; +import React, { useRef } from 'react'; +import { useReactToPrint } from 'react-to-print'; +import PrintIcon from '@material-ui/icons/Print'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import { + Typography, Button, +} from '@material-ui/core'; import { Searcher, useModulesManager, useTranslations, @@ -11,6 +18,7 @@ import { fetchBenefitConsumptions } from '../../actions'; import { BENEFIT_CONSUMPTION_STATUS, DEFAULT_PAGE_SIZE, ROWS_PER_PAGE_OPTIONS } from '../../constants'; import BenefitConsumptionFilter from './BenefitConsumptionFilter'; import AdditionalFieldsDialog from './dialogs/AdditionalFieldsDialog'; +import PayrollPrintTemplate from '../PayrollPrintTemplate'; function BenefitConsumptionSearcher({ fetchBenefitConsumptions, @@ -25,6 +33,11 @@ function BenefitConsumptionSearcher({ }) { const modulesManager = useModulesManager(); const { formatMessageWithValues } = useTranslations('payroll', modulesManager); + const payrollPrintTemplateRef = useRef(null); + + const handlePrint = useReactToPrint({ + documentTitle: `${payrollUuid}`, + }); const fetch = (params) => fetchBenefitConsumptions(modulesManager, params); @@ -127,28 +140,48 @@ function BenefitConsumptionSearcher({ ); return ( -
- -
+ <> +
+ +
+
+ +
+ +
+
+ ); } diff --git a/src/components/payroll/BenefitConsumptionSearcherModal.js b/src/components/payroll/BenefitConsumptionSearcherModal.js index 8d8d15a..623a9f2 100644 --- a/src/components/payroll/BenefitConsumptionSearcherModal.js +++ b/src/components/payroll/BenefitConsumptionSearcherModal.js @@ -1,9 +1,13 @@ +/* eslint-disable max-len */ /* eslint-disable no-param-reassign */ -import React, { useState } from 'react'; +import React, { useState, useRef } from 'react'; +import { useReactToPrint } from 'react-to-print'; +import PrintIcon from '@material-ui/icons/Print'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; +import Typography from '@material-ui/core/Typography'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; @@ -20,6 +24,7 @@ import BenefitConsumptionFilterModal from './BenefitConsumptionFilterModal'; import ErrorSummaryModal from './dialogs/ErrorSummaryModal'; import { mutationLabel } from '../../utils/string-utils'; import AdditionalFieldsDialog from './dialogs/AdditionalFieldsDialog'; +import PayrollBenefitPrintTemplate from '../PayrollBenefitPrintTemplate'; function BenefitConsumptionSearcherModal({ fetchBenefitAttachments, @@ -39,6 +44,11 @@ function BenefitConsumptionSearcherModal({ const [selectedBenefitAttachment, setSelectedBenefitAttachment] = useState(null); const [openConfirmDialog, setOpenConfirmDialog] = useState(false); const [benefitToDelete, setBenefitToDelete] = useState(null); + const payrollPrintTemplateRef = useRef(null); + + const handlePrint = useReactToPrint({ + documentTitle: `${payrollUuid}`, + }); const fetch = (params) => { fetchBenefitAttachments(modulesManager, params); @@ -193,54 +203,74 @@ function BenefitConsumptionSearcherModal({ ); return ( -
- - {selectedBenefitAttachment && ( + <> +
+ +
+
+ + {selectedBenefitAttachment && ( setSelectedBenefitAttachment(null)} benefitAttachment={selectedBenefitAttachment} /> - )} - setOpenConfirmDialog(false)} - > - {formatMessage('benefitConsumption.delete.confirm.title')} - - - {formatMessage('benefitConsumption.delete.confirm.message')} - - - - - - - -
+ )} + setOpenConfirmDialog(false)} + > + {formatMessage('benefitConsumption.delete.confirm.title')} + + + {formatMessage('benefitConsumption.delete.confirm.message')} + + + + + + + +
+ +
+
+ ); } diff --git a/src/utils/last-day-month.js b/src/utils/last-day-month.js new file mode 100644 index 0000000..d8516a2 --- /dev/null +++ b/src/utils/last-day-month.js @@ -0,0 +1,9 @@ +export default function getLastDayOfMonth(runMonth, runYear) { + // Create a new Date object for the first day of the next month + const nextMonthDate = new Date(runYear, runMonth, 1); + + // Subtract 1 day from the first day of the next month to get the last day of the current month + const lastDayOfMonth = new Date(nextMonthDate - 1); + + return lastDayOfMonth; +}