Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
48 changes: 26 additions & 22 deletions src/actions/sponsor-purchases-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment on lines +303 to +308

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Prioritize the explicit purchase sponsor ID.

The global purchase list passes the row’s purchaseOrder.sponsor_id, but Line 308 ignores it whenever Redux still holds a previously viewed sponsor. That can fetch the order through the wrong sponsor URL. Prefer the explicit argument, with Redux only as the fallback.

Proposed fix
-    const sponsor_id = sponsor.id || sponsorId;
+    const sponsor_id = sponsorId || (sponsor && sponsor.id);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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;
const { currentSummitState, currentSponsorState } = getState();
const { currentSummit } = currentSummitState;
const { entity: sponsor } = currentSponsorState;
const accessToken = await getAccessTokenSafely();
const sponsor_id = sponsorId || (sponsor && sponsor.id);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/actions/sponsor-purchases-actions.js` around lines 303 - 308, Update the
sponsor ID selection in the purchase action around getAccessTokenSafely so the
explicit sponsorId argument is preferred, falling back to sponsor.id only when
it is absent. Preserve the existing currentSponsorState lookup for that fallback
and use the selected ID for subsequent sponsor-specific requests.


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)({}));
Expand Down
Binary file added src/assets/fn-invoice-header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
34 changes: 27 additions & 7 deletions src/pages/sponsors/show-purchase-list-page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -26,18 +26,22 @@ 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 {
DEFAULT_CURRENT_PAGE,
PURCHASE_METHODS,
PURCHASE_STATUS
} from "../../../utils/constants";
import logoInvoice from "../../../assets/fn-invoice-header.png";

const ShowPurchaseListPage = ({
match,
Expand All @@ -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);
};
Expand Down Expand Up @@ -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));
Comment on lines +99 to +109

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the imported translation instance in the failure handler.

Line 108 references undefined t; a failed fetch/PDF generation throws instead of showing the snackbar.

-      .catch(() => errorMessage(t("errors.invoice_generation")))
+      .catch(() => errorMessage(T.translate("errors.invoice_generation")))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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 handleInvoiceDownload = (purchaseOrder) => {
if (loadingPDF) return;
setLoadingPDF(true);
getSponsorOrder(purchaseOrder.id, purchaseOrder.sponsor_id)
.then(({ response: fetchedOrder }) =>
generateInvoicePDF(fetchedOrder, currentSummit, {
logoSrc: logoInvoice
})
)
.catch(() => errorMessage(T.translate("errors.invoice_generation")))
.finally(() => setLoadingPDF(false));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/sponsors/show-purchase-list-page/index.js` around lines 99 - 109,
Update the failure handler in handleInvoiceDownload to use the imported
translation instance instead of the undefined t reference, while preserving the
existing invoice_generation error message and loading-state cleanup.

};

const handleStatusChange = (sponsorId, purchaseId, newStatus) => {
Expand Down Expand Up @@ -184,7 +202,7 @@ const ShowPurchaseListPage = ({
<IconButton
size="large"
sx={{ color: "primary.main" }}
onClick={() => handleMenu(row)}
onClick={() => handleInvoiceDownload(row)}
>
<DownloadIcon fontSize="large" />
</IconButton>
Comment on lines 202 to 208

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add an accessible name to both invoice-download buttons.

Screen-reader users cannot identify icon-only controls without an aria-label.

  • src/pages/sponsors/show-purchase-list-page/index.js#L202-L208: add a localized invoice-download aria-label.
  • src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js#L185-L191: add the same localized aria-label.
📍 Affects 2 files
  • src/pages/sponsors/show-purchase-list-page/index.js#L202-L208 (this comment)
  • src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js#L185-L191
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/sponsors/show-purchase-list-page/index.js` around lines 202 - 208,
Add the same localized invoice-download aria-label to both IconButton controls:
src/pages/sponsors/show-purchase-list-page/index.js lines 202-208 and
src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/index.js lines
185-191. Reuse the existing localization mechanism and keep the button behavior
unchanged.

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -25,17 +25,21 @@ 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 {
DEFAULT_CURRENT_PAGE,
PURCHASE_METHODS,
PURCHASE_STATUS
} from "../../../../../utils/constants";
import logoInvoice from "../../../../../assets/fn-invoice-header.png";

const SponsorPurchasesTab = ({
sponsor,
Expand All @@ -46,14 +50,19 @@ const SponsorPurchasesTab = ({
currentPage,
perPage,
totalCount,
currentSummit,
getSponsorPurchases,
getSponsorOrder,
approveSponsorPurchase,
rejectSponsorPurchase
}) => {
useEffect(() => {
getSponsorPurchases();
}, [sponsor?.id]);

const { errorMessage } = useSnackbarMessage();
const [loadingPDF, setLoadingPDF] = useState(false);

const handlePageChange = (page) => {
getSponsorPurchases(term, page, perPage, order, orderDir);
};
Expand All @@ -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) => {
Expand Down Expand Up @@ -167,7 +185,7 @@ const SponsorPurchasesTab = ({
<IconButton
size="large"
sx={{ color: "primary.main" }}
onClick={() => handleMenu(row)}
onClick={() => handleInvoiceDownload(row)}
>
<DownloadIcon fontSize="large" />
</IconButton>
Expand Down Expand Up @@ -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);
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
Loading