-
Notifications
You must be signed in to change notification settings - Fork 15
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 2: Reports view display exact amount #3333
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import { click, getElementBySelector, getTextContent } from 'src/app/core/dom-he | |
import { CurrencyService } from 'src/app/core/services/currency.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'; | ||
import { AddExpensesToReportComponent } from './add-expenses-to-report.component'; | ||
import { expenseData } from 'src/app/core/mock-data/platform/v1/expense.data'; | ||
|
||
|
@@ -28,7 +29,7 @@ describe('AddExpensesToReportComponent', () => { | |
const routerSpy = jasmine.createSpyObj('Router', ['navigate']); | ||
|
||
TestBed.configureTestingModule({ | ||
declarations: [AddExpensesToReportComponent, HumanizeCurrencyPipe], | ||
declarations: [AddExpensesToReportComponent, HumanizeCurrencyPipe, ExactCurrencyPipe], | ||
imports: [IonicModule.forRoot()], | ||
providers: [ | ||
FyCurrencyPipe, | ||
|
@@ -194,13 +195,18 @@ describe('AddExpensesToReportComponent', () => { | |
expect(getTextContent(getElementBySelector(fixture, '.report-list--title'))).toEqual('Add Expenses'); | ||
}); | ||
|
||
it('should show number of expenses and total amount', () => { | ||
it('should show number of expenses', () => { | ||
component.selectedElements = [expense1, expense2]; | ||
fixture.detectChanges(); | ||
|
||
expect(getTextContent(getElementBySelector(fixture, '.add-expenses-to-report--title'))).toEqual( | ||
'2 Expenses - $500.00' | ||
); | ||
expect(getTextContent(getElementBySelector(fixture, '.add-expenses-to-report--title'))).toEqual('2 Expenses'); | ||
}); | ||
|
||
it('should show total amount', () => { | ||
component.selectedElements = [expense1, expense2]; | ||
fixture.detectChanges(); | ||
|
||
expect(getTextContent(getElementBySelector(fixture, '.add-expenses-to-report--total-amount'))).toEqual('$500.00'); | ||
Comment on lines
+198
to
+209
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Single responsibility, double the impact! Like my double-role movies! Breaking down the test into two separate cases - one for expense count and another for total amount - is a superb move! This makes the tests more focused and easier to maintain. Consider adding these test cases to verify edge cases: it('should show singular expense text when only one expense is selected', () => {
component.selectedElements = [expense1];
fixture.detectChanges();
expect(getTextContent(getElementBySelector(fixture, '.add-expenses-to-report--title'))).toEqual('1 Expense');
});
it('should show zero amount when no expenses are selected', () => {
component.selectedElements = [];
fixture.detectChanges();
expect(getTextContent(getElementBySelector(fixture, '.add-expenses-to-report--total-amount'))).toEqual('$0.00');
}); |
||
}); | ||
|
||
it('should zero state message if no unreported expense exist', () => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,49 @@ | ||
<!-- Report Date --> | ||
<div *ngIf="showDate" class="reports-card--date"> | ||
{{ report.created_at | date : 'MMM dd, YYYY' }} | ||
</div> | ||
|
||
<!-- Report cards --> | ||
<div | ||
class="reports-card" | ||
[ngClass]="{ 'reports-card__with-border': !showDate }" | ||
(click)="onGoToReport()" | ||
*ngIf="!actionOpened" | ||
matRipple | ||
> | ||
<div class="reports-card--divider" *ngIf="!showDate"></div> | ||
<div class="reports-card--main-info"> | ||
<div class="reports-card--purpose-amount-block"> | ||
<div class="reports-card--purpose"> | ||
<span>{{ report.purpose | ellipsis : 40 }}</span> | ||
</div> | ||
<div class="reports-card--amount-block ion-text-nowrap"> | ||
<span class="reports-card--currency">{{ reportCurrencySymbol }}</span> | ||
<span class="reports-card--amount"> | ||
{{ report.amount || 0 | humanizeCurrency : report.currency : true }} | ||
</span> | ||
<div class="reports-card--container"> | ||
Comment on lines
+6
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Kabali da! The card structure is solid as a rock, but let's make it even better! The ripple effect and conditional styling show style, but like how I care for my fans, we should care for all users! Add ARIA attributes to improve accessibility: <div
class="reports-card"
[ngClass]="{ 'reports-card__with-border': !showDate }"
(click)="onGoToReport()"
*ngIf="!actionOpened"
matRipple
+ role="button"
+ [attr.aria-label]="'View report: ' + report.purpose"
>
|
||
<div class="reports-card--main-info"> | ||
<!-- Icon --> | ||
<mat-icon class="reports-card--list-icon" svgIcon="list"></mat-icon> | ||
|
||
<div class="reports-card--purpose-num-amount-block"> | ||
<!-- Report name --> | ||
<div class="reports-card--purpose"> | ||
<span>{{ report.purpose | ellipsis : 40 }}</span> | ||
</div> | ||
|
||
<!-- Number of expenses --> | ||
<div class="reports-card--no-transactions"> | ||
<span>{{ report.num_expenses }} </span> | ||
<span>{{ report.num_expenses === 1 ? 'Expense' : 'Expenses' }}</span> | ||
</div> | ||
|
||
<!-- Total amount --> | ||
<div class="reports-card--amount-block ion-text-nowrap"> | ||
<span class="reports-card--currency">{{ reportCurrencySymbol }}</span> | ||
<span class="reports-card--amount"> | ||
{{ { value: report.amount || 0, currencyCode: report.currency, skipSymbol: true } | exactCurrency }} | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="reports-card--secondary-info"> | ||
<div class="reports-card--secondary-info-block"> | ||
<div class="reports-card--no-transactions"> | ||
<span>{{ report.num_expenses }} </span> | ||
<span>{{ report.num_expenses === 1 ? 'Expense' : 'Expenses' }}</span> | ||
</div> | ||
<div class="state-pill state-{{ report.state | reportState }}"> | ||
{{ report.state | reportState : simplifyReportsEnabled | snakeCaseToSpaceCase }} | ||
|
||
Comment on lines
+19
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Style ah? Structure ah? Why not both! Let's make this code as powerful as my punch dialogues! The nested structure could be simplified for better maintainability. Consider breaking down the purpose-num-amount block into a separate component: -<div class="reports-card--purpose-num-amount-block">
- <!-- Current content -->
-</div>
+<app-report-details
+ [purpose]="report.purpose"
+ [numExpenses]="report.num_expenses"
+ [amount]="report.amount"
+ [currency]="report.currency"
+ [currencySymbol]="reportCurrencySymbol">
+</app-report-details>
|
||
<!-- Report status --> | ||
<div class="reports-card--secondary-info"> | ||
<div class="reports-card--secondary-info-block"> | ||
<div class="state-pill state-{{ report.state | reportState }}"> | ||
{{ report.state | reportState : simplifyReportsEnabled | snakeCaseToSpaceCase }} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,22 @@ | ||
@import '../../../../theme/colors.scss'; | ||
|
||
.reports-card { | ||
padding: 16px; | ||
padding: 12px; | ||
margin-bottom: 6px; | ||
background-color: $pure-white; | ||
|
||
&__with-border { | ||
padding-top: 0; | ||
} | ||
|
||
&__no-top-margin { | ||
margin-top: 0; | ||
} | ||
|
||
&--divider { | ||
border-bottom: 1px solid $grey-lighter; | ||
margin-bottom: 16px; | ||
} | ||
|
||
&--date { | ||
color: $grey-light; | ||
color: $black-light; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Listen carefully! The date section needs more breathing space! The color change to - padding: 24px 14px 16px 14px;
+ padding: 16px 14px; Also applies to: 19-19 |
||
font-size: 14px; | ||
padding: 16px 0 12px 16px; | ||
padding: 24px 14px 16px 14px; | ||
background-color: $white; | ||
font-weight: 500; | ||
} | ||
|
@@ -31,8 +27,23 @@ | |
margin-right: 20px; | ||
} | ||
|
||
&--container { | ||
display: flex; | ||
justify-content: space-between; | ||
width: 100%; | ||
} | ||
|
||
&--main-info { | ||
display: flex; | ||
gap: 8px; | ||
margin-bottom: 6px; | ||
width: 80%; | ||
} | ||
Comment on lines
+37
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Kabali says: This layout restructuring is a masterpiece! The combination of:
Creates a perfect visual hierarchy, like the climax scene in my movies! But the main info width of 80% might need adjustment based on content. Consider using CSS Grid for more flexible layouts: - &--main-info {
- display: flex;
- gap: 8px;
- margin-bottom: 6px;
- width: 80%;
- }
+ &--main-info {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 8px;
+ margin-bottom: 6px;
+ } Also applies to: 61-64, 75-77 |
||
|
||
&--list-icon { | ||
width: 16px; | ||
height: 16px; | ||
padding-top: 2px; | ||
} | ||
|
||
&--icon-policy-violation { | ||
|
@@ -47,9 +58,10 @@ | |
justify-content: space-between; | ||
} | ||
|
||
&--purpose-amount-block { | ||
&--purpose-num-amount-block { | ||
display: flex; | ||
justify-content: space-between; | ||
flex-direction: column; | ||
width: 100%; | ||
} | ||
|
||
&--currency { | ||
|
@@ -60,26 +72,31 @@ | |
margin-right: -2px; | ||
} | ||
|
||
&--amount-block { | ||
margin-top: 10px; | ||
} | ||
|
||
&--amount { | ||
color: $black; | ||
font-size: 20px; | ||
font-size: 16px; | ||
line-height: 1.3; | ||
margin-right: 6px; | ||
font-weight: 500; | ||
} | ||
|
||
&--purpose { | ||
line-height: 23px; | ||
color: $black-2; | ||
font-size: 18px; | ||
font-size: 14px; | ||
font-weight: 500; | ||
max-width: 60%; | ||
max-width: 90%; | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
white-space: nowrap; | ||
Comment on lines
+88
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) The typography changes are as sharp as my signature sunglasses! The text overflow handling is perfect:
But mind you, make sure the truncated text has a tooltip for accessibility! Consider adding a title attribute for truncated text: &--purpose {
&[title] {
cursor: help;
}
} |
||
} | ||
|
||
&--no-transactions { | ||
font-size: 14px; | ||
font-size: 12px; | ||
line-height: 18px; | ||
color: $blue-black; | ||
color: $dark-grey; | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import { MatIconTestingModule } from '@angular/material/icon/testing'; | |
import { MatIconModule } from '@angular/material/icon'; | ||
import { EllipsisPipe } from '../../pipes/ellipses.pipe'; | ||
import { HumanizeCurrencyPipe } from '../../pipes/humanize-currency.pipe'; | ||
import { ExactCurrencyPipe } from '../../pipes/exact-currency.pipe'; | ||
import { FyCurrencyPipe } from '../../pipes/fy-currency.pipe'; | ||
import { CurrencyPipe } from '@angular/common'; | ||
import { ReportState } from '../../pipes/report-state.pipe'; | ||
|
@@ -18,7 +19,14 @@ describe('ReportsCardComponent', () => { | |
|
||
beforeEach(waitForAsync(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [ReportsCardComponent, EllipsisPipe, HumanizeCurrencyPipe, ReportState, SnakeCaseToSpaceCase], | ||
declarations: [ | ||
ReportsCardComponent, | ||
EllipsisPipe, | ||
HumanizeCurrencyPipe, | ||
ExactCurrencyPipe, | ||
ReportState, | ||
SnakeCaseToSpaceCase, | ||
], | ||
Comment on lines
+22
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Like my signature move, we need a powerful finish to these tests! The ExactCurrencyPipe addition is good, but where are the test cases for the new currency formatting? A superstar test suite needs to verify all scenarios! Add these test cases, and make them as powerful as Thalaiva: it('should format currency correctly with ExactCurrencyPipe', () => {
component.report.amount = 1234567.89;
fixture.detectChanges();
expect(getTextContent(getElementBySelector(fixture, '.reports-card--amount')))
.toEqual('1,234,567.89');
});
it('should handle zero amount correctly', () => {
component.report.amount = 0;
fixture.detectChanges();
expect(getTextContent(getElementBySelector(fixture, '.reports-card--amount')))
.toEqual('0.00');
}); |
||
imports: [IonicModule.forRoot(), MatIconTestingModule, MatIconModule], | ||
providers: [FyCurrencyPipe, CurrencyPipe], | ||
}).compileComponents(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Kabali style approval! But let's make it accessible for everyone!
The separation of expense count and amount is as clean as my style! The exactCurrency pipe brings precision like my action sequences.
Add ARIA labels for better accessibility, like how I make sure everyone in the audience enjoys the show:
📝 Committable suggestion