Skip to content

WEB-813: Working Capital loan delinquency actions#3460

Open
alberto-art3ch wants to merge 1 commit intoopenMF:devfrom
alberto-art3ch:WEB-813/working-capital-loan-delinquency-actions
Open

WEB-813: Working Capital loan delinquency actions#3460
alberto-art3ch wants to merge 1 commit intoopenMF:devfrom
alberto-art3ch:WEB-813/working-capital-loan-delinquency-actions

Conversation

@alberto-art3ch
Copy link
Copy Markdown
Collaborator

@alberto-art3ch alberto-art3ch commented Mar 31, 2026

Description

For Working Capital loans we would like to introduce a new delinquency action which allows us to change on the minimum payment amount.

Based on the provided date it target the appropriate minimum payment - or breach ranges and update the minimum payment amount. All consecutive periods to be updated with the new value.

Once it was updated, we need to reevaluate these ranges and update (if applicable) the balances and delinquency status.

Related issues and discussion

WEB-813

Screenshots

  • Pause Action
Screenshot 2026-03-30 at 9 17 56 PM
  • Reschedule Action
Screenshot 2026-03-30 at 11 09 37 PM

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

    • Added a Reschedule dialog and Reschedule action for delinquency items on working-capital loans (set frequency, type, and minimum payment).
  • Bug Fixes

    • Prevented processing of invalid/non-numeric loan IDs when fetching delinquency data/actions.
  • UI Improvements

    • Reworked delinquency tags table to show classification, added date, and lifted date.
    • Clarified repayment frequency field label.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

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(s) in object: '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

Adds date comparison helpers, a new loan delinquency "Reschedule" dialog and its form, adjusts resolver logic for numeric loanId and product-type branching, updates delinquency tags UI and action submission to include reschedule params, and changes loans.service delinquency endpoints/signatures.

Changes

Cohort / File(s) Summary
Date Utilities
src/app/core/utils/dates.ts
Added public comparison helpers isBefore(date1, date2) and isAfter(date1, date2).
Loan Resolvers
src/app/loans/common-resolvers/loan-delinquency-actions.resolver.ts, src/app/loans/common-resolvers/loan-delinquency-data.resolver.ts, src/app/loans/common-resolvers/loan-delinquency-tags.resolver.ts
Added numeric-coercion checks and product-type conditional branching before calling LoansService; some paths may now return no value when conditions fail.
Reschedule Dialog Component
src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts, ... .html, ... .scss
New standalone Angular Material dialog component with reactive form (minimumPayment, frequency, frequencyType) and template; SCSS header/licence added.
Delinquency Tags Tab (UI + Logic)
src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts, ... .html
UI now conditionally renders by product type, table columns changed (classification, addedOn, liftedOn), added Reschedule button for working-capital, tightened action visibility, integrated dialog and reschedule flow, and extended sendDelinquencyAction payload to include reschedule fields.
Loans Service
src/app/loans/loans.service.ts
Changed getDelinquencyTags signature/path to accept only loanId and changed createDelinquencyActions signature to (productType, loanId, delinquencyActions) and corresponding endpoint path.
Loan Terms Step (label)
src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html
Updated validation error label key from labels.inputs.Repaid every to labels.inputs.Period Payment Frequency.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TagsTab as "Delinquency Tags Tab"
    participant Dialog as "Reschedule Dialog"
    participant Service as "Loans Service"
    participant Backend as "Backend API"

    User->>TagsTab: Click Reschedule
    TagsTab->>Dialog: open(RescheduleDialog, {data})
    Dialog->>Dialog: initialize form (minPayment, frequency, type)
    User->>Dialog: Fill form and submit
    Dialog-->>TagsTab: Return {data: form}
    TagsTab->>Service: createDelinquencyActions(productType, loanId, payload with reschedule fields)
    Service->>Backend: POST /{productType}/{loanId}/delinquency-actions
    Backend-->>Service: 200 OK
    Service-->>TagsTab: Observable resolves
    TagsTab->>Service: getDelinquencyActions(...) refresh
    Service->>Backend: GET delinquency actions
    Backend-->>Service: updated data
    Service-->>TagsTab: Updated actions
    TagsTab-->>User: UI refresh
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • adamsaghy
  • IOhacker
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main feature: introducing a new delinquency action for Working Capital loans. It references the Jira ticket (WEB-813) and clearly indicates the primary change scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html (2)

12-15: Consider adding validation error display for minimumPayment.

The minimumPayment field is marked as required in the component (per form builder), but unlike the frequency field (lines 26-31), it lacks a <mat-error> block to display validation feedback to users. For consistency and better UX, consider adding error handling:

♻️ Suggested enhancement
   <mat-form-field class="flex-28">
     <mat-label>{{ 'labels.inputs.Minimum Payment' | translate }}</mat-label>
     <input type="number" matInput formControlName="minimumPayment" />
