From da8142797507043ddbcba5399168d9020944c896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Castillo?= Date: Thu, 27 Nov 2025 12:33:41 -0300 Subject: [PATCH 1/9] feat: add new page and route for sponsor customized form managed items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Castillo --- src/actions/sponsor-forms-actions.js | 233 +++++++++++ src/i18n/en.json | 20 +- src/layouts/sponsor-id-layout.js | 14 +- src/pages/sponsors/edit-sponsor-page.js | 30 +- .../sponsor-form-item-from-inventory.js | 271 +++++++++++++ .../sponsor-forms-manage-items.js | 383 ++++++++++++++++++ src/pages/sponsors/sponsor-forms-tab/index.js | 5 +- ...nsor-customized-form-items-list-reducer.js | 214 ++++++++++ src/store.js | 2 + src/utils/constants.js | 2 + 10 files changed, 1165 insertions(+), 9 deletions(-) create mode 100644 src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js create mode 100644 src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js create mode 100644 src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js diff --git a/src/actions/sponsor-forms-actions.js b/src/actions/sponsor-forms-actions.js index 9253b92fc..eb23a88d7 100644 --- a/src/actions/sponsor-forms-actions.js +++ b/src/actions/sponsor-forms-actions.js @@ -64,6 +64,23 @@ export const SPONSOR_CUSTOMIZED_FORM_DELETED = export const SPONSOR_CUSTOMIZED_FORM_ARCHIVED_CHANGED = "SPONSOR_CUSTOMIZED_FORM_ARCHIVED_CHANGED"; +export const RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS = + "RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS"; +export const REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS = + "REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS"; +export const SPONSOR_CUSTOMIZED_FORM_ITEM_DELETED = + "SPONSOR_CUSTOMIZED_FORM_ITEM_DELETED"; +export const SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED = + "SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED"; +export const SPONSOR_CUSTOMIZED_FORM_ITEM_UNARCHIVED = + "SPONSOR_CUSTOMIZED_FORM_ITEM_UNARCHIVED"; +export const UPDATE_SPONSOR_FORM_MANAGED_ITEM = + "UPDATE_SPONSOR_FORM_MANAGED_ITEM"; +export const SPONSOR_FORM_MANAGED_ITEM_UPDATED = + "SPONSOR_FORM_MANAGED_ITEM_UPDATED"; +export const SPONSOR_FORM_MANAGED_ITEM_ADDED = + "SPONSOR_FORM_MANAGED_ITEM_ADDED"; + // ITEMS export const REQUEST_SPONSOR_FORM_ITEMS = "REQUEST_SPONSOR_FORM_ITEMS"; export const RECEIVE_SPONSOR_FORM_ITEMS = "RECEIVE_SPONSOR_FORM_ITEMS"; @@ -632,6 +649,60 @@ export const getSponsorCustomizedForm = }); }; +export const getSponsorCustomizedFormItems = + ( + formId, + term = "", + page = DEFAULT_CURRENT_PAGE, + perPage = DEFAULT_PER_PAGE, + order = "id", + orderDir = DEFAULT_ORDER_DIR, + hideArchived = false + ) => + async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + const accessToken = await getAccessTokenSafely(); + const filter = []; + + dispatch(startLoading()); + + if (term) { + const escapedTerm = escapeFilterValue(term); + filter.push(`name=@${escapedTerm},code=@${escapedTerm}`); + } + + const params = { + page, + per_page: perPage, + access_token: accessToken + }; + + if (hideArchived) filter.push("is_archived==0"); + + if (filter.length > 0) { + params["filter[]"] = filter; + } + + // order + if (order != null && orderDir != null) { + const orderDirSign = orderDir === 1 ? "" : "-"; + params.order = `${orderDirSign}${order}`; + } + + return getRequest( + createAction(REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS), + createAction(RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items`, + authErrorHandler + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; + export const saveSponsorCustomizedForm = (entity) => async (dispatch, getState) => { const { currentSummitState, currentSponsorState } = getState(); @@ -1208,3 +1279,165 @@ export const addInventoryItems = dispatch(stopLoading()); }); }; + +export const saveSponsorFormManagedItem = + (formId, entity) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + if (entity.id) { + putRequest( + createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), + createAction(SPONSOR_FORM_MANAGED_ITEM_UPDATED), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${entity.id}`, + entity, + snackbarErrorHandler, + entity + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + dispatch( + snackbarSuccessHandler({ + title: T.translate("general.success"), + html: T.translate( + "edit_sponsor.forms_tab.form_manage_items.item_updated" + ) + }) + ); + }); + } else { + const successMessage = { + title: T.translate("general.done"), + html: T.translate( + "edit_sponsor.forms_tab.form_manage_items.item_created" + ), + type: "success" + }; + + postRequest( + createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), + createAction(SPONSOR_FORM_MANAGED_ITEM_ADDED), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${entity.id}`, + entity, + snackbarErrorHandler, + entity + )(params)(dispatch).then(() => { + dispatch(showMessage(successMessage)); + }); + } + }; + +export const getSponsorFormManagedItem = + (formId, itemId) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + return getRequest( + null, + createAction(RECEIVE_SPONSOR_CUSTOMIZED_FORM), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${itemId}`, + authErrorHandler + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; + +export const addSponsorFormItems = + (formId, itemIds) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + return postRequest( + null, + createAction(SPONSOR_FORM_ITEMS_ADDED), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/clone`, + { inventory_item_ids: itemIds }, + snackbarErrorHandler + )(params)(dispatch) + .then(() => { + dispatch(getSponsorCustomizedFormItems(formId)); + dispatch( + snackbarSuccessHandler({ + title: T.translate("general.success"), + html: T.translate( + "sponsor_form_item_list.add_from_inventory.items_added" + ) + }) + ); + }) + .catch(console.log) // need to catch promise reject + .finally(() => { + dispatch(stopLoading()); + }); + }; + +export const archiveSponsorCustomizedFormItem = + (formId, itemId) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + const params = { access_token: accessToken }; + + return putRequest( + null, + createAction(SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${itemId}/archive`, + null, + snackbarErrorHandler + )(params)(dispatch); + }; + +export const unarchiveSponsorCustomizedFormItem = + (formId, itemId) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + const params = { access_token: accessToken }; + + dispatch(startLoading()); + + return deleteRequest( + null, + createAction(SPONSOR_CUSTOMIZED_FORM_ITEM_UNARCHIVED)({ itemId }), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${itemId}/archive`, + null, + snackbarErrorHandler + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; diff --git a/src/i18n/en.json b/src/i18n/en.json index 8a04b78c8..a96c08949 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2429,6 +2429,24 @@ "error": "There was a problem creating the forms, please try again.", "archived": "Form successfully archived.", "unarchived": "Form successfully unarchived." + }, + "form_manage_items": { + "add_item": "Add Item", + "add_item_inventory": "Add Item from Inventory", + "alert_info": "You can add or archive items from the list. To edit an item click on the item's Edit botton. You can also change only a rate by clicking on it.", + "select_items": "Select items", + "code": "Code", + "name": "Name", + "early_bird_rate": "Early Bird Rate", + "standard_rate": "Standard Rate", + "onsite_rate": "On site rate", + "default_quantity": "Default Quantity", + "add_selected": "Add Selected Items", + "item_updated": "Form item created successfully", + "item_created": "Form item {item} updated successfully", + "placeholder": { + "search": "Search..." + } } }, "placeholders": { @@ -2566,7 +2584,7 @@ "code": "Code", "name": "Name", "early_bird_rate": "Early bird rate", - "standard_rate": "Standad rate", + "standard_rate": "Standard rate", "onsite_rate": "On site rate", "save": "Add selected items", "items_added": "Items added successfully." diff --git a/src/layouts/sponsor-id-layout.js b/src/layouts/sponsor-id-layout.js index a488d5585..62041bd8f 100644 --- a/src/layouts/sponsor-id-layout.js +++ b/src/layouts/sponsor-id-layout.js @@ -2,9 +2,9 @@ import React from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; import { Switch, Route } from "react-router-dom"; +import { Breadcrumb } from "react-breadcrumbs"; import EditSponsorPage from "../pages/sponsors/edit-sponsor-page"; import { getSponsor, resetSponsorForm } from "../actions/sponsor-actions"; -import { Breadcrumb } from "react-breadcrumbs"; import EditAdSponsorPage from "../pages/sponsors/edit-advertisement-sponsor-page"; import EditMaterialSponsorPage from "../pages/sponsors/edit-material-sponsor-page"; import EditSocialNetworkSponsorPage from "../pages/sponsors/edit-social-network-sponsor-page"; @@ -23,7 +23,7 @@ class SponsorIdLayout extends React.Component { } } - componentDidUpdate(prevProps, prevState, snapshot) { + componentDidUpdate(prevProps) { const oldId = prevProps.match.params.sponsor_id; const newId = this.props.match.params.sponsor_id; @@ -38,7 +38,7 @@ class SponsorIdLayout extends React.Component { render() { const { match, currentSponsor } = this.props; - let sponsorId = this.props.match.params.sponsor_id; + const sponsorId = this.props.match.params.sponsor_id; const breadcrumb = currentSponsor.id ? currentSponsor.company.name : T.translate("general.new"); @@ -141,7 +141,13 @@ class SponsorIdLayout extends React.Component { )} /> - + + + + diff --git a/src/pages/sponsors/edit-sponsor-page.js b/src/pages/sponsors/edit-sponsor-page.js index 5f3b6e214..623512085 100644 --- a/src/pages/sponsors/edit-sponsor-page.js +++ b/src/pages/sponsors/edit-sponsor-page.js @@ -42,6 +42,8 @@ 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 SponsorFormsManageItems from "./sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items"; +import { FOUR } from "../../utils/constants"; const CustomTabPanel = (props) => { const { children, value, index, ...other } = props; @@ -68,6 +70,9 @@ const EditSponsorPage = (props) => { const { entity, member, + history, + location, + match, currentSummit, resetSponsorForm, getSponsorAdvertisements, @@ -91,10 +96,16 @@ const EditSponsorPage = (props) => { getExtraQuestionMeta } = props; - const [selectedTab, setSelectedTab] = useState(0); + const [selectedTab, setSelectedTab] = useState( + location.pathname.includes("/sponsor-forms/") && + location.pathname.includes("/items") + ? FOUR + : 0 + ); const handleTabChange = (event, newValue) => { setSelectedTab(newValue); + history.push(`/app/summits/${currentSummit.id}/sponsors/${entity.id}`); }; useEffect(() => { @@ -125,9 +136,13 @@ const EditSponsorPage = (props) => { { label: T.translate("edit_sponsor.tab.badge_scans"), value: 7 } ]; + const sponsorFormItemRoute = + location.pathname.includes("/sponsor-forms/") && + location.pathname.includes("/items"); + return ( - + {entity.company?.name} @@ -144,6 +159,7 @@ const EditSponsorPage = (props) => { key={t.value} label={t.label} value={t.value} + onClick={() => handleTabChange(null, t.value)} sx={{ fontSize: "1.4rem", lineHeight: "1.8rem", @@ -183,7 +199,15 @@ const EditSponsorPage = (props) => { - + {sponsorFormItemRoute ? ( + + ) : ( + + )} diff --git a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js new file mode 100644 index 000000000..f5d29aaab --- /dev/null +++ b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js @@ -0,0 +1,271 @@ +import React, { useEffect, useState } from "react"; +import T from "i18n-react/dist/i18n-react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { + Box, + Button, + Checkbox, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Divider, + FormControlLabel, + Grid2, + IconButton, + Tooltip, + Typography +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import ImageIcon from "@mui/icons-material/Image"; +import SwapVertIcon from "@mui/icons-material/SwapVert"; +import SearchInput from "../../../../../components/mui/search-input"; +import { + DEFAULT_CURRENT_PAGE, + DEFAULT_PER_PAGE +} from "../../../../../utils/constants"; + +import { getInventoryItems } from "../../../../../actions/inventory-item-actions"; +import MuiTable from "../../../../../components/mui/table/mui-table"; +import { amountFromCents } from "../../../../../utils/currency"; +import MenuButton from "../../../../../components/mui/menu-button"; + +const SponsorFormItemFromInventoryPopup = ({ + open, + inventoryItems, + term, + order, + perPage, + orderDir, + currentPage, + totalInventoryItems, + onSave, + onClose, + getInventoryItems +}) => { + const [selectedRows, setSelectedRows] = useState([]); + + useEffect(() => { + getInventoryItems("", 1, DEFAULT_PER_PAGE, "id", 1); + }, []); + + const handleSort = (key, dir) => { + getInventoryItems(term, 1, DEFAULT_PER_PAGE, key, dir); + }; + + const handlePageChange = (page) => { + getInventoryItems(term, page, perPage, order, orderDir); + }; + + const handlePerPageChange = (newPerPage) => { + getInventoryItems(term, DEFAULT_CURRENT_PAGE, newPerPage, order, orderDir); + }; + + const handleClose = () => { + setSelectedRows([]); + onClose(); + }; + + const handleOnCheck = (rowId, checked) => { + if (checked) { + setSelectedRows([...selectedRows, rowId]); + } else { + setSelectedRows(selectedRows.filter((r) => r !== rowId)); + } + }; + + const handleOnSearch = (searchTerm) => { + getInventoryItems(searchTerm, 1, DEFAULT_PER_PAGE, "id", 1); + }; + + const handleOnSave = () => { + onSave(selectedRows); + }; + + const columns = [ + { + columnKey: "select", + header: "", + width: 30, + align: "center", + render: (row) => ( + handleOnCheck(row.id, ev.target.checked)} + /> + } + /> + ) + }, + { + columnKey: "code", + header: T.translate("edit_sponsor.forms_tab.form_manage_items.code"), + sortable: false + }, + { + columnKey: "name", + header: T.translate("edit_sponsor.forms_tab.form_manage_items.name"), + sortable: false + }, + { + columnKey: "early_bird_rate", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.early_bird_rate" + ), + sortable: false, + render: (row) => `$ ${amountFromCents(row.early_bird_rate)}` + }, + { + columnKey: "standard_rate", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.standard_rate" + ), + sortable: false, + render: (row) => `$ ${amountFromCents(row.standard_rate)}` + }, + { + columnKey: "onsite_rate", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.onsite_rate" + ), + sortable: false, + render: (row) => `$ ${amountFromCents(row.onsite_rate)}` + }, + { + columnKey: "default_quantity", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.default_quantity" + ), + sortable: false + }, + { + columnKey: "images", + header: "", + width: 40, + align: "center", + render: (row) => + row.images?.length > 0 ? ( + + + + window.open( + row.images[0].file_url, + "_blank", + "noopener,noreferrer" + ) + } + /> + + + ) : null + } + ]; + + const tableOptions = { + sortCol: order, + sortDir: orderDir + }; + + return ( + + + + {T.translate( + "edit_sponsor.forms_tab.form_manage_items.add_item_inventory" + )} + + handleClose()}> + + + + + + + + {selectedRows.length} items selected + + + + handleSort("name", 1) }, + { label: "Z-A", onClick: () => handleSort("name", 0) } + ]} + > + sort by + + + + + + + + + {inventoryItems.length > 0 && ( + + + + )} + + + + + + + ); +}; + +SponsorFormItemFromInventoryPopup.propTypes = { + onClose: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired +}; + +const mapStateToProps = ({ currentInventoryItemListState }) => ({ + ...currentInventoryItemListState +}); + +export default connect(mapStateToProps, { + getInventoryItems +})(SponsorFormItemFromInventoryPopup); diff --git a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js new file mode 100644 index 000000000..d23b06abc --- /dev/null +++ b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js @@ -0,0 +1,383 @@ +/** + * Copyright 2024 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 React, { useEffect, useState } from "react"; +import { connect } from "react-redux"; +import T from "i18n-react/dist/i18n-react"; +import { + Box, + Button, + Checkbox, + FormControlLabel, + FormGroup, + Grid2, + IconButton, + Tooltip +} from "@mui/material"; +import AddIcon from "@mui/icons-material/Add"; +import ImageIcon from "@mui/icons-material/Image"; +import { + addSponsorFormItems, + archiveSponsorCustomizedFormItem, + getSponsorCustomizedFormItems, + saveSponsorFormManagedItem, + unarchiveSponsorCustomizedFormItem, + getSponsorFormManagedItem +} from "../../../../../actions/sponsor-forms-actions"; +import { resetInventoryItemForm } from "../../../../../actions/inventory-item-actions"; +import CustomAlert from "../../../../../components/mui/custom-alert"; +import SearchInput from "../../../../../components/mui/search-input"; +import MuiTableEditable from "../../../../../components/mui/editable-table/mui-table-editable"; +import SponsorInventoryDialog from "../../../../sponsors_inventory/popup/sponsor-inventory-popup"; +import SponsorFormItemFromInventoryPopup from "./sponsor-form-item-from-inventory"; +import { parsePrice } from "../../../../../utils/currency"; +import { ONE_HUNDRED } from "../../../../../utils/constants"; +// import FormTemplateDialog from "../../../../sponsors_inventory/popup/form-template-popup"; + +const SponsorFormsManageItems = ({ + term, + match, + hideArchived, + items, + order, + orderDir, + perPage, + currentPage, + totalCount, + getSponsorCustomizedFormItems, + currentInventoryItem, + resetInventoryItemForm, + addSponsorFormItems, + saveSponsorFormManagedItem, + archiveSponsorCustomizedFormItem, + unarchiveSponsorCustomizedFormItem, + getSponsorFormManagedItem +}) => { + const [openPopup, setOpenPopup] = useState(null); + + const handleClose = () => { + setOpenPopup(null); + }; + + const formId = match.params.form_id; + + useEffect(() => { + getSponsorCustomizedFormItems(formId); + }, []); + + const handleManagedPageChange = (page) => { + const { perPage, order, orderDir } = items; + getSponsorCustomizedFormItems( + formId, + term, + page, + perPage, + order, + orderDir, + hideArchived + ); + }; + + const handleManagedSort = (key, dir) => { + const { currentPage, perPage } = items; + getSponsorCustomizedFormItems( + formId, + term, + currentPage, + perPage, + key, + dir, + hideArchived + ); + }; + + const handleSearch = (searchTerm) => { + getSponsorCustomizedFormItems( + formId, + searchTerm, + currentPage, + perPage, + order, + orderDir, + hideArchived + ); + }; + + const handleItemSave = (item) => { + saveSponsorFormManagedItem(formId, item).then(() => + getSponsorCustomizedFormItems( + formId, + term, + currentPage, + perPage, + order, + orderDir, + hideArchived + ) + ); + setOpenPopup(null); + }; + + const handleOpenItemPopup = () => { + resetInventoryItemForm(); + setOpenPopup("add_item"); + }; + + const handleArchiveItem = (item) => + item.is_archived + ? unarchiveSponsorCustomizedFormItem(formId, item.id) + : archiveSponsorCustomizedFormItem(formId, item.id); + + const handleHideArchivedItens = (ev) => { + getSponsorCustomizedFormItems( + formId, + term, + items.currentPage, + items.perPage, + items.order, + items.orderDir, + ev.target.checked + ); + }; + + const handleAddFromInventory = (itemsId) => { + addSponsorFormItems(formId, itemsId).then(() => handleClose()); + }; + + const handleCellEdit = (rowId, column, value) => { + const tmpEntity = { + id: rowId, + [column]: Math.round(parsePrice(value) * ONE_HUNDRED) + }; + saveSponsorFormManagedItem(formId, tmpEntity); + }; + + const handleRowEdit = (row) => { + getSponsorFormManagedItem(formId, row.id).then(() => + setOpenPopup("add_item") + ); + }; + + const sponsorItemColumns = [ + { + columnKey: "code", + header: T.translate("edit_sponsor.forms_tab.form_manage_items.code"), + sortable: false + }, + { + columnKey: "name", + header: T.translate("edit_sponsor.forms_tab.form_manage_items.name"), + sortable: false + }, + { + columnKey: "early_bird_rate", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.early_bird_rate" + ), + sortable: false, + editable: true + }, + { + columnKey: "standard_rate", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.standard_rate" + ), + sortable: false, + editable: true + }, + { + columnKey: "onsite_rate", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.onsite_rate" + ), + sortable: false, + editable: true + }, + { + columnKey: "default_quantity", + header: T.translate( + "edit_sponsor.forms_tab.form_manage_items.default_quantity" + ), + sortable: false + }, + { + columnKey: "images", + header: "", + width: 40, + align: "center", + render: (row) => + row.images?.length > 0 ? ( + + + + window.open( + row.images[0].file_url, + "_blank", + "noopener,noreferrer" + ) + } + /> + + + ) : null + }, + { + columnKey: "archive", + header: "", + width: 70, + align: "center", + render: (row) => ( + + ), + dottedBorder: true + } + ]; + + return ( + + + + + {totalCount} items + + + + + } + label={T.translate("edit_sponsor.forms_tab.hide_archived")} + /> + + + + + + + + + + + + + +
+ +
+ + {/* ADD ITEM */} + + + +
+ ); +}; + +const mapStateToProps = ({ sponsorCustomizedFormItemsListState }) => ({ + ...sponsorCustomizedFormItemsListState, + currentInventoryItem: sponsorCustomizedFormItemsListState.currentItem +}); + +export default connect(mapStateToProps, { + getSponsorCustomizedFormItems, + resetInventoryItemForm, + addSponsorFormItems, + saveSponsorFormManagedItem, + getSponsorFormManagedItem, + archiveSponsorCustomizedFormItem, + unarchiveSponsorCustomizedFormItem +})(SponsorFormsManageItems); diff --git a/src/pages/sponsors/sponsor-forms-tab/index.js b/src/pages/sponsors/sponsor-forms-tab/index.js index 91f56a286..ce8b14a98 100644 --- a/src/pages/sponsors/sponsor-forms-tab/index.js +++ b/src/pages/sponsors/sponsor-forms-tab/index.js @@ -40,6 +40,7 @@ import CustomizedFormPopup from "./components/customized-form/customized-form-po const SponsorFormsTab = ({ term, + history, hideArchived, managedForms, customizedForms, @@ -110,7 +111,9 @@ const SponsorFormsTab = ({ : archiveSponsorCustomizedForm(item.id); const handleManageItems = (item) => { - console.log("MANAGE ITEMS : ", item); + history.push( + `/app/summits/${summitId}/sponsors/${sponsor.id}/sponsor-forms/${item.id}/items` + ); }; const handleCustomizedEdit = (item) => { diff --git a/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js b/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js new file mode 100644 index 000000000..1d5aab02a --- /dev/null +++ b/src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js @@ -0,0 +1,214 @@ +/** + * Copyright 2019 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 { LOGOUT_USER } from "openstack-uicore-foundation/lib/security/actions"; +import { + RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS, + REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS, + RECEIVE_SPONSOR_CUSTOMIZED_FORM, + // RECEIVE_SPONSOR_FORM_ITEM, + // RESET_SPONSOR_FORM_ITEM, + SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED, + SPONSOR_CUSTOMIZED_FORM_ITEM_DELETED, + SPONSOR_CUSTOMIZED_FORM_ITEM_UNARCHIVED, + SPONSOR_FORM_MANAGED_ITEM_UPDATED +} from "../../actions/sponsor-forms-actions"; +import { SET_CURRENT_SUMMIT } from "../../actions/summit-actions"; +import { CENTS_FACTOR, DECIMAL_DIGITS } from "../../utils/constants"; + +const DEFAULT_STATE = { + items: [], + hideArchived: false, + order: "name", + orderDir: 1, + currentPage: 1, + lastPage: 1, + perPage: 10, + totalCount: 0, + currentItem: { + code: "", + name: "", + description: "", + early_bird_rate: "", + standard_rate: "", + onsite_rate: "", + quantity_limit_per_show: "", + quantity_limit_per_sponsor: "", + default_quantity: "", + images: [], + meta_fields: [ + { + name: "", + type: "Text", + is_required: false, + values: [] + } + ] + } +}; + +const sponsorCustomizedFormItemsListReducer = ( + state = DEFAULT_STATE, + action +) => { + const { type, payload } = action; + + switch (type) { + case SET_CURRENT_SUMMIT: + case LOGOUT_USER: { + return DEFAULT_STATE; + } + case REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS: { + const { order, orderDir, page, hideArchived } = payload; + + return { + ...state, + order, + orderDir, + items: [], + currentPage: page, + hideArchived + }; + } + case RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS: { + const { + current_page: currentPage, + total, + last_page: lastPage + } = payload.response; + + const items = payload.response.data.map((a) => ({ + id: a.id, + code: a.code, + name: a.name, + early_bird_rate: `$${(a.early_bird_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + standard_rate: `$${(a.standard_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + onsite_rate: `$${(a.onsite_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + default_quantity: a.default_quantity, + is_archived: a.is_archived, + images: a.images + })); + + return { + ...state, + items, + currentPage, + totalCount: total, + lastPage + }; + } + case RECEIVE_SPONSOR_CUSTOMIZED_FORM: { + const item = payload.response; + + const currentItem = { + ...item, + early_bird_rate: `$${(item.early_bird_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + standard_rate: `$${(item.standard_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + onsite_rate: `$${(item.onsite_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + meta_fields: + item.meta_fields.length > 0 + ? item.meta_fields + : [ + { + name: "", + type: "Text", + is_required: false, + values: [] + } + ] + }; + return { ...state, currentItem }; + } + case SPONSOR_CUSTOMIZED_FORM_ITEM_DELETED: { + const { itemId } = payload; + const items = state.items.filter((it) => it.id !== itemId); + + return { ...state, items }; + } + case SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED: { + const { id: itemId } = payload.response; + + const items = state.items.map((item) => + item.id === itemId ? { ...item, is_archived: true } : item + ); + + return { ...state, items }; + } + case SPONSOR_CUSTOMIZED_FORM_ITEM_UNARCHIVED: { + const { itemId } = payload; + + const items = state.items.map((item) => + item.id === itemId ? { ...item, is_archived: false } : item + ); + + return { ...state, items }; + } + case SPONSOR_FORM_MANAGED_ITEM_UPDATED: { + const updatedItem = payload.response; + const items = state.items.map((item) => + item.id === updatedItem.id + ? { + id: updatedItem.id, + code: updatedItem.code, + name: updatedItem.name, + early_bird_rate: `$${( + updatedItem.early_bird_rate / CENTS_FACTOR + ).toFixed(DECIMAL_DIGITS)}`, + standard_rate: `$${( + updatedItem.standard_rate / CENTS_FACTOR + ).toFixed(DECIMAL_DIGITS)}`, + onsite_rate: `$${(updatedItem.onsite_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + default_quantity: updatedItem.default_quantity, + is_archived: updatedItem.is_archived, + images: updatedItem.images + } + : { + id: item.id, + code: item.code, + name: item.name, + early_bird_rate: `$${( + item.early_bird_rate / CENTS_FACTOR + ).toFixed(DECIMAL_DIGITS)}`, + standard_rate: `$${(item.standard_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + onsite_rate: `$${(item.onsite_rate / CENTS_FACTOR).toFixed( + DECIMAL_DIGITS + )}`, + default_quantity: item.default_quantity, + is_archived: item.is_archived, + images: item.images + } + ); + return { ...state, items }; + } + default: + return state; + } +}; + +export default sponsorCustomizedFormItemsListReducer; diff --git a/src/store.js b/src/store.js index 64762f8ac..ef7e2e218 100644 --- a/src/store.js +++ b/src/store.js @@ -164,6 +164,7 @@ import eventRSVPInvitationListReducer from "./reducers/rsvps/event-rsvp-invitati import eventRSVPReducer from "./reducers/events/event-rsvp-reducer.js"; import sponsorPageFormsListReducer from "./reducers/sponsors/sponsor-page-forms-list-reducer.js"; import sponsorCustomizedFormReducer from "./reducers/sponsors/sponsor-customized-form-reducer.js"; +import sponsorCustomizedFormItemsListReducer from "./reducers/sponsors/sponsor-customized-form-items-list-reducer.js"; // default: localStorage if web, AsyncStorage if react-native @@ -250,6 +251,7 @@ const reducers = persistCombineReducers(config, { sponsorUsersListState: sponsorUsersListReducer, sponsorPageFormsListState: sponsorPageFormsListReducer, sponsorCustomizedFormState: sponsorCustomizedFormReducer, + sponsorCustomizedFormItemsListState: sponsorCustomizedFormItemsListReducer, currentSponsorPromocodeListState: sponsorPromocodeListReducer, currentSponsorExtraQuestionState: sponsorExtraQuestionReducer, currentSponsorAdvertisementState: sponsorAdvertisementReducer, diff --git a/src/utils/constants.js b/src/utils/constants.js index e273e38ce..4e818ee6d 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -142,6 +142,8 @@ export const DECIMAL_DIGITS = 2; export const TWO = 2; +export const FOUR = 4; + export const TEN = 10; export const ONE_HUNDRED = 100; From 893f2ecc6d4366403e653df4da298c16cd8f69dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Castillo?= Date: Sat, 6 Dec 2025 00:54:52 -0300 Subject: [PATCH 2/9] fix: adjust ui, texts, add save and fix reducer data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Castillo --- src/actions/sponsor-forms-actions.js | 110 ++++++++++++++++-- src/i18n/en.json | 2 +- .../sponsor-forms-manage-items.js | 49 +++++--- ...nsor-customized-form-items-list-reducer.js | 80 +++++++------ 4 files changed, 176 insertions(+), 65 deletions(-) diff --git a/src/actions/sponsor-forms-actions.js b/src/actions/sponsor-forms-actions.js index eb23a88d7..b44f1eba2 100644 --- a/src/actions/sponsor-forms-actions.js +++ b/src/actions/sponsor-forms-actions.js @@ -31,6 +31,7 @@ import { DEFAULT_PER_PAGE } from "../utils/constants"; import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions"; +import { amountToCents } from "../utils/currency"; export const REQUEST_SPONSOR_FORMS = "REQUEST_SPONSOR_FORMS"; export const RECEIVE_SPONSOR_FORMS = "RECEIVE_SPONSOR_FORMS"; @@ -68,6 +69,8 @@ export const RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS = "RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEMS"; export const REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS = "REQUEST_SPONSOR_CUSTOMIZED_FORM_ITEMS"; +export const RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEM = + "RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEM"; export const SPONSOR_CUSTOMIZED_FORM_ITEM_DELETED = "SPONSOR_CUSTOMIZED_FORM_ITEM_DELETED"; export const SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED = @@ -80,6 +83,12 @@ export const SPONSOR_FORM_MANAGED_ITEM_UPDATED = "SPONSOR_FORM_MANAGED_ITEM_UPDATED"; export const SPONSOR_FORM_MANAGED_ITEM_ADDED = "SPONSOR_FORM_MANAGED_ITEM_ADDED"; +export const SPONSOR_FORM_MANAGED_ITEM_DELETED = + "SPONSOR_FORM_MANAGED_ITEM_DELETED"; +export const SPONSOR_CUSTOMIZED_FORM_ITEMS_ADDED = + "SPONSOR_CUSTOMIZED_FORM_ITEMS_ADDED"; +export const RESET_SPONSOR_FORM_MANAGED_ITEM = + "RESET_SPONSOR_FORM_MANAGED_ITEM"; // ITEMS export const REQUEST_SPONSOR_FORM_ITEMS = "REQUEST_SPONSOR_FORM_ITEMS"; @@ -1219,6 +1228,7 @@ const normalizeItem = (entity) => { if (images) { normalizedEntity.images = images?.filter((img) => img.file_path); + console.log("CHECK!", normalizedEntity); } if (early_bird_rate === "" || typeof early_bird_rate === "undefined") @@ -1295,12 +1305,16 @@ export const saveSponsorFormManagedItem = access_token: accessToken }; + const normalizedEntity = normalizeManagedItem(entity); + + console.log("TO SAVE ENTITY NORMALIZED", normalizedEntity); + if (entity.id) { putRequest( createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), createAction(SPONSOR_FORM_MANAGED_ITEM_UPDATED), `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${entity.id}`, - entity, + normalizedEntity, snackbarErrorHandler, entity )(params)(dispatch).then(() => { @@ -1326,16 +1340,92 @@ export const saveSponsorFormManagedItem = postRequest( createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), createAction(SPONSOR_FORM_MANAGED_ITEM_ADDED), - `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${entity.id}`, - entity, + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items`, + normalizedEntity, snackbarErrorHandler, entity )(params)(dispatch).then(() => { - dispatch(showMessage(successMessage)); + dispatch(snackbarSuccessHandler(successMessage)); }); } }; +export const resetSponsorFormManagedItem = () => (dispatch) => { + dispatch(createAction(RESET_SPONSOR_FORM_MANAGED_ITEM)({})); +}; + +const normalizeManagedItem = (entity) => { + const normalizedEntity = { ...entity }; + normalizedEntity.meta_fields = normalizedEntity.meta_fields?.filter( + (mf) => mf.name + ); + normalizedEntity.images = normalizedEntity.images?.filter( + (img) => img.file_path + ); + + if ( + entity.early_bird_rate === "" || + typeof entity.early_bird_rate === "undefined" + ) + delete normalizedEntity.early_bird_rate; + else + normalizedEntity.early_bird_rate = amountToCents( + normalizedEntity.early_bird_rate + ); + + if ( + entity.standard_rate === "" || + typeof entity.standard_rate === "undefined" + ) + delete normalizedEntity.standard_rate; + else + normalizedEntity.standard_rate = amountToCents( + normalizedEntity.standard_rate + ); + + if (entity.onsite_rate === "" || typeof entity.onsite_rate === "undefined") + delete normalizedEntity.onsite_rate; + else + normalizedEntity.onsite_rate = amountToCents(normalizedEntity.onsite_rate); + + return normalizedEntity; +}; + +export const deleteSponsorFormManagedItem = + (formId, itemId) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const { + entity: { id: sponsorId } + } = currentSponsorState; + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + return deleteRequest( + null, + createAction(SPONSOR_FORM_MANAGED_ITEM_DELETED)({ itemId }), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${itemId}`, + null, + snackbarErrorHandler + )(params)(dispatch) + .then(() => { + dispatch( + snackbarSuccessHandler({ + title: T.translate("general.success"), + html: T.translate("sponsor_forms.form_delete_success") + }) + ); + }) + .finally(() => { + dispatch(stopLoading()); + }); + }; + export const getSponsorFormManagedItem = (formId, itemId) => async (dispatch, getState) => { const { currentSummitState, currentSponsorState } = getState(); @@ -1353,7 +1443,7 @@ export const getSponsorFormManagedItem = return getRequest( null, - createAction(RECEIVE_SPONSOR_CUSTOMIZED_FORM), + createAction(RECEIVE_SPONSOR_CUSTOMIZED_FORM_ITEM), `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${itemId}`, authErrorHandler )(params)(dispatch).then(() => { @@ -1361,7 +1451,7 @@ export const getSponsorFormManagedItem = }); }; -export const addSponsorFormItems = +export const addSponsorManagedFormItems = (formId, itemIds) => async (dispatch, getState) => { const { currentSummitState, currentSponsorState } = getState(); const accessToken = await getAccessTokenSafely(); @@ -1378,7 +1468,7 @@ export const addSponsorFormItems = return postRequest( null, - createAction(SPONSOR_FORM_ITEMS_ADDED), + createAction(SPONSOR_CUSTOMIZED_FORM_ITEMS_ADDED), `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/clone`, { inventory_item_ids: itemIds }, snackbarErrorHandler @@ -1410,13 +1500,17 @@ export const archiveSponsorCustomizedFormItem = } = currentSponsorState; const params = { access_token: accessToken }; + dispatch(startLoading()); + return putRequest( null, createAction(SPONSOR_CUSTOMIZED_FORM_ITEM_ARCHIVED), `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${itemId}/archive`, null, snackbarErrorHandler - )(params)(dispatch); + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); }; export const unarchiveSponsorCustomizedFormItem = diff --git a/src/i18n/en.json b/src/i18n/en.json index a96c08949..3c0ef8f82 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2442,7 +2442,7 @@ "onsite_rate": "On site rate", "default_quantity": "Default Quantity", "add_selected": "Add Selected Items", - "item_updated": "Form item created successfully", + "item_updated": "Form item updated successfully", "item_created": "Form item {item} updated successfully", "placeholder": { "search": "Search..." diff --git a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js index d23b06abc..12725a8be 100644 --- a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js +++ b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js @@ -27,21 +27,22 @@ import { import AddIcon from "@mui/icons-material/Add"; import ImageIcon from "@mui/icons-material/Image"; import { - addSponsorFormItems, + addSponsorManagedFormItems, archiveSponsorCustomizedFormItem, getSponsorCustomizedFormItems, saveSponsorFormManagedItem, + deleteSponsorFormManagedItem, + resetSponsorFormManagedItem, unarchiveSponsorCustomizedFormItem, getSponsorFormManagedItem } from "../../../../../actions/sponsor-forms-actions"; -import { resetInventoryItemForm } from "../../../../../actions/inventory-item-actions"; import CustomAlert from "../../../../../components/mui/custom-alert"; import SearchInput from "../../../../../components/mui/search-input"; import MuiTableEditable from "../../../../../components/mui/editable-table/mui-table-editable"; import SponsorInventoryDialog from "../../../../sponsors_inventory/popup/sponsor-inventory-popup"; import SponsorFormItemFromInventoryPopup from "./sponsor-form-item-from-inventory"; import { parsePrice } from "../../../../../utils/currency"; -import { ONE_HUNDRED } from "../../../../../utils/constants"; +import { DEFAULT_CURRENT_PAGE } from "../../../../../utils/constants"; // import FormTemplateDialog from "../../../../sponsors_inventory/popup/form-template-popup"; const SponsorFormsManageItems = ({ @@ -56,9 +57,10 @@ const SponsorFormsManageItems = ({ totalCount, getSponsorCustomizedFormItems, currentInventoryItem, - resetInventoryItemForm, - addSponsorFormItems, + resetSponsorFormManagedItem, + addSponsorManagedFormItems, saveSponsorFormManagedItem, + deleteSponsorFormManagedItem, archiveSponsorCustomizedFormItem, unarchiveSponsorCustomizedFormItem, getSponsorFormManagedItem @@ -114,7 +116,7 @@ const SponsorFormsManageItems = ({ }; const handleItemSave = (item) => { - saveSponsorFormManagedItem(formId, item).then(() => + saveSponsorFormManagedItem(formId, item).then(() => { getSponsorCustomizedFormItems( formId, term, @@ -123,13 +125,14 @@ const SponsorFormsManageItems = ({ order, orderDir, hideArchived - ) - ); + ); + resetSponsorFormManagedItem(); + }); setOpenPopup(null); }; const handleOpenItemPopup = () => { - resetInventoryItemForm(); + resetSponsorFormManagedItem(); setOpenPopup("add_item"); }; @@ -151,13 +154,13 @@ const SponsorFormsManageItems = ({ }; const handleAddFromInventory = (itemsId) => { - addSponsorFormItems(formId, itemsId).then(() => handleClose()); + addSponsorManagedFormItems(formId, itemsId).then(() => handleClose()); }; const handleCellEdit = (rowId, column, value) => { const tmpEntity = { id: rowId, - [column]: Math.round(parsePrice(value) * ONE_HUNDRED) + [column]: parsePrice(value) }; saveSponsorFormManagedItem(formId, tmpEntity); }; @@ -168,6 +171,20 @@ const SponsorFormsManageItems = ({ ); }; + const handleRowDelete = (rowId) => { + deleteSponsorFormManagedItem(formId, rowId).then(() => + getSponsorCustomizedFormItems( + formId, + term, + DEFAULT_CURRENT_PAGE, + perPage, + order, + orderDir, + hideArchived + ) + ); + }; + const sponsorItemColumns = [ { columnKey: "code", @@ -271,7 +288,7 @@ const SponsorFormsManageItems = ({ mb: 2 }} > - + {totalCount} items @@ -311,7 +328,7 @@ const SponsorFormsManageItems = ({ {T.translate("edit_sponsor.forms_tab.form_manage_items.add_item")} - + - ), - dottedBorder: true } ]; diff --git a/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js b/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js index 4ec4344e3..b92b098eb 100644 --- a/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js +++ b/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js @@ -70,8 +70,8 @@ const SponsorItemDialog = ({ name: "", type: "Text", is_required: false, - minimum_quantity: null, - maximum_quantity: null, + minimum_quantity: 0, + maximum_quantity: 0, values: [] } ], @@ -98,11 +98,12 @@ const SponsorItemDialog = ({ yup.object().shape({ name: yup .string() - .when(["values", "minimum_quantity", "maximum_quantity"], { - is: (values, minQty, maxQty) => { + .when(["type", "values", "minimum_quantity", "maximum_quantity"], { + is: (type, values, minQty, maxQty) => { // required only if has values or quantities const hasValues = values && values.length > 0; - const hasQuantities = minQty != null || maxQty != null; + const hasQuantities = + type === "Quantity" && (minQty != null || maxQty != null); return hasValues || hasQuantities; }, then: (schema) => @@ -184,8 +185,8 @@ const SponsorItemDialog = ({ name: "", type: "Text", is_required: false, - minimum_quantity: null, - maximum_quantity: null, + minimum_quantity: 0, + maximum_quantity: 0, values: [] } ]); @@ -194,7 +195,7 @@ const SponsorItemDialog = ({ } }; - if (fieldType.id) { + if (fieldType.id && onMetaFieldTypeDeleted) { onMetaFieldTypeDeleted(initialEntity.id, fieldType.id) .then(() => removeOrResetField()) .catch((err) => console.log("Error at delete field from API", err)); @@ -590,8 +591,8 @@ const SponsorItemDialog = ({ type: "Text", is_required: false, values: [], - minimum_quantity: null, - maximum_quantity: null + minimum_quantity: 0, + maximum_quantity: 0 }) } > From cd699ff04822e9e7292566f475146c1cd93b6942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Castillo?= Date: Tue, 16 Dec 2025 16:17:44 -0300 Subject: [PATCH 7/9] fix: adjust image validation, reload list after save MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Castillo --- src/actions/sponsor-forms-actions.js | 40 +++++++++---------- .../popup/sponsor-inventory-popup.js | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/actions/sponsor-forms-actions.js b/src/actions/sponsor-forms-actions.js index 4becc3ac8..a1982fb02 100644 --- a/src/actions/sponsor-forms-actions.js +++ b/src/actions/sponsor-forms-actions.js @@ -1307,7 +1307,7 @@ export const saveSponsorFormManagedItem = const normalizedEntity = normalizeManagedItem(entity); if (entity.id) { - putRequest( + return putRequest( createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), createAction(SPONSOR_FORM_MANAGED_ITEM_UPDATED), `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items/${entity.id}`, @@ -1325,26 +1325,26 @@ export const saveSponsorFormManagedItem = }) ); }); - } else { - const successMessage = { - title: T.translate("general.done"), - html: T.translate( - "edit_sponsor.forms_tab.form_manage_items.item_created" - ), - type: "success" - }; - - postRequest( - createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), - createAction(SPONSOR_FORM_MANAGED_ITEM_ADDED), - `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items`, - normalizedEntity, - snackbarErrorHandler, - entity - )(params)(dispatch).then(() => { - dispatch(snackbarSuccessHandler(successMessage)); - }); } + + const successMessage = { + title: T.translate("general.done"), + html: T.translate( + "edit_sponsor.forms_tab.form_manage_items.item_created" + ), + type: "success" + }; + + return postRequest( + createAction(UPDATE_SPONSOR_FORM_MANAGED_ITEM), + createAction(SPONSOR_FORM_MANAGED_ITEM_ADDED), + `${window.PURCHASES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-forms/${formId}/items`, + normalizedEntity, + snackbarErrorHandler, + entity + )(params)(dispatch).then(() => { + dispatch(snackbarSuccessHandler(successMessage)); + }); }; export const resetSponsorFormManagedItem = () => (dispatch) => { diff --git a/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js b/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js index b92b098eb..434288705 100644 --- a/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js +++ b/src/pages/sponsors_inventory/popup/sponsor-inventory-popup.js @@ -81,7 +81,7 @@ const SponsorItemDialog = ({ code: yup.string().required(T.translate("validation.required")), name: yup.string().required(T.translate("validation.required")), description: yup.string().required(T.translate("validation.required")), - images: yup.array().min(1, T.translate("validation.required")), + images: yup.array(), early_bird_rate: decimalValidation(), standard_rate: decimalValidation(), onsite_rate: decimalValidation(), From d5ce9f8c7c6fd7e3ad70122c535c83cdd5cd235f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Castillo?= Date: Tue, 16 Dec 2025 16:45:28 -0300 Subject: [PATCH 8/9] fix: address changes from copilot suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Castillo --- src/actions/sponsor-forms-actions.js | 14 +++----- src/i18n/en.json | 6 ++-- src/layouts/sponsor-id-layout.js | 2 +- src/pages/sponsors/edit-sponsor-page.js | 32 +++++++++++++------ .../sponsor-form-item-from-inventory.js | 11 ++++++- .../sponsor-forms-manage-items.js | 7 +--- ...nsor-customized-form-items-list-reducer.js | 14 +------- src/utils/constants.js | 11 +++++++ 8 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/actions/sponsor-forms-actions.js b/src/actions/sponsor-forms-actions.js index a1982fb02..7dc067bf8 100644 --- a/src/actions/sponsor-forms-actions.js +++ b/src/actions/sponsor-forms-actions.js @@ -1360,27 +1360,21 @@ const normalizeManagedItem = (entity) => { (img) => img.file_path ); - if ( - entity.early_bird_rate === "" || - typeof entity.early_bird_rate === "undefined" - ) + if (entity.early_bird_rate === "" || entity.early_bird_rate === undefined) delete normalizedEntity.early_bird_rate; else normalizedEntity.early_bird_rate = amountToCents( normalizedEntity.early_bird_rate ); - if ( - entity.standard_rate === "" || - typeof entity.standard_rate === "undefined" - ) + if (entity.standard_rate === "" || entity.standard_rate === undefined) delete normalizedEntity.standard_rate; else normalizedEntity.standard_rate = amountToCents( normalizedEntity.standard_rate ); - if (entity.onsite_rate === "" || typeof entity.onsite_rate === "undefined") + if (entity.onsite_rate === "" || entity.onsite_rate === undefined) delete normalizedEntity.onsite_rate; else normalizedEntity.onsite_rate = amountToCents(normalizedEntity.onsite_rate); @@ -1481,7 +1475,7 @@ export const addSponsorManagedFormItems = }) ); }) - .catch(console.log) // need to catch promise reject + .catch(snackbarErrorHandler) // need to catch promise reject .finally(() => { dispatch(stopLoading()); }); diff --git a/src/i18n/en.json b/src/i18n/en.json index a4353cf83..eb149cd98 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2433,7 +2433,7 @@ "form_manage_items": { "add_item": "Add Item", "add_item_inventory": "Add Item from Inventory", - "alert_info": "You can add or archive items from the list. To edit an item click on the item's Edit botton. You can also change only a rate by clicking on it.", + "alert_info": "You can add or archive items from the list. To edit an item click on the item's Edit button. You can also change only a rate by clicking on it.", "select_items": "Select items", "code": "Code", "name": "Name", @@ -2443,7 +2443,7 @@ "default_quantity": "Default Quantity", "add_selected": "Add Selected Items", "item_updated": "Form item updated successfully", - "item_created": "Form item {item} updated successfully", + "item_created": "Form item {item} created successfully", "placeholder": { "search": "Search..." } @@ -2542,7 +2542,7 @@ }, "sponsor_form_item_list": { "form_items": "Form Items", - "alert_info": "You can add or archive items from the list. To edit an item click on the item's Edit botton. You can also change only a rate by clicking on it.", + "alert_info": "You can add or archive items from the list. To edit an item click on the item's Edit button. You can also change only a rate by clicking on it.", "code": "Code", "name": "Name", "early_bird_rate": "Early bird rate", diff --git a/src/layouts/sponsor-id-layout.js b/src/layouts/sponsor-id-layout.js index 62041bd8f..ddbdf1166 100644 --- a/src/layouts/sponsor-id-layout.js +++ b/src/layouts/sponsor-id-layout.js @@ -142,7 +142,7 @@ class SponsorIdLayout extends React.Component { )} /> - + { const { children, value, index, ...other } = props; @@ -99,7 +99,7 @@ const EditSponsorPage = (props) => { const [selectedTab, setSelectedTab] = useState( location.pathname.includes("/sponsor-forms/") && location.pathname.includes("/items") - ? FOUR + ? SPONSOR_TABS.FORMS : 0 ); @@ -126,14 +126,26 @@ const EditSponsorPage = (props) => { }; const tabs = [ - { label: T.translate("edit_sponsor.tab.general"), value: 0 }, - { label: T.translate("edit_sponsor.tab.users"), value: 1 }, - { label: T.translate("edit_sponsor.tab.pages"), value: 2 }, - { label: T.translate("edit_sponsor.tab.media_uploads"), value: 3 }, - { label: T.translate("edit_sponsor.tab.forms"), value: 4 }, - { label: T.translate("edit_sponsor.tab.cart"), value: 5 }, - { label: T.translate("edit_sponsor.tab.purchases"), value: 6 }, - { label: T.translate("edit_sponsor.tab.badge_scans"), value: 7 } + { + label: T.translate("edit_sponsor.tab.general"), + value: SPONSOR_TABS.GENERAL + }, + { label: T.translate("edit_sponsor.tab.users"), value: SPONSOR_TABS.USERS }, + { label: T.translate("edit_sponsor.tab.pages"), value: SPONSOR_TABS.PAGES }, + { + label: T.translate("edit_sponsor.tab.media_uploads"), + value: SPONSOR_TABS.MEDIA_UPLOADS + }, + { label: T.translate("edit_sponsor.tab.forms"), value: SPONSOR_TABS.FORMS }, + { label: T.translate("edit_sponsor.tab.cart"), value: SPONSOR_TABS.CART }, + { + label: T.translate("edit_sponsor.tab.purchases"), + value: SPONSOR_TABS.PURCHASES + }, + { + label: T.translate("edit_sponsor.tab.badge_scans"), + value: SPONSOR_TABS.BADGE_SCANS + } ]; const sponsorFormItemRoute = diff --git a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js index f5d29aaab..4fe13fca6 100644 --- a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js +++ b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js @@ -259,7 +259,16 @@ const SponsorFormItemFromInventoryPopup = ({ SponsorFormItemFromInventoryPopup.propTypes = { onClose: PropTypes.func.isRequired, - onSave: PropTypes.func.isRequired + onSave: PropTypes.func.isRequired, + open: PropTypes.bool.isRequired, + inventoryItems: PropTypes.array.isRequired, + term: PropTypes.string, + order: PropTypes.string, + perPage: PropTypes.number, + orderDir: PropTypes.string, + currentPage: PropTypes.number, + totalInventoryItems: PropTypes.number, + getInventoryItems: PropTypes.func.isRequired }; const mapStateToProps = ({ currentInventoryItemListState }) => ({ diff --git a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js index 1e6cb0934..c5cc4b29a 100644 --- a/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js +++ b/src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js @@ -44,7 +44,6 @@ import SponsorInventoryDialog from "../../../../sponsors_inventory/popup/sponsor import SponsorFormItemFromInventoryPopup from "./sponsor-form-item-from-inventory"; import { parsePrice } from "../../../../../utils/currency"; import { DEFAULT_CURRENT_PAGE } from "../../../../../utils/constants"; -// import FormTemplateDialog from "../../../../sponsors_inventory/popup/form-template-popup"; const SponsorFormsManageItems = ({ term, @@ -318,7 +317,7 @@ const SponsorFormsManageItems = ({ Date: Thu, 18 Dec 2025 11:52:30 -0300 Subject: [PATCH 9/9] fix: adjust impots on sponsor id layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomás Castillo --- src/layouts/sponsor-id-layout.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/sponsor-id-layout.js b/src/layouts/sponsor-id-layout.js index ddbdf1166..20af2cee8 100644 --- a/src/layouts/sponsor-id-layout.js +++ b/src/layouts/sponsor-id-layout.js @@ -1,8 +1,8 @@ import React from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; -import { Switch, Route } from "react-router-dom"; import { Breadcrumb } from "react-breadcrumbs"; +import { Switch, Route } from "react-router-dom"; import EditSponsorPage from "../pages/sponsors/edit-sponsor-page"; import { getSponsor, resetSponsorForm } from "../actions/sponsor-actions"; import EditAdSponsorPage from "../pages/sponsors/edit-advertisement-sponsor-page";