Skip to content

Commit

Permalink
Merge pull request #11 from openimis/feature/OPL-63
Browse files Browse the repository at this point in the history
OPL-63: Bill - Add Events tab to card page
  • Loading branch information
delcroip authored Feb 22, 2022
2 parents b5d014d + 5aad563 commit 285ee4a
Show file tree
Hide file tree
Showing 11 changed files with 432 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ It is dedicated to be deployed as a module of [openimis-fe_js](https://github.co
* `BILL_CREATE_BILL_PAYMENT_RESP` receiving a result of create Bill Payment mutation
* `BILL_UPDATE_BILL_PAYMENT_RESP` receiving a result of update Bill Payment mutation
* `BILL_DELETE_BILL_PAYMENT_RESP` receiving a result of delete Bill Payment mutation
* `BILL_BILL_EVENTS_{REQ|RESP|ERR}` fetching Bill Events (as triggered by the searcher)
* `BILL_CREATE_BILL_EVENT_MESSAGE_RESP` receiving a result of create Bill Event Message mutation

## Other Modules Listened Redux Actions
None
Expand Down
43 changes: 41 additions & 2 deletions src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ const formatBillPaymentGQL = (payment) =>
${!!payment.paymentOrigin ? `paymentOrigin: "${payment.paymentOrigin}"` : ""}
`;

const formatBillEventMessageGQL = (eventMessage) =>
`
${!!eventMessage.billId ? `billId: "${eventMessage.billId}"` : ""}
${!!eventMessage.eventType ? `eventType: ${eventMessage.eventType}` : ""}
${!!eventMessage.message ? `message: "${eventMessage.message}"` : ""}
`;

export function fetchInvoices(params) {
const payload = formatPageQueryWithCount("invoice", params, INVOICE_FULL_PROJECTION);
return graphql(payload, ACTION_TYPE.SEARCH_INVOICES);
Expand Down Expand Up @@ -313,7 +320,11 @@ export function fetchBillPayments(params) {
}

export function createBillPayment(billPayment, clientMutationLabel) {
const mutation = formatMutation("createBillPayment", formatBillPaymentGQL(billPayment), clientMutationLabel);
const mutation = formatMutation(
"createBillPayment",
formatBillPaymentGQL(billPayment),
clientMutationLabel
);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
Expand All @@ -328,7 +339,11 @@ export function createBillPayment(billPayment, clientMutationLabel) {
}

export function updateBillPayment(billPayment, clientMutationLabel) {
const mutation = formatMutation("updateBillPayment", formatBillPaymentGQL(billPayment), clientMutationLabel);
const mutation = formatMutation(
"updateBillPayment",
formatBillPaymentGQL(billPayment),
clientMutationLabel
);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
Expand Down Expand Up @@ -357,3 +372,27 @@ export function deleteBillPayment(billPayment, clientMutationLabel) {
},
);
}

export function fetchBillEvents(params) {
const payload = formatPageQueryWithCount("billEvent", params, INVOICE_EVENT_FULL_PROJECTION);
return graphql(payload, ACTION_TYPE.SEARCH_BILL_EVENTS);
}

export function createBillEventType(billEvent, clientMutationLabel) {
const mutation = formatMutation(
"createBillEventType",
formatBillEventMessageGQL(billEvent),
clientMutationLabel
);
const requestedDateTime = new Date();
return graphql(
mutation.payload,
[REQUEST(ACTION_TYPE.MUTATION), SUCCESS(ACTION_TYPE.CREATE_BILL_EVENT_MESSAGE), ERROR(ACTION_TYPE.MUTATION)],
{
actionType: ACTION_TYPE.CREATE_BILL_EVENT_MESSAGE,
clientMutationId: mutation.clientMutationId,
clientMutationLabel,
requestedDateTime,
},
);
}
59 changes: 59 additions & 0 deletions src/components/BillEventsFilter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from "react";
import { injectIntl } from "react-intl";
import { withModulesManager, formatMessage, TextInput } from "@openimis/fe-core";
import { Grid } from "@material-ui/core";
import { withTheme, withStyles } from "@material-ui/core/styles";
import { CONTAINS_LOOKUP, DEFUALT_DEBOUNCE_TIME } from "../constants";
import _debounce from "lodash/debounce";
import { defaultFilterStyles } from "../util/styles";
import InvoiceEventTypePicker from "../pickers/InvoiceEventTypePicker";

const BillEventsFilter = ({intl, classes, filters, onChangeFilters }) => {
const debouncedOnChangeFilters = _debounce(onChangeFilters, DEFUALT_DEBOUNCE_TIME);

const filterValue = (filterName) => filters?.[filterName]?.value;

const onChangeStringFilter =
(filterName, lookup = null) =>
(value) => {
lookup
? debouncedOnChangeFilters([
{
id: filterName,
value,
filter: `${filterName}_${lookup}: "${value}"`,
},
])
: onChangeFilters([
{
id: filterName,
value,
filter: `${filterName}: "${value}"`,
},
]);
};

return (
<Grid container className={classes.form}>
<Grid item xs={2} className={classes.item}>
<InvoiceEventTypePicker
label="billEvent.eventType.label"
withNull
nullLabel={formatMessage(intl, "invoice", "any")}
value={filterValue("eventType")}
onChange={onChangeStringFilter("eventType")}
/>
</Grid>
<Grid item xs={2} className={classes.item}>
<TextInput
module="invoice"
label="billEvent.message"
value={filterValue("message")}
onChange={onChangeStringFilter("message", CONTAINS_LOOKUP)}
/>
</Grid>
</Grid>
);
};

export default injectIntl(withTheme(withStyles(defaultFilterStyles)(BillEventsFilter)));
125 changes: 125 additions & 0 deletions src/components/BillEventsSearcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { useRef, useEffect, useState } from "react";
import { injectIntl } from "react-intl";
import { formatMessageWithValues, Searcher } from "@openimis/fe-core";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { fetchBillEvents } from "../actions";
import { DEFAULT_PAGE_SIZE, ROWS_PER_PAGE_OPTIONS} from "../constants";
import BillEventsFilter from "./BillEventsFilter";
import InvoiceEventTypePicker from "../pickers/InvoiceEventTypePicker"
import { ACTION_TYPE } from "../reducer";

const BillEventsSearcher = ({
intl,
bill,
submittingMutation,
mutation,
fetchBillEvents,
fetchingBillEvents,
fetchedBillEvents,
errorBillEvents,
billEvents,
billEventsPageInfo,
billEventsTotalCount,
}) => {
const [queryParams, setQueryParams] = useState([]);
const prevSubmittingMutationRef = useRef();

useEffect(() => {
if (
prevSubmittingMutationRef.current &&
!submittingMutation &&
mutation?.actionType === ACTION_TYPE.CREATE_BILL_EVENT_MESSAGE
) {
refetch();
}
}, [submittingMutation]);

useEffect(() => {
prevSubmittingMutationRef.current = submittingMutation;
});

const fetch = (params) => fetchBillEvents(params);

const refetch = () => fetch(queryParams);

const filtersToQueryParams = ({ filters, pageSize, beforeCursor, afterCursor, orderBy }) => {
const queryParams = Object.keys(filters)
.filter((f) => !!filters[f]["filter"])
.map((f) => filters[f]["filter"]);
pageSize && queryParams.push(`first: ${pageSize}`);
beforeCursor && queryParams.push(`before: "${beforeCursor}"`);
afterCursor && queryParams.push(`after: "${afterCursor}"`);
orderBy && queryParams.push(`orderBy: ["${orderBy}"]`);
setQueryParams(queryParams);
return queryParams;
};

const headers = () => [
"billEvent.eventType.label",
"billEvent.message",
];

const itemFormatters = () => [
(billEvent) => <InvoiceEventTypePicker value={billEvent?.eventType} readOnly />,
(billEvent) => billEvent.message,
];

const sorts = () => [
["eventType", true],
["message", true],
];

const defaultFilters = () => ({
bill_Id: {
value: bill?.id,
filter: `bill_Id: "${bill?.id}"`,
},
isDeleted: {
value: false,
filter: "isDeleted: false",
},
});

return (
!!bill?.id && (
<Searcher
module="invoice"
FilterPane={BillEventsFilter}
fetch={fetch}
items={billEvents}
itemsPageInfo={billEventsPageInfo}
fetchingItems={fetchingBillEvents}
fetchedItems={fetchedBillEvents}
errorItems={errorBillEvents}
tableTitle={formatMessageWithValues(intl, "invoice", "billEvents.searcherResultsTitle", {
billEventsTotalCount,
})}
filtersToQueryParams={filtersToQueryParams}
headers={headers}
itemFormatters={itemFormatters}
sorts={sorts}
rowsPerPageOptions={ROWS_PER_PAGE_OPTIONS}
defaultPageSize={DEFAULT_PAGE_SIZE}
defaultOrderBy="eventType"
defaultFilters={defaultFilters()}
/>
)
);
};

const mapStateToProps = (state) => ({
fetchingBillEvents: state.invoice.fetchingBillEvents,
fetchedBillEvents: state.invoice.fetchedBillEvents,
errorBillEvents: state.invoice.errorBillEvents,
billEvents: state.invoice.billEvents,
billEventsPageInfo: state.invoice.billEventsPageInfo,
billEventsTotalCount: state.invoice.billEventsTotalCount,
submittingMutation: state.invoice.submittingMutation,
mutation: state.invoice.mutation,
confirmed: state.core.confirmed,
});

const mapDispatchToProps = (dispatch) => bindActionCreators({ fetchBillEvents }, dispatch);

export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(BillEventsSearcher));
40 changes: 40 additions & 0 deletions src/components/BillEventsTab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { Tab, Grid, Typography } from "@material-ui/core";
import { formatMessage, PublishedComponent, FormattedMessage } from "@openimis/fe-core";
import { BILL_EVENTS_TAB_VALUE, RIGHT_BILL_EVENT_SEARCH, RIGHT_BILL_EVENT_CREATE_MESSAGE } from "../constants";
import BillEventsSearcher from "./BillEventsSearcher";
import CreateBillEventMessageDialog from "../dialogs/BillEventMessageDialog";


const BillEventsTabLabel = ({ intl, rights, onChange, tabStyle, isSelected }) =>
rights?.includes(RIGHT_BILL_EVENT_SEARCH) && (
<Tab
onChange={onChange}
className={tabStyle(BILL_EVENTS_TAB_VALUE)}
selected={isSelected(BILL_EVENTS_TAB_VALUE)}
value={BILL_EVENTS_TAB_VALUE}
label={formatMessage(intl, "invoice", "billEvents.label")}
/>
);


const BillEventsTabPanel = ({ rights, value, bill }) => (
<PublishedComponent pubRef="policyHolder.TabPanel" module="bill" index={BILL_EVENTS_TAB_VALUE} value={value}>
{rights?.includes(RIGHT_BILL_EVENT_CREATE_MESSAGE) && (
<Grid container justify="flex-end" alignItems="center" spacing={1}>
<Grid item>
<Typography>
<FormattedMessage module="invoice" id="billEventMessage.create.label" />
</Typography>
</Grid>
<Grid item>
<CreateBillEventMessageDialog bill={bill} />
</Grid>
</Grid>
)}
<BillEventsSearcher bill={bill} />
</PublishedComponent>
);


export { BillEventsTabLabel, BillEventsTabPanel };
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const BILL_TABS_PANEL_CONTRIBUTION_KEY = "bill.TabPanel.panel";
export const BILL_TABS_LABEL_CONTRIBUTION_KEY = "bill.TabPanel.label";
export const BILL_LINE_ITEMS_TAB_VALUE = "billLineItemsTab";
export const BILL_PAYMENTS_TAB_VALUE = "billPaymentsTab";
export const BILL_EVENTS_TAB_VALUE = "billEventsTab";

export const EMPTY_PAYMENT = {
status: null,
Expand Down
Loading

0 comments on commit 285ee4a

Please sign in to comment.