Skip to content

SL-351 translations and customer id parsing - #314

Merged
justelis22 merged 46 commits into
feature/react-admin-settingsfrom
SL-351/parse-customer-id
Jul 9, 2026
Merged

SL-351 translations and customer id parsing#314
justelis22 merged 46 commits into
feature/react-admin-settingsfrom
SL-351/parse-customer-id

Conversation

@GytisZum

Copy link
Copy Markdown
Collaborator

Self-Checks

  • I have performed a self-review of my code.
  • I have updated/added necessary technical documentation in the README file.

JIRA task link

Summary

QA Checklist Labels

  • Bug fix?
  • New feature?
  • Improvement?
  • Technical debt?
  • Reusable?
  • Covered by tests?

QA Checklist

Additional Context

Frontend Changes

@GytisZum GytisZum self-assigned this Mar 12, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Saferpay module's administrative interface by improving security, streamlining API credential management, and modernizing the frontend development and user experience. It centralizes translation efforts for the React settings page, adds robust validation for API credentials, and secures AJAX communications, making the module more reliable, user-friendly, and easier to maintain.

Highlights

  • Enhanced Security for AJAX Endpoints: Implemented a whitelist for allowed AJAX actions and added token validation to secure administrative AJAX requests, preventing unauthorized access and potential vulnerabilities.
  • Improved API Credential Handling: Introduced automatic parsing of the customer ID directly from the API username, eliminating the need for a separate customer ID input field. Credentials are now validated against the Saferpay API before being saved, providing immediate feedback on their correctness.
  • Centralized Frontend Translations: A new service has been added to manage and provide all necessary translatable strings to the React-based settings frontend, ensuring a consistent and easily maintainable multilingual user interface.
  • Refined React Development Workflow: New Makefile targets were added to streamline React development, including commands for starting a development server with Hot Module Replacement (HMR), watching for changes, and running TypeScript type checks.
  • Enhanced User Experience in Settings: The React frontend now includes an error boundary for better fault tolerance, improved AJAX request handling with admin token inclusion, and more descriptive, translatable success/error messages for various operations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • Makefile
    • Added new 'dev-react' target for starting the React development server with Hot Module Replacement (HMR).
    • Introduced 'watch-react' target to build the React application and watch for file changes.
    • Included 'lint-react' target for running TypeScript type checks on the React frontend.
  • controllers/admin/AdminSaferPayOfficialSettingsController.php
    • Defined a constant ALLOWED_AJAX_ACTIONS to whitelist valid AJAX actions.
    • Implemented validateAjaxToken() method to ensure AJAX requests originate from an authenticated admin.
    • Modified postProcess() to enforce AJAX token validation and action whitelisting.
    • Updated isAjax() to use strict type comparison for Tools::getValue('ajax').
    • Refactored ajaxProcessSaveCredentials() to validate API credentials against the Saferpay API before saving and to parse customer ID from the username.
    • Removed explicit customer ID fields from the collected settings data.
    • Updated various success and error messages to use the module's translation function ($this->module->l()).
    • Replaced ajaxDie(json_encode(...)) with a new sendJsonResponse() helper for consistent JSON responses.
    • Added parseCustomerIdFromUsername() to extract the customer ID from the API username string.
    • Implemented parseApiErrorMessage() to provide user-friendly messages from raw Saferpay API error responses.
    • Removed pSQL() from getStringValue() as it's not needed for frontend data.
  • src/DTO/Request/GetTerminals/GetTerminalsRequest.php
    • Added validation for the customer ID format in the constructor to ensure it matches expected patterns.
  • src/Service/SettingsTranslationService.php
    • Added a new service file to centralize and retrieve all translatable strings for the React frontend settings page.
  • views/js/admin/settings-app/src/App.tsx
    • Introduced a React ErrorBoundary component to gracefully handle rendering errors in the application.
    • Integrated translation utility for displaying error messages from the ErrorBoundary.
  • views/js/admin/settings-app/src/api/client.ts
    • Modified postAjax to include the admin token in AJAX requests for enhanced security.
    • Refined return types for API calls to ensure type safety and consistent handling of success/error responses.
  • views/js/admin/settings-app/src/components/settings/api-credentials.tsx
    • Removed the explicit customer ID input field, as it's now parsed automatically from the username.
    • Integrated the new translation utility for all user-facing text.
    • Implemented debounced auto-fetching of terminals when credentials are provided.
    • Added logic to reset terminals when switching environments.
    • Conditional rendering for the terminal ID selection based on whether credentials are provided.
  • views/js/admin/settings-app/src/components/settings/email-notifications.tsx
    • Integrated the new translation utility for all user-facing text.
  • views/js/admin/settings-app/src/components/settings/general-settings.tsx
    • Integrated the new translation utility for all user-facing text.
  • views/js/admin/settings-app/src/components/settings/payment-methods.tsx
    • Integrated the new translation utility for all user-facing text.
    • Adjusted saving logic to ensure the save button is only shown when payment methods are available.
    • Added validation to skip payment methods without a name during iteration.
  • views/js/admin/settings-app/src/components/settings/payment-processing.tsx
    • Integrated the new translation utility for all user-facing text.
    • Added conditional rendering for the 'Show Cards' payment method logo setting, only displaying it if 'Group debit/credit cards' is enabled.
  • views/js/admin/settings-app/src/components/settings/saferpay-settings.tsx
    • Integrated the new translation utility for main titles and tab labels.
  • views/js/admin/settings-app/src/components/settings/toast-container.tsx
    • Updated the styling of toast notifications for better visibility and consistency.
  • views/js/admin/settings-app/src/context/settings-context.tsx
    • Refactored the saving state to use a savingSections Set, allowing tracking of saving status per section.
    • Updated fetchTerminals signature to no longer require customerId.
    • Integrated the new translation utility for toast messages.
    • Improved handling of paymentMethods initialization to ensure it's always an array.
    • Added useRef for settings and paymentMethods to ensure latest state is captured in callbacks.
  • views/js/admin/settings-app/src/hooks/use-mobile.tsx
    • Removed the use-mobile hook, simplifying the frontend codebase.
  • views/js/admin/settings-app/src/hooks/use-toast.ts
    • Updated useEffect dependency array to ensure correct behavior.
  • views/js/admin/settings-app/src/main.tsx
    • Modified the script to parse settings data from a <script type="application/json"> tag.
    • Added error handling for parsing settings data and displaying a fallback message.
    • Initialized the new translation utility with data from the backend.
  • views/js/admin/settings-app/src/types/index.ts
    • Removed testCustomerId and liveCustomerId from the SaferpaySettingsData interface.
    • Added translations field to SaferpaySettingsData to hold frontend translation strings.
  • views/js/admin/settings-app/src/utils/translations.ts
    • Added a new utility file containing functions to initialize and retrieve translated strings for the frontend.
  • views/templates/admin/settings_react.tpl
    • Changed how the $settingsDataJson variable is embedded into the HTML, now using a <script type="application/json"> tag instead of direct assignment to window.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

