diff --git a/package.json b/package.json index 8243f06a5..42d52b3d3 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "moment-duration-format": "^2.3.2", "moment-timezone": "^0.5.33", "mui-color-input": "^9.0.0", - "openstack-uicore-foundation": "5.0.43", + "openstack-uicore-foundation": "5.0.46-beta.2", "p-limit": "^6.1.0", "path-browserify": "^1.0.1", "postcss-loader": "^6.2.1", diff --git a/src/actions/sponsor-purchases-actions.js b/src/actions/sponsor-purchases-actions.js index 868acbebc..c91726d98 100644 --- a/src/actions/sponsor-purchases-actions.js +++ b/src/actions/sponsor-purchases-actions.js @@ -297,29 +297,33 @@ export const rejectSponsorPurchase = }); }; -export const getSponsorOrder = (orderId) => async (dispatch, getState) => { - const { currentSummitState, currentSponsorState } = getState(); - const { currentSummit } = currentSummitState; - const { entity: sponsor } = currentSponsorState; - const accessToken = await getAccessTokenSafely(); - - dispatch(startLoading()); - - const params = { - access_token: accessToken, - expand: - "forms,forms.items,forms.items.meta_fields,forms.items.type,refunds,payments,notes,fees" - }; +export const getSponsorOrder = + (orderId, sponsorId = null) => + async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const { currentSummit } = currentSummitState; + const { entity: sponsor } = currentSponsorState; + const accessToken = await getAccessTokenSafely(); - return getRequest( - null, - createAction(RECEIVE_SPONSOR_ORDER), - `${window.PURCHASES_API_URL}/api/v2/summits/${currentSummit.id}/sponsors/${sponsor.id}/purchases/${orderId}`, - authErrorHandler - )(params)(dispatch).finally(() => { - dispatch(stopLoading()); - }); -}; + const sponsor_id = sponsor.id || sponsorId; + + dispatch(startLoading()); + + const params = { + access_token: accessToken, + expand: + "forms,forms.items,forms.items.meta_fields,forms.items.type,refunds,payments,notes,fees" + }; + + return getRequest( + null, + createAction(RECEIVE_SPONSOR_ORDER), + `${window.PURCHASES_API_URL}/api/v2/summits/${currentSummit.id}/sponsors/${sponsor_id}/purchases/${orderId}`, + authErrorHandler + )(params)(dispatch).finally(() => { + dispatch(stopLoading()); + }); + }; export const clearSponsorOrder = () => async (dispatch) => { dispatch(createAction(CLEAR_SPONSOR_ORDER)({})); diff --git a/src/assets/fn-invoice-header.png b/src/assets/fn-invoice-header.png new file mode 100644 index 000000000..952fefeba Binary files /dev/null and b/src/assets/fn-invoice-header.png differ diff --git a/src/i18n/en.json b/src/i18n/en.json index 90d959ede..c208be4e5 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -11,7 +11,8 @@ "entity_not_found": "The entity you are looking for was not found.", "maximum_files": "Maximum number of files has been reached", "payment_profile_not_found_title": "Payment Profile not found", - "payment_profile_not_found": "Missing payment profile for summit {{summitName}}. Please contact support." + "payment_profile_not_found": "Missing payment profile for summit {{summitName}}. Please contact support.", + "invoice_generation": "Invoice could not be generated. Please contact support." }, "general": { "summit": "Event", diff --git a/src/pages/sponsors/show-purchase-list-page/index.js b/src/pages/sponsors/show-purchase-list-page/index.js index 070e03f9f..c7d5639fe 100644 --- a/src/pages/sponsors/show-purchase-list-page/index.js +++ b/src/pages/sponsors/show-purchase-list-page/index.js @@ -11,7 +11,7 @@ * limitations under the License. * */ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; import { Breadcrumb } from "react-breadcrumbs"; @@ -26,11 +26,14 @@ import { import DownloadIcon from "@mui/icons-material/Download"; import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; import SearchInput from "openstack-uicore-foundation/lib/components/mui/search-input"; +import { useSnackbarMessage } from "openstack-uicore-foundation/lib/components/mui/snackbar-notification"; +import { generateInvoicePDF } from "openstack-uicore-foundation/lib/components/order-invoice-pdf"; import history from "../../../history"; import { approveSponsorPurchase, exportAllSponsorPurchases, getAllSponsorPurchases, + getSponsorOrder, rejectSponsorPurchase } from "../../../actions/sponsor-purchases-actions"; import { @@ -38,6 +41,7 @@ import { PURCHASE_METHODS, PURCHASE_STATUS } from "../../../utils/constants"; +import logoInvoice from "../../../assets/fn-invoice-header.png"; const ShowPurchaseListPage = ({ match, @@ -49,14 +53,19 @@ const ShowPurchaseListPage = ({ perPage, totalCount, getAllSponsorPurchases, + getSponsorOrder, exportAllSponsorPurchases, approveSponsorPurchase, - rejectSponsorPurchase + rejectSponsorPurchase, + currentSummit }) => { useEffect(() => { getAllSponsorPurchases(); }, []); + const { errorMessage } = useSnackbarMessage(); + const [loadingPDF, setLoadingPDF] = useState(false); + const handlePageChange = (page) => { getAllSponsorPurchases(term, page, perPage, order, orderDir); }; @@ -87,8 +96,17 @@ const ShowPurchaseListPage = ({ history.push(`${item.sponsor_id}/purchases/${item.id}`); }; - const handleMenu = (item) => { - console.log("MENU : ", item); + const handleInvoiceDownload = (purchaseOrder) => { + if (loadingPDF) return; + setLoadingPDF(true); + getSponsorOrder(purchaseOrder.id, purchaseOrder.sponsor_id) + .then(({ response: fetchedOrder }) => + generateInvoicePDF(fetchedOrder, currentSummit, { + logoSrc: logoInvoice + }) + ) + .catch(() => errorMessage(t("errors.invoice_generation"))) + .finally(() => setLoadingPDF(false)); }; const handleStatusChange = (sponsorId, purchaseId, newStatus) => { @@ -184,7 +202,7 @@ const ShowPurchaseListPage = ({ handleMenu(row)} + onClick={() => handleInvoiceDownload(row)} > @@ -248,12 +266,14 @@ const ShowPurchaseListPage = ({ ); }; -const mapStateToProps = ({ showPurchaseListState }) => ({ - ...showPurchaseListState +const mapStateToProps = ({ showPurchaseListState, currentSummitState }) => ({ + ...showPurchaseListState, + currentSummit: currentSummitState.currentSummit }); export default connect(mapStateToProps, { getAllSponsorPurchases, + getSponsorOrder, exportAllSponsorPurchases, approveSponsorPurchase, rejectSponsorPurchase diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js index cd16c2bd6..09003b86a 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js @@ -11,7 +11,7 @@ * limitations under the License. * */ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; import { @@ -25,10 +25,13 @@ import { import DownloadIcon from "@mui/icons-material/Download"; import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; import SearchInput from "openstack-uicore-foundation/lib/components/mui/search-input"; +import { useSnackbarMessage } from "openstack-uicore-foundation/lib/components/mui/snackbar-notification"; +import { generateInvoicePDF } from "openstack-uicore-foundation/lib/components/order-invoice-pdf"; import history from "../../../../../history"; import { approveSponsorPurchase, getSponsorPurchases, + getSponsorOrder, rejectSponsorPurchase } from "../../../../../actions/sponsor-purchases-actions"; import { @@ -36,6 +39,7 @@ import { PURCHASE_METHODS, PURCHASE_STATUS } from "../../../../../utils/constants"; +import logoInvoice from "../../../../../assets/fn-invoice-header.png"; const SponsorPurchasesTab = ({ sponsor, @@ -46,7 +50,9 @@ const SponsorPurchasesTab = ({ currentPage, perPage, totalCount, + currentSummit, getSponsorPurchases, + getSponsorOrder, approveSponsorPurchase, rejectSponsorPurchase }) => { @@ -54,6 +60,9 @@ const SponsorPurchasesTab = ({ getSponsorPurchases(); }, [sponsor?.id]); + const { errorMessage } = useSnackbarMessage(); + const [loadingPDF, setLoadingPDF] = useState(false); + const handlePageChange = (page) => { getSponsorPurchases(term, page, perPage, order, orderDir); }; @@ -80,8 +89,17 @@ const SponsorPurchasesTab = ({ history.push(`purchases/${item.id}`); }; - const handleMenu = (item) => { - console.log("MENU : ", item); + const handleInvoiceDownload = (item) => { + if (loadingPDF) return; + setLoadingPDF(true); + getSponsorOrder(item.id, sponsor.id) + .then(({ response: fetchedOrder }) => + generateInvoicePDF(fetchedOrder, currentSummit, { + logoSrc: logoInvoice + }) + ) + .catch(() => errorMessage(T.translate("errors.invoice_generation"))) + .finally(() => setLoadingPDF(false)); }; const handleStatusChange = (purchaseId, newStatus) => { @@ -167,7 +185,7 @@ const SponsorPurchasesTab = ({ handleMenu(row)} + onClick={() => handleInvoiceDownload(row)} > @@ -218,14 +236,17 @@ const SponsorPurchasesTab = ({ const mapStateToProps = ({ sponsorPagePurchaseListState, - currentSponsorState + currentSponsorState, + currentSummitState }) => ({ ...sponsorPagePurchaseListState, - sponsor: currentSponsorState.entity + sponsor: currentSponsorState.entity, + currentSummit: currentSummitState.currentSummit }); export default connect(mapStateToProps, { getSponsorPurchases, + getSponsorOrder, approveSponsorPurchase, rejectSponsorPurchase })(SponsorPurchasesTab); diff --git a/yarn.lock b/yarn.lock index db00b7c94..46090d20e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9068,10 +9068,10 @@ open@^10.0.3: is-inside-container "^1.0.0" wsl-utils "^0.1.0" -openstack-uicore-foundation@5.0.43: - version "5.0.43" - resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.43.tgz#a0f870bd2d1dd7a97a1b6e78009b5248ca27baab" - integrity sha512-UBIENc7nEhhKEsmaGRKdEIziNhnGypy5bf9ydssEgFB/Fe6Q6gH07x1U8m5s1nXYV9OCneMvLTBH98tprUXlOg== +openstack-uicore-foundation@5.0.46-beta.2: + version "5.0.46-beta.2" + resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.46-beta.2.tgz#14ef22899ebb91c54e265c9dbebf90ca682c6951" + integrity sha512-IhNOFYCNQIiqgxc7iMru0AnPZkV2MRjC+kt3jWiIDGtn5zCUbXQ5QJ8ipGNDJaLCzHILNd5J2Wdr6JXiETY7YA== dependencies: use-sync-external-store "^1.6.0"