Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Milestone 7: Dashboard > Home display exact amount #3376

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/app/fyle/dashboard/stat-badge/stat-badge.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="stat-badge--container">
<ion-grid class="stat-badge--grid">
<ion-row>
<ion-col class="stat-badge--count-col" size="4">
<ion-col class="stat-badge--count-col" size="3">
<div *ngIf="!loading && reportState">
<div
*ngIf="!loading"
Expand All @@ -23,7 +23,7 @@
<ion-skeleton-text animated></ion-skeleton-text>
</div>
</ion-col>
<ion-col class="stat-badge--grid-outer-col" size="8">
<ion-col class="stat-badge--grid-outer-col" size="9">
<ion-grid class="stat-badge--grid">
<ion-row>
<ion-col class="stat-badge--grid-col">
Expand All @@ -44,7 +44,12 @@
<span class="stat-badge--currency">
{{ currencySymbol }}
</span>
{{ value | humanizeCurrency: currency:true }}
<ng-container *ngIf="!isSmallScreen && value > -1000000000 && value < 1000000000; else humanize">
{{ { value: value, currencyCode: currency, skipSymbol: true } | exactCurrency }}
</ng-container>
<ng-template #humanize>
{{ value | humanizeCurrency : currency : true }}
</ng-template>
Comment on lines +47 to +52
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

When numbers are big, style becomes small - that's the rule of currency display!

The conditional currency display is like my signature move - powerful but needs precision! A few style points:

  1. The billion-value threshold (-1B to 1B) needs validation:
-  *ngIf="!isSmallScreen && value > -1000000000 && value < 1000000000; else humanize"
+  *ngIf="!isSmallScreen && value > -1e9 && value < 1e9; else humanize"
  1. Consider extracting these magic numbers to constants, like how I never reveal all my power at once!

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +47 to +52
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Style ah? Let's make this template as clean as my sunglasses!

That condition is longer than my punch dialogues! Let's move it to the component, machan!

  1. Move the magic numbers to constants:
+  private readonly MAX_EXACT_CURRENCY_VALUE = 1000000000;
+  private readonly MIN_EXACT_CURRENCY_VALUE = -1000000000;
  1. Add a method to handle the condition:
+  shouldShowExactCurrency(value: number): boolean {
+    return !this.isSmallScreen && 
+           value > this.MIN_EXACT_CURRENCY_VALUE && 
+           value < this.MAX_EXACT_CURRENCY_VALUE;
+  }
  1. Simplify the template:
-  <ng-container *ngIf="!isSmallScreen && value > -1000000000 && value < 1000000000; else humanize">
+  <ng-container *ngIf="shouldShowExactCurrency(value); else humanize">

Mind it! This makes the code more maintainable and readable!

Committable suggestion skipped: line range outside the PR's diff.

</div>
<div *ngIf="loading">
<ion-skeleton-text
Expand Down
9 changes: 3 additions & 6 deletions src/app/fyle/dashboard/stat-badge/stat-badge.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@
--ion-grid-column-padding: 4px;
}

&--count-col {
padding-left: 8px;
padding-right: 8px;
}