+    `@if` (delinquencyActionForm.controls.minimumPayment.hasError('required')) {
+      <mat-error>
+        {{ 'labels.inputs.Minimum Payment' | translate }} {{ 'labels.commons.is' | translate }}
+        <strong>{{ 'labels.commons.required' | translate }}</strong>
+      </mat-error>
+    }
   </mat-form-field>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html`
around lines 12 - 15, The template is missing a validation error display for the
minimumPayment form control; add a <mat-error> under the input bound to
formControlName="minimumPayment" that mirrors the frequency field's validation
messaging (e.g., show a "required" message when minimumPayment.errors?.required
and the control is touched or dirty) so users see feedback when
LoanDelinquencyActionRescheduleDialogComponent's form requires this field.

37-41: Use unique identifier for track expression.

The track frequencyType tracks the entire object reference. For optimal change detection, track by a unique identifier:

-      `@for` (frequencyType of frequencyTypeOptions; track frequencyType) {
+      `@for` (frequencyType of frequencyTypeOptions; track frequencyType.id) {

As per coding guidelines: "verify component separation, trackBy on *ngFor, strict type safety".

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

In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html`
around lines 37 - 41, The template is tracking the whole object with "track
frequencyType"; change the *ngFor to use a trackBy function (e.g., "trackBy:
trackByFrequencyType") and implement a strongly-typed method on the component
(e.g., trackByFrequencyType(index: number, frequencyType: FrequencyType): string
| number) that returns the unique id (frequencyType.id); update the component
class where frequencyTypeOptions is defined to ensure FrequencyType typing and
export the trackBy method so Angular can use it for optimal change detection.
src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html (1)

19-24: Simplify mutually exclusive conditionals with @else.

The two @if blocks check opposite conditions for maximumAgeDays. Use @else for cleaner logic:

