Skip to content
Open
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
3 changes: 3 additions & 0 deletions frontend/Exence/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.preferences.quoteStyle": "single"
}
3 changes: 3 additions & 0 deletions frontend/Exence/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default defineConfig([
languageOptions: {
parserOptions: {
projectService: true,
allowDefaultProject: ['eslint.config.mjs'],
},
},
},
Expand Down Expand Up @@ -56,6 +57,7 @@ export default defineConfig([
}
],
"@typescript-eslint/method-signature-style": ["error", "property"],
"@typescript-eslint/require-await": "off",
"@typescript-eslint/no-deprecated": "warn",
"@typescript-eslint/no-inferrable-types": "warn",
"@typescript-eslint/no-misused-promises": [
Expand All @@ -78,6 +80,7 @@ export default defineConfig([
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/unbound-method": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-arguments": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { TransactionType } from './TransactionType';

export interface TransactionFilter {
keyword?: string;
dateFrom: string;
dateTo: string;
categoryId: number;
type: TransactionType;
amountFrom: number;
amountTo: number;
recurring: boolean;
dateFrom?: string;
dateTo?: string;
categoryId?: number;
type?: TransactionType;
amountFrom?: number;
amountTo?: number;
recurring?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { CategoriesComponent, DateInterval } from '../../private/dashboard/categ
import {
SummaryContainerComponent
} from '../../private/dashboard/summary-container/summary-container.component';
import { BaseComponent } from '../../shared/base-component/base.component';
import { ButtonComponent } from '../../shared/button/button.component';
import { CardSliderDirective } from '../../shared/card-slider.directive';
import { ChartComponent } from '../../shared/chart/chart.component';
Expand Down Expand Up @@ -41,7 +42,7 @@ import { TransactionService } from '../transactions-and-categories/transaction.s
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.scss',
})
export class DashboardComponent implements OnInit {
export class DashboardComponent extends BaseComponent implements OnInit {
private readonly currentUserService = inject(CurrentUserService);
private readonly transactionService = inject(TransactionService);
private readonly categoryService = inject(CategoryService);
Expand All @@ -50,7 +51,6 @@ export class DashboardComponent implements OnInit {
readonly dialog = inject(MatDialog);
readonly router = inject(Router);
readonly navigation = inject(NavigationService);


transactionTypes = TransactionType;
dateIntervals = DateInterval;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ <h3 class="fs-1 fw-bold">New transaction</h3>
</mat-error>
</mat-form-field>

<!-- TODO change to textarea -->
@let recurringControl = form.controls.recurring;
<mat-checkbox [formControl]="recurringControl">Automatically recurring?</mat-checkbox>
</mat-card-content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { lastValueFrom } from 'rxjs';
import { PagedResponse } from '../../data-model/modules/common/PagedResponse';
import { RecurringTransactionsResponse } from '../../data-model/modules/transaction/RecurringTransactionsResponse';
import { Transaction } from '../../data-model/modules/transaction/Transaction';
import { TransactionFilter } from '../../data-model/modules/transaction/TransactionFilter';
import { TransactionTotalsResponse } from '../../data-model/modules/transaction/TransactionTotalsResponse';
import { HttpService } from '../../shared/http/http.service';

Expand All @@ -18,8 +19,9 @@ export class TransactionService {
return lastValueFrom(this.http.get<Transaction>(`${this.baseUrl}/${id}`));
}

public list(): Promise<PagedResponse<Transaction>> {
return lastValueFrom(this.http.get<PagedResponse<Transaction>>(this.baseUrl));
public list(filters?: TransactionFilter): Promise<PagedResponse<Transaction>> {
const request: Record<string, string> = filters !== undefined ? JSON.parse(JSON.stringify(filters)) : {};
return lastValueFrom(this.http.get<PagedResponse<Transaction>>(this.baseUrl, request));
}

public listRecurrings(): Promise<RecurringTransactionsResponse> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
<div
class="d-flex flex-column flex-md-row justify-content-center justify-content-md-between align-items-center gap-2"
>
<h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}">
<h2
class="m-0 text-center text-md-start {{
display.isSm() ? 'fs-1' : 'fs-2'
}}"
>
@if (selectedIndex === 0) {
Transactions
} @else {
Expand All @@ -20,7 +24,9 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
>
<mat-tab>
<ng-template mat-tab-label>
<div class="d-flex flex-row flex-nowrap align-items-center gap-2">
<div
class="d-flex flex-row flex-nowrap align-items-center gap-2"
>
<mat-icon size="md">payments</mat-icon>
@if (display.isMd()) {
Transactions
Expand All @@ -30,7 +36,9 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<div class="d-flex flex-row flex-nowrap align-items-center gap-2">
<div
class="d-flex flex-row flex-nowrap align-items-center gap-2"
>
<mat-icon size="md">cached</mat-icon>
@if (display.isMd()) {
Categories
Expand All @@ -55,9 +63,11 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
<div class="d-flex flex-row gap-4 smaller-row">
@if (display.isLg()) {
<ex-data-table
[data]="{ transactions: recurringTransactions.incomes, categories }"
[data]="{
transactions: recurringTransactions.incomes,
categories
}"
matIcon="money_off"
class="flex-grow-1"
nonExpandable
paginationDisabled
title="Recurring Incomes"
Expand All @@ -66,7 +76,10 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
(dataChangedEvent)="onDataChanged()"
/>
<ex-data-table
[data]="{ transactions: recurringTransactions.expenses, categories }"
[data]="{
transactions: recurringTransactions.expenses,
categories
}"
matIcon="money_off"
class="flex-grow-1"
nonExpandable
Expand All @@ -78,9 +91,11 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
/>
} @else {
<ex-data-table
[data]="{ transactions: recurringTransactions.mergedTransactions, categories }"
[data]="{
transactions: recurringTransactions.mergedTransactions,
categories
}"
matIcon="money_off"
class="flex-grow-1"
nonExpandable
paginationDisabled
title="Recurrings"
Expand All @@ -95,7 +110,12 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
[class.overflow-hidden]="display.isMd()"
>
<div class="d-flex flex-row flex-nowrap justif-content-between">
<div [matTooltip]="!canCreateTransaction ? 'First create a category!' : ''">
<div
class="d-flex flex-row flex-nowrap justify-content-between gap-3 w-100"
[matTooltip]="
!canCreateTransaction ? 'First create a category!' : ''
"
>
<ex-button
filled
matIcon="add"
Expand All @@ -106,6 +126,93 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"
>
Add transaction
</ex-button>

<div class="d-flex flex-row flex-nowrap gap-3">
<mat-error class="align-self-center">
<ex-validator [control]="transactionFilterForm.controls.searchText" />
</mat-error>
<mat-form-field subscriptSizing="dynamic" class="search">
<ex-button
iconButton
matPrefix
matIcon="search"
color="accent"
/>
<input [formControl]="transactionFilterForm.controls.searchText" matInput placeholder="Search..." autocomplete="off">
<ex-input-clear [control]="transactionFilterForm.controls.searchText" matSuffix />
</mat-form-field>
<ex-filter-menu class="align-self-end" [form]="transactionFilterForm" [appliedFiltersCount]="appliedFiltersCount">
@let dateRangeControl = transactionFilterForm.controls.dateRange;
<mat-form-field subscriptSizing="dynamic">
<mat-label>Enter a date range</mat-label>
<mat-date-range-input
[formGroup]="dateRangeControl"
[rangePicker]="dateRangePicker"
>
<input
matStartDate
[formControl]="dateRangeControl.controls.dateFrom"
/>
<input
matEndDate
[formControl]="dateRangeControl.controls.dateTo"
/>
</mat-date-range-input>
<mat-datepicker-toggle
matIconSuffix
[for]="dateRangePicker"
></mat-datepicker-toggle>
<mat-date-range-picker
#dateRangePicker
></mat-date-range-picker>
</mat-form-field>

<div class="d-flex flex-column gap-1">
<div class="fs-6 ps-1">Amount</div>
@let amountRangeControl = transactionFilterForm.controls.amountRange;
<mat-form-field
class="mb-3" subscriptSizing="dynamic">
<mat-label>Min</mat-label>
<input matInput type="number" min="0" [formControl]="amountRangeControl.controls.min">
</mat-form-field>
<mat-form-field subscriptSizing="dynamic">
<mat-label>Max</mat-label>
<input matInput type="number" min="0" [formControl]="amountRangeControl.controls.max">
</mat-form-field>
</div>

@let categoryControl = transactionFilterForm.controls.category;
<mat-form-field subscriptSizing="dynamic">
<mat-label>Category</mat-label>
<mat-select [formControl]="categoryControl">
<mat-option [value]="null">All</mat-option>
@for (category of categories; track category.id) {
<mat-option [value]="category">{{ `${category.name} - ${category.emoji}` }}</mat-option>
}
</mat-select>
<mat-error>
<ex-validator [control]="categoryControl" />
</mat-error>
</mat-form-field>

@let typeControl = transactionFilterForm.controls.type;
<mat-form-field subscriptSizing="dynamic">
<mat-label>Type</mat-label>
<mat-select [formControl]="typeControl">
<mat-option [value]="null">All</mat-option>
@for (type of transactionTypesArr; track type) {
<mat-option [value]="type">{{ type }}</mat-option>
}
</mat-select>
<mat-error>
<ex-validator [control]="typeControl" />
</mat-error>
</mat-form-field>

@let recurringControl = transactionFilterForm.controls.recurring;
<mat-checkbox [formControl]="recurringControl">Recurring</mat-checkbox>
</ex-filter-menu>
</div>
</div>
</div>
<ex-data-table
Expand All @@ -121,7 +228,7 @@ <h2 class="m-0 text-center text-md-start {{ display.isSm() ? 'fs-1' : 'fs-2' }}"

<ng-template #categoriesTab>
<div
class="d-flex flex-column justify-content-between gap-4 h-100 mt-4"
class="d-flex flex-column justify-content-between gap-2 h-100 mt-4"
[class.overflow-hidden]="display.isMd()"
>
<div class="d-flex flex-row flex-norwap gap-2 align-items-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
@include displayMd {
.smaller-row {
flex-basis: 30%;
height: 30%;
}

.bigger-row {
flex-basis: 70%;
}

mat-form-field {
width: 225px;
}
}
Loading
Loading