Skip to content
Merged
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 .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ PRINT_APP_URL=https://badge-print-app.dev.fnopen.com
PUB_API_BASE_URL=
OS_BASE_URL=
SCOPES_BASE_REALM=${API_BASE_URL}
PURCHASES_API_SCOPES=purchases-show-medata/read purchases-show-medata/write show-form/read show-form/write
PURCHASES_API_SCOPES=purchases-show-medata/read purchases-show-medata/write show-form/read show-form/write customized-form/write customized-form/read carts/read carts/write
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add quotes around the PURCHASES_API_SCOPES value for consistency and correct parsing.

The value contains space-separated scopes but lacks surrounding quotes, inconsistent with other scope variables in the file (lines 5, 16, 17, 18) and flagged by dotenv-linter. Space-separated values should be quoted to ensure proper dotenv parsing.

🔧 Proposed fix
-PURCHASES_API_SCOPES=purchases-show-medata/read purchases-show-medata/write show-form/read show-form/write customized-form/write customized-form/read carts/read carts/write
+PURCHASES_API_SCOPES="purchases-show-medata/read purchases-show-medata/write show-form/read show-form/write customized-form/write customized-form/read carts/read carts/write"
📝 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
PURCHASES_API_SCOPES=purchases-show-medata/read purchases-show-medata/write show-form/read show-form/write customized-form/write customized-form/read carts/read carts/write
PURCHASES_API_SCOPES="purchases-show-medata/read purchases-show-medata/write show-form/read show-form/write customized-form/write customized-form/read carts/read carts/write"
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 15-15: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🤖 Prompt for AI Agents
In @.env.example at line 15, The PURCHASES_API_SCOPES env variable value is not
quoted and contains space-separated scopes; update the .env.example to wrap the
PURCHASES_API_SCOPES value in double quotes (e.g., PURCHASES_API_SCOPES="...")
so it matches other scope variables and parses correctly by dotenv-linter and
dotenv parsers.

SPONSOR_USERS_API_SCOPES="show-medata/read show-medata/write access-requests/read access-requests/write sponsor-users/read sponsor-users/write groups/read groups/write"
EMAIL_SCOPES="clients/read templates/read templates/write emails/read"
FILE_UPLOAD_SCOPES="files/upload"
Expand Down
116 changes: 116 additions & 0 deletions src/actions/sponsor-cart-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* Copyright 2018 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* */

import {
authErrorHandler,
createAction,
getRequest,
deleteRequest,
startLoading,
stopLoading
} from "openstack-uicore-foundation/lib/utils/actions";

import T from "i18n-react";
import { escapeFilterValue, getAccessTokenSafely } from "../utils/methods";
import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions";
import { ERROR_CODE_404 } from "../utils/constants";

export const REQUEST_SPONSOR_CART = "REQUEST_SPONSOR_CART";
export const RECEIVE_SPONSOR_CART = "RECEIVE_SPONSOR_CART";
export const SPONSOR_CART_FORM_DELETED = "SPONSOR_CART_FORM_DELETED";

const customErrorHandler = (err, res) => (dispatch, state) => {
const code = err.status;
dispatch(stopLoading());
switch (code) {
case ERROR_CODE_404:
break;
default:
authErrorHandler(err, res)(dispatch, state);
}
};

export const getSponsorCart =
(term = "") =>
async (dispatch, getState) => {
const { currentSummitState, currentSponsorState } = getState();
const { currentSummit } = currentSummitState;
const {
entity: { id: sponsorId }
} = currentSponsorState;
const accessToken = await getAccessTokenSafely();
const summitTZ = currentSummit.time_zone.name;
const filter = [];

dispatch(startLoading());

if (term) {
const escapedTerm = escapeFilterValue(term);
filter.push(`name=@${escapedTerm},code=@${escapedTerm}`);
}

const params = {
access_token: accessToken
};

if (filter.length > 0) {
params["filter[]"] = filter;
}

return getRequest(
Copy link

Choose a reason for hiding this comment

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

@santipalenque as stated on ticket
current cart call could return 404 is cart does not exists
how is this managed to meet the acceptance criteria ?

Copy link
Author

Choose a reason for hiding this comment

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

it is handled in customErrorHandler

createAction(REQUEST_SPONSOR_CART),
createAction(RECEIVE_SPONSOR_CART),
`${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/carts/current`,
customErrorHandler,
{ term, summitTZ }
)(params)(dispatch)
.catch((err) => {
console.error(err);
})
.finally(() => {
dispatch(stopLoading());
});
};


export const deleteSponsorCartForm =
(formId) => async (dispatch, getState) => {
const { currentSummitState, currentSponsorState } = getState();
const { currentSummit } = currentSummitState;
const {
entity: { id: sponsorId }
} = currentSponsorState;
const accessToken = await getAccessTokenSafely();
const params = { access_token: accessToken };

dispatch(startLoading());

return deleteRequest(
null,
createAction(SPONSOR_CART_FORM_DELETED)({ formId }),
`${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}`,
null,
snackbarErrorHandler
)(params)(dispatch)
.then(() => {
dispatch(
snackbarSuccessHandler({
title: T.translate("general.success"),
html: T.translate("sponsor_forms.form_delete_success")
})
);
})
.finally(() => {
dispatch(stopLoading());
});
};
16 changes: 16 additions & 0 deletions src/components/mui/table/extra-rows/NotesRow.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow";
import * as React from "react";
import { Typography } from "@mui/material";

