Skip to content

feat: add template popup on sponsor tab#804

Open
tomrndom wants to merge 8 commits intomasterfrom
feature/sponsor-page-tab-managed-popup
Open

feat: add template popup on sponsor tab#804
tomrndom wants to merge 8 commits intomasterfrom
feature/sponsor-page-tab-managed-popup

Conversation

@tomrndom
Copy link

@tomrndom tomrndom commented Feb 25, 2026

ref: https://app.clickup.com/t/86b7991c2

Signed-off-by: Tomás Castillo [email protected]

Summary by CodeRabbit

  • New Features

    • Add pages from templates via a modal: bulk page selection, add-on selection (supports "all"), sorting, searching, pagination, and direct save of managed pages from the template workflow.
  • UI/UX Improvements

    • Select controls show customizable "no items" text and improved menu states (loading / empty / grouped options).
    • "Using template" now opens the template workflow.
  • Localization

    • Added A–Z / Z–A sort labels, new page-tab strings, and updated validation/empty-list messages.

@tomrndom tomrndom requested a review from smarcet February 25, 2026 15:41
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a template-based workflow for creating sponsor-managed pages: new saveSponsorManagedPage action and normalize helper, a modal AddSponsorPageTemplatePopup component integrated into SponsorPagesTab, a Formik select-group empty-state prop, several i18n keys, and localized sort labels across form template UIs.

Changes

Cohort / File(s) Summary
Actions
src/actions/sponsor-pages-actions.js
Added SPONSOR_MANAGED_PAGE_ADDED constant, saveSponsorManagedPage(entity) async thunk, and normalizeSponsorManagedPage(entity) helper (maps pagesshow_page_ids, add_onsallowed_add_ons / apply_to_all_add_ons).
Template Popup Component
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js
New connected React component AddSponsorPageTemplatePopup: Formik + Yup modal to select show pages and add‑ons, supports paging/sorting/search, validates add‑ons selection, and emits composed entity on submit.
Page Integration
src/pages/sponsors/sponsor-pages-tab/index.js
Integrated popup into SponsorPagesTab: added openPopup state, handleUsingTemplate, handleSaveManagedPageFromTemplate, passed sponsor/summitId props, and exposed saveSponsorManagedPage in mapDispatchToProps.
UI Form Input
src/components/mui/formik-inputs/mui-formik-select-group.js
Added noOptionsLabel prop (default "No items"); refactored menu rendering into renderMenuContent to show loading, empty, or grouped options; updated PropTypes.
i18n / Translations
src/i18n/en.json
Updated errors.empty_list to include {item} placeholder; added general.sort_by, general.sort_asc_label, general.sort_desc_label; added validation.add_on_required; added sponsor/pages_tab keys: no_add_ons, no_pages, add_page_using_template, add_selected_page_template.
Localized Sort Labels
src/pages/sponsors-global/form-templates/add-form-template-item-popup.js, src/pages/sponsors-global/form-templates/form-template-from-duplicate-popup.js, src/pages/sponsors/sponsor-forms-tab/components/add-sponsor-form-template-popup/index.js, src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js
Replaced hard-coded "A-Z" / "Z-A" and "sort by" texts with localized T.translate("general.sort_...") values and updated menu item labels accordingly.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as SponsorPagesTab
    participant Popup as AddSponsorPageTemplatePopup
    participant Form as FormikForm
    participant Redux as ReduxStore
    participant API as BackendAPI

    User->>UI: Click "Using template"
    UI->>UI: set openPopup = "template"
    UI->>Popup: render with onSubmit/onClose

    Popup->>Redux: dispatch getShowPages (on mount / search / sort / page)
    Redux->>API: GET /show-pages
    API-->>Redux: pages list
    Redux-->>Popup: pages loaded
    Popup->>User: render table (select, search, sort, paginate)

    User->>Popup: select pages & add-ons, click "Add"
    Popup->>Form: validate selections
    alt valid
        Form-->>Popup: valid
        Popup->>UI: call onSubmit(entity)
        UI->>Redux: dispatch saveSponsorManagedPage(entity)
        Redux->>API: POST /sponsor-managed-pages
        API-->>Redux: created resource
        Redux->>Redux: dispatch SPONSOR_MANAGED_PAGE_ADDED
        UI->>Redux: refresh managed pages list
        UI->>Popup: close popup
    else invalid
        Form-->>Popup: show errors
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • smarcet
  • romanetar
  • santipalenque