♻️ Suggested refactor
             `@if` (item.delinquencyRange.maximumAgeDays) {
               <span>( {{ item.delinquencyRange.minimumAgeDays }} - {{ item.delinquencyRange.maximumAgeDays }} )</span>
-            }
-            `@if` (!item.delinquencyRange.maximumAgeDays) {
+            } `@else` {
               <span>( {{ item.delinquencyRange.minimumAgeDays }} )</span>
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html`
around lines 19 - 24, The template currently uses two mutually exclusive
conditionals on item.delinquencyRange.maximumAgeDays; replace the second "@if
(!item.delinquencyRange.maximumAgeDays)" with an "@else" to simplify logic in
loan-delinquency-tags-tab.component.html so the first block checks "@if
(item.delinquencyRange.maximumAgeDays)" and the alternate branch uses "@else" to
render the single-value span, keeping the same bindings
(item.delinquencyRange.minimumAgeDays / maximumAgeDays).
src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts (1)

52-67: Consider adding numeric validators for payment and frequency fields.

The minimumPayment and frequency fields accept numeric input but only validate for required. Consider adding minimum value validators to prevent invalid negative values:

♻️ Suggested enhancement
   createDelinquencyActionForm() {
     this.delinquencyActionForm = this.formBuilder.group({
       minimumPayment: [
         '',
-        Validators.required
+        [Validators.required, Validators.min(0)]
       ],
       frequency: [
         '',
-        Validators.required
+        [Validators.required, Validators.min(1)]
       ],
       frequencyType: [
         '',
         Validators.required
       ]
     });
   }

This ensures users cannot submit negative payment amounts or zero/negative frequency values.

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

In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts`
around lines 52 - 67, The form created in createDelinquencyActionForm currently
only checks for required values; update the delinquencyActionForm definition to
add numeric validators for minimumPayment and frequency (e.g., Validators.min
for a positive minimumPayment like Validators.min(0.01) and Validators.min(1) or
Validators.min(0) as appropriate for frequency) and optionally a numeric pattern
validator to ensure only numbers are accepted; adjust the formBuilder.group for
the minimumPayment and frequency controls to include these validators so
negative or zero values are rejected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/loans/common-resolvers/loan-base.resolver.ts`:
- Around line 22-30: The initialize method currently only ignores null and can
leave this.productType (the BehaviorSubject) unchanged when the query param is
missing or unexpected; update initialize(route: ActivatedRouteSnapshot) to
always reset this.productType by reading route.queryParams['productType'] and
setting this.productType.next(LOAN_PRODUCT_TYPE.LOAN) as the default, then
override with LOAN_PRODUCT_TYPE.WORKING_CAPITAL if the param ===
'working-capital' (or LOAN if param === 'loan'), so any missing/unknown values
reliably revert to LOAN.

In `@src/app/loans/common-resolvers/loan-delinquency-tags.resolver.ts`:
- Around line 35-41: The resolver method resolve currently can return undefined
when loanId is non-numeric; update resolve in loan-delinquency-tags.resolver
(and the sibling resolvers loan-delinquency-data.resolver.ts and
loan-delinquency-actions.resolver.ts) to explicitly return an RxJS EMPTY
observable for the non-numeric branch: keep the existing initialize(route) and
loanId extraction, but replace the implicit undefined path with a return of
EMPTY so resolve always returns an Observable; target the resolve method and the
call to this.loansService.getDelinquencyTags(loanId) when making the change.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`:
- Around line 249-258: The success handler after createDelinquencyActions
currently only re-fetches getDelinquencyActions and updates
loanDelinquencyActions, leaving loanDelinquencyTags and
installmentLevelDelinquency stale; replace the inner getDelinquencyActions call
with a call to reload() (inherited from LoanProductBaseComponent) so the
component fully refreshes state (loanDelinquencyActions, loanDelinquencyTags,
installmentLevelDelinquency) after createDelinquencyActions completes.
- Around line 190-195: Guard against dialog cancellation by checking the value
emitted from loanDelinquencyActionDialogRef.afterClosed() before accessing
response.data.value and only calling sendDelinquencyAction when the dialog
returned a valid payload; specifically, in the subscription to
loanDelinquencyActionDialogRef.afterClosed() validate that response is defined
and has the expected data/value properties and return early on cancel. Also fix
the type contract: either make the Date parameters in sendDelinquencyAction
nullable (e.g., allow Date | null) or ensure you pass real Date values when
calling it for the reschedule flow so the method signature and callers (the
reschedule branch around sendDelinquencyAction) match strict typing; apply the
same checks/fix to the other similar block referenced (lines ~217–246).

---

Nitpick comments:
In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html`:
- Around line 12-15: The template is missing a validation error display for the
minimumPayment form control; add a <mat-error> under the input bound to
formControlName="minimumPayment" that mirrors the frequency field's validation
messaging (e.g., show a "required" message when minimumPayment.errors?.required
and the control is touched or dirty) so users see feedback when
LoanDelinquencyActionRescheduleDialogComponent's form requires this field.
- Around line 37-41: The template is tracking the whole object with "track
frequencyType"; change the *ngFor to use a trackBy function (e.g., "trackBy:
trackByFrequencyType") and implement a strongly-typed method on the component
(e.g., trackByFrequencyType(index: number, frequencyType: FrequencyType): string
| number) that returns the unique id (frequencyType.id); update the component
class where frequencyTypeOptions is defined to ensure FrequencyType typing and
export the trackBy method so Angular can use it for optimal change detection.

In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts`:
- Around line 52-67: The form created in createDelinquencyActionForm currently
only checks for required values; update the delinquencyActionForm definition to
add numeric validators for minimumPayment and frequency (e.g., Validators.min
for a positive minimumPayment like Validators.min(0.01) and Validators.min(1) or
Validators.min(0) as appropriate for frequency) and optionally a numeric pattern
validator to ensure only numbers are accepted; adjust the formBuilder.group for
the minimumPayment and frequency controls to include these validators so
negative or zero values are rejected.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html`:
- Around line 19-24: The template currently uses two mutually exclusive
conditionals on item.delinquencyRange.maximumAgeDays; replace the second "@if
(!item.delinquencyRange.maximumAgeDays)" with an "@else" to simplify logic in
loan-delinquency-tags-tab.component.html so the first block checks "@if
(item.delinquencyRange.maximumAgeDays)" and the alternate branch uses "@else" to
render the single-value span, keeping the same bindings
(item.delinquencyRange.minimumAgeDays / maximumAgeDays).
🪄 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: 92372f55-cf17-4045-822f-a12ac72ecc4c

📥 Commits

Reviewing files that changed from the base of the PR and between 35b428f and 0def1ca.

📒 Files selected for processing (13)
  • src/app/core/utils/dates.ts
  • src/app/loans/common-resolvers/loan-base.resolver.ts
  • src/app/loans/common-resolvers/loan-delinquency-actions.resolver.ts
  • src/app/loans/common-resolvers/loan-delinquency-data.resolver.ts
  • src/app/loans/common-resolvers/loan-delinquency-tags.resolver.ts
  • src/app/loans/common-resolvers/loan-details.resolver.ts
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.scss
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts
  • src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html
  • src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html
  • src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts
  • src/app/loans/loans.service.ts

Comment on lines +22 to +30
protected initialize(route: ActivatedRouteSnapshot): void {
const productType = route.queryParams['productType'];
if (productType !== null) {
if (productType === 'loan') {
this.productType.next(LOAN_PRODUCT_TYPE.LOAN);
} else if (productType === 'working-capital') {
this.productType.next(LOAN_PRODUCT_TYPE.WORKING_CAPITAL);
}
}
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 | 🔴 Critical

Always reset productType during initialization.

Line 24 only filters out null, not the missing-param case, so this resolver keeps the previous BehaviorSubject value when productType is absent or unexpected. After a working-capital navigation, a plain loan route can keep resolving working-capital-loans endpoints until something else resets it. src/app/loans/common-resolvers/loan-details.resolver.ts:35-47 already defaults that case back to LOAN_PRODUCT_TYPE.LOAN, so this new base resolver can diverge from the rest of the page.

💡 Proposed fix
  protected initialize(route: ActivatedRouteSnapshot): void {
-    const productType = route.queryParams['productType'];
-    if (productType !== null) {
-      if (productType === 'loan') {
-        this.productType.next(LOAN_PRODUCT_TYPE.LOAN);
-      } else if (productType === 'working-capital') {
-        this.productType.next(LOAN_PRODUCT_TYPE.WORKING_CAPITAL);
-      }
-    }
+    const productType = route.queryParamMap.get('productType');
+    this.productType.next(
+      productType === LOAN_PRODUCT_TYPE.WORKING_CAPITAL
+        ? LOAN_PRODUCT_TYPE.WORKING_CAPITAL
+        : LOAN_PRODUCT_TYPE.LOAN
+    );
  }
📝 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
protected initialize(route: ActivatedRouteSnapshot): void {
const productType = route.queryParams['productType'];
if (productType !== null) {
if (productType === 'loan') {
this.productType.next(LOAN_PRODUCT_TYPE.LOAN);
} else if (productType === 'working-capital') {
this.productType.next(LOAN_PRODUCT_TYPE.WORKING_CAPITAL);
}
}
protected initialize(route: ActivatedRouteSnapshot): void {
const productType = route.queryParamMap.get('productType');
this.productType.next(
productType === LOAN_PRODUCT_TYPE.WORKING_CAPITAL
? LOAN_PRODUCT_TYPE.WORKING_CAPITAL
: LOAN_PRODUCT_TYPE.LOAN
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/loans/common-resolvers/loan-base.resolver.ts` around lines 22 - 30,
The initialize method currently only ignores null and can leave this.productType
(the BehaviorSubject) unchanged when the query param is missing or unexpected;
update initialize(route: ActivatedRouteSnapshot) to always reset
this.productType by reading route.queryParams['productType'] and setting
this.productType.next(LOAN_PRODUCT_TYPE.LOAN) as the default, then override with
LOAN_PRODUCT_TYPE.WORKING_CAPITAL if the param === 'working-capital' (or LOAN if
param === 'loan'), so any missing/unknown values reliably revert to LOAN.

Comment on lines 35 to 41
resolve(route: ActivatedRouteSnapshot): Observable<any> {
this.initialize(route);
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
return this.loansService.getDelinquencyTags(loanId);
if (!isNaN(+loanId)) {
return this.loansService.getDelinquencyTags(loanId);
}
}
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

Resolver may return undefined for non-numeric loanId.

When loanId fails the numeric check, resolve() implicitly returns undefined. Angular's router resolver contract expects an Observable, Promise, or a resolved value. Returning undefined may cause unpredictable behavior or silent failures in route resolution.

Consider returning EMPTY from RxJS to explicitly handle the non-numeric case:

🛡️ Suggested fix
+import { EMPTY, Observable } from 'rxjs';

 resolve(route: ActivatedRouteSnapshot): Observable<any> {
   this.initialize(route);
   const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
   if (!isNaN(+loanId)) {
     return this.loansService.getDelinquencyTags(loanId);
   }
+  return EMPTY;
 }

This same pattern applies to sibling resolvers (loan-delinquency-data.resolver.ts, loan-delinquency-actions.resolver.ts).

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

In `@src/app/loans/common-resolvers/loan-delinquency-tags.resolver.ts` around
lines 35 - 41, The resolver method resolve currently can return undefined when
loanId is non-numeric; update resolve in loan-delinquency-tags.resolver (and the
sibling resolvers loan-delinquency-data.resolver.ts and
loan-delinquency-actions.resolver.ts) to explicitly return an RxJS EMPTY
observable for the non-numeric branch: keep the existing initialize(route) and
loanId extraction, but replace the implicit undefined path with a return of
EMPTY so resolve always returns an Observable; target the resolve method and the
call to this.loansService.getDelinquencyTags(loanId) when making the change.

Comment on lines +190 to +195
loanDelinquencyActionDialogRef.afterClosed().subscribe((response: { data: any }) => {
const minimumPayment: number = response.data.value.minimumPayment;
const frequency: number = response.data.value.frequency;
const frequencyType: string = response.data.value.frequencyType;

this.sendDelinquencyAction(action, null, null, minimumPayment, frequency, frequencyType);
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
set -euo pipefail

echo "Dates.formatDate implementation:"
rg -n -C3 'formatDate\s*\(' src/app/core/utils/dates.ts

echo
echo "TypeScript nullability settings:"
rg -n --iglob 'tsconfig*.json' '"strict"\s*:|"strictNullChecks"\s*:'

Repository: openMF/web-app

Length of output: 447


🏁 Script executed:

cat src/app/core/utils/dates.ts

Repository: openMF/web-app

Length of output: 2557


🏁 Script executed:

cat tsconfig.json | grep -A 10 '"strict"'

Repository: openMF/web-app

Length of output: 40


🏁 Script executed:

sed -n '180,260p' src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts

Repository: openMF/web-app

Length of output: 2774


Guard against dialog cancellation in the reschedule flow.

When the dialog is cancelled or closed via backdrop, afterClosed() emits undefined, causing immediate crash on accessing response.data.value. Additionally, sendDelinquencyAction() declares non-nullable Date parameters but receives null for the reschedule action, violating the coding guideline for strict typing conventions. While the reschedule payload overwrites the initial payload (avoiding the formatDate(null) call), the type mismatch remains a contract violation.

💡 Proposed fix
    loanDelinquencyActionDialogRef.afterClosed().subscribe((response?: { data?: { value?: any } }) => {
      const formValue = response?.data?.value;
      if (!formValue) {
        return;
      }

      this.sendDelinquencyAction(action, null, null, formValue.minimumPayment, formValue.frequency, formValue.frequencyType);
    });
  }

  sendDelinquencyAction(
    action: string,
-   startDate: Date,
-   endDate: Date,
-   minimumPayment: number,
-   frequency: number,
-   frequencyType: string
+   startDate: Date | null,
+   endDate: Date | null,
+   minimumPayment: number | null,
+   frequency: number | null,
+   frequencyType: string | null
  ): void {

Note: TypeScript strict null checks are not enabled in the main tsconfig.json, so these violations are not caught at compile time. The crash on dialog cancellation is the immediate runtime risk; the type violations should be fixed to align with coding guidelines and prevent future regressions.

Also applies to: 217–246

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

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 190 - 195, Guard against dialog cancellation by checking the value
emitted from loanDelinquencyActionDialogRef.afterClosed() before accessing
response.data.value and only calling sendDelinquencyAction when the dialog
returned a valid payload; specifically, in the subscription to
loanDelinquencyActionDialogRef.afterClosed() validate that response is defined
and has the expected data/value properties and return early on cancel. Also fix
the type contract: either make the Date parameters in sendDelinquencyAction
nullable (e.g., allow Date | null) or ensure you pass real Date values when
calling it for the reschedule flow so the method signature and callers (the
reschedule branch around sendDelinquencyAction) match strict typing; apply the
same checks/fix to the other similar block referenced (lines ~217–246).

Comment on lines +249 to +258
this.loansServices
.createDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId, payload)
.subscribe((result: any) => {
this.loansServices
.getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
.subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
this.loanDelinquencyActions = loanDelinquencyActions;
this.validateDelinquencyActions();
});
});
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