The pull request introduces significant security enhancements and architectural improvements. A critical SQL injection vulnerability was identified due to the removal of pSQL from getStringValue, which needs to be addressed. Security was improved by embedding settingsDataJson in a safer script tag to prevent XSS, and by adding admin token authentication to AJAX requests to prevent CSRF. Additionally, the code now includes validation for payment method data to prevent errors from malformed input, and the customerId is now derived from the username, simplifying API contracts and reducing redundancy.

private function getStringValue($data, $key)
{
return isset($data[$key]) ? pSQL((string) $data[$key]) : '';
return isset($data[$key]) ? (string) $data[$key] : '';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The removal of pSQL from getStringValue is a critical security concern. pSQL is essential for sanitizing strings before they are used in SQL queries to prevent SQL injection. If the values retrieved by getStringValue are later used in database operations without explicit sanitization, this change could introduce a severe vulnerability. It is highly recommended to re-introduce pSQL here or ensure that every call site of getStringValue that leads to a database query performs proper escaping.

        return isset($data[$key]) ? pSQL((string) $data[$key]) : '';

Comment thread controllers/admin/AdminSaferPayOfficialSettingsController.php
Comment thread controllers/admin/AdminSaferPayOfficialSettingsController.php
Comment thread views/templates/admin/settings_react.tpl
Comment thread views/js/admin/settings-app/src/api/client.ts
Comment thread views/js/admin/settings-app/src/main.tsx
Comment thread views/js/admin/settings-app/src/types/index.ts
Comment thread views/js/admin/settings-app/src/types/index.ts
Comment thread views/js/admin/settings-app/src/utils/translations.ts
Comment thread controllers/admin/AdminSaferPayOfficialSettingsController.php
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

Gytautas Zumaras and others added 24 commits March 15, 2026 11:49
Adds discernible accessible names to interactive controls that
were unlabelled at narrow viewports, resolving 33 of the 36 axe-core
violations found during SL-346 QA.

- Payment Methods mobile cards: add aria-label to "Logos" and
  "Custom form" switches (28 violations). Desktop layout was already
  labelled; only the md:sp-hidden mobile block was missing labels.
- Settings tab triggers: add aria-label to all five TabsTrigger
  buttons (5 violations). Visible text labels are wrapped in
  sp-hidden sm:sp-inline so on mobile only the icon shows; without
  aria-label the buttons had no accessible name.
- Darken --sp-muted-foreground from 46% to 38% lightness (4.31:1 -> ~6.4:1)
- Replace sp-text-emerald-600 with sp-text-emerald-700 in API Credentials
  (3.76:1 -> 5.27:1 on white, 3.57:1 -> ~5:1 on emerald-50)

Resolves 3 axe-core color-contrast violations across all 5 settings tabs.
Verified: 0 contrast issues remain inside #saferpay-settings-root.
Radix Label component does not auto-wire to SelectTrigger; without
an explicit aria-label, screen readers announced only the selected
value. Resolves last open finding in TC-346.1.
Previously Tab could escape the modal into background page content
violating WCAG 2.1.2 (Focus Order) for modal dialogs. Tab/Shift+Tab
now cycle within the modal's focusable elements.

Resolves TC-346.7.
PrestaShop core .btn-primary teal (#25b9d7) on white was 2.6:1 — fails
WCAG 2.1 AA (requires 4.5:1). Scoped override on #saferpay-admin-form
only, so other admin pages keep their PS theme. Refund/Capture buttons
now use the module brand teal #1c7c80 (5.27:1).
Without scope, screen readers cannot reliably associate header cells
with their data column. Resolves TC-346.10 (FO saved credit cards).
The PS Classic theme rendered the Remove link in teal #24b9d7 on white
(2.6:1) which fails WCAG 2.1 AA. Use brand teal #1c7c80 (5.27:1) via
inline color so the override does not bleed to other theme buttons.
The .btn-primary (BO admin order) and .btn-default (FO saved cards)
contrast issues originate in PrestaShop core/theme CSS, not in our
module. Overriding them at module level was the wrong layer:
- fragile against theme updates
- could clash with merchant theme customizations
- inconsistent with our decision to scope SL-346 to module-owned UI

These now match the same out-of-scope category as the BO breadcrumb,
help button, and submenu tabs. Module-owned a11y fixes (React Settings
app contrast, aria-labels, scope=col, focus trap, etc.) remain in PR.
- Disable Save Changes button when username/password empty, credential
  check is in flight, or inline credential error is shown
- Mark JSON API Username and Password as required (visual asterisk +
  aria-required) to surface the requirement before user clicks Save
The Saferpay Fields section was driven by a single hasBusinessLicense
flag derived from the active environment's stored license at page load.
Switching environments client-side did not re-evaluate it, so the
section stayed visible after switching to an environment with no
validated business license.

Expose testHasBusinessLicense and liveHasBusinessLicense separately
from the controller (initial payload and save response), and pick the
active one in api-credentials.tsx based on testMode.
When the Saferpay Management API license lookup fails during credentials
save, the previous flow showed a misleading green success toast that
asked merchants to verify credentials they had just successfully validated.

- Log the underlying error to the SaferPay module Logs tab via LoggerInterface
- Return a 'warning' flag in the save credentials response
- Render an amber warning toast with a clearer message that points to the Logs
…ntials

Disable Save Changes when API credentials empty or invalid
…nse-visibility

Fix Saferpay Fields visibility per active environment license
…toast

Log license fetch failures and surface honest warning toast on save
The polling script in saferpay_wait.tpl navigated the iframe itself via
window.location.href, leaving the parent window stuck on the SaferPay
iframe controller URL while the cart or order-confirmation page rendered
nested inside the iframe.

Use window.top so the redirect targets the parent window and the user
lands at /cart or /order-confirmation with the proper top-level chrome.
Tadas Labutis and others added 20 commits May 15, 2026 13:03
Address review feedback on PR #325:
- Use location.replace() so the polling page is not stored in history
  (Back from order-confirmation should not return to the spinner).
- Wrap window.top access in try/catch with an in-iframe fallback in
  case sandboxing or browser policy blocks the breakout.
…rictions-default

BUGFIX: payment methods default to all countries/currencies and dropdowns show All instead of 0
fix: break out of SaferPay iframe on payment status redirect
BUGFIX: redirect customer to cart instead of order history after Saferpay transaction abort
…le-info

BUGFIX: clarify Hosted field style info banner to mention Custom form requirement
Frontend (api-credentials.tsx): show inline error and disable Save when
any comma-separated entry fails an email regex.

Backend (AdminSaferPayOfficialSettingsController): reject save when
testMerchantEmails or liveMerchantEmails contains a value that fails
Validate::isEmail() — guards against curl/devtools bypass.
BUGFIX: validate Merchant Emails field on save
When 'Behavior when 3D Secure Payer Authentication was not successful'
was set to Authorize, the order was still being captured because the
AUTHORIZE branch was missing and the CANCEL branch did not return early,
so control fell through to the default-payment-behavior Capture block.

Each 3DS-fail branch now returns/dies explicitly, so the configured
3DS-fail behavior is always honored.
isValidResponse() already logs API errors before throwing
SaferPayApiException, so the surrounding catch in get(),
getWithCredentials(), and postWithCredentials() produced a redundant
error row for every failed call. Guard the catch-block logger->error
with if ($response === null) so it only fires on transport-level
failures, where isValidResponse() never ran.
…6/accessibility-eaa-compliance

# Conflicts:
#	controllers/admin/AdminSaferPayOfficialSettingsController.php
…ance

SL-346: add accessibility improvements for EAA compliance
SL-358: add ConfigSet field validation, move hosted field style to general settings
…cription

SL-356: add Order reference on payment page toggle to control Descripton
SL-355: add Capture option to 3D Secure failure behavior setting
SL-353/SL-354: fields settings block logic
SL-350: fixing styles and credentials saving logic
@justelis22
justelis22 merged commit 97ce036 into feature/react-admin-settings Jul 9, 2026
0 of 2 checks passed
@justelis22
justelis22 deleted the SL-351/parse-customer-id branch July 9, 2026 06:17
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