Skip to content

Commit

Permalink
CM-832: added generating pdf reports - comments and grievance
Browse files Browse the repository at this point in the history
  • Loading branch information
sniedzielski committed Aug 8, 2024
1 parent 3d82f9a commit 9f3d992
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 10 deletions.
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,18 @@
"@rollup/plugin-json": "^4.0.3",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-url": "^5.0.0",
"rollup": "^2.10.0",
"eslint": "^7.32.0 || ^8.2.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0"
"eslint-plugin-react-hooks": "^4.3.0",
"rollup": "^2.10.0"
},
"files": [
"dist"
],
"dependencies": {}
"dependencies": {
"react-to-print": "^2.15.1"
}
}
28 changes: 26 additions & 2 deletions src/components/TicketCommentsPanel.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/* eslint-disable no-return-assign */
/* eslint-disable no-nested-ternary */
/* eslint-disable no-unused-vars */
/* eslint-disable react/destructuring-assignment */
/* eslint-disable react/sort-comp */
import React, { Component } from 'react';
import ReactToPrint, { PrintContextConsumer } from 'react-to-print';
import PrintIcon from '@material-ui/icons/Print';
import { withStyles, withTheme } from '@material-ui/core/styles';
import { connect } from 'react-redux';
import { injectIntl } from 'react-intl';
Expand All @@ -16,13 +19,16 @@ import {
withHistory,
withModulesManager,
} from '@openimis/fe-core';
import { IconButton, Paper, Tooltip } from '@material-ui/core';
import {
IconButton, Paper, Tooltip,
} from '@material-ui/core';
import ReplayIcon from '@material-ui/icons/Replay';
import DoneIcon from '@material-ui/icons/Done';
import { createTicketComment, fetchComments, resolveGrievanceByComment } from '../actions';
import GrievanceCommentDialog from '../dialogs/GrievanceCommentDialog';
import { isEmptyObject } from '../utils/utils';
import { MODULE_NAME, TICKET_STATUSES } from '../constants';
import TicketPrintCommentTemplate from './TicketPrintCommentTemplate';

const styles = (theme) => ({
paper: theme.paper.paper,
Expand Down Expand Up @@ -267,6 +273,19 @@ class TicketCommentPanel extends Component {
commenterType={commenterType}
disabled={this.isReadOnly()}
/>
<ReactToPrint content={() => this.componentRef}>
<PrintContextConsumer>
{({ handlePrint }) => (
<IconButton
variant="contained"
component="label"
onClick={handlePrint}
>
<PrintIcon />
</IconButton>
)}
</PrintContextConsumer>
</ReactToPrint>
</div>
<Table
module={MODULE_NAME}
Expand All @@ -287,7 +306,12 @@ class TicketCommentPanel extends Component {
defaultOrderBy="-dateCreated"
/>
</Paper>

<div style={{ display: 'none' }}>
<TicketPrintCommentTemplate
ref={(el) => (this.componentRef = el)}
ticketComments={ticketComments}
/>
</div>
</div>
);
}
Expand Down
139 changes: 139 additions & 0 deletions src/components/TicketPrintCommentTemplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* 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',
},
resolutionComment: {
color: '#d9534f',
fontWeight: 'bold',
},
}));

const TicketPrintCommentTemplate = forwardRef(({ ticketComments }, ref) => {
const classes = useStyles();
const modulesManager = useModulesManager();
const { formatMessage } = useTranslations(modulesManager, MODULE_NAME);

const formatCommenterName = (commenterTypeName, commenter) => {
if (!commenterTypeName) return 'Anonymous User';

if (commenterTypeName === 'individual') {
const commenterData = JSON.parse(JSON.parse(commenter));
return `Individual: ${commenterData.firstName} ${commenterData.lastName}`;
}

if (commenterTypeName === 'user') {
const commenterData = JSON.parse(JSON.parse(commenter));
return `User: ${commenterData.username}`;
}

return commenterTypeName;
};

const formatDate = (dateStr) => {
const date = new Date(dateStr);
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
};

return (
<div ref={ref} className={classes.containerPadding}>
<div className={classes.topHeader} />
<Divider className={classes.dividerMargin} />
<div className={classes.detailsContainer}>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.comments')}</p>
<div className={classes.detailValue}>
{ticketComments?.length > 0 ? (
ticketComments.map((comment) => (
<div
key={comment.id}
className={comment.isResolution ? classes.resolutionComment : ''}
style={{ marginBottom: '8px' }}
>
<strong>
{formatCommenterName(comment.commenterTypeName, comment.commenter)}
:
</strong>
{' '}
{comment.comment}
<div style={{ fontSize: '12px', color: '#777' }}>
{formatDate(comment.dateCreated)}
</div>
</div>
))
) : (
<p>{formatMessage('ticket.template.noComments')}</p>
)}
</div>
</div>
</div>
</div>
);
});

export default TicketPrintCommentTemplate;
154 changes: 154 additions & 0 deletions src/components/TicketPrintTemplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/* 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',
},
}));

const TicketPrintTemplate = forwardRef(({ ticket, reporter }, ref) => {
const classes = useStyles();
const modulesManager = useModulesManager();
const { formatMessage } = useTranslations(modulesManager, MODULE_NAME);

return (
<div ref={ref} className={classes.containerPadding}>
<div className={classes.topHeader} />
<Divider className={classes.dividerMargin} />
<div className={classes.detailsContainer}>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.title')}</p>
<p className={classes.detailValue}>{ticket.title}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.ticketCode')}</p>
<p className={classes.detailValue}>{ticket.code}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.status')}</p>
<p className={classes.detailValue}>{ticket.status}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.dateOfIncident')}</p>
<p className={classes.detailValue}>{ticket.dateOfIncident}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.channel')}</p>
<p className={classes.detailValue}>{ticket.channel}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.category')}</p>
<p className={classes.detailValue}>{ticket.category}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.flags')}</p>
<p className={classes.detailValue}>{ticket.flags}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.priority')}</p>
<p className={classes.detailValue}>{ticket.priority}</p>
</div>
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.description')}</p>
<p className={classes.detailValue}>{ticket.description}</p>
</div>
{ticket.reporterTypeName === 'individual' && (
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.reporter')}</p>
<p className={classes.detailValue}>
{reporter && reporter.individual
? `${reporter.individual.firstName} ${reporter.individual.lastName} ${reporter.individual.dob}`
: reporter
? `${reporter.firstName} ${reporter.lastName} ${reporter.dob}`
: EMPTY_STRING}
</p>
</div>
)}
{ticket.reporterTypeName === 'beneficiary' && (
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.reporter')}</p>
<p className={classes.detailValue}>
{reporter?.jsonExt?.national_id ?? ''}
</p>
</div>
)}
{ticket.reporterTypeName === null && (
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.reporter')}</p>
<p className={classes.detailValue}>{formatMessage('ticket.anonymousUser')}</p>
</div>
)}
<div className={classes.detailRow}>
<p className={classes.detailName}>{formatMessage('ticket.template.attendingStaff')}</p>
<p className={classes.detailValue}>{ticket?.attendingStaff?.username}</p>
</div>
</div>
</div>
);
});

export default TicketPrintTemplate;
Loading

0 comments on commit 9f3d992

Please sign in to comment.