dev #14253
Добавил состояние приложения(профиль) Сделал проверку на активность карты, на то, хватает ли баланса для совершения заказа, доработал обработку ошибок, пофиксил некоторые баги
This commit is contained in:
parent
ab8e909b08
commit
2428870ba8
@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { PrimeNGConfig } from 'primeng/api';
|
||||
import * as ConfigActions from './state/config/config.actions';
|
||||
import * as ProfileActions from './state/profile/profile.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -16,5 +17,6 @@ export class AppComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.primengConfig.ripple = false;
|
||||
this.store.dispatch(ConfigActions.getConfig());
|
||||
this.store.dispatch(ProfileActions.getProfile());
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,6 +77,9 @@ import { PurchaseInfoComponent } from './components/purchase-info/purchase-info.
|
||||
import { DateFilterComponent } from './components/date-filter/date-filter.component';
|
||||
import {MatDatepickerModule} from '@angular/material/datepicker';
|
||||
import {MatNativeDateModule} from '@angular/material/core';
|
||||
import { profileReducer } from './state/profile/profile.reducer';
|
||||
import { ProfileEffects } from './state/profile/profile.effects';
|
||||
import { CustomerInfoInterceptor } from './interceptors/customer-info.interceptor';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'products', pathMatch: 'full' },
|
||||
@ -152,8 +155,8 @@ const routes: Routes = [
|
||||
CalendarModule,
|
||||
MatIconModule,
|
||||
MdbCarouselModule,
|
||||
StoreModule.forRoot({ config: configReducer }),
|
||||
EffectsModule.forRoot([ConfigEffects]),
|
||||
StoreModule.forRoot({ config: configReducer, profile: profileReducer }),
|
||||
EffectsModule.forRoot([ConfigEffects, ProfileEffects]),
|
||||
PaginatorModule,
|
||||
InputTextModule,
|
||||
SidebarModule,
|
||||
@ -178,6 +181,11 @@ const routes: Routes = [
|
||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
useValue: { appearance: 'outline' },
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: CustomerInfoInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
||||
50
angular/src/app/interceptors/customer-info.interceptor.ts
Normal file
50
angular/src/app/interceptors/customer-info.interceptor.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpHandler,
|
||||
HttpEvent,
|
||||
HttpInterceptor,
|
||||
HttpResponse,
|
||||
HttpErrorResponse,
|
||||
} from '@angular/common/http';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerInfoInterceptor implements HttpInterceptor {
|
||||
constructor(private _snackBar: MatSnackBar) {}
|
||||
|
||||
intercept(
|
||||
request: HttpRequest<unknown>,
|
||||
next: HttpHandler
|
||||
): Observable<HttpEvent<unknown>> {
|
||||
return next.handle(request).pipe(
|
||||
tap(
|
||||
(event) => {
|
||||
if (event instanceof HttpResponse) {
|
||||
const body = event.body as any;
|
||||
const url = new URL(event.url || '');
|
||||
if (url.pathname.includes('/icard-proxy/customer_info')) {
|
||||
if (
|
||||
body.customer_info?.errorCode === 'Customer_CustomerNotFound'
|
||||
) {
|
||||
this._snackBar.open(
|
||||
'Пользователь не найден в системе! Обратитесь к руководству',
|
||||
'Ок'
|
||||
);
|
||||
} else if ('Error' in body) {
|
||||
this._snackBar.open('Произошла ошибка! Попробуйте снова', 'Ок');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event instanceof HttpErrorResponse) {
|
||||
this._snackBar.open('Произошла ошибка! Попробуйте снова', 'Ок');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
console.error('ERROR FROM INTERCEPTOR: ', err);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -35,7 +35,7 @@ export interface UserDataForm {
|
||||
export interface BonusProgramAccount {
|
||||
// BonusProgramName: string;
|
||||
// BonusProgramTypeID: string;
|
||||
CardNumber: number;
|
||||
CardNumber: string;
|
||||
Bonuses: number;
|
||||
// HoldedBonuses: number;
|
||||
// BonusProgramAccounts: BonusProgramAccount[];
|
||||
@ -286,3 +286,66 @@ export interface IDateFilter {
|
||||
from?: Date;
|
||||
to?: Date;
|
||||
}
|
||||
|
||||
export interface ICustomerInfo {
|
||||
anonymized: boolean;
|
||||
birthday: string | Date;
|
||||
cards: ICardCustomer[];
|
||||
categories: ICategoriesCustomer[];
|
||||
comment: string | null;
|
||||
consentStatus: number;
|
||||
cultureName: string;
|
||||
email: string | null;
|
||||
id: string;
|
||||
iikoCardOrdersSum: number;
|
||||
isBlocked: boolean;
|
||||
isDeleted: boolean;
|
||||
middleName: string | null;
|
||||
name: string;
|
||||
personalDataConsentFrom: string | null;
|
||||
personalDataConsentTo: string | null;
|
||||
personalDataProcessingFrom: string | null;
|
||||
personalDataProcessingTo: string | null;
|
||||
phone: string;
|
||||
rank: string | null;
|
||||
referrerId: string | null;
|
||||
sex: number;
|
||||
shouldReceiveLoyaltyInfo: boolean;
|
||||
shouldReceiveOrderStatusInfo: boolean;
|
||||
shouldReceivePromoActionsInfo: boolean;
|
||||
surname: string;
|
||||
userData: any;
|
||||
walletBalances: IWalletBalance[];
|
||||
errorCode?: string;
|
||||
|
||||
first_name: string | null;
|
||||
last_name: string | null;
|
||||
street: string | null;
|
||||
house: string | null;
|
||||
flat: string | null;
|
||||
city: string;
|
||||
selectedTerminal: ITerminal | null;
|
||||
}
|
||||
|
||||
export interface ICardCustomer {
|
||||
Id: string;
|
||||
IsActivated: boolean;
|
||||
NetworkId: string | null;
|
||||
Number: string;
|
||||
OrganizationId: string;
|
||||
OrganizationName: string | null;
|
||||
Track: string;
|
||||
ValidToDate: string | Date;
|
||||
}
|
||||
|
||||
export interface ICategoriesCustomer {}
|
||||
|
||||
export interface IWalletBalance {
|
||||
balance: number;
|
||||
wallet: {
|
||||
id: string;
|
||||
name: string;
|
||||
programType: string;
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { CartService } from 'src/app/services/cart.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { getProfile, getTransactions, getTransactionsInfo } from 'src/app/state/profile/profile.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-account',
|
||||
@ -31,6 +33,7 @@ export class AccountComponent implements OnInit {
|
||||
private jsonRpcService: JsonrpcService,
|
||||
private messageService: MessageService,
|
||||
private cartService: CartService,
|
||||
private store: Store
|
||||
) { }
|
||||
|
||||
public currentPage!: Page;
|
||||
@ -52,6 +55,12 @@ export class AccountComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
|
||||
this.checkAuthorization(true)
|
||||
|
||||
this.store.dispatch(getProfile())
|
||||
this.store.dispatch(getTransactions())
|
||||
this.store.dispatch(getTransactionsInfo())
|
||||
|
||||
|
||||
this.currentPage = this.pageList[0];
|
||||
document.body.classList.add(
|
||||
'woocommerce-account',
|
||||
|
||||
@ -20,10 +20,10 @@
|
||||
</div>
|
||||
<div *ngIf="accountData" class="info__row">
|
||||
<span class="key">Имя</span>
|
||||
<span class="value" *ngIf="userName.length">{{
|
||||
<span class="value" *ngIf="userName?.length">{{
|
||||
userName
|
||||
}}</span>
|
||||
<span class="value" *ngIf="!userName.length"
|
||||
<span class="value" *ngIf="!userName?.length"
|
||||
>Не задано</span
|
||||
>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,23 @@
|
||||
import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { orderStatuses, PageList, PageListWithBonus } from 'src/app/app.constants';
|
||||
import { BonusProgramAccount, Page, Purchase, Transaction } from 'src/app/interface/data';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Inject,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { distinctUntilChanged, lastValueFrom } from 'rxjs';
|
||||
import {
|
||||
orderStatuses,
|
||||
PageList,
|
||||
PageListWithBonus,
|
||||
} from 'src/app/app.constants';
|
||||
import {
|
||||
BonusProgramAccount,
|
||||
Page,
|
||||
Purchase,
|
||||
Transaction,
|
||||
} from 'src/app/interface/data';
|
||||
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
|
||||
import * as moment from 'moment-timezone';
|
||||
import * as barcode from 'jsbarcode';
|
||||
@ -9,38 +25,36 @@ import { environment } from 'src/environments/environment';
|
||||
import { AppleWalletService } from 'src/app/services/apple-wallet.service';
|
||||
import { CookiesService } from 'src/app/services/cookies.service';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { WpJsonService } from 'src/app/services/wp-json.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { selectCustomerInfo } from 'src/app/state/profile/profile.reducer';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bonus-program',
|
||||
templateUrl: './bonus-program.component.html',
|
||||
styleUrls: ['./bonus-program.component.scss']
|
||||
styleUrls: ['./bonus-program.component.scss'],
|
||||
})
|
||||
export class BonusProgramComponent implements OnInit {
|
||||
@Input() currentPage!: Page;
|
||||
@Output() deauthorization = new EventEmitter<boolean>(false)
|
||||
@Output() deauthorization = new EventEmitter<boolean>(false);
|
||||
public accountData!: BonusProgramAccount;
|
||||
public purchases: Purchase[] = [];
|
||||
public loadingBonuses: boolean = false;
|
||||
readonly orderStatuses = orderStatuses;
|
||||
readonly moment = moment;
|
||||
readonly pageList = environment.hasBonusProgram ? PageListWithBonus : PageList;
|
||||
readonly pageList = environment.hasBonusProgram
|
||||
? PageListWithBonus
|
||||
: PageList;
|
||||
public userName: string = '';
|
||||
public deviceType: 'ios' | 'android' | null = null;
|
||||
private profile$ = this.store.select(selectCustomerInfo);
|
||||
|
||||
constructor(
|
||||
private jsonrpc: JsonrpcService,
|
||||
private appleWallet: AppleWalletService,
|
||||
private cookiesService: CookiesService,
|
||||
@Inject(DOCUMENT) private document: Document,
|
||||
private http: HttpClient,
|
||||
private wpJsonService: WpJsonService,
|
||||
private _snackBar: MatSnackBar
|
||||
) { }
|
||||
|
||||
|
||||
private store: Store
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getAccountData();
|
||||
@ -48,50 +62,54 @@ export class BonusProgramComponent implements OnInit {
|
||||
}
|
||||
|
||||
getAccountData() {
|
||||
const token = this.cookiesService.getItem('token')
|
||||
const token = this.cookiesService.getItem('token');
|
||||
if (!token) {
|
||||
this.cookiesService.deleteCookie('token')
|
||||
this.deauthorization.emit(true)
|
||||
return
|
||||
this.cookiesService.deleteCookie('token');
|
||||
this.deauthorization.emit(true);
|
||||
return;
|
||||
}
|
||||
this.loadingBonuses = true;
|
||||
this.wpJsonService.getCustomerInfo(environment.systemId, token, environment.icardProxy).subscribe({
|
||||
this.profile$.pipe(distinctUntilChanged()).subscribe({
|
||||
next: (res) => {
|
||||
if (res.customer_info?.errorCode === 'Customer_CustomerNotFound' || 'Error' in res) {
|
||||
// this._snackBar.open('Пользователь не найден в системе! Обратитесь к руководству', 'Ок')
|
||||
if (!res) return;
|
||||
if (res.errorCode === 'Customer_CustomerNotFound' || 'Error' in res) {
|
||||
this.loadingBonuses = false;
|
||||
return
|
||||
return;
|
||||
}
|
||||
this.userName = res.customer_info.name
|
||||
this.userName = res.name;
|
||||
this.accountData = {
|
||||
CardNumber: res.customer_info.cards[0]?.Number || '',
|
||||
Bonuses: res.customer_info.walletBalances[0].balance
|
||||
CardNumber: res.cards[0]?.Number || '',
|
||||
Bonuses: res.walletBalances[0].balance,
|
||||
};
|
||||
if (this.document.getElementById('barcode')) {
|
||||
barcode('#barcode')
|
||||
.options({ font: 'OCR-B' }) // Will affect all barcodes
|
||||
.EAN13(`${this.accountData.CardNumber}`.padStart(12, '0'), {
|
||||
fontSize: 18,
|
||||
textMargin: 0,
|
||||
})
|
||||
.render();
|
||||
}
|
||||
barcode("#barcode")
|
||||
.options({ font: "OCR-B" }) // Will affect all barcodes
|
||||
.EAN13(`${this.accountData.CardNumber}`.padStart(12, "0"), { fontSize: 18, textMargin: 0 })
|
||||
.render();
|
||||
this.loadingBonuses = false;
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Error: ', err)
|
||||
}
|
||||
})
|
||||
console.error('Error: ', err);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getTypeDevice() {
|
||||
const userAgent = window.navigator.userAgent.toLowerCase()
|
||||
const userAgent = window.navigator.userAgent.toLowerCase();
|
||||
const ios = /iphone|ipod|ipad/.test(userAgent);
|
||||
this.deviceType = ios ? 'ios' : 'android'
|
||||
this.deviceType = ios ? 'ios' : 'android';
|
||||
}
|
||||
|
||||
|
||||
async addCardToWallet(e: any) {
|
||||
e.preventDefault()
|
||||
const token = this.cookiesService.getItem('token')
|
||||
const accountData = (await lastValueFrom(
|
||||
this.jsonrpc
|
||||
.rpc(
|
||||
e.preventDefault();
|
||||
const token = this.cookiesService.getItem('token');
|
||||
const accountData = (
|
||||
await lastValueFrom(
|
||||
this.jsonrpc.rpc(
|
||||
{
|
||||
method: 'getTokenData',
|
||||
params: [],
|
||||
@ -99,19 +117,17 @@ export class BonusProgramComponent implements OnInit {
|
||||
RpcService.authService,
|
||||
true
|
||||
)
|
||||
)).data
|
||||
)
|
||||
).data;
|
||||
if (token && accountData.user_id) {
|
||||
this.appleWallet.generateCard(token, accountData.user_id).subscribe({
|
||||
next: (res: any) => {
|
||||
this.document.location.href = res.url
|
||||
this.document.location.href = res.url;
|
||||
},
|
||||
error: (err) => {
|
||||
console.log('Error: ', err);
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,36 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { IDateFilter, Page, Purchase, PurchaseInfo } from 'src/app/interface/data';
|
||||
import {
|
||||
IDateFilter,
|
||||
Page,
|
||||
Purchase,
|
||||
PurchaseInfo,
|
||||
} from 'src/app/interface/data';
|
||||
import * as moment from 'moment-timezone';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import {
|
||||
combineLatest,
|
||||
combineLatestWith,
|
||||
distinctUntilChanged,
|
||||
forkJoin,
|
||||
lastValueFrom,
|
||||
} from 'rxjs';
|
||||
import { WpJsonService } from 'src/app/services/wp-json.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { CookiesService } from 'src/app/services/cookies.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { PurchaseInfoComponent } from 'src/app/components/purchase-info/purchase-info.component';
|
||||
import { dateFilterOptions } from 'src/app/app.constants';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import {
|
||||
selectCustomerInfo,
|
||||
selectProfileState,
|
||||
selectTransactions,
|
||||
selectTransactionsInfo,
|
||||
} from 'src/app/state/profile/profile.reducer';
|
||||
import {
|
||||
getTransactions,
|
||||
getTransactionsInfo,
|
||||
} from 'src/app/state/profile/profile.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-orders',
|
||||
@ -25,16 +47,20 @@ export class OrdersComponent implements OnInit {
|
||||
public purchases: Purchase[] = [];
|
||||
public purchasesShortArray: Purchase[] = [];
|
||||
|
||||
private profileState$ = this.store.select(selectCustomerInfo);
|
||||
private transactionsState$ = this.store.select(selectTransactions);
|
||||
private transactionsInfoState$ = this.store.select(selectTransactionsInfo);
|
||||
|
||||
public dateFilterOptions = dateFilterOptions
|
||||
public dateFilterOptions = dateFilterOptions;
|
||||
public defaultFilterType = 'currentMonth';
|
||||
private startOfMonth = moment().startOf('month').format('YYYY-MM-DD HH:mm');
|
||||
public filteredOfDatePurchases: Purchase[] = []
|
||||
public filteredOfDatePurchases: Purchase[] = [];
|
||||
|
||||
constructor(
|
||||
private wpJsonService: WpJsonService,
|
||||
private cookiesService: CookiesService,
|
||||
public dialog: MatDialog
|
||||
public dialog: MatDialog,
|
||||
private store: Store
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -42,32 +68,40 @@ export class OrdersComponent implements OnInit {
|
||||
}
|
||||
|
||||
dateFilter(dateFilter: IDateFilter) {
|
||||
this.lastViewOrder = 3
|
||||
this.lastViewOrder = 3;
|
||||
switch (dateFilter.filterType) {
|
||||
case 'between':
|
||||
this.filteredOfDatePurchases = this.purchases.filter((value) => {
|
||||
return moment(value.transactionCreateDate).isBetween(dateFilter.from, moment(dateFilter.to).add(1, 'day'))
|
||||
})
|
||||
return moment(value.transactionCreateDate).isBetween(
|
||||
dateFilter.from,
|
||||
moment(dateFilter.to).add(1, 'day')
|
||||
);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'currentMonth':
|
||||
this.filteredOfDatePurchases = this.purchases.filter((value) => {
|
||||
return moment(value.transactionCreateDate).isAfter(this.startOfMonth)
|
||||
})
|
||||
return moment(value.transactionCreateDate).isAfter(this.startOfMonth);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'lastMonth':
|
||||
this.filteredOfDatePurchases = this.purchases.filter((value) => {
|
||||
return moment(value.transactionCreateDate).isBetween(moment(this.startOfMonth).subtract(1, 'month'), this.startOfMonth)
|
||||
})
|
||||
return moment(value.transactionCreateDate).isBetween(
|
||||
moment(this.startOfMonth).subtract(1, 'month'),
|
||||
this.startOfMonth
|
||||
);
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
this.filteredOfDatePurchases = this.purchases
|
||||
this.filteredOfDatePurchases = this.purchases;
|
||||
break;
|
||||
}
|
||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(0, this.lastViewOrder);
|
||||
|
||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(
|
||||
0,
|
||||
this.lastViewOrder
|
||||
);
|
||||
}
|
||||
|
||||
async getOrders() {
|
||||
@ -77,77 +111,49 @@ export class OrdersComponent implements OnInit {
|
||||
this.deauthorization.emit(true);
|
||||
return;
|
||||
}
|
||||
const customerInfo = await lastValueFrom(
|
||||
this.wpJsonService.getCustomerInfo(
|
||||
environment.systemId,
|
||||
token,
|
||||
environment.icardProxy
|
||||
)
|
||||
);
|
||||
if (
|
||||
customerInfo.customer_info?.errorCode === 'Customer_CustomerNotFound' ||
|
||||
'Error' in customerInfo
|
||||
) {
|
||||
this.ordersLoadingStatus = false;
|
||||
return;
|
||||
}
|
||||
const purchases: Purchase[] = (
|
||||
await lastValueFrom(
|
||||
this.wpJsonService.getTransactions(
|
||||
environment.systemId,
|
||||
token,
|
||||
environment.icardProxy,
|
||||
30
|
||||
)
|
||||
)
|
||||
)[customerInfo.customer_info?.id];
|
||||
|
||||
const purchasesInfo: PurchaseInfo[] = (
|
||||
await lastValueFrom(
|
||||
this.wpJsonService.getTransactionsInfo(
|
||||
environment.systemId,
|
||||
token,
|
||||
environment.icardProxy,
|
||||
30
|
||||
)
|
||||
)
|
||||
)['purchase'];
|
||||
combineLatest([this.transactionsState$, this.transactionsInfoState$])
|
||||
.pipe(distinctUntilChanged())
|
||||
.subscribe({
|
||||
next: ([transactions, transactionsInfo]) => {
|
||||
if (transactions && transactionsInfo) {
|
||||
this.purchases = transactions
|
||||
.map<Purchase>((purchase) => {
|
||||
return {
|
||||
...purchase,
|
||||
more_info:
|
||||
transactionsInfo.find(
|
||||
(purchaseInfo: PurchaseInfo) =>
|
||||
Number(purchaseInfo.number) === purchase.orderNumber
|
||||
) || null,
|
||||
};
|
||||
})
|
||||
.filter((purchase: Purchase) =>
|
||||
[
|
||||
'PayFromWallet',
|
||||
'CancelPayFromWallet',
|
||||
'RefillWallet',
|
||||
].includes(purchase.transactionType)
|
||||
);
|
||||
|
||||
this.purchases = purchases
|
||||
.map<Purchase>((purchase) => {
|
||||
// const id = purchase.ID.slice(0,36).toLowerCase();
|
||||
// purchase.Transactions = transactions.filter((transaction) => {
|
||||
// const same = transaction.Purchase === id;
|
||||
// transaction.HasPurchase = same;
|
||||
// return same;
|
||||
// });
|
||||
if (purchasesInfo) {
|
||||
purchase.more_info =
|
||||
purchasesInfo.find(
|
||||
(purchaseInfo: PurchaseInfo) =>
|
||||
Number(purchaseInfo.number) === purchase.orderNumber
|
||||
) || null;
|
||||
}
|
||||
return purchase;
|
||||
})
|
||||
.filter((purchase: Purchase) =>
|
||||
['PayFromWallet', 'CancelPayFromWallet', 'RefillWallet'].includes(
|
||||
purchase.transactionType
|
||||
)
|
||||
);
|
||||
|
||||
this.dateFilter({filterType: this.defaultFilterType})
|
||||
this.ordersLoadingStatus = false;
|
||||
this.ordersLoadingStatus = false;
|
||||
this.dateFilter({ filterType: this.defaultFilterType });
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getMoreOrders() {
|
||||
this.lastViewOrder += 4;
|
||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(0, this.lastViewOrder);
|
||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(
|
||||
0,
|
||||
this.lastViewOrder
|
||||
);
|
||||
}
|
||||
|
||||
showPurchaseInfo(purchaseInfo: PurchaseInfo) {
|
||||
const dialogRef = this.dialog.open(PurchaseInfoComponent, {
|
||||
data: {purchaseInfo},
|
||||
data: { purchaseInfo },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,8 +6,11 @@ import {
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { SnackBarComponent } from 'src/app/components/snack-bar/snack-bar.component';
|
||||
import { ICardCustomer } from 'src/app/interface/data';
|
||||
import { Order } from 'src/app/models/order';
|
||||
import { OrderProduct } from 'src/app/models/order-product';
|
||||
import {
|
||||
@ -15,6 +18,12 @@ import {
|
||||
ProductAmountAction,
|
||||
} from 'src/app/services/cart.service';
|
||||
import { OrderService } from 'src/app/services/order.service';
|
||||
import {
|
||||
selectCustomerCards,
|
||||
selectCustomerWalletBalance,
|
||||
} from 'src/app/state/profile/profile.reducer';
|
||||
import * as ProfileActions from '../../state/profile/profile.actions';
|
||||
import { CookiesService } from 'src/app/services/cookies.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cart',
|
||||
@ -30,18 +39,39 @@ export class CartComponent implements OnInit {
|
||||
public visibleSidebar: boolean = false;
|
||||
public isFullScreen!: boolean;
|
||||
public width!: number;
|
||||
public CardsCustomer!: ICardCustomer[];
|
||||
public WalletBalanceCustomer!: number;
|
||||
|
||||
private CardsCustomer$ = this.store.select(selectCustomerCards);
|
||||
private WalletBalanceCustomer$ = this.store.select(
|
||||
selectCustomerWalletBalance
|
||||
);
|
||||
|
||||
constructor(
|
||||
private orderService: OrderService,
|
||||
private cartService: CartService,
|
||||
private messageService: MessageService,
|
||||
private _snackBar: MatSnackBar
|
||||
private _snackBar: MatSnackBar,
|
||||
private store: Store,
|
||||
private cookiesService: CookiesService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
async ngOnInit() {
|
||||
this.width = window.innerWidth;
|
||||
this.changeDullScreenMode();
|
||||
this.loadCart();
|
||||
await this.loadCart();
|
||||
combineLatest([this.CardsCustomer$, this.WalletBalanceCustomer$]).subscribe(
|
||||
{
|
||||
next: ([cards, balance]) => {
|
||||
this.CardsCustomer = cards!;
|
||||
this.WalletBalanceCustomer = balance!;
|
||||
if (cards && balance) this.loading = false;
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Произошла ошибка!');
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Изменение размера окна
|
||||
@ -72,27 +102,48 @@ export class CartComponent implements OnInit {
|
||||
async loadCart(): Promise<void> {
|
||||
this.loading = true;
|
||||
this.order = await this.orderService.getOrder(true);
|
||||
const token = this.cookiesService.getItem('token');
|
||||
if (!token) {
|
||||
this._snackBar.open('Авторизуйтесь!', 'Ок');
|
||||
this.userNotFound();
|
||||
return;
|
||||
}
|
||||
if (this.order?.userData?.errorCode === 'Customer_CustomerNotFound') {
|
||||
this.userNotFound()
|
||||
return
|
||||
this.userNotFound();
|
||||
return;
|
||||
}
|
||||
if (this.order) this.price = this.order.price;
|
||||
this.loading = false;
|
||||
this.store.dispatch(ProfileActions.getProfile());
|
||||
}
|
||||
|
||||
userNotFound(event: null = null) {
|
||||
this.visibleSidebar = false
|
||||
this._snackBar.open('Пользователь не найден в системе! Обратитесь к руководству', 'Ок')
|
||||
this.visibleSidebar = false;
|
||||
// this._snackBar.open('Пользователь не найден в системе! Обратитесь к руководству', 'Ок')
|
||||
}
|
||||
|
||||
removeFromCart(event: Event, guid: string): void {
|
||||
async removeFromCart(event: Event, guid: string) {
|
||||
event.preventDefault();
|
||||
this.orderService.removeFromCart(guid);
|
||||
await this.loadCart();
|
||||
}
|
||||
|
||||
confirmOrder(event: Event): void {
|
||||
event.preventDefault();
|
||||
this.showAuthoriztion.emit(true);
|
||||
if (!this.CardsCustomer[0].IsActivated || !this.CardsCustomer.length) {
|
||||
this._snackBar.open(
|
||||
'Ваша карта неактивна! Обратитесь к руководству',
|
||||
'Ок'
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (this.WalletBalanceCustomer < this.order.price) {
|
||||
this._snackBar.open(
|
||||
'На Вашей карте недостаточно средств для оформления заказа!',
|
||||
'Ок'
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.orderConfirmed = true;
|
||||
// this.confirm.emit();
|
||||
}
|
||||
@ -117,7 +168,7 @@ export class CartComponent implements OnInit {
|
||||
|
||||
orderSubmitted(orderid: number) {
|
||||
this.visibleSidebar = false;
|
||||
this._snackBar.open(`Заказ оформлен! Номер заказа: ${orderid}`, 'Ок')
|
||||
this._snackBar.open(`Заказ оформлен! Номер заказа: ${orderid}`, 'Ок');
|
||||
}
|
||||
|
||||
confirmClearCart() {
|
||||
|
||||
@ -16,6 +16,7 @@ import { MessagingService } from 'src/app/services/messaging.service';
|
||||
import { CookiesService } from 'src/app/services/cookies.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import * as ConfigActions from '../../state/config/config.actions'
|
||||
import { getProfile } from 'src/app/state/profile/profile.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-main',
|
||||
@ -62,7 +63,8 @@ export class MainComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.appendAccount();
|
||||
this.store.dispatch(ConfigActions.getConfig());
|
||||
// this.store.dispatch(ConfigActions.getConfig());
|
||||
// this.store.dispatch(getProfile());
|
||||
// this.checkRequestPermission()
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Group, Modifier, ModifiersGroup, Product } from '../../interface/data';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { DialogService } from 'primeng/dynamicdialog';
|
||||
import { ProductModalComponent } from 'src/app/components/product-modal/product-modal.component';
|
||||
import { WpJsonService } from 'src/app/services/wp-json.service';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { CartService } from 'src/app/services/cart.service';
|
||||
import { CookiesService } from 'src/app/services/cookies.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
||||
import { TerminalListComponent } from 'src/app/components/terminal-list/terminal-list.component';
|
||||
import { GetTerminalsService } from 'src/app/services/get-terminals.service';
|
||||
|
||||
@ -18,6 +18,10 @@ import { MessageService } from 'primeng/api';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { getProfile } from '../state/profile/profile.actions';
|
||||
import * as ProfileActions from '../state/profile/profile.actions';
|
||||
import { selectCustomerInfo } from '../state/profile/profile.reducer';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@ -30,7 +34,8 @@ export class OrderService {
|
||||
private wpJsonService: WpJsonService,
|
||||
private jsonRpcService: JsonrpcService,
|
||||
private cookiesService: CookiesService,
|
||||
private messageService: MessageService
|
||||
private messageService: MessageService,
|
||||
private store: Store
|
||||
) {}
|
||||
|
||||
async getDeliveryTypes(): Promise<DeliveryType[]> {
|
||||
@ -66,11 +71,8 @@ export class OrderService {
|
||||
});
|
||||
return this.order;
|
||||
}
|
||||
const additionalInfo = this.wpJsonService.getCustomerInfo(
|
||||
environment.systemId,
|
||||
token,
|
||||
environment.icardProxy
|
||||
);
|
||||
this.store.dispatch(ProfileActions.getProfile())
|
||||
const additionalInfo = this.store.select(selectCustomerInfo);
|
||||
|
||||
const tokenData = this.jsonRpcService.rpc(
|
||||
{
|
||||
@ -82,17 +84,23 @@ export class OrderService {
|
||||
);
|
||||
|
||||
const info = await lastValueFrom(
|
||||
forkJoin([additionalInfo, tokenData, products])
|
||||
forkJoin([tokenData, products])
|
||||
);
|
||||
const customer_info = info[0]?.customer_info;
|
||||
|
||||
this.order = new Order({
|
||||
products: products,
|
||||
userData: customer_info,
|
||||
phone: info[1].data?.mobile_number,
|
||||
token: token,
|
||||
terminal_id: terminal.id,
|
||||
});
|
||||
|
||||
additionalInfo.subscribe({
|
||||
next: (value) => {
|
||||
this.order = new Order({
|
||||
products: products,
|
||||
userData: value! as UserData,
|
||||
phone: info[0].data?.mobile_number,
|
||||
token: token,
|
||||
terminal_id: terminal.id,
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
console.error(err);
|
||||
}
|
||||
})
|
||||
} else if (this.order) {
|
||||
this.order.products.length = 0;
|
||||
}
|
||||
@ -101,11 +109,12 @@ export class OrderService {
|
||||
}
|
||||
|
||||
async getProducts(cart: Cart): Promise<OrderProduct[]> {
|
||||
const terminal =
|
||||
JSON.parse(this.cookiesService.getItem('selectedTerminal') || 'null');
|
||||
const terminal = JSON.parse(
|
||||
this.cookiesService.getItem('selectedTerminal') || 'null'
|
||||
);
|
||||
const products: OrderProduct[] = [];
|
||||
if (!terminal) {
|
||||
return products
|
||||
return products;
|
||||
}
|
||||
const allData = await lastValueFrom(
|
||||
this.wpJsonService.getAllData(`${terminal.label}${terminal.id}`)
|
||||
|
||||
@ -3,11 +3,11 @@ import { createAction, props } from '@ngrx/store';
|
||||
export const getConfig = createAction('[Config] Get');
|
||||
|
||||
export const getSuccess = createAction(
|
||||
'[Config] Get Success',
|
||||
props<{ getSuccessResponse: any }>()
|
||||
'[Config] Get Success',
|
||||
props<{ getSuccessResponse: any }>()
|
||||
);
|
||||
|
||||
export const getFailure = createAction(
|
||||
'[Config] Get Failure',
|
||||
props<{ error: string }>()
|
||||
);
|
||||
);
|
||||
|
||||
15
angular/src/app/state/profile/profile.actions.ts
Normal file
15
angular/src/app/state/profile/profile.actions.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { createAction, props } from '@ngrx/store';
|
||||
|
||||
export const getProfile = createAction('[Profile] Get Profile');
|
||||
export const getTransactions = createAction('[Profile] Get Transactions');
|
||||
export const getTransactionsInfo = createAction('[Profile] Get TransactionsInfo');
|
||||
|
||||
export const getSuccess = createAction(
|
||||
'[Profile] Get Success',
|
||||
props<{ getSuccessResponse: any }>()
|
||||
);
|
||||
|
||||
export const getFailure = createAction(
|
||||
'[Profile] Get Failure',
|
||||
props<{ error: string }>()
|
||||
);
|
||||
124
angular/src/app/state/profile/profile.effects.ts
Normal file
124
angular/src/app/state/profile/profile.effects.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as ProfileActions from './profile.actions';
|
||||
import { WpJsonService } from 'src/app/services/wp-json.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { CookiesService } from 'src/app/services/cookies.service';
|
||||
import { catchError, exhaustMap, map, of, throwError } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class ProfileEffects {
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private wpJsonService: WpJsonService,
|
||||
private cookiesService: CookiesService
|
||||
) {}
|
||||
|
||||
getProfile$ = createEffect(() => {
|
||||
const token = this.cookiesService.getItem('token');
|
||||
return this.actions$.pipe(
|
||||
ofType(ProfileActions.getProfile),
|
||||
exhaustMap(() => {
|
||||
return this.wpJsonService
|
||||
.getCustomerInfo(
|
||||
environment.systemId,
|
||||
token || '',
|
||||
environment.icardProxy
|
||||
)
|
||||
.pipe(
|
||||
map((value) => {
|
||||
if (
|
||||
value.customer_info?.errorCode === 'Customer_CustomerNotFound'
|
||||
) {
|
||||
throw new Error('Пользователь не найден в системе! Обратитесь к руководству')
|
||||
}
|
||||
if ('Error' in value) {
|
||||
throw new Error('Ошибка получения данных');
|
||||
}
|
||||
return {
|
||||
getSuccessResponse: value,
|
||||
};
|
||||
}),
|
||||
map((value) => ProfileActions.getSuccess(value as any)),
|
||||
catchError((error) => {
|
||||
return of(ProfileActions.getFailure({ error }));
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
getTransactions$ = createEffect(() => {
|
||||
const token = this.cookiesService.getItem('token');
|
||||
return this.actions$.pipe(
|
||||
ofType(ProfileActions.getTransactions),
|
||||
exhaustMap(() => {
|
||||
return this.wpJsonService
|
||||
.getTransactions(
|
||||
environment.systemId,
|
||||
token || '',
|
||||
environment.icardProxy,
|
||||
60
|
||||
)
|
||||
.pipe(
|
||||
map((value) => {
|
||||
if (
|
||||
value.customer_info?.errorCode === 'Customer_CustomerNotFound'
|
||||
) {
|
||||
throw new Error('Пользователь не найден в системе! Обратитесь к руководству')
|
||||
}
|
||||
if ('Error' in value) {
|
||||
throw new Error('Ошибка получения данных');
|
||||
}
|
||||
return {
|
||||
getSuccessResponse: {
|
||||
transactions: Object.values(value)[0]
|
||||
},
|
||||
};
|
||||
}),
|
||||
map((value) => ProfileActions.getSuccess(value as any)),
|
||||
catchError((error) => {
|
||||
return of(ProfileActions.getFailure({ error }));
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
getTransactionsInfo$ = createEffect(() => {
|
||||
const token = this.cookiesService.getItem('token');
|
||||
return this.actions$.pipe(
|
||||
ofType(ProfileActions.getTransactionsInfo),
|
||||
exhaustMap(() => {
|
||||
return this.wpJsonService
|
||||
.getTransactionsInfo(
|
||||
environment.systemId,
|
||||
token || '',
|
||||
environment.icardProxy,
|
||||
60
|
||||
)
|
||||
.pipe(
|
||||
map((value) => {
|
||||
if (
|
||||
value.customer_info?.errorCode === 'Customer_CustomerNotFound'
|
||||
) {
|
||||
throw new Error('Пользователь не найден в системе! Обратитесь к руководству')
|
||||
}
|
||||
if ('Error' in value) {
|
||||
throw new Error('Ошибка получения данных');
|
||||
}
|
||||
return {
|
||||
getSuccessResponse: {
|
||||
transactionsInfo: value.purchase
|
||||
},
|
||||
};
|
||||
}),
|
||||
map((value) => ProfileActions.getSuccess(value as any)),
|
||||
catchError((error) => {
|
||||
return of(ProfileActions.getFailure({ error }));
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
81
angular/src/app/state/profile/profile.reducer.ts
Normal file
81
angular/src/app/state/profile/profile.reducer.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import {
|
||||
createFeatureSelector,
|
||||
createReducer,
|
||||
createSelector,
|
||||
on,
|
||||
} from '@ngrx/store';
|
||||
import { getFailure, getSuccess } from './profile.actions';
|
||||
import { ICustomerInfo, Purchase, PurchaseInfo } from 'src/app/interface/data';
|
||||
|
||||
export interface ProfileState {
|
||||
customer_info: ICustomerInfo | null;
|
||||
transactions: Purchase[] | null;
|
||||
transactionsInfo: PurchaseInfo[] | null;
|
||||
}
|
||||
|
||||
export const initialProfileState: ProfileState = {
|
||||
customer_info: null,
|
||||
transactions: null,
|
||||
transactionsInfo: null,
|
||||
};
|
||||
|
||||
const _profileReducer = createReducer(
|
||||
initialProfileState,
|
||||
on(getSuccess, (state, { getSuccessResponse }) => {
|
||||
return {
|
||||
...state,
|
||||
...getSuccessResponse,
|
||||
};
|
||||
}),
|
||||
on(getFailure, (state, { error }) => {
|
||||
console.error(error);
|
||||
return state;
|
||||
})
|
||||
);
|
||||
|
||||
export function profileReducer(state: any, action: any) {
|
||||
return _profileReducer(state, action);
|
||||
}
|
||||
|
||||
export const selectProfileState =
|
||||
createFeatureSelector<ProfileState>('profile');
|
||||
|
||||
export const selectCustomerInfo = createSelector(
|
||||
selectProfileState,
|
||||
(state) => {
|
||||
return state.customer_info;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectCustomerWalletBalance = createSelector(
|
||||
selectProfileState,
|
||||
(state) => {
|
||||
return state?.customer_info?.walletBalances?.reduce<number>(
|
||||
(previousValue, currentValue) => {
|
||||
return previousValue + currentValue.balance;
|
||||
},
|
||||
0
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const selectCustomerCards = createSelector(
|
||||
selectProfileState,
|
||||
(state) => {
|
||||
return state?.customer_info?.cards
|
||||
}
|
||||
);
|
||||
|
||||
export const selectTransactions = createSelector(
|
||||
selectProfileState,
|
||||
(state) => {
|
||||
return state.transactions;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectTransactionsInfo = createSelector(
|
||||
selectProfileState,
|
||||
(state) => {
|
||||
return state.transactionsInfo;
|
||||
}
|
||||
);
|
||||
Loading…
Reference in New Issue
Block a user