Skip to content

feat(core): Admin-driven customer verification and password reset#4763

Open
tbouliere-datasolution wants to merge 1 commit into
vendurehq:masterfrom
tbouliere-datasolution:feat-customer-action-admin
Open

feat(core): Admin-driven customer verification and password reset#4763
tbouliere-datasolution wants to merge 1 commit into
vendurehq:masterfrom
tbouliere-datasolution:feat-customer-action-admin

Conversation

@tbouliere-datasolution
Copy link
Copy Markdown
Contributor

@tbouliere-datasolution tbouliere-datasolution commented May 21, 2026

Description

This PR adds two administrator-driven actions on the Customer detail to handle the cases where a customer can no longer self-serve their account state — either because they never confirmed their verification email or because they've lost access to their inbox.

Two new admin-API mutations are exposed on the Customer namespace:

  • verifyCustomerAccountAsAdmin(customerId: ID!) — completes the email-verification step for a registered but unverified Customer with a randomly generated 16-character password, bypassing the verification-token flow. The cleartext password is returned once in the response
    (via the new AdminGeneratedPassword type) so the administrator can communicate it to the customer; it is not persisted anywhere else. A CUSTOMER_VERIFIED history entry is written and an AccountVerifiedEvent is published.
  • resetCustomerPasswordAsAdmin(customerId: ID!) — administrator-driven counterpart to the storefront requestPasswordReset mutation. For a verified Customer, it issues a password-reset token and publishes a PasswordResetEvent so the configured email handler can send the
    customer a reset link. No password is generated or returned — the customer chooses their new password through the standard reset flow.

