diff --git a/frontend/Exence/.vscode/settings.json b/frontend/Exence/.vscode/settings.json new file mode 100644 index 0000000..8134a6c --- /dev/null +++ b/frontend/Exence/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.preferences.quoteStyle": "single" +} \ No newline at end of file diff --git a/frontend/Exence/eslint.config.mjs b/frontend/Exence/eslint.config.mjs index b0e3949..224ed1f 100644 --- a/frontend/Exence/eslint.config.mjs +++ b/frontend/Exence/eslint.config.mjs @@ -11,6 +11,7 @@ export default defineConfig([ languageOptions: { parserOptions: { projectService: true, + allowDefaultProject: ['eslint.config.mjs'], }, }, }, @@ -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": [ @@ -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", diff --git a/frontend/Exence/src/app/data-model/modules/transaction/TransactionFilter.ts b/frontend/Exence/src/app/data-model/modules/transaction/TransactionFilter.ts index 3dab7a1..bfa0935 100644 --- a/frontend/Exence/src/app/data-model/modules/transaction/TransactionFilter.ts +++ b/frontend/Exence/src/app/data-model/modules/transaction/TransactionFilter.ts @@ -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; } \ No newline at end of file diff --git a/frontend/Exence/src/app/private/dashboard/dashboard.component.ts b/frontend/Exence/src/app/private/dashboard/dashboard.component.ts index e9a0159..bcd4af1 100644 --- a/frontend/Exence/src/app/private/dashboard/dashboard.component.ts +++ b/frontend/Exence/src/app/private/dashboard/dashboard.component.ts @@ -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'; @@ -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); @@ -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; diff --git a/frontend/Exence/src/app/private/transactions-and-categories/create-transaction-dialog/create-transaction-dialog.component.html b/frontend/Exence/src/app/private/transactions-and-categories/create-transaction-dialog/create-transaction-dialog.component.html index c32befe..6ff291e 100644 --- a/frontend/Exence/src/app/private/transactions-and-categories/create-transaction-dialog/create-transaction-dialog.component.html +++ b/frontend/Exence/src/app/private/transactions-and-categories/create-transaction-dialog/create-transaction-dialog.component.html @@ -85,7 +85,6 @@

New transaction

- @let recurringControl = form.controls.recurring; Automatically recurring? diff --git a/frontend/Exence/src/app/private/transactions-and-categories/transaction.service.ts b/frontend/Exence/src/app/private/transactions-and-categories/transaction.service.ts index 6a60eeb..fda4de2 100644 --- a/frontend/Exence/src/app/private/transactions-and-categories/transaction.service.ts +++ b/frontend/Exence/src/app/private/transactions-and-categories/transaction.service.ts @@ -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'; @@ -18,8 +19,9 @@ export class TransactionService { return lastValueFrom(this.http.get(`${this.baseUrl}/${id}`)); } - public list(): Promise> { - return lastValueFrom(this.http.get>(this.baseUrl)); + public list(filters?: TransactionFilter): Promise> { + const request: Record = filters !== undefined ? JSON.parse(JSON.stringify(filters)) : {}; + return lastValueFrom(this.http.get>(this.baseUrl, request)); } public listRecurrings(): Promise { diff --git a/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.html b/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.html index 376b352..68927ca 100644 --- a/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.html +++ b/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.html @@ -5,7 +5,11 @@
-

+

@if (selectedIndex === 0) { Transactions } @else { @@ -20,7 +24,9 @@

-
+
payments @if (display.isMd()) { Transactions @@ -30,7 +36,9 @@

-
+
cached @if (display.isMd()) { Categories @@ -55,9 +63,11 @@

@if (display.isLg()) { } @else {
-
+
Add transaction + +
+ + + + + + + + + + @let dateRangeControl = transactionFilterForm.controls.dateRange; + + Enter a date range + + + + + + + + +
+
Amount
+ @let amountRangeControl = transactionFilterForm.controls.amountRange; + + Min + + + + Max + + +
+ + @let categoryControl = transactionFilterForm.controls.category; + + Category + + All + @for (category of categories; track category.id) { + {{ `${category.name} - ${category.emoji}` }} + } + + + + + + + @let typeControl = transactionFilterForm.controls.type; + + Type + + All + @for (type of transactionTypesArr; track type) { + {{ type }} + } + + + + + + + @let recurringControl = transactionFilterForm.controls.recurring; + Recurring +
+
diff --git a/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.scss b/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.scss index b9cae63..1beab8b 100644 --- a/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.scss +++ b/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.scss @@ -3,10 +3,13 @@ @include displayMd { .smaller-row { flex-basis: 30%; - height: 30%; } .bigger-row { flex-basis: 70%; } + + mat-form-field { + width: 225px; + } } \ No newline at end of file diff --git a/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.ts b/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.ts index 8b650e5..d0d3dfc 100644 --- a/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.ts +++ b/frontend/Exence/src/app/private/transactions-and-categories/transactions-and-categories.component.ts @@ -1,18 +1,30 @@ import { CommonModule } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; +import { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatBadgeModule } from '@angular/material/badge'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { MatError, MatFormFieldModule, MatLabel } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatTabsModule } from '@angular/material/tabs'; import { MatTooltipModule } from '@angular/material/tooltip'; import { Category } from '../../data-model/modules/category/Category'; 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 { TransactionType } from '../../data-model/modules/transaction/TransactionType'; +import { BaseComponent } from '../../shared/base-component/base.component'; import { ButtonComponent } from '../../shared/button/button.component'; import { DataTableComponent } from '../../shared/data-table/data-table.component'; import { DisplaySizeService } from '../../shared/display-size.service'; +import { FilterMenuComponent } from '../../shared/filter-menu/filter-menu.component'; +import { InputClearButtonComponent } from '../../shared/input-clear-button/input-clear-button.component'; import { SnackbarService } from '../../shared/snackbar/snackbar.service'; +import { ValidatorComponent } from '../../shared/validator/validator.component'; import { CategoryService } from '../category.service'; import { CreateCategoryDialogComponent } from './create-category-dialog/create-category-dialog.component'; import { CreateTransactionDialogComponent, CreateTransactionDialogData } from './create-transaction-dialog/create-transaction-dialog.component'; @@ -24,21 +36,49 @@ import { TransactionService } from './transaction.service'; styleUrl: './transactions-and-categories.component.scss', imports: [ CommonModule, + ReactiveFormsModule, + MatFormFieldModule, MatDialogModule, MatTabsModule, MatIconModule, MatTooltipModule, + MatInputModule, + MatCheckboxModule, + MatSelectModule, + MatBadgeModule, + MatDatepickerModule, + MatLabel, + MatError, DataTableComponent, ButtonComponent, + FilterMenuComponent, + ValidatorComponent, + InputClearButtonComponent, ], }) -export class TransactionsAndCategoriesComponent implements OnInit { +export class TransactionsAndCategoriesComponent extends BaseComponent implements OnInit { private readonly transactionService = inject(TransactionService); private readonly categoryService = inject(CategoryService); private readonly dialog = inject(MatDialog); private readonly snackbarService = inject(SnackbarService); + private readonly fb = inject(NonNullableFormBuilder); readonly display = inject(DisplaySizeService); + transactionFilterForm = this.fb.group({ + searchText: this.fb.control('', [Validators.maxLength(100)]), + dateRange: this.fb.group({ + dateFrom: this.fb.control(null), + dateTo: this.fb.control(null), + }), + amountRange: this.fb.group({ + min: this.fb.control(null), + max: this.fb.control(null), + }), + category: this.fb.control(null), + type: this.fb.control(null), + recurring: this.fb.control(false), + }); + transactions: PagedResponse = {} as PagedResponse; recurringTransactions: RecurringTransactionsResponse = {} as RecurringTransactionsResponse; categories: Category[] = []; @@ -46,13 +86,29 @@ export class TransactionsAndCategoriesComponent implements OnInit { selectedIndex = 0; transactionTypes = TransactionType; + transactionTypesArr = Object.values(this.transactionTypes); + + get canCreateTransaction(): boolean { return !!this.categories.length; } - get canCreateTransaction(): boolean { - return !!this.categories.length; + get appliedFiltersCount(): number { + return Object.entries(this.transactionFilterForm.controls).reduce((sum, [key, control]) => { + if (key === 'dateRange' || key === 'amountRange') { + const groupValue = control.value as Record; + const hasValue = Object.values(groupValue).some(v => !!v); + return sum + (hasValue ? 1 : 0); + } + if (control.value) return sum + 1; + return sum; + }, 0); } async ngOnInit(): Promise { await this.initialize(); + + this.addSubscription(this.transactionFilterForm.valueChanges.subscribe(async () => { + if (this.transactionFilterForm.invalid) return; + this.transactions = await this.getTransactions(); + })); } async initialize(): Promise { @@ -67,7 +123,7 @@ export class TransactionsAndCategoriesComponent implements OnInit { }); } - public openCreateTransactionDialog(): void { + openCreateTransactionDialog(): void { this.dialog.open( CreateTransactionDialogComponent, undefined ).afterClosed().subscribe( @@ -80,7 +136,7 @@ export class TransactionsAndCategoriesComponent implements OnInit { ); } - public openCreateCategoryDialog(): void { + openCreateCategoryDialog(): void { this.dialog.open( CreateCategoryDialogComponent, undefined ).afterClosed().subscribe( @@ -96,4 +152,19 @@ export class TransactionsAndCategoriesComponent implements OnInit { async onDataChanged(): Promise { await this.initialize(); } + + getTransactions(): Promise> { + const formValue = this.transactionFilterForm.getRawValue(); + const filters = { + keyword: formValue.searchText, + dateFrom: formValue.dateRange.dateFrom?.toISOString(), + dateTo: formValue.dateRange.dateTo?.toISOString(), + categoryId: formValue.category?.id, + type: formValue.type, + amountFrom: formValue.amountRange.min, + amountTo: formValue.amountRange.max, + recurring: formValue.recurring, + } as TransactionFilter; + return this.transactionService.list(filters); + } } diff --git a/frontend/Exence/src/app/shared/auth/guard/logged-in.guard.ts b/frontend/Exence/src/app/shared/auth/guard/logged-in.guard.ts index 67b4d30..2ae794e 100644 --- a/frontend/Exence/src/app/shared/auth/guard/logged-in.guard.ts +++ b/frontend/Exence/src/app/shared/auth/guard/logged-in.guard.ts @@ -17,7 +17,6 @@ export const loggedInGuard: CanActivateFn = ( filter(user => user !== null), take(1), map((user) => { - console.log(user) if (user && currentUserService.isAuthenticated()) { return true; } else { diff --git a/frontend/Exence/src/app/shared/data-table/data-table.component.scss b/frontend/Exence/src/app/shared/data-table/data-table.component.scss index 8cf83b1..51b3a48 100644 --- a/frontend/Exence/src/app/shared/data-table/data-table.component.scss +++ b/frontend/Exence/src/app/shared/data-table/data-table.component.scss @@ -1,7 +1,7 @@ @import '../../../styles/imports.scss'; :host { - height: 100%; + flex-grow: 1; } .table-container { @@ -174,7 +174,6 @@ td.mat-column-actions mat-icon { background-color: var(--primary-color); } -// TODO details .detail-container { display: flex; diff --git a/frontend/Exence/src/app/shared/data-table/data-table.component.ts b/frontend/Exence/src/app/shared/data-table/data-table.component.ts index 0994676..45ee761 100644 --- a/frontend/Exence/src/app/shared/data-table/data-table.component.ts +++ b/frontend/Exence/src/app/shared/data-table/data-table.component.ts @@ -233,7 +233,6 @@ export class DataTableComponent extends BaseComponent { // } } - // TODO refactor openCreateDialog(): void { // All transactions if (!this.type()) { diff --git a/frontend/Exence/src/app/shared/error.service.ts b/frontend/Exence/src/app/shared/error.service.ts index 56561e5..e6590f6 100644 --- a/frontend/Exence/src/app/shared/error.service.ts +++ b/frontend/Exence/src/app/shared/error.service.ts @@ -1,9 +1,9 @@ -import { inject, Injectable } from "@angular/core"; -import { SnackbarService } from "./snackbar/snackbar.service"; -import { HttpErrorResponse } from "@angular/common/http"; -import { ErrorResponse } from "../data-model/modules/ErrorResponse"; -import { SUPPRESS_ERROR_SNACKBAR } from "./auth/interceptors/refresh-token.interceptor"; -import { HttpSettings } from "./http/http.service"; +import { inject, Injectable } from '@angular/core'; +import { SnackbarService } from './snackbar/snackbar.service'; +import { HttpErrorResponse } from '@angular/common/http'; +import { ErrorResponse } from '../data-model/modules/ErrorResponse'; +import { SUPPRESS_ERROR_SNACKBAR } from './auth/interceptors/refresh-token.interceptor'; +import { HttpSettings } from './http/http.service'; @Injectable({ providedIn: 'root' @@ -14,6 +14,7 @@ export class ErrorService { handleError(errorResponse: HttpErrorResponse, settings?: HttpSettings): void { settings = settings ?? {}; + // eslint-disable-next-line const suppressFromInterceptor = (errorResponse as any).context?.get?.(SUPPRESS_ERROR_SNACKBAR) ?? false; if (!settings.suppressErrorMessage && !suppressFromInterceptor) { diff --git a/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.html b/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.html new file mode 100644 index 0000000..87141c5 --- /dev/null +++ b/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.html @@ -0,0 +1,85 @@ +@if (display.isMd()) { + + Add filter + +} @else { + +} + + + + + + + +
+

Filters

+ +
+ +
+ +
+ + Show ({{ appliedFiltersCount() }}) + + + Clear all + +
+
+
+ + + + diff --git a/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.scss b/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.scss new file mode 100644 index 0000000..52d506c --- /dev/null +++ b/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.scss @@ -0,0 +1,3 @@ +.menu { + max-width: 266px; +} \ No newline at end of file diff --git a/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.ts b/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.ts new file mode 100644 index 0000000..f444624 --- /dev/null +++ b/frontend/Exence/src/app/shared/filter-menu/filter-menu.component.ts @@ -0,0 +1,42 @@ +import { Component, inject, input, TemplateRef, viewChild } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { MatBadgeModule } from '@angular/material/badge'; +import { MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet'; +import { MatMenuModule } from '@angular/material/menu'; +import { ButtonComponent } from '../button/button.component'; +import { DisplaySizeService } from '../display-size.service'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'ex-filter-menu', + templateUrl: './filter-menu.component.html', + styleUrl: './filter-menu.component.scss', + imports: [ + CommonModule, + MatMenuModule, + MatBadgeModule, + MatBottomSheetModule, + ButtonComponent, + ], +}) +export class FilterMenuComponent { + private readonly bottomSheet = inject(MatBottomSheet); + readonly display = inject(DisplaySizeService); + + form = input.required(); + appliedFiltersCount = input.required(); + + filterSheet = viewChild>('filterSheet'); + + openBottomSheet(): void { + this.bottomSheet.open(this.filterSheet()!); + } + + closeSheet(): void { + this.bottomSheet.dismiss(); + } + + clearFilters(): void { + this.form().reset(); + } +} \ No newline at end of file diff --git a/frontend/Exence/src/app/shared/user/current-user.service.ts b/frontend/Exence/src/app/shared/user/current-user.service.ts index c410849..fb01f1a 100644 --- a/frontend/Exence/src/app/shared/user/current-user.service.ts +++ b/frontend/Exence/src/app/shared/user/current-user.service.ts @@ -7,10 +7,10 @@ import { User } from '../../data-model/modules/auth/User'; export class CurrentUserService { private _user: WritableSignal = signal(null); + isAuthenticated = computed(() => !!this._user()); + get user(): Signal { return this._user.asReadonly() as Signal; } set user(user: User | null | undefined) { this._user.set(user); } - - isAuthenticated = computed(() => !!this._user()); clearUser(): void { this.user = undefined; diff --git a/frontend/Exence/src/app/shared/validator/validator.component.html b/frontend/Exence/src/app/shared/validator/validator.component.html index aff4a5b..57b0883 100644 --- a/frontend/Exence/src/app/shared/validator/validator.component.html +++ b/frontend/Exence/src/app/shared/validator/validator.component.html @@ -1,5 +1,5 @@ -@if (errorKey) { - @switch (errorKey) { +@if (errorKey()) { + @switch (errorKey()) { @case ('required') { Field required } @@ -13,13 +13,13 @@ Invalid email format! } @case ('maxlength') { - Max length is {{ errorValue?.requiredLength }}! + Max length is {{ errorValue()?.requiredLength }}! } @case ('min') { - Minimum value is {{ errorValue?.min }}! + Minimum value is {{ errorValue()?.min }}! } @case ('max') { - MaximumValue value is {{ errorValue?.max }}! + Maximum value is {{ errorValue()?.max }}! } } } diff --git a/frontend/Exence/src/app/shared/validator/validator.component.ts b/frontend/Exence/src/app/shared/validator/validator.component.ts index ce18598..3d1d6bb 100644 --- a/frontend/Exence/src/app/shared/validator/validator.component.ts +++ b/frontend/Exence/src/app/shared/validator/validator.component.ts @@ -1,5 +1,5 @@ -import { Component, input, OnInit } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { Component, input, OnInit, signal } from '@angular/core'; +import { AbstractControl } from '@angular/forms'; import { merge, of } from 'rxjs'; import { BaseComponent } from '../base-component/base.component'; @@ -15,17 +15,21 @@ interface ErrorInfo { imports: [], }) export class ValidatorComponent extends BaseComponent implements OnInit { - control = input.required(); + control = input.required(); - errorKey?: string; - errorValue?: ErrorInfo; + errorKey = signal(''); + errorValue = signal(null); ngOnInit(): void { this.addSubscription(merge(of(this.control().dirty), this.control().statusChanges).subscribe( () => { - if (!this.control().errors) return; - this.errorKey = Object.keys(this.control().errors!)[0]; - this.errorValue = this.control().errors![this.errorKey]; + if (!this.control().errors) { + this.errorKey.set(''); + this.errorValue.set(null); + return; + } + this.errorKey.set(Object.keys(this.control().errors!)[0]); + this.errorValue.set(this.control().errors![this.errorKey()] as ErrorInfo); } )); } diff --git a/frontend/Exence/src/styles/components/badge.scss b/frontend/Exence/src/styles/components/badge.scss new file mode 100644 index 0000000..c0e343c --- /dev/null +++ b/frontend/Exence/src/styles/components/badge.scss @@ -0,0 +1,7 @@ +.mat-badge-medium.mat-badge-overlap span.mat-badge-content { + --mat-badge-container-overlap-offset: -10px; + --mat-badge-text-size: 10px; + --mat-badge-container-padding: 1px 7px; + --mat-badge-background-color: var(--default-text-color); + --mat-badge-text-color: var(--secondary-text-color); +} \ No newline at end of file diff --git a/frontend/Exence/src/styles/components/bottom-sheet.scss b/frontend/Exence/src/styles/components/bottom-sheet.scss new file mode 100644 index 0000000..a933df6 --- /dev/null +++ b/frontend/Exence/src/styles/components/bottom-sheet.scss @@ -0,0 +1,7 @@ +mat-bottom-sheet-container.mat-bottom-sheet-container { + --mat-bottom-sheet-container-background-color: var(--app-card-color); + --mat-bottom-sheet-container-text-color: var(--default-text-color); + + position: relative; + overflow: hidden; +} \ No newline at end of file diff --git a/frontend/Exence/src/styles/components/error.scss b/frontend/Exence/src/styles/components/error.scss new file mode 100644 index 0000000..98b9c38 --- /dev/null +++ b/frontend/Exence/src/styles/components/error.scss @@ -0,0 +1,4 @@ +mat-error.mat-mdc-form-field-error { + --mat-form-field-error-text-color: var(--error-color); + font-weight: 600; +} \ No newline at end of file diff --git a/frontend/Exence/src/styles/components/form-field.scss b/frontend/Exence/src/styles/components/form-field.scss index c59a573..da120ce 100644 --- a/frontend/Exence/src/styles/components/form-field.scss +++ b/frontend/Exence/src/styles/components/form-field.scss @@ -64,4 +64,23 @@ mat-error { .mat-mdc-form-field-icon-suffix { margin-right: 0.5rem; +} + +mat-form-field.mat-mdc-form-field.search { + --mat-form-field-container-height: 32px; + --mat-form-field-outlined-outline-width: 1px; + --mat-form-field-container-vertical-padding: 1px; + --mat-form-field-outlined-container-shape: 20px; + + .mat-mdc-form-field-infix { + min-height: unset; + padding: unset; + } + + .mat-mdc-form-field-flex { + height: 100%; + display: flex; + align-items: center; + padding-left: 0.5rem; + } } \ No newline at end of file diff --git a/frontend/Exence/src/styles/styles.scss b/frontend/Exence/src/styles/styles.scss index 5aedb74..9259d5a 100644 --- a/frontend/Exence/src/styles/styles.scss +++ b/frontend/Exence/src/styles/styles.scss @@ -15,6 +15,9 @@ @import './components/dialog.scss'; @import './components/divider.scss'; @import './components/snackbar.scss'; +@import './components/badge.scss'; +@import './components/error.scss'; +@import './components/bottom-sheet.scss'; @import './fonts/material-icons.scss'; * {