Skip to content

WEB-977: Redesign client list and general tab views#3643

Open
alberto-art3ch wants to merge 1 commit into
openMF:devfrom
alberto-art3ch:WEB-977/redesign-client-views-list-and-general-tab
Open

WEB-977: Redesign client list and general tab views#3643
alberto-art3ch wants to merge 1 commit into
openMF:devfrom
alberto-art3ch:WEB-977/redesign-client-views-list-and-general-tab

Conversation

@alberto-art3ch

@alberto-art3ch alberto-art3ch commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Description

Redesign views to align with the new design system, client list and general tab

Related issues and discussion

WEB-977

Screenshots

Screen.Recording.2026-06-10.at.2.31.51.PM.mov

Checklist

Please make sure these boxes are checked before submitting your pull request - thanks!

  • If you have multiple commits please combine them into one commit by squashing them.

  • Read and understood the contribution guidelines at web-app/.github/CONTRIBUTING.md.

Summary by CodeRabbit

  • New Features

    • Redesigned client profile header with profile image actions, masked-name support, and reorganized metadata; accounts view adds type tabs and closed-accounts toggle.
    • KPI grid for performance metrics.
  • Bug Fixes

    • Fixed decimal formatting precision.
  • UI Improvements

    • Tab icons, refreshed tab styles, revamped clients list, custom toolbar, row actions, and redesigned pagination.
  • Refactor

    • Client list and accounts driven by simplified component state.
  • Localization

    • Expanded translations across many languages.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "pre_merge_checks"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

This PR redesigns the clients module UI from Material table/card layouts to custom styled components with a design token system. It restructures the client list view with local pagination, updates the client detail header with a new account header component, redesigns the general tab with account type tabs and KPI cards, and adds SVG icons to the tab navigation. Translation catalogs across multiple locales are updated with new UI labels, messages, and tooltips. A small fix is applied to the format-number pipe for decimal formatting.

Changes

Clients Module UI Redesign

Layer / File(s) Summary
Clients list: Material table to custom list
src/app/clients/clients.component.html, src/app/clients/clients.component.scss, src/app/clients/clients.component.ts
Material mat-table/paginator/sort removed; list rendering replaced by manual @for rows, toolbar search, explicit pagination/sorting state, ChangeDetectorRef usage, and helpers for initials, severity, meta-date, and page ranges.
Client detail header: Material card to account header
src/app/clients/clients-view/clients-view.component.html, src/app/clients/clients-view/clients-view.component.ts
mat-card-header replaced with mifosx-account-header; profile image rendering with conditional sources and permission-gated upload/capture/delete buttons; signature view action; reorganized account overview metadata with masking via mifosx-entity-name. Component imports adjusted.
Tab bar redesign: SVG icons and tab tokens
src/app/clients/clients-view/clients-view.component.html, src/app/clients/clients-view/clients-view.component.scss
Tab bar class tabs-redesign added; inline SVG icons added for General, Personal Data, Address, Family Members, Identities, Documents, Notes, and dynamic datatable tabs; Material tab styling restyled using design tokens and active border-bottom indicator.
General tab: Accounts, KPI, Upcoming Charges
src/app/clients/clients-view/general-tab/general-tab.component.html, src/app/clients/clients-view/general-tab/general-tab.component.ts
Performance History converted to KPI grid; Upcoming Charges to conditional mat-table with row actions; accounts unified into sub-tabs (all/loan/savings/fixed/recurring/shares) with showClosedAccounts toggle, card-row rendering via @if/@for/@empty, status styling, and permission-gated actions. New public fields: currentAccountType, showClosedAccounts, accountCounts; new methods: selectAccountType(), toggleShowClosedAccounts(), loanSeverity(), accountSeverity(), loanProgress().
General tab and clients styles: tokenized SCSS
src/app/clients/clients.component.scss, src/app/clients/clients-view/clients-view.component.scss, src/app/clients/clients-view/general-tab/general-tab.component.scss
Introduces CSS design tokens on :host and dark overrides, token-driven styling for KPI cards, account cards/rows/chips/progress, tabs redesign, info banners, data tables, and PDF modal overlay.
Component imports and standalone wiring
src/app/clients/clients-view/clients-view.component.ts, src/app/clients/clients-view/general-tab/general-tab.component.ts
Refined component decorator imports to narrower set of Material directives and shared standalone components; removed unused footer/table directives and StatusLookupPipe from clients view imports.
FormatNumberPipe decimal pattern fix
src/app/pipes/format-number.pipe.ts
Decimal format now uses configured decimals value for both minimum and maximum fraction digits.
Translation catalog updates
src/assets/translations/* (multiple files)
Extensive additions and reordering across locales (en-US, de-DE, fr-FR, es-CL, es-MX, it-IT, pt-PT, cs-CS, ko-KO, lt-LT, lv-LV, ne-NE, sw-SW) adding many new button labels, headings (Accounts), text/help entries (Activated, Council Approval, Page, Rows, Showing, Submitted), “No … Found” messages, and tooltip entries including ACTIVE/INACTIVE/PENDING and product/repayment tooltips.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • openMF/web-app#3021: Also modifies clients-view header metadata and client classification rendering.
  • openMF/web-app#3253: Related translation updates in es-MX.json and other locale catalog work.

Suggested reviewers

  • IOhacker
  • adamsaghy
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (1)
src/assets/translations/ko-KO.json (1)

1-4788: ⚠️ Potential issue | 🟠 Major

Fix Prettier formatting for src/assets/translations/ko-KO.json

npx prettier --check fails because the configured prettier-plugin-multiline-arrays plugin can’t be resolved. Install dependencies and rerun npx prettier --write . to apply formatting.

🤖 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 `@src/assets/translations/ko-KO.json` around lines 1 - 4788, Prettier check
fails due to the missing prettier-plugin-multiline-arrays plugin causing
formatting not to be applied to src/assets/translations/ko-KO.json; fix by
adding the missing plugin to devDependencies and reformatting. Install the
plugin (e.g. npm install --save-dev prettier prettier-plugin-multiline-arrays or
yarn add -D prettier prettier-plugin-multiline-arrays), ensure package.json /
.prettierrc references are unchanged, then run npx prettier --write . (or npx
prettier --write src/assets/translations/ko-KO.json) to apply formatting and
commit the updated file.

Source: Coding guidelines

🟡 Minor comments (29)
src/app/clients/clients.component.scss-193-193 (1)

193-193: ⚠️ Potential issue | 🟡 Minor

Ensure JetBrains Mono is loaded (otherwise you’ll fall back).

src/app/clients/clients.component.scss uses font-family: 'JetBrains Mono', 'Cascadia Code', monospace; at lines 193/465/611, but src/index.html only loads Roboto/Roboto Mono and there’s no @font-face or Google Fonts import for JetBrains Mono in src/main.scss or src/theme/*. Add the JetBrains Mono import or switch these stacks to Roboto Mono to match what’s already loaded.

🤖 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 `@src/app/clients/clients.component.scss` at line 193, The CSS rule using the
exact font-family declaration "font-family: 'JetBrains Mono', 'Cascadia Code',
monospace;" must not reference an unloaded font; either import JetBrains Mono at
your app root (add a Google Fonts `@import` or `@font-face` for JetBrains Mono in
your global stylesheet) so that that declaration can take effect, or change the
declaration to use a loaded font such as "Roboto Mono" to match the fonts
already included. Locate the instances of that exact font-family string in the
component stylesheet and update them accordingly, and ensure the global font
import is added to your main/global stylesheet if you choose to add JetBrains
Mono.
src/assets/translations/cs-CS.json-772-775 (1)

772-775: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Untranslated Czech catalog values were introduced.

Several newly added labels.catalogs values are still English (e.g., Line 772 % Amount, Line 774 % Interest, Line 775 % Loan Amount + Interest, Line 813 Client). Please localize these to Czech to avoid mixed-language UI.

Also applies to: 813-813

🤖 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 `@src/assets/translations/cs-CS.json` around lines 772 - 775, Several catalog
label keys are still in English; update the Czech translations for the
translation keys "% Amount", "% Disbursement Amount", "% Interest", "% Loan
Amount + Interest" (and the "Client" entry referenced) in the cs-CS.json
translations so they are fully localized to Czech — replace the English strings
with their correct Czech equivalents while preserving the exact JSON keys and
string quoting.
src/assets/translations/de-DE.json-844-844 (1)

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

Use domain-correct German for core financial terms.

These translations change meaning in ways that can confuse financial workflows (Escheat, Flat, Principal). Please replace them with finance-appropriate German terms (e.g., “Heimfall”, “Pauschal”, “Kapital/Hauptbetrag”).

Suggested patch
-      "Escheat": "Betrug",
+      "Escheat": "Heimfall",
-      "Flat": "Wohnung",
+      "Flat": "Pauschal",
-      "Principal": "Rektor",
+      "Principal": "Kapital",

Also applies to: 853-853, 924-924

🤖 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 `@src/assets/translations/de-DE.json` at line 844, The German translations use
incorrect domain terms: update the JSON entries for the keys "Escheat", "Flat",
and "Principal" to finance-appropriate German — replace "Escheat": "Betrug" with
"Escheat": "Heimfall", change "Flat" translation to "Pauschal" (or "fest" if
context requires), and change "Principal" translation to "Kapital" or
"Hauptbetrag" as appropriate; ensure you also update the other occurrences of
those same keys elsewhere in this file (the other "Escheat"/"Flat"/"Principal"
entries mentioned in the review) so all instances use the consistent,
domain-correct terms.
src/assets/translations/de-DE.json-4268-4268 (1)

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

Recurring deposit account label is mistranslated.

“Dauerauftragskonten” means standing-order accounts, not recurring deposit accounts. This should use a recurring-deposit term to avoid product confusion.

Suggested patch
-      "No Active Recurring Deposit Accounts Found": "Keine aktiven Dauerauftragskonten gefunden",
+      "No Active Recurring Deposit Accounts Found": "Keine aktiven Konten für wiederkehrende Einlagen gefunden",
🤖 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 `@src/assets/translations/de-DE.json` at line 4268, The German translation for
the key "No Active Recurring Deposit Accounts Found" uses "Dauerauftragskonten"
(standing orders) and must be replaced with a correct recurring-deposit term;
update the value for the "No Active Recurring Deposit Accounts Found" key to a
proper German phrase such as "Keine aktiven wiederkehrenden Spareinlagen
gefunden" (or another approved product-localized term), preserving
punctuation/capitalization and then run the i18n/translation validation to
ensure no formatting tokens were changed.
src/assets/translations/en-US.json-928-928 (1)

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

Fix user-facing copy regressions in new catalog/tooltips entries.

A few newly added strings contain typos/wording errors that will surface directly in the UI.

✏️ Suggested patch
-      "Quarterly": "Quartely",
+      "Quarterly": "Quarterly",

-      "fourth": "four",
+      "fourth": "fourth",

-    "This sections defines an interest penalty": "This sections defines an interest penalty for pre-mature closure.",
+    "This sections defines an interest penalty": "This section defines an interest penalty for pre-mature closure.",

-    "loan product will become inactive and unavailable to clients": "The date that the loan product will become inactive and unavailable to clients. If blank, the load product will never become inactive."
+    "loan product will become inactive and unavailable to clients": "The date that the loan product will become inactive and unavailable to clients. If blank, the loan product will never become inactive."

Also applies to: 1015-1015, 4680-4680, 4713-4713

🤖 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 `@src/assets/translations/en-US.json` at line 928, The translation entry for
the "Quarterly" key has a typo in its value ("Quartely") — update the value to
the correct spelling "Quarterly" in the translations JSON (look for the
"Quarterly" key), and also fix the same misspelling occurrences referenced at
the other locations (the entries around the indices called out: 1015, 4680,
4713) so all user-facing strings show the corrected "Quarterly".
src/assets/translations/es-CL.json-772-772 (1)

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

Percent-based catalog key lost percent meaning in translation.

Line 772 translates "% Disbursement Amount" as "Monto de curso"; it drops the percentage concept from the label and may mislabel calculation modes.

Suggested fix
-      "% Disbursement Amount": "Monto de curso",
+      "% Disbursement Amount": "% Monto de desembolso",
🤖 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 `@src/assets/translations/es-CL.json` at line 772, The translation for the key
"% Disbursement Amount" currently becomes "Monto de curso" and drops the percent
semantics; update the value for the key "% Disbursement Amount" in es-CL.json so
it preserves the percent meaning (for example use a phrase like "Porcentaje del
monto desembolsado" or "Monto de desembolso (%)") ensuring the key "%
Disbursement Amount" remains unchanged and only the translated string is
corrected.
src/assets/translations/es-CL.json-944-944 (1)

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

Incorrect translation for shares label.

Line 944 maps "SHARES" to "COMPARTE", which is a verb and not the financial noun used elsewhere in this file ("Acciones"). This will show incorrect domain terminology in the UI.

Suggested fix
-      "SHARES": "COMPARTE",
+      "SHARES": "ACCIONES",
🤖 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 `@src/assets/translations/es-CL.json` at line 944, The "SHARES" translation
currently set to "COMPARTE" is incorrect (verb); update the translation for the
key "SHARES" to the proper financial noun "Acciones" (match existing
capitalization/locale style used in this file) so the UI uses the correct domain
term; ensure only the value for "SHARES" is changed and keep JSON formatting
intact.
src/assets/translations/es-CL.json-4484-4484 (1)

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

Tooltip sentence is grammatically broken and hard to understand.

Line 4484 has a malformed phrase (...incluso la cuenta de acciones... está inactiva) that reads incomplete and can confuse users.

Suggested fix
-    "Indicates whether the dividends can be processed even share account of this share product is inactive": "Indica si los dividendos se pueden procesar incluso la cuenta de acciones de este producto de acciones está inactiva",
+    "Indicates whether the dividends can be processed even share account of this share product is inactive": "Indica si los dividendos se pueden procesar incluso si la cuenta de acciones de este producto está inactiva",
🤖 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 `@src/assets/translations/es-CL.json` at line 4484, The Spanish tooltip value
for the key "Indicates whether the dividends can be processed even share account
of this share product is inactive" is grammatically broken; update the
translation string for that exact key to a clear, natural Spanish sentence
(e.g., "Indica si los dividendos pueden procesarse incluso cuando la cuenta de
acciones de este producto está inactiva" or similar) so the phrase reads
complete and unambiguous while preserving the original meaning.
src/assets/translations/es-CL.json-4606-4606 (1)

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

Tooltip uses wrong product term (carga vs crédito).

Line 4606 says producto de carga, which changes meaning and conflicts with the rest of the loan domain terminology in this locale.

Suggested fix
-    "loan product will become inactive and unavailable to clients": "La fecha en que el producto de Crédito quedará inactivo y no estará disponibles para los clientes. Si está en blanco, el producto de carga nunca quedará inactivo."
+    "loan product will become inactive and unavailable to clients": "La fecha en que el producto de Crédito quedará inactivo y no estará disponible para los clientes. Si está en blanco, el producto de Crédito nunca quedará inactivo."
🤖 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 `@src/assets/translations/es-CL.json` at line 4606, The Spanish translation for
the key "loan product will become inactive and unavailable to clients"
incorrectly uses "producto de carga" and has number agreement errors; update the
value to use the correct term "producto de crédito" and fix agreement (e.g., "no
estará disponible") so the sentence reads clearly and consistently with loan
domain terminology (replace all occurrences of "carga" in this value with
"crédito" and correct "no estará disponibles" → "no estará disponible").
src/assets/translations/es-MX.json-1436-1436 (1)

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

Translate remaining English strings in es-MX to avoid mixed-language UI.

These keys are still in English (or partially English) in the Spanish locale, which creates inconsistent UX.

Suggested patch
-      "Quick Access": "Quick Access",
+      "Quick Access": "Acceso rápido",
-      "Center banking": "Center banking",
+      "Center banking": "Banca de centros",
-      "Configure offerings": "Configure offerings",
+      "Configure offerings": "Configurar ofertas",
-      "Group lending": "Group lending",
+      "Group lending": "Crédito grupal",
-      "Journals and ledger": "Journals & ledger",
+      "Journals and ledger": "Diarios y libro mayor",
-      "Navigate directly to any platform area": "Navigate directly to any platform area",
+      "Navigate directly to any platform area": "Navega directamente a cualquier área de la plataforma",
-      "Offices and staff": "Offices & staff",
+      "Offices and staff": "Sucursales y personal",
-      "Profiles and accounts": "Profiles & accounts",
+      "Profiles and accounts": "Perfiles y cuentas",
-      "Savings accounts": "Savings accounts",
+      "Savings accounts": "Cuentas de ahorro",
-      "System configuration": "Configuration",
+      "System configuration": "Configuración del sistema",

Also applies to: 3381-3381, 3415-3415, 3646-3646, 3659-3659, 3744-3744, 3777-3777, 3806-3806, 3852-3852, 3907-3907

🤖 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 `@src/assets/translations/es-MX.json` at line 1436, The es-MX locale file
contains English strings (e.g., the "Quick Access" key) that should be
translated into Spanish to avoid mixed-language UI; update each mentioned key in
src/assets/translations/es-MX.json (including "Quick Access" and the other keys
referenced at lines ~3381, 3415, 3646, 3659, 3744, 3777, 3806, 3852, 3907) by
replacing the English values with appropriate Spanish translations (e.g.,
"Acceso rápido" for "Quick Access"), ensuring the JSON string values remain
valid and preserving the original key names.
src/assets/translations/es-MX.json-776-776 (1)

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

Fix missing accent marks in day labels.

Dias should be Días for correct Spanish orthography.

Suggested patch
-      "30 Days": "30 Dias",
+      "30 Days": "30 Días",
-      "365 Days": "365 Dias",
+      "365 Days": "365 Días",

Also applies to: 779-779

🤖 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 `@src/assets/translations/es-MX.json` at line 776, The Spanish translation
value for the key "30 Days" uses "30 Dias" without the accent; update the value
to "30 Días" (replace "Dias" with "Días") and scan the same translations file
for any other day-label values that use "Dias" (e.g., other keys like "7
Days"/"1 Day"/similar entries) and correct them to "Días" so all day labels use
the proper accent.
src/assets/translations/es-MX.json-947-947 (1)

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

Correct mistranslation for SHARES.

"SHARES": "COMPARTE" is semantically incorrect in this domain; use "Acciones".

Suggested patch
-      "SHARES": "COMPARTE",
+      "SHARES": "ACCIONES",
🤖 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 `@src/assets/translations/es-MX.json` at line 947, The translation entry for
the key "SHARES" is incorrect; locate the "SHARES" property in the translations
JSON (the entry reading "SHARES": "COMPARTE") and replace its value with the
correct Spanish term "Acciones" so the key becomes "SHARES": "Acciones". Ensure
the JSON remains valid (quotes and trailing commas) after the edit and run a
quick grep for other "SHARES" occurrences to verify consistency across
translation files.
src/assets/translations/fr-FR.json-842-842 (1)

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

Fix domain-term mistranslations in catalogs

These two values change product meaning in finance flows:

  • Line 842 "Escheat": "Escroquerie" is incorrect (escheat ≠ scam).
  • Line 917 "Penalty": "Peine" should use the financial term for fee/penalty.
Suggested patch
-      "Escheat": "Escroquerie",
+      "Escheat": "Déshérence",
...
-      "Penalty": "Peine",
+      "Penalty": "Pénalité",

Also applies to: 917-917

🤖 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 `@src/assets/translations/fr-FR.json` at line 842, The translations for the
catalog domain terms are incorrect: update the JSON entries for the keys
"Escheat" and "Penalty" in fr-FR.json so they use proper financial
terminology—replace the value for "Escheat" with a French financial term such as
"Déshérence" (or "Droit de déshérence" if more explicit) and replace the value
for "Penalty" with the financial term "Pénalité" (not "Peine"); ensure the keys
remain unchanged and the file remains valid JSON after editing.
src/assets/translations/fr-FR.json-4031-4031 (1)

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

Correct French connector mapping for of

Line 4031 maps "of" to "sur", which is grammatically wrong in most UI phrases and will read unnaturally in composed strings.

Suggested patch
-      "of": "sur",
+      "of": "de",
🤖 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 `@src/assets/translations/fr-FR.json` at line 4031, The translation key "of" in
src/assets/translations/fr-FR.json currently maps to "sur" which is incorrect
for UI connector phrases; update the value for the "of" key to the correct
French connector (e.g., "de" or the appropriate contraction like "d'") so
composed strings read naturally—locate the "of" key in the JSON and replace
"sur" with the chosen connector.
src/assets/translations/fr-FR.json-4342-4342 (1)

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

Fix gender agreement in empty-state message

Line 4342 uses "Aucune donnée trouvé". donnée is feminine, so this should be trouvée.

Suggested patch
-      "No Data Found": "Aucune donnée trouvé",
+      "No Data Found": "Aucune donnée trouvée",
🤖 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 `@src/assets/translations/fr-FR.json` at line 4342, Update the French
translation for the "No Data Found" key in src/assets/translations/fr-FR.json:
change the value from "Aucune donnée trouvé" to the correct feminine agreement
"Aucune donnée trouvée" so the message reads properly for the key "No Data
Found".
src/assets/translations/it-IT.json-942-945 (1)

942-945: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use consistent Italian domain terminology for share labels.

"SHARES": "CONDIVISIONI" conflicts with nearby "Shares": "Azioni" and the rest of the share-account vocabulary, creating inconsistent wording across the UI.

Suggested fix
-      "SHARES": "CONDIVISIONI",
+      "SHARES": "AZIONI",
🤖 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 `@src/assets/translations/it-IT.json` around lines 942 - 945, SHARES is
incorrectly translated as "CONDIVISIONI" which conflicts with the domain term
used by neighboring keys ("SHAREACCOUNT": "Conto Azioni", "SHAREPRODUCT":
"Prodotto Azioni"); update the value for the "SHARES" key to the consistent
Italian term "Azioni" (matching capitalization) so all share-related labels use
the same vocabulary; also scan nearby keys like SHAREACCOUNT, SHAREPRODUCT, and
SSBENEFICIARYTPT to ensure they remain consistent after the change.
src/assets/translations/it-IT.json-4512-4512 (1)

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

PENDING translation is grammatically incomplete.

"IN ATTESA DI" ends with a dangling preposition and reads truncated in status contexts.

Suggested fix
-    "PENDING": "IN ATTESA DI",
+    "PENDING": "IN ATTESA",
🤖 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 `@src/assets/translations/it-IT.json` at line 4512, The translation value for
the "PENDING" key is incomplete ("IN ATTESA DI"); update the "PENDING" entry in
the it-IT translations to a grammatically complete status phrase (for example
replace "IN ATTESA DI" with "IN ATTESA" or another complete option like "IN
ATTESA DI CONFERMA") so the status reads correctly in UI contexts.
src/assets/translations/it-IT.json-771-774 (1)

771-774: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve % semantics in percentage catalog labels.

"% Amount" and "% Interest" currently read like non-percentage fields, which can make option selection ambiguous in financial dropdowns.

Suggested fix
-      "% Amount": "Quantità",
+      "% Amount": "% Importo",
       "% Disbursement Amount": "Importo dell'esborso",
-      "% Interest": "Interesse",
-      "% Loan Amount + Interest": "Importo del prestito + interessi",
+      "% Interest": "% Interesse",
+      "% Loan Amount + Interest": "% Importo del prestito + interessi",
🤖 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 `@src/assets/translations/it-IT.json` around lines 771 - 774, Update the
Italian translations for the percentage catalog keys so the percent semantics
are preserved rather than reading as plain nouns: modify the translations for
the keys "% Amount", "% Disbursement Amount", "% Interest", and "% Loan Amount +
Interest" in src/assets/translations/it-IT.json to include the percent symbol or
an explicit "Percentuale" wording (for example "Percentuale importo" or "%
importo") so dropdown options unambiguously convey percentage values; ensure
each translated value maps to the exact source key names above and keep phrasing
consistent across all four entries.
src/assets/translations/ko-KO.json-4028-4028 (1)

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

Avoid using / as the translation for the generic of token.

"of": "/" can break non-pagination phrases if this shared key is reused outside a numeric context. Prefer a proper connective (e.g., , ) or use a dedicated pagination-specific key instead.

💡 Suggested fix
-      "of": "/",
+      "of": "중",
🤖 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 `@src/assets/translations/ko-KO.json` at line 4028, The translation for the
shared key "of" is currently "/", which is unsafe for non-pagination contexts;
update the "of" entry in the JSON to a proper Korean connective (e.g., "의" or
"중") or replace usages with a dedicated pagination key (e.g., "pagination.of")
and set that pagination-specific key to "/" so generic "of" remains a
natural-language connective; ensure any code that expects a pagination-only
token is updated to use the new "pagination.of" key.
src/assets/translations/lt-LT.json-4523-4523 (1)

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

Replace non-Lithuanian text in Lithuanian locale

This value is in Latvian, not Lithuanian, causing mixed-language UX in lt-LT.

Suggested fix
-    "Refund transactions where interest refund will automatically be calculated": "Atmaksas darījumi, kuros procentu atmaksa tiks aprēķināta automātiski",
+    "Refund transactions where interest refund will automatically be calculated": "Grąžinimo operacijos, kuriose palūkanų grąžinimas bus apskaičiuotas automatiškai",
🤖 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 `@src/assets/translations/lt-LT.json` at line 4523, The value for the JSON key
"Refund transactions where interest refund will automatically be calculated" in
the lt-LT locale is in Latvian; replace the current Latvian string with the
correct Lithuanian translation for that key (ensure the value is valid JSON
string), e.g. update the value to the proper Lithuanian phrase and run a quick
locale build or linter to confirm no syntax errors; verify translation with a
native speaker or translation source before committing.
src/assets/translations/lv-LV.json-902-902 (1)

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

None is mapped to the wrong meaning.

Line 902 maps "None" to "Kapitāls", which changes the option meaning instead of translating “none”. This will show incorrect UI meaning in any enum/dropdown using this key.

Suggested fix
-      "None": "Kapitāls",
+      "None": "Nav",
🤖 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 `@src/assets/translations/lv-LV.json` at line 902, The "None" key in
src/assets/translations/lv-LV.json is incorrectly translated as "Kapitāls";
update the value for the "None" JSON key to the proper Latvian equivalent for
"none" (e.g., "Nav") so enum/dropdown UI shows the correct meaning; locate the
"None" entry in the lv-LV.json file and replace "Kapitāls" with the correct
translation string.
src/assets/translations/lv-LV.json-4522-4522 (1)

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

Wrong language content in Latvian locale.

Line 4522 contains Lithuanian text ("Grąžinimo operacijos...") inside lv-LV.json. This will surface mixed-language UI text.

Suggested fix
-    "Refund transactions where interest refund will automatically be calculated": "Grąžinimo operacijos, kai palūkanų grąžinimas bus skaičiuojamas automatiškai",
+    "Refund transactions where interest refund will automatically be calculated": "Atmaksas darījumi, kuros procentu atmaksa tiks aprēķināta automātiski",
🤖 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 `@src/assets/translations/lv-LV.json` at line 4522, The value for the JSON key
"Refund transactions where interest refund will automatically be calculated" in
lv-LV locale contains Lithuanian text ("Grąžinimo operacijos..."); replace that
value with the correct Latvian translation for the same key (ensure the string
preserves punctuation and encoding) so the lv-LV.json entry matches Latvian UI
copy and run a quick scan of lv-LV.json for any other non-Latvian entries to
correct.
src/assets/translations/lv-LV.json-4604-4604 (1)

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

Typo in tooltip text changes readability.

Line 4604 uses "ielādes produkts" in a loan-product tooltip. This looks like a typo and reads incorrectly in Latvian.

Suggested fix
-    "loan product will become inactive and unavailable to clients": "Datums, kad aizdevuma produkts kļūs neaktīvs un klientiem nebūs pieejams. Ja lauks ir tukšs, ielādes produkts nekad nekļūs neaktīvs."
+    "loan product will become inactive and unavailable to clients": "Datums, kad aizdevuma produkts kļūs neaktīvs un klientiem nebūs pieejams. Ja lauks ir tukšs, aizdevuma produkts nekad nekļūs neaktīvs."
🤖 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 `@src/assets/translations/lv-LV.json` at line 4604, The translated value for
the key "loan product will become inactive and unavailable to clients" contains
a typo: "ielādes produkts" should be corrected to the proper Latvian term
"aizdevuma produkts"; update the translation string so the sentence reads
"Datums, kad aizdevuma produkts kļūs neaktīvs un klientiem nebūs pieejams. Ja
lauks ir tukšs, aizdevuma produkts nekad nekļūs neaktīvs." ensuring the same key
remains unchanged.
src/assets/translations/ne-NE.json-4528-4528 (1)

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

Replace garbled translation in tooltips.Resume Delinquency Classification.

Line 4528 contains corrupted text ("Deminuquicum वर्गीकरण...") instead of a valid Nepali translation, which will surface broken tooltip copy.

🤖 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 `@src/assets/translations/ne-NE.json` at line 4528, The translation value for
the JSON key "Resume Delinquency Classification" in
src/assets/translations/ne-NE.json is corrupted; open the file, locate the
"Resume Delinquency Classification" entry (tooltip key tooltips.Resume
Delinquency Classification) and replace the garbled string ("Deminuquicum ...")
with the correct Nepali tooltip text; ensure the new value is valid JSON
(properly quoted and escaped) and matches the tone/length of other tooltip
entries.
src/assets/translations/ne-NE.json-4604-4604 (1)

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

Fix term mismatch in loan-product tooltip string.

Line 4604 uses "लोड उत्पादन" (load product) where the key is about loan product lifecycle; this appears to be a mistranslation and can mislead users.

🤖 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 `@src/assets/translations/ne-NE.json` at line 4604, The translation for the key
"loan product will become inactive and unavailable to clients" contains the
incorrect term "लोड उत्पादन" (load product); update the Nepali value to use the
correct term "ऋण उत्पादन" so the string reads with "ऋण उत्पादन निष्क्रिय र
ग्राहकहरु को लागी अनुपलब्ध हुने मिति..." preserving the rest of the sentence and
punctuation exactly as in the existing value.
src/assets/translations/ne-NE.json-707-707 (1)

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

Correct duplicated wording in labels.buttons.Run and Download Report.

Line 707 translates to a duplicated “download” phrase ("रन र डाउनलोड रिपोर्ट डाउनलोड गर्नुहोस्"), producing awkward UI text.

🤖 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 `@src/assets/translations/ne-NE.json` at line 707, The translation for the key
labels.buttons.Run and Download Report contains a duplicated "डाउनलोड" ("रन र
डाउनलोड रिपोर्ट डाउनलोड गर्नुहोस्"); update the value to a single, natural
Nepali phrase (for example remove the extra "डाउनलोड" so it reads like "रन र
डाउनलोड रिपोर्ट गर्नुहोस्" or "रिपोर्ट रन गरी डाउनलोड गर्नुहोस्") by editing the
JSON value for "Run and Download Report" to remove the duplicated word and
ensure the phrase is grammatically correct.
src/assets/translations/ne-NE.json-901-901 (1)

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

Fix incorrect Nepali value for labels.catalogs.None.

Line 901 maps "None" to "राजधानी" (“capital”), which changes the meaning and will show a wrong option label in UI filters/forms.

🤖 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 `@src/assets/translations/ne-NE.json` at line 901, labels.catalogs.None is
incorrectly translated as "राजधानी"; update the value for the key "None" in
src/assets/translations/ne-NE.json (labels.catalogs.None) to the correct Nepali
equivalent for "None" (e.g., "कुनै छैन" or "कुनै") so the UI filter/form shows
the intended option; ensure the JSON string is properly quoted and preserved in
the same file structure.
src/assets/translations/pt-PT.json-860-860 (1)

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

Correct mistranslations that change business meaning.

Several new catalog values map to unrelated terms (IdEu ia, PrincipalDiretor, lastdurar, on dayUm dia), which can mislead users in core loan/account flows.

Suggested fix
-      "Id": "Eu ia",
+      "Id": "ID",
-      "Principal": "Diretor",
+      "Principal": "Principal",
-      "last": "durar",
+      "last": "último",
-      "on day": "Um dia",
+      "on day": "no dia",

Also applies to: 922-922, 1016-1016, 1026-1026

🤖 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 `@src/assets/translations/pt-PT.json` at line 860, Replace the incorrect
Portuguese values that change business meaning for the JSON keys: update the
value for "Id" (currently "Eu ia") to a correct business-term translation such
as "Id" or "Identificador"; change "Principal" (currently "Diretor") back to the
financial term "Principal" or "Montante principal"; correct "last" (currently
"durar") to "último"; and change "on day" (currently "Um dia") to "no dia";
ensure you only modify the values for the existing keys ("Id", "Principal",
"last", "on day") across the file so keys remain unchanged and semantics are
restored.
src/assets/translations/pt-PT.json-771-774 (1)

771-774: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep % in percentage-based option labels.

These labels removed the percentage marker, making financial options ambiguous in dropdowns and summaries.

Suggested fix
-      "% Amount": "Quantia",
-      "% Disbursement Amount": "Valor do Desembolso",
-      "% Interest": "Interesse",
-      "% Loan Amount + Interest": "Valor do empréstimo + juros",
+      "% Amount": "% Quantia",
+      "% Disbursement Amount": "% Valor do desembolso",
+      "% Interest": "% Juros",
+      "% Loan Amount + Interest": "% Valor do empréstimo + juros",
🤖 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 `@src/assets/translations/pt-PT.json` around lines 771 - 774, The translations
for the percentage-based labels ("% Amount", "% Disbursement Amount", "%
Interest", "% Loan Amount + Interest") removed the leading percent sign, causing
ambiguity; update the values in src/assets/translations/pt-PT.json so each
corresponding value includes the "%" prefix (e.g., "% Quantia", "% Valor do
Desembolso", "% Interesse", "% Valor do empréstimo + juros") so UI dropdowns and
summaries retain the percent marker.
🧹 Nitpick comments (9)
src/app/clients/clients.component.ts (1)

85-98: 🏗️ Heavy lift

Introduce typed interfaces for client row and API responses.

Multiple helper methods (severity, legalFormLabel, metaDate, metaDateLabel) use any for the row parameter, and dataSource is typed as MatTableDataSource<any>. Based on learnings, introduce a ClientRow interface covering { status: { code: string, value: string }, legalForm?: { id: number }, activationDate?, submittedOnDate?, timeline?: { closedOnDate? }, ... } and a ClientSearchResponse interface for the API shape, then update method signatures and the data source accordingly.

Also applies to: 101-104, 107-109, 112-117, 141-141

🤖 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 `@src/app/clients/clients.component.ts` around lines 85 - 98, Create a typed
ClientRow interface (including fields used by the component: status { code:
string; value?: string }, legalForm?: { id?: number }, activationDate?: string,
submittedOnDate?: string, timeline?: { closedOnDate?: string }, etc.) and a
ClientSearchResponse for the API result, then replace all any usages: change the
severity(row: any) signature to severity(row: ClientRow) and update
legalFormLabel, metaDate, metaDateLabel to accept ClientRow; also change the
component's dataSource from MatTableDataSource<any> to
MatTableDataSource<ClientRow> and update any API handling code to cast/validate
to ClientSearchResponse before assigning rows to dataSource.

Source: Learnings

src/app/clients/clients-view/clients-view.component.scss (2)

91-147: 💤 Low value

::ng-deep is deprecated but required for Material component styling.

Line 91 uses the deprecated ::ng-deep pseudo-element to style Angular Material's MDC-based tab navigation. While stylelint flags this, it remains a necessary workaround for deep component styling when view encapsulation prevents direct selector targeting. The alternative is moving these rules to a global stylesheet, but that reduces component encapsulation. The current approach is acceptable for Material theming overrides.

🤖 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 `@src/app/clients/clients-view/clients-view.component.scss` around lines 91 -
147, The CSS uses the deprecated ::ng-deep selector to override MDC tab styles
(selector block starting with :host ::ng-deep .tabs-redesign.mat-mdc-tab-nav-bar
and related rules for .mat-mdc-tab-link, .mdc-tab-indicator__content,
.tab-icon); keep using ::ng-deep here but silence the linter by adding a
stylelint disable/enable comment around this rule block (e.g., disable the
specific rule that flags ::ng-deep) so the Material theming override remains
intact while suppressing the stylelint warning.

Source: Linters/SAST tools


9-38: ⚖️ Poor tradeoff

Design tokens duplicated across components.

The --ch-* custom properties are identical to those in src/app/clients/clients.component.scss. Consider extracting these to a shared SCSS file or defining them at the :root level in src/main.scss to avoid duplication and maintain consistency.

🤖 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 `@src/app/clients/clients-view/clients-view.component.scss` around lines 9 -
38, The --ch-* design tokens (e.g. --ch-blue-700, --ch-surface, --ch-text-1) are
duplicated in the :host and :host-context(.dark-theme) blocks; extract them into
a single shared SCSS token file or define them at :root (and a .dark-theme
override) in your global stylesheet, then remove these duplicated declarations
from clients-view.component.scss and have the component import or rely on the
global tokens; ensure the dark-theme overrides still use the same variable names
so :host, :host-context(.dark-theme), and components like clients.component.scss
reference the centralized tokens.
src/app/clients/clients.component.scss (1)

9-53: Centralize --ch-* design tokens instead of redeclaring per component
src/main.scss and src/theme/mifosx-theme.scss don’t define any shared --ch-*/$ch-* tokens, so this :host/:host-context(.dark-theme) block can’t reuse centralized values from those files. The palette is redeclared locally in src/app/clients/clients.component.scss and is duplicated in other component styles (e.g., src/app/clients/clients-view/clients-view.component.scss), so extract these tokens into a shared SCSS partial/global variable set and import/use it to prevent drift.

🤖 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 `@src/app/clients/clients.component.scss` around lines 9 - 53, The color/design
tokens (--ch-*) are being redeclared inside the component :host and
:host-context(.dark-theme) blocks causing duplication; extract all --ch-*
variables (e.g., --ch-blue-700, --ch-surface, --ch-text-1, --ch-paid, etc.) into
a shared SCSS partial (a global variables file), replace the local declarations
in the clients component (:host and :host-context(.dark-theme)) with imports of
that partial, and update other components that currently redeclare the same
tokens (e.g., any clients-view styles) to import and use the centralized tokens
instead of redefining them.

Source: Coding guidelines

src/app/clients/clients-view/general-tab/general-tab.component.ts (2)

258-261: 💤 Low value

Consider extracting the accountCounts type into an interface.

The inline object type for accountCounts works but could be more maintainable as a named interface, especially if this structure is referenced elsewhere or grows.

♻️ Optional refactor
+interface AccountCounts {
+  loan: number;
+  savings: number;
+  fixed: number;
+  recurring: number;
+  shares: number;
+  total: number;
+}
+
  /** Unified accounts view state */
  currentAccountType: 'all' | 'loan' | 'savings' | 'fixed' | 'recurring' | 'shares' = 'all';
  showClosedAccounts = false;
- accountCounts = { loan: 0, savings: 0, fixed: 0, recurring: 0, shares: 0, total: 0 };
+ accountCounts: AccountCounts = { loan: 0, savings: 0, fixed: 0, recurring: 0, shares: 0, total: 0 };
🤖 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 `@src/app/clients/clients-view/general-tab/general-tab.component.ts` around
lines 258 - 261, Extract the inline shape used for accountCounts into a named
interface (e.g., AccountCounts) and use that interface for the accountCounts
property type; update the declaration on general-tab.component.ts by adding an
interface like interface AccountCounts { loan: number; savings: number; fixed:
number; recurring: number; shares: number; total: number } and change
accountCounts' type to AccountCounts to improve maintainability and reuse (refer
to the accountCounts symbol and currentAccountType for locating the surrounding
state).

297-339: Closed status code sets match AccountsFilterPipe
CLOSED_LOAN_CODES, CLOSED_SAVING_CODES, and CLOSED_SHARE_CODES in src/app/clients/clients-view/general-tab/general-tab.component.ts use the same status code strings as the status === 'closed' branches in src/app/pipes/accounts-filter.pipe.ts, so counts should align with the rendered lists; consider centralizing these constants to reduce future duplication drift.

🤖 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 `@src/app/clients/clients-view/general-tab/general-tab.component.ts` around
lines 297 - 339, Summary: duplicate closed-status code sets (CLOSED_LOAN_CODES,
CLOSED_SAVING_CODES, CLOSED_SHARE_CODES) in computeAccountCounts duplicate the
logic in AccountsFilterPipe leading to drift; centralize them. Fix: extract the
closed status code sets into a single exported constant (e.g.,
CLOSED_ACCOUNT_STATUS_CODES or separate CLOSED_LOAN_CODES/.. in a new shared
module/file) and import that constant into both general-tab.component.ts (used
by computeAccountCounts) and accounts-filter.pipe.ts (used by its status ===
'closed' branch); update computeAccountCounts to remove its local sets and
reference the imported constants so both components use the same source of
truth.
src/app/clients/clients-view/general-tab/general-tab.component.scss (3)

