mirror of
https://github.com/valitydev/dashboard.git
synced 2024-11-06 10:35:21 +00:00
Integrate daterange filter into reports module (#273)
This commit is contained in:
parent
8cf96c561f
commit
90a29f1b7c
@ -24,16 +24,15 @@ export class ReportsService {
|
||||
return this.reportsService.getReport(genXRequestID(), reportID);
|
||||
}
|
||||
|
||||
searchReports({ fromTime, toTime, reportTypes, shopIDs, continuationToken }: SearchReportsReq) {
|
||||
console.warn('Skip types, return after backend fix', reportTypes);
|
||||
searchReports({ fromTime, toTime, reportTypes, continuationToken }: SearchReportsReq) {
|
||||
return this.reportsService.searchReports(
|
||||
genXRequestID(),
|
||||
toDateLike(fromTime),
|
||||
toDateLike(toTime),
|
||||
['paymentRegistry', 'provisionOfService'],
|
||||
reportTypes,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
shopIDs,
|
||||
continuationToken
|
||||
);
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './filter-shops';
|
@ -1 +0,0 @@
|
||||
export * from './filter';
|
@ -19,7 +19,6 @@ import { LayoutModule } from '@dsh/components/layout';
|
||||
import { StateNavModule } from '@dsh/components/navigation';
|
||||
import { TableModule } from '@dsh/components/table';
|
||||
|
||||
import { FilterShopsModule } from '../../../../components';
|
||||
import { LanguageModule } from '../../../../language';
|
||||
import { ToMajorModule } from '../../../../to-major';
|
||||
import { ShopSelectorModule } from '../../../shop-selector';
|
||||
@ -53,7 +52,6 @@ import { TableComponent } from './table';
|
||||
RangeDatepickerModule,
|
||||
EmptySearchResultModule,
|
||||
ShopSelectorModule,
|
||||
FilterShopsModule,
|
||||
FiltersModule,
|
||||
],
|
||||
declarations: [PaymentsComponent, SearchFormComponent, PaymentStatusColorPipe, TableComponent],
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable, of, Subject } from 'rxjs';
|
||||
import { first, map, pluck, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { map, pluck, shareReplay, switchMap, take } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class ExpandedIdManager<T extends { id: string | number }> {
|
||||
@ -10,7 +10,7 @@ export class ExpandedIdManager<T extends { id: string | number }> {
|
||||
data$: Observable<T[]> = of([]);
|
||||
|
||||
expandedId$: Observable<number> = this.route.fragment.pipe(
|
||||
first(),
|
||||
take(1),
|
||||
switchMap((fragment) => this.data$.pipe(map((d) => d.findIndex(({ id }) => id + '' === fragment)))),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
@ -0,0 +1,25 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { ReportsService as ReportsApiService } from '../../../api';
|
||||
import { Report } from '../../../api-codegen/anapi';
|
||||
import { booleanDebounceTime } from '../../../custom-operators';
|
||||
import { PartialFetcher } from '../../partial-fetcher';
|
||||
import { mapToTimestamp } from '../operations/operators';
|
||||
import { SearchFiltersParams } from './reports-search-filters';
|
||||
|
||||
@Injectable()
|
||||
export class FetchReportsService extends PartialFetcher<Report, SearchFiltersParams> {
|
||||
isLoading$: Observable<boolean> = this.doAction$.pipe(booleanDebounceTime(), shareReplay(1));
|
||||
lastUpdated$: Observable<string> = this.searchResult$.pipe(mapToTimestamp, shareReplay(1));
|
||||
|
||||
constructor(private reportsService: ReportsApiService) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected fetch(params: SearchFiltersParams, continuationToken: string) {
|
||||
const reportTypes = ['paymentRegistry', 'provisionOfService'] as Report.ReportTypeEnum[];
|
||||
return this.reportsService.searchReports({ ...params, reportTypes, continuationToken });
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { ExpandedIdManager } from '@dsh/app/shared/services';
|
||||
|
||||
import { Report } from '../../../api-codegen/anapi';
|
||||
import { FetchReportsService } from './fetch-reports.service';
|
||||
|
||||
@Injectable()
|
||||
export class PayoutsExpandedIdManager extends ExpandedIdManager<Report> {
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
private fetchReportsService: FetchReportsService
|
||||
) {
|
||||
super(route, router);
|
||||
}
|
||||
|
||||
protected get dataSet$(): Observable<Report[]> {
|
||||
return this.fetchReportsService.searchResult$;
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ export class ReportFilesComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.reportFilesService.errorOccurred$.subscribe(() =>
|
||||
this.snackBar.open(this.transloco.translate('commonError', null, 'reports|scoped'), 'OK', {
|
||||
this.snackBar.open(this.transloco.translate('errors.downloadReportError', null, 'reports|scoped'), 'OK', {
|
||||
duration: 2000,
|
||||
})
|
||||
);
|
||||
|
@ -20,7 +20,9 @@
|
||||
>{{ report.fromTime | date: 'dd MMMM yyyy, HH:mm' }} -
|
||||
{{ report.toTime | date: 'dd MMMM yyyy, HH:mm' }}</dsh-details-item
|
||||
>
|
||||
<dsh-shop-details-item *ngIf="report?.shopID" [shopID]="report?.shopID"></dsh-shop-details-item>
|
||||
<dsh-details-item *ngIf="report?.shopID" [title]="t.shop">
|
||||
{{ report?.shopID | shopDetails }}
|
||||
</dsh-details-item>
|
||||
<mat-divider></mat-divider>
|
||||
<dsh-report-files [reportID]="report.id" [files]="report.files"></dsh-report-files>
|
||||
</div>
|
||||
|
@ -6,13 +6,13 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { ApiModelRefsModule } from '@dsh/app/shared/pipes';
|
||||
import { ButtonModule } from '@dsh/components/buttons';
|
||||
import { IndicatorsModule } from '@dsh/components/indicators';
|
||||
import { LayoutModule } from '@dsh/components/layout';
|
||||
|
||||
import { ReportsModule } from '../../../../api';
|
||||
import { ReportFilesModule } from '../report-files';
|
||||
import { ShopDetailsItemModule } from '../shop-details-item';
|
||||
import { ReportDetailsComponent } from './report-details';
|
||||
import { ReportRowComponent } from './report-row';
|
||||
import { ReportRowHeaderComponent } from './report-row-header';
|
||||
@ -32,9 +32,9 @@ import { ReportsListComponent } from './reports-list.component';
|
||||
CommonModule,
|
||||
MatSnackBarModule,
|
||||
MatDividerModule,
|
||||
ShopDetailsItemModule,
|
||||
ReportFilesModule,
|
||||
IndicatorsModule,
|
||||
ApiModelRefsModule,
|
||||
],
|
||||
declarations: [
|
||||
ReportsListComponent,
|
||||
|
@ -0,0 +1,21 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
|
||||
import { QueryParamsStore } from '@dsh/app/shared/services';
|
||||
|
||||
import { SearchFiltersParams } from './reports-search-filters';
|
||||
|
||||
@Injectable()
|
||||
export class ReportsSearchFiltersStore extends QueryParamsStore<SearchFiltersParams> {
|
||||
constructor(protected route: ActivatedRoute, protected router: Router) {
|
||||
super(router, route);
|
||||
}
|
||||
|
||||
mapToData(queryParams: Params): SearchFiltersParams {
|
||||
return queryParams as SearchFiltersParams;
|
||||
}
|
||||
|
||||
mapToParams(data: SearchFiltersParams): Params {
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { Daterange } from '@dsh/pipes/daterange';
|
||||
|
||||
import { SearchFiltersParams } from './search-filters-params';
|
||||
|
||||
export const daterangeToSearchFilterParams = ({ begin, end }: Daterange): SearchFiltersParams => ({
|
||||
fromTime: begin.utc().format(),
|
||||
toTime: end.utc().format(),
|
||||
});
|
@ -0,0 +1,8 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import { Daterange } from '@dsh/pipes/daterange';
|
||||
|
||||
export const getDefaultDaterange = (): Daterange => ({
|
||||
begin: moment().startOf('M'),
|
||||
end: moment().endOf('M'),
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
export * from './reports-search-filters.module';
|
||||
export * from './reports-search-filters.component';
|
||||
export * from './search-filters-params';
|
@ -0,0 +1,12 @@
|
||||
<div
|
||||
*transloco="let t; scope: 'reports'; read: 'reports.searchFilters'"
|
||||
fxLayout="row"
|
||||
fxLayoutGap="16px"
|
||||
fxLayoutAlign="center center"
|
||||
>
|
||||
<div class="dsh-body-1">{{ t.dateRangeDescription }}:</div>
|
||||
<dsh-daterange-filter
|
||||
[selected]="daterange"
|
||||
(selectedChange)="daterangeSelectionChange($event)"
|
||||
></dsh-daterange-filter>
|
||||
</div>
|
@ -0,0 +1,44 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
|
||||
import { Daterange } from '@dsh/pipes/daterange';
|
||||
|
||||
import { daterangeToSearchFilterParams } from './daterange-to-search-filter-params';
|
||||
import { getDefaultDaterange } from './get-default-daterange';
|
||||
import { searchFilterParamsToDaterange } from './search-filter-params-to-daterange';
|
||||
import { SearchFiltersParams } from './search-filters-params';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-reports-search-filters',
|
||||
templateUrl: 'reports-search-filters.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ReportsSearchFiltersComponent implements OnChanges {
|
||||
@Input() initParams: SearchFiltersParams;
|
||||
@Output() searchParamsChanges: EventEmitter<SearchFiltersParams> = new EventEmitter();
|
||||
|
||||
daterange: Daterange;
|
||||
|
||||
ngOnChanges({ initParams }: SimpleChanges) {
|
||||
if (initParams && initParams.firstChange && initParams.currentValue) {
|
||||
const v = initParams.currentValue;
|
||||
this.daterange = !(v.fromTime || v.toTime) ? getDefaultDaterange() : searchFilterParamsToDaterange(v);
|
||||
this.daterangeSelectionChange(this.daterange);
|
||||
}
|
||||
}
|
||||
|
||||
daterangeSelectionChange(v: Daterange | null) {
|
||||
const daterange = v === null ? getDefaultDaterange() : v;
|
||||
if (v === null) {
|
||||
this.daterange = daterange;
|
||||
}
|
||||
this.searchParamsChanges.emit(daterangeToSearchFilterParams(daterange));
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { FiltersModule } from '@dsh/components/filters';
|
||||
|
||||
import { ReportsSearchFiltersComponent } from './reports-search-filters.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, TranslocoModule, FiltersModule, FlexLayoutModule],
|
||||
declarations: [ReportsSearchFiltersComponent],
|
||||
exports: [ReportsSearchFiltersComponent],
|
||||
})
|
||||
export class ReportsSearchFiltersModule {}
|
@ -0,0 +1,10 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import { Daterange } from '@dsh/pipes/daterange';
|
||||
|
||||
import { SearchFiltersParams } from './search-filters-params';
|
||||
|
||||
export const searchFilterParamsToDaterange = ({ fromTime, toTime }: SearchFiltersParams): Daterange => ({
|
||||
begin: moment(fromTime),
|
||||
end: moment(toTime),
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
export interface SearchFiltersParams {
|
||||
fromTime: string;
|
||||
toTime: string;
|
||||
}
|
@ -1,16 +1,14 @@
|
||||
<div class="dsh-reports" *transloco="let r; scope: 'reports'; read: 'reports'" fxLayout="column" fxLayoutGap="32px">
|
||||
<h1 class="dsh-display-1">{{ r.title }}</h1>
|
||||
<div fxLayout="row" fxLayoutGap="24px">
|
||||
<div fxFlex class="dsh-body-1">
|
||||
{{ r.description }}
|
||||
</div>
|
||||
<div>
|
||||
<button dsh-button color="accent" (click)="create()">
|
||||
{{ r.create.button }}
|
||||
</button>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutAlign="space-between">
|
||||
<dsh-reports-search-filters
|
||||
[initParams]="initSearchParams$ | async"
|
||||
(searchParamsChanges)="searchParamsChanges($event)"
|
||||
></dsh-reports-search-filters>
|
||||
<button dsh-button color="accent" (click)="create()">
|
||||
{{ r.create.button }}
|
||||
</button>
|
||||
</div>
|
||||
<dsh-reports-search-form></dsh-reports-search-form>
|
||||
<dsh-reports-list
|
||||
[expandedId]="expandedId$ | async"
|
||||
(expandedIdChange)="expandedIdChange($event)"
|
||||
@ -18,7 +16,9 @@
|
||||
[lastUpdated]="lastUpdated$ | async"
|
||||
(refreshData)="refresh()"
|
||||
></dsh-reports-list>
|
||||
<dsh-empty-search-result *ngIf="(reports$ | async)?.length === 0"></dsh-empty-search-result>
|
||||
<dsh-empty-search-result
|
||||
*ngIf="!(fetchErrors$ | async) && (reports$ | async)?.length === 0"
|
||||
></dsh-empty-search-result>
|
||||
<dsh-spinner *ngIf="isLoading$ | async" fxLayoutAlign="center"></dsh-spinner>
|
||||
</div>
|
||||
<dsh-scroll-up></dsh-scroll-up>
|
||||
|
@ -1,9 +1,4 @@
|
||||
.dsh-reports {
|
||||
max-width: 744px;
|
||||
margin: auto;
|
||||
|
||||
&-empty {
|
||||
padding-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +1,67 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { filter, shareReplay } from 'rxjs/operators';
|
||||
import { filter, pluck, take } from 'rxjs/operators';
|
||||
|
||||
import { Report } from '../../../api-codegen/anapi';
|
||||
import { booleanDebounceTime } from '../../../custom-operators';
|
||||
import { mapToTimestamp } from '../operations/operators';
|
||||
import { ShopService } from '../../../api';
|
||||
import { filterShopsByEnv, mapToShopInfo } from '../operations/operators';
|
||||
import { CreateReportDialogComponent } from './create-report-dialog';
|
||||
import { ExpandedIdManager } from './expanded-id-manager.service';
|
||||
import { ReportsService } from './reports.service';
|
||||
import { FetchReportsService } from './fetch-reports.service';
|
||||
import { PayoutsExpandedIdManager } from './payouts-expanded-id-manager.service';
|
||||
import { SearchFiltersParams } from './reports-search-filters';
|
||||
import { ReportsSearchFiltersStore } from './reports-search-filters-store.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-reports',
|
||||
templateUrl: 'reports.component.html',
|
||||
styleUrls: ['reports.component.scss'],
|
||||
providers: [ReportsService, ExpandedIdManager],
|
||||
providers: [FetchReportsService, ReportsSearchFiltersStore, PayoutsExpandedIdManager],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ReportsComponent {
|
||||
reports$ = this.reportsService.searchResult$;
|
||||
isLoading$ = this.reportsService.doAction$.pipe(booleanDebounceTime(), shareReplay(1));
|
||||
lastUpdated$ = this.reportsService.searchResult$.pipe(mapToTimestamp, shareReplay(1));
|
||||
expandedId$ = this.expandedIdManager.expandedId$;
|
||||
export class ReportsComponent implements OnInit {
|
||||
reports$ = this.fetchReportsService.searchResult$;
|
||||
isLoading$ = this.fetchReportsService.isLoading$;
|
||||
lastUpdated$ = this.fetchReportsService.lastUpdated$;
|
||||
expandedId$ = this.payoutsExpandedIdManager.expandedId$;
|
||||
initSearchParams$ = this.reportsSearchFiltersStore.data$.pipe(take(1));
|
||||
fetchErrors$ = this.fetchReportsService.errors$;
|
||||
|
||||
private shopsInfo$ = this.route.params.pipe(
|
||||
pluck('envID'),
|
||||
filterShopsByEnv(this.shopService.shops$),
|
||||
mapToShopInfo
|
||||
);
|
||||
|
||||
constructor(
|
||||
private reportsService: ReportsService,
|
||||
private fetchReportsService: FetchReportsService,
|
||||
private payoutsExpandedIdManager: PayoutsExpandedIdManager,
|
||||
private reportsSearchFiltersStore: ReportsSearchFiltersStore,
|
||||
private dialog: MatDialog,
|
||||
private snackBar: MatSnackBar,
|
||||
private transloco: TranslocoService,
|
||||
private expandedIdManager: ExpandedIdManager<Report>
|
||||
) {
|
||||
this.expandedIdManager.data$ = this.reports$;
|
||||
private shopService: ShopService,
|
||||
private route: ActivatedRoute
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.fetchReportsService.errors$.subscribe(() =>
|
||||
this.snackBar.open(this.transloco.translate('errors.fetchError', null, 'reports|scoped'), 'OK')
|
||||
);
|
||||
}
|
||||
|
||||
searchParamsChanges(p: SearchFiltersParams) {
|
||||
this.fetchReportsService.search(p);
|
||||
this.reportsSearchFiltersStore.preserve(p);
|
||||
}
|
||||
|
||||
expandedIdChange(id: number) {
|
||||
this.expandedIdManager.expandedIdChange(id);
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.reportsService.fetchMore();
|
||||
this.payoutsExpandedIdManager.expandedIdChange(id);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.reportsService.refresh();
|
||||
this.fetchReportsService.refresh();
|
||||
}
|
||||
|
||||
create() {
|
||||
@ -52,7 +70,7 @@ export class ReportsComponent {
|
||||
width: '560px',
|
||||
disableClose: true,
|
||||
data: {
|
||||
shopsInfo$: this.reportsService.shopsInfo$,
|
||||
shopsInfo$: this.shopsInfo$,
|
||||
},
|
||||
})
|
||||
.afterClosed()
|
||||
|
@ -23,9 +23,8 @@ import { ReportsModule as ReportsApiModule } from '../../../api';
|
||||
import { CreateReportDialogComponent } from './create-report-dialog';
|
||||
import { ReportsListModule } from './reports-list';
|
||||
import { ReportsRoutingModule } from './reports-routing.module';
|
||||
import { ReportsSearchFiltersModule } from './reports-search-filters';
|
||||
import { ReportsComponent } from './reports.component';
|
||||
import { SearchFormComponent } from './search-form';
|
||||
import { ShopDetailsItemModule } from './shop-details-item';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -49,10 +48,10 @@ import { ShopDetailsItemModule } from './shop-details-item';
|
||||
EmptySearchResultModule,
|
||||
MatDividerModule,
|
||||
ReportsListModule,
|
||||
ShopDetailsItemModule,
|
||||
ScrollUpModule,
|
||||
ReportsSearchFiltersModule,
|
||||
],
|
||||
declarations: [ReportsComponent, SearchFormComponent, CreateReportDialogComponent],
|
||||
declarations: [ReportsComponent, CreateReportDialogComponent],
|
||||
exports: [ReportsComponent],
|
||||
entryComponents: [CreateReportDialogComponent],
|
||||
})
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { pluck } from 'rxjs/operators';
|
||||
|
||||
import { ReportsService as ReportsApiService, ShopService } from '../../../api';
|
||||
import { Report } from '../../../api-codegen/anapi';
|
||||
import { PartialFetcher } from '../../partial-fetcher';
|
||||
import { filterShopsByEnv, mapToShopInfo } from '../operations/operators';
|
||||
import { SearchParams } from './search-params';
|
||||
|
||||
@Injectable()
|
||||
export class ReportsService extends PartialFetcher<Report, SearchParams> {
|
||||
shopsInfo$ = this.route.params.pipe(pluck('envID'), filterShopsByEnv(this.shopService.shops$), mapToShopInfo);
|
||||
|
||||
constructor(
|
||||
private reportsService: ReportsApiService,
|
||||
private route: ActivatedRoute,
|
||||
private shopService: ShopService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
protected fetch(params: SearchParams, continuationToken: string) {
|
||||
return this.reportsService.searchReports({ ...params, continuationToken });
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import { Range } from '@dsh/components/form-controls';
|
||||
|
||||
import { Report } from '../../../../api-codegen/anapi';
|
||||
|
||||
export interface FormParams {
|
||||
date: Range;
|
||||
reportType: Report.ReportTypeEnum;
|
||||
shopIDs?: string[];
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './search-form.component';
|
@ -1,8 +0,0 @@
|
||||
import { Report } from '../../../../api-codegen/anapi';
|
||||
|
||||
export interface QueryParams {
|
||||
fromTime: string;
|
||||
toTime: string;
|
||||
reportType: Report.ReportTypeEnum;
|
||||
shopIDs?: string[];
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<dsh-float-panel *transloco="let r; scope: 'reports'; read: 'reports'">
|
||||
<form *transloco="let c" [formGroup]="form">
|
||||
<dsh-justify-wrapper
|
||||
fxLayout
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutAlign="space-between center"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutAlign.lt-md="space-between stretch"
|
||||
>
|
||||
<dsh-range-datepicker formControlName="date" fxFlex></dsh-range-datepicker>
|
||||
<dsh-shop-selector formControlName="shopIDs" fxFlex></dsh-shop-selector>
|
||||
</dsh-justify-wrapper>
|
||||
<dsh-float-panel-actions>
|
||||
<button dsh-button (click)="reset()">
|
||||
{{ c.resetSearchParams }}
|
||||
</button>
|
||||
</dsh-float-panel-actions>
|
||||
<dsh-float-panel-more>
|
||||
<mat-form-field fxFlexFill>
|
||||
<mat-label>{{ r.filter.type }}</mat-label>
|
||||
<mat-select formControlName="reportType">
|
||||
<mat-option>
|
||||
{{ c.any }}
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let type of reportTypes" [value]="type">
|
||||
{{ r.type[type] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</dsh-float-panel-more>
|
||||
</form>
|
||||
</dsh-float-panel>
|
@ -1,17 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { Report } from '../../../../api-codegen/anapi/swagger-codegen';
|
||||
import { SearchFormService } from './search-form.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-reports-search-form',
|
||||
templateUrl: 'search-form.component.html',
|
||||
providers: [SearchFormService],
|
||||
})
|
||||
export class SearchFormComponent {
|
||||
form = this.searchFormService.form;
|
||||
reset = this.searchFormService.reset;
|
||||
reportTypes = Object.values(Report.ReportTypeEnum);
|
||||
|
||||
constructor(private searchFormService: SearchFormService) {}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import moment from 'moment';
|
||||
import { filter, pluck, take } from 'rxjs/operators';
|
||||
|
||||
import { RouteEnv } from '../../../route-env';
|
||||
import { ReportsService } from '../reports.service';
|
||||
import { FormParams } from './form-params';
|
||||
import { QueryParams } from './query-params';
|
||||
import { toFormValue } from './to-form-value';
|
||||
import { toQueryParams } from './to-query-params';
|
||||
import { toSearchParams } from './to-search-params';
|
||||
|
||||
@Injectable()
|
||||
export class SearchFormService {
|
||||
defaultParams: FormParams = {
|
||||
shopIDs: [],
|
||||
reportType: null,
|
||||
date: {
|
||||
begin: moment().startOf('month'),
|
||||
end: moment().endOf('month'),
|
||||
},
|
||||
};
|
||||
|
||||
form = this.fb.group(this.defaultParams);
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private reportsService: ReportsService
|
||||
) {
|
||||
this.init();
|
||||
}
|
||||
|
||||
search(value = this.form.value) {
|
||||
this.reportsService.search(toSearchParams(value));
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.form.setValue(this.defaultParams);
|
||||
}
|
||||
|
||||
private init() {
|
||||
this.route.params
|
||||
.pipe(
|
||||
pluck('envID'),
|
||||
take(1),
|
||||
filter((e) => e === RouteEnv.test)
|
||||
)
|
||||
.subscribe(() => this.form.controls.shopIDs.disable());
|
||||
this.syncQueryParams();
|
||||
this.search();
|
||||
this.form.valueChanges.subscribe((v) => this.search(v));
|
||||
}
|
||||
|
||||
private syncQueryParams() {
|
||||
const queryParams = this.route.snapshot.queryParams as QueryParams;
|
||||
const formValue = toFormValue(queryParams, this.defaultParams);
|
||||
this.form.setValue(formValue);
|
||||
this.setQueryParams(formValue);
|
||||
this.form.valueChanges.subscribe((v) => this.setQueryParams(v));
|
||||
}
|
||||
|
||||
private setQueryParams(formValue: FormParams) {
|
||||
const queryParams = toQueryParams(formValue);
|
||||
this.router.navigate([location.pathname], { queryParams, preserveFragment: true });
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import { Report } from '../../../../api-codegen/anapi/swagger-codegen';
|
||||
import { FormParams } from './form-params';
|
||||
import { QueryParams } from './query-params';
|
||||
|
||||
export function toFormValue(
|
||||
{ fromTime, toTime, reportType, shopIDs, ...params }: QueryParams,
|
||||
defaultParams: FormParams
|
||||
): FormParams {
|
||||
return {
|
||||
...defaultParams,
|
||||
...params,
|
||||
shopIDs: shopIDs ? (Array.isArray(shopIDs) ? shopIDs : [shopIDs]) : null,
|
||||
date: {
|
||||
begin: fromTime ? moment(fromTime) : defaultParams.date.begin,
|
||||
end: toTime ? moment(toTime) : defaultParams.date.end,
|
||||
},
|
||||
reportType: reportType ? (reportType as Report.ReportTypeEnum) : defaultParams.reportType,
|
||||
};
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { FormParams } from './form-params';
|
||||
import { QueryParams } from './query-params';
|
||||
|
||||
export function toQueryParams({ date, shopIDs, ...params }: FormParams): QueryParams {
|
||||
return {
|
||||
...params,
|
||||
shopIDs: shopIDs?.length ? shopIDs : null,
|
||||
fromTime: date.begin.utc().format(),
|
||||
toTime: date.end.utc().format(),
|
||||
};
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { Report } from '../../../../api-codegen/anapi';
|
||||
import { SearchParams } from '../search-params';
|
||||
import { FormParams } from './form-params';
|
||||
|
||||
export function toSearchParams({ reportType, date, shopIDs, ...params }: FormParams): SearchParams {
|
||||
return {
|
||||
...params,
|
||||
shopIDs: shopIDs?.length ? shopIDs : null,
|
||||
reportTypes: reportType ? [reportType] : Object.values(Report.ReportTypeEnum),
|
||||
fromTime: date.begin.utc().format(),
|
||||
toTime: date.end.utc().format(),
|
||||
};
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { Report } from '../../../api-codegen/anapi';
|
||||
|
||||
export interface SearchParams {
|
||||
fromTime: string;
|
||||
toTime: string;
|
||||
reportTypes: Report.ReportTypeEnum[];
|
||||
shopIDs?: string[];
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './shop-details-item.module';
|
||||
export * from './shop-details-item.component';
|
@ -1 +0,0 @@
|
||||
<dsh-details-item *transloco="let t" [title]="t.shop">{{ shopName$ | async }}</dsh-details-item>
|
@ -1,20 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
|
||||
import { ShopDetailsItemService } from './shop-details-item.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-shop-details-item',
|
||||
templateUrl: 'shop-details-item.component.html',
|
||||
providers: [ShopDetailsItemService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShopDetailsItemComponent {
|
||||
@Input()
|
||||
set shopID(id: string) {
|
||||
this.shopDetailsItemService.setShopID(id);
|
||||
}
|
||||
|
||||
shopName$ = this.shopDetailsItemService.shopName$;
|
||||
|
||||
constructor(private shopDetailsItemService: ShopDetailsItemService) {}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { LayoutModule } from '@dsh/components/layout';
|
||||
|
||||
import { ShopDetailsItemComponent } from './shop-details-item.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, TranslocoModule, LayoutModule],
|
||||
declarations: [ShopDetailsItemComponent],
|
||||
exports: [ShopDetailsItemComponent],
|
||||
})
|
||||
export class ShopDetailsItemModule {}
|
@ -1,25 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { combineLatest, Observable, ReplaySubject, Subject } from 'rxjs';
|
||||
import { distinctUntilChanged, map, pluck, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { ShopService } from '../../../../api';
|
||||
|
||||
@Injectable()
|
||||
export class ShopDetailsItemService {
|
||||
private shopID$: Subject<string> = new ReplaySubject(1);
|
||||
|
||||
shopName$: Observable<string> = combineLatest([
|
||||
this.shopID$.pipe(distinctUntilChanged()),
|
||||
this.shopService.shops$,
|
||||
]).pipe(
|
||||
map(([shopID, shops]) => shops.find((s) => s.id === shopID)),
|
||||
pluck('details', 'name'),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(private shopService: ShopService) {}
|
||||
|
||||
setShopID(shopID: string) {
|
||||
this.shopID$.next(shopID);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
import { Shop } from '../../../api-codegen/capi';
|
||||
import { Shop } from '../../../../api-codegen/capi';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-filter-shops',
|
11
src/app/shared/components/filters/filters.module.ts
Normal file
11
src/app/shared/components/filters/filters.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { FilterShopsModule } from './filter-shops';
|
||||
|
||||
const EXPORTED_MODULES = [FilterShopsModule];
|
||||
|
||||
@NgModule({
|
||||
imports: EXPORTED_MODULES,
|
||||
exports: EXPORTED_MODULES,
|
||||
})
|
||||
export class FiltersModule {}
|
2
src/app/shared/components/filters/index.ts
Normal file
2
src/app/shared/components/filters/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './filters.module';
|
||||
export * from './filter-shops';
|
1
src/app/shared/components/index.ts
Normal file
1
src/app/shared/components/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './filters';
|
3
src/app/shared/index.ts
Normal file
3
src/app/shared/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './components';
|
||||
export * from './services';
|
||||
export * from './pipes';
|
@ -0,0 +1,9 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { ShopDetailsPipe } from './shop-details.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ShopDetailsPipe],
|
||||
exports: [ShopDetailsPipe],
|
||||
})
|
||||
export class ApiModelRefsModule {}
|
1
src/app/shared/pipes/api-model-refs/index.ts
Normal file
1
src/app/shared/pipes/api-model-refs/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './api-model-refs.module';
|
37
src/app/shared/pipes/api-model-refs/shop-details.pipe.ts
Normal file
37
src/app/shared/pipes/api-model-refs/shop-details.pipe.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { ChangeDetectorRef, OnDestroy, Pipe, PipeTransform } from '@angular/core';
|
||||
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
|
||||
import { distinctUntilChanged, map, pluck, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { ShopService } from '../../../api';
|
||||
|
||||
@Pipe({
|
||||
name: 'shopDetails',
|
||||
pure: false,
|
||||
})
|
||||
export class ShopDetailsPipe implements PipeTransform, OnDestroy {
|
||||
private shopName$: BehaviorSubject<string> = new BehaviorSubject('');
|
||||
private shopIDChange$: Subject<string> = new Subject();
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
|
||||
constructor(private shopService: ShopService, private ref: ChangeDetectorRef) {
|
||||
combineLatest([this.shopService.shops$, this.shopIDChange$.pipe(distinctUntilChanged())])
|
||||
.pipe(
|
||||
takeUntil(this.destroy$),
|
||||
map(([shops, shopID]) => shops.find((s) => s.id === shopID)),
|
||||
pluck('details', 'name')
|
||||
)
|
||||
.subscribe((v) => {
|
||||
this.shopName$.next(v);
|
||||
this.ref.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
transform(shopID: string): string {
|
||||
this.shopIDChange$.next(shopID);
|
||||
return this.shopName$.value;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
}
|
||||
}
|
1
src/app/shared/pipes/index.ts
Normal file
1
src/app/shared/pipes/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './api-model-refs';
|
40
src/app/shared/services/expanded-id-manager.ts
Normal file
40
src/app/shared/services/expanded-id-manager.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, pluck, shareReplay, switchMap, take } from 'rxjs/operators';
|
||||
|
||||
export type ExpandedID = number;
|
||||
|
||||
export type DataSetItemID = { id: string | number };
|
||||
|
||||
const dataIdToFragment = <T extends DataSetItemID>(id: T['id']): string => (!!id ? id + '' : '');
|
||||
|
||||
const byFragment = (fragment: string) => ({ id }: DataSetItemID) => id + '' === fragment;
|
||||
const findExpandedId = <T extends DataSetItemID>(fragment: string) => (d: T[]) => d.findIndex(byFragment(fragment));
|
||||
|
||||
export abstract class ExpandedIdManager<T extends DataSetItemID> {
|
||||
private expandedIdChange$: Subject<ExpandedID> = new Subject();
|
||||
|
||||
expandedId$: Observable<ExpandedID> = this.route.fragment.pipe(
|
||||
take(1),
|
||||
switchMap((fragment) => this.dataSet$.pipe(map(findExpandedId(fragment)))),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(protected route: ActivatedRoute, protected router: Router) {
|
||||
this.expandedIdChange$
|
||||
.pipe(
|
||||
switchMap((expandedId) => this.dataSet$.pipe(pluck(expandedId, 'id'))),
|
||||
map(dataIdToFragment)
|
||||
)
|
||||
.subscribe((fragment) => this.router.navigate([], { fragment, preserveQueryParams: true }));
|
||||
}
|
||||
|
||||
expandedIdChange(id: ExpandedID | null) {
|
||||
if (id === null) {
|
||||
return;
|
||||
}
|
||||
this.expandedIdChange$.next(id);
|
||||
}
|
||||
|
||||
protected abstract get dataSet$(): Observable<T[]>;
|
||||
}
|
2
src/app/shared/services/index.ts
Normal file
2
src/app/shared/services/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './query-params-store';
|
||||
export * from './expanded-id-manager';
|
22
src/app/shared/services/query-params-store.ts
Normal file
22
src/app/shared/services/query-params-store.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import isEqual from 'lodash.isequal';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
export abstract class QueryParamsStore<D> {
|
||||
data$: Observable<D> = this.route.queryParams.pipe(
|
||||
distinctUntilChanged(isEqual),
|
||||
map((p) => this.mapToData(p)),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(protected router: Router, protected route: ActivatedRoute) {}
|
||||
|
||||
abstract mapToData(queryParams: Params): D;
|
||||
|
||||
abstract mapToParams(data: D): Params;
|
||||
|
||||
preserve(data: D) {
|
||||
this.router.navigate([], { queryParams: this.mapToParams(data), preserveFragment: true });
|
||||
}
|
||||
}
|
@ -12,7 +12,8 @@
|
||||
"status": "Статус",
|
||||
"type": "Тип формирования",
|
||||
"createdAt": "Дата создания",
|
||||
"period": "Период отчетности"
|
||||
"period": "Период отчетности",
|
||||
"shop": "Магазин"
|
||||
},
|
||||
"status": {
|
||||
"created": "Сформирован",
|
||||
@ -23,20 +24,24 @@
|
||||
"downloadAll": "Загрузить все"
|
||||
},
|
||||
"errors": {
|
||||
"commonError": "Не удалось загрузить документы"
|
||||
"downloadReportError": "Не удалось загрузить документы",
|
||||
"fetchError": "Не удалось получить отчеты"
|
||||
},
|
||||
"type": {
|
||||
"provisionOfService": "Автоматический",
|
||||
"paymentRegistry": "Реестр операций",
|
||||
"paymentRegistryByPayout": "Реестр операций выплаты"
|
||||
},
|
||||
"searchFilters": {
|
||||
"dateRangeDescription": "Период создания отчетов"
|
||||
},
|
||||
|
||||
"filter": {
|
||||
"shopID": "Магазин",
|
||||
"type": "Тип формирования"
|
||||
},
|
||||
"create": {
|
||||
"button": "Сформировать отчет",
|
||||
"button": "Создать отчет",
|
||||
"success": "Отчет формируется",
|
||||
"dialog": {
|
||||
"title": "Параметры формирования отчета",
|
||||
|
@ -190,6 +190,5 @@
|
||||
"risk_score_is_too_high": "Операция с высоким риском"
|
||||
},
|
||||
"timeout": "Превышен лимит ожидания"
|
||||
},
|
||||
"shop": "Магазин"
|
||||
}
|
||||
}
|
||||
|
7
src/components/filters/daterange-filter/date-adapter.ts
Normal file
7
src/components/filters/daterange-filter/date-adapter.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { NativeDateAdapter } from '@angular/material/core';
|
||||
|
||||
export class DateAdapter extends NativeDateAdapter {
|
||||
getFirstDayOfWeek(): number {
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -65,6 +65,7 @@ export class DaterangeFilterComponent implements OnChanges {
|
||||
this.endCalendar.activeDate = end.toDate();
|
||||
}
|
||||
});
|
||||
this.savedSelected$.subscribe();
|
||||
}
|
||||
|
||||
ngOnChanges({ selected }: ComponentChanges<DaterangeFilterComponent>): void {
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { DateAdapter } from '@angular/material/core';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { DaterangeModule } from '@dsh/pipes/daterange';
|
||||
|
||||
import { FilterModule } from '../filter';
|
||||
import { DateAdapter as CustomDateAdapter } from './date-adapter';
|
||||
import { DaterangeFilterMenuComponent } from './daterange-filter-selector';
|
||||
import { DaterangeFilterComponent } from './daterange-filter.component';
|
||||
|
||||
@ -16,5 +18,6 @@ const EXPORTED_DECLARATIONS = [DaterangeFilterComponent, DaterangeFilterMenuComp
|
||||
imports: [CommonModule, FlexLayoutModule, FilterModule, TranslocoModule, DaterangeModule, MatDatepickerModule],
|
||||
declarations: EXPORTED_DECLARATIONS,
|
||||
exports: EXPORTED_DECLARATIONS,
|
||||
providers: [{ provide: DateAdapter, useClass: CustomDateAdapter }],
|
||||
})
|
||||
export class DaterangeFilterModule {}
|
||||
|
@ -1,6 +1,9 @@
|
||||
<dsh-filter-button [disabled]="disabled" [active]="active" [dshDropdownTriggerFor]="dropdown">
|
||||
{{ title }}
|
||||
</dsh-filter-button>
|
||||
<div class="button-wrapper" [ngClass]="{ 'button-wrapper-disabled': disabled }">
|
||||
<div class="dropdown-trigger" [dshDropdownTriggerFor]="dropdown"></div>
|
||||
<dsh-filter-button [disabled]="disabled" [active]="active">
|
||||
{{ title }}
|
||||
</dsh-filter-button>
|
||||
</div>
|
||||
|
||||
<dsh-dropdown #dropdown="dshDropdown" hasArrow="false" position="left" offset="16px 0 0" (closed)="closed.emit()">
|
||||
<ng-template>
|
||||
|
17
src/components/filters/filter/filter.component.scss
Normal file
17
src/components/filters/filter/filter.component.scss
Normal file
@ -0,0 +1,17 @@
|
||||
// Hack, the title won't always update with the dshDropdownTriggerFor
|
||||
.button-wrapper {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
&-disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dropdown-trigger {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import { coerceBoolean } from '../../../utils';
|
||||
@Component({
|
||||
selector: 'dsh-filter',
|
||||
templateUrl: 'filter.component.html',
|
||||
styleUrls: ['filter.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FilterComponent {
|
||||
|
@ -1,23 +1,29 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { ChangeDetectorRef, Pipe, PipeTransform } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { Daterange } from './daterange';
|
||||
import { DaterangeService } from './daterange.service';
|
||||
|
||||
@Pipe({ name: 'daterange' })
|
||||
@Pipe({ name: 'daterange', pure: false })
|
||||
export class DaterangePipe implements PipeTransform {
|
||||
private daterange$ = new BehaviorSubject<Partial<Daterange>>({});
|
||||
private result = '';
|
||||
|
||||
constructor(daterangeService: DaterangeService) {
|
||||
constructor(daterangeService: DaterangeService, private ref: ChangeDetectorRef) {
|
||||
this.daterange$
|
||||
.pipe(switchMap((daterange) => daterangeService.switchToDaterangeStr(daterange)))
|
||||
.subscribe((r) => (this.result = r));
|
||||
.pipe(
|
||||
switchMap((daterange) => daterangeService.switchToDaterangeStr(daterange)),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
.subscribe((r) => {
|
||||
this.result = r;
|
||||
this.ref.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
transform(daterange: Partial<Daterange>): string {
|
||||
this.daterange$.next(daterange || {});
|
||||
this.daterange$.next(daterange);
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ export class DaterangeService {
|
||||
constructor(@Inject(LOCALE_ID) private locale: string, private transloco: TranslocoService) {}
|
||||
|
||||
switchToDaterangeStr(daterange: Partial<Daterange>): Observable<string> {
|
||||
daterange = { begin: daterange?.begin?.local(), end: daterange?.end?.local() };
|
||||
if (!isDaterange(daterange)) {
|
||||
return of('');
|
||||
} else if (isYearsRange(daterange)) {
|
||||
|
@ -19,7 +19,8 @@
|
||||
"noUnusedParameters": true,
|
||||
"paths": {
|
||||
"@dsh/components/*": ["src/components/*"],
|
||||
"@dsh/pipes/*": ["src/pipes/*"]
|
||||
"@dsh/pipes/*": ["src/pipes/*"],
|
||||
"@dsh/app/shared/*": ["src/app/shared"]
|
||||
}
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
|
Loading…
Reference in New Issue
Block a user