const NotesRow = ({ colCount, note }) => (
<TableRow>
<TableCell sx={{ fontWeight: 800 }} colSpan={colCount}>
<Typography variant="body2" sx={{ color: "text.secondary" }}>
{note}
</Typography>
</TableCell>
</TableRow>
);

export default NotesRow;
32 changes: 32 additions & 0 deletions src/components/mui/table/extra-rows/TotalRow.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow";
import * as React from "react";
import T from "i18n-react/dist/i18n-react";

const TotalRow = ({ columns, targetCol, total, trailing = 0 }) => {
return (
<TableRow>
{columns.map((col, i) => {
if (i === 0)
return (
<TableCell key={col.columnKey} sx={{ fontWeight: 800, textTransform: "uppercase" }}>
{T.translate("mui_table.total")}
</TableCell>
);
if (col.columnKey === targetCol)
return (
<TableCell key={col.columnKey} sx={{ fontWeight: 800 }}>
{total}
</TableCell>
);
return <TableCell key={col.columnKey} />;
})}
{[...Array(trailing)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`extra-row-total-${i}`} sx={{ width: 40 }} />
))}
</TableRow>
);
};

export default TotalRow;
2 changes: 2 additions & 0 deletions src/components/mui/table/extra-rows/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as TotalRow } from "./TotalRow";
export { default as NotesRow } from "./NotesRow";
51 changes: 28 additions & 23 deletions src/components/mui/table/mui-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import T from "i18n-react/dist/i18n-react";
import { isBoolean } from "lodash";
import {
Box,
Button,
IconButton,
Paper,
Button,
Table,
TableBody,
TableCell,
Expand All @@ -31,6 +31,7 @@ import styles from "./mui-table.module.less";
const MuiTable = ({
columns = [],
data = [],
children,
totalRows,
perPage,
currentPage,
Expand Down Expand Up @@ -253,6 +254,8 @@ const MuiTable = ({
)}
</TableRow>
))}
{/* Here we inject extra rows passed as children */}
{children}
{data.length === 0 && (
Copy link

Choose a reason for hiding this comment

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

@santipalenque we need to review this logic
children are rendered without any check of data.length

Copy link
Author

Choose a reason for hiding this comment

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

not sure I understand, you want to hide the total row if no data ?

<TableRow>
<TableCell colSpan={columns.length} align="center">
Expand All @@ -265,28 +268,30 @@ const MuiTable = ({
</TableContainer>

{/* PAGINATION */}
<TablePagination
component="div"
count={totalRows}
rowsPerPageOptions={customPerPageOptions}
rowsPerPage={perPage}
page={currentPage - 1}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
labelRowsPerPage={T.translate("mui_table.rows_per_page")}
sx={{
".MuiTablePagination-toolbar": {
alignItems: "baseline",
marginTop: "1.6rem"
},
".MuiTablePagination-spacer": {
display: "none"
},
".MuiTablePagination-displayedRows": {
marginLeft: "auto"
}
}}
/>
{perPage && currentPage && (
<TablePagination
component="div"
count={totalRows}
rowsPerPageOptions={customPerPageOptions}
rowsPerPage={perPage}
page={currentPage - 1}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
labelRowsPerPage={T.translate("mui_table.rows_per_page")}
sx={{
".MuiTablePagination-toolbar": {
alignItems: "baseline",
marginTop: "1.6rem"
},
".MuiTablePagination-spacer": {
display: "none"
},
".MuiTablePagination-displayedRows": {
marginLeft: "auto"
}
}}
/>
)}
</Paper>
</Box>
);
Expand Down
17 changes: 16 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,20 @@
"unarchived": "Form successfully unarchived."
}
},
"cart_tab": {
"new_form": "New Form",
"forms": "forms",
"code": "Code",
"name": "Name",
"add_ons": "Add-ons",
"discount": "Discount",
"amount": "Amount",
"manage_items": "Manage Items",
"add_form": "Add Form",
"no_cart": "No cart found.",
"pay_cc": "pay with credit card or ach",
"pay_invoice": "pay with invoice"
},
Comment on lines +2437 to +2450
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, explore the i18n directory structure
echo "=== Locale files in src/i18n ==="
ls -la src/i18n/ | grep -E "\.(json|js)$"

# Count total locale files
echo "=== Total locale files ==="
fd -e json src/i18n | wc -l

Repository: fntechgit/summit-admin

Length of output: 542


🏁 Script executed:

#!/bin/bash
# Read the exact lines around the cart_tab section
echo "=== Content at lines 2437-2450 in en.json ==="
sed -n '2437,2450p' src/i18n/en.json

Repository: fntechgit/summit-admin

Length of output: 508


🏁 Script executed:

#!/bin/bash
# Search for cart_tab in all locale files
echo "=== Files containing 'cart_tab' ==="
rg "cart_tab" src/i18n -l

# Show content of cart_tab in each file
echo -e "\n=== cart_tab definitions across locales ==="
rg -A 12 '"cart_tab"' src/i18n

Repository: fntechgit/summit-admin

Length of output: 774


🏁 Script executed:

#!/bin/bash
# Search for JSON files that might be locale files
echo "=== All JSON files in repo ==="
fd -e json . | grep -iE "(locale|lang|i18n|translation)" | head -20

# Check if there's a locales directory elsewhere
echo -e "\n=== Searching for locale-like directories ==="
fd -type d -iE "(locale|lang|i18n|translation)" .

# Verify all json files in src/i18n
echo -e "\n=== All files in src/i18n ==="
fd . src/i18n

Repository: fntechgit/summit-admin

Length of output: 396


🏁 Script executed:

#!/bin/bash
# Check git history to see if this is a new feature
echo "=== Recent changes to src/i18n/en.json ==="
git log --oneline -10 -- src/i18n/en.json

# Check if cart_tab was recently added
echo -e "\n=== Checking cart_tab presence in git ==="
git log -p --all -S "cart_tab" -- "*.json" | head -50

Repository: fntechgit/summit-admin

Length of output: 182


🏁 Script executed:

#!/bin/bash
# Check if the application uses i18n/internationalization
echo "=== Checking for i18n usage in code ==="
rg -t js -t ts "i18n|i18next|translation|locale" src --max-count=5

# Check package.json for i18n libraries
echo -e "\n=== I18n related dependencies ==="
rg "i18n|i18next|react-intl" package.json

Repository: fntechgit/summit-admin

Length of output: 41358


🏁 Script executed:

#!/bin/bash
# Check if there's a build process or config that expects multiple locales
echo "=== Checking for locale config/setup ==="
rg "locale|lang" . --type json -t toml -t yaml -t js --max-count=10

# Look for any comments or documentation about locales
echo -e "\n=== README or docs mentioning locales ==="
fd README . && cat README.md | grep -iA 5 -B 5 "locale\|language\|i18n" || echo "No README found"

Repository: fntechgit/summit-admin

Length of output: 50437


Normalize capitalization in cart_tab values for UI consistency.

The cart_tab strings have inconsistent capitalization: "forms", "pay with credit card or ach", and "pay with invoice" are lowercase while other values use Title Case ("New Form", "Code", "Name", etc.). Standardize to Title Case to match the rest of the object.

🤖 Prompt for AI Agents
In @src/i18n/en.json around lines 2437 - 2450, The cart_tab translation entries
use inconsistent lowercase for some values; update the values for keys "forms",
"pay_cc", and "pay_invoice" inside the cart_tab object to Title Case ("Forms",
"Pay with Credit Card or ACH", "Pay with Invoice") so they match the
capitalization style of the other entries like "New Form", "Code", and "Name".

"placeholders": {
"select_sponsorship": "Select a Sponsorship",
"sponsorship_type": "Start typing to choose a Tier...",
Expand Down Expand Up @@ -3762,7 +3776,8 @@
"no_items": "No items found.",
"rows_per_page": "Rows per page",
"sorted_desc": "sorted descending",
"sorted_asc": "sorted ascending"
"sorted_asc": "sorted ascending",
"total": "Total"
},
"event_rsvp_list": {
"name": "Name",
Expand Down
6 changes: 5 additions & 1 deletion src/pages/sponsors/edit-sponsor-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import SponsorGeneralForm from "../../components/forms/sponsor-general-form/inde
import SponsorUsersListPerSponsorPage from "./sponsor-users-list-per-sponsor";
import SponsorFormsTab from "./sponsor-forms-tab";
import SponsorBadgeScans from "./sponsor-badge-scans";
import SponsorCartTab from "./sponsor-cart-tab";

const CustomTabPanel = (props) => {
const { children, value, index, ...other } = props;
Expand Down Expand Up @@ -127,7 +128,7 @@ const EditSponsorPage = (props) => {

return (
<Box>
<Container maxWidth="lg" sx={{position: "relative"}}>
<Container maxWidth="lg" sx={{ position: "relative" }}>
<Typography fontSize="3.4rem" variant="h4">
{entity.company?.name}
</Typography>
Expand Down Expand Up @@ -185,6 +186,9 @@ const EditSponsorPage = (props) => {
<CustomTabPanel value={selectedTab} index={4}>
<SponsorFormsTab sponsor={entity} summitId={currentSummit.id} />
</CustomTabPanel>
<CustomTabPanel value={selectedTab} index={5}>
<SponsorCartTab sponsor={entity} summitId={currentSummit.id} />
</CustomTabPanel>
<CustomTabPanel value={selectedTab} index={7}>
<SponsorBadgeScans sponsor={entity} />
</CustomTabPanel>
Expand Down
Loading