Shops: show more (#207)

This commit is contained in:
Rinat Arsaev 2020-04-28 13:44:28 +03:00 committed by GitHub
parent ba4288009f
commit 3760ea9709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 25 deletions

@ -0,0 +1 @@
Subproject commit 9ebe453f77d7ffba9284d51669a60fb5d702d643

View File

@ -57,5 +57,5 @@
</dsh-timeline-item-content>
</dsh-timeline-item>
</dsh-timeline>
<!-- <dsh-send-comment (conversationSaved)="commentSaved($event)"></dsh-send-comment> -->
<dsh-send-comment (conversationSaved)="commentSaved($event)"></dsh-send-comment>
</div>

View File

@ -2,7 +2,7 @@
fxLayout="column"
fxLayoutGap="20px"
*transloco="let p; scope: 'shops'; read: 'shops.panel'"
[expanded]="selectedIdx$ | async"
[expanded]="selectedPanelPosition$ | async"
(expandedChange)="select($event)"
>
<dsh-expand-panel *ngFor="let shop of shops$ | async">
@ -65,4 +65,5 @@
</ng-container>
</dsh-expand-panel-more>
</dsh-expand-panel>
<dsh-show-more-panel *ngIf="hasMore$ | async" (showMore)="showMore()"></dsh-show-more-panel>
</dsh-expand-panel-accordion>

View File

@ -2,7 +2,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { TranslocoService } from '@ngneat/transloco';
import { ShopsService } from '../shops.service';
import { ShopsPanelsListService } from './shops-panels-list.service';
@Component({
@ -12,12 +11,12 @@ import { ShopsPanelsListService } from './shops-panels-list.service';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ShopsPanelsListComponent {
shops$ = this.shopsService.shops$;
selectedIdx$ = this.shopsPanelsListService.selectedIdx$;
shops$ = this.shopsPanelsListService.shops$;
selectedPanelPosition$ = this.shopsPanelsListService.selectedPanelPosition$;
hasMore$ = this.shopsPanelsListService.hasMore$;
constructor(
private shopsPanelsListService: ShopsPanelsListService,
private shopsService: ShopsService,
private snackBar: MatSnackBar,
private transloco: TranslocoService
) {}
@ -37,4 +36,8 @@ export class ShopsPanelsListComponent {
activate(id: string) {
this.shopsPanelsListService.activate(id);
}
showMore() {
this.shopsPanelsListService.showMore();
}
}

View File

@ -13,6 +13,7 @@ import { ButtonModule } from '@dsh/components/buttons';
import { SpinnerModule } from '@dsh/components/indicators';
import { LayoutModule } from '@dsh/components/layout';
import { ConfirmActionDialogModule } from '@dsh/components/popups';
import { ShowMorePanelModule } from '@dsh/components/show-more-panel';
import { CategoriesModule } from '../../../../../api';
import { CategoryPipe } from './category.pipe';
@ -33,7 +34,8 @@ import { ShopsPanelsListComponent } from './shops-panels-list.component';
MatSnackBarModule,
ClipboardModule,
ConfirmActionDialogModule,
CategoriesModule
CategoriesModule,
ShowMorePanelModule
],
declarations: [ShopsPanelsListComponent, CategoryPipe],
exports: [ShopsPanelsListComponent]

View File

@ -3,8 +3,8 @@ import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslocoService } from '@ngneat/transloco';
import { combineLatest } from 'rxjs';
import { filter, first, map, pluck, shareReplay, switchMap } from 'rxjs/operators';
import { combineLatest, concat, Subject } from 'rxjs';
import { filter, first, map, mapTo, pluck, scan, shareReplay, switchMap } from 'rxjs/operators';
import { ConfirmActionDialogComponent } from '@dsh/components/popups';
@ -12,14 +12,36 @@ import { ShopService } from '../../../../../api';
import { SHARE_REPLAY_CONF } from '../../../../../custom-operators';
import { ShopsService } from '../shops.service';
const SHOPS_LIMIT = 10;
@Injectable()
export class ShopsPanelsListService {
selectedIdx$ = combineLatest([this.route.fragment, this.shopsService.shops$]).pipe(
private showMore$ = new Subject<void>();
selectedPanelPosition$ = combineLatest([this.route.fragment, this.shopsService.shops$]).pipe(
first(),
map(([fragment, shops]) => shops.findIndex(({ id }) => id === fragment)),
shareReplay(SHARE_REPLAY_CONF)
);
private offset$ = concat(
this.selectedPanelPosition$.pipe(map(idx => this.getOffsetBySelectedPanelPosition(idx))),
this.showMore$.pipe(mapTo(SHOPS_LIMIT))
).pipe(
scan((offset, limit) => offset + limit, 0),
shareReplay(SHARE_REPLAY_CONF)
);
shops$ = combineLatest([this.shopService.shops$, this.offset$]).pipe(
map(([shops, showedCount]) => shops.slice(0, showedCount)),
shareReplay(SHARE_REPLAY_CONF)
);
hasMore$ = combineLatest([this.shopService.shops$.pipe(pluck('length')), this.offset$]).pipe(
map(([count, showedCount]) => count > showedCount),
shareReplay(SHARE_REPLAY_CONF)
);
constructor(
private dialog: MatDialog,
private shopsService: ShopsService,
@ -73,4 +95,15 @@ export class ShopsPanelsListService {
() => this.snackBar.open(this.transloco.translate('activate.error', null, 'shops|scoped'), 'OK')
);
}
showMore() {
this.showMore$.next();
}
private getOffsetBySelectedPanelPosition(idx: number) {
if (idx === -1) {
return SHOPS_LIMIT;
}
return Math.ceil((idx + 1) / SHOPS_LIMIT) * SHOPS_LIMIT;
}
}

View File

@ -1,19 +1,16 @@
<div fxLayout="column" [fxLayoutGap]="layoutGap" *transloco="let t; scope: 'shops'; read: 'shops'">
<div fxLayout="column" [fxLayoutGap]="layoutGap" *transloco="let s; scope: 'shops'; read: 'shops'">
<div class="mat-body-1">
{{ t.description }}
{{ s.description }}
</div>
<ng-container *ngIf="shops$ | async; else spinner">
<dsh-shops-panels-list></dsh-shops-panels-list>
<div *ngIf="!(shops$ | async)?.length" class="mat-headline dsh-payouts-empty">
<ng-container *transloco="let t">
{{ t.emptySearchResult }}
</ng-container>
<dsh-empty-search-result>{{ t.empty }}</dsh-empty-search-result>
<ng-container *ngIf="(isLoading$ | async) || !(shops$ | async); else shopsPanelsList">
<div fxLayout fxFlexAlign="center">
<dsh-spinner></dsh-spinner>
</div>
</ng-container>
<ng-template #spinner>
<div *ngIf="shops$ | async" fxLayout fxFlexAlign="center">
<dsh-spinner></dsh-spinner>
<ng-template #shopsPanelsList>
<dsh-shops-panels-list></dsh-shops-panels-list>
<div *ngIf="!(shops$ | async)?.length" class="mat-headline dsh-payouts-empty">
<dsh-empty-search-result *transloco="let t">{{ t.emptySearchResult }}</dsh-empty-search-result>
</div>
</ng-template>
</div>

View File

@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { booleanDebounceTime } from '../../../../custom-operators';
import { LAYOUT_GAP } from '../../../constants';
import { ShopsService } from './shops.service';
@ -11,6 +12,7 @@ import { ShopsService } from './shops.service';
})
export class ShopsComponent {
shops$ = this.shopsService.shops$;
isLoading$ = this.shopsService.isLoading$.pipe(booleanDebounceTime());
constructor(@Inject(LAYOUT_GAP) public layoutGap: string, private shopsService: ShopsService) {}
}

View File

@ -3,7 +3,7 @@ import { ActivatedRoute } from '@angular/router';
import { pluck, shareReplay } from 'rxjs/operators';
import { ShopService } from '../../../../api';
import { SHARE_REPLAY_CONF } from '../../../../custom-operators';
import { progress, SHARE_REPLAY_CONF } from '../../../../custom-operators';
import { filterShopsByEnv } from '../../operations/operators';
@Injectable()
@ -14,5 +14,7 @@ export class ShopsService {
shareReplay(SHARE_REPLAY_CONF)
);
isLoading$ = progress(this.route.params, this.shops$).pipe(shareReplay(SHARE_REPLAY_CONF));
constructor(private route: ActivatedRoute, private shopService: ShopService) {}
}

View File

@ -2,10 +2,10 @@ import { Injectable } from '@angular/core';
import { FormArray, FormBuilder } from '@angular/forms';
import moment from 'moment';
import { map, shareReplay, startWith } from 'rxjs/operators';
import { SHARE_REPLAY_CONF } from 'src/app/custom-operators';
import { InvoiceService } from '../../../../../api';
import { InvoiceLine, InvoiceLineTaxMode } from '../../../../../api-codegen/anapi';
import { SHARE_REPLAY_CONF } from '../../../../../custom-operators';
export const WITHOUT_VAT = Symbol('without VAT');
export const EMPTY_CART_ITEM = { product: '', quantity: null, price: null, taxVatRate: WITHOUT_VAT };

View File

@ -4,7 +4,7 @@
"directive-selector": [true, ["attribute", "element"], "dsh", ["camelCase", "kebab-case"]],
"component-selector": [true, ["attribute", "element"], "dsh", "kebab-case"],
"template-no-negated-async": false,
"import-blacklist": [true, "rxjs/Rx", "lodash", "lodash-es"],
"import-blacklist": [true, "rxjs/Rx", "lodash", "lodash-es", [".*\\./components/.*", "src/.+"]],
"no-unused-variable": [true, { "ignore-pattern": "^_" }],
"variable-name": {
"options": ["allow-leading-underscore", "ban-keywords", "check-format", "allow-pascal-case"]