A new CustomerAccountStateError (with an accountState: String field — "guest", "registered", or "verified") surfaces the cases where the action does not apply to the current account state. Under the hood, a new UserService.resetPasswordAsAdmin(ctx, userId, newPassword)
primitive performs the direct password reset without a token (also marking the user as verified if it wasn't already), and a getUserByIdWithPasswordHash helper consolidates the passwordHash-selecting query previously inlined in setPassword.

The Vendure Dashboard customer detail page gains a corresponding action button to invoke either mutation depending on the customer's current state.

Breaking changes

No breaking changes. This PR is purely additive:

  • New GraphQL types (AdminGeneratedPassword, CustomerAccountStateError) and unions (VerifyCustomerAccountAsAdminResult, ResetCustomerPasswordAsAdminResult).
  • New mutations behind the existing Permission.UpdateCustomer permission.
  • New public method on UserService (resetPasswordAsAdmin).
  • The internal refactor in UserService.setPassword (extracting getUserByIdWithPasswordHash) preserves the existing behavior.

Screenshot

Verify
Verify_OK
Reset

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vendure-storybook Ready Ready Preview, Comment May 21, 2026 9:45am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds two admin GraphQL mutations: verifyCustomerAccountAsAdmin and resetCustomerPasswordAsAdmin, with new types/unions and a CustomerAccountStateError. Implements resolver handlers and service logic including admin password reset, random password generation, verification history/event emission, and a RequestContext bridge for password reset emails. Updates generated types and introspection. Extends admin error resolvers. Adds E2E tests covering success and error states. Wires dashboard UI: action button, GraphQL documents, and conditional actions on the customer page. Updates translations across locales.

Possibly related PRs

Suggested reviewers

  • michaelbromley
  • grolmus
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Copy link
Copy Markdown
Contributor

@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: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/dashboard/src/i18n/locales/bg.po (1)

2546-2548: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the actor in the verification history entry.

Проверен от клиента means “verified by the customer”, not “customer verified”. With the new admin-triggered verification flow, this history line will read backwards. Something like Клиентът е верифициран or Профилът е верифициран would match the event.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/bg.po` around lines 2546 - 2548, Replace
the Bulgarian translation for the "Customer verified" history entry in
packages/dashboard/src/i18n/locales/bg.po (msgid "Customer verified") so it
reflects that the customer was verified (not that they verified someone); update
msgstr from "Проверен от клиента" to a passive/agent-less phrase such as
"Клиентът е верифициран" or "Профилът е верифициран" to match the
admin-triggered verification flow referenced by customer-history-utils.tsx (the
history entry text).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/service/services/customer.service.ts`:
- Around line 662-664: The Fisher–Yates shuffle in the loop that iterates "for
(let i = combined.length - 1; i > 0; i--)" is using randomInt(0, i) which
excludes i and creates an off-by-one bias; update the call to allow j to equal i
by using randomInt(0, i + 1) (or otherwise make the upper bound inclusive) so
the swap "[combined[i], combined[j]] = [combined[j], combined[i]]" implements a
correct unbiased Fisher–Yates shuffle.

In `@packages/dashboard/src/i18n/locales/ar.po`:
- Around line 2911-2914: The Arabic translation for the msgid beginning "This
marks the account as verified..." uses "موثوق" which is inconsistent with other
entries; update the msgstr to use the same term used elsewhere (e.g., "تم
التحقق" or "مُتحقق منه") to match status and success messages. Edit the msgstr
in packages/dashboard/src/i18n/locales/ar.po for the entry whose msgid matches
that sentence (found in customer-credential-action-button.tsx) and replace
"موثوق" with the project's chosen verified term so all related strings are
consistent.

In `@packages/dashboard/src/i18n/locales/bg.po`:
- Around line 2523-2525: Update the Bulgarian translation for the msgid "Send
reset email" so the CTA explicitly mentions password reset; in the locales file
change the msgstr to include "парола" (e.g. "Изпрати имейл за нулиране на
парола") to match the button in customer-credential-action-button.tsx and make
the action unambiguous.

In `@packages/dashboard/src/i18n/locales/cs.po`:
- Around line 1281-1284: The Czech ICU plural for the cancellation label is
missing the "few" form; update the msgstr for the ICU key used in
cancel-jobs-bulk-action.tsx (the msgid "{cancellableCount, plural, one {Cancel
{cancellableCount} job} other {Cancel {cancellableCount} jobs}}") to include a
few branch so counts 2–4 use "úlohy" (e.g. one {Zrušit {cancellableCount} úlohu}
few {Zrušit {cancellableCount} úlohy} other {Zrušit {cancellableCount} úloh});
apply the same change to the other occurrence mentioned (around lines 5487-5490)
so both pluralized strings use one/few/other Czech forms.
- Around line 2505-2508: Update the Czech translation for the "Send reset email"
string used in customer-credential-action-button.tsx: replace the current msgstr
"Odeslat e-mail pro obnovení" with the fuller label "Odeslat e-mail pro obnovení
hesla" so the UI clearly states that a password reset email will be sent and
matches nearby translations.

In `@packages/dashboard/src/i18n/locales/es.po`:
- Around line 5189-5190: The translation drops pluralization: update the PO
entry for msgid "Select {0}s" so plural intent is preserved — either provide a
proper plural Spanish translation or convert the entry to use gettext plural
forms (add msgid_plural "Select {0}s" and supply msgstr[0]/msgstr[1] with
singular and plural Spanish variants). Locate the existing msgid "Select {0}s"
and its msgstr and replace the msgstr with the correct plural-aware translations
(e.g., add msgid_plural and both msgstr indexes) matching Spanish grammar.

In `@packages/dashboard/src/i18n/locales/fa.po`:
- Line 3584: The pluralization for the "jobs" failure message currently uses
singular phrasing in the plural branch ("{rejected, plural, one {لغو {rejected}
کار با شکست مواجه شد} other {لغو {rejected} کار با شکست مواجه شد}}"); update the
plural-specific form (the "other" branch) to use the plural verb form (e.g.,
"...کار ... شدند") so plural counts read correctly, and apply the same change to
the second identical occurrence of this msgstr elsewhere in the file.

In `@packages/dashboard/src/i18n/locales/nl.po`:
- Around line 5184-5185: This entry currently loses plural semantics: replace
the single msgid/msgstr pair for "Select {0}s" with a proper pluralizable PO
entry by adding msgid_plural and providing msgstr[0] (singular) and msgstr[1]
(plural) translations, preserving the {0} placeholder and using correct Dutch
wording (e.g., singular "Selecteer {0}" and an appropriate plural form) so
plural rendering matches the original msgid's intent.

In `@packages/dashboard/src/i18n/locales/ro.po`:
- Around line 97-99: Replace the English heading labels in the ro.po entries
(msgid "Heading 1" ... "Heading 6") with their Romanian equivalents (e.g.,
"Titlu 1", "Titlu 2", ..., "Titlu 6") so the rich-text editor toolbar strings
from responsive-toolbar.tsx are localized; update every occurrence noted (the
other msgid repeats) to keep translations consistent across the file.

---

Outside diff comments:
In `@packages/dashboard/src/i18n/locales/bg.po`:
- Around line 2546-2548: Replace the Bulgarian translation for the "Customer
verified" history entry in packages/dashboard/src/i18n/locales/bg.po (msgid
"Customer verified") so it reflects that the customer was verified (not that
they verified someone); update msgstr from "Проверен от клиента" to a
passive/agent-less phrase such as "Клиентът е верифициран" or "Профилът е
верифициран" to match the admin-triggered verification flow referenced by
customer-history-utils.tsx (the history entry text).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: be3a1a0d-c532-48ab-885c-e48ebfc8cfa9

