diff --git a/src/actions/page-template-actions.js b/src/actions/page-template-actions.js index 363230881..bd54f5e0e 100644 --- a/src/actions/page-template-actions.js +++ b/src/actions/page-template-actions.js @@ -12,6 +12,7 @@ * */ import T from "i18n-react/dist/i18n-react"; +import moment from "moment-timezone"; import { getRequest, putRequest, @@ -27,7 +28,8 @@ import { getAccessTokenSafely } from "../utils/methods"; import { DEFAULT_CURRENT_PAGE, DEFAULT_ORDER_DIR, - DEFAULT_PER_PAGE + DEFAULT_PER_PAGE, + PAGES_MODULE_KINDS } from "../utils/constants"; import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions"; @@ -143,7 +145,16 @@ export const resetPageTemplateForm = () => (dispatch) => { const normalizeEntity = (entity) => { const normalizedEntity = { ...entity }; - normalizedEntity.modules = []; + normalizedEntity.modules = entity.modules.map((module) => { + const normalizedModule = { ...module }; + + if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.upload_deadline) { + normalizedModule.upload_deadline = moment(module.upload_deadline).unix(); + } + delete normalizedModule._tempId; + + return normalizedModule; + }); return normalizedEntity; }; diff --git a/src/actions/sponsor-pages-actions.js b/src/actions/sponsor-pages-actions.js new file mode 100644 index 000000000..e93e0042c --- /dev/null +++ b/src/actions/sponsor-pages-actions.js @@ -0,0 +1,134 @@ +/** + * 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, + postRequest, + startLoading, + stopLoading +} from "openstack-uicore-foundation/lib/utils/actions"; +import T from "i18n-react/dist/i18n-react"; +import { escapeFilterValue, getAccessTokenSafely } from "../utils/methods"; +import { + DEFAULT_CURRENT_PAGE, + DEFAULT_ORDER_DIR, + DEFAULT_PER_PAGE +} from "../utils/constants"; +import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions"; + +export const REQUEST_SPONSOR_PAGES = "REQUEST_SPONSOR_PAGES"; +export const RECEIVE_SPONSOR_PAGES = "RECEIVE_SPONSOR_PAGES"; + +export const GLOBAL_PAGE_CLONED = "GLOBAL_PAGE_CLONED"; + +export const getSponsorPages = + ( + term = "", + page = DEFAULT_CURRENT_PAGE, + perPage = DEFAULT_PER_PAGE, + order = "id", + orderDir = DEFAULT_ORDER_DIR, + hideArchived = false, + sponsorshipTypesId = [] + ) => + async (dispatch, getState) => { + const { currentSummitState } = getState(); + const { currentSummit } = currentSummitState; + 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, + expand: "sponsorship_types" + }; + + if (hideArchived) filter.push("is_archived==0"); + + if (sponsorshipTypesId?.length > 0) { + const formattedSponsorships = sponsorshipTypesId.join("&&"); + filter.push("applies_to_all_tiers==0"); + filter.push(`sponsorship_type_id_not_in==${formattedSponsorships}`); + } + + 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_PAGES), + createAction(RECEIVE_SPONSOR_PAGES), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/show-pages`, + authErrorHandler, + { order, orderDir, page, term, hideArchived } + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; + +export const cloneGlobalPage = + (pagesIds, sponsorIds, allSponsors) => async (dispatch, getState) => { + const { currentSummitState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + const normalizedEntity = { + page_template_ids: pagesIds, + sponsorship_types: sponsorIds, + apply_to_all_types: allSponsors + }; + + if (allSponsors) { + delete normalizedEntity.sponsorship_types; + } + + return postRequest( + null, + createAction(GLOBAL_PAGE_CLONED), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/show-pages/clone`, + normalizedEntity, + snackbarErrorHandler + )(params)(dispatch) + .then(() => { + dispatch(getSponsorForms()); + dispatch( + snackbarSuccessHandler({ + title: T.translate("general.success"), + html: T.translate("sponsor_pages.global_page_popup.success") + }) + ); + }) + .catch(() => {}); // need to catch promise reject + }; diff --git a/src/components/menu/index.js b/src/components/menu/index.js index 83e492498..0689c4f10 100644 --- a/src/components/menu/index.js +++ b/src/components/menu/index.js @@ -244,6 +244,11 @@ const getSummitItems = (summitId) => [ linkUrl: `summits/${summitId}/sponsors/forms`, accessRoute: "admin-sponsors" }, + { + name: "sponsor_pages", + linkUrl: `summits/${summitId}/sponsors/pages`, + accessRoute: "admin-sponsors" + }, { name: "sponsorship_list", linkUrl: `summits/${summitId}/sponsorships`, diff --git a/src/components/mui/formik-inputs/mui-formik-datepicker.js b/src/components/mui/formik-inputs/mui-formik-datepicker.js index 3bb67cecc..a9c23486f 100644 --- a/src/components/mui/formik-inputs/mui-formik-datepicker.js +++ b/src/components/mui/formik-inputs/mui-formik-datepicker.js @@ -19,8 +19,7 @@ const MuiFormikDatepicker = ({ name, label, required }) => { label: required ? requiredLabel : label, error: meta.touched && Boolean(meta.error), helperText: meta.touched && meta.error, - fullWidth: true, - margin: "normal" + fullWidth: true }, day: { sx: { @@ -36,6 +35,9 @@ const MuiFormikDatepicker = ({ name, label, required }) => { } } }} + margin="normal" + // eslint-disable-next-line react/jsx-props-no-spreading + {...props} /> ); diff --git a/src/components/mui/formik-inputs/mui-formik-radio-group.js b/src/components/mui/formik-inputs/mui-formik-radio-group.js index 01200434f..79cb82327 100644 --- a/src/components/mui/formik-inputs/mui-formik-radio-group.js +++ b/src/components/mui/formik-inputs/mui-formik-radio-group.js @@ -10,13 +10,19 @@ import { } from "@mui/material"; import { useField } from "formik"; -const MuiFormikRadioGroup = ({ name, label, options, ...props }) => { +const MuiFormikRadioGroup = ({ + name, + label, + margin = "normal", + options, + ...props +}) => { const [field, meta] = useField({ name }); return ( {label && {label}} @@ -56,6 +62,7 @@ const MuiFormikRadioGroup = ({ name, label, options, ...props }) => { MuiFormikRadioGroup.propTypes = { name: PropTypes.string.isRequired, label: PropTypes.string, + margin: PropTypes.string, options: PropTypes.array.isRequired }; diff --git a/src/components/mui/formik-inputs/mui-formik-select.js b/src/components/mui/formik-inputs/mui-formik-select.js index f8c2aa75e..8bde07ba0 100644 --- a/src/components/mui/formik-inputs/mui-formik-select.js +++ b/src/components/mui/formik-inputs/mui-formik-select.js @@ -5,13 +5,15 @@ import { FormHelperText, FormControl, InputAdornment, - IconButton + IconButton, + InputLabel } from "@mui/material"; import ClearIcon from "@mui/icons-material/Clear"; import { useField } from "formik"; const MuiFormikSelect = ({ name, + label, placeholder, children, isClearable, @@ -24,12 +26,23 @@ const MuiFormikSelect = ({ helpers.setValue(""); }; + const hasValue = + field.value !== "" && field.value !== undefined && field.value !== null; + return ( + {label && ( + + {label} + + )}