Skip to content
12 changes: 10 additions & 2 deletions src/actions/show-pages-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export const getShowPages =
page,
per_page: perPage,
access_token: accessToken,
fields: "code,name,id,modules_count,sponsorship_types,is_archived",
fields:
"code,name,id,modules_count,sponsorship_types,is_archived,apply_to_all_types",
expand: "sponsorship_types"
};

Expand Down Expand Up @@ -113,7 +114,7 @@ export const getShowPage = (pageId) => async (dispatch, getState) => {

const params = {
access_token: accessToken,
expand: "modules,modules.file_type"
expand: "modules,modules.file_type,sponsorship_types"
};

return getRequest(
Expand All @@ -129,6 +130,13 @@ export const getShowPage = (pageId) => async (dispatch, getState) => {
const normalizeShowPage = (entity) => {
const normalizedEntity = { ...entity };

normalizedEntity.apply_to_all_types = false;

if (entity.sponsorship_types?.includes("all")) {
normalizedEntity.apply_to_all_types = true;
delete normalizedEntity.sponsorship_types;
}

normalizedEntity.modules = entity.modules.map((module) => {
const normalizedModule = { ...module };

Expand Down
2 changes: 1 addition & 1 deletion src/components/mui/dropdown-checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const DropdownCheckbox = ({
};

return (
<FormControl fullWidth>
<FormControl fullWidth margin="normal">
<InputLabel id={`${name}_label`}>{label}</InputLabel>
<Select
labelId={`${name}_label`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const BLOCKED_KEYS = ["e", "E", "+", "-", ".", ","];
const MuiFormikFilesizeField = ({ name, label, ...props }) => {
const [field, meta, helpers] = useField(name);

const displayValue =
field.value != null ? Math.floor(field.value / BYTES_PER_MB) : 0;
const displayValue = field.value
? Math.floor(field.value / BYTES_PER_MB)
: "";
Comment on lines +13 to +15
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid treating 0 bytes as empty.

With the falsy check, a real value of 0 MB renders as blank, so users see “empty” while the form state holds 0. If 0 is a valid value, this is a UX mismatch. Consider only treating null/undefined as empty.

Suggested fix
-  const displayValue = field.value
-    ? Math.floor(field.value / BYTES_PER_MB)
-    : "";
+  const displayValue =
+    field.value == null ? "" : Math.floor(field.value / BYTES_PER_MB);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const displayValue = field.value
? Math.floor(field.value / BYTES_PER_MB)
: "";
const displayValue =
field.value == null ? "" : Math.floor(field.value / BYTES_PER_MB);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/formik-inputs/mui-formik-file-size-field.js` around lines
13 - 15, The current computation of displayValue treats 0 as falsy and renders
an empty string; update the conditional so only null/undefined are considered
empty (e.g. check field.value == null or typeof field.value === 'undefined') and
keep the Math.floor(field.value / BYTES_PER_MB) for numeric values; modify the
expression around displayValue (which uses field.value and BYTES_PER_MB) to
return "" only when field.value is null/undefined so 0 bytes render as "0".


const emptyValue = meta.initialValue === null ? null : 0;

Expand Down
1 change: 1 addition & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2682,6 +2682,7 @@
"hide_archived": "Hide archived Pages",
"filter": "Filter",
"sort_by": "Sort By",
"all_tiers": "All Tiers",
"no_sponsors_pages": "No pages found for this search criteria.",
"page_saved": "Page updated successfully.",
"page_created": "Page created successfully.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,13 @@ const PageTemplateListPage = ({
</div>
)}
</Box>
<PageTemplatePopup
open={!!pageTemplateId}
onClose={() => setPageTemplateId(null)}
onSave={handleSavePageTemplate}
summitTZ={summitTZ}
/>
{!!pageTemplateId && (
<PageTemplatePopup
onClose={() => setPageTemplateId(null)}
onSave={handleSavePageTemplate}
summitTZ={summitTZ}
/>
)}
<PageTemplateClonePopup
open={openCloneDialog}
onClose={() => setOpenCloneDialog(false)}
Expand Down
111 changes: 65 additions & 46 deletions src/pages/sponsors-global/page-templates/page-template-popup/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";
import T from "i18n-react/dist/i18n-react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import {
Box,
Expand All @@ -24,10 +23,13 @@ import PageModules from "./page-template-modules-form";
import { resetPageTemplateForm } from "../../../../actions/page-template-actions";
import {
BYTES_PER_MB,
COLUMN_4,
COLUMN_8,
PAGES_MODULE_KINDS,
PAGE_MODULES_MEDIA_TYPES,
PAGE_MODULES_DOWNLOAD
} from "../../../../utils/constants";
import DropdownCheckbox from "../../../../components/mui/dropdown-checkbox";

const normalizeModules = (modules = [], summitTZ = "UTC") =>
modules.map((m) => {
Expand All @@ -52,56 +54,20 @@ const normalizeModules = (modules = [], summitTZ = "UTC") =>

const PageTemplatePopup = ({
pageTemplate,
open,
onClose,
onSave,
summitTZ,
resetPageTemplateForm
resetPageTemplateForm,
sponsorships
}) => {
const showSponsorships =
Array.isArray(sponsorships) && sponsorships.length > 0;

const handleClose = () => {
resetPageTemplateForm();
onClose();
};

const addModule = (moduleData) => {
const modules = formik.values.modules || [];
const newModule = {
...moduleData,
_tempId: `temp-${Date.now()}`,
custom_order: modules.length
};
formik.setFieldValue("modules", [...modules, newModule]);
};

const handleAddInfo = () => {
addModule({
kind: PAGES_MODULE_KINDS.INFO,
content: ""
});
};

const handleAddDocument = () => {
addModule({
kind: PAGES_MODULE_KINDS.DOCUMENT,
name: "",
description: "",
external_url: "",
file: []
});
};

const handleAddMedia = () => {
addModule({
kind: PAGES_MODULE_KINDS.MEDIA,
type: PAGE_MODULES_MEDIA_TYPES.FILE,
name: "",
description: "",
upload_deadline: null,
max_file_size: 0,
file_type_id: null
});
};

const infoModuleSchema = yup.object().shape({
kind: yup.string().equals([PAGES_MODULE_KINDS.INFO]),
content: yup.string().required(T.translate("validation.required"))
Expand Down Expand Up @@ -183,8 +149,47 @@ const PageTemplatePopup = ({
}
});

const addModule = (moduleData) => {
const modules = formik.values.modules || [];
const newModule = {
...moduleData,
_tempId: `temp-${Date.now()}`,
custom_order: modules.length
};
formik.setFieldValue("modules", [...modules, newModule]);
};

const handleAddInfo = () => {
addModule({
kind: PAGES_MODULE_KINDS.INFO,
content: ""
});
};

const handleAddDocument = () => {
addModule({
kind: PAGES_MODULE_KINDS.DOCUMENT,
name: "",
description: "",
external_url: "",
file: []
});
};

const handleAddMedia = () => {
addModule({
kind: PAGES_MODULE_KINDS.MEDIA,
type: PAGE_MODULES_MEDIA_TYPES.FILE,
name: "",
description: "",
upload_deadline: null,
max_file_size: 0,
file_type_id: null
});
};

return (
<Dialog open={open} onClose={handleClose} maxWidth="md" fullWidth>
<Dialog open onClose={handleClose} maxWidth="md" fullWidth>
<DialogTitle sx={{ display: "flex", justifyContent: "space-between" }}>
<Typography fontSize="1.5rem">
{T.translate("page_template_list.page_crud.title")}
Expand All @@ -210,13 +215,27 @@ const PageTemplatePopup = ({
fullWidth
/>
</Grid2>
<Grid2 size={8}>
<Grid2 spacing={2} size={showSponsorships ? COLUMN_4 : COLUMN_8}>
<MuiFormikTextField
name="name"
label={T.translate("page_template_list.name")}
fullWidth
/>
</Grid2>
{showSponsorships && (
<Grid2 spacing={2} size={4}>
<DropdownCheckbox
name="sponsorship_types"
label={T.translate("page_template_list.sponsorship")}
allLabel={T.translate("page_template_list.all_tiers")}
value={formik.values.sponsorship_types.map(
(st) => st.id ?? st
)}
options={sponsorships}
onChange={formik.handleChange}
/>
</Grid2>
)}
</Grid2>
<Divider sx={{ mb: 2 }} />
<Grid2 container spacing={2} size={12} sx={{ p: 2 }}>
Expand Down Expand Up @@ -269,10 +288,10 @@ const PageTemplatePopup = ({
};

PageTemplatePopup.propTypes = {
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired,
summitTZ: PropTypes.string.isRequired
summitTZ: PropTypes.string,
sponsorships: PropTypes.array
};

const mapStateToProps = ({ pageTemplateState }) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import {
archiveShowPage,
unarchiveShowPage
} from "../../../../actions/show-pages-actions";
import { getSponsorships } from "../../../../actions/sponsor-forms-actions";
import {
DEFAULT_CURRENT_PAGE,
MAX_PER_PAGE
} from "../../../../utils/constants";

// Mocks

Expand All @@ -32,14 +37,14 @@ jest.mock("../../../../components/mui/showConfirmDialog", () => jest.fn());
jest.mock(
"../../../sponsors-global/page-templates/page-template-popup",
() =>
function MockPageTemplatePopup({ open, onClose, onSave, pageTemplate }) {
return open ? (
function MockPageTemplatePopup({ onClose, onSave, pageTemplate }) {
return (
<div data-testid="page-template-popup">
<span data-testid="popup-page-id">{pageTemplate?.id}</span>
<button onClick={onClose}>Close</button>
<button onClick={() => onSave({ id: 1, name: "Test" })}>Save</button>
</div>
) : null;
);
}
);

Expand All @@ -56,6 +61,10 @@ jest.mock("../../../../actions/show-pages-actions", () => ({
resetShowPageForm: jest.fn(() => ({ type: "MOCK_ACTION" }))
}));

jest.mock("../../../../actions/sponsor-forms-actions", () => ({
getSponsorships: jest.fn(() => () => Promise.resolve({ items: [] }))
}));

// Helper to create show page data
const createShowPage = (id, overrides = {}) => ({
id,
Expand Down Expand Up @@ -117,6 +126,10 @@ describe("ShowPagesListPage", () => {
await act(async () => {
await userEvent.click(editButton);
});
expect(getSponsorships).toHaveBeenCalledWith(
DEFAULT_CURRENT_PAGE,
MAX_PER_PAGE
);
expect(getShowPage).toHaveBeenCalledWith(1);
await waitFor(() => {
expect(screen.getByTestId("page-template-popup")).toBeInTheDocument();
Expand All @@ -137,6 +150,10 @@ describe("ShowPagesListPage", () => {
await act(async () => {
await userEvent.click(editButton);
});
expect(getSponsorships).toHaveBeenCalledWith(
DEFAULT_CURRENT_PAGE,
MAX_PER_PAGE
);
await waitFor(() => {
expect(screen.getByTestId("page-template-popup")).toBeInTheDocument();
});
Expand Down
Loading