📥 Commits

Reviewing files that changed from the base of the PR and between c2b48fc and f902304.

📒 Files selected for processing (50)
  • packages/admin-ui/src/lib/core/src/common/generated-types.ts
  • packages/admin-ui/src/lib/core/src/common/introspection-result.ts
  • packages/asset-server-plugin/e2e/graphql/graphql-admin.ts
  • packages/asset-server-plugin/e2e/graphql/graphql-env-admin.d.ts
  • packages/asset-server-plugin/e2e/graphql/graphql-env-shop.d.ts
  • packages/asset-server-plugin/e2e/graphql/graphql-shop.ts
  • packages/common/src/generated-shop-types.ts
  • packages/common/src/generated-types.ts
  • packages/core/e2e/customer.e2e-spec.ts
  • packages/core/e2e/graphql/admin-definitions.ts
  • packages/core/e2e/graphql/graphql-admin.ts
  • packages/core/e2e/graphql/graphql-env-admin.d.ts
  • packages/core/e2e/graphql/graphql-env-shop.d.ts
  • packages/core/e2e/graphql/graphql-shop.ts
  • packages/core/src/api/resolvers/admin/customer.resolver.ts
  • packages/core/src/api/schema/admin-api/customer.api.graphql
  • packages/core/src/common/error/generated-graphql-admin-errors.ts
  • packages/core/src/service/services/customer.service.ts
  • packages/core/src/service/services/user.service.ts
  • packages/dashboard/src/app/routes/_authenticated/_customers/components/customer-credential-action-button.tsx
  • packages/dashboard/src/app/routes/_authenticated/_customers/customers.graphql.ts
  • packages/dashboard/src/app/routes/_authenticated/_customers/customers_.$id.tsx
  • packages/dashboard/src/i18n/locales/ar.po
  • packages/dashboard/src/i18n/locales/bg.po
  • packages/dashboard/src/i18n/locales/cs.po
  • packages/dashboard/src/i18n/locales/de.po
  • packages/dashboard/src/i18n/locales/en.po
  • packages/dashboard/src/i18n/locales/es.po
  • packages/dashboard/src/i18n/locales/fa.po
  • packages/dashboard/src/i18n/locales/fr.po
  • packages/dashboard/src/i18n/locales/he.po
  • packages/dashboard/src/i18n/locales/hr.po
  • packages/dashboard/src/i18n/locales/hu.po
  • packages/dashboard/src/i18n/locales/it.po
  • packages/dashboard/src/i18n/locales/ja.po
  • packages/dashboard/src/i18n/locales/nb.po
  • packages/dashboard/src/i18n/locales/ne.po
  • packages/dashboard/src/i18n/locales/nl.po
  • packages/dashboard/src/i18n/locales/pl.po
  • packages/dashboard/src/i18n/locales/pt_BR.po
  • packages/dashboard/src/i18n/locales/pt_PT.po
  • packages/dashboard/src/i18n/locales/ro.po
  • packages/dashboard/src/i18n/locales/ru.po
  • packages/dashboard/src/i18n/locales/sv.po
  • packages/dashboard/src/i18n/locales/tr.po
  • packages/dashboard/src/i18n/locales/uk.po
  • packages/dashboard/src/i18n/locales/zh_Hans.po
  • packages/dashboard/src/i18n/locales/zh_Hant.po
  • packages/dashboard/src/lib/graphql/graphql-env.d.ts
  • schema-admin.json