Refresh the delinquency data, not just the actions list.

The new reschedule action can re-evaluate balances and delinquency status, but this success handler only refetches loanDelinquencyActions. That leaves loanDelinquencyTags and installmentLevelDelinquency stale until the user manually reloads the page. Since this component now extends LoanProductBaseComponent, reload() is already available here.

💡 Proposed fix
     this.loansServices
       .createDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId, payload)
-      .subscribe((result: any) => {
-        this.loansServices
-          .getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
-          .subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
-            this.loanDelinquencyActions = loanDelinquencyActions;
-            this.validateDelinquencyActions();
-          });
+      .subscribe(() => {
+        if (action === 'reschedule') {
+          this.reload();
+          return;
+        }
+
+        this.loansServices
+          .getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
+          .subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
+            this.loanDelinquencyActions = loanDelinquencyActions;
+            this.validateDelinquencyActions();
+          });
       });
📝 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
this.loansServices
.createDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId, payload)
.subscribe((result: any) => {
this.loansServices
.getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
.subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
this.loanDelinquencyActions = loanDelinquencyActions;
this.validateDelinquencyActions();
});
});
this.loansServices
.createDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId, payload)
.subscribe(() => {
if (action === 'reschedule') {
this.reload();
return;
}
this.loansServices
.getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
.subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
this.loanDelinquencyActions = loanDelinquencyActions;
this.validateDelinquencyActions();
});
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 249 - 258, The success handler after createDelinquencyActions
currently only re-fetches getDelinquencyActions and updates
loanDelinquencyActions, leaving loanDelinquencyTags and
installmentLevelDelinquency stale; replace the inner getDelinquencyActions call
with a call to reload() (inherited from LoanProductBaseComponent) so the
component fully refreshes state (loanDelinquencyActions, loanDelinquencyTags,
installmentLevelDelinquency) after createDelinquencyActions completes.

@alberto-art3ch alberto-art3ch force-pushed the WEB-813/working-capital-loan-delinquency-actions branch from 0def1ca to b33757e Compare April 2, 2026 13:18
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts (3)

190-195: ⚠️ Potential issue | 🟠 Major

Handle dialog cancellation before reading response.data.value.

afterClosed() can emit no payload. This subscription still dereferences response.data.value, so cancelling the new reschedule dialog via backdrop or Cancel crashes the tab. The same failure mode still exists in the pause flow on Line 174.

Angular Material MatDialogRef afterClosed emitted value when a dialog is closed without passing a result
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 190 - 195, The subscription to
loanDelinquencyActionDialogRef.afterClosed() dereferences response.data.value
without guarding for a null/undefined response when the dialog is cancelled;
update the afterClosed() handlers (both the reschedule flow and the pause flow
that also subscribes around line 174) to first check that response and
response.data (and response.data.value) exist before reading minimumPayment,
frequency, or frequencyType, and bail out (return) if not present so
sendDelinquencyAction is only called with valid data.

217-246: ⚠️ Potential issue | 🟠 Major

Split payload construction by action and make the nullable inputs explicit.

createDelinquencyActionReschedule() passes null dates, but sendDelinquencyAction() still declares non-null Date/number/string parameters and eagerly formats startDate before the reschedule branch overwrites the payload. That makes every reschedule call depend on Dates.formatDate(null, ...) and leaves the method contract inaccurate.

#!/bin/bash
set -euo pipefail

sed -n '182,246p' src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts

echo
sed -n '1,220p' src/app/core/utils/dates.ts | rg -n 'formatDate|parseDate'

echo
rg -n --iglob 'tsconfig*.json' '"strict"\s*:|"strictNullChecks"\s*:'

As per coding guidelines: src/app/**/*.ts: Use TypeScript for all application code with strict typing conventions.

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

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 217 - 246, The sendDelinquencyAction method currently declares
non-nullable parameters and eagerly formats startDate, causing null to be passed
into dateUtils.formatDate for reschedule flows; update sendDelinquencyAction
signature to accept nullable types for startDate, endDate, minimumPayment,
frequency, and frequencyType and stop formatting dates until you know the action
requires them—build separate payload objects per action (e.g., for 'pause'
include formatted startDate and formatted endDate, for 'reschedule' include
minimumPayment, frequency, frequencyType) and only call
this.dateUtils.formatDate when the corresponding date parameter is non-null;
ensure createDelinquencyActionReschedule callers that pass null align with the
new nullable types and adjust any type annotations or usages in
loan-delinquency-tags-tab.component.ts accordingly.

249-258: ⚠️ Potential issue | 🟠 Major

Refresh the full delinquency tab after a reschedule succeeds.

This handler only re-fetches loanDelinquencyActions, but reschedule also changes tags, balances, and delinquency status. The actions table updates while loanDelinquencyTags and installmentLevelDelinquency stay stale until the user manually reloads the page.

💡 Suggested change
     this.loansServices
       .createDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId, payload)
-      .subscribe((result: any) => {
-        this.loansServices
-          .getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
-          .subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
-            this.loanDelinquencyActions = loanDelinquencyActions;
-            this.validateDelinquencyActions();
-          });
+      .subscribe(() => {
+        if (action === 'reschedule') {
+          this.reload();
+          return;
+        }
+
+        this.loansServices
+          .getDelinquencyActions(this.loanProductService.loanAccountPath, this.loanId)
+          .subscribe((loanDelinquencyActions: LoanDelinquencyAction[]) => {
+            this.loanDelinquencyActions = loanDelinquencyActions;
+            this.validateDelinquencyActions();
+          });
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 249 - 258, The current createDelinquencyActions success handler
only re-fetches loanDelinquencyActions, leaving loanDelinquencyTags and
installmentLevelDelinquency stale after a reschedule; inside the subscribe
callback in loan-delinquency-tags-tab.component.ts (the
createDelinquencyActions(...) .subscribe(...) block), after reloading
getDelinquencyActions and calling validateDelinquencyActions(), also invoke the
existing methods that refresh the rest of the delinquency tab state (e.g., call
the component/service methods that fetch loanDelinquencyTags and
installmentLevelDelinquency and any balance/status refresh — e.g.,
getDelinquencyTags(...), getInstallmentLevelDelinquency(...) or a central
refreshDelinquencyTab() if present) so tags, installment-level delinquency and
balances are re-fetched and UI stays consistent after a reschedule.
🧹 Nitpick comments (1)
src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html (1)

77-77: Use an 8px-aligned gap utility instead of gap-5px.

gap-5px is off-grid relative to the rest of the layout helpers. Please switch this container to an 8px-based spacing token/class so the action bar stays aligned with the repo’s spacing system.

As per coding guidelines: src/**/*.{scss,html}: Stick to the 8px grid system for visual design and spacing.

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

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html`
at line 77, Replace the off-grid class on the action bar div (the element with
class "layout-row m-t-20 m-b-10 align-end align-items-center gap-5px") by
swapping out "gap-5px" for the 8px-aligned spacing utility your project uses
(e.g., "gap-8px" or the project's equivalent "gap-8") so the container uses the
8px grid spacing token and stays aligned with the repo spacing system.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`:
- Around line 144-150: frequencyTypeOptions is populated asynchronously by
getWorkingCapitalLoansAccountTemplate but createDelinquencyActionReschedule can
open the reschedule dialog before that array is filled; update the component so
the dialog is not opened until options are ready—either (preferably) disable the
reschedule button until frequencyTypeOptions is populated (set a boolean like
frequencyOptionsLoaded when assigning response.periodFrequencyTypeOptions and
bind the button disabled state) and add a guard in
createDelinquencyActionReschedule to return/await if frequencyTypeOptions is
empty, or alternatively make createDelinquencyActionReschedule fetch
getWorkingCapitalLoansAccountTemplate on demand and open the dialog only after
the observable resolves; apply the same fix to the other similar block
referenced (createDelinquencyActionReschedule usage around the 182-188 area).
- Around line 158-163: The working-capital branch of allowPause uses
currentLoanDelinquencyAction.endDate unconditionally; change the logic in the
block that checks loanProductService.isWorkingCapital to first verify the
currentLoanDelinquencyAction.action === 'PAUSE' and that endDate is present
before calling dateUtils.parseDate/dateUtils.isAfter; if not a PAUSE action or
endDate is missing, set allowPause = false. Update any similar logic around the
reschedule payload handling (references: currentLoanDelinquencyAction,
allowPause, loanProductService.isWorkingCapital, dateUtils.parseDate,
dateUtils.isAfter) so pause availability is only derived from PAUSE actions with
a valid endDate.

---

Duplicate comments:
In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`:
- Around line 190-195: The subscription to
loanDelinquencyActionDialogRef.afterClosed() dereferences response.data.value
without guarding for a null/undefined response when the dialog is cancelled;
update the afterClosed() handlers (both the reschedule flow and the pause flow
that also subscribes around line 174) to first check that response and
response.data (and response.data.value) exist before reading minimumPayment,
frequency, or frequencyType, and bail out (return) if not present so
sendDelinquencyAction is only called with valid data.
- Around line 217-246: The sendDelinquencyAction method currently declares
non-nullable parameters and eagerly formats startDate, causing null to be passed
into dateUtils.formatDate for reschedule flows; update sendDelinquencyAction
signature to accept nullable types for startDate, endDate, minimumPayment,
frequency, and frequencyType and stop formatting dates until you know the action
requires them—build separate payload objects per action (e.g., for 'pause'
include formatted startDate and formatted endDate, for 'reschedule' include
minimumPayment, frequency, frequencyType) and only call
this.dateUtils.formatDate when the corresponding date parameter is non-null;
ensure createDelinquencyActionReschedule callers that pass null align with the
new nullable types and adjust any type annotations or usages in
loan-delinquency-tags-tab.component.ts accordingly.
- Around line 249-258: The current createDelinquencyActions success handler only
re-fetches loanDelinquencyActions, leaving loanDelinquencyTags and
installmentLevelDelinquency stale after a reschedule; inside the subscribe
callback in loan-delinquency-tags-tab.component.ts (the
createDelinquencyActions(...) .subscribe(...) block), after reloading
getDelinquencyActions and calling validateDelinquencyActions(), also invoke the
existing methods that refresh the rest of the delinquency tab state (e.g., call
the component/service methods that fetch loanDelinquencyTags and
installmentLevelDelinquency and any balance/status refresh — e.g.,
getDelinquencyTags(...), getInstallmentLevelDelinquency(...) or a central
refreshDelinquencyTab() if present) so tags, installment-level delinquency and
balances are re-fetched and UI stays consistent after a reschedule.

---

Nitpick comments:
In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html`:
- Line 77: Replace the off-grid class on the action bar div (the element with
class "layout-row m-t-20 m-b-10 align-end align-items-center gap-5px") by
swapping out "gap-5px" for the 8px-aligned spacing utility your project uses
(e.g., "gap-8px" or the project's equivalent "gap-8") so the container uses the
8px grid spacing token and stays aligned with the repo spacing system.
🪄 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: bcd7c9f9-4193-4db1-9e62-f9f1e90430f8

📥 Commits

Reviewing files that changed from the base of the PR and between 0def1ca and b33757e.

📒 Files selected for processing (10)
  • src/app/core/utils/dates.ts
  • src/app/loans/common-resolvers/loan-delinquency-actions.resolver.ts
  • src/app/loans/common-resolvers/loan-delinquency-data.resolver.ts
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.scss
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts
  • src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html
  • src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html
  • src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts
  • src/app/loans/loans.service.ts
✅ Files skipped from review due to trivial changes (3)
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.scss
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html
  • src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/core/utils/dates.ts
  • src/app/loans/loans.service.ts
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts

Comment on lines +144 to +150
if (this.loanProductService.isWorkingCapital) {
const clientId: number = this.route.parent.parent.snapshot.params['clientId'];
this.loansServices
.getWorkingCapitalLoansAccountTemplate(clientId, this.loanProductId)
.subscribe((response: any) => {
this.frequencyTypeOptions = response.periodFrequencyTypeOptions;
});
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

Don’t open the reschedule dialog until frequencyTypeOptions are ready.

frequencyTypeOptions are loaded asynchronously in ngOnInit(), but createDelinquencyActionReschedule() opens the dialog with whatever array exists at that moment. If the user clicks early, the dialog gets an empty list and never sees the later response because Line 149 replaces the array reference. Either fetch the template before opening the dialog or disable the button until the options are loaded.

Also applies to: 182-188

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

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 144 - 150, frequencyTypeOptions is populated asynchronously by
getWorkingCapitalLoansAccountTemplate but createDelinquencyActionReschedule can
open the reschedule dialog before that array is filled; update the component so
the dialog is not opened until options are ready—either (preferably) disable the
reschedule button until frequencyTypeOptions is populated (set a boolean like
frequencyOptionsLoaded when assigning response.periodFrequencyTypeOptions and
bind the button disabled state) and add a guard in
createDelinquencyActionReschedule to return/await if frequencyTypeOptions is
empty, or alternatively make createDelinquencyActionReschedule fetch
getWorkingCapitalLoansAccountTemplate on demand and open the dialog only after
the observable resolves; apply the same fix to the other similar block
referenced (createDelinquencyActionReschedule usage around the 182-188 area).

Comment on lines +158 to +163
if (this.loanProductService.isLoanProduct) {
this.allowPause = this.currentLoanDelinquencyAction.action === 'RESUME';
} else if (this.loanProductService.isWorkingCapital) {
const delinquencyActionEndDate = this.dateUtils.parseDate(this.currentLoanDelinquencyAction.endDate);
this.allowPause = this.dateUtils.isAfter(businessDate, delinquencyActionEndDate);
}
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

Guard the working-capital pause logic for non-PAUSE actions.

The new reschedule payload on Lines 239-246 sends no dates. After that action becomes the current action, Line 161 parses currentLoanDelinquencyAction.endDate unconditionally, which can leave allowPause wrong or break the pause-state calculation if endDate is absent. Only derive pause availability from PAUSE actions that actually have an end date.

Also applies to: 239-246

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

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 158 - 163, The working-capital branch of allowPause uses
currentLoanDelinquencyAction.endDate unconditionally; change the logic in the
block that checks loanProductService.isWorkingCapital to first verify the
currentLoanDelinquencyAction.action === 'PAUSE' and that endDate is present
before calling dateUtils.parseDate/dateUtils.isAfter; if not a PAUSE action or
endDate is missing, set allowPause = false. Update any similar logic around the
reschedule payload handling (references: currentLoanDelinquencyAction,
allowPause, loanProductService.isWorkingCapital, dateUtils.parseDate,
dateUtils.isAfter) so pause availability is only derived from PAUSE actions with
a valid endDate.

@alberto-art3ch alberto-art3ch force-pushed the WEB-813/working-capital-loan-delinquency-actions branch from b33757e to 8b70279 Compare April 7, 2026 13:36
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts (1)

174-179: ⚠️ Potential issue | 🟠 Major

Guard against dialog cancellation in the pause flow.

The afterClosed() subscription accesses response.data.value without checking if the user cancelled the dialog. When cancelled, response may be undefined, causing a runtime error.

🛡️ Proposed fix
 loanDelinquencyActionDialogRef.afterClosed().subscribe((response: { data: any }) => {
+  if (!response?.data?.value) {
+    return;
+  }
   const startDate: Date = response.data.value.startDate;
   const endDate: Date = response.data.value.endDate;

   this.sendDelinquencyAction(action, startDate, endDate, null, null, null);
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`
around lines 174 - 179, The afterClosed() callback for
loanDelinquencyActionDialogRef accesses response.data.value without guarding for
cancellation; update the subscription in loan-delinquency-tags-tab.component
(the loanDelinquencyActionDialogRef.afterClosed().subscribe handler) to first
check that response and response.data (or response.data.value) are defined
(e.g., if (!response || !response.data || !response.data.value) return;) or use
optional chaining to extract startDate/endDate only when present, and only then
call this.sendDelinquencyAction(action, startDate, endDate, ...); this prevents
runtime errors when the dialog is cancelled.
🧹 Nitpick comments (2)
src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html (1)

77-77: Use 8px grid-aligned spacing.

The gap-5px class doesn't follow the 8px grid system specified in the coding guidelines. Consider using gap-8px or a spacing variable that aligns with the grid.

As per coding guidelines: "Stick to the 8px grid system for visual design and spacing."

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

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html`
at line 77, The layout row uses a non‑standard spacing class "gap-5px" which
violates the 8px grid guideline; update the div that contains classes
"layout-row m-t-20 m-b-10 align-end align-items-center gap-5px" to use an
8px-aligned spacing token (e.g., replace "gap-5px" with "gap-8px" or the project
spacing variable/class that represents 8px) so the spacing follows the design
system.
src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts (1)

52-66: Consider adding numeric validation for monetary and frequency fields.

The form controls minimumPayment and frequency only have Validators.required. For better input validation, consider adding Validators.min(0) or Validators.min(1) to ensure positive values, especially since minimumPayment handles monetary amounts.

💡 Suggested enhancement
 createDelinquencyActionForm() {
   this.delinquencyActionForm = this.formBuilder.group({
     minimumPayment: [
       '',
-      Validators.required
+      [Validators.required, Validators.min(0)]
     ],
     frequency: [
       '',
-      Validators.required
+      [Validators.required, Validators.min(1)]
     ],
     frequencyType: [
       '',
       Validators.required
     ]
   });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts`
around lines 52 - 66, The form currently built in createDelinquencyActionForm
sets Validators.required only for minimumPayment and frequency; update the
delinquencyActionForm builder to add numeric range validators (e.g.,
Validators.min(0) or Validators.min(1) and optionally
Validators.pattern(/^\d+(\.\d{1,2})?$/) for monetary formatting) to the
minimumPayment control and Validators.min(1) (and/or a digits pattern) to the
frequency control so they reject non-positive or non-numeric input; keep
frequencyType as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts`:
- Around line 174-179: The afterClosed() callback for
loanDelinquencyActionDialogRef accesses response.data.value without guarding for
cancellation; update the subscription in loan-delinquency-tags-tab.component
(the loanDelinquencyActionDialogRef.afterClosed().subscribe handler) to first
check that response and response.data (or response.data.value) are defined
(e.g., if (!response || !response.data || !response.data.value) return;) or use
optional chaining to extract startDate/endDate only when present, and only then
call this.sendDelinquencyAction(action, startDate, endDate, ...); this prevents
runtime errors when the dialog is cancelled.

---

Nitpick comments:
In
`@src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts`:
- Around line 52-66: The form currently built in createDelinquencyActionForm
sets Validators.required only for minimumPayment and frequency; update the
delinquencyActionForm builder to add numeric range validators (e.g.,
Validators.min(0) or Validators.min(1) and optionally
Validators.pattern(/^\d+(\.\d{1,2})?$/) for monetary formatting) to the
minimumPayment control and Validators.min(1) (and/or a digits pattern) to the
frequency control so they reject non-positive or non-numeric input; keep
frequencyType as-is.

In
`@src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html`:
- Line 77: The layout row uses a non‑standard spacing class "gap-5px" which
violates the 8px grid guideline; update the div that contains classes
"layout-row m-t-20 m-b-10 align-end align-items-center gap-5px" to use an
8px-aligned spacing token (e.g., replace "gap-5px" with "gap-8px" or the project
spacing variable/class that represents 8px) so the spacing follows the design
system.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5dc664ef-87ee-4abc-8f54-2bb9c2207821

📥 Commits

Reviewing files that changed from the base of the PR and between b33757e and 8b70279.

📒 Files selected for processing (11)
  • src/app/core/utils/dates.ts
  • src/app/loans/common-resolvers/loan-delinquency-actions.resolver.ts
  • src/app/loans/common-resolvers/loan-delinquency-data.resolver.ts
  • src/app/loans/common-resolvers/loan-delinquency-tags.resolver.ts
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.scss
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.ts
  • src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html
  • src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.html
  • src/app/loans/loans-view/loan-delinquency-tags-tab/loan-delinquency-tags-tab.component.ts
  • src/app/loans/loans.service.ts
✅ Files skipped from review due to trivial changes (4)
  • src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html
  • src/app/loans/common-resolvers/loan-delinquency-data.resolver.ts
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.scss
  • src/app/loans/custom-dialog/loan-delinquency-action-reschedule-dialog/loan-delinquency-action-reschedule-dialog.component.html
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/core/utils/dates.ts
  • src/app/loans/loans.service.ts

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