diff --git a/src/actions/sponsor-pages-actions.js b/src/actions/sponsor-pages-actions.js index cb7355d1d..e8517585e 100644 --- a/src/actions/sponsor-pages-actions.js +++ b/src/actions/sponsor-pages-actions.js @@ -34,6 +34,14 @@ export const RECEIVE_SPONSOR_PAGES = "RECEIVE_SPONSOR_PAGES"; export const GLOBAL_PAGE_CLONED = "GLOBAL_PAGE_CLONED"; +export const REQUEST_SPONSOR_MANAGED_PAGES = "REQUEST_SPONSOR_MANAGED_PAGES"; +export const RECEIVE_SPONSOR_MANAGED_PAGES = "RECEIVE_SPONSOR_MANAGED_PAGES"; + +export const REQUEST_SPONSOR_CUSTOMIZED_PAGES = + "REQUEST_SPONSOR_CUSTOMIZED_PAGES"; +export const RECEIVE_SPONSOR_CUSTOMIZED_PAGES = + "RECEIVE_SPONSOR_CUSTOMIZED_PAGES"; + export const getSponsorPages = ( term = "", @@ -133,3 +141,123 @@ export const cloneGlobalPage = }) .finally(() => dispatch(stopLoading())); }; + +/* ************************************************************************ */ +/* MANAGED PAGES */ +/* ************************************************************************ */ + +export const getSponsorManagedPages = + ( + 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 summitTZ = currentSummit.time_zone.name; + const filter = []; + + dispatch(startLoading()); + + if (term) { + const escapedTerm = escapeFilterValue(term); + filter.push(`name=@${escapedTerm},code=@${escapedTerm}`); + } + + const params = { + page, + fields: "id,code,name,kind,modules_count,allowed_add_ons", + 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_MANAGED_PAGES), + createAction(RECEIVE_SPONSOR_MANAGED_PAGES), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/managed-pages`, + authErrorHandler, + { order, orderDir, page, perPage, term, hideArchived, summitTZ } + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; + +/* ************************************************************************ */ +/* CUSTOMIZED PAGES */ +/* ************************************************************************ */ + +export const getSponsorCustomizedPages = + ( + 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 summitTZ = currentSummit.time_zone.name; + const filter = []; + + dispatch(startLoading()); + + if (term) { + const escapedTerm = escapeFilterValue(term); + filter.push(`name=@${escapedTerm},code=@${escapedTerm}`); + } + + const params = { + page, + fields: "id,code,name,kind,modules_count,allowed_add_ons", + 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_PAGES), + createAction(RECEIVE_SPONSOR_CUSTOMIZED_PAGES), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/sponsor-pages`, + authErrorHandler, + { order, orderDir, page, perPage, term, hideArchived, summitTZ } + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; diff --git a/src/i18n/en.json b/src/i18n/en.json index abea35a2c..8b9a4e6d0 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2460,6 +2460,23 @@ } } }, + "pages_tab": { + "alert_info": "To add a Sponsor Specific Page for this show's sponsor, click Add Page button. Note: this Page will be visible only to this sponsor for this show. The General Pages can only be managed on the Show's Pages section.", + "hide_archived": "Hide archived Pages", + "using_template": "Using Template", + "new_page": "New Page", + "pages": "pages", + "managed_pages": "Managed Pages", + "sponsor_customized_pages": "Customized Sponsor Pages", + "code": "Code", + "name": "Name", + "add_ons": "Add-ons", + "info_mod": "Info Mod", + "upload_mod": "Upload Mod", + "download_mod": "Download Mod", + "archive": "Archive", + "unarchive": "Unarchive" + }, "cart_tab": { "new_form": "New Form", "forms": "forms", diff --git a/src/pages/sponsors/edit-sponsor-page.js b/src/pages/sponsors/edit-sponsor-page.js index d3101dc25..e50a842d2 100644 --- a/src/pages/sponsors/edit-sponsor-page.js +++ b/src/pages/sponsors/edit-sponsor-page.js @@ -43,6 +43,7 @@ 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"; +import SponsorPagesTab from "./sponsor-pages-tab"; import SponsorFormsManageItems from "./sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items"; import { SPONSOR_TABS } from "../../utils/constants"; @@ -235,6 +236,13 @@ const EditSponsorPage = (props) => { + + + {sponsorFormItemRoute ? ( diff --git a/src/pages/sponsors/sponsor-pages-tab/index.js b/src/pages/sponsors/sponsor-pages-tab/index.js new file mode 100644 index 000000000..2bccf1a86 --- /dev/null +++ b/src/pages/sponsors/sponsor-pages-tab/index.js @@ -0,0 +1,355 @@ +/** + * 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 } from "react"; +import { connect } from "react-redux"; +import T from "i18n-react/dist/i18n-react"; +import { + Box, + Button, + Checkbox, + FormControlLabel, + FormGroup, + Grid2 +} from "@mui/material"; +import AddIcon from "@mui/icons-material/Add"; +import { + archiveSponsorCustomizedForm, + deleteSponsorCustomizedForm, + saveSponsorManagedForm, + unarchiveSponsorCustomizedForm +} from "../../../actions/sponsor-forms-actions"; +import { + getSponsorManagedPages, + getSponsorCustomizedPages +} from "../../../actions/sponsor-pages-actions"; +import CustomAlert from "../../../components/mui/custom-alert"; +import SearchInput from "../../../components/mui/search-input"; +import MuiTable from "../../../components/mui/table/mui-table"; +// import AddSponsorFormTemplatePopup from "./components/add-sponsor-form-template-popup"; +// import CustomizedFormPopup from "./components/customized-form/customized-form-popup"; +import { DEFAULT_CURRENT_PAGE } from "../../../utils/constants"; + +const SponsorPagesTab = ({ + term, + hideArchived, + managedPages, + customizedPages, + getSponsorManagedPages, + getSponsorCustomizedPages +}) => { + useEffect(() => { + getSponsorManagedPages(); + getSponsorCustomizedPages(); + }, []); + + const handleManagedPageChange = (page) => { + const { perPage, order, orderDir } = managedPages; + getSponsorManagedPages(term, page, perPage, order, orderDir, hideArchived); + }; + + const handleManagedPerPageChange = (newPerPage) => { + const { currentPage, order, orderDir } = managedPages; + getSponsorManagedPages( + term, + currentPage, + newPerPage, + order, + orderDir, + hideArchived + ); + }; + + const handleManagedSort = (key, dir) => { + const { currentPage, perPage } = managedPages; + getSponsorManagedPages(term, currentPage, perPage, key, dir, hideArchived); + }; + + const handleCustomizedPageChange = (page) => { + const { perPage, order, orderDir } = customizedPages; + getSponsorCustomizedPages( + term, + page, + perPage, + order, + orderDir, + hideArchived + ); + }; + + const handleCustomizedPerPageChange = (newPerPage) => { + const { currentPage, order, orderDir } = customizedPages; + getSponsorCustomizedPages( + term, + currentPage, + newPerPage, + order, + orderDir, + hideArchived + ); + }; + + const handleCustomizedSort = (key, dir) => { + const { currentPage, perPage } = customizedPages; + + getSponsorCustomizedPages( + term, + currentPage, + perPage, + key, + dir, + hideArchived + ); + }; + + const handleSearch = (searchTerm) => { + const { + perPage: perPageManaged, + order: orderManaged, + orderDir: orderDirManaged + } = managedPages; + const { + perPage: perPageCustomized, + order: orderCustomized, + orderDir: orderDirCustomized + } = customizedPages; + getSponsorManagedPages( + searchTerm, + DEFAULT_CURRENT_PAGE, + perPageManaged, + orderManaged, + orderDirManaged, + hideArchived + ); + getSponsorCustomizedPages( + searchTerm, + DEFAULT_CURRENT_PAGE, + perPageCustomized, + orderCustomized, + orderDirCustomized, + hideArchived + ); + }; + + const handleArchiveCustomizedPage = (item) => + console.log("ARCHIVE CUSTOMIZED ", item); + + const handleArchiveManagedPage = (item) => + console.log("ARCHIVE MANAGED ", item); + + const handleManagedEdit = (item) => { + console.log("EDIT MANAGED ", item); + }; + + const handleManagedDelete = (itemId) => { + console.log("DELETE MANAGED ", itemId); + }; + + const handleCustomizedEdit = (item) => { + console.log("EDIT CUSTOMIZED ", item); + }; + + const handleCustomizedDelete = (itemId) => { + console.log("DELETE CUSTOMIZED ", itemId); + }; + + const handleHideArchived = (ev) => { + getSponsorManagedPages( + term, + DEFAULT_CURRENT_PAGE, + managedPages.perPage, + managedPages.order, + managedPages.orderDir, + ev.target.checked + ); + getSponsorCustomizedPages( + term, + DEFAULT_CURRENT_PAGE, + customizedPages.perPage, + customizedPages.order, + customizedPages.orderDir, + ev.target.checked + ); + }; + + const baseColumns = (name) => [ + { + columnKey: "name", + header: name, + sortable: true + }, + { + columnKey: "code", + header: T.translate("edit_sponsor.pages_tab.code"), + sortable: true + }, + { + columnKey: "allowed_add_ons", + header: T.translate("edit_sponsor.pages_tab.add_ons"), + sortable: true, + render: (row) => + row.allowed_add_ons?.length > 0 + ? row.allowed_add_ons.map((a) => `${a.type} ${a.name}`).join(", ") + : "" + }, + { + columnKey: "info_mod", + header: T.translate("edit_sponsor.pages_tab.info_mod") + }, + { + columnKey: "upload_mod", + header: T.translate("edit_sponsor.pages_tab.upload_mod") + }, + { + columnKey: "download_mod", + header: T.translate("edit_sponsor.pages_tab.download_mod") + } + ]; + + const managedPagesColumns = [ + ...baseColumns(T.translate("edit_sponsor.pages_tab.managed_pages")) + ]; + + const customizedPagesColumns = [ + ...baseColumns( + T.translate("edit_sponsor.pages_tab.sponsor_customized_pages") + ) + ]; + + return ( + + + + + + {managedPages.totalCount + customizedPages.totalCount}{" "} + {T.translate("edit_sponsor.pages_tab.pages")} + + + + + + } + label={T.translate("edit_sponsor.pages_tab.hide_archived")} + /> + + + + + + + + + + + + +
+ +
+ +
+ +
+
+ ); +}; + +const mapStateToProps = ({ sponsorPagePagesListState }) => ({ + ...sponsorPagePagesListState +}); + +export default connect(mapStateToProps, { + getSponsorManagedPages, + saveSponsorManagedForm, + getSponsorCustomizedPages, + archiveSponsorCustomizedForm, + unarchiveSponsorCustomizedForm, + deleteSponsorCustomizedForm +})(SponsorPagesTab); diff --git a/src/reducers/sponsors/sponsor-page-pages-list-reducer.js b/src/reducers/sponsors/sponsor-page-pages-list-reducer.js new file mode 100644 index 000000000..b5e799ea0 --- /dev/null +++ b/src/reducers/sponsors/sponsor-page-pages-list-reducer.js @@ -0,0 +1,154 @@ +/** + * 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 { + REQUEST_SPONSOR_MANAGED_PAGES, + RECEIVE_SPONSOR_MANAGED_PAGES, + RECEIVE_SPONSOR_CUSTOMIZED_PAGES, + REQUEST_SPONSOR_CUSTOMIZED_PAGES +} from "../../actions/sponsor-pages-actions"; +import { SET_CURRENT_SUMMIT } from "../../actions/summit-actions"; + +const DEFAULT_STATE = { + managedPages: { + pages: [], + order: "name", + orderDir: 1, + currentPage: 1, + lastPage: 1, + perPage: 10, + totalCount: 0 + }, + customizedPages: { + pages: [], + order: "name", + orderDir: 1, + currentPage: 1, + lastPage: 1, + perPage: 10, + totalCount: 0 + }, + term: "", + hideArchived: false, + summitTZ: "" +}; + +const sponsorPagePagesListReducer = (state = DEFAULT_STATE, action) => { + const { type, payload } = action; + + switch (type) { + case SET_CURRENT_SUMMIT: + case LOGOUT_USER: { + return DEFAULT_STATE; + } + case REQUEST_SPONSOR_MANAGED_PAGES: { + const { order, orderDir, page, perPage, term, summitTZ, hideArchived } = + payload; + + return { + ...state, + managedPages: { + ...state.managedPages, + order, + orderDir, + pages: [], + currentPage: page, + perPage + }, + term, + summitTZ, + hideArchived + }; + } + case REQUEST_SPONSOR_CUSTOMIZED_PAGES: { + const { order, orderDir, page, perPage, term, summitTZ, hideArchived } = + payload; + + return { + ...state, + customizedPages: { + ...state.customizedPages, + order, + orderDir, + pages: [], + currentPage: page, + perPage + }, + term, + summitTZ, + hideArchived + }; + } + case RECEIVE_SPONSOR_MANAGED_PAGES: { + const { + current_page: currentPage, + total, + last_page: lastPage + } = payload.response; + + const pages = payload.response.data.map((a) => ({ + id: a.id, + code: a.code, + name: a.name, + allowed_add_ons: a.allowed_add_ons, + info_mod: a.modules_count.info_modules_count, + upload_mod: a.modules_count.document_download_modules_count, + download_mod: a.modules_count.media_request_modules_count + })); + + return { + ...state, + managedPages: { + ...state.managedPages, + pages, + currentPage, + totalCount: total, + lastPage + } + }; + } + case RECEIVE_SPONSOR_CUSTOMIZED_PAGES: { + const { + current_page: currentPage, + total, + last_page: lastPage + } = payload.response; + + const pages = payload.response.data.map((a) => ({ + id: a.id, + code: a.code, + name: a.name, + allowed_add_ons: a.allowed_add_ons, + info_mod: a.modules_count.info_modules_count, + upload_mod: a.modules_count.media_request_modules_count, + download_mod: a.modules_count.document_download_modules_count + })); + + return { + ...state, + customizedPages: { + ...state.customizedPages, + pages, + currentPage, + totalCount: total, + lastPage + } + }; + } + default: + return state; + } +}; + +export default sponsorPagePagesListReducer; diff --git a/src/store.js b/src/store.js index ae9386539..978711df4 100644 --- a/src/store.js +++ b/src/store.js @@ -168,6 +168,7 @@ import sponsorCustomizedFormReducer from "./reducers/sponsors/sponsor-customized import sponsorPageCartListReducer from "./reducers/sponsors/sponsor-page-cart-list-reducer"; import sponsorCustomizedFormItemsListReducer from "./reducers/sponsors/sponsor-customized-form-items-list-reducer.js"; import sponsorPagesListReducer from "./reducers/sponsors/sponsor-pages-list-reducer.js"; +import sponsorPagePagesListReducer from "./reducers/sponsors/sponsor-page-pages-list-reducer.js"; // default: localStorage if web, AsyncStorage if react-native @@ -255,6 +256,7 @@ const reducers = persistCombineReducers(config, { sponsorUsersListState: sponsorUsersListReducer, sponsorPageFormsListState: sponsorPageFormsListReducer, sponsorPageCartListState: sponsorPageCartListReducer, + sponsorPagePagesListState: sponsorPagePagesListReducer, sponsorCustomizedFormState: sponsorCustomizedFormReducer, sponsorCustomizedFormItemsListState: sponsorCustomizedFormItemsListReducer, currentSponsorPromocodeListState: sponsorPromocodeListReducer, @@ -307,7 +309,7 @@ const reducers = persistCombineReducers(config, { sponsoredProjectState: sponsoredProjectReducer, sponsoredProjectSponsorshipTypeState: sponsoredProjectSponsorshipTypeReducer, sponsoredProjectSponsorshipTypeSupportingCompanyState: - sponsoredProjectSponsorshipTypeSupportingCompanyReducer, + sponsoredProjectSponsorshipTypeSupportingCompanyReducer, scheduleSettingsState: scheduleSettingsReducer, scheduleSettingsListState: scheduleSettingsListReducer, currentSelectionPlanExtraQuestionState: selectionPlanExtraQuestionReducer,