Comment on lines +662 to +664
for (let i = combined.length - 1; i > 0; i--) {
const j = randomInt(0, i);
[combined[i], combined[j]] = [combined[j], combined[i]];
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Off-by-one error in Fisher-Yates shuffle.

Similarly, randomInt(0, i) excludes index i from the swap candidates. The correct Fisher-Yates implementation should allow j to equal i (the element can stay in place), so the upper bound should be i + 1.

🐛 Proposed fix
         for (let i = combined.length - 1; i > 0; i--) {
-            const j = randomInt(0, i);
+            const j = randomInt(0, i + 1);
             [combined[i], combined[j]] = [combined[j], combined[i]];
         }
📝 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
for (let i = combined.length - 1; i > 0; i--) {
const j = randomInt(0, i);
[combined[i], combined[j]] = [combined[j], combined[i]];
for (let i = combined.length - 1; i > 0; i--) {
const j = randomInt(0, i + 1);
[combined[i], combined[j]] = [combined[j], combined[i]];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/service/services/customer.service.ts` around lines 662 -
664, The Fisher–Yates shuffle in the loop that iterates "for (let i =
combined.length - 1; i > 0; i--)" is using randomInt(0, i) which excludes i and
creates an off-by-one bias; update the call to allow j to equal i by using
randomInt(0, i + 1) (or otherwise make the upper bound inclusive) so the swap
"[combined[i], combined[j]] = [combined[j], combined[i]]" implements a correct
unbiased Fisher–Yates shuffle.

Comment on lines +2911 to +2914
#: src/app/routes/_authenticated/_customers/components/customer-credential-action-button.tsx:81
msgid "This marks the account as verified and sets a new random password, bypassing the email verification flow. The password will be displayed once — the customer will not receive any notification."
msgstr "يحدد هذا الإجراء الحساب كموثوق ويعين كلمة مرور عشوائية جديدة، متجاوزًا تدفق التحقق عبر البريد الإلكتروني. سيتم عرض كلمة المرور مرة واحدة — لن يتلقى العميل أي إشعار."

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use consistent term for “verified” in Arabic copy.

Line 2913 uses "موثوق" for “verified”, but other related entries in this file use "مُتحقق منه/تم التحقق" (e.g., status and success messages). Please align this string to the same term to avoid UX inconsistency in the new account-verification flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/ar.po` around lines 2911 - 2914, The
Arabic translation for the msgid beginning "This marks the account as
verified..." uses "موثوق" which is inconsistent with other entries; update the
msgstr to use the same term used elsewhere (e.g., "تم التحقق" or "مُتحقق منه")
to match status and success messages. Edit the msgstr in
packages/dashboard/src/i18n/locales/ar.po for the entry whose msgid matches that
sentence (found in customer-credential-action-button.tsx) and replace "موثوق"
with the project's chosen verified term so all related strings are consistent.

Comment on lines +2523 to +2525
#: src/app/routes/_authenticated/_customers/components/customer-credential-action-button.tsx:70
msgid "Send reset email"
msgstr "Изпращане на имейл за нулиране"
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the CTA explicit about password reset.

Изпращане на имейл за нулиране drops what is being reset, so the button reads vague in Bulgarian. Please keep парола in the label, e.g. Изпрати имейл за нулиране на парола.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/bg.po` around lines 2523 - 2525, Update
the Bulgarian translation for the msgid "Send reset email" so the CTA explicitly
mentions password reset; in the locales file change the msgstr to include
"парола" (e.g. "Изпрати имейл за нулиране на парола") to match the button in
customer-credential-action-button.tsx and make the action unambiguous.

Comment on lines 1281 to 1284
#: src/app/routes/_authenticated/_system/components/cancel-jobs-bulk-action.tsx:63
msgid "{cancellableCount, plural, one {Cancel {cancellableCount} job} other {Cancel {cancellableCount} jobs}}"
msgstr ""
msgstr "{cancellableCount, plural, one {Zrušit {cancellableCount} úlohu} other {Zrušit {cancellableCount} úloh}}"

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use Czech plural categories for job counts.

These ICU plurals currently use one/other, with other rendered as úloh. In Czech, counts 2–4 should use a different form (e.g. úlohy). Please add a few branch to avoid grammatically incorrect UI text for common counts.

Suggested ICU update
-msgstr "{cancellableCount, plural, one {Zrušit {cancellableCount} úlohu} other {Zrušit {cancellableCount} úloh}}"
+msgstr "{cancellableCount, plural, one {Zrušit {cancellableCount} úlohu} few {Zrušit {cancellableCount} úlohy} other {Zrušit {cancellableCount} úloh}}"

-msgstr "{cancellableCount, plural, one {Opravdu chcete zrušit {cancellableCount} úlohu? Tuto akci nelze vrátit zpět.} other {Opravdu chcete zrušit {cancellableCount} úloh? Tuto akci nelze vrátit zpět.}}"
+msgstr "{cancellableCount, plural, one {Opravdu chcete zrušit {cancellableCount} úlohu? Tuto akci nelze vrátit zpět.} few {Opravdu chcete zrušit {cancellableCount} úlohy? Tuto akci nelze vrátit zpět.} other {Opravdu chcete zrušit {cancellableCount} úloh? Tuto akci nelze vrátit zpět.}}"

Also applies to: 5487-5490

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/cs.po` around lines 1281 - 1284, The
Czech ICU plural for the cancellation label is missing the "few" form; update
the msgstr for the ICU key used in cancel-jobs-bulk-action.tsx (the msgid
"{cancellableCount, plural, one {Cancel {cancellableCount} job} other {Cancel
{cancellableCount} jobs}}") to include a few branch so counts 2–4 use "úlohy"
(e.g. one {Zrušit {cancellableCount} úlohu} few {Zrušit {cancellableCount}
úlohy} other {Zrušit {cancellableCount} úloh}); apply the same change to the
other occurrence mentioned (around lines 5487-5490) so both pluralized strings
use one/few/other Czech forms.

Comment on lines +2505 to +2508
#: src/app/routes/_authenticated/_customers/components/customer-credential-action-button.tsx:70
msgid "Send reset email"
msgstr "Odeslat e-mail pro obnovení"

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify the reset action label for users.

"Odeslat e-mail pro obnovení" is understandable but incomplete in Czech UI context (missing what is being reset). Use a fuller label like "Odeslat e-mail pro obnovení hesla" for consistency with nearby strings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/cs.po` around lines 2505 - 2508, Update
the Czech translation for the "Send reset email" string used in
customer-credential-action-button.tsx: replace the current msgstr "Odeslat
e-mail pro obnovení" with the fuller label "Odeslat e-mail pro obnovení hesla"
so the UI clearly states that a password reset email will be sent and matches
nearby translations.

Comment on lines 5189 to 5190
msgid "Select {0}s"
msgstr "Seleccionar {0}"
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Plural meaning is dropped in Spanish translation.

Line 5189 uses msgid "Select {0}s" but Line 5190 translates to singular ("Seleccionar {0}"). This loses the plural intent in the UI.

Suggested fix
 msgid "Select {0}s"
-msgstr "Seleccionar {0}"
+msgstr "Seleccionar {0}s"
📝 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
msgid "Select {0}s"
msgstr "Seleccionar {0}"
msgid "Select {0}s"
msgstr "Seleccionar {0}s"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/es.po` around lines 5189 - 5190, The
translation drops pluralization: update the PO entry for msgid "Select {0}s" so
plural intent is preserved — either provide a proper plural Spanish translation
or convert the entry to use gettext plural forms (add msgid_plural "Select {0}s"
and supply msgstr[0]/msgstr[1] with singular and plural Spanish variants).
Locate the existing msgid "Select {0}s" and its msgstr and replace the msgstr
with the correct plural-aware translations (e.g., add msgid_plural and both
msgstr indexes) matching Spanish grammar.

#: src/app/routes/_authenticated/_system/components/cancel-jobs-bulk-action.tsx:41
msgid "{rejected, plural, one {{0}} other {{1}}}"
msgstr ""
msgstr "{rejected, plural, one {لغو {rejected} کار با شکست مواجه شد} other {لغو {rejected} کار با شکست مواجه شد}}"
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Plural failure message should use plural phrasing in the “jobs” branch.

At Line 3584 and Line 4867, the “jobs” failure text still uses singular phrasing (...کار ... شد). For counts > 1, this reads incorrectly in UI notifications. Update the plural branch / plural-specific string to plural wording (e.g., ...کار ... شدند).

Also applies to: 4867-4867

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/fa.po` at line 3584, The pluralization
for the "jobs" failure message currently uses singular phrasing in the plural
branch ("{rejected, plural, one {لغو {rejected} کار با شکست مواجه شد} other {لغو
{rejected} کار با شکست مواجه شد}}"); update the plural-specific form (the
"other" branch) to use the plural verb form (e.g., "...کار ... شدند") so plural
counts read correctly, and apply the same change to the second identical
occurrence of this msgstr elsewhere in the file.

Comment on lines 5184 to 5185
msgid "Select {0}s"
msgstr "Selecteer {0}"
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Plural meaning is lost in translation for this label.

At Line 5184, msgid is plural (Select {0}s) but msgstr is singular (Selecteer {0}), which can render misleading text in multi-item contexts.

Suggested fix
 msgid "Select {0}s"
-msgstr "Selecteer {0}"
+msgstr "Selecteer {0}s"
📝 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
msgid "Select {0}s"
msgstr "Selecteer {0}"
msgid "Select {0}s"
msgstr "Selecteer {0}s"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/nl.po` around lines 5184 - 5185, This
entry currently loses plural semantics: replace the single msgid/msgstr pair for
"Select {0}s" with a proper pluralizable PO entry by adding msgid_plural and
providing msgstr[0] (singular) and msgstr[1] (plural) translations, preserving
the {0} placeholder and using correct Dutch wording (e.g., singular "Selecteer
{0}" and an appropriate plural form) so plural rendering matches the original
msgid's intent.

Comment on lines +97 to 99
#: src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx:100
msgid "Heading 5"
msgstr "Heading 5"
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize rich-text heading labels instead of leaving English copy.

These entries remain in English (Heading 1Heading 6) while nearby UI strings are Romanian, causing inconsistent localization in the editor toolbar.

Suggested update
 msgid "Heading 1"
-msgstr "Heading 1"
+msgstr "Titlu 1"

 msgid "Heading 2"
-msgstr "Heading 2"
+msgstr "Titlu 2"

 msgid "Heading 3"
-msgstr "Heading 3"
+msgstr "Titlu 3"

 msgid "Heading 4"
-msgstr "Heading 4"
+msgstr "Titlu 4"

 msgid "Heading 5"
-msgstr "Heading 5"
+msgstr "Titlu 5"

 msgid "Heading 6"
-msgstr "Heading 6"
+msgstr "Titlu 6"

Also applies to: 1731-1733, 3362-3364, 3593-3595, 4615-4617, 5569-5571

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dashboard/src/i18n/locales/ro.po` around lines 97 - 99, Replace the
English heading labels in the ro.po entries (msgid "Heading 1" ... "Heading 6")
with their Romanian equivalents (e.g., "Titlu 1", "Titlu 2", ..., "Titlu 6") so
the rich-text editor toolbar strings from responsive-toolbar.tsx are localized;
update every occurrence noted (the other msgid repeats) to keep translations
consistent across the file.

@latifniz
Copy link
Copy Markdown
Contributor

I identified this same issue and implemented a fix locally. Happy to share my approach or help review if useful.
but my focus was just on verification of the customer from the admin side, a simple mutation.

@Ryrahul
Copy link
Copy Markdown
Contributor

Ryrahul commented May 23, 2026

I think this might already be covered by the existing admin customer creation flow in resolver/service layer. (password is missing in the dashboard ui)

`CustomerService.create() is documented as:

"This method is intended to be used in admin-created Customer flows."

and it already immediately verifies the customer when a password is provided by calling the existing verification flow internally.

So from my understanding, admins can already create a verified customer account through the existing API/service behavior, previous angular admin ui already had this behaviour so maybe adding password in the dashboard ui may be the appropriate way to go ahead ( i am not a maintainer so , you should probably wait for maintainer take on it ),

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