Poem

🐰 I hopped through code and found a new trail,
Pages and templates set sail without fail.
Check boxes, add‑ons, a form neat and bright,
I dug a small tunnel and pushed save overnight. 🌿

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: a new template popup component (AddSponsorPageTemplatePopup) was added to the sponsor pages tab with supporting actions, state management, and translations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/sponsor-page-tab-managed-popup

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

@tomrndom tomrndom changed the title Feature/sponsor page tab managed popup feat: add template popup on sponsor tab Feb 25, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/actions/sponsor-pages-actions.js (1)

172-185: normalizeSponsorManagedPage handles "all" correctly, but the initial .map() on line 175 is wasteful when "all" is present.

When add_ons is ["all"], line 175 calls "all".idundefined, then lines 179-182 immediately overwrite allowed_add_ons with []. Consider checking the "all" case first to avoid the unnecessary mapping and the transient [undefined] value.

♻️ Suggested refactor
 const normalizeSponsorManagedPage = (entity) => {
+  const isAll = entity.add_ons.includes("all");
   const normalizedEntity = {
     show_page_ids: entity.pages,
-    allowed_add_ons: entity.add_ons.map((a) => a.id),
-    apply_to_all_add_ons: false
+    allowed_add_ons: isAll ? [] : entity.add_ons.map((a) => a.id),
+    apply_to_all_add_ons: isAll
   };
 
-  if (entity.add_ons.includes("all")) {
-    normalizedEntity.apply_to_all_add_ons = true;
-    normalizedEntity.allowed_add_ons = [];
-  }
-
   return normalizedEntity;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/actions/sponsor-pages-actions.js` around lines 172 - 185,
normalizeSponsorManagedPage currently maps entity.add_ons to ids before checking
for the "all" sentinel, producing a transient [undefined]; change the logic so
you first check if entity.add_ons.includes("all") and if so set
apply_to_all_add_ons = true and allowed_add_ons = [] immediately, otherwise
compute allowed_add_ons = entity.add_ons.map(a => a.id); preserve show_page_ids
assignment and default apply_to_all_add_ons = false, and update only within the
normalizeSponsorManagedPage function.
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js (1)

301-303: Incomplete PropTypes declaration.

Only onClose is declared. onSubmit, sponsor, and summitId are required for correct operation but are missing from propTypes.

♻️ Suggested improvement
 AddSponsorPageTemplatePopup.propTypes = {
-  onClose: PropTypes.func.isRequired
+  onClose: PropTypes.func.isRequired,
+  onSubmit: PropTypes.func.isRequired,
+  sponsor: PropTypes.object.isRequired,
+  summitId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 301 - 303, Add missing PropTypes for AddSponsorPageTemplatePopup:
extend AddSponsorPageTemplatePopup.propTypes to include onSubmit
(PropTypes.func.isRequired), sponsor (PropTypes.object.isRequired or a more
specific shape if available), and summitId
(PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired) alongside
the existing onClose declaration so the component's required props are
explicitly validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/actions/sponsor-pages-actions.js`:
- Around line 161-170: The loading state isn't cleared on failures because
stopLoading is only dispatched in the .then() of the postRequest call; update
the postRequest invocation (the call that returns
postRequest(...)(params)(dispatch) in this file) to call .finally(() => {
dispatch(stopLoading()); }) instead of .then(...), so stopLoading runs on both
success and failure (follow the same pattern used in cloneGlobalPage).

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 229-242: Replace the two hardcoded English strings with i18n
calls: change the selected count label currently rendered in the Grid2 that
shows "{selectedPages.length} items selected" to use T.translate with a key like
"forms_tab.items_selected" (or reuse an existing key) and interpolate
selectedPages.length, and change the MenuButton children text "sort by" to
T.translate("forms_tab.sort_by") (or the appropriate locale key); keep the
SwapVertIcon and the MenuButton menuItems using
T.translate("forms_tab.sort_asc_label") and
T.translate("forms_tab.sort_desc_label") for "A-Z"/"Z-A" if not already, and
update code around MenuButton, handleSort, selectedPages to pass the translated
strings.
- Around line 46-51: sponsor.sponsorships can be null/undefined so mapping
directly causes runtime errors; fix by using a safe fallback when creating
sponsorshipIds and sponsorshipTypeIds (e.g. map over sponsor?.sponsorships ?? []
or (sponsor.sponsorships || [])) so the declarations for sponsorshipIds and
sponsorshipTypeIds use that fallback and avoid throwing when sponsorships is
missing.
- Around line 89-124: handlePageChange and handleSort call getShowPages with the
Redux prop term while handleOnSearch uses local searchTerm, causing the search
to be lost on pagination/sort; fix by using a single source of truth—either
(preferred) pass the local searchTerm from handlePageChange and handleSort into
getShowPages (replace term with searchTerm) or update the Redux term when
handleOnSearch runs so all handlers use the Redux term. Update the function
calls in handlePageChange and handleSort (and any other pagination/sort
handlers) to use the chosen search value and keep other parameters (currentPage,
perPage/FIVE_PER_PAGE, order, orderDir, sponsorshipTypeIds) unchanged so
searches persist across pages and sorts.

In `@src/pages/sponsors/sponsor-pages-tab/index.js`:
- Around line 195-200: The handler handleSaveManagedPageFromTemplate currently
calls saveSponsorManagedPage(entity).then(...) but has no .catch(), allowing
snackbarErrorHandler to swallow errors and still run setOpenPopup(null) and
getSponsorManagedPages(); change it to only close the popup and refresh on true
success by attaching a .catch() (or using async/await with try/catch) around
saveSponsorManagedPage: on success call setOpenPopup(null) and
getSponsorManagedPages(), on failure do not close the popup and let
snackbarErrorHandler display the error (or rethrow/return a rejected promise) so
failure paths prevent closing and refreshing.

---

Nitpick comments:
In `@src/actions/sponsor-pages-actions.js`:
- Around line 172-185: normalizeSponsorManagedPage currently maps entity.add_ons
to ids before checking for the "all" sentinel, producing a transient
[undefined]; change the logic so you first check if
entity.add_ons.includes("all") and if so set apply_to_all_add_ons = true and
allowed_add_ons = [] immediately, otherwise compute allowed_add_ons =
entity.add_ons.map(a => a.id); preserve show_page_ids assignment and default
apply_to_all_add_ons = false, and update only within the
normalizeSponsorManagedPage function.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 301-303: Add missing PropTypes for AddSponsorPageTemplatePopup:
extend AddSponsorPageTemplatePopup.propTypes to include onSubmit
(PropTypes.func.isRequired), sponsor (PropTypes.object.isRequired or a more
specific shape if available), and summitId
(PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired) alongside
the existing onClose declaration so the component's required props are
explicitly validated.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0fbe8c and b3b9132.

📒 Files selected for processing (5)
  • src/actions/sponsor-pages-actions.js
  • src/components/mui/formik-inputs/mui-formik-select-group.js
  • src/i18n/en.json
  • src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js
  • src/pages/sponsors/sponsor-pages-tab/index.js

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js (2)

52-54: ⚠️ Potential issue | 🟠 Major

Guard sponsor access before mapping and query param usage.

Line 52 and Line 54 can throw if sponsor/sponsorships is missing, and Line 213 also assumes sponsor.id exists.

Proposed fix
-  const sponsorshipIds = sponsor.sponsorships.map((e) => e.id);
-
-  const sponsorshipTypeIds = sponsor.sponsorships.map((e) => e.type.id);
+  const sponsorships = sponsor?.sponsorships ?? [];
+  const sponsorshipIds = sponsorships.map((e) => e.id);
+  const sponsorshipTypeIds = sponsorships
+    .map((e) => e?.type?.id)
+    .filter((id) => id != null);

...
-                queryParams={[summitId, sponsor.id, sponsorshipIds]}
+                queryParams={[summitId, sponsor?.id, sponsorshipIds]}

Also applies to: 213-213

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 52 - 54, Guard against missing sponsor or sponsor.sponsorships
before mapping and before using sponsor.id: ensure sponsor is defined and
sponsor.sponsorships is an array (e.g., default to [] or use optional chaining)
before computing sponsorshipIds and sponsorshipTypeIds in the code that defines
those constants, and validate sponsor.id exists before using it at the location
referencing sponsor.id (line ~213) to avoid runtime errors in
functions/components that reference sponsorshipIds, sponsorshipTypeIds, and
sponsor.id.

232-232: ⚠️ Potential issue | 🟡 Minor

Replace remaining hardcoded labels with i18n keys.

Line 232 (items selected) and Line 250 (sort by) are still hardcoded English.

Proposed fix
-                <Grid2 size={4}>{selectedPages.length} items selected</Grid2>
+                <Grid2 size={4}>
+                  {selectedPages.length}{" "}
+                  {T.translate("show_pages.global_page_popup.items_selected")}
+                </Grid2>

...
-                    <SwapVertIcon fontSize="large" sx={{ mr: 1 }} /> sort by
+                    <SwapVertIcon fontSize="large" sx={{ mr: 1 }} />{" "}
+                    {T.translate("show_pages.sort_by")}

Also applies to: 250-250

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
at line 232, Replace the hardcoded English labels with i18n keys: change the
Grid2 text that renders "{selectedPages.length} items selected" to use the
translation helper (e.g. t or useTranslation) and pass the count via
interpolation (for example t('sponsors.selectedItems', { count:
selectedPages.length }) or a pluralized key), and likewise replace the "sort by"
label with a translation key (e.g. t('sponsors.sortBy')). Ensure you import/use
the i18n hook/function in the component and add appropriate keys
(sponsors.selectedItems, sponsors.sortBy) to the locale files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 116-127: handleOnSearch currently triggers getShowPages on Enter
but because the input is inside a form pressing Enter also causes a form submit;
update the Enter branch in handleOnSearch to call ev.preventDefault() and
ev.stopPropagation() before invoking getShowPages to avoid the unintended
onSubmit, and apply the same fix to the other search key handler used at the
block referenced around lines 201-203 so both handlers prevent default
submission and propagation when ev.key === "Enter".
- Around line 278-291: The code hides the MuiTable when showPages is empty which
suppresses the table’s built-in empty state; remove the conditional around the
MuiTable so it always renders (pass showPages as the data prop even when length
is 0) and keep existing props (columns, tableOptions, currentPage, perPage,
totalCount, onSort: handleSort, onPageChange: handlePageChange) so the table can
display its empty/no-results UI.

---

Duplicate comments:
In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 52-54: Guard against missing sponsor or sponsor.sponsorships
before mapping and before using sponsor.id: ensure sponsor is defined and
sponsor.sponsorships is an array (e.g., default to [] or use optional chaining)
before computing sponsorshipIds and sponsorshipTypeIds in the code that defines
those constants, and validate sponsor.id exists before using it at the location
referencing sponsor.id (line ~213) to avoid runtime errors in
functions/components that reference sponsorshipIds, sponsorshipTypeIds, and
sponsor.id.
- Line 232: Replace the hardcoded English labels with i18n keys: change the
Grid2 text that renders "{selectedPages.length} items selected" to use the
translation helper (e.g. t or useTranslation) and pass the count via
interpolation (for example t('sponsors.selectedItems', { count:
selectedPages.length }) or a pluralized key), and likewise replace the "sort by"
label with a translation key (e.g. t('sponsors.sortBy')). Ensure you import/use
the i18n hook/function in the component and add appropriate keys
(sponsors.selectedItems, sponsors.sortBy) to the locale files.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b3b9132 and e86dd28.

📒 Files selected for processing (2)
  • src/i18n/en.json
  • src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js

Comment on lines 116 to 127
const handleOnSearch = (ev) => {
if (ev.key === "Enter")
getShowPages(
searchTerm,
DEFAULT_CURRENT_PAGE,
perPage,
order,
orderDir,
false,
sponsorshipTypeIds
);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Pressing Enter in search can trigger an unintended submit.

Because the search field is inside a <form>, Enter can submit and call onSubmit while trying to search.

Proposed fix
   const handleOnSearch = (ev) => {
-    if (ev.key === "Enter")
+    if (ev.key === "Enter") {
+      ev.preventDefault();
+      ev.stopPropagation();
       getShowPages(
         searchTerm,
         DEFAULT_CURRENT_PAGE,
         perPage,
         order,
         orderDir,
         false,
         sponsorshipTypeIds
       );
+    }
   };

Also applies to: 201-203

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 116 - 127, handleOnSearch currently triggers getShowPages on Enter
but because the input is inside a form pressing Enter also causes a form submit;
update the Enter branch in handleOnSearch to call ev.preventDefault() and
ev.stopPropagation() before invoking getShowPages to avoid the unintended
onSubmit, and apply the same fix to the other search key handler used at the
block referenced around lines 201-203 so both handlers prevent default
submission and propagation when ev.key === "Enter".

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js (3)

52-54: ⚠️ Potential issue | 🔴 Critical

sponsor.sponsorships still lacks null-safety.

sponsor.sponsorships.map(...) throws if sponsorships is null or undefined.

🛡️ Proposed fix
-  const sponsorshipIds = sponsor.sponsorships.map((e) => e.id);
-
-  const sponsorshipTypeIds = sponsor.sponsorships.map((e) => e.type.id);
+  const sponsorships = sponsor?.sponsorships ?? [];
+  const sponsorshipIds = sponsorships.map((e) => e.id);
+  const sponsorshipTypeIds = sponsorships.map((e) => e.type.id);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 52 - 54, sponsor.sponsorships can be null/undefined causing
sponsorshipIds and sponsorshipTypeIds to throw; update the code that builds
sponsorshipIds and sponsorshipTypeIds to guard against a missing array (e.g.,
use optional chaining or default to an empty array when mapping) so both const
sponsorshipIds and const sponsorshipTypeIds operate on a safe array derived from
sponsor.sponsorships.

92-114: ⚠️ Potential issue | 🔴 Critical

handlePageChange and handleSort still use stale Redux term, breaking search-then-paginate/sort.

Both handlers pass the Redux term prop instead of the local searchTerm, so any active search is silently discarded when the user paginates or sorts.

🐛 Proposed fix
   const handlePageChange = (page) => {
     getShowPages(
-      term,
+      searchTerm,
       page,
       FIVE_PER_PAGE,
       order,
       orderDir,
       false,
       sponsorshipTypeIds
     );
   };

   const handleSort = (key, dir) => {
     getShowPages(
-      term,
+      searchTerm,
       DEFAULT_CURRENT_PAGE,
       FIVE_PER_PAGE,
       key,
       dir,
       false,
       sponsorshipTypeIds
     );
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 92 - 114, The handlers handlePageChange and handleSort are passing
the stale Redux prop term instead of the local controlled searchTerm, causing
active searches to be lost when paginating/sorting; update both functions so
they call getShowPages with searchTerm (not term) as the first argument—keep all
other args (page/current, FIVE_PER_PAGE, order/orderDir or key/dir, false,
sponsorshipTypeIds, and DEFAULT_CURRENT_PAGE for handleSort) unchanged so
pagination and sorting respect the current local search state.

235-235: ⚠️ Potential issue | 🟡 Minor

Hardcoded English strings — "items selected" and "sort by" are not translated.

Line 235 ("{n} items selected") and line 253 ("sort by") bypass T.translate() while every other UI label in the component uses it.

🛡️ Proposed fix
-              <Grid2 size={4}>{selectedPages.length} items selected</Grid2>
+              <Grid2 size={4}>
+                {T.translate("edit_sponsor.pages_tab.items_selected", { count: selectedPages.length })}
+              </Grid2>
-                    <SwapVertIcon fontSize="large" sx={{ mr: 1 }} /> sort by
+                    <SwapVertIcon fontSize="large" sx={{ mr: 1 }} />
+                    {T.translate("edit_sponsor.pages_tab.sort_by")}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
at line 235, The strings "items selected" and "sort by" are hardcoded and must
use the project's translation helper; replace the literal text in the JSX where
Grid2 renders "{selectedPages.length} items selected" and where the sort label
is rendered with calls to T.translate (e.g., T.translate('items_selected', {
count: selectedPages.length }) or the project's pluralization pattern) and
T.translate('sort_by') respectively, ensuring you pass the dynamic count to the
translation function for correct pluralization and match the existing
T.translate usage elsewhere in this component.
🧹 Nitpick comments (1)
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js (1)

318-320: PropTypes is incomplete — onSubmit, sponsor, summitId are required but undeclared.

Only onClose is declared. The component will silently receive wrong types or miss required props without any dev-time warning.

♻️ Proposed additions
 AddSponsorPageTemplatePopup.propTypes = {
-  onClose: PropTypes.func.isRequired
+  onClose: PropTypes.func.isRequired,
+  onSubmit: PropTypes.func.isRequired,
+  summitId: PropTypes.number.isRequired,
+  sponsor: PropTypes.shape({
+    id: PropTypes.number.isRequired,
+    sponsorships: PropTypes.arrayOf(
+      PropTypes.shape({
+        id: PropTypes.number.isRequired,
+        type: PropTypes.shape({
+          id: PropTypes.number.isRequired
+        }).isRequired
+      })
+    )
+  }).isRequired
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 318 - 320, Add missing PropTypes for AddSponsorPageTemplatePopup:
declare onSubmit as PropTypes.func.isRequired, sponsor as
PropTypes.object.isRequired (or a PropTypes.shape(...) if specific fields are
known), and summitId as PropTypes.oneOfType([PropTypes.string,
PropTypes.number]).isRequired alongside the existing onClose, so the
AddSponsorPageTemplatePopup component validates all required props at dev time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Line 65: Replace the hardcoded validation message "Select at least one add-on"
in the Yup schema inside the AddSponsorPageTemplatePopup component with a call
to the i18n helper (T.translate) and use the translation key (e.g.
T.translate('sponsor_pages.select_at_least_one_addon')); locate the validation
rule in
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js
(the Yup validationSchema / the min(1, ... ) message) and swap the literal
string for T.translate(...), then add the corresponding key to the translation
files.

---

Duplicate comments:
In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 52-54: sponsor.sponsorships can be null/undefined causing
sponsorshipIds and sponsorshipTypeIds to throw; update the code that builds
sponsorshipIds and sponsorshipTypeIds to guard against a missing array (e.g.,
use optional chaining or default to an empty array when mapping) so both const
sponsorshipIds and const sponsorshipTypeIds operate on a safe array derived from
sponsor.sponsorships.
- Around line 92-114: The handlers handlePageChange and handleSort are passing
the stale Redux prop term instead of the local controlled searchTerm, causing
active searches to be lost when paginating/sorting; update both functions so
they call getShowPages with searchTerm (not term) as the first argument—keep all
other args (page/current, FIVE_PER_PAGE, order/orderDir or key/dir, false,
sponsorshipTypeIds, and DEFAULT_CURRENT_PAGE for handleSort) unchanged so
pagination and sorting respect the current local search state.
- Line 235: The strings "items selected" and "sort by" are hardcoded and must
use the project's translation helper; replace the literal text in the JSX where
Grid2 renders "{selectedPages.length} items selected" and where the sort label
is rendered with calls to T.translate (e.g., T.translate('items_selected', {
count: selectedPages.length }) or the project's pluralization pattern) and
T.translate('sort_by') respectively, ensuring you pass the dynamic count to the
translation function for correct pluralization and match the existing
T.translate usage elsewhere in this component.

---

Nitpick comments:
In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 318-320: Add missing PropTypes for AddSponsorPageTemplatePopup:
declare onSubmit as PropTypes.func.isRequired, sponsor as
PropTypes.object.isRequired (or a PropTypes.shape(...) if specific fields are
known), and summitId as PropTypes.oneOfType([PropTypes.string,
PropTypes.number]).isRequired alongside the existing onClose, so the
AddSponsorPageTemplatePopup component validates all required props at dev time.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e86dd28 and 47d910d.

📒 Files selected for processing (2)
  • src/i18n/en.json
  • src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/i18n/en.json

@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js (2)

49-113: ⚠️ Potential issue | 🟠 Major

Pagination/sort still drops the searched query.

Line 94 and Line 106 use term, while Line 121 searches with local searchTerm. After searching, sorting/paging can revert results to a stale filter.

🐛 Proposed fix
-  const [searchTerm, setSearchTerm] = useState("");
+  const [searchTerm, setSearchTerm] = useState(term);

   const handlePageChange = (page) => {
     getShowPages(
-      term,
+      searchTerm,
       page,
       FIVE_PER_PAGE,
       order,
       orderDir,
       false,
       sponsorshipTypeIds
     );
   };

   const handleSort = (key, dir) => {
     getShowPages(
-      term,
+      searchTerm,
       DEFAULT_CURRENT_PAGE,
       FIVE_PER_PAGE,
       key,
       dir,
       false,
       sponsorshipTypeIds
     );
   };

Also applies to: 116-128

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 49 - 113, The pagination/sort calls use the wrong query variable
(term) causing searches to be lost; change all getShowPages invocations in
useEffect, handlePageChange, handleSort (and any other paging/sorting helpers
around those lines) to use the component state searchTerm instead of term,
ensure searchTerm is updated via setSearchTerm when the user searches, and add
searchTerm to the useEffect dependency array so fetching reacts to search
changes; references: searchTerm, setSearchTerm, getShowPages, handlePageChange,
handleSort, and the existing useEffect.

235-235: ⚠️ Potential issue | 🟡 Minor

Two UI labels are still hardcoded in English.

Line 235 (items selected) and Line 253 (sort by) should be translated for i18n consistency.

🌐 Proposed fix
-                <Grid2 size={4}>{selectedPages.length} items selected</Grid2>
+                <Grid2 size={4}>
+                  {T.translate("edit_sponsor.pages_tab.items_selected", {
+                    count: selectedPages.length
+                  })}
+                </Grid2>

-                    <SwapVertIcon fontSize="large" sx={{ mr: 1 }} /> sort by
+                    <SwapVertIcon fontSize="large" sx={{ mr: 1 }} />
+                    {T.translate("general.sort_by")}

Also applies to: 253-253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
at line 235, Replace the two hardcoded English labels in the
AddSponsorPageTemplatePopup component with i18n translation keys: wrap the
"items selected" string rendered in the Grid2 that shows {selectedPages.length}
and the "sort by" label (the control near line 253) with the project's
translation function (e.g., useTranslation().t or t) and use descriptive keys
like "sponsorPages.itemsSelected" and "sponsorPages.sortBy" so the UI reads
t('sponsorPages.itemsSelected', { count: selectedPages.length }) and
t('sponsorPages.sortBy'); update the translation resource files with these keys
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 49-113: The pagination/sort calls use the wrong query variable
(term) causing searches to be lost; change all getShowPages invocations in
useEffect, handlePageChange, handleSort (and any other paging/sorting helpers
around those lines) to use the component state searchTerm instead of term,
ensure searchTerm is updated via setSearchTerm when the user searches, and add
searchTerm to the useEffect dependency array so fetching reacts to search
changes; references: searchTerm, setSearchTerm, getShowPages, handlePageChange,
handleSort, and the existing useEffect.
- Line 235: Replace the two hardcoded English labels in the
AddSponsorPageTemplatePopup component with i18n translation keys: wrap the
"items selected" string rendered in the Grid2 that shows {selectedPages.length}
and the "sort by" label (the control near line 253) with the project's
translation function (e.g., useTranslation().t or t) and use descriptive keys
like "sponsorPages.itemsSelected" and "sponsorPages.sortBy" so the UI reads
t('sponsorPages.itemsSelected', { count: selectedPages.length }) and
t('sponsorPages.sortBy'); update the translation resource files with these keys
accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47d910d and 76a430a.

📒 Files selected for processing (3)
  • src/i18n/en.json
  • src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js
  • src/pages/sponsors/sponsor-pages-tab/index.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/i18n/en.json

@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
@fntechgit fntechgit deleted a comment from coderabbitai bot Feb 26, 2026
Copy link

@smarcet smarcet left a comment

Choose a reason for hiding this comment

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

@tomrndom please review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/i18n/en.json`:
- Line 2486: The i18n string "no_pages" currently reads "There is no pages that
match the criteria" and uses incorrect singular verb; update the value for the
"no_pages" key to use plural agreement—e.g., change it to "There are no pages
that match the criteria" (or "There are no pages matching the criteria") so the
copy is grammatically correct.
- Line 6: Update the errors.empty_list message string in en.json to correct the
grammar; replace the current text ("there not are any {item} that match your
criteria.") with a natural sentence such as "There are no {item} that match your
criteria." keeping the {item} placeholder intact and preserving JSON string
formatting and punctuation/capitalization.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`:
- Around line 116-124: The search handler handleOnSearch calls getShowPages with
perPage which is inconsistent with the rest of the popup that uses
FIVE_PER_PAGE; update the getShowPages invocation inside handleOnSearch to pass
FIVE_PER_PAGE (and ensure any other pagination-related calls in this component
consistently use FIVE_PER_PAGE) so search requests and pagination share the same
page size.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76a430a and 478d516.

📒 Files selected for processing (7)
  • src/actions/sponsor-pages-actions.js
  • src/i18n/en.json
  • src/pages/sponsors-global/form-templates/add-form-template-item-popup.js
  • src/pages/sponsors-global/form-templates/form-template-from-duplicate-popup.js
  • src/pages/sponsors/sponsor-forms-tab/components/add-sponsor-form-template-popup/index.js
  • src/pages/sponsors/sponsor-forms-tab/components/manage-items/sponsor-form-item-from-inventory.js
  • src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js

"user_not_set": "Hold on. Can not get any valid user.",
"session_expired": "Hold on. Your session expired!.",
"empty_list": "there not are any item that match your criteria.",
"empty_list": "there not are any {item} that match your criteria.",
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

Fix grammar in the errors.empty_list message.

Line [6] currently reads unnaturally: "there not are any {item} that match your criteria.".

✍️ Proposed fix
-    "empty_list": "there not are any {item} that match your criteria.",
+    "empty_list": "There are no {item} that match your criteria.",
📝 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
"empty_list": "there not are any {item} that match your criteria.",
"empty_list": "There are no {item} that match your criteria.",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/i18n/en.json` at line 6, Update the errors.empty_list message string in
en.json to correct the grammar; replace the current text ("there not are any
{item} that match your criteria.") with a natural sentence such as "There are no
{item} that match your criteria." keeping the {item} placeholder intact and
preserving JSON string formatting and punctuation/capitalization.

"unarchive": "Unarchive",
"items_selected": "items selected",
"no_add_ons": "No Add-ons Available",
"no_pages": "There is no pages that match the criteria",
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

Fix grammar in sponsor pages empty-state copy.

Line [2486] should use plural agreement (are + pages) for correct UX copy.

✍️ Proposed fix
-      "no_pages": "There is no pages that match the criteria",
+      "no_pages": "There are no pages that match the criteria",
📝 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
"no_pages": "There is no pages that match the criteria",
"no_pages": "There are no pages that match the criteria",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/i18n/en.json` at line 2486, The i18n string "no_pages" currently reads
"There is no pages that match the criteria" and uses incorrect singular verb;
update the value for the "no_pages" key to use plural agreement—e.g., change it
to "There are no pages that match the criteria" (or "There are no pages matching
the criteria") so the copy is grammatically correct.

Comment on lines +116 to +124
const handleOnSearch = (ev) => {
if (ev.key === "Enter") {
ev.preventDefault();
ev.stopPropagation();
getShowPages(
searchTerm,
DEFAULT_CURRENT_PAGE,
perPage,
order,
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

Use a consistent page size for search requests.

Line [123] uses perPage, while the rest of this popup uses FIVE_PER_PAGE (Lines [84], [96], [108]). That can cause inconsistent result sizing and pagination state.

🔧 Proposed fix
       getShowPages(
         searchTerm,
         DEFAULT_CURRENT_PAGE,
-        perPage,
+        FIVE_PER_PAGE,
         order,
         orderDir,
         false,
         sponsorshipTypeIds
       );
📝 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 handleOnSearch = (ev) => {
if (ev.key === "Enter") {
ev.preventDefault();
ev.stopPropagation();
getShowPages(
searchTerm,
DEFAULT_CURRENT_PAGE,
perPage,
order,
const handleOnSearch = (ev) => {
if (ev.key === "Enter") {
ev.preventDefault();
ev.stopPropagation();
getShowPages(
searchTerm,
DEFAULT_CURRENT_PAGE,
FIVE_PER_PAGE,
order,
orderDir,
false,
sponsorshipTypeIds
);
}
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/sponsors/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js`
around lines 116 - 124, The search handler handleOnSearch calls getShowPages
with perPage which is inconsistent with the rest of the popup that uses
FIVE_PER_PAGE; update the getShowPages invocation inside handleOnSearch to pass
FIVE_PER_PAGE (and ensure any other pagination-related calls in this component
consistently use FIVE_PER_PAGE) so search requests and pagination share the same
page size.

Added licensing information and copyright notice to the file.

Signed-off-by: Santi <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants