From 1927cdb23593ff834b72f13608a4bf002e5fcad1 Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Tue, 18 Aug 2026 13:47:41 -0300 Subject: [PATCH 1/6] chore: add actions and mu_type --- src/actions/sponsor-mu-actions.js | 59 +++++++++++++++++++ .../tabs/sponsor-media-upload-tab/index.js | 14 ++++- .../sponsors/sponsor-page-mu-list-reducer.js | 3 +- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/actions/sponsor-mu-actions.js b/src/actions/sponsor-mu-actions.js index f8ef47791..4c31c84de 100644 --- a/src/actions/sponsor-mu-actions.js +++ b/src/actions/sponsor-mu-actions.js @@ -178,3 +178,62 @@ export const removeFileForSponsorMU = dispatch(stopLoading()); }); }; + +export const uploadTextForSponsorMU = + (pageId, moduleId, text) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const { currentSummit } = currentSummitState; + const { entity: sponsor } = currentSponsorState; + const accessToken = await getAccessTokenSafely(); + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + return putRequest( + null, + createAction("DUMMY_ACTION"), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsor.id}/available-pages/${pageId}/modules/${moduleId}/text`, + {value: text}, + snackbarErrorHandler + )(params)(dispatch) + .then(({ response }) => { + console.log('RESPONSE: ', response); + + dispatch( + createAction(SPONSOR_MEDIA_UPLOAD_FILE_UPLOADED)({ + ...response, + moduleId + }) + ); + }) + .finally(() => { + dispatch(stopLoading()); + }); + }; + +export const removeTextForSponsorMU = + (pageId, moduleId) => async (dispatch, getState) => { + const { currentSummitState, currentSponsorState } = getState(); + const { currentSummit } = currentSummitState; + const { entity: sponsor } = currentSponsorState; + const accessToken = await getAccessTokenSafely(); + + dispatch(startLoading()); + + const params = { + access_token: accessToken + }; + + return deleteRequest( + null, + createAction(SPONSOR_MEDIA_UPLOAD_FILE_DELETED)({ moduleId }), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsor.id}/available-pages/${pageId}/modules/${moduleId}/text`, + null, + snackbarErrorHandler + )(params)(dispatch).finally(() => { + dispatch(stopLoading()); + }); + }; \ No newline at end of file diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js index 3488daf48..78124f12d 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js @@ -24,7 +24,9 @@ import { getGeneralMURequests, getSponsorMURequests, removeFileForSponsorMU, - uploadFileForSponsorMU + uploadFileForSponsorMU, + uploadTextForSponsorMU, + removeTextForSponsorMU } from "../../../../../actions/sponsor-mu-actions"; import CustomAlert from "../../../../../components/mui/custom-alert"; import { SPONSOR_MEDIA_UPLOAD_STATUS } from "../../../../../utils/constants"; @@ -39,7 +41,9 @@ const SponsorMediaUploadTab = ({ getSponsorMURequests, getGeneralMURequests, uploadFileForSponsorMU, - removeFileForSponsorMU + removeFileForSponsorMU, + uploadTextForSponsorMU, + removeTextForSponsorMU }) => { const [uploadModule, setUploadModule] = useState(null); const [previewModule, setPreviewModule] = useState(null); @@ -95,6 +99,8 @@ const SponsorMediaUploadTab = ({ confirmButtonText: T.translate("general.yes_delete") }); + console.log("ITEM: ", item); + if (isConfirmed) { removeFileForSponsorMU(item.page_id, item.id); } @@ -300,5 +306,7 @@ export default connect(mapStateToProps, { getSponsorMURequests, getGeneralMURequests, uploadFileForSponsorMU, - removeFileForSponsorMU + removeFileForSponsorMU, + uploadTextForSponsorMU, + removeTextForSponsorMU })(SponsorMediaUploadTab); diff --git a/src/reducers/sponsors/sponsor-page-mu-list-reducer.js b/src/reducers/sponsors/sponsor-page-mu-list-reducer.js index 3d7453395..e904d6d6d 100644 --- a/src/reducers/sponsors/sponsor-page-mu-list-reducer.js +++ b/src/reducers/sponsors/sponsor-page-mu-list-reducer.js @@ -81,7 +81,8 @@ const mapMediaObject = (mediaObject) => { max_size: `${bytesToMb(mediaObject.max_file_size)} MB`, format: mediaObject.file_type?.allowed_extensions || "N/A", deadline, - status: getStatus(mediaObject) + status: getStatus(mediaObject), + mu_type: mediaObject.file_type ? "file" : "text" }; }; From e03cfcded0d3a0689f8c729bf3be66e90c61cba7 Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Tue, 18 Aug 2026 16:34:22 -0300 Subject: [PATCH 2/6] chore: new text type media upload dialogs --- package.json | 2 +- src/actions/sponsor-mu-actions.js | 6 +- src/components/mui/PreviewModal/index.jsx | 38 +-- src/components/upload-dialog/index.js | 30 +- src/i18n/en.json | 5 +- .../__tests__/index.test.jsx | 276 ++++++++++++++++++ .../__tests__/index.test.jsx | 68 +++++ .../components/text-preview-modal/index.jsx | 76 +++++ .../__tests__/index.test.jsx | 105 +++++++ .../components/text-value-dialog/index.js | 99 +++++++ .../tabs/sponsor-media-upload-tab/index.js | 94 ++++-- yarn.lock | 8 +- 12 files changed, 715 insertions(+), 92 deletions(-) create mode 100644 src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/__tests__/index.test.jsx create mode 100644 src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/__tests__/index.test.jsx create mode 100644 src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx create mode 100644 src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx create mode 100644 src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js diff --git a/package.json b/package.json index 849620011..f8e5daf70 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "moment-duration-format": "^2.3.2", "moment-timezone": "^0.5.33", "mui-color-input": "^9.0.0", - "openstack-uicore-foundation": "5.0.47", + "openstack-uicore-foundation": "5.0.50-beta.0", "p-limit": "^6.1.0", "path-browserify": "^1.0.1", "postcss-loader": "^6.2.1", diff --git a/src/actions/sponsor-mu-actions.js b/src/actions/sponsor-mu-actions.js index 4c31c84de..be0cd3fe9 100644 --- a/src/actions/sponsor-mu-actions.js +++ b/src/actions/sponsor-mu-actions.js @@ -196,12 +196,10 @@ export const uploadTextForSponsorMU = null, createAction("DUMMY_ACTION"), `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsor.id}/available-pages/${pageId}/modules/${moduleId}/text`, - {value: text}, + { value: text }, snackbarErrorHandler )(params)(dispatch) .then(({ response }) => { - console.log('RESPONSE: ', response); - dispatch( createAction(SPONSOR_MEDIA_UPLOAD_FILE_UPLOADED)({ ...response, @@ -236,4 +234,4 @@ export const removeTextForSponsorMU = )(params)(dispatch).finally(() => { dispatch(stopLoading()); }); - }; \ No newline at end of file + }; diff --git a/src/components/mui/PreviewModal/index.jsx b/src/components/mui/PreviewModal/index.jsx index 23b038794..be2db4c7b 100644 --- a/src/components/mui/PreviewModal/index.jsx +++ b/src/components/mui/PreviewModal/index.jsx @@ -1,15 +1,8 @@ import React, { useEffect, useState } from "react"; import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; -import { - Dialog, - DialogTitle, - DialogContent, - Box, - Typography, - IconButton -} from "@mui/material"; -import CloseIcon from "@mui/icons-material/Close"; +import { Box, DialogContent, Typography } from "@mui/material"; +import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; import BrokenImageOutlinedIcon from "@mui/icons-material/BrokenImageOutlined"; import { formatDate } from "../../../utils/methods"; @@ -35,30 +28,7 @@ const PreviewModal = ({ title, open, onClose, url, filename, uploadDate }) => { }, [open]); return ( - - - {title} - - ({ - position: "absolute", - right: 12, - top: 12, - color: theme.palette.grey[500] - })} - > - - + { )} - + ); }; diff --git a/src/components/upload-dialog/index.js b/src/components/upload-dialog/index.js index a9dcd8ccf..4bc966642 100644 --- a/src/components/upload-dialog/index.js +++ b/src/components/upload-dialog/index.js @@ -15,21 +15,19 @@ import React, { useState } from "react"; import { Box, Button, - Dialog, + DialogActions, DialogContent, - DialogTitle, Divider, IconButton, Typography } from "@mui/material"; import PropTypes from "prop-types"; import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3"; +import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; import T from "i18n-react/dist/i18n-react"; -import CloseIcon from "@mui/icons-material/Close"; import NoteAddIcon from "@mui/icons-material/NoteAdd"; import DeleteIcon from "@mui/icons-material/Delete"; import CheckCircleIcon from "@mui/icons-material/CheckCircle"; -import DialogActions from "@mui/material/DialogActions"; const MAX_PAGE_MODULE_UPLOAD_QTY = 1; @@ -108,23 +106,11 @@ const UploadDialog = ({ const canAddMore = () => (value?.length || 0) < maxFiles; return ( - - - {T.translate("edit_sponsor.mu_tab.upload_input.upload_file")} - - ({ - position: "absolute", - right: 8, - top: 8, - color: theme.palette.grey[500] - })} - > - - - + {fileMeta.name} @@ -163,7 +149,7 @@ const UploadDialog = ({ {T.translate("edit_sponsor.mu_tab.upload_input.upload_file")} - + ); }; diff --git a/src/i18n/en.json b/src/i18n/en.json index 58eb3a2c0..0836c5b2d 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2721,6 +2721,7 @@ "media_upload": "media upload", "sponsor_request": "Sponsor Specific Request", "general_request": "General Media Request", + "type": "Type", "add_on": "Add-on", "max_size": "Max Size", "format": "Format", @@ -2728,7 +2729,9 @@ "status": "Status", "upload_input": { "complete": "Complete", - "upload_file": "Upload file" + "upload_file": "Upload file", + "enter_text": "Enter text", + "save_answer": "Save Answer" } }, "placeholders": { diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/__tests__/index.test.jsx b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/__tests__/index.test.jsx new file mode 100644 index 000000000..ec1a1cc13 --- /dev/null +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/__tests__/index.test.jsx @@ -0,0 +1,276 @@ +import React from "react"; +import { screen, within, act } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import "@testing-library/jest-dom"; +import { renderWithRedux } from "../../../../../../utils/test-utils"; +import SponsorMediaUploadTab from "../index"; +import { + uploadFileForSponsorMU, + removeFileForSponsorMU, + uploadTextForSponsorMU, + removeTextForSponsorMU +} from "../../../../../../actions/sponsor-mu-actions"; + +jest.mock("../../../../../../actions/sponsor-mu-actions", () => ({ + getSponsorMURequests: jest.fn(() => () => Promise.resolve()), + getGeneralMURequests: jest.fn(() => () => Promise.resolve()), + uploadFileForSponsorMU: jest.fn(() => () => Promise.resolve()), + removeFileForSponsorMU: jest.fn(() => () => Promise.resolve()), + uploadTextForSponsorMU: jest.fn(() => () => Promise.resolve()), + removeTextForSponsorMU: jest.fn(() => () => Promise.resolve()) +})); + +jest.mock("../../../../../../components/mui/showConfirmDialog", () => ({ + __esModule: true, + default: jest.fn(() => Promise.resolve(true)) +})); + +jest.mock("../../../../../../components/upload-dialog", () => ({ + __esModule: true, + default: ({ open, onUpload, onClose }) => + open ? ( +
+ + +
+ ) : null +})); + +jest.mock("../components/text-value-dialog", () => ({ + __esModule: true, + default: ({ open, onSubmit, onClose }) => + open ? ( +
+ + +
+ ) : null +})); + +jest.mock("../../../../../../components/mui/PreviewModal", () => ({ + __esModule: true, + default: ({ open, url }) => + open ?
{url}
: null +})); + +jest.mock("../components/text-preview-modal", () => ({ + __esModule: true, + default: ({ open, value }) => + open ?
{value}
: null +})); + +jest.mock("openstack-uicore-foundation/lib/components/mui/table", () => ({ + __esModule: true, + default: ({ columns, data }) => ( +
+ {data.map((row) => ( +
+ {columns.map((col) => ( + + {col.render ? col.render(row) : row[col.columnKey]} + + ))} +
+ ))} +
+ ) +})); + +jest.mock("i18n-react/dist/i18n-react", () => ({ + __esModule: true, + default: { translate: (key) => key } +})); + +const fileRowWithValue = { + id: 1, + page_id: 10, + name: "Logo", + mu_type: "file", + status: "Complete", + media_upload: { + file_mimetype: "image/png", + public_url: "https://example.com/logo.png", + file_name: "logo.png", + file_created: 123 + } +}; + +const fileRowWithoutValue = { + id: 2, + page_id: 10, + name: "Brochure", + mu_type: "file", + status: "Pending", + media_upload: null +}; + +const textRowWithValue = { + id: 3, + page_id: 10, + name: "Company Bio", + mu_type: "text", + status: "Complete", + media_upload: { value: "Sponsor's bio text" } +}; + +const textRowWithoutValue = { + id: 4, + page_id: 10, + name: "Tagline", + mu_type: "text", + status: "Pending", + media_upload: null +}; + +const buildInitialState = (requests) => ({ + sponsorPageMUListState: { + sponsorRequests: { + requests, + order: "name", + orderDir: 1, + currentPage: 1, + lastPage: 1, + perPage: 10, + totalCount: requests.length + }, + generalRequests: { + requests: [], + order: "name", + orderDir: 1, + currentPage: 1, + lastPage: 1, + perPage: 10, + totalCount: 0 + }, + summitTZ: "" + }, + currentSponsorState: { entity: { id: 99 } } +}); + +const getCell = (rowId, columnKey) => + screen.getByTestId(`cell-${rowId}-${columnKey}`); + +describe("SponsorMediaUploadTab", () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.spyOn(window, "open").mockImplementation(() => {}); + }); + + it("enables view but keeps download disabled for a text row with a saved value, and previews the text", async () => { + renderWithRedux(, { + initialState: buildInitialState([textRowWithValue]) + }); + + const viewButton = within(getCell(3, "view")).getByRole("button"); + const downloadButton = within(getCell(3, "download")).getByRole("button"); + + expect(viewButton).toBeEnabled(); + expect(downloadButton).toBeDisabled(); + + await userEvent.click(viewButton); + + expect(screen.getByTestId("text-preview-modal")).toHaveTextContent( + "Sponsor's bio text" + ); + expect(screen.queryByTestId("preview-modal")).not.toBeInTheDocument(); + }); + + it("disables view and download for a text row with no saved value", () => { + renderWithRedux(, { + initialState: buildInitialState([textRowWithoutValue]) + }); + + expect(within(getCell(4, "view")).getByRole("button")).toBeDisabled(); + expect(within(getCell(4, "download")).getByRole("button")).toBeDisabled(); + }); + + it("opens the text dialog for an empty text row and submits via uploadTextForSponsorMU", async () => { + renderWithRedux(, { + initialState: buildInitialState([textRowWithoutValue]) + }); + + await userEvent.click( + within(getCell(4, "upload_delete")).getByRole("button") + ); + + expect(screen.getByTestId("text-value-dialog")).toBeInTheDocument(); + + await act(async () => { + await userEvent.click( + screen.getByRole("button", { name: "submit-text" }) + ); + }); + + expect(uploadTextForSponsorMU).toHaveBeenCalledWith(10, 4, "new answer"); + }); + + it("deletes a text row with a saved value via removeTextForSponsorMU", async () => { + renderWithRedux(, { + initialState: buildInitialState([textRowWithValue]) + }); + + await act(async () => { + await userEvent.click( + within(getCell(3, "upload_delete")).getByRole("button") + ); + }); + + expect(removeTextForSponsorMU).toHaveBeenCalledWith(10, 3); + expect(removeFileForSponsorMU).not.toHaveBeenCalled(); + }); + + it("keeps File-row behavior unchanged: image preview, public_url download, upload dialog, file delete", async () => { + renderWithRedux(, { + initialState: buildInitialState([fileRowWithValue, fileRowWithoutValue]) + }); + + expect(within(getCell(1, "view")).getByRole("button")).toBeEnabled(); + expect(within(getCell(1, "download")).getByRole("button")).toBeEnabled(); + + await userEvent.click(within(getCell(1, "view")).getByRole("button")); + expect(screen.getByTestId("preview-modal")).toHaveTextContent( + "https://example.com/logo.png" + ); + expect(screen.queryByTestId("text-preview-modal")).not.toBeInTheDocument(); + + await userEvent.click(within(getCell(1, "download")).getByRole("button")); + expect(window.open).toHaveBeenCalledWith( + "https://example.com/logo.png", + "_blank", + "noopener,noreferrer" + ); + + await act(async () => { + await userEvent.click( + within(getCell(1, "upload_delete")).getByRole("button") + ); + }); + expect(removeFileForSponsorMU).toHaveBeenCalledWith(10, 1); + expect(removeTextForSponsorMU).not.toHaveBeenCalled(); + + await userEvent.click( + within(getCell(2, "upload_delete")).getByRole("button") + ); + expect(screen.getByTestId("upload-dialog")).toBeInTheDocument(); + + await act(async () => { + await userEvent.click( + screen.getByRole("button", { name: "submit-file" }) + ); + }); + expect(uploadFileForSponsorMU).toHaveBeenCalledWith(10, 2, { + name: "file.pdf" + }); + }); +}); diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/__tests__/index.test.jsx b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/__tests__/index.test.jsx new file mode 100644 index 000000000..ab9734c4b --- /dev/null +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/__tests__/index.test.jsx @@ -0,0 +1,68 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import "@testing-library/jest-dom"; +import TextPreviewModal from "../index"; + +jest.mock("i18n-react/dist/i18n-react", () => ({ + __esModule: true, + default: { translate: (key) => key } +})); + +describe("TextPreviewModal", () => { + const onClose = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + Object.defineProperty(navigator, "clipboard", { + value: { writeText: jest.fn() }, + configurable: true + }); + }); + + it("renders the title and the stored text value", () => { + render( + + ); + + expect(screen.getByText("Company Bio")).toBeInTheDocument(); + expect( + screen.getByText("This is the sponsor's answer") + ).toBeInTheDocument(); + }); + + it("copies the value to the clipboard when the copy button is clicked", async () => { + render( + + ); + + const copyButton = screen.getByRole("button", { + name: "general.copy_to_clipboard" + }); + + await userEvent.click(copyButton); + + expect(navigator.clipboard.writeText).toHaveBeenCalledWith("Copy me"); + expect(copyButton).toHaveTextContent("general.copied"); + }); + + it("calls onClose when closing", async () => { + render( + + ); + + await userEvent.click(screen.getByRole("button", { name: "close" })); + + expect(onClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx new file mode 100644 index 000000000..1751ae7a7 --- /dev/null +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx @@ -0,0 +1,76 @@ +import React, { useEffect, useState } from "react"; +import PropTypes from "prop-types"; +import T from "i18n-react/dist/i18n-react"; +import { + Box, + Button, + DialogActions, + DialogContent, + Typography +} from "@mui/material"; +import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; +import { MILLISECONDS_IN_SECOND } from "../../../../../../../utils/constants"; + +const TextPreviewModal = ({ title, open, onClose, value }) => { + const [copyLabel, setCopyLabel] = useState( + T.translate("general.copy_to_clipboard") + ); + + useEffect(() => { + if (open) { + setCopyLabel(T.translate("general.copy_to_clipboard")); + } + }, [open]); + + const handleCopy = () => { + navigator.clipboard.writeText(value); + setCopyLabel(T.translate("general.copied")); + setTimeout(() => { + setCopyLabel(T.translate("general.copy_to_clipboard")); + }, MILLISECONDS_IN_SECOND); + }; + + return ( + + + + + {value} + + + + + + + + ); +}; + +TextPreviewModal.propTypes = { + title: PropTypes.string.isRequired, + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, + value: PropTypes.string +}; + +TextPreviewModal.defaultProps = { + value: "" +}; + +export default TextPreviewModal; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx new file mode 100644 index 000000000..8d83e7dde --- /dev/null +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx @@ -0,0 +1,105 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import "@testing-library/jest-dom"; +import TextValueDialog from "../index"; + +jest.mock("i18n-react/dist/i18n-react", () => ({ + __esModule: true, + default: { translate: (key) => key } +})); + +describe("TextValueDialog", () => { + const onClose = jest.fn(); + const onSubmit = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("renders an empty text field with a disabled submit button when there is no value", () => { + render( + + ); + + expect(screen.getByRole("textbox")).toHaveValue(""); + expect( + screen.getByRole("button", { + name: "edit_sponsor.mu_tab.upload_input.save_answer" + }) + ).toBeDisabled(); + }); + + it("enables submit once text is typed and calls onSubmit with it", async () => { + render( + + ); + + await userEvent.type(screen.getByRole("textbox"), "Hello sponsor"); + + const submitButton = screen.getByRole("button", { + name: "edit_sponsor.mu_tab.upload_input.save_answer" + }); + expect(submitButton).toBeEnabled(); + + await userEvent.click(submitButton); + + expect(onSubmit).toHaveBeenCalledWith("Hello sponsor"); + }); + + it("pre-fills the text field with the stored value and keeps submit disabled until it changes", async () => { + render( + + ); + + const textbox = screen.getByRole("textbox"); + const submitButton = screen.getByRole("button", { + name: "edit_sponsor.mu_tab.upload_input.save_answer" + }); + + expect(textbox).toHaveValue("Existing answer"); + expect(submitButton).toBeDisabled(); + + await userEvent.type(textbox, " updated"); + + expect(submitButton).toBeEnabled(); + + await userEvent.click(submitButton); + + expect(onSubmit).toHaveBeenCalledWith("Existing answer updated"); + }); + + it("calls onClose when closing", async () => { + render( + + ); + + await userEvent.click(screen.getByRole("button", { name: "close" })); + + expect(onClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js new file mode 100644 index 000000000..87687baf4 --- /dev/null +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js @@ -0,0 +1,99 @@ +/** + * Copyright 2026 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 { + Button, + DialogActions, + DialogContent, + TextField, + Typography +} from "@mui/material"; +import PropTypes from "prop-types"; +import T from "i18n-react/dist/i18n-react"; +import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; + +const TextValueDialog = ({ + name, + moduleName, + value, + open, + onClose, + onSubmit +}) => { + const [text, setText] = useState(value || ""); + + useEffect(() => { + if (open) { + setText(value || ""); + } + }, [open, value]); + + const handleSubmit = () => { + onSubmit(text); + }; + + const handleClose = () => { + setText(value || ""); + onClose(); + }; + + return ( + + + + {moduleName} + + setText(ev.target.value)} + /> + + + + + + ); +}; + +TextValueDialog.propTypes = { + open: PropTypes.bool.isRequired, + name: PropTypes.string.isRequired, + moduleName: PropTypes.string, + value: PropTypes.string, + onClose: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired +}; + +TextValueDialog.defaultProps = { + moduleName: "", + value: null +}; + +export default TextValueDialog; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js index 78124f12d..64d646c6b 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js @@ -31,8 +31,10 @@ import { import CustomAlert from "../../../../../components/mui/custom-alert"; import { SPONSOR_MEDIA_UPLOAD_STATUS } from "../../../../../utils/constants"; import UploadDialog from "../../../../../components/upload-dialog"; +import TextValueDialog from "./components/text-value-dialog"; import showConfirmDialog from "../../../../../components/mui/showConfirmDialog"; import PreviewModal from "../../../../../components/mui/PreviewModal"; +import TextPreviewModal from "./components/text-preview-modal"; const SponsorMediaUploadTab = ({ sponsor, @@ -75,6 +77,14 @@ const SponsorMediaUploadTab = ({ ); }; + const handleUploadText = (text) => { + uploadTextForSponsorMU(uploadModule.page_id, uploadModule.id, text).then( + () => { + setUploadModule(null); + } + ); + }; + const handleView = (item) => { setPreviewModule(item); }; @@ -99,10 +109,12 @@ const SponsorMediaUploadTab = ({ confirmButtonText: T.translate("general.yes_delete") }); - console.log("ITEM: ", item); - if (isConfirmed) { - removeFileForSponsorMU(item.page_id, item.id); + if (item.mu_type === "text") { + removeTextForSponsorMU(item.page_id, item.id); + } else { + removeFileForSponsorMU(item.page_id, item.id); + } } }; @@ -141,6 +153,10 @@ const SponsorMediaUploadTab = ({ header: nameLabel, sortable: true }, + { + columnKey: "mu_type", + header: T.translate("edit_sponsor.mu_tab.type") + }, { columnKey: "add_on", header: T.translate("edit_sponsor.mu_tab.add_on") @@ -177,10 +193,16 @@ const SponsorMediaUploadTab = ({ align: "center", render: (row) => { const isImage = row.media_upload?.file_mimetype?.includes("image"); + const isTextWithValue = + row.mu_type === "text" && !!row.media_upload?.value; + const viewDisabled = + row.mu_type === "text" + ? !isTextWithValue + : !row.media_upload || !isImage; return ( handleView(row)} > @@ -196,7 +218,7 @@ const SponsorMediaUploadTab = ({ render: (row) => ( handleDownload(row)} > @@ -272,27 +294,47 @@ const SponsorMediaUploadTab = ({ onSort={handleGeneralSort} /> - setUploadModule(null)} - onUpload={handleUploadFile} - onRemove={() => handleDelete(uploadModule)} - value={uploadModule?.media_upload} - fileMeta={{ - ...(uploadModule?.file_type || {}), - max_file_size: uploadModule?.max_file_size - }} - maxFiles={1} - /> - setPreviewModule(null)} - title={previewModule?.name} - filename={previewModule?.media_upload?.file_name} - uploadDate={previewModule?.media_upload?.file_created} - url={previewModule?.media_upload?.public_url} - /> + {uploadModule?.mu_type === "text" ? ( + setUploadModule(null)} + onSubmit={handleUploadText} + value={uploadModule?.media_upload?.value} + /> + ) : ( + setUploadModule(null)} + onUpload={handleUploadFile} + onRemove={() => handleDelete(uploadModule)} + value={uploadModule?.media_upload} + fileMeta={{ + ...(uploadModule?.file_type || {}), + max_file_size: uploadModule?.max_file_size + }} + maxFiles={1} + /> + )} + {previewModule?.mu_type === "text" ? ( + setPreviewModule(null)} + title={previewModule?.name} + value={previewModule?.media_upload?.value} + /> + ) : ( + setPreviewModule(null)} + title={previewModule?.name} + filename={previewModule?.media_upload?.file_name} + uploadDate={previewModule?.media_upload?.file_created} + url={previewModule?.media_upload?.public_url} + /> + )} ); }; diff --git a/yarn.lock b/yarn.lock index 57c547313..ed0f98cff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9042,10 +9042,10 @@ open@^10.0.3: is-inside-container "^1.0.0" wsl-utils "^0.1.0" -openstack-uicore-foundation@5.0.47: - version "5.0.47" - resolved "https://registry.npmjs.org/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.47.tgz#32500fb4d8392cbf5713e968afa875cea42a67a2" - integrity sha512-E/6uO7Q5MtTfhWExshuNIrwVcxDewDvA76YmGzQz2f5LeZ8Gsv22eqBNbylDakwxuPmyD16r/AQEURr5soALAw== +openstack-uicore-foundation@5.0.50-beta.0: + version "5.0.50-beta.0" + resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.50-beta.0.tgz#8aae1c5bba9ffbacbdd4296867d89e2a7668ba61" + integrity sha512-4IuCsY/Q7Kk7W1YNwlrXgNB0b1vRsjFIpa4IduZi/0orsbcva3mXgdU/4oqPVmNzcJP091z70Sexo8zZPRlo8A== dependencies: use-sync-external-store "^1.6.0" From 75d2b4903b1800317ad7479ef6d1bef9fb6e6f0e Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Thu, 20 Aug 2026 15:43:25 -0300 Subject: [PATCH 3/6] chore: pr review and improve CustomDialog --- package.json | 2 +- .../components/text-value-dialog/index.js | 63 +++++++------------ .../tabs/sponsor-media-upload-tab/index.js | 3 +- .../sponsors/sponsor-page-mu-list-reducer.js | 1 + src/utils/constants.js | 2 + yarn.lock | 8 +-- 6 files changed, 31 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index f8e5daf70..22505cc49 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "moment-duration-format": "^2.3.2", "moment-timezone": "^0.5.33", "mui-color-input": "^9.0.0", - "openstack-uicore-foundation": "5.0.50-beta.0", + "openstack-uicore-foundation": "5.0.50-beta.1", "p-limit": "^6.1.0", "path-browserify": "^1.0.1", "postcss-loader": "^6.2.1", diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js index 87687baf4..30ee6c01e 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/index.js @@ -12,16 +12,11 @@ * */ import React, { useEffect, useState } from "react"; -import { - Button, - DialogActions, - DialogContent, - TextField, - Typography -} from "@mui/material"; +import { TextField, Typography } from "@mui/material"; import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; +import { TEXT_MAX_LENGTH_1024 } from "../../../../../../../utils/constants"; const TextValueDialog = ({ name, @@ -39,45 +34,31 @@ const TextValueDialog = ({ } }, [open, value]); - const handleSubmit = () => { - onSubmit(text); - }; - - const handleClose = () => { - setText(value || ""); - onClose(); - }; - return ( onSubmit(text).then(() => onClose()), + disabled: text === (value || "") + }} > - - - {moduleName} - - setText(ev.target.value)} - /> - - - - + + {moduleName} + + setText(ev.target.value)} + inputProps={{ maxLength: TEXT_MAX_LENGTH_1024 }} + helperText={`${text.length}/${TEXT_MAX_LENGTH_1024}`} + /> ); }; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js index 64d646c6b..2ba3c59ba 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js @@ -77,13 +77,12 @@ const SponsorMediaUploadTab = ({ ); }; - const handleUploadText = (text) => { + const handleUploadText = (text) => uploadTextForSponsorMU(uploadModule.page_id, uploadModule.id, text).then( () => { setUploadModule(null); } ); - }; const handleView = (item) => { setPreviewModule(item); diff --git a/src/reducers/sponsors/sponsor-page-mu-list-reducer.js b/src/reducers/sponsors/sponsor-page-mu-list-reducer.js index e904d6d6d..12c481c36 100644 --- a/src/reducers/sponsors/sponsor-page-mu-list-reducer.js +++ b/src/reducers/sponsors/sponsor-page-mu-list-reducer.js @@ -82,6 +82,7 @@ const mapMediaObject = (mediaObject) => { format: mediaObject.file_type?.allowed_extensions || "N/A", deadline, status: getStatus(mediaObject), + // TODO: type should come from API mu_type: mediaObject.file_type ? "file" : "text" }; }; diff --git a/src/utils/constants.js b/src/utils/constants.js index 5882abf4b..cc333f7d5 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -361,3 +361,5 @@ export const IMPORT_SPONSOR_USERS_STATUS = { export const DEFAULT_REOPEN_HOURS = 24; export const REOPEN_PRESET_HOURS_48 = 48; export const REOPEN_PRESET_HOURS_72 = 72; + +export const TEXT_MAX_LENGTH_1024 = 1024; diff --git a/yarn.lock b/yarn.lock index ed0f98cff..d62d18927 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9042,10 +9042,10 @@ open@^10.0.3: is-inside-container "^1.0.0" wsl-utils "^0.1.0" -openstack-uicore-foundation@5.0.50-beta.0: - version "5.0.50-beta.0" - resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.50-beta.0.tgz#8aae1c5bba9ffbacbdd4296867d89e2a7668ba61" - integrity sha512-4IuCsY/Q7Kk7W1YNwlrXgNB0b1vRsjFIpa4IduZi/0orsbcva3mXgdU/4oqPVmNzcJP091z70Sexo8zZPRlo8A== +openstack-uicore-foundation@5.0.50-beta.1: + version "5.0.50-beta.1" + resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.50-beta.1.tgz#78de73c5158379a8f240b7813b42fcfad9e3b6c6" + integrity sha512-ecsKFM0haCV2LzKPihR+DeKdA5f3JEXTOgP/aevBoEgL8wOrcPtmmH2gJCcpL7qPvWdFWVN9Kwcg7hBBmpbVOA== dependencies: use-sync-external-store "^1.6.0" From 22ab5a88c7ff680090b39b61d1e8d76e4c593326 Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Thu, 20 Aug 2026 16:11:59 -0300 Subject: [PATCH 4/6] chore: fix tests --- .../__tests__/index.test.jsx | 31 +------------------ .../components/text-value-dialog/index.js | 25 +++------------ .../tabs/sponsor-media-upload-tab/index.js | 1 - 3 files changed, 6 insertions(+), 51 deletions(-) diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx index 8d83e7dde..cf0208668 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-value-dialog/__tests__/index.test.jsx @@ -11,7 +11,7 @@ jest.mock("i18n-react/dist/i18n-react", () => ({ describe("TextValueDialog", () => { const onClose = jest.fn(); - const onSubmit = jest.fn(); + const onSubmit = jest.fn(() => Promise.resolve()); beforeEach(() => { jest.clearAllMocks(); @@ -59,35 +59,6 @@ describe("TextValueDialog", () => { expect(onSubmit).toHaveBeenCalledWith("Hello sponsor"); }); - it("pre-fills the text field with the stored value and keeps submit disabled until it changes", async () => { - render( - - ); - - const textbox = screen.getByRole("textbox"); - const submitButton = screen.getByRole("button", { - name: "edit_sponsor.mu_tab.upload_input.save_answer" - }); - - expect(textbox).toHaveValue("Existing answer"); - expect(submitButton).toBeDisabled(); - - await userEvent.type(textbox, " updated"); - - expect(submitButton).toBeEnabled(); - - await userEvent.click(submitButton); - - expect(onSubmit).toHaveBeenCalledWith("Existing answer updated"); - }); - it("calls onClose when closing", async () => { render( { - const [text, setText] = useState(value || ""); - - useEffect(() => { - if (open) { - setText(value || ""); - } - }, [open, value]); +const TextValueDialog = ({ name, moduleName, open, onClose, onSubmit }) => { + const [text, setText] = useState(""); return ( onSubmit(text).then(() => onClose()), - disabled: text === (value || "") + disabled: text === "" }} > @@ -67,14 +54,12 @@ TextValueDialog.propTypes = { open: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, moduleName: PropTypes.string, - value: PropTypes.string, onClose: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired }; TextValueDialog.defaultProps = { - moduleName: "", - value: null + moduleName: "" }; export default TextValueDialog; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js index 2ba3c59ba..46508c07c 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js @@ -300,7 +300,6 @@ const SponsorMediaUploadTab = ({ open={!!uploadModule} onClose={() => setUploadModule(null)} onSubmit={handleUploadText} - value={uploadModule?.media_upload?.value} /> ) : ( Date: Fri, 21 Aug 2026 10:52:16 -0300 Subject: [PATCH 5/6] chore: pr review --- src/actions/sponsor-mu-actions.js | 8 +- src/components/mui/PreviewModal/index.jsx | 101 ++++++++---------- src/components/upload-dialog/index.js | 83 ++++++-------- .../components/text-preview-modal/index.jsx | 54 ++++------ .../tabs/sponsor-media-upload-tab/index.js | 3 +- 5 files changed, 108 insertions(+), 141 deletions(-) diff --git a/src/actions/sponsor-mu-actions.js b/src/actions/sponsor-mu-actions.js index be0cd3fe9..a486a3cfb 100644 --- a/src/actions/sponsor-mu-actions.js +++ b/src/actions/sponsor-mu-actions.js @@ -231,7 +231,9 @@ export const removeTextForSponsorMU = `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsor.id}/available-pages/${pageId}/modules/${moduleId}/text`, null, snackbarErrorHandler - )(params)(dispatch).finally(() => { - dispatch(stopLoading()); - }); + )(params)(dispatch) + .catch(() => {}) + .finally(() => { + dispatch(stopLoading()); + }); }; diff --git a/src/components/mui/PreviewModal/index.jsx b/src/components/mui/PreviewModal/index.jsx index be2db4c7b..5dfd0e2ed 100644 --- a/src/components/mui/PreviewModal/index.jsx +++ b/src/components/mui/PreviewModal/index.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; -import { Box, DialogContent, Typography } from "@mui/material"; +import { Box, Typography } from "@mui/material"; import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; import BrokenImageOutlinedIcon from "@mui/icons-material/BrokenImageOutlined"; import { formatDate } from "../../../utils/methods"; @@ -29,62 +29,53 @@ const PreviewModal = ({ title, open, onClose, url, filename, uploadDate }) => { return ( - - - {!url || imageError ? ( - - ) : ( - setImageError(true)} - sx={{ - maxWidth: "100%", - maxHeight: 400, - display: "block", - objectFit: "contain" - }} - /> - )} + + {!url || imageError ? ( + + ) : ( + setImageError(true)} + sx={{ + maxWidth: "100%", + maxHeight: 400, + display: "block", + objectFit: "contain" + }} + /> + )} + + {filename && ( + + + {T.translate("preview_modal.file_name")} + + + {filename} + - - {filename && ( - - - {T.translate("preview_modal.file_name")} - - - {filename} - - - )} - {!!uploadDate && ( - - - {T.translate("preview_modal.uploaded")} - - {formatDate(uploadDate)} - - )} + )} + {!!uploadDate && ( + + + {T.translate("preview_modal.uploaded")} + + {formatDate(uploadDate)} - + )} ); }; diff --git a/src/components/upload-dialog/index.js b/src/components/upload-dialog/index.js index 4bc966642..718a6faf1 100644 --- a/src/components/upload-dialog/index.js +++ b/src/components/upload-dialog/index.js @@ -12,15 +12,7 @@ * */ import React, { useState } from "react"; -import { - Box, - Button, - DialogActions, - DialogContent, - Divider, - IconButton, - Typography -} from "@mui/material"; +import { Box, Divider, IconButton, Typography } from "@mui/material"; import PropTypes from "prop-types"; import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3"; import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; @@ -88,9 +80,7 @@ const UploadDialog = ({ } }; - const handleUpload = () => { - onUpload(uploadedFile); - }; + const handleUpload = () => onUpload(uploadedFile); const handleRemove = () => { if (onRemove) { @@ -110,45 +100,38 @@ const UploadDialog = ({ title={T.translate("edit_sponsor.mu_tab.upload_input.upload_file")} open={open} onClose={handleClose} + primaryAction={{ + label: T.translate("edit_sponsor.mu_tab.upload_input.upload_file"), + onClick: handleUpload, + disabled: !uploadedFile + }} > - - - {fileMeta.name} - - - {fileMeta.description} - - {value ? ( - <> - - - - ) : ( - setUploadedFile(null)} - postUrl={`${window.FILE_UPLOAD_API_BASE_URL}/api/v1/files/upload`} - djsConfig={{ withCredentials: true }} - maxFiles={maxFiles} - canAdd={canAddMore()} - parallelChunkUploads - /> - )} - - - - + + {fileMeta.name} + + + {fileMeta.description} + + {value ? ( + <> + + + + ) : ( + setUploadedFile(null)} + postUrl={`${window.FILE_UPLOAD_API_BASE_URL}/api/v1/files/upload`} + djsConfig={{ withCredentials: true }} + maxFiles={maxFiles} + canAdd={canAddMore()} + parallelChunkUploads + /> + )} ); }; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx index 1751ae7a7..b5bce412f 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/components/text-preview-modal/index.jsx @@ -1,13 +1,7 @@ import React, { useEffect, useState } from "react"; import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; -import { - Box, - Button, - DialogActions, - DialogContent, - Typography -} from "@mui/material"; +import { Box, Typography } from "@mui/material"; import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog"; import { MILLISECONDS_IN_SECOND } from "../../../../../../../utils/constants"; @@ -31,33 +25,31 @@ const TextPreviewModal = ({ title, open, onClose, value }) => { }; return ( - - - + + - - {value} - - - - - - + {value} + + ); }; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js index 46508c07c..f4d8d5fc6 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-media-upload-tab/index.js @@ -69,13 +69,12 @@ const SponsorMediaUploadTab = ({ setUploadModule(item); }; - const handleUploadFile = (file) => { + const handleUploadFile = (file) => uploadFileForSponsorMU(uploadModule.page_id, uploadModule.id, file).then( () => { setUploadModule(null); } ); - }; const handleUploadText = (text) => uploadTextForSponsorMU(uploadModule.page_id, uploadModule.id, text).then( From 6d37af51e5486f34d5c1fa7ae8c47f6f521aa539 Mon Sep 17 00:00:00 2001 From: Santiago Palenque Date: Fri, 21 Aug 2026 17:44:14 -0300 Subject: [PATCH 6/6] chore: update uicore --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 22505cc49..cca05f3cf 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "moment-duration-format": "^2.3.2", "moment-timezone": "^0.5.33", "mui-color-input": "^9.0.0", - "openstack-uicore-foundation": "5.0.50-beta.1", + "openstack-uicore-foundation": "5.0.50", "p-limit": "^6.1.0", "path-browserify": "^1.0.1", "postcss-loader": "^6.2.1", diff --git a/yarn.lock b/yarn.lock index d62d18927..90a8c4869 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9042,10 +9042,10 @@ open@^10.0.3: is-inside-container "^1.0.0" wsl-utils "^0.1.0" -openstack-uicore-foundation@5.0.50-beta.1: - version "5.0.50-beta.1" - resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.50-beta.1.tgz#78de73c5158379a8f240b7813b42fcfad9e3b6c6" - integrity sha512-ecsKFM0haCV2LzKPihR+DeKdA5f3JEXTOgP/aevBoEgL8wOrcPtmmH2gJCcpL7qPvWdFWVN9Kwcg7hBBmpbVOA== +openstack-uicore-foundation@5.0.50: + version "5.0.50" + resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.50.tgz#e3212570a768c70e9add8dc717b4344a301c03f9" + integrity sha512-OpS73E7MWMeHcRF2qVBby2LmI3kt2bgBh4udXwc7VMv5UbCktla+hWsPVeHBIZLFExPT414pn7nt/DOkE0gYDQ== dependencies: use-sync-external-store "^1.6.0"