207-254: 💤 Low value

Consider alternatives to ::ng-deep for Material table styling.

The ::ng-deep pseudo-element is deprecated in Angular and flagged by Stylelint. While :host ::ng-deep remains the transitional pattern for deep styling, Angular recommends alternatives:

  1. Disable view encapsulation: encapsulation: ViewEncapsulation.None (affects global scope)
  2. Use global styles in styles.scss for shared table styling
  3. Use Material's theming APIs for component customization

The MDC class targeting (.mat-mdc-header-row, .mat-mdc-cell, etc.) correctly follows the learning to prefer MDC DOM classes in Angular Material v20+.

🤖 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 `@src/app/clients/clients-view/general-tab/general-tab.component.scss` around
lines 207 - 254, The component uses the deprecated selector ":host ::ng-deep
.data-table" to style Material MDC table classes (e.g., .mat-mdc-header-row,
.mat-mdc-header-cell, .mat-mdc-cell); remove the ::ng-deep usage and either (A)
move these selectors wholesale into the global styles file (styles.scss) so they
apply app-wide, or (B) keep them in this component by setting encapsulation:
ViewEncapsulation.None on the component and removing :host ::ng-deep, ensuring
the same selectors (.data-table .mat-mdc-header-row, .mat-mdc-header-cell,
.mat-mdc-cell, etc.) are used; choose one approach and update the component
decorator or global stylesheet accordingly.

Source: Linters/SAST tools


74-193: ⚡ Quick win

Align spacing values to the 8px grid system.

The coding guidelines require sticking to the 8px grid system for visual design and spacing. Several values deviate from this standard:

  • Line 75: padding: 20px 24px (20px should be 16px or 24px)
  • Line 80: margin-top: 24px ✓ (compliant)
  • Line 87: margin-bottom: 12px, gap: 12px (12px should be 8px or 16px)
  • Line 127: padding: 14px 18px (14px → 16px, 18px → 16px or 24px)
♻️ Proposed alignment to 8px grid
 .tab-container {
-  padding: 20px 24px;
+  padding: 16px 24px;
   background: var(--ch-surface-alt);
 }

 .section-head {
   display: flex;
   align-items: baseline;
   justify-content: space-between;
-  margin-bottom: 12px;
-  gap: 12px;
+  margin-bottom: 16px;
+  gap: 16px;
 }

 .kpi-card {
   flex: 1 1 0;
   min-width: 180px;
   background: var(--ch-surface);
   border: 1px solid var(--ch-border);
   border-radius: 6px;
-  padding: 14px 18px;
+  padding: 16px 16px;
   display: flex;
   flex-direction: column;
   gap: 6px;

Review all spacing/padding/margin values throughout the file for 8px grid compliance.

🤖 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 `@src/app/clients/clients-view/general-tab/general-tab.component.scss` around
lines 74 - 193, Update SCSS spacing to the 8px grid: change .tab-container
padding from 20px 24px to 16px 24px; change .section-head margin-bottom and gap
from 12px to 16px; change .section-link gap from 4px to 8px; change .kpi-grid
gap from 12px to 16px; change .kpi-card padding from 14px 18px to 16px 16px;
change .kpi-card & .savings before widths remain but ensure any internal gaps
follow 8px multiples; change .info-banner padding from 18px 22px to 16px 24px
and .info-banner gap from 12px to 16px; change .info-banner-text gap from 10px
to 8px. Locate these in the selectors named .tab-container, .section-head,
.section-link, .kpi-grid, .kpi-card, .info-banner, and .info-banner-text and
apply the new 8px-multiple values consistently.

Source: Coding guidelines


9-72: Design tokens in general-tab.component.scss: align with existing theming tokens / avoid duplication
src/main.scss’s color theming is driven by Material CSS variables (e.g., var(--md-sys-color-*)), while general-tab.component.scss introduces its own --ch-*/--pr-* custom properties on :host/:host-context. If --ch-*/--pr-* are meant to be the canonical design-token layer, centralize their definitions (shared SCSS/mixin/theme file) or document the mapping to --md-sys-color-* to prevent drift across components.

🤖 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 `@src/app/clients/clients-view/general-tab/general-tab.component.scss` around
lines 9 - 72, general-tab.component.scss currently defines local design tokens
(--ch-*/--pr-*) on :host and :host-context which duplicates theming from
src/main.scss; remove these local definitions and instead import or reference
the centralized theme tokens (create/extend the shared SCSS or theme mixin that
exposes the canonical --ch-*/--pr-* or maps them to var(--md-sys-color-*) ),
update general-tab.component.scss to use the imported/shared tokens (keep only
component-specific overrides if needed) and add a short comment documenting the
mapping between --ch-*/--pr-* and var(--md-sys-color-*) so other components
won’t drift.

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3f79a3b0-5333-4b26-aab8-d748289ed4dc

📥 Commits

Reviewing files that changed from the base of the PR and between 070b861 and f58b320.

📒 Files selected for processing (23)
  • src/app/clients/clients-view/clients-view.component.html
  • src/app/clients/clients-view/clients-view.component.scss
  • src/app/clients/clients-view/clients-view.component.ts
  • src/app/clients/clients-view/general-tab/general-tab.component.html
  • src/app/clients/clients-view/general-tab/general-tab.component.scss
  • src/app/clients/clients-view/general-tab/general-tab.component.ts
  • src/app/clients/clients.component.html
  • src/app/clients/clients.component.scss
  • src/app/clients/clients.component.ts
  • src/app/pipes/format-number.pipe.ts
  • src/assets/translations/cs-CS.json
  • src/assets/translations/de-DE.json
  • src/assets/translations/en-US.json
  • src/assets/translations/es-CL.json
  • src/assets/translations/es-MX.json
  • src/assets/translations/fr-FR.json
  • src/assets/translations/it-IT.json
  • src/assets/translations/ko-KO.json
  • src/assets/translations/lt-LT.json
  • src/assets/translations/lv-LV.json
  • src/assets/translations/ne-NE.json
  • src/assets/translations/pt-PT.json
  • src/assets/translations/sw-SW.json

Comment thread src/app/clients/clients-view/general-tab/general-tab.component.html Outdated
Comment on lines +349 to +385
/**
* Resolves a UI-level severity for a loan account.
* Returns one of: 'active' | 'arrears' | 'pending' | 'closed' | 'overpaid'
*/
loanSeverity(loan: any): string {
if (loan.inArrears) return 'arrears';
if (loan.status?.overpaid) return 'overpaid';
if (loan.status?.pendingApproval) return 'pending';
if (loan.status?.active) return 'active';
if (loan.status?.closed) return 'closed';
return 'pending';
}

/**
* Generic status resolver for non-loan accounts.
*/
accountSeverity(account: any): string {
if (account.status?.submittedAndPendingApproval) return 'pending';
if (account.status?.active) return 'active';
if (account.status?.closed) return 'closed';
return 'pending';
}

/** Repayment progress as a 0–100 percentage for a loan account. */
loanProgress(loan: any): number {
const paid = Number(loan.amountPaid ?? 0);
if (loan.productType === 'loan') {
const original = Number(loan.originalLoan ?? 0);
if (original <= 0) return 0;
return Math.min(Math.max((paid / original) * 100, 0), 100);
} else if (loan.productType === 'working-capital') {
const original = Number(loan.loanBalance ?? 0) + paid;
if (original <= 0) return 0;
return Math.min(Math.max((paid / original) * 100, 0), 100);
}
return 0;
}

Copy link
Copy Markdown

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

Replace any parameter types with proper interfaces.

The loanSeverity, accountSeverity, and loanProgress methods accept any parameters, which bypasses TypeScript's type safety. Based on learnings, avoid using any for API response shapes and introduce specific interfaces instead.

🔒 Proposed fix: introduce loan and account interfaces

Define minimal interfaces for the expected shapes:

+interface LoanAccount {
+  id: string;
+  productType?: string;
+  inArrears?: boolean;
+  status?: {
+    overpaid?: boolean;
+    pendingApproval?: boolean;
+    active?: boolean;
+    closed?: boolean;
+  };
+  amountPaid?: number;
+  originalLoan?: number;
+  loanBalance?: number;
+}
+
+interface GenericAccount {
+  status?: {
+    submittedAndPendingApproval?: boolean;
+    active?: boolean;
+    closed?: boolean;
+  };
+}
+
  /**
   * Resolves a UI-level severity for a loan account.
   * Returns one of: 'active' | 'arrears' | 'pending' | 'closed' | 'overpaid'
   */
- loanSeverity(loan: any): string {
+ loanSeverity(loan: LoanAccount): string {
    if (loan.inArrears) return 'arrears';
    if (loan.status?.overpaid) return 'overpaid';
    if (loan.status?.pendingApproval) return 'pending';
    if (loan.status?.active) return 'active';
    if (loan.status?.closed) return 'closed';
    return 'pending';
  }

  /**
   * Generic status resolver for non-loan accounts.
   */
- accountSeverity(account: any): string {
+ accountSeverity(account: GenericAccount): string {
    if (account.status?.submittedAndPendingApproval) return 'pending';
    if (account.status?.active) return 'active';
    if (account.status?.closed) return 'closed';
    return 'pending';
  }

  /** Repayment progress as a 0–100 percentage for a loan account. */
- loanProgress(loan: any): number {
+ loanProgress(loan: LoanAccount): number {
    const paid = Number(loan.amountPaid ?? 0);
    if (loan.productType === 'loan') {
      const original = Number(loan.originalLoan ?? 0);
      if (original <= 0) return 0;
      return Math.min(Math.max((paid / original) * 100, 0), 100);
    } else if (loan.productType === 'working-capital') {
      const original = Number(loan.loanBalance ?? 0) + paid;
      if (original <= 0) return 0;
      return Math.min(Math.max((paid / original) * 100, 0), 100);
    }
    return 0;
  }
🤖 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 `@src/app/clients/clients-view/general-tab/general-tab.component.ts` around
lines 349 - 385, Methods loanSeverity, accountSeverity and loanProgress use
loose any types which bypass TypeScript checks; define and use minimal
interfaces (e.g., LoanSummary and AccountSummary) that capture the required
fields (for LoanSummary: inArrears, productType, amountPaid, originalLoan,
loanBalance, status with boolean properties
overpaid/pendingApproval/active/closed; for AccountSummary: status with
submittedAndPendingApproval/active/closed booleans) and replace the any
parameter types with these interfaces in loanSeverity(loan: LoanSummary),
accountSeverity(account: AccountSummary) and loanProgress(loan: LoanSummary);
update any related imports/types in the file to use these new interfaces and
ensure nullable fields use optional properties (?), preserving current runtime
checks.

Source: Learnings

Comment thread src/app/clients/clients.component.html Outdated
Comment on lines +74 to +82
/** Two-letter uppercase initials from a display name. */
initials(name: string): string {
if (!name) return '?';
const display = this.hideClientData ? name : name;
const parts = display.trim().split(/\s+/).filter(Boolean);
if (parts.length === 0) return '?';
if (parts.length === 1) return parts[0].substring(0, 2).toUpperCase();
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}

Copy link
Copy Markdown

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

Redundant ternary defeats compliance masking.

Line 77 has this.hideClientData ? name : name — both branches return the same unmasked name, so compliance masking is never applied to avatar initials. This likely should use maskName(name) in the true branch to match the intent elsewhere.

🛡️ Proposed fix
 initials(name: string): string {
   if (!name) return '?';
-  const display = this.hideClientData ? name : name;
+  const display = this.hideClientData ? this.maskName(name) : name;
   const parts = display.trim().split(/\s+/).filter(Boolean);
📝 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
/** Two-letter uppercase initials from a display name. */
initials(name: string): string {
if (!name) return '?';
const display = this.hideClientData ? name : name;
const parts = display.trim().split(/\s+/).filter(Boolean);
if (parts.length === 0) return '?';
if (parts.length === 1) return parts[0].substring(0, 2).toUpperCase();
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}
/** Two-letter uppercase initials from a display name. */
initials(name: string): string {
if (!name) return '?';
const display = this.hideClientData ? this.maskName(name) : name;
const parts = display.trim().split(/\s+/).filter(Boolean);
if (parts.length === 0) return '?';
if (parts.length === 1) return parts[0].substring(0, 2).toUpperCase();
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}
🤖 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 `@src/app/clients/clients.component.ts` around lines 74 - 82, The
initials(name: string) function currently ignores masking because it uses the
redundant expression this.hideClientData ? name : name; change the true branch
to apply the masking function used elsewhere (e.g., maskName(name)) so that when
this.hideClientData is true the display variable receives the masked value; keep
the rest of initials logic the same and reference the initials method and the
hideClientData and maskName symbols when making the change.

Comment on lines +199 to +201
toggleShowClosed() {
this.showClosedAccounts = !this.showClosedAccounts;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if showClosedAccounts or status filtering is implemented elsewhere
rg -nP --type=ts -C3 'showClosed|closedAccounts|status.*filter' -g '!node_modules' -g 'clients.service.ts'

Repository: openMF/web-app

Length of output: 40


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find all usages of showClosedAccounts in the TS codebase
rg -n --type=ts "showClosedAccounts" .

# 2) Locate the definition and call sites of searchByText()
rg -n --type=ts "searchByText" src/app

# 3) Inspect clients.service.ts for the request/params used for the clients search endpoint
# (print only the most relevant portions)
FILE="$(fd -t f -e ts "clients.service.ts" src/app || true)"
if [ -z "${FILE}" ]; then
  FILE="$(fd -t f -e ts "client*.service.ts" src/app | head -n 1 || true)"
fi
echo "Using service file: ${FILE}"
if [ -n "${FILE}" ]; then
  # show around likely HTTP/query building code
  rg -n --type=ts "clients?/search|/v2/clients|searchByText|HttpClient|params|query" "${FILE}" -n -S -C3 || true
  # also show type of method that wraps the search
  rg -n --type=ts "searchByText\\s*\\(|search\\s*By\\s*Text\\s*\\(" "${FILE}" -n -S -C5 || true
  # finally, dump the full searchByText method block if small enough
  METHOD_LINE="$(rg -n --type=ts "searchByText\\s*\\(" "${FILE}" | head -n 1 | cut -d: -f1 || true)"
  if [ -n "${METHOD_LINE}" ]; then
    start=$((METHOD_LINE-20)); end=$((METHOD_LINE+120))
    sed -n "${start},${end}p" "${FILE}"
  fi
fi

# 4) Check for any other filter/status params passed from the component
rg -n --type=ts "closed|status" src/app/clients

Repository: openMF/web-app

Length of output: 22447


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant TS logic around showClosedAccounts + toggle + getClients/dataSource update
sed -n '130,320p' src/app/clients/clients.component.ts | cat -n

# Find where showClosedAccounts appears in the clients component template(s)
rg -n --hidden --glob '!**/node_modules/**' "showClosedAccounts" src/app/clients

# Dump the relevant portion of the main component HTML if present
HTML_FILES=$(fd -t f "clients.component.html" src/app/clients || true)
if [ -n "${HTML_FILES}" ]; then
  for f in ${HTML_FILES}; do
    echo "---- $f ----"
    sed -n '1,260p' "$f" | cat -n
  done
fi

# Also check if any client-side filtering is done based on "closed" near dataSource usage
rg -n --type=ts "dataSource\\.|filterData|searchByText\\(|getClients\\(|showClosed|closedAccounts|clientStatusType\\.closed" src/app/clients/clients.component.ts -n -S

Repository: openMF/web-app

Length of output: 16445


Fix “Show Closed Accounts” toggle in clients list

  • toggleShowClosed() flips showClosedAccounts, but getClients() never uses it—searchByText() is called with only filterText, pagination, and sort params (src/app/clients/clients.component.ts).
  • ClientsService.searchByText() builds the /v2/clients/search request with only request.text, page, size, and optional sorts, so the returned data.content is assigned directly to dataSource.data without any closed/status filtering (src/app/clients/clients.service.ts).
🤖 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 `@src/app/clients/clients.component.ts` around lines 199 - 201, The
toggleShowClosed() flips showClosedAccounts but neither getClients() nor
ClientsService.searchByText() uses it, so closed accounts are never filtered;
update the flow so the toggle affects results by either (preferred) extending
ClientsService.searchByText(request) to accept a showClosed flag (or include it
on the request object) and send it to the backend so the /v2/clients/search call
filters server-side, or (alternative) have getClients() call searchByText(...)
as today and then apply a client-side filter on the returned data.content before
assigning dataSource.data; modify the functions referenced (toggleShowClosed,
getClients, ClientsService.searchByText and the handling of data.content /
dataSource.data) accordingly so showClosedAccounts controls which clients are
displayed.

Comment thread src/assets/translations/cs-CS.json
Comment thread src/assets/translations/lt-LT.json
Comment thread src/assets/translations/lt-LT.json
Comment thread src/assets/translations/sw-SW.json
@alberto-art3ch alberto-art3ch force-pushed the WEB-977/redesign-client-views-list-and-general-tab branch from f58b320 to b5bae13 Compare June 10, 2026 20:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (3)
src/assets/translations/sw-SW.json (1)

773-774: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix incorrect Swahili glossary terms for finance/status/action keys.

Several entries still use semantically wrong terms (e.g., Interest as “Hamu”, PENDING as “INAKARIBISHWA”, Waive as “Kataa”), which can mislead users during financial operations. Please normalize these to domain-accurate wording.

Suggested patch
-      "% Interest": "Hamu",
+      "% Interest": "Riba",
...
-      "Due interest": "Nia inayostahili",
+      "Due interest": "Riba inayodaiwa",
...
-      "Interest": "Hamu",
+      "Interest": "Riba",
...
-      "Interest posting": "Nia ya kuchapisha",
+      "Interest posting": "Uchapishaji wa riba",
...
-      "None": "Mtaji",
+      "None": "Hakuna",
...
-    "PENDING": "INAKARIBISHWA",
+    "PENDING": "INASUBIRI",
...
-    "Waive": "Kataa",
+    "Waive": "Kusamehe",
...
-    "loan product will become inactive and unavailable to clients": "Tarehe ambayo bidhaa ya mkopo itaacha kutumika na haitapatikana kwa wateja. Ikiwa tupu, bidhaa ya kupakia haitafanya kazi kamwe."
+    "loan product will become inactive and unavailable to clients": "Tarehe ambayo bidhaa ya mkopo itaacha kutumika na haitapatikana kwa wateja. Ikiwa tupu, bidhaa ya mkopo haitazimwa kiotomatiki."

Also applies to: 833-834, 870-874, 902-902, 4508-4508, 4595-4595, 4601-4601

🤖 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 `@src/assets/translations/sw-SW.json` around lines 773 - 774, Replace
semantically incorrect Swahili finance/status/action values with domain-accurate
terms: change "% Interest" value from "Hamu" to "Riba" (and ensure "% Loan
Amount + Interest" stays as "Kiasi cha Mkopo + Riba"), change status "PENDING"
to a waiting-state term like "INASUBIRI", and change action "Waive" from "Kataa"
to a proper waiver term such as "Kuachilia" or "Kutoa msamaha"; update these
keys ("% Interest", "% Loan Amount + Interest", "PENDING", "Waive") throughout
the file (including the other occurrences noted) to use the corrected
translations consistently.
src/app/clients/clients.component.ts (2)

200-202: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Wire showClosedAccounts to the client search request.

toggleShowClosed() flips the boolean, but getClients() (line 254) never passes showClosedAccounts to searchByText(), so the toggle has no effect on displayed results.

🛡️ Proposed fix

Extend ClientsService.searchByText() to accept a showClosed parameter and include it in the /v2/clients/search request. Then update the call on line 254:

-      .searchByText(this.filterText, this.currentPage, this.pageSize, this.sortAttribute, this.sortDirection)
+      .searchByText(this.filterText, this.currentPage, this.pageSize, this.sortAttribute, this.sortDirection, this.showClosedAccounts)
🤖 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 `@src/app/clients/clients.component.ts` around lines 200 - 202, The
toggleShowClosed flips the component boolean but getClients never forwards
showClosedAccounts to the backend; update ClientsService.searchByText to accept
a showClosed (boolean) argument and include it in the /v2/clients/search request
payload/query params, update any typings/signature for searchByText accordingly,
and then modify the call from the component's getClients to pass
this.showClosedAccounts (and update any unit tests or call sites) so the toggle
actually affects search results.

76-83: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Apply compliance masking before extracting initials.

initials() does not respect hideClientData—it always exposes the raw name. When environment.complianceHideClientData is true, this leaks PII via avatar initials.

🛡️ Proposed fix
 initials(name: string): string {
   if (!name) return '?';
-  const parts = name.trim().split(/\s+/).filter(Boolean);
+  const display = this.hideClientData ? this.maskName(name) : name;
+  const parts = display.trim().split(/\s+/).filter(Boolean);
   if (parts.length === 0) return '?';
   if (parts.length === 1) return parts[0].substring(0, 2).toUpperCase();
   return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
🤖 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 `@src/app/clients/clients.component.ts` around lines 76 - 83, The
initials(name: string) method in clients.component.ts currently returns raw
initials and ignores the compliance masking flag; update initials() to first
apply the same compliance masking used elsewhere when
environment.complianceHideClientData (or the component's hideClientData flag) is
true, and then compute initials from the masked/obfuscated name (falling back to
'?' if masking yields empty). Ensure you reference the existing initials()
function and the environment.complianceHideClientData / hideClientData boolean
used in the component so the avatar initials never reveal raw PII.
🧹 Nitpick comments (2)
src/app/clients/clients.component.ts (2)

107-110: 💤 Low value

Consider normalizing metaDate() return type.

Returning Date | string | null requires callers to handle both Date and string values. If the backend API returns different types for different date fields, consider normalizing them to a single type (e.g., always Date or always string) for consistency.

🤖 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 `@src/app/clients/clients.component.ts` around lines 107 - 110, metaDate
currently returns Date | string | null causing callers to handle mixed types;
update metaDate(row: any) to normalize all date sources (row.activationDate,
row.submittedOnDate, row.timeline?.closedOnDate) to a single type (pick Date or
ISO string) before returning and keep null for missing values; e.g., parse any
string values into Date objects (or format Date objects to ISO strings) and
return that consistent type so callers of metaDate no longer need to branch on
Date vs string.

68-74: maskName() is used, but masking logic is duplicated

  • src/app/clients/clients.component.html calls maskName(row.displayName) when hideClientData is true, so src/app/clients/clients.component.ts’s maskName() is not dead code.
  • There’s also a separate maskName() in src/app/clients/clients-view/clients-view.component.ts (used by clients-view.component.html), and the logic differs—consider extracting a shared helper to keep masking behavior consistent.
🤖 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 `@src/app/clients/clients.component.ts` around lines 68 - 74, Both components
implement their own maskName logic (maskName in ClientsComponent and maskName in
ClientsViewComponent) causing duplication and inconsistent behavior; create a
single exported helper function (e.g., maskName) in a shared utility module and
replace the component-local maskName implementations with imports of that helper
in both ClientsComponent and ClientsViewComponent, update clients.component.html
and clients-view.component.html usages to continue calling
maskName(row.displayName) unchanged, and remove the duplicated methods so
masking logic is centralized and consistent across the app.
🤖 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 `@src/app/clients/clients.component.ts`:
- Around line 85-99: The severity method uses an untyped parameter (row: any);
define a proper Client interface (e.g., interface Client { status?: { code?:
string } } or a more specific ClientRow) and replace the any with that type in
the severity signature (severity(row: Client): Severity). Add the new interface
in this file or import it from the shared models/types module, update any other
usages of severity/call sites if needed to match the new type, and ensure
TypeScript strict checks pass.
- Around line 264-267: The error callback currently only resets this.isLoading
and calls this.cdr.markForCheck(), so add explicit error handling in that
subscribe error handler: log the error (e.g., console.error or your component
logger) and show a user-facing notification (e.g., call your
toast/snackbar/notification method) so users know the search failed; ensure you
still set this.isLoading = false and call this.cdr.markForCheck() in that error
branch. Target the subscribe/error callback in
src/app/clients/clients.component.ts (the block that currently only executes ()
=> { this.isLoading = false; this.cdr.markForCheck(); }) and augment it to
accept the error parameter, log it, and invoke the app's notification API.

In `@src/assets/translations/en-US.json`:
- Line 4154: The JSON English copy contains grammar/typo mistakes: update the
translation key/value for "“Maker-Checker” principle requires every tasks" to
use correct grammar ("every task") and fix the other flagged strings (the
entries at the other mentioned keys that currently read "This sections..." and
"load product") to correct English ("This section" or "These sections" as
appropriate, and "load product(s)" or "load products" depending on intent).
Locate the exact keys shown in the diff (e.g., the key starting with
“Maker-Checker” and the entries at the other two reported keys) and replace the
faulty phrases with the grammatically correct alternatives so the end-user copy
is accurate.
- Line 928: Fix the user-facing typos in the translations: update the value for
the "Quarterly" key from "Quartely" to "Quarterly", and also correct the other
misspelled value shown as "four" (update it to the intended "four"
spelling/context if it's incorrect or to the proper label if it's a numeric word
key); locate the entries by the JSON keys "Quarterly" and the nearby translation
entry referenced in the review and replace the erroneous strings with the
correct spellings so the UI displays the proper labels.

In `@src/assets/translations/es-MX.json`:
- Line 1436: Several newly added es-MX entries have English values (e.g., "Quick
Access", "Center banking", "Configure offerings", "Group lending", "Journals &
ledger", "System configuration"); update the es-MX JSON so the values are proper
Spanish translations while keeping the keys unchanged—find these keys in
src/assets/translations/es-MX.json (and the other occurrences noted) and replace
their string values with correct Spanish equivalents (preserve
punctuation/capitalization and use accents where appropriate), then run the
locale/JSON linter or tests to ensure no syntax/issues remain.

---

Duplicate comments:
In `@src/app/clients/clients.component.ts`:
- Around line 200-202: The toggleShowClosed flips the component boolean but
getClients never forwards showClosedAccounts to the backend; update
ClientsService.searchByText to accept a showClosed (boolean) argument and
include it in the /v2/clients/search request payload/query params, update any
typings/signature for searchByText accordingly, and then modify the call from
the component's getClients to pass this.showClosedAccounts (and update any unit
tests or call sites) so the toggle actually affects search results.
- Around line 76-83: The initials(name: string) method in clients.component.ts
currently returns raw initials and ignores the compliance masking flag; update
initials() to first apply the same compliance masking used elsewhere when
environment.complianceHideClientData (or the component's hideClientData flag) is
true, and then compute initials from the masked/obfuscated name (falling back to
'?' if masking yields empty). Ensure you reference the existing initials()
function and the environment.complianceHideClientData / hideClientData boolean
used in the component so the avatar initials never reveal raw PII.

In `@src/assets/translations/sw-SW.json`:
- Around line 773-774: Replace semantically incorrect Swahili
finance/status/action values with domain-accurate terms: change "% Interest"
value from "Hamu" to "Riba" (and ensure "% Loan Amount + Interest" stays as
"Kiasi cha Mkopo + Riba"), change status "PENDING" to a waiting-state term like
"INASUBIRI", and change action "Waive" from "Kataa" to a proper waiver term such
as "Kuachilia" or "Kutoa msamaha"; update these keys ("% Interest", "% Loan
Amount + Interest", "PENDING", "Waive") throughout the file (including the other
occurrences noted) to use the corrected translations consistently.

---

Nitpick comments:
In `@src/app/clients/clients.component.ts`:
- Around line 107-110: metaDate currently returns Date | string | null causing
callers to handle mixed types; update metaDate(row: any) to normalize all date
sources (row.activationDate, row.submittedOnDate, row.timeline?.closedOnDate) to
a single type (pick Date or ISO string) before returning and keep null for
missing values; e.g., parse any string values into Date objects (or format Date
objects to ISO strings) and return that consistent type so callers of metaDate
no longer need to branch on Date vs string.
- Around line 68-74: Both components implement their own maskName logic
(maskName in ClientsComponent and maskName in ClientsViewComponent) causing
duplication and inconsistent behavior; create a single exported helper function
(e.g., maskName) in a shared utility module and replace the component-local
maskName implementations with imports of that helper in both ClientsComponent
and ClientsViewComponent, update clients.component.html and
clients-view.component.html usages to continue calling maskName(row.displayName)
unchanged, and remove the duplicated methods so masking logic is centralized and
consistent across the app.
🪄 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: f793b7b8-5ed1-4a2c-9671-9e181692481b

📥 Commits

Reviewing files that changed from the base of the PR and between f58b320 and b5bae13.

📒 Files selected for processing (23)
  • src/app/clients/clients-view/clients-view.component.html
  • src/app/clients/clients-view/clients-view.component.scss
  • src/app/clients/clients-view/clients-view.component.ts
  • src/app/clients/clients-view/general-tab/general-tab.component.html
  • src/app/clients/clients-view/general-tab/general-tab.component.scss
  • src/app/clients/clients-view/general-tab/general-tab.component.ts
  • src/app/clients/clients.component.html
  • src/app/clients/clients.component.scss
  • src/app/clients/clients.component.ts
  • src/app/pipes/format-number.pipe.ts
  • src/assets/translations/cs-CS.json
  • src/assets/translations/de-DE.json
  • src/assets/translations/en-US.json
  • src/assets/translations/es-CL.json
  • src/assets/translations/es-MX.json
  • src/assets/translations/fr-FR.json
  • src/assets/translations/it-IT.json
  • src/assets/translations/ko-KO.json
  • src/assets/translations/lt-LT.json
  • src/assets/translations/lv-LV.json
  • src/assets/translations/ne-NE.json
  • src/assets/translations/pt-PT.json
  • src/assets/translations/sw-SW.json
🚧 Files skipped from review as they are similar to previous changes (19)
  • src/app/pipes/format-number.pipe.ts
  • src/app/clients/clients.component.scss
  • src/app/clients/clients-view/clients-view.component.ts
  • src/app/clients/clients-view/clients-view.component.scss
  • src/app/clients/clients-view/general-tab/general-tab.component.ts
  • src/app/clients/clients.component.html
  • src/app/clients/clients-view/clients-view.component.html
  • src/app/clients/clients-view/general-tab/general-tab.component.scss
  • src/app/clients/clients-view/general-tab/general-tab.component.html
  • src/assets/translations/ko-KO.json
  • src/assets/translations/ne-NE.json
  • src/assets/translations/es-CL.json
  • src/assets/translations/pt-PT.json
  • src/assets/translations/lt-LT.json
  • src/assets/translations/cs-CS.json
  • src/assets/translations/de-DE.json
  • src/assets/translations/lv-LV.json
  • src/assets/translations/it-IT.json
  • src/assets/translations/fr-FR.json

Comment on lines +85 to +99
/** UI severity class for a row from its status.code. */
severity(row: any): Severity {
const code: string = row?.status?.code ?? '';
if (code === 'clientStatusType.active' || code === 'clientStatusType.approved') return 'active';
if (
code === 'clientStatusType.pending' ||
code === 'clientStatusType.submitted.and.pending.approval' ||
code.includes('transfer')
) {
return 'pending';
}
if (code === 'clientStatusType.closed' || code === 'clientStatusType.withdraw') return 'closed';
if (code === 'clientStatusType.rejected') return 'rejected';
return 'neutral';
}

Copy link
Copy Markdown

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

Replace any with a typed Client interface.

row: any violates strict typing conventions. Define a client interface with at least { status?: { code?: string } } to type-check row access.

As per coding guidelines, "Use TypeScript for all application code with strict typing conventions." Based on learnings, avoid any for API responses and introduce specific interfaces/types for response shapes.

🤖 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 `@src/app/clients/clients.component.ts` around lines 85 - 99, The severity
method uses an untyped parameter (row: any); define a proper Client interface
(e.g., interface Client { status?: { code?: string } } or a more specific
ClientRow) and replace the any with that type in the severity signature
(severity(row: Client): Severity). Add the new interface in this file or import
it from the shared models/types module, update any other usages of severity/call
sites if needed to match the new type, and ensure TypeScript strict checks pass.

Sources: Coding guidelines, Learnings

Comment on lines +264 to 267
() => {
this.isLoading = false;
this.cdr.markForCheck();
}

Copy link
Copy Markdown

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

Log or notify user on client search errors.

The error callback silently swallows exceptions—no log, no user feedback. When the search request fails, users see the loading spinner disappear but have no indication of the failure.

🛡️ Proposed fix
-        () => {
+        (error) => {
+          console.error('Failed to load clients:', error);
+          // Optionally: show a user-facing error notification
           this.isLoading = false;
           this.cdr.markForCheck();
         }
🤖 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 `@src/app/clients/clients.component.ts` around lines 264 - 267, The error
callback currently only resets this.isLoading and calls this.cdr.markForCheck(),
so add explicit error handling in that subscribe error handler: log the error
(e.g., console.error or your component logger) and show a user-facing
notification (e.g., call your toast/snackbar/notification method) so users know
the search failed; ensure you still set this.isLoading = false and call
this.cdr.markForCheck() in that error branch. Target the subscribe/error
callback in src/app/clients/clients.component.ts (the block that currently only
executes () => { this.isLoading = false; this.cdr.markForCheck(); }) and augment
it to accept the error parameter, log it, and invoke the app's notification API.

"Withdraw Deposit": "Withdraw Deposit",
"Principal, Interest, Penalties, Fees Order": "Principal, Interest, Penalties, Fees Order",
"Progressive": "Progressive",
"Quarterly": "Quartely",

Copy link
Copy Markdown

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

Fix user-facing typos in catalog labels.

These values appear to be accidental misspellings and will surface directly in UI text ("Quartely" and "four").

Suggested patch
-      "Quarterly": "Quartely",
+      "Quarterly": "Quarterly",
...
-      "fourth": "four",
+      "fourth": "fourth",

Also applies to: 1015-1015

🤖 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 `@src/assets/translations/en-US.json` at line 928, Fix the user-facing typos in
the translations: update the value for the "Quarterly" key from "Quartely" to
"Quarterly", and also correct the other misspelled value shown as "four" (update
it to the intended "four" spelling/context if it's incorrect or to the proper
label if it's a numeric word key); locate the entries by the JSON keys
"Quarterly" and the nearby translation entry referenced in the review and
replace the erroneous strings with the correct spellings so the UI displays the
proper labels.

"Savings accounts": "Savings accounts",
"Offices and staff": "Offices & staff",
"System configuration": "Configuration"
"“Maker-Checker” principle requires every tasks": "The “Maker-Checker” principle requires every task to be completed by two people to reduce the chance of errors and misuse. One person initiates the process and the second completes it."

Copy link
Copy Markdown

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

Correct grammar/wording regressions in English copy.

These changed strings contain grammatical errors/typos ("every tasks", "This sections...", "load product"), which will be visible to end users.

Suggested patch
-      "“Maker-Checker” principle requires every tasks": "The “Maker-Checker” principle requires every task to be completed by two people to reduce the chance of errors and misuse. One person initiates the process and the second completes it."
+      "“Maker-Checker” principle requires every tasks": "The “Maker-Checker” principle requires every task to be completed by two people to reduce the chance of errors and misuse. One person initiates the process and the second completes it."
...
-      "This sections defines an interest penalty": "This sections defines an interest penalty for pre-mature closure.",
+      "This sections defines an interest penalty": "This section defines an interest penalty for pre-mature closure.",
...
-      "loan product will become inactive and unavailable to clients": "The date that the loan product will become inactive and unavailable to clients. If blank, the load product will never become inactive."
+      "loan product will become inactive and unavailable to clients": "The date that the loan product will become inactive and unavailable to clients. If blank, the loan product will never become inactive."

Also applies to: 4680-4680, 4713-4713

🤖 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 `@src/assets/translations/en-US.json` at line 4154, The JSON English copy
contains grammar/typo mistakes: update the translation key/value for
"“Maker-Checker” principle requires every tasks" to use correct grammar ("every
task") and fix the other flagged strings (the entries at the other mentioned
keys that currently read "This sections..." and "load product") to correct
English ("This section" or "These sections" as appropriate, and "load
product(s)" or "load products" depending on intent). Locate the exact keys shown
in the diff (e.g., the key starting with “Maker-Checker” and the entries at the
other two reported keys) and replace the faulty phrases with the grammatically
correct alternatives so the end-user copy is accurate.

"Progress Bar": "Barra de progreso",
"Provisioning Entries": "Entradas de aprovisionamiento",
"Question": "Pregunta",
"Quick Access": "Quick Access",

Copy link
Copy Markdown

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

Translate newly added es-MX values to avoid mixed-language UI.

Several newly added es-MX values remain in English, which causes visible locale inconsistency in production UI (for example: Quick Access, Center banking, Configure offerings, Group lending, Journals & ledger, System configuration).

💡 Proposed fix (sample)
-      "Quick Access": "Quick Access",
+      "Quick Access": "Acceso rápido",
...
-      "Center banking": "Center banking",
+      "Center banking": "Banca de centros",
...
-      "Configure offerings": "Configure offerings",
+      "Configure offerings": "Configurar ofertas",
...
-      "Group lending": "Group lending",
+      "Group lending": "Crédito grupal",
...
-      "Journals and ledger": "Journals & ledger",
+      "Journals and ledger": "Diarios y libro mayor",
...
-      "Navigate directly to any platform area": "Navigate directly to any platform area",
+      "Navigate directly to any platform area": "Navega directamente a cualquier área de la plataforma",
...
-      "Offices and staff": "Offices & staff",
+      "Offices and staff": "Oficinas y personal",
...
-      "Profiles and accounts": "Profiles & accounts",
+      "Profiles and accounts": "Perfiles y cuentas",
...
-      "Savings accounts": "Savings accounts",
+      "Savings accounts": "Cuentas de ahorro",
...
-      "System configuration": "Configuration",
+      "System configuration": "Configuración",

Also applies to: 3381-3381, 3415-3415, 3646-3646, 3659-3659, 3744-3744, 3777-3777, 3806-3806, 3852-3852, 3907-3907

🤖 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 `@src/assets/translations/es-MX.json` at line 1436, Several newly added es-MX
entries have English values (e.g., "Quick Access", "Center banking", "Configure
offerings", "Group lending", "Journals & ledger", "System configuration");
update the es-MX JSON so the values are proper Spanish translations while
keeping the keys unchanged—find these keys in src/assets/translations/es-MX.json
(and the other occurrences noted) and replace their string values with correct
Spanish equivalents (preserve punctuation/capitalization and use accents where
appropriate), then run the locale/JSON linter or tests to ensure no
syntax/issues remain.

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.

1 participant