&--count {
min-width: 30px;
min-height: 30px;
Expand Down Expand Up @@ -81,10 +76,12 @@

&--amount {
font-weight: 500;
font-size: 12px;
color: $black;
}

&--name {
font-size: 14px;
font-size: 12px;
line-height: 18px;
color: $blue-black;
white-space: nowrap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IonicModule } from '@ionic/angular';
import { getElementBySelector, getTextContent } from 'src/app/core/dom-helpers';
import { FyCurrencyPipe } from 'src/app/shared/pipes/fy-currency.pipe';
import { HumanizeCurrencyPipe } from 'src/app/shared/pipes/humanize-currency.pipe';
import { ExactCurrencyPipe } from 'src/app/shared/pipes/exact-currency.pipe';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Testing is like my stunts - it needs to cover everything!

Mind it! We've added ExactCurrencyPipe but where are the tests for our new currency display logic? Let's add some power-packed test cases:

it('should use exact currency for values within range on large screens', () => {
  component.isSmallScreen = false;
  component.value = 999999999;
  fixture.detectChanges();
  const amountElement = getElementBySelector(fixture, '.stat-badge--amount');
  expect(amountElement.textContent).toContain(exactCurrencyPipe.transform({
    value: component.value,
    currencyCode: 'USD',
    skipSymbol: true
  }));
});

it('should use humanized currency for values outside range', () => {
  component.value = 1000000001;
  fixture.detectChanges();
  const amountElement = getElementBySelector(fixture, '.stat-badge--amount');
  expect(amountElement.textContent).toContain(humanizeCurrencyPipe.transform(
    component.value,
    'USD',
    true
  ));
});

Also applies to: 18-18

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Mind it! Test coverage needs more power!

You've added ExactCurrencyPipe to the declarations, but where are the test cases for it? Like my movies need action scenes, your tests need coverage!

Add test cases to verify the ExactCurrencyPipe behavior:

it('should use ExactCurrencyPipe for appropriate values', () => {
  component.value = 999999999;
  component.isSmallScreen = false;
  fixture.detectChanges();
  const amountElement = getElementBySelector(fixture, '.stat-badge--amount');
  expect(amountElement.textContent).toContain('999,999,999.00');
});

Also applies to: 18-18

import { ReportStates } from './report-states';

import { StatBadgeComponent } from './stat-badge.component';
Expand All @@ -14,7 +15,7 @@ describe('StatBadgeComponent', () => {
beforeEach(waitForAsync(() => {
const fyCurrencyPipeSpy = jasmine.createSpyObj('FyCurrencyPipe', ['transform']);
TestBed.configureTestingModule({
declarations: [StatBadgeComponent, HumanizeCurrencyPipe, FyCurrencyPipe],
declarations: [StatBadgeComponent, HumanizeCurrencyPipe, ExactCurrencyPipe, FyCurrencyPipe],
imports: [IonicModule.forRoot()],
providers: [
{
Expand Down
5 changes: 4 additions & 1 deletion src/app/fyle/dashboard/stat-badge/stat-badge.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ export class StatBadgeComponent {

@Output() badgeClicked = new EventEmitter();

onBadgeClicked() {
// To track if the screen is small (370px or below)
isSmallScreen = window.innerWidth <= 370;
Comment on lines +28 to +29
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Mind-blowing! But let's make this screen detection more powerful, like my punch!

The screen size detection needs to be as dynamic as my action sequences! Currently, it only checks once during initialization.

Add this powerful resize listener, like this:

+ import { Component, Input, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
+ import { Subject } from 'rxjs';
+ import { takeUntil } from 'rxjs/operators';

  export class StatBadgeComponent implements OnInit, OnDestroy {
+   private destroy$: Subject<void> = new Subject();
    isSmallScreen = window.innerWidth <= 370;
+
+   ngOnInit(): void {
+     fromEvent(window, 'resize')
+       .pipe(takeUntil(this.destroy$))
+       .subscribe(() => {
+         this.isSmallScreen = window.innerWidth <= 370;
+       });
+   }
+
+   ngOnDestroy(): void {
+     this.destroy$.next();
+     this.destroy$.complete();
+   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +28 to +29
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Mind blowing! But let's make this magic number a constant, partner!

When I see magic numbers like 370, I say to them - "Don't act smart!" Let's move this to a constant at the top of the file, macha!

+  private readonly SMALL_SCREEN_THRESHOLD = 370;
-  isSmallScreen = window.innerWidth <= 370;
+  isSmallScreen = window.innerWidth <= this.SMALL_SCREEN_THRESHOLD;
📝 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
// To track if the screen is small (370px or below)
isSmallScreen = window.innerWidth <= 370;
private readonly SMALL_SCREEN_THRESHOLD = 370;
// To track if the screen is small (370px or below)
isSmallScreen = window.innerWidth <= this.SMALL_SCREEN_THRESHOLD;


onBadgeClicked(): void {
if (!this.loading) {
this.badgeClicked.emit(this.reportState);
if (this.expenseState) {
Expand Down
8 changes: 3 additions & 5 deletions src/app/fyle/dashboard/stats/stats.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ $ccc-bank-name: #c4cae8;
&--header {
font-size: 14px;
line-height: 18px;
color: $grey-light;
color: $black-light;
font-weight: 500;
}

Expand Down Expand Up @@ -87,14 +87,12 @@ $ccc-bank-name: #c4cae8;
}

&--report-stats-row {
padding-bottom: 18px;
padding-top: 18px;
padding: 24px 0 20px 0;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Style like a boss! But we can make it even more stylish!

The padding consolidation is clean, but why stop there? When two elements share the same style, they can share the same SCSS selector too!

Here's a super-punch refactor, style:

-  &--report-stats-row {
-    padding: 24px 0 20px 0;
-    --ion-grid-column-padding: 0;
-  }
-
-  &--expenses-stats-row {
-    padding: 24px 0 20px 0;
-    --ion-grid-column-padding: 0;
-  }
+  &--report-stats-row,
+  &--expenses-stats-row {
+    padding: 24px 0 20px 0;
+    --ion-grid-column-padding: 0;
+  }

Also applies to: 95-95

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Style simplification that packs a punch!

Mind it! The padding consolidation is like my signature move - simple yet powerful! Both rows now use the same clean shorthand syntax. But let me tell you something interesting - we could make this even more powerful!

Consider extracting this common padding to a shared class or variable, like how I share my style with millions:

.stats {
+  $stats-row-padding: 24px 0 20px 0;
   
   &--report-stats-row {
-    padding: 24px 0 20px 0;
+    padding: $stats-row-padding;
     --ion-grid-column-padding: 0;
   }

   &--expenses-stats-row {
-    padding: 24px 0 20px 0;
+    padding: $stats-row-padding;
     --ion-grid-column-padding: 0;
   }
}

Also applies to: 95-95

--ion-grid-column-padding: 0;
}

&--expenses-stats-row {
padding-bottom: 18px;
padding-top: 8px;
padding: 24px 0 20px 0;
--ion-grid-column-padding: 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,21 @@
<span class="stats--expenses-amount-currency">
{{ currencySymbol }}
</span>
{{ cardDetail.stats.totalDraftValue | humanizeCurrency : homeCurrency : true }}
<ng-container
*ngIf="
!isSmallScreen &&
cardDetail.stats.totalDraftValue > -1000000000 &&
cardDetail.stats.totalDraftValue < 1000000000;
else humanizeDraftAmount
"
>
{{
{ value: cardDetail.stats.totalDraftValue, currencyCode: homeCurrency, skipSymbol: true } | exactCurrency
}}
</ng-container>
<ng-template #humanizeDraftAmount>
{{ cardDetail.stats.totalDraftValue | humanizeCurrency : homeCurrency : true }}
</ng-template>
Comment on lines +28 to +42
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Mind it! Don't repeat yourself, even if you're as stylish as me!

Like how I never repeat the same punch dialogue twice, we shouldn't repeat the same template logic! The currency display condition is duplicated for both draft and total amounts.

Let's create a reusable template, macha:

+ <ng-template #currencyDisplay let-value="value">
+   <ng-container *ngIf="!isSmallScreen && value > -1e9 && value < 1e9; else humanizeAmount">
+     {{ { value: value, currencyCode: homeCurrency, skipSymbol: true } | exactCurrency }}
+   </ng-container>
+   <ng-template #humanizeAmount>
+     {{ value | humanizeCurrency : homeCurrency : true }}
+   </ng-template>
+ </ng-template>

  <!-- Use it like this -->
- <ng-container *ngIf="!isSmallScreen && cardDetail.stats.totalDraftValue > -1000000000...">
-   {{ { value: cardDetail.stats.totalDraftValue, ... } | exactCurrency }}
- </ng-container>
- <ng-template #humanizeDraftAmount>
-   {{ cardDetail.stats.totalDraftValue | humanizeCurrency : homeCurrency : true }}
- </ng-template>
+ <ng-container *ngTemplateOutlet="currencyDisplay; context: { value: cardDetail.stats.totalDraftValue }">
+ </ng-container>

Also applies to: 60-74

</div>
</div>
<div class="stats--ccc-stats-title">
Expand All @@ -43,7 +57,21 @@
<span class="stats--expenses-amount-currency">
{{ currencySymbol }}
</span>
{{ cardDetail.stats.totalAmountValue | humanizeCurrency : homeCurrency : true }}
<ng-container
*ngIf="
!isSmallScreen &&
cardDetail.stats.totalAmountValue > -1000000000 &&
cardDetail.stats.totalAmountValue < 1000000000;
else humanizeTotalAmount
"
>
{{
{ value: cardDetail.stats.totalAmountValue, currencyCode: homeCurrency, skipSymbol: true } | exactCurrency
}}
</ng-container>
<ng-template #humanizeTotalAmount>
{{ cardDetail.stats.totalAmountValue | humanizeCurrency : homeCurrency : true }}
</ng-template>
Comment on lines +60 to +74
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Kabali style code duplication detected!

Like how I don't repeat my punch dialogues, we shouldn't repeat our code logic! The same condition structure appears twice.

Let's create a reusable template, thalaiva:

+ <ng-template #exactAmount let-value="value">
+   <ng-container
+     *ngIf="
+       !isSmallScreen &&
+       Math.abs(value) <= 1000000000;
+       else humanizeAmount
+     "
+   >
+     {{
+       { value: value, currencyCode: homeCurrency, skipSymbol: true } | exactCurrency
+     }}
+   </ng-container>
+ </ng-template>
+ 
+ <ng-template #humanizeAmount let-value="value">
+   {{ value | humanizeCurrency : homeCurrency : true }}
+ </ng-template>

- <ng-container *ngIf="...">
-   {{ ... }}
- </ng-container>
+ <ng-container 
+   *ngTemplateOutlet="exactAmount; context: { value: cardDetail.stats.totalAmountValue }"
+ >
+ </ng-container>

Committable suggestion skipped: line range outside the PR's diff.

</div>
</div>
<div class="stats--ccc-stats-title">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,29 @@
margin-top: 16px;
display: flex;
justify-content: space-between;
align-items: center;

&__margin-top {
margin-top: 24px;
}
}

&--ccc-classified-count,
&--ccc-classified-count {
font-weight: 500;
font-size: 16px;
line-height: 28px;
color: $black;
}

&--ccc-classified-amount {
font-weight: 500;
font-size: 18px;
font-size: 14px;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Font size reduction for better responsiveness, what a performance! 🌟

Reducing font sizes from 18px to 14px and 16px to 14px is like my famous punch dialogues - compact but powerful! This change aligns perfectly with the small screen detection mentioned in the summary.

However, mind-blowing suggestion coming up!

Consider using SCSS variables for these font sizes, making them as legendary as my movie titles:

+$font-size-regular: 14px;
+
 .stats {
   &--ccc-classified-amount {
     font-weight: 500;
-    font-size: 14px;
+    font-size: $font-size-regular;
   }

   &--ccc-stats-title {
-    font-size: 14px;
+    font-size: $font-size-regular;
   }
 }

Also applies to: 66-66

line-height: 28px;
color: $black;
}

&--ccc-stats-title {
font-size: 16px;
font-size: 14px;
line-height: 20px;
color: $black-2;
Comment on lines +44 to 68
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

One more thing, superstar! Let's talk about screen sizes! 📱

The AI summary mentioned screen size detection, but these styles don't have media queries. Like how I handle different camera angles in my movies, we should handle different screen sizes with style!

Consider adding media queries for better responsive design:

@media screen and (max-width: 320px) {
  .stats {
    &--ccc-classified-amount,
    &--ccc-stats-title {
      font-size: 12px;
    }
  }
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { IonicModule } from '@ionic/angular';
import { TrackingService } from 'src/app/core/services/tracking.service';
import { FyCurrencyPipe } from 'src/app/shared/pipes/fy-currency.pipe';
import { HumanizeCurrencyPipe } from 'src/app/shared/pipes/humanize-currency.pipe';
import { ExactCurrencyPipe } from 'src/app/shared/pipes/exact-currency.pipe';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Style ah? Where are the test cases for our new currency superstar?

Like how I test my stunts before performing them, we need to test our new currency display logic! The ExactCurrencyPipe is imported but not properly tested.

Add these test cases, partner:

describe('currency display', () => {
  it('should use ExactCurrencyPipe for non-small screens and values within range', () => {
    component.isSmallScreen = false;
    component.cardDetail.stats.totalAmountValue = 999999999;
    fixture.detectChanges();
    const amountElement = fixture.debugElement.query(By.css('.stats--ccc-classified-amount'));
    expect(amountElement.nativeElement.textContent).toContain('999,999,999.00');
  });

  it('should fallback to HumanizeCurrencyPipe for values outside range', () => {
    component.isSmallScreen = false;
    component.cardDetail.stats.totalAmountValue = 1000000001;
    fixture.detectChanges();
    const amountElement = fixture.debugElement.query(By.css('.stats--ccc-classified-amount'));
    expect(amountElement.nativeElement.textContent).toContain('1B');
  });
});

Also applies to: 45-51

import { MaskNumber } from 'src/app/shared/pipes/mask-number.pipe';
import { CardDetailComponent } from './card-detail.component';
import { cardDetailsRes } from 'src/app/core/mock-data/platform-corporate-card-detail.data';
Expand Down Expand Up @@ -41,7 +42,13 @@ describe('CardDetailComponent', () => {
]);
const orgSettingServiceSpy = jasmine.createSpyObj('OrgSettingsService', ['get']);
TestBed.configureTestingModule({
declarations: [CardDetailComponent, HumanizeCurrencyPipe, MaskNumber, MockCorporateCardComponent],
declarations: [
CardDetailComponent,
HumanizeCurrencyPipe,
ExactCurrencyPipe,
MaskNumber,
MockCorporateCardComponent,
],
imports: [IonicModule.forRoot(), RouterModule, RouterTestingModule],
providers: [
FyCurrencyPipe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export class CardDetailComponent {

@Input() currencySymbol: string;

// To track if the screen is small (320px or below)
isSmallScreen = window.innerWidth <= 320;
Comment on lines +19 to +20
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

⚠️ Potential issue

Hold on! These breakpoints are dancing to different tunes!

I notice we're using different breakpoints:

  • StatBadgeComponent: 370px
  • CardDetailComponent: 320px

This inconsistency could create a confusing user experience, like a movie with mismatched scenes!

Let's make this epic by:

  1. Creating a shared constant for breakpoints:
// src/app/shared/constants/breakpoints.ts
export const SCREEN_BREAKPOINTS = {
  EXTRA_SMALL: 320,
  SMALL: 370,
  // Add more as needed
} as const;
  1. Creating a shared service for screen size detection:
// src/app/shared/services/screen-size.service.ts
@Injectable({
  providedIn: 'root'
})
export class ScreenSizeService {
  private screenSize$ = new BehaviorSubject<{
    isExtraSmall: boolean;
    isSmall: boolean;
  }>({
    isExtraSmall: window.innerWidth <= SCREEN_BREAKPOINTS.EXTRA_SMALL,
    isSmall: window.innerWidth <= SCREEN_BREAKPOINTS.SMALL
  });

  constructor() {
    fromEvent(window, 'resize')
      .pipe(
        debounceTime(100)
      )
      .subscribe(() => {
        this.screenSize$.next({
          isExtraSmall: window.innerWidth <= SCREEN_BREAKPOINTS.EXTRA_SMALL,
          isSmall: window.innerWidth <= SCREEN_BREAKPOINTS.SMALL
        });
      });
  }

  get screenSize() {
    return this.screenSize$.asObservable();
  }
}

This way, all components can dance to the same tune! 🕺

Comment on lines +19 to +20
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ey! What's this? Different screen sizes dancing different steps!

Listen here, partner! I'm seeing 320px here but 370px in StatBadgeComponent. This inconsistency is like serving different curries in the same dish! Let's standardize this across components!

Consider:

  1. Create a shared constant for small screen threshold
  2. Use the same value across components
  3. Document why we chose this specific value
+// Move to a shared constants file
+export const SMALL_SCREEN_THRESHOLD = 370; // or 320, but pick one!
+
 @Component({
   selector: 'app-card-detail',
   templateUrl: './card-detail.component.html',
   styleUrls: ['./card-detail.component.scss'],
 })
 export class CardDetailComponent {
-  isSmallScreen = window.innerWidth <= 320;
+  isSmallScreen = window.innerWidth <= SMALL_SCREEN_THRESHOLD;

Committable suggestion skipped: line range outside the PR's diff.


constructor(
private router: Router,
private trackingService: TrackingService,
Expand Down
Loading