Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 0 additions & 4 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
<div *ngIf="offline" class="offline">
<span>offline</span>
</div>

<router-outlet></router-outlet>

<app-chat-contact-admin-pop-up></app-chat-contact-admin-pop-up>
11 changes: 0 additions & 11 deletions src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
@import '../typography/typography';

.offline {
top: 50px;
left: 50%;
position: fixed;
font-weight: 500;
font-size: larger;
background: transparent;
color: var(--error-red);
z-index: 999;
}

::ng-deep .mat-select:focus-visible {
outline: 2px solid currentcolor !important;
}
Expand Down
18 changes: 17 additions & 1 deletion src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { SwUpdate } from '@angular/service-worker';
import { MatSnackBarService } from '@global-service/mat-snack-bar/mat-snack-bar.service';

export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient);
Expand All @@ -19,6 +20,7 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let matSnackBarMock: jasmine.SpyObj<MatSnackBarService>;

const localStorageMock = jasmine.createSpyObj('LocalStorageService', [
'userIdBehaviourSubject',
Expand All @@ -32,6 +34,7 @@ describe('AppComponent', () => {
const metaServiceMock = jasmine.createSpyObj('MetaService', ['setMetaOnRouteChange']);

beforeEach(waitForAsync(() => {
matSnackBarMock = jasmine.createSpyObj('MatSnackBarService', ['openSnackBar']);
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
Expand All @@ -49,7 +52,8 @@ describe('AppComponent', () => {
provideMockStore(),
{ provide: LocalStorageService, useValue: localStorageMock },
{ provide: MetaService, useValue: metaServiceMock },
{ provide: SwUpdate, useValue: {} }
{ provide: SwUpdate, useValue: {} },
{ provide: MatSnackBarService, useValue: matSnackBarMock }
],
declarations: [AppComponent]
}).compileComponents();
Expand All @@ -64,4 +68,16 @@ describe('AppComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});

it('should show snackbar when network is offline', () => {
spyOnProperty(navigator, 'onLine', 'get').and.returnValue(false);
component.onNetworkStatusChange();
expect(matSnackBarMock.openSnackBar).toHaveBeenCalledWith('noInternet');
});

it('should NOT show snackbar when network is online', () => {
spyOnProperty(navigator, 'onLine', 'get').and.returnValue(true);
component.onNetworkStatusChange();
expect(matSnackBarMock.openSnackBar).not.toHaveBeenCalled();
});
});
7 changes: 5 additions & 2 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { filter, Subject } from 'rxjs';
import { LocalStorageService } from 'src/app/shared/services/localstorage/local-storage.service';
import { MetaService } from 'src/app/shared/services/meta/meta.service';
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
import { MatSnackBarService } from '@global-service/mat-snack-bar/mat-snack-bar.service';

@Component({
selector: 'app-root',
Expand All @@ -21,7 +22,7 @@ export class AppComponent implements OnInit, OnDestroy {
private readonly destroy$: Subject<void> = new Subject<void>();
router: Router = inject(Router);
metaService: MetaService = inject(MetaService);
offline: boolean;
private readonly snackBar = inject(MatSnackBarService);

ngOnInit(): void {
this.metaService.setMetaOnRouteChange();
Expand All @@ -45,7 +46,9 @@ export class AppComponent implements OnInit, OnDestroy {
}

onNetworkStatusChange(): void {
this.offline = !navigator.onLine;
if (!navigator.onLine) {
this.snackBar.openSnackBar('noInternet');
}
}

ngOnDestroy(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
<th id="head" mat-header-cell *matHeaderCellDef [appResizeColumn]="{ resizable: true, index: i }">
<div class="columns_header">
<span>{{ column.title | serverTranslate: currentLang }}</span>
<mat-icon *ngIf="arrowDirection !== column.title.key" (click)="onSortTable(column.title.key, 'DESC')">
<mat-icon *ngIf="arrowDirection !== column.title.key" (click)="onSortTable(column.title.key, 'ASC')">
arrow_downward
</mat-icon>
<mat-icon *ngIf="arrowDirection === column.title.key" (click)="onSortTable(column.title.key, 'ASC')"> arrow_upward </mat-icon>
<mat-icon *ngIf="arrowDirection === column.title.key" (click)="onSortTable(column.title.key, 'DESC')">
arrow_upward
</mat-icon>
</div>
</th>
<td mat-cell *matCellDef="let row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@
</div>
</div>
</div>
<div class="tag-filtrs-list" *ngIf="activeFilters.length">
<div class="tag-filter-item" *ngFor="let filter of activeFilters">
<div class="remove-item-btn" (click)="removeActiveFilter(filter)"></div>
<span class="filter-content">{{ filter.labelKey | translate }} {{ filter.valueText }}</span>
</div>
</div>

<div id="table-container" class="scrolling" infiniteScroll [infiniteScrollThrottle]="100" (scrolled)="onScroll()" [scrollWindow]="false">
<mat-table [dataSource]="dataSource" id="table" class="customers_table" *ngIf="!isLoading" cdkDropListGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,38 @@ button:disabled {
background-color: var(--ubs-primary-light-grey);
border-color: var(--ubs-quaternary-light-grey);
}

.tag-filtrs-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
margin-bottom: 10px;
}

.tag-filter-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 2px 6px;
border-radius: 4px;
font-size: 12px;
line-height: 16px;
max-width: fit-content;
}

.remove-item-btn {
width: 6px;
height: 6px;
margin-left: 1px;
margin-right: 5px;
background-image: url('/assets/img/ubs-admin-employees/cross.svg');
background-size: contain;
background-repeat: no-repeat;
cursor: pointer;
}

.filter-content {
color: var(--ubs-dark-purple);
white-space: nowrap;
}
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,27 @@ describe('UbsAdminCustomersComponent', () => {
expect((component as any)['getTable']).toHaveBeenCalledTimes(1);
});

it('should remove active filter and reset form controls', () => {
spyOn(component, 'submitFilterForm');
component.activeFilters = [
{
key: 'bonuses',
labelKey: 'ubs-customer-filters.bonuses',
valueText: 'from 10 to 20',
fromControl: 'bonusesFrom',
toControl: 'bonusesTo'
}
];
component.filterForm.patchValue({
bonusesFrom: 10,
bonusesTo: 20
});
component.removeActiveFilter(component.activeFilters[0]);
expect(component.activeFilters.length).toBe(0);
expect(component.filterForm.value.bonusesFrom).toBe('');
expect(component.filterForm.value.bonusesTo).toBe('');
});

it('should clear all filters and submit form', () => {
component.filterForm.get('bonusesFrom').setValue('10');
spyOn(component, 'submitFilterForm').and.callThrough();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import { ClientStatusEnum } from '@ubs/ubs/enums/client-status.enum';
import { MatSelectChange } from '@angular/material/select';
import { IAppState } from '../../../../store/state/app.state';
import { ColumnParam, columnsParams } from '@ubs/ubs-admin/components/ubs-admin-customers/columnsParams.mock';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';

export const CUSTOM_DATE_FORMATS = {
parse: {
Expand Down Expand Up @@ -78,6 +80,7 @@ export class UbsAdminCustomersComponent implements OnInit, AfterViewChecked, OnD
enterPressed: boolean;
adminTableOfCustomersSelector$ = this.store.select(adminTableOfCustomersSelector);
tableData: any[];
activeFilters: Array<{key: string; labelKey: string;valueText: string; fromControl: string; toControl: string;}> = [];
readonly customerStatus = Object.values(ClientStatusEnum);
private sortType: string;
private sortingColumn: string;
Expand Down Expand Up @@ -111,7 +114,8 @@ export class UbsAdminCustomersComponent implements OnInit, AfterViewChecked, OnD
private readonly convertFromDateToStringService: ConvertFromDateToStringService,
private readonly localStorageService: LocalStorageService,
private readonly tableHeightService: TableHeightService,
private readonly adminCustomerService: AdminCustomersService
private readonly adminCustomerService: AdminCustomersService,
private readonly translate: TranslateService
) {}

ngOnInit() {
Expand Down Expand Up @@ -256,7 +260,94 @@ export class UbsAdminCustomersComponent implements OnInit, AfterViewChecked, OnD
this.currentPage = 0;
this.getTable();
}
}
this.buildActiveFilters();
}

private buildActiveFilters(): void {
this.activeFilters = [];

const map = [
{
key: 'registrationDate',
label: 'ubs-customer-filters.registration-date',
from: 'registrationDateFrom',
to: 'registrationDateTo',
isDate: true
},
{
key: 'lastOrderDate',
label: 'ubs-customer-filters.last-order-date',
from: 'lastOrderDateFrom',
to: 'lastOrderDateTo',
isDate: true
},
{
key: 'ordersCount',
label: 'ubs-customer-filters.orders-amount',
from: 'ordersCountFrom',
to: 'ordersCountTo'
},
{
key: 'violations',
label: 'ubs-customer-filters.violations',
from: 'violationsFrom',
to: 'violationsTo'
},
{
key: 'bonuses',
label: 'ubs-customer-filters.bonuses',
from: 'bonusesFrom',
to: 'bonusesTo'
}
];

const localeMap = {
uk: 'uk-UA',
en: 'en-GB'
};
const locale = localeMap[this.currentLang] || this.currentLang;
const datePipe = new DatePipe(locale);

map.forEach((f) => {
let from = this.filterForm.get(f.from).value;
let to = this.filterForm.get(f.to).value;

if (from || to) {
const fromText = this.translate.instant('ubs-customer-filters.from').toLowerCase();
const toText = this.translate.instant('ubs-customer-filters.to').toLowerCase();

if (f.isDate) {
from = from ? datePipe.transform(new Date(from), 'dd/MM/yyyy') : from;
to = to ? datePipe.transform(new Date(to), 'dd/MM/yyyy') : to;
}

let valueText = '';

if (from && to) {
valueText = `${fromText} ${from} ${toText} ${to}`;
} else if (from) {
valueText = `${fromText} ${from}`;
} else if (to) {
valueText = `${toText} ${to}`;
}

this.activeFilters.push({
key: f.key,
labelKey: f.label,
valueText,
fromControl: f.from,
toControl: f.to
});
}
});
}

removeActiveFilter(filter): void {
this.filterForm.get(filter.fromControl).setValue('');
this.filterForm.get(filter.toControl).setValue('');
this.activeFilters = this.activeFilters.filter(f => f.key !== filter.key);
this.submitFilterForm();
}

onDeleteFilter(filterFrom: string, filterTo: string) {
this.filterForm.get(filterFrom).setValue('');
Expand Down
Loading