Добавил состояние приложения(профиль)
Сделал проверку на активность карты, на то, хватает ли баланса для совершения заказа, доработал обработку ошибок, пофиксил некоторые баги
This commit is contained in:
gofnnp 2023-05-26 01:35:37 +04:00
parent ab8e909b08
commit 2428870ba8
16 changed files with 601 additions and 168 deletions

View File

@ -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());
}
}

View File

@ -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],
})

View 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);
}
)
);
}
}

View File

@ -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;
};
}

View File

@ -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',

View File

@ -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>

View File

@ -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);
}
})
},
});
}
}
}

View File

@ -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 },
});
}
}

View File

@ -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() {

View File

@ -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()
}

View File

@ -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';

View File

@ -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}`)

View File

@ -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 }>()
);
);

View 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 }>()
);

View 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 }));
})
);
})
);
});
}

View 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;
}
);