Compare commits
No commits in common. "sakura" and "master" have entirely different histories.
58
.gitignore
vendored
58
.gitignore
vendored
@ -1,42 +1,42 @@
|
|||||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
# Compiled output
|
# Compiled output
|
||||||
angular/dist
|
/dist
|
||||||
angular/tmp
|
/tmp
|
||||||
angular/out-tsc
|
/out-tsc
|
||||||
angular/bazel-out
|
/bazel-out
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
angular/node_modules
|
/node_modules
|
||||||
angular/npm-debug.log
|
npm-debug.log
|
||||||
angular/yarn-error.log
|
yarn-error.log
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
angular/.idea/
|
.idea/
|
||||||
angular/.project
|
.project
|
||||||
angular/.classpath
|
.classpath
|
||||||
angular/.c9/
|
.c9/
|
||||||
angular/*.launch
|
*.launch
|
||||||
angular/.settings/
|
.settings/
|
||||||
angular/*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
|
||||||
# Visual Studio Code
|
# Visual Studio Code
|
||||||
angular/.vscode/*
|
.vscode/*
|
||||||
angular/!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
angular/!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
angular/!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
angular/!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
angular/.history/*
|
.history/*
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
angular/.angular/cache
|
/.angular/cache
|
||||||
angular/.sass-cache/
|
.sass-cache/
|
||||||
angular/connect.lock
|
/connect.lock
|
||||||
angular/coverage
|
/coverage
|
||||||
angular/libpeerconnection.log
|
/libpeerconnection.log
|
||||||
angular/testem.log
|
testem.log
|
||||||
angular/typings
|
/typings
|
||||||
|
|
||||||
# System files
|
# System files
|
||||||
angular/.DS_Store
|
.DS_Store
|
||||||
angular/Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
4
.vscode/extensions.json
vendored
Normal file
4
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||||
|
"recommendations": ["angular.ng-template"]
|
||||||
|
}
|
||||||
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "ng serve",
|
||||||
|
"type": "pwa-chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "npm: start",
|
||||||
|
"url": "http://localhost:4200/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ng test",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "npm: test",
|
||||||
|
"url": "http://localhost:9876/debug.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
42
.vscode/tasks.json
vendored
Normal file
42
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "start",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "typescript",
|
||||||
|
"pattern": "$tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": {
|
||||||
|
"regexp": "(.*?)"
|
||||||
|
},
|
||||||
|
"endsPattern": {
|
||||||
|
"regexp": "bundle generation complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "test",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "typescript",
|
||||||
|
"pattern": "$tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": {
|
||||||
|
"regexp": "(.*?)"
|
||||||
|
},
|
||||||
|
"endsPattern": {
|
||||||
|
"regexp": "bundle generation complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
33
Jenkinsfile
vendored
33
Jenkinsfile
vendored
@ -1,33 +0,0 @@
|
|||||||
env.HL_BUILD_MODE = "jenkins"
|
|
||||||
|
|
||||||
node('Lithium'){
|
|
||||||
|
|
||||||
stage('get new version to repo') {
|
|
||||||
checkout scm
|
|
||||||
if (lastCommitIsBumpCommit()) {
|
|
||||||
currentBuild.result = 'ABORTED'
|
|
||||||
error('Последний коммит - результат сборки jenkins')
|
|
||||||
}
|
|
||||||
sh "git checkout ${env.BRANCH_NAME}"
|
|
||||||
sh "git checkout -- ."
|
|
||||||
|
|
||||||
sh "git pull"
|
|
||||||
//sh "git submodule update --init --recursive"
|
|
||||||
//sh "git submodule update --remote --merge"
|
|
||||||
}
|
|
||||||
stage("build and publish"){
|
|
||||||
dir('angular'){
|
|
||||||
sh label: '', script: 'npm i'
|
|
||||||
sh label: '', script: 'npm run build'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean lastCommitIsBumpCommit() {
|
|
||||||
lastCommit = sh([script: 'git log -1', returnStdout: true])
|
|
||||||
if (lastCommit.contains("Author: jenkins")) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
# Sakura
|
# FashionLogica
|
||||||
|
|
||||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.0.6.
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.0.6.
|
||||||
|
|
||||||
@ -1,17 +1,15 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"newProjectRoot": "projects",
|
"newProjectRoot": "projects",
|
||||||
"projects": {
|
"projects": {
|
||||||
"sakura": {
|
"fashion-logica": {
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"@schematics/angular:component": {
|
"@schematics/angular:component": {
|
||||||
"style": "scss"
|
"style": "scss"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"root": "",
|
"root": "",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
@ -19,9 +17,8 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular-devkit/build-angular:browser",
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
"options": {
|
"options": {
|
||||||
"outputPath": "/var/www/html/lk.crm4retail.ru/sakura",
|
"outputPath": "/var/www/lk/fashion-logica",
|
||||||
"deleteOutputPath": false,
|
"baseHref": "/fashion-logica/",
|
||||||
"baseHref": "/",
|
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"polyfills": "src/polyfills.ts",
|
"polyfills": "src/polyfills.ts",
|
||||||
@ -34,9 +31,7 @@
|
|||||||
"src/firebase-messaging-sw.js"
|
"src/firebase-messaging-sw.js"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
"node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
|
||||||
"node_modules/mdb-angular-ui-kit/assets/scss/mdb.scss",
|
|
||||||
"node_modules/primeng/resources/themes/saga-blue/theme.css",
|
|
||||||
"node_modules/primeicons/primeicons.css",
|
"node_modules/primeicons/primeicons.css",
|
||||||
"node_modules/primeng/resources/primeng.min.css",
|
"node_modules/primeng/resources/primeng.min.css",
|
||||||
"node_modules/ngx-sharebuttons/themes/modern.scss",
|
"node_modules/ngx-sharebuttons/themes/modern.scss",
|
||||||
@ -58,7 +53,7 @@
|
|||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
"maximumWarning": "2kb",
|
"maximumWarning": "2kb",
|
||||||
"maximumError": "4.5kb"
|
"maximumError": "4kb"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
@ -84,11 +79,10 @@
|
|||||||
"builder": "@angular-devkit/build-angular:dev-server",
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"browserTarget": "sakura:build:production"
|
"browserTarget": "fashion-logica:build:production"
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"browserTarget": "sakura:build:development",
|
"browserTarget": "fashion-logica:build:development"
|
||||||
"proxyConfig": "proxy.confi.json"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
@ -96,7 +90,7 @@
|
|||||||
"extract-i18n": {
|
"extract-i18n": {
|
||||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
"options": {
|
"options": {
|
||||||
"browserTarget": "sakura:build"
|
"browserTarget": "fashion-logica:build"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
@ -114,7 +108,6 @@
|
|||||||
"src/manifest.webmanifest"
|
"src/manifest.webmanifest"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"/icard-proxy": {
|
|
||||||
"target": "https://sakura.lk.crm4retail.ru/api/icard-proxy",
|
|
||||||
"secure": false,
|
|
||||||
"pathRewrite": {
|
|
||||||
"^/icard-proxy": ""
|
|
||||||
},
|
|
||||||
"changeOrigin": true,
|
|
||||||
"logLevel": "debug"
|
|
||||||
},
|
|
||||||
"/static": {
|
|
||||||
"target": "https://sakura.lk.crm4retail.ru/static",
|
|
||||||
"secure": false,
|
|
||||||
"pathRewrite": {
|
|
||||||
"^/static": ""
|
|
||||||
},
|
|
||||||
"changeOrigin": true,
|
|
||||||
"logLevel": "debug"
|
|
||||||
},
|
|
||||||
"/api/orders": {
|
|
||||||
"target": "https://sakura.lk.crm4retail.ru/api/orders",
|
|
||||||
"secure": false,
|
|
||||||
"pathRewrite": {
|
|
||||||
"^/api/orders": ""
|
|
||||||
},
|
|
||||||
"changeOrigin": true,
|
|
||||||
"logLevel": "debug"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
<app-navbar></app-navbar>
|
|
||||||
<p-toast position="top-center"></p-toast>
|
|
||||||
<div class="layout">
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
</div>
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
:host {
|
|
||||||
.layout {
|
|
||||||
padding: 0 16px 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
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',
|
|
||||||
templateUrl: './app.component.html',
|
|
||||||
styleUrls: ['./app.component.scss'],
|
|
||||||
})
|
|
||||||
export class AppComponent implements OnInit {
|
|
||||||
title = 'Sakura';
|
|
||||||
|
|
||||||
constructor(private primengConfig: PrimeNGConfig, private store: Store) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.primengConfig.ripple = false;
|
|
||||||
this.store.dispatch(ConfigActions.getConfig());
|
|
||||||
this.store.dispatch(ProfileActions.getProfile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
import { MatDateFormats } from '@angular/material/core';
|
|
||||||
import {
|
|
||||||
IOptionDateFilter,
|
|
||||||
MainPageCode,
|
|
||||||
OrderStatus,
|
|
||||||
Page,
|
|
||||||
PageCode,
|
|
||||||
PaymentMethod,
|
|
||||||
} from './interface/data';
|
|
||||||
|
|
||||||
export const PageList: Page[] = [
|
|
||||||
// {
|
|
||||||
// code: PageCode.Auth,
|
|
||||||
// name: 'Вход',
|
|
||||||
// resName: 'auth',
|
|
||||||
// onSideBar: false,
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
code: PageCode.Orders,
|
|
||||||
name: 'Заказы',
|
|
||||||
resName: 'orders',
|
|
||||||
onSideBar: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const PageListWithBonus: Page[] = [
|
|
||||||
// {
|
|
||||||
// code: PageCode.Auth,
|
|
||||||
// name: 'Вход',
|
|
||||||
// resName: 'auth',
|
|
||||||
// onSideBar: false,
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
code: PageCode.BonusProgram,
|
|
||||||
name: 'Ваша карта лояльности',
|
|
||||||
description: '',
|
|
||||||
resName: 'bonus-program',
|
|
||||||
onSideBar: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: PageCode.Transactions,
|
|
||||||
name: 'Чеки',
|
|
||||||
description: '',
|
|
||||||
resName: 'transactions',
|
|
||||||
onSideBar: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: PageCode.Orders,
|
|
||||||
name: 'Заказы',
|
|
||||||
description: '',
|
|
||||||
resName: 'orders',
|
|
||||||
onSideBar: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: PageCode.Logout,
|
|
||||||
name: 'Выйти',
|
|
||||||
description: '',
|
|
||||||
resName: 'logout',
|
|
||||||
onSideBar: true,
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// code: PageCode.UserData,
|
|
||||||
// name: 'Заполнить анкету',
|
|
||||||
// description: '',
|
|
||||||
// resName: 'user-data',
|
|
||||||
// onSideBar: true
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// code: PageCode.RefSystem,
|
|
||||||
// name: 'Пригласить друга',
|
|
||||||
// description: '',
|
|
||||||
// resName: 'ref-system',
|
|
||||||
// onSideBar: true,
|
|
||||||
// },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const PageListMain: Page[] = [
|
|
||||||
{
|
|
||||||
code: MainPageCode.Account,
|
|
||||||
name: 'Аккаунт',
|
|
||||||
resName: 'account',
|
|
||||||
onSideBar: true,
|
|
||||||
icon: 'person',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: MainPageCode.Products,
|
|
||||||
name: 'Товары',
|
|
||||||
resName: 'products',
|
|
||||||
onSideBar: true,
|
|
||||||
icon: 'manage_search',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: MainPageCode.Cart,
|
|
||||||
name: 'Корзина',
|
|
||||||
resName: 'cart',
|
|
||||||
onSideBar: true,
|
|
||||||
icon: 'shopping_bag',
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// code: MainPageCode.Info,
|
|
||||||
// name: 'О нас',
|
|
||||||
// resName: 'info',
|
|
||||||
// onSideBar: true,
|
|
||||||
// icon: 'info'
|
|
||||||
// },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const orderStatuses: OrderStatus = {
|
|
||||||
Cancelled: 'Отменен',
|
|
||||||
InProcessing: 'В обработке',
|
|
||||||
Unconfirmed: 'Принят',
|
|
||||||
WaitCooking: 'Принят',
|
|
||||||
ReadyForCooking: 'Принят',
|
|
||||||
CookingStarted: 'Готовится',
|
|
||||||
CookingCompleted: 'Приготовлен',
|
|
||||||
Waiting: 'В пути',
|
|
||||||
OnWay: 'В пути',
|
|
||||||
Delivered: 'Выполнен',
|
|
||||||
Closed: 'Выполнен',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const paymentMethods: PaymentMethod[] = [
|
|
||||||
{
|
|
||||||
type: 'Card',
|
|
||||||
label: 'Безналичный расчет',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'Cash',
|
|
||||||
label: 'Наличными',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const dateFilterOptions: IOptionDateFilter[] = [
|
|
||||||
{
|
|
||||||
name: 'Текущий месяц',
|
|
||||||
value: 'currentMonth',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Прошлый месяц',
|
|
||||||
value: 'lastMonth',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Между',
|
|
||||||
value: 'between',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const APP_DATE_FORMATS: MatDateFormats = {
|
|
||||||
parse: {
|
|
||||||
dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
|
|
||||||
},
|
|
||||||
display: {
|
|
||||||
dateInput: 'input',
|
|
||||||
monthYearLabel: { year: 'numeric', month: 'numeric' },
|
|
||||||
dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
|
|
||||||
monthYearA11yLabel: { year: 'numeric', month: 'long' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,194 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
import { MainComponent } from './pages/main/main.component';
|
|
||||||
import { NavbarComponent } from './components/navbar/navbar.component';
|
|
||||||
import { CardComponent } from './components/card/card.component';
|
|
||||||
import { InputMaskModule } from 'primeng/inputmask';
|
|
||||||
import { AuthComponent } from './pages/account/auth/auth.component';
|
|
||||||
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { AccountComponent } from './pages/account/account.component';
|
|
||||||
import { ExitComponent } from './components/exit/exit.component';
|
|
||||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
||||||
import { DialogService } from 'primeng/dynamicdialog';
|
|
||||||
import { BonusProgramComponent } from './pages/account/bonus-program/bonus-program.component';
|
|
||||||
import { OrdersComponent } from './pages/account/orders/orders.component';
|
|
||||||
import { OrderInfoComponent } from './components/order-info/order-info.component';
|
|
||||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
|
||||||
import { environment } from '../environments/environment';
|
|
||||||
import { AngularFireModule } from '@angular/fire/compat';
|
|
||||||
import { AngularFireMessagingModule } from '@angular/fire/compat/messaging';
|
|
||||||
import { ToastModule } from 'primeng/toast';
|
|
||||||
import { MessageService } from 'primeng/api';
|
|
||||||
import { FooterButtonsComponent } from './components/footer-buttons/footer-buttons.component';
|
|
||||||
import { UserDataComponent } from './pages/account/user-data/user-data.component';
|
|
||||||
import { RefSystemComponent } from './pages/account/ref-system/ref-system.component';
|
|
||||||
import { QRCodeModule } from 'angularx-qrcode';
|
|
||||||
import { ShareButtonsModule } from 'ngx-sharebuttons/buttons';
|
|
||||||
import { ShareIconsModule } from 'ngx-sharebuttons/icons';
|
|
||||||
import { MessagingService } from './services/messaging.service';
|
|
||||||
import { NotFoundComponent } from './pages/not-found/not-found.component';
|
|
||||||
import { ProductsComponent } from './pages/products/products.component';
|
|
||||||
import { CartComponent } from './pages/cart/cart.component';
|
|
||||||
import { ListboxModule } from 'primeng/listbox';
|
|
||||||
import { ProductModalComponent } from './components/product-modal/product-modal.component';
|
|
||||||
import { CheckboxGroupComponent } from './components/checkbox-group/checkbox-group.component';
|
|
||||||
import { TreeSelectModule } from 'primeng/treeselect';
|
|
||||||
import { UserDataOrderComponent } from './components/user-data-order/user-data-order.component';
|
|
||||||
import { DropdownModule } from 'primeng/dropdown';
|
|
||||||
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
||||||
import { CalendarModule } from 'primeng/calendar';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { InfoComponent } from './pages/info/info.component';
|
|
||||||
import { MdbCarouselModule } from 'mdb-angular-ui-kit/carousel';
|
|
||||||
import { StoreModule } from '@ngrx/store';
|
|
||||||
import { configReducer } from './state/config/config.reducer';
|
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
|
||||||
import { ConfigEffects } from './state/config/config.effects';
|
|
||||||
import { PaginatorModule } from 'primeng/paginator';
|
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
|
||||||
import { ChangeQuantityComponent } from './components/change-quantity/change-quantity.component';
|
|
||||||
import { MenuComponent } from './components/menu/menu.component';
|
|
||||||
import { SidebarModule } from 'primeng/sidebar';
|
|
||||||
import { RippleModule } from 'primeng/ripple';
|
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
|
||||||
import { ModifierComponent } from './components/modifier/modifier.component';
|
|
||||||
import { OptionComponent } from './components/option/option.component';
|
|
||||||
import { ChangeQuantityOptionDirective } from './directives/change-quantity-option.directive';
|
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
|
||||||
import {
|
|
||||||
MatFormFieldModule,
|
|
||||||
MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
|
||||||
} from '@angular/material/form-field';
|
|
||||||
import { MatInputModule } from '@angular/material/input';
|
|
||||||
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
|
||||||
import { TerminalListComponent } from './components/terminal-list/terminal-list.component';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatListModule } from '@angular/material/list';
|
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { SnackBarComponent } from './components/snack-bar/snack-bar.component';
|
|
||||||
import {MatDialogModule} from '@angular/material/dialog';
|
|
||||||
import { PurchaseInfoComponent } from './components/purchase-info/purchase-info.component';
|
|
||||||
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';
|
|
||||||
import { PurcahsesComponent } from './pages/account/purcahses/purcahses.component';
|
|
||||||
|
|
||||||
const routes: Routes = [
|
|
||||||
{ path: '', redirectTo: 'products', pathMatch: 'full' },
|
|
||||||
{ path: 'products', component: ProductsComponent },
|
|
||||||
// { path: 'cart', component: CartComponent },
|
|
||||||
{ path: 'account', component: AccountComponent },
|
|
||||||
{ path: '**', component: NotFoundComponent },
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
|
||||||
AppComponent,
|
|
||||||
NavbarComponent,
|
|
||||||
MainComponent,
|
|
||||||
CardComponent,
|
|
||||||
AuthComponent,
|
|
||||||
AccountComponent,
|
|
||||||
ExitComponent,
|
|
||||||
BonusProgramComponent,
|
|
||||||
OrdersComponent,
|
|
||||||
OrderInfoComponent,
|
|
||||||
FooterButtonsComponent,
|
|
||||||
UserDataComponent,
|
|
||||||
RefSystemComponent,
|
|
||||||
NotFoundComponent,
|
|
||||||
ProductsComponent,
|
|
||||||
CartComponent,
|
|
||||||
ProductModalComponent,
|
|
||||||
CheckboxGroupComponent,
|
|
||||||
UserDataOrderComponent,
|
|
||||||
InfoComponent,
|
|
||||||
ChangeQuantityComponent,
|
|
||||||
MenuComponent,
|
|
||||||
ModifierComponent,
|
|
||||||
OptionComponent,
|
|
||||||
ChangeQuantityOptionDirective,
|
|
||||||
TerminalListComponent,
|
|
||||||
SnackBarComponent,
|
|
||||||
PurchaseInfoComponent,
|
|
||||||
DateFilterComponent,
|
|
||||||
PurcahsesComponent,
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
AppRoutingModule,
|
|
||||||
RouterModule.forRoot(routes, {
|
|
||||||
scrollPositionRestoration: 'enabled',
|
|
||||||
}),
|
|
||||||
InputMaskModule,
|
|
||||||
ProgressSpinnerModule,
|
|
||||||
FormsModule,
|
|
||||||
HttpClientModule,
|
|
||||||
BrowserAnimationsModule,
|
|
||||||
BrowserModule,
|
|
||||||
ServiceWorkerModule.register('ngsw-worker.js', {
|
|
||||||
enabled: environment.production,
|
|
||||||
// Register the ServiceWorker as soon as the application is stable
|
|
||||||
// or after 30 seconds (whichever comes first).
|
|
||||||
registrationStrategy: 'registerWhenStable:30000',
|
|
||||||
}),
|
|
||||||
AngularFireModule.initializeApp(environment.firebase),
|
|
||||||
AngularFireMessagingModule,
|
|
||||||
ToastModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
QRCodeModule,
|
|
||||||
ShareButtonsModule.withConfig({
|
|
||||||
debug: true,
|
|
||||||
}),
|
|
||||||
ShareIconsModule,
|
|
||||||
ListboxModule,
|
|
||||||
TreeSelectModule,
|
|
||||||
DropdownModule,
|
|
||||||
SelectButtonModule,
|
|
||||||
CalendarModule,
|
|
||||||
MatIconModule,
|
|
||||||
MdbCarouselModule,
|
|
||||||
StoreModule.forRoot({ config: configReducer, profile: profileReducer }),
|
|
||||||
EffectsModule.forRoot([ConfigEffects, ProfileEffects]),
|
|
||||||
PaginatorModule,
|
|
||||||
InputTextModule,
|
|
||||||
SidebarModule,
|
|
||||||
RippleModule,
|
|
||||||
MatTabsModule,
|
|
||||||
MatSelectModule,
|
|
||||||
MatFormFieldModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatBottomSheetModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatListModule,
|
|
||||||
MatSnackBarModule,
|
|
||||||
MatDialogModule,
|
|
||||||
MatDatepickerModule,
|
|
||||||
MatNativeDateModule
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
DialogService,
|
|
||||||
MessageService,
|
|
||||||
MessagingService,
|
|
||||||
{
|
|
||||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
|
||||||
useValue: { appearance: 'outline' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: HTTP_INTERCEPTORS,
|
|
||||||
useClass: CustomerInfoInterceptor,
|
|
||||||
multi: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
bootstrap: [AppComponent],
|
|
||||||
})
|
|
||||||
export class AppModule {}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
<div class="change-quantity">
|
|
||||||
<button (click)="changeValue({type: 'minus', variableQuantity: variableQuantity})"
|
|
||||||
[disabled]="disabledButton.includes('minus')"
|
|
||||||
[ngClass]="{
|
|
||||||
'is-active': !disabledButton.includes('minus')
|
|
||||||
}">
|
|
||||||
-
|
|
||||||
</button>
|
|
||||||
<span>
|
|
||||||
{{value}}
|
|
||||||
</span>
|
|
||||||
<button (click)="changeValue({type: 'plus', variableQuantity: variableQuantity})"
|
|
||||||
[disabled]="disabledButton.includes('plus')"
|
|
||||||
[ngClass]="{
|
|
||||||
'is-active': !disabledButton.includes('plus')
|
|
||||||
}">
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
:host {
|
|
||||||
.change-quantity {
|
|
||||||
border: 1px solid #dfdee2;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin: 0;
|
|
||||||
height: 100%;
|
|
||||||
min-width: 100px;
|
|
||||||
padding: 0 8px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: #ffffff;
|
|
||||||
border: 0;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 300;
|
|
||||||
&:disabled {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ChangeQuantityComponent } from './change-quantity.component';
|
|
||||||
|
|
||||||
describe('ChangeQuantityComponent', () => {
|
|
||||||
let component: ChangeQuantityComponent;
|
|
||||||
let fixture: ComponentFixture<ChangeQuantityComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ ChangeQuantityComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ChangeQuantityComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
||||||
|
|
||||||
export interface ChangeValue {
|
|
||||||
type: 'plus' | 'minus',
|
|
||||||
variableQuantity: number
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-change-quantity',
|
|
||||||
templateUrl: './change-quantity.component.html',
|
|
||||||
styleUrls: ['./change-quantity.component.scss']
|
|
||||||
})
|
|
||||||
export class ChangeQuantityComponent implements OnInit {
|
|
||||||
@Output() onChangeValue = new EventEmitter<ChangeValue>();
|
|
||||||
@Input() variableQuantity: number = 1
|
|
||||||
@Input() value: number = 1
|
|
||||||
@Input() disabledButton: 'minus' | 'plus' | 'none' | string[] = 'none'
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
changeValue(changeValue: ChangeValue) {
|
|
||||||
this.onChangeValue.emit(changeValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
<!-- <div *ngFor="let option of options; let index = index;" class="extra_options_checkbox">
|
|
||||||
<div class="extra_options_label"><label>{{option.name}}</label></div>
|
|
||||||
<div class="extra_options_value">
|
|
||||||
<div class="woofood-cbx-wrapper">
|
|
||||||
<input class="inp-woofood-cbx"
|
|
||||||
[disabled]="!optionIsSelected(option) && selectedOptions.length >= modifier.restrictions.maxQuantity && (modifier.restrictions.maxQuantity > 1 || !modifier.restrictions.minQuantity)"
|
|
||||||
[checked]="optionIsSelected(option)"
|
|
||||||
[type]="modifier.restrictions.maxQuantity > 1 || !modifier.restrictions.minQuantity ? 'checkbox' : 'radio'"
|
|
||||||
style="display: none" name="add_extra_option" value="{{option.id}}" id="{{option.id}}"
|
|
||||||
(change)="onToggle(option)">
|
|
||||||
<label class="woofood-cbx" for="{{option.id}}">
|
|
||||||
<span>
|
|
||||||
<svg width="12px" height="10px" viewBox="0 0 12 10">
|
|
||||||
<polyline points="1.5 6 4.5 9 10.5 1"></polyline>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<span>{{currencySymbol}}{{option.price}}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<span *ngIf="modifier.restrictions.minQuantity > allQuantity" class="validator-text">
|
|
||||||
Минимальное количество продуктов: {{modifier.restrictions.minQuantity}}
|
|
||||||
</span>
|
|
||||||
<div *ngFor="let option of options; let index = index;" class="extra_options_checkbox">
|
|
||||||
<div class="extra_options_label"><label>{{option.name}}</label></div>
|
|
||||||
<div class="extra_options_value">
|
|
||||||
<app-change-quantity (onChangeValue)="changeQuantity($event, option)"
|
|
||||||
[value]="(option.quantity || option.quantity === 0) ? option.quantity : option.restrictions.byDefault"
|
|
||||||
[disabledButton]="getDisabledButton(option)">
|
|
||||||
</app-change-quantity>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
:host {
|
|
||||||
.extra_options_checkbox {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.extra_options_label {
|
|
||||||
width: 70%;
|
|
||||||
float: left;
|
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin: 5px;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.extra_options_value {
|
|
||||||
width: 30%;
|
|
||||||
float: left;
|
|
||||||
|
|
||||||
.woofood-cbx-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
|
|
||||||
.woofood-cbx {
|
|
||||||
margin: auto;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: 30px;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
|
|
||||||
span:first-child {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
margin-right: 8px;
|
|
||||||
border-radius: 3px;
|
|
||||||
transform: scale(1);
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 1px solid #9098A9;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: #cc0000;
|
|
||||||
display: block;
|
|
||||||
transform: scale(0);
|
|
||||||
opacity: 1;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
position: absolute;
|
|
||||||
top: 3px;
|
|
||||||
left: 2px;
|
|
||||||
fill: none;
|
|
||||||
stroke: #FFFFFF;
|
|
||||||
stroke-width: 2;
|
|
||||||
stroke-linecap: round;
|
|
||||||
stroke-linejoin: round;
|
|
||||||
stroke-dasharray: 16px;
|
|
||||||
stroke-dashoffset: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.inp-woofood-cbx:checked+.woofood-cbx span:first-child {
|
|
||||||
background: #cc0000;
|
|
||||||
border-color: #cc0000;
|
|
||||||
animation: wave 0.4s ease;
|
|
||||||
svg {
|
|
||||||
stroke-dashoffset: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.inp-woofood-cbx:disabled+.woofood-cbx span:first-child {
|
|
||||||
border-color: #dfdfdf !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.validator-text {
|
|
||||||
color: #cc0000;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { CheckboxGroupComponent } from './checkbox-group.component';
|
|
||||||
|
|
||||||
describe('CheckboxGroupComponent', () => {
|
|
||||||
let component: CheckboxGroupComponent;
|
|
||||||
let fixture: ComponentFixture<CheckboxGroupComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ CheckboxGroupComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(CheckboxGroupComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
|
||||||
import {CartModifier, Modifier, ModifiersGroup, Option} from 'src/app/interface/data';
|
|
||||||
import { cloneDeep } from 'lodash/fp';
|
|
||||||
import { ChangeValue } from '../change-quantity/change-quantity.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-checkbox-group',
|
|
||||||
templateUrl: './checkbox-group.component.html',
|
|
||||||
styleUrls: ['./checkbox-group.component.scss']
|
|
||||||
})
|
|
||||||
export class CheckboxGroupComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
@Input() modifier!: CartModifier;
|
|
||||||
@Input() options!: Modifier[];
|
|
||||||
@Input() currencySymbol!: string;
|
|
||||||
@Input() selectedOptions: Modifier[] = [];
|
|
||||||
|
|
||||||
@Output() toggle = new EventEmitter<Modifier>();
|
|
||||||
@Output() onChangeQuantity = new EventEmitter<any>();
|
|
||||||
|
|
||||||
|
|
||||||
public allQuantity!: number
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.allQuantity = this.getAllQuantity(this.options, 'quantity')
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllQuantity(array: Array<any>, key: string) {
|
|
||||||
return array.reduce((a, b) => a + (b[key] || 0), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
optionIsSelected(option: Modifier): boolean{
|
|
||||||
return !!this.selectedOptions.find(selected => selected.id === option.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggle(option: Modifier){
|
|
||||||
this.toggle.emit(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeQuantity(value: ChangeValue, option: Modifier) {
|
|
||||||
this.onChangeQuantity.emit({
|
|
||||||
value,
|
|
||||||
option,
|
|
||||||
modifierGroup: this.modifier
|
|
||||||
})
|
|
||||||
this.allQuantity = this.getAllQuantity(this.options, 'quantity')
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
getDisabledButton(option: Modifier) {
|
|
||||||
if (!option.quantity && option.quantity !== 0) option.quantity = option.restrictions.byDefault
|
|
||||||
const minusCondition = option.quantity === 0 || option.quantity === option.restrictions.minQuantity
|
|
||||||
const plusCondition = option.quantity === option.restrictions.maxQuantity && option.restrictions.maxQuantity !== 0
|
|
||||||
const maxQuantityCondition = this.allQuantity === this.modifier.restrictions.maxQuantity && this.modifier.restrictions.maxQuantity !== 0
|
|
||||||
const minQuantityCondition = this.allQuantity === this.modifier.restrictions.minQuantity
|
|
||||||
let result: any = 'none'
|
|
||||||
if (minusCondition || (minQuantityCondition && !minusCondition)) result = 'minus'
|
|
||||||
if (plusCondition || (maxQuantityCondition && !minusCondition)) result = 'plus'
|
|
||||||
if ((maxQuantityCondition && minusCondition) || (minQuantityCondition && plusCondition)) result = ['plus', 'minus']
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
<div class="date-filter-container">
|
|
||||||
<form [formGroup]="dateFilterForm" (ngSubmit)="submitFilter()">
|
|
||||||
<mat-form-field appearance="fill">
|
|
||||||
<mat-select formControlName="filterType">
|
|
||||||
<mat-option *ngFor="let option of options" [value]="option.value">{{
|
|
||||||
option.name
|
|
||||||
}}</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
<mat-label>Фильтр</mat-label>
|
|
||||||
<mat-hint>Тип</mat-hint>
|
|
||||||
</mat-form-field>
|
|
||||||
<div
|
|
||||||
*ngIf="currentFilterType === 'between'"
|
|
||||||
class="date-filter-container__date-inputs"
|
|
||||||
>
|
|
||||||
<mat-form-field class="date-range-input-field" appearance="fill">
|
|
||||||
<mat-label>Интервал времени</mat-label>
|
|
||||||
<mat-date-range-input
|
|
||||||
[rangePicker]="campaignTwoPicker"
|
|
||||||
[comparisonStart]="dateFilterForm.value.from"
|
|
||||||
[comparisonEnd]="dateFilterForm.value.to"
|
|
||||||
>
|
|
||||||
<input matStartDate placeholder="От: " formControlName="from" />
|
|
||||||
<input matEndDate placeholder="До: " formControlName="to" />
|
|
||||||
</mat-date-range-input>
|
|
||||||
<mat-hint>дд.мм.гггг – дд.мм.гггг</mat-hint>
|
|
||||||
<mat-datepicker-toggle
|
|
||||||
matIconSuffix
|
|
||||||
[for]="campaignTwoPicker"
|
|
||||||
></mat-datepicker-toggle>
|
|
||||||
<mat-date-range-picker #campaignTwoPicker>
|
|
||||||
<mat-date-range-picker-actions>
|
|
||||||
<button mat-button matDateRangePickerCancel>Назад</button>
|
|
||||||
<button mat-raised-button color="primary" matDateRangePickerApply>
|
|
||||||
Подтвердить
|
|
||||||
</button>
|
|
||||||
</mat-date-range-picker-actions>
|
|
||||||
</mat-date-range-picker>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<button mat-stroked-button class="apply" type="submit">Применить</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
:host {
|
|
||||||
.date-filter-container {
|
|
||||||
& > form {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1065px) {
|
|
||||||
:host {
|
|
||||||
.date-filter-container {
|
|
||||||
& > form {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-range-input-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.apply {
|
|
||||||
height: 51.67px;
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { DateFilterComponent } from './date-filter.component';
|
|
||||||
|
|
||||||
describe('DateFilterComponent', () => {
|
|
||||||
let component: DateFilterComponent;
|
|
||||||
let fixture: ComponentFixture<DateFilterComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ DateFilterComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(DateFilterComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
|
||||||
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
|
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import moment from 'moment';
|
|
||||||
import { APP_DATE_FORMATS } from 'src/app/app.constants';
|
|
||||||
import { IDateFilter, IOptionDateFilter } from 'src/app/interface/data';
|
|
||||||
import { DateAdapterService } from 'src/app/services/date-adapter.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-date-filter[options]',
|
|
||||||
templateUrl: './date-filter.component.html',
|
|
||||||
styleUrls: ['./date-filter.component.scss'],
|
|
||||||
providers: [
|
|
||||||
{ provide: DateAdapter, useClass: DateAdapterService },
|
|
||||||
{ provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS },
|
|
||||||
{ provide: MAT_DATE_LOCALE, useValue: 'ru-RU' }
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class DateFilterComponent implements OnInit {
|
|
||||||
@Input() defaultFilterType!: string;
|
|
||||||
@Output() onSubmitFilter = new EventEmitter<any>();
|
|
||||||
@Input() options!: IOptionDateFilter[];
|
|
||||||
|
|
||||||
public currentFilterType!: string;
|
|
||||||
|
|
||||||
public dateFilterForm = new FormGroup({
|
|
||||||
filterType: new FormControl<string>(''),
|
|
||||||
from: new FormControl<Date | null>(null),
|
|
||||||
to: new FormControl<Date | null>(null),
|
|
||||||
});
|
|
||||||
|
|
||||||
constructor(private _snackBar: MatSnackBar) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.currentFilterType = this.defaultFilterType
|
|
||||||
? this.defaultFilterType
|
|
||||||
: this.options[0].value;
|
|
||||||
const filterType = this.dateFilterForm.get('filterType');
|
|
||||||
filterType?.setValue(this.currentFilterType);
|
|
||||||
filterType?.valueChanges.subscribe({
|
|
||||||
next: (value) => {
|
|
||||||
this.currentFilterType = value ?? '';
|
|
||||||
const fromControl = this.dateFilterForm.get('from')
|
|
||||||
const toControl = this.dateFilterForm.get('to')
|
|
||||||
|
|
||||||
if (this.currentFilterType === 'between') {
|
|
||||||
this.dateFilterForm.controls.from.addValidators([
|
|
||||||
Validators.required,
|
|
||||||
]);
|
|
||||||
this.dateFilterForm.controls.to.addValidators([Validators.required]);
|
|
||||||
} else {
|
|
||||||
fromControl?.clearValidators()
|
|
||||||
toControl?.clearValidators()
|
|
||||||
}
|
|
||||||
fromControl?.updateValueAndValidity()
|
|
||||||
toControl?.updateValueAndValidity()
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submitFilter() {
|
|
||||||
if (!this.dateFilterForm.valid) {
|
|
||||||
this._snackBar.open('Заполните все поля!', 'Ок', {
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.onSubmitFilter.emit(this.dateFilterForm.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
<nav class="main-menu-container" isShow="false" #menu>
|
|
||||||
<ul>
|
|
||||||
<ng-container
|
|
||||||
*ngFor="
|
|
||||||
let page of mainPageList;
|
|
||||||
let index = index;
|
|
||||||
let last = last;
|
|
||||||
let first = first
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<li
|
|
||||||
*ngIf="page.onSideBar && !last"
|
|
||||||
class="main-menu-container__item"
|
|
||||||
[ngClass]="{
|
|
||||||
cart: page.resName === 'cart'
|
|
||||||
}"
|
|
||||||
[attr.data-counter]="page.resName === 'cart' ? cartCount : null"
|
|
||||||
[routerLink]="page.resName"
|
|
||||||
routerLinkActive="active"
|
|
||||||
>
|
|
||||||
<mat-icon
|
|
||||||
[ngClass]="{
|
|
||||||
'mat-icon': true
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ page.icon }}
|
|
||||||
</mat-icon>
|
|
||||||
<a>
|
|
||||||
{{ page.name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ng-container>
|
|
||||||
<li
|
|
||||||
*ngIf="mainPageList[mainPageList.length - 1].onSideBar"
|
|
||||||
class="main-menu-container__item"
|
|
||||||
[ngClass]="{
|
|
||||||
cart: true
|
|
||||||
}"
|
|
||||||
[attr.data-counter]="cartCount"
|
|
||||||
(click)="changeMainPage(mainPageList[mainPageList.length - 1])"
|
|
||||||
>
|
|
||||||
<mat-icon
|
|
||||||
[ngClass]="{
|
|
||||||
'mat-icon': true
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ mainPageList[mainPageList.length - 1].icon }}
|
|
||||||
</mat-icon>
|
|
||||||
<a>
|
|
||||||
{{ mainPageList[mainPageList.length - 1].name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
@ -1,122 +0,0 @@
|
|||||||
@import "src/sass/mixins";
|
|
||||||
|
|
||||||
:host {
|
|
||||||
.main-menu-container {
|
|
||||||
// position: fixed;
|
|
||||||
// width: 100%;
|
|
||||||
// bottom: 0;
|
|
||||||
// left: 0;
|
|
||||||
// margin: 0;
|
|
||||||
// z-index: 777;
|
|
||||||
// height: 57px;
|
|
||||||
// border-top: solid 1px #dfdfdf;
|
|
||||||
// background-color: #fff;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 32px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
color: #b5b5b9;
|
|
||||||
transition: color 0.3s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: #252525;
|
|
||||||
|
|
||||||
a {
|
|
||||||
border-bottom: 2px solid #e16f38;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include hover-supported() {
|
|
||||||
color: #252525;
|
|
||||||
|
|
||||||
a {
|
|
||||||
border-bottom: 2px solid #e16f38;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
border-bottom: 2px solid #e16f3800;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .mat-icon {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.cart {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: attr(data-counter);
|
|
||||||
color: #fff;
|
|
||||||
position: absolute;
|
|
||||||
right: -18px;
|
|
||||||
top: -8px;
|
|
||||||
background: #d7120b;
|
|
||||||
border-radius: 50px;
|
|
||||||
min-width: 1.2rem;
|
|
||||||
line-height: 1.2rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.main-menu-container {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
margin: 0;
|
|
||||||
z-index: 777;
|
|
||||||
border-top: solid 1px #dfdfdf;
|
|
||||||
background-color: #fff;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
padding-top: 8px;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
li {
|
|
||||||
&.cart {
|
|
||||||
&::before {
|
|
||||||
right: 34px;
|
|
||||||
top: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .mat-icon {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { MenuComponent } from './menu.component';
|
|
||||||
|
|
||||||
describe('MenuComponent', () => {
|
|
||||||
let component: MenuComponent;
|
|
||||||
let fixture: ComponentFixture<MenuComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ MenuComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(MenuComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { PageListMain } from 'src/app/app.constants';
|
|
||||||
import { Page } from 'src/app/interface/data';
|
|
||||||
import { CartService } from 'src/app/services/cart.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-menu',
|
|
||||||
templateUrl: './menu.component.html',
|
|
||||||
styleUrls: ['./menu.component.scss'],
|
|
||||||
})
|
|
||||||
export class MenuComponent implements OnInit {
|
|
||||||
@Output() toggleMenu = new EventEmitter();
|
|
||||||
readonly mainPageList = PageListMain;
|
|
||||||
public cartCount = 0;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private cartService: CartService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.cartCount = this.cartService.cartCount;
|
|
||||||
this.cartService.cartCount$.subscribe({
|
|
||||||
next: (count) => {
|
|
||||||
this.cartCount = count;
|
|
||||||
document
|
|
||||||
.querySelectorAll('.cart')[0]
|
|
||||||
.setAttribute('data-counter', this.cartCount.toString());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
changeMainPage(page: Page, event?: MouseEvent): void {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
if (page.resName === 'cart') {
|
|
||||||
this.toggleMenu.emit()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.router.navigate([page.resName], {
|
|
||||||
// relativeTo: this.route,
|
|
||||||
// queryParamsHandling: 'merge',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<div class="modifier-container">
|
|
||||||
<ng-content select="[counter]"></ng-content>
|
|
||||||
<h3>{{ modifier.name }}</h3>
|
|
||||||
<div class="modifier-container__options">
|
|
||||||
<app-option
|
|
||||||
*ngFor="let option of modifier.options"
|
|
||||||
[option]="option"
|
|
||||||
[modifier]="modifier"
|
|
||||||
[product]="product"
|
|
||||||
></app-option>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
:host {
|
|
||||||
.modifier-container {
|
|
||||||
margin-bottom: 32px;
|
|
||||||
&__options {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ModifierComponent } from './modifier.component';
|
|
||||||
|
|
||||||
describe('ModifierComponent', () => {
|
|
||||||
let component: ModifierComponent;
|
|
||||||
let fixture: ComponentFixture<ModifierComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ ModifierComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ModifierComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
||||||
import { CartModifier, Modifier } from 'src/app/interface/data';
|
|
||||||
import { CartProduct } from 'src/app/models/cart-product';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-modifier[modifier][product]',
|
|
||||||
templateUrl: './modifier.component.html',
|
|
||||||
styleUrls: ['./modifier.component.scss']
|
|
||||||
})
|
|
||||||
export class ModifierComponent implements OnInit {
|
|
||||||
@Input() product!: CartProduct
|
|
||||||
@Input() modifier!: CartModifier
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<div class="container-navbar">
|
|
||||||
<img src="./assets/sakura-logo.png" alt="Логотип">
|
|
||||||
<!-- <span class="menu" (click)="showMenu()">Меню</span> -->
|
|
||||||
<app-cart #cart></app-cart>
|
|
||||||
<app-menu (toggleMenu)="cart.toggleSideBar()"></app-menu>
|
|
||||||
</div>
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
.container-navbar {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 16px 54px;
|
|
||||||
width: 100%;
|
|
||||||
height: fit-content;
|
|
||||||
color: #fff;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 68px;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu {
|
|
||||||
color: #252525;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 14px;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
border-bottom: 2px solid #e16f38;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 18px;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.container-navbar {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 549px) {
|
|
||||||
.container-navbar {
|
|
||||||
.menu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
<div
|
|
||||||
appChangeQuantityOption
|
|
||||||
[option]="option"
|
|
||||||
[modifier]="modifier"
|
|
||||||
[product]="product"
|
|
||||||
[ngClass]="{
|
|
||||||
'option-container': true,
|
|
||||||
'selected': option.quantity
|
|
||||||
}"
|
|
||||||
[attr.quantity]="option.quantity"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="{{ option.image?.length ? option.image : './assets/no-image.png' }}"
|
|
||||||
alt="{{ option.name }}"
|
|
||||||
/>
|
|
||||||
<h4>{{ option.name }}</h4>
|
|
||||||
</div>
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
:host {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 170px;
|
|
||||||
.option-container {
|
|
||||||
align-items: center;
|
|
||||||
border: 1px solid #d8d8d8;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 0;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
position: relative;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
border-color: var(--orange-main);
|
|
||||||
}
|
|
||||||
|
|
||||||
&[quantity] {
|
|
||||||
&::before {
|
|
||||||
content: attr(quantity);
|
|
||||||
display: block;
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
background-color: var(--orange-main);
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
color: #fff;
|
|
||||||
right: 10px;
|
|
||||||
top: 6px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[quantity="0"] {
|
|
||||||
&::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
|
||||||
:host {
|
|
||||||
max-width: calc(50% - 6px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { OptionComponent } from './option.component';
|
|
||||||
|
|
||||||
describe('OptionComponent', () => {
|
|
||||||
let component: OptionComponent;
|
|
||||||
let fixture: ComponentFixture<OptionComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ OptionComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(OptionComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
||||||
import { CartModifier, Modifier } from 'src/app/interface/data';
|
|
||||||
import { CartProduct } from 'src/app/models/cart-product';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-option[option][modifier][product]',
|
|
||||||
templateUrl: './option.component.html',
|
|
||||||
styleUrls: ['./option.component.scss']
|
|
||||||
})
|
|
||||||
export class OptionComponent implements OnInit {
|
|
||||||
@Input() option!: Modifier
|
|
||||||
@Input() modifier!: CartModifier;
|
|
||||||
@Input() product!: CartProduct;
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
<div class="product-modal">
|
|
||||||
<div class="product-modal__information-container" [ngStyle]="{
|
|
||||||
'max-width': product.modifiers_group.length ? 'calc(50% - 16px)' : '100%'
|
|
||||||
}">
|
|
||||||
<img
|
|
||||||
src="{{
|
|
||||||
product.image?.length ? product.image : './assets/no-image.png'
|
|
||||||
}}"
|
|
||||||
alt="{{ product.name }}"
|
|
||||||
/>
|
|
||||||
<p class="product-modal__description">{{product.description}}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
*ngIf="product.modifiers_group.length"
|
|
||||||
class="product-modal__modifiers-container"
|
|
||||||
>
|
|
||||||
<!-- <ng-container *ngIf="product.modifiers_group.length">
|
|
||||||
<div *ngFor="let modifierGroup of cartProduct.modifiers" [attr.isShow]="false"
|
|
||||||
[ngClass]="{'product-modal__modifier': true, 'no-valid': isValidate && modifierGroup.allQuantity < modifierGroup.restrictions.minQuantity}" #modifierContainer>
|
|
||||||
<a (click)="setOptionsView($event, modifierContainer)">
|
|
||||||
{{modifierGroup.name}}
|
|
||||||
<span [ngClass]="{
|
|
||||||
'product-modal__modifier-icon': true,
|
|
||||||
'isShow': getIsShow(modifierContainer)
|
|
||||||
}"></span>
|
|
||||||
</a>
|
|
||||||
<div [ngClass]="{
|
|
||||||
'options-container': true,
|
|
||||||
'isShow': getIsShow(modifierContainer)
|
|
||||||
}">
|
|
||||||
<app-checkbox-group [modifier]="modifierGroup" [options]="modifierGroup.options"
|
|
||||||
currencySymbol="₽" (onChangeQuantity)="changeQuantity($event)">
|
|
||||||
</app-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-container> -->
|
|
||||||
<app-modifier
|
|
||||||
*ngFor="let modifier of cartProduct.modifiers; let index = index"
|
|
||||||
[modifier]="modifier"
|
|
||||||
[product]="cartProduct"
|
|
||||||
>
|
|
||||||
<span counter>{{ index + 1 }} из {{ cartProduct.modifiers.length }}</span>
|
|
||||||
</app-modifier>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="product-modal__footer">
|
|
||||||
<!-- <app-change-quantity (onChangeValue)="changeProductAmount()"></app-change-quantity> -->
|
|
||||||
<span class="product-modal__footer-price">{{ cartProduct.finalPrice }}₽</span>
|
|
||||||
<div class="product-modal__footer-buttons">
|
|
||||||
<app-change-quantity [disabledButton]="cartProduct.amount === 1 ? 'minus' : 'none'" [value]="cartProduct.amount" (onChangeValue)="changeProductAmount($event)"></app-change-quantity>
|
|
||||||
<button class="product-modal__add-to-cart" (click)="addToCart($event)">
|
|
||||||
Добавить
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p-toast
|
|
||||||
position="bottom-center"
|
|
||||||
key="cC"
|
|
||||||
(onClose)="onReject()"
|
|
||||||
[baseZIndex]="5000"
|
|
||||||
>
|
|
||||||
<ng-template let-message pTemplate="message">
|
|
||||||
<div class="flex flex-column" style="flex: 1">
|
|
||||||
<div class="text-center">
|
|
||||||
<i class="pi pi-exclamation-triangle" style="font-size: 3rem"></i>
|
|
||||||
<h4>{{ message.summary }}</h4>
|
|
||||||
<p style="font-weight: 600">{{ message.detail }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="grid p-fluid">
|
|
||||||
<div class="col-6">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
pButton
|
|
||||||
(click)="onConfirm()"
|
|
||||||
label="Да"
|
|
||||||
class="p-button-success"
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
pButton
|
|
||||||
(click)="onReject()"
|
|
||||||
label="Нет"
|
|
||||||
class="p-button-secondary"
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</p-toast>
|
|
||||||
@ -1,139 +0,0 @@
|
|||||||
:host {
|
|
||||||
.product-modal {
|
|
||||||
position: relative;
|
|
||||||
padding-bottom: 39px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 32px;
|
|
||||||
|
|
||||||
&__information-container {
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
object-fit: contain;
|
|
||||||
max-height: 50vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__description {
|
|
||||||
margin-top: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// & > img {
|
|
||||||
// width: 50%;
|
|
||||||
// border-radius: 1.125rem;
|
|
||||||
// height: fit-content;
|
|
||||||
// object-fit: cover;
|
|
||||||
// }
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
display: flex;
|
|
||||||
position: absolute;
|
|
||||||
bottom: -14px;
|
|
||||||
padding-top: 16px;
|
|
||||||
border-top: solid #d1d1d1 1px;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer-price {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__add-to-cart {
|
|
||||||
padding: 8px 26px;
|
|
||||||
background: var(--orange-main);
|
|
||||||
border: none;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__modifier {
|
|
||||||
border: 1px solid rgba(128, 128, 128, 0.23);
|
|
||||||
margin: 0.5em 0;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
|
|
||||||
a {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
padding: 0.75em;
|
|
||||||
border-radius: 0.15em;
|
|
||||||
transition: background 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options-container {
|
|
||||||
transition: opacity 0.5s ease;
|
|
||||||
padding-left: 16px;
|
|
||||||
display: none;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&.isShow {
|
|
||||||
display: block;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.no-valid {
|
|
||||||
border-color: #cc0000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__modifiers-container {
|
|
||||||
height: 400px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__modifier-icon {
|
|
||||||
float: right;
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: transform 0.5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "\\";
|
|
||||||
transform: rotate(346deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "/";
|
|
||||||
transform: rotate(14deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.isShow {
|
|
||||||
&::before {
|
|
||||||
transform: rotate(76deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
transform: rotate(104deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1070px) {
|
|
||||||
.product-modal {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&__information-container {
|
|
||||||
max-width: 100% !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ProductModalComponent } from './product-modal.component';
|
|
||||||
|
|
||||||
describe('ProductModalComponent', () => {
|
|
||||||
let component: ProductModalComponent;
|
|
||||||
let fixture: ComponentFixture<ProductModalComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ ProductModalComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ProductModalComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { MessageService } from 'primeng/api';
|
|
||||||
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
|
||||||
import { AllData, CartModifier, Modifier, ModifiersGroup, Option, Product } from 'src/app/interface/data';
|
|
||||||
import { CartProduct } from 'src/app/models/cart-product';
|
|
||||||
import { CartService } from 'src/app/services/cart.service';
|
|
||||||
import { WpJsonService } from 'src/app/services/wp-json.service';
|
|
||||||
import { ChangeValue } from '../change-quantity/change-quantity.component';
|
|
||||||
import { CookiesService } from 'src/app/services/cookies.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-product-modal',
|
|
||||||
templateUrl: './product-modal.component.html',
|
|
||||||
styleUrls: ['./product-modal.component.scss']
|
|
||||||
})
|
|
||||||
export class ProductModalComponent implements OnInit {
|
|
||||||
public product!: Product;
|
|
||||||
public allData!: AllData;
|
|
||||||
public modifiersGroups!: ModifiersGroup[];
|
|
||||||
public modifiers!: Modifier[];
|
|
||||||
public cartProduct!: CartProduct;
|
|
||||||
public isValidate: boolean = false;
|
|
||||||
private selectedTerminal: any;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public dialogRef: DynamicDialogRef,
|
|
||||||
public config: DynamicDialogConfig,
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
private cartService: CartService,
|
|
||||||
private messageService: MessageService,
|
|
||||||
private cookiesService: CookiesService
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.product = this.config.data.product
|
|
||||||
this.modifiersGroups = this.config.data.modifiersGroups
|
|
||||||
this.modifiers = this.config.data.modifiers
|
|
||||||
this.selectedTerminal = this.config.data.selectedTerminal
|
|
||||||
this.cartProduct = new CartProduct(this.product.id, this.product.name, this.modifiersFilter(), this.modifiers, this.product.price);
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiersFilter(): ModifiersGroup[] {
|
|
||||||
return this.modifiersGroups.filter((value) => this.product.modifiers_group.includes(value.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsFilter(modifierGroup: ModifiersGroup): Modifier[] {
|
|
||||||
return this.modifiers.filter((modifier) => modifier.groupId === modifierGroup.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedOptions(modifier: ModifiersGroup): Modifier[] {
|
|
||||||
const cartModifier = this.cartProduct.modifiers.find(cartModifier => cartModifier.id === modifier.id)
|
|
||||||
if (modifier.restrictions.maxQuantity === 1 && modifier.restrictions.minQuantity === 1) {
|
|
||||||
cartModifier?.options.push(this.optionsFilter(modifier)[0])
|
|
||||||
}
|
|
||||||
return cartModifier?.options ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
addOption(modifier: ModifiersGroup, option: Modifier) {
|
|
||||||
const modif = this.cartProduct.modifiers.find((modif) => modif.id === modifier.id);
|
|
||||||
const optionSelectedCartIndex = modif?.options.findIndex((modif) => modif.id === option.id)
|
|
||||||
if (modifier.restrictions.maxQuantity === 1 && modifier.restrictions.minQuantity === 1) {
|
|
||||||
if (modif?.options) {
|
|
||||||
modif.options.length = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((optionSelectedCartIndex || optionSelectedCartIndex === 0) && optionSelectedCartIndex !== -1) {
|
|
||||||
modif?.options.splice(optionSelectedCartIndex, 1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
modif?.options.push(option)
|
|
||||||
}
|
|
||||||
|
|
||||||
getIsShow(element: HTMLDivElement) {
|
|
||||||
const isShow = Object.values(element.attributes).find((value) => value.name === 'isshow')?.value
|
|
||||||
return isShow === 'true'
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptionsView(event: Event, element: HTMLDivElement) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
const isShow = this.getIsShow(element)
|
|
||||||
if (isShow) {
|
|
||||||
element.setAttribute('isShow', 'false')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
element.setAttribute('isShow', 'true')
|
|
||||||
}
|
|
||||||
|
|
||||||
changeProductAmount({type, variableQuantity}: ChangeValue) {
|
|
||||||
if (type === 'plus') {
|
|
||||||
this.cartProduct.increment()
|
|
||||||
} else {
|
|
||||||
this.cartProduct.decrement()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
onReject() {
|
|
||||||
this.messageService.clear('cC');
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirm() {
|
|
||||||
this.cartService.clearCart()
|
|
||||||
this.cartService.changeTerminal(this.config.data.selectedTerminal)
|
|
||||||
this.cartService.addToCart(this.cartProduct);
|
|
||||||
this.messageService.clear('cC');
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
addToCart(event: Event) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
const cookiesTerminal = JSON.parse(this.cookiesService.getItem('selectedTerminal') || '')
|
|
||||||
|
|
||||||
for (let modifiersGroup of this.cartProduct.modifiers) {
|
|
||||||
const isValidModifier = modifiersGroup.allQuantity < modifiersGroup.restrictions.minQuantity
|
|
||||||
if (isValidModifier) {
|
|
||||||
this.messageService.add({
|
|
||||||
severity: 'error',
|
|
||||||
summary: 'Заполните все модификаторы!'
|
|
||||||
});
|
|
||||||
this.isValidate = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.selectedTerminal.id !== cookiesTerminal?.id) {
|
|
||||||
this.messageService.add({ key: 'cC', sticky: true, severity: 'warn', summary: 'В заказе могут быть товары только из одного магазина, очистить корзину для создания нового заказа?' });
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.cartService.changeTerminal(this.config.data.selectedTerminal)
|
|
||||||
this.cartService.addToCart(this.cartProduct);
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
<h2 mat-dialog-title>{{ moment(purchaseInfo.date).format("DD.MM.YYYY") }}</h2>
|
|
||||||
<mat-dialog-content>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
*ngFor="let good of purchaseInfo.goods_list"
|
|
||||||
class="woocommerce-orders-table__row woocommerce-orders-table__row--status-processing order"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-name"
|
|
||||||
data-title="Название"
|
|
||||||
>
|
|
||||||
{{ good.name }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-price"
|
|
||||||
data-title="Цена"
|
|
||||||
>
|
|
||||||
{{ good.price }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-quantity"
|
|
||||||
data-title="Количество"
|
|
||||||
>
|
|
||||||
{{ good.quantity }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</mat-dialog-content>
|
|
||||||
<mat-dialog-actions>
|
|
||||||
<span class="amount">Сумма: {{ purchaseInfo.sum }}</span>
|
|
||||||
<button mat-stroked-button mat-dialog-close>Закрыть</button>
|
|
||||||
</mat-dialog-actions>
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
:host {
|
|
||||||
.woocommerce-orders-table {
|
|
||||||
&__cell {
|
|
||||||
padding: 8px 4px;
|
|
||||||
border-bottom: 2px solid #dee2e6;
|
|
||||||
text-align: right !important;
|
|
||||||
display: block;
|
|
||||||
&::before {
|
|
||||||
content: attr(data-title) ": ";
|
|
||||||
font-weight: 700;
|
|
||||||
float: left;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__row {
|
|
||||||
display: block;
|
|
||||||
&:nth-child(even) {
|
|
||||||
background: #ebebeb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// &__cell-order-actions::before {
|
|
||||||
// display: none;
|
|
||||||
// }
|
|
||||||
&__cell-order-actions {
|
|
||||||
&.red-color {
|
|
||||||
color: #ed0000;
|
|
||||||
}
|
|
||||||
&.green-color {
|
|
||||||
color: #00a700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__cell-order-number a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #009688;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.amount {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-dialog-actions {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { PurchaseInfoComponent } from './purchase-info.component';
|
|
||||||
|
|
||||||
describe('PurchaseInfoComponent', () => {
|
|
||||||
let component: PurchaseInfoComponent;
|
|
||||||
let fixture: ComponentFixture<PurchaseInfoComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ PurchaseInfoComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(PurchaseInfoComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { Component, OnInit, Inject } from '@angular/core';
|
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|
||||||
import moment from 'moment';
|
|
||||||
import { PurchaseInfo } from 'src/app/interface/data';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-purchase-info',
|
|
||||||
templateUrl: './purchase-info.component.html',
|
|
||||||
styleUrls: ['./purchase-info.component.scss']
|
|
||||||
})
|
|
||||||
export class PurchaseInfoComponent implements OnInit {
|
|
||||||
public purchaseInfo!: PurchaseInfo;
|
|
||||||
readonly moment = moment;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public dialogRef: MatDialogRef<PurchaseInfoComponent>,
|
|
||||||
@Inject(MAT_DIALOG_DATA) public data: {purchaseInfo: PurchaseInfo},
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.purchaseInfo = this.data.purchaseInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
<div class="snack-bar">
|
|
||||||
<span>{{ data.text }}</span>
|
|
||||||
<div class="buttons">
|
|
||||||
<button mat-stroked-button matSnackBarAction (click)="buttonClick('no')">
|
|
||||||
Нет
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
mat-stroked-button
|
|
||||||
matSnackBarAction
|
|
||||||
color="error"
|
|
||||||
(click)="buttonClick('yes')"
|
|
||||||
>
|
|
||||||
Да
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
:host {
|
|
||||||
.snack-bar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
span {
|
|
||||||
color: #323232;
|
|
||||||
}
|
|
||||||
.buttons {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { SnackBarComponent } from './snack-bar.component';
|
|
||||||
|
|
||||||
describe('SnackBarComponent', () => {
|
|
||||||
let component: SnackBarComponent;
|
|
||||||
let fixture: ComponentFixture<SnackBarComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ SnackBarComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(SnackBarComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { Component, Inject, OnInit } from '@angular/core';
|
|
||||||
import { MatSnackBarRef, MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-snack-bar',
|
|
||||||
templateUrl: './snack-bar.component.html',
|
|
||||||
styleUrls: ['./snack-bar.component.scss']
|
|
||||||
})
|
|
||||||
export class SnackBarComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(@Inject(MAT_SNACK_BAR_DATA) public data: {text: string}, private _matSnackBarRef: MatSnackBarRef<SnackBarComponent>) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonClick(result: 'yes' | 'no') {
|
|
||||||
if (result === 'yes') {
|
|
||||||
this._matSnackBarRef.dismissWithAction()
|
|
||||||
} else {
|
|
||||||
this._matSnackBarRef.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
<mat-nav-list>
|
|
||||||
<div
|
|
||||||
mat-list-item
|
|
||||||
*ngFor="let item of data.list"
|
|
||||||
[ngClass]="{
|
|
||||||
'list-item': true,
|
|
||||||
active: item.id === data.active.id
|
|
||||||
}"
|
|
||||||
(click)="selectItem(item)"
|
|
||||||
>
|
|
||||||
<span matListItemTitle>{{ item.label }}</span>
|
|
||||||
</div>
|
|
||||||
</mat-nav-list>
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
@import 'src/sass/mixins';
|
|
||||||
|
|
||||||
:host {
|
|
||||||
.list-item {
|
|
||||||
padding: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
border-radius: 6px;
|
|
||||||
transition: all .4s ease;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
&.active {
|
|
||||||
background-color: var(--orange-main);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
@include hover-supported() {
|
|
||||||
background-color: #eee;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { TerminalListComponent } from './terminal-list.component';
|
|
||||||
|
|
||||||
describe('TerminalListComponent', () => {
|
|
||||||
let component: TerminalListComponent;
|
|
||||||
let fixture: ComponentFixture<TerminalListComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ TerminalListComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(TerminalListComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import { Component, Inject, OnInit } from '@angular/core';
|
|
||||||
import { MatBottomSheetRef, MAT_BOTTOM_SHEET_DATA } from '@angular/material/bottom-sheet';
|
|
||||||
|
|
||||||
export interface IListData {
|
|
||||||
list: Array<any>;
|
|
||||||
active: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-terminal-list',
|
|
||||||
templateUrl: './terminal-list.component.html',
|
|
||||||
styleUrls: ['./terminal-list.component.scss']
|
|
||||||
})
|
|
||||||
export class TerminalListComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(@Inject(MAT_BOTTOM_SHEET_DATA) public data: IListData, private _bottomSheetRef: MatBottomSheetRef<TerminalListComponent>) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
selectItem(item: any) {
|
|
||||||
this._bottomSheetRef.dismiss(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
<div
|
|
||||||
*ngIf="mainFormGroup && !loading; else loadingEl"
|
|
||||||
class="woocommerce-shipping-fields__field-wrapper"
|
|
||||||
>
|
|
||||||
<form
|
|
||||||
*ngIf="!showAuthoriztion; else authEl"
|
|
||||||
(ngSubmit)="submit()"
|
|
||||||
[formGroup]="mainFormGroup"
|
|
||||||
action="false"
|
|
||||||
autocomplete="on"
|
|
||||||
>
|
|
||||||
<h2 class="order_form__title">Оформление заказа</h2>
|
|
||||||
<p *ngIf="hasError" class="request-error-message">
|
|
||||||
Произошла ошибка. Попробуйте позже.
|
|
||||||
</p>
|
|
||||||
<div class="order_form" formGroupName="userDataForm">
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<input
|
|
||||||
formControlName="first_name"
|
|
||||||
id="first_name"
|
|
||||||
pInputText
|
|
||||||
placeholder="Ваше имя"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<div *ngIf="deliverData.deliveryType?.name === 'Доставка'">
|
|
||||||
<p сlass="form-row form-row-last">
|
|
||||||
<input
|
|
||||||
formControlName="flat"
|
|
||||||
id="flat"
|
|
||||||
pInputText
|
|
||||||
placeholder="Квартира"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<input
|
|
||||||
formControlName="street"
|
|
||||||
id="street"
|
|
||||||
pInputText
|
|
||||||
placeholder="Улица"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p сlass="form-row form-row-first">
|
|
||||||
<input
|
|
||||||
formControlName="house"
|
|
||||||
id="house"
|
|
||||||
pInputText
|
|
||||||
placeholder="Номер дома"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<label class="terminal-list-label">Пункты самовывоза</label>
|
|
||||||
<p-dropdown
|
|
||||||
*ngIf="deliverData.deliveryType?.name === 'Самовывоз'"
|
|
||||||
[options]="terminalList"
|
|
||||||
formControlName="selectedTerminal"
|
|
||||||
placeholder="Пункты выдачи"
|
|
||||||
optionLabel="label"
|
|
||||||
></p-dropdown>
|
|
||||||
</p>
|
|
||||||
<!-- <div *ngIf="deliverData.deliveryType?.name === 'Самовывоз'" class="terminal-list-container">
|
|
||||||
<div *ngFor="let terminal of terminalList" [ngClass]="{
|
|
||||||
'terminal-container': true,
|
|
||||||
'selected': terminal.label === selectedTerminal.label
|
|
||||||
}">
|
|
||||||
<img src="{{terminal.image}}" alt="{{terminal.address}}">
|
|
||||||
<span class="terminal-container__name">{{terminal.label}}</span>
|
|
||||||
<span class="terminal-container__address">{{terminal.address}}</span>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
<div formGroupName="deliveryDataForm">
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<label class="terminal-list-label">Способ получения</label>
|
|
||||||
<p-dropdown
|
|
||||||
[options]="deliveryTypes"
|
|
||||||
formControlName="deliveryType"
|
|
||||||
placeholder="Доставка"
|
|
||||||
optionLabel="name"
|
|
||||||
(onChange)="changeDeliveryType($event)"
|
|
||||||
></p-dropdown>
|
|
||||||
</p>
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<label id="deliveryDate">Время выдачи</label>
|
|
||||||
<p-calendar
|
|
||||||
formControlName="deliveryDate"
|
|
||||||
[showTime]="true"
|
|
||||||
[showSeconds]="false"
|
|
||||||
[touchUI]="true"
|
|
||||||
inputId="time"
|
|
||||||
placeholder="Время выдачи"
|
|
||||||
dateFormat="dd.mm.yy"
|
|
||||||
></p-calendar>
|
|
||||||
</p>
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<p-dropdown
|
|
||||||
[options]="paymentMethods"
|
|
||||||
formControlName="paymentMethod"
|
|
||||||
optionLabel="label"
|
|
||||||
placeholder="Тип оплаты"
|
|
||||||
>
|
|
||||||
</p-dropdown>
|
|
||||||
<!-- *Оплата бонусами -->
|
|
||||||
</p>
|
|
||||||
<!-- <p сlass="form-row form-row-last">
|
|
||||||
<input [maxLength]="255" id="promo-code" pInputText placeholder="Промокод" type="text">
|
|
||||||
</p> -->
|
|
||||||
<p сlass="form-row form-row-wide">
|
|
||||||
<textarea
|
|
||||||
[maxLength]="255"
|
|
||||||
cols="30"
|
|
||||||
formControlName="comment"
|
|
||||||
pInputTextarea
|
|
||||||
placeholder="Комментарий"
|
|
||||||
rows="1"
|
|
||||||
></textarea>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="bootom-info">
|
|
||||||
<div class="subtotal">
|
|
||||||
<span class="products-count">Товаров: {{ order.products.length }}</span>
|
|
||||||
<span class="woocommerce-Price-amount amount"
|
|
||||||
><bdi
|
|
||||||
><span class="woocommerce-Price-currencySymbol">{{
|
|
||||||
order.products[0].currency_symbol
|
|
||||||
}}</span
|
|
||||||
>{{ order.price }}</bdi
|
|
||||||
></span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="elementor-button elementor-button--checkout elementor-size-md"
|
|
||||||
>
|
|
||||||
<span class="elementor-button-text">Оформить заказ</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p *ngIf="showMyMessage" style="color: red; font-size: 20px">
|
|
||||||
Такой адрес не найден! Введите правильный адрес
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #loadingEl>
|
|
||||||
<div
|
|
||||||
class="angular-spinner-container"
|
|
||||||
style="width: fit-content; height: 100%; margin: 16px auto"
|
|
||||||
>
|
|
||||||
<p-progressSpinner styleClass="angular-spinner"></p-progressSpinner>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #authEl>
|
|
||||||
<app-auth (phoneConfirmed)="phoneConfirmed()"></app-auth>
|
|
||||||
</ng-template>
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
:host {
|
|
||||||
.woocommerce-shipping-fields__field-wrapper {
|
|
||||||
margin: 8px auto 100px auto;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.order_form__title {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 18px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 100%;
|
|
||||||
color: #000000;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica,
|
|
||||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", Segoe UI Symbol;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #495057;
|
|
||||||
background: #ffffff;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
border: 1px solid #ced4da;
|
|
||||||
transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
&.ng-dirty.ng-invalid {
|
|
||||||
border-color: red;
|
|
||||||
}
|
|
||||||
&.ng-invalid.ng-touched {
|
|
||||||
border-color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
width: 100%;
|
|
||||||
height: 52px;
|
|
||||||
color: #000000;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica,
|
|
||||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", Segoe UI Symbol;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #495057;
|
|
||||||
background: #ffffff;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
border: 1px solid #ced4da;
|
|
||||||
transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-list-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
|
||||||
margin: 8px 0 16px;
|
|
||||||
|
|
||||||
.terminal-container {
|
|
||||||
width: calc(50% - 8px);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
border: solid var(--orange-main) 1px;
|
|
||||||
border-radius: 16px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
opacity: 0.5;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
height: 120px;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
}
|
|
||||||
|
|
||||||
&__address {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-list-label {
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row-wide {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
#deliveryDate {
|
|
||||||
margin-left: 8px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bootom-info {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
bottom: 0;
|
|
||||||
padding: 18px;
|
|
||||||
background: #fff;
|
|
||||||
z-index: 3;
|
|
||||||
border-top: solid 1px #e7e7e7;
|
|
||||||
|
|
||||||
.subtotal {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.products-count {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.elementor-button--checkout {
|
|
||||||
background-color: var(--orange-main);
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 6px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: none;
|
|
||||||
padding: 12px;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 650px) {
|
|
||||||
.bootom-info {
|
|
||||||
width: 450px;
|
|
||||||
right: 0;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { UserDataOrderComponent } from './user-data-order.component';
|
|
||||||
|
|
||||||
describe('UserDataOrderComponent', () => {
|
|
||||||
let component: UserDataOrderComponent;
|
|
||||||
let fixture: ComponentFixture<UserDataOrderComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ UserDataOrderComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(UserDataOrderComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,269 +0,0 @@
|
|||||||
import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
|
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
|
||||||
import { DeliveryData, DeliveryType, PaymentMethod, UserData } from 'src/app/interface/data';
|
|
||||||
import { paymentMethods } from "../../app.constants";
|
|
||||||
import { OrderService } from "../../services/order.service";
|
|
||||||
import { AutocompleteService } from "../../services/autocomplete.service";
|
|
||||||
import { StreetValidator } from "../../validators/street.validator";
|
|
||||||
import { CartService } from 'src/app/services/cart.service';
|
|
||||||
import { environment } from "../../../environments/environment";
|
|
||||||
import { MessageService } from "primeng/api";
|
|
||||||
import { WpJsonService } from "../../services/wp-json.service";
|
|
||||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
|
||||||
import { CookiesService } from 'src/app/services/cookies.service';
|
|
||||||
import moment from 'moment';
|
|
||||||
import { Order } from 'src/app/models/order';
|
|
||||||
import { Store } from '@ngrx/store';
|
|
||||||
import * as fromConfig from '../../state/config/config.reducer'
|
|
||||||
import { lastValueFrom } from 'rxjs';
|
|
||||||
import { GetTerminalsService } from 'src/app/services/get-terminals.service';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-user-data-order',
|
|
||||||
templateUrl: './user-data-order.component.html',
|
|
||||||
styleUrls: ['./user-data-order.component.scss']
|
|
||||||
})
|
|
||||||
export class UserDataOrderComponent implements OnInit, OnDestroy {
|
|
||||||
|
|
||||||
@Output() orderSubmitted = new EventEmitter<number>();
|
|
||||||
@Output() userNotFound = new EventEmitter<null>();
|
|
||||||
readonly cities = environment.cities;
|
|
||||||
public paymentMethods!: PaymentMethod[];
|
|
||||||
public loading = false;
|
|
||||||
public hasError = false;
|
|
||||||
public mainFormGroup!: FormGroup;
|
|
||||||
public deliveryTypes: DeliveryType[] = [];
|
|
||||||
public new_street!: string | null;
|
|
||||||
public street!: string;
|
|
||||||
public new_house!: string | null;
|
|
||||||
public checkAddress: boolean = true;
|
|
||||||
public showMyMessage: boolean = false;
|
|
||||||
public order!: Order;
|
|
||||||
public showAuthoriztion = false;
|
|
||||||
private intervalTimeDelivery!: any
|
|
||||||
|
|
||||||
public userData: UserData = {
|
|
||||||
name: '',
|
|
||||||
first_name: null,
|
|
||||||
last_name: null,
|
|
||||||
street: null,
|
|
||||||
house: null,
|
|
||||||
flat: null,
|
|
||||||
city: this.cities[0],
|
|
||||||
phone: null,
|
|
||||||
selectedTerminal: null
|
|
||||||
};
|
|
||||||
public deliverData: DeliveryData = {
|
|
||||||
deliveryDate: null,
|
|
||||||
deliveryType: null,
|
|
||||||
paymentMethod: null,
|
|
||||||
comment: '',
|
|
||||||
persons: 1,
|
|
||||||
orderid: 0
|
|
||||||
};
|
|
||||||
public terminalList!: any;
|
|
||||||
public selectedTerminal!: any;
|
|
||||||
|
|
||||||
checkoutConfig$ = this.store.select(fromConfig.selectCheckout);
|
|
||||||
checkoutConfig!: any;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private fb: FormBuilder,
|
|
||||||
private orderService: OrderService,
|
|
||||||
private autoCompleteService: AutocompleteService,
|
|
||||||
private streetValidator: StreetValidator,
|
|
||||||
private cartService: CartService,
|
|
||||||
private messageService: MessageService,
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
private http: HttpClient,
|
|
||||||
private cookiesService: CookiesService,
|
|
||||||
private store: Store,
|
|
||||||
private _getTerminals: GetTerminalsService
|
|
||||||
) { }
|
|
||||||
|
|
||||||
async ngOnInit() {
|
|
||||||
this.checkAuthorization(true)
|
|
||||||
this._createMainForm();
|
|
||||||
this.getTerminalList();
|
|
||||||
this.checkoutConfig$.subscribe({
|
|
||||||
next: (value: any) => {
|
|
||||||
this.checkoutConfig = value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.deliverData.deliveryDate = moment().add(this.checkoutConfig?.timeDelivery?.changeTime?.defaultValue || 0, 'minutes').toDate()
|
|
||||||
this.intervalTimeDelivery = setInterval(() => {
|
|
||||||
this.mainFormGroup.controls['deliveryDataForm'].patchValue({
|
|
||||||
deliveryDate: moment().add(this.checkoutConfig?.timeDelivery?.changeTime?.defaultValue || 0, 'minutes').toDate()
|
|
||||||
})
|
|
||||||
}, 60_000)
|
|
||||||
this.paymentMethods = this.checkoutConfig.payments.values
|
|
||||||
this.deliverData.paymentMethod = this.paymentMethods[this.checkoutConfig.payments.default]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTerminalList() {
|
|
||||||
// this.http.get('./assets/terminal_list1.json').subscribe({
|
|
||||||
// next: (value) => {
|
|
||||||
// this.terminalList = value
|
|
||||||
// },
|
|
||||||
// error: (err) => {
|
|
||||||
// console.error(err);
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
const _getTerminals = await this._getTerminals.getTerminalList()
|
|
||||||
this.terminalList = _getTerminals.list
|
|
||||||
this.selectedTerminal = _getTerminals.active
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAuthorization(showAuthoriztion: boolean, forced = false) {
|
|
||||||
if (!this.getToken() || forced) {
|
|
||||||
this.showAuthoriztion = showAuthoriztion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getToken(): string | void {
|
|
||||||
return this.cookiesService.getItem('token');
|
|
||||||
}
|
|
||||||
|
|
||||||
phoneConfirmed() {
|
|
||||||
this._createMainForm();
|
|
||||||
this.showAuthoriztion = false
|
|
||||||
this.checkAuthorization(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
changeDeliveryType(event: any) {
|
|
||||||
this.deliverData.deliveryType = event.value;
|
|
||||||
if (this.deliverData.deliveryType?.name) {
|
|
||||||
this.changeValidators(this.deliverData.deliveryType.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changeValidators(name: string) {
|
|
||||||
const comment = this.mainFormGroup.controls['deliveryDataForm'].value.comment;
|
|
||||||
const streetValidators = name === 'Доставка' ? [Validators.required, Validators.minLength(2), Validators.maxLength(255),] : []
|
|
||||||
const houseValidators = name === 'Доставка' ? [Validators.required, Validators.maxLength(10),] : []
|
|
||||||
const userDataForm = this.fb.group({
|
|
||||||
phone: [this.userData.phone],
|
|
||||||
first_name: [this.userData.first_name, [Validators.required, Validators.minLength(2), Validators.maxLength(255)]],
|
|
||||||
// last_name: [this.userData.last_name, [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
|
||||||
street: [this.userData.street, streetValidators],
|
|
||||||
house: [this.userData.house, houseValidators],
|
|
||||||
flat: [this.userData.flat, []],
|
|
||||||
// city: [this.userData.city, [Validators.required]],
|
|
||||||
});
|
|
||||||
const deliveryDataForm = this.fb.group({
|
|
||||||
deliveryDate: [this.deliverData.deliveryDate, []],
|
|
||||||
deliveryType: [this.deliverData.deliveryType, [Validators.required]],
|
|
||||||
paymentMethod: [this.deliverData.paymentMethod, [Validators.required]],
|
|
||||||
// persons: [this.deliverData.persons, [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
|
||||||
comment: [comment, [Validators.maxLength(255),]],
|
|
||||||
});
|
|
||||||
|
|
||||||
this.mainFormGroup = this.fb.group({
|
|
||||||
userDataForm,
|
|
||||||
deliveryDataForm,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(): void {
|
|
||||||
const mainControls = this.mainFormGroup.controls;
|
|
||||||
if (this.mainFormGroup.invalid) {
|
|
||||||
Object.keys(mainControls).forEach(groupName => {
|
|
||||||
const childGroupControls = (mainControls[groupName] as FormGroup).controls;
|
|
||||||
Object.keys(childGroupControls).forEach(controlName => {
|
|
||||||
childGroupControls[controlName].markAsTouched();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.messageService.add({
|
|
||||||
severity: 'error',
|
|
||||||
summary: 'Заполните обязательные поля',
|
|
||||||
})
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.submitOrder();
|
|
||||||
}
|
|
||||||
|
|
||||||
async submitOrder() {
|
|
||||||
this.loading = true;
|
|
||||||
const userData: UserData = this.mainFormGroup.controls['userDataForm'].getRawValue();
|
|
||||||
userData.phone = this.userData.phone;
|
|
||||||
const deliveryData = this.mainFormGroup.controls['deliveryDataForm'].getRawValue()
|
|
||||||
deliveryData.orderid = Math.floor(Math.random() * (10 ** 12))
|
|
||||||
this.orderService.setUserData(userData);
|
|
||||||
this.orderService.setDeliveryData(deliveryData);
|
|
||||||
|
|
||||||
this.orderService.submit().subscribe({
|
|
||||||
next: (_) => {
|
|
||||||
this.loading = false;
|
|
||||||
this.cartService.clearCart();
|
|
||||||
this.orderSubmitted.next(deliveryData.orderid);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading = false;
|
|
||||||
this.hasError = true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _createMainForm(): Promise<void> {
|
|
||||||
try {
|
|
||||||
this.loading = true;
|
|
||||||
const userDataForm = await this._createUserDataForm();
|
|
||||||
const deliveryDataForm = await this._createDeliveryDataForm();
|
|
||||||
this.mainFormGroup = this.fb.group({
|
|
||||||
userDataForm,
|
|
||||||
deliveryDataForm,
|
|
||||||
});
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error('Error: ', e);
|
|
||||||
|
|
||||||
this.messageService.add({
|
|
||||||
severity: 'error',
|
|
||||||
summary: 'Произошла ошибка',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _createUserDataForm(): Promise<FormGroup> {
|
|
||||||
this.order = await this.orderService.getOrder(true);
|
|
||||||
if (this.order.userData?.errorCode === "Customer_CustomerNotFound") {
|
|
||||||
this.userNotFound.emit(null)
|
|
||||||
}
|
|
||||||
this.userData = Object.assign({}, this.userData, this.order.userData);
|
|
||||||
this.userData.city = this.cities[0];
|
|
||||||
this.userData.phone = this.order.phone;
|
|
||||||
// await this.autoCompleteService.setCity(this.userData.city);
|
|
||||||
const isSelfDelivery = this.deliverData.deliveryType?.name === "Самовывоз"
|
|
||||||
return this.fb.group({
|
|
||||||
selectedTerminal: [{ value: this.selectedTerminal, disabled: true }, []],
|
|
||||||
phone: [this.userData.phone],
|
|
||||||
first_name: [{value: this.userData.name, disabled: true}, [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
|
||||||
// last_name: [this.userData.last_name, [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
|
||||||
street: [{ value: this.userData.street, disabled: isSelfDelivery }, isSelfDelivery ?? [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
|
||||||
house: [{ value: this.userData.house, disabled: isSelfDelivery }, isSelfDelivery ?? [Validators.required, Validators.maxLength(10), Validators.pattern('^\\d+[-|\\d]+\\d+$|^\\d*$')]],
|
|
||||||
flat: [this.userData.flat, []],
|
|
||||||
// city: [this.userData.city, [Validators.required]],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _createDeliveryDataForm(): Promise<FormGroup> {
|
|
||||||
this.deliveryTypes = this.checkoutConfig.delivery.filter((value: any) => value.isPickUp);
|
|
||||||
this.deliverData.deliveryType = this.deliveryTypes[0];
|
|
||||||
return this.fb.group({
|
|
||||||
deliveryDate: [{ value: this.deliverData.deliveryDate, disabled: this.checkoutConfig.timeDelivery.changeTime.disabled }, []],
|
|
||||||
deliveryType: [{ value: this.deliverData.deliveryType, disabled: this.checkoutConfig.delivery.disabled || this.deliveryTypes.length < 2 }, [Validators.required]],
|
|
||||||
paymentMethod: [{ value: this.deliverData.paymentMethod, disabled: this.checkoutConfig.payments.disabled }, [Validators.required]],
|
|
||||||
persons: [this.deliverData.persons, [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
|
||||||
comment: [this.deliverData.comment, [Validators.maxLength(255),]]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
clearInterval(this.intervalTimeDelivery)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import { ChangeQuantityOptionDirective } from './change-quantity-option.directive';
|
|
||||||
|
|
||||||
describe('ChangeQuantityOptionDirective', () => {
|
|
||||||
it('should create an instance', () => {
|
|
||||||
const directive = new ChangeQuantityOptionDirective();
|
|
||||||
expect(directive).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
import {
|
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
HostListener,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { CartModifier, Modifier } from '../interface/data';
|
|
||||||
import { CartProduct } from '../models/cart-product';
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[appChangeQuantityOption]',
|
|
||||||
})
|
|
||||||
export class ChangeQuantityOptionDirective implements OnInit {
|
|
||||||
@Input() option!: Modifier;
|
|
||||||
@Input() modifier!: CartModifier;
|
|
||||||
@Input() product!: CartProduct;
|
|
||||||
|
|
||||||
constructor(private el: ElementRef) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.option.quantity = this.option.restrictions.byDefault;
|
|
||||||
|
|
||||||
if (!this.modifier.lastChangeOption && this.option.restrictions.byDefault) {
|
|
||||||
this.modifier.lastChangeOption = this.option.idLocal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('click') onOptionClick() {
|
|
||||||
this.changeQuantity({ option: this.option, modifier: this.modifier });
|
|
||||||
}
|
|
||||||
|
|
||||||
changeQuantity({
|
|
||||||
option,
|
|
||||||
modifier,
|
|
||||||
}: {
|
|
||||||
option: Modifier;
|
|
||||||
modifier: CartModifier;
|
|
||||||
}): void {
|
|
||||||
if (!option.quantity && option.quantity !== 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const quantity = option.quantity;
|
|
||||||
const allQuantity = modifier.allQuantity;
|
|
||||||
const maxOptionQ = option.restrictions.maxQuantity;
|
|
||||||
const minOptionQ = option.restrictions.minQuantity;
|
|
||||||
const maxModifierQ = modifier.restrictions.maxQuantity;
|
|
||||||
const minModifierQ = modifier.restrictions.minQuantity;
|
|
||||||
const plusCondition =
|
|
||||||
(quantity < maxOptionQ && allQuantity < maxModifierQ) ||
|
|
||||||
(maxOptionQ === 0 && (allQuantity < maxModifierQ || maxModifierQ === 0));
|
|
||||||
|
|
||||||
if (!plusCondition && quantity > minOptionQ && allQuantity > minModifierQ) {
|
|
||||||
this.product.decrementOption(modifier.idLocal, option.idLocal);
|
|
||||||
}
|
|
||||||
if (allQuantity === maxModifierQ && modifier.lastChangeOption) {
|
|
||||||
this.product.decrementOption(modifier.idLocal, modifier.lastChangeOption);
|
|
||||||
this.changeQuantity({ option, modifier });
|
|
||||||
}
|
|
||||||
if (plusCondition) {
|
|
||||||
this.product.incrementOption(modifier.idLocal, option.idLocal);
|
|
||||||
modifier.lastChangeOption = option.idLocal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,353 +0,0 @@
|
|||||||
import { CartProduct } from '../models/cart-product';
|
|
||||||
|
|
||||||
export enum PageCode {
|
|
||||||
// Auth,
|
|
||||||
BonusProgram,
|
|
||||||
Orders,
|
|
||||||
RefSystem,
|
|
||||||
UserData,
|
|
||||||
Transactions,
|
|
||||||
Logout
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum MainPageCode {
|
|
||||||
Account,
|
|
||||||
Products,
|
|
||||||
Cart,
|
|
||||||
Info,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Page {
|
|
||||||
code: PageCode | MainPageCode;
|
|
||||||
component?: any;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
getMethod?: string;
|
|
||||||
resName?: string;
|
|
||||||
onSideBar: boolean;
|
|
||||||
icon?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserDataForm {
|
|
||||||
first_name: string;
|
|
||||||
birthdate: string;
|
|
||||||
gender: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BonusProgramAccount {
|
|
||||||
// BonusProgramName: string;
|
|
||||||
// BonusProgramTypeID: string;
|
|
||||||
CardNumber: string;
|
|
||||||
Bonuses: number;
|
|
||||||
// HoldedBonuses: number;
|
|
||||||
// BonusProgramAccounts: BonusProgramAccount[];
|
|
||||||
// DateBonusBurn: string;
|
|
||||||
// _links: any[];
|
|
||||||
// _embedded: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Purchase {
|
|
||||||
// PurchaseId?: string;
|
|
||||||
// CustomerId?: string;
|
|
||||||
// PurchaseDate: string;
|
|
||||||
// PurchaseState?: number;
|
|
||||||
// CardNumber?: number;
|
|
||||||
// Address?: string
|
|
||||||
// CheckSummary?: number
|
|
||||||
// BonusSummary?: number
|
|
||||||
// ID: string;
|
|
||||||
// Transactions: Transaction[];
|
|
||||||
// IsSingleTransaction?: boolean;
|
|
||||||
orderNumber: number;
|
|
||||||
transactionCreateDate: string;
|
|
||||||
orderSum: number;
|
|
||||||
transactionSum: number;
|
|
||||||
transactionType: 'CancelPayFromWallet' | 'PayFromWallet' | 'RefillWallet';
|
|
||||||
more_info: PurchaseInfo | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PurchaseInfo {
|
|
||||||
date: string;
|
|
||||||
goods_list: [
|
|
||||||
{
|
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
quantity: number;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
number: string;
|
|
||||||
sum: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Transaction {
|
|
||||||
User: string;
|
|
||||||
Purchase: string;
|
|
||||||
Date: string;
|
|
||||||
Value: number;
|
|
||||||
TransactionType: number;
|
|
||||||
UserBonusesSnapshot: number;
|
|
||||||
BonusPercent: number;
|
|
||||||
DateActiveBonus: string;
|
|
||||||
AccountBonus: string;
|
|
||||||
Bonus: string;
|
|
||||||
ID: string;
|
|
||||||
HasPurchase?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderStatus {
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeliveryType {
|
|
||||||
// cost: number;
|
|
||||||
// title: string;
|
|
||||||
// id: number;
|
|
||||||
// type: string;
|
|
||||||
name: string;
|
|
||||||
iikoId: string;
|
|
||||||
iikoName: string;
|
|
||||||
isPickUp: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AcceptedOrder {
|
|
||||||
id: number;
|
|
||||||
status: string;
|
|
||||||
currency_symbol: string;
|
|
||||||
total: number;
|
|
||||||
address: {
|
|
||||||
city: string;
|
|
||||||
street: string;
|
|
||||||
house: number;
|
|
||||||
flat: number;
|
|
||||||
};
|
|
||||||
payment_method: string;
|
|
||||||
shipping: {
|
|
||||||
name: string;
|
|
||||||
total: number;
|
|
||||||
};
|
|
||||||
date_created: string;
|
|
||||||
items: OrderProduct[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Product {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
image: string;
|
|
||||||
image_gallery: string[];
|
|
||||||
category_id: number;
|
|
||||||
description: string;
|
|
||||||
stock_status: string;
|
|
||||||
currency_symbol: string;
|
|
||||||
modifier_data: CartModifier[];
|
|
||||||
short_description: string;
|
|
||||||
guid: string;
|
|
||||||
groupId: string;
|
|
||||||
modifiers_group: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AllData {
|
|
||||||
datetime: string;
|
|
||||||
groups: Group[];
|
|
||||||
products: Product[];
|
|
||||||
modifiers_groups: ModifiersGroup[];
|
|
||||||
modifiers: Modifier[];
|
|
||||||
categories: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Group {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ModifiersGroup {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
restrictions: {
|
|
||||||
minQuantity: number;
|
|
||||||
maxQuantity: number;
|
|
||||||
freeQuantity: number;
|
|
||||||
byDefault: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Modifier {
|
|
||||||
id: string;
|
|
||||||
idLocal: string;
|
|
||||||
name: string;
|
|
||||||
groupId: string;
|
|
||||||
price?: number;
|
|
||||||
quantity?: number;
|
|
||||||
image?: string;
|
|
||||||
restrictions: {
|
|
||||||
minQuantity: number;
|
|
||||||
maxQuantity: number;
|
|
||||||
freeQuantity: number;
|
|
||||||
byDefault: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CartModifier {
|
|
||||||
lastChangeOption?: string;
|
|
||||||
id: string;
|
|
||||||
idLocal: string;
|
|
||||||
name: string;
|
|
||||||
options: Modifier[];
|
|
||||||
allQuantity: number;
|
|
||||||
restrictions: {
|
|
||||||
minQuantity: number;
|
|
||||||
maxQuantity: number;
|
|
||||||
freeQuantity: number;
|
|
||||||
byDefault: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Cart {
|
|
||||||
products: CartProduct[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// export interface Modifier {
|
|
||||||
// id: number;
|
|
||||||
// name: string;
|
|
||||||
// category_type: string;
|
|
||||||
// minimum_options: number;
|
|
||||||
// maximum_options: number;
|
|
||||||
// global_categories: string;
|
|
||||||
// required: number;
|
|
||||||
// options: Option[];
|
|
||||||
// allOptions?: Option[];
|
|
||||||
// }
|
|
||||||
|
|
||||||
export interface Option {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
groupId: string;
|
|
||||||
restrictions: {
|
|
||||||
minQuantity: number;
|
|
||||||
maxQuantity: number;
|
|
||||||
freeQuantity: number;
|
|
||||||
byDefault: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderProduct {
|
|
||||||
id: number;
|
|
||||||
amount: number;
|
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
modifiers: {
|
|
||||||
[name: string]: OrderModifier[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderModifier {
|
|
||||||
name: string;
|
|
||||||
id: number;
|
|
||||||
price: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeliveryData {
|
|
||||||
paymentMethod: PaymentMethod | null;
|
|
||||||
deliveryDate: Date | null;
|
|
||||||
deliveryType: DeliveryType | null;
|
|
||||||
persons: number;
|
|
||||||
comment: string;
|
|
||||||
orderid: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentMethod {
|
|
||||||
type: string;
|
|
||||||
label: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserData {
|
|
||||||
first_name: string | null;
|
|
||||||
last_name: string | null;
|
|
||||||
street: string | null;
|
|
||||||
house: string | null;
|
|
||||||
flat: string | null;
|
|
||||||
city: string;
|
|
||||||
phone: string | null;
|
|
||||||
selectedTerminal: ITerminal | null;
|
|
||||||
name: string;
|
|
||||||
errorCode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITerminal {
|
|
||||||
label: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IOptionDateFilter {
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDateFilter {
|
|
||||||
filterType: string;
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
import { CartModifier, Modifier, ModifiersGroup } from "../interface/data";
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
|
|
||||||
export class CartProduct {
|
|
||||||
|
|
||||||
|
|
||||||
constructor(id: string, name: string, modifiers: ModifiersGroup[] = [], options: Modifier[], price: number, amount: number = 1) {
|
|
||||||
this.id = id;
|
|
||||||
this.guid = uuidv4();
|
|
||||||
this.amount = amount;
|
|
||||||
this.name = name;
|
|
||||||
this.price = price * amount
|
|
||||||
this.modifiers = modifiers.map(modifier => ({
|
|
||||||
name: modifier.name,
|
|
||||||
id: modifier.id,
|
|
||||||
idLocal: uuidv4(),
|
|
||||||
options: JSON.parse(JSON.stringify(options)).filter((option: any) => option.groupId === modifier.id),
|
|
||||||
restrictions: modifier.restrictions,
|
|
||||||
get allQuantity() {
|
|
||||||
return this.options.reduce((a: any, b: any) => a + (b['quantity'] || 0), 0)
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
this.modifiers.forEach((modifier) => {
|
|
||||||
modifier.options.forEach((option) => {
|
|
||||||
option.idLocal = uuidv4()
|
|
||||||
if (!option.quantity && option.quantity !== 0) {
|
|
||||||
option.quantity = option.restrictions.byDefault
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
id: string;
|
|
||||||
guid: string;
|
|
||||||
amount: number;
|
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
modifiers: CartModifier[];
|
|
||||||
|
|
||||||
increment(): void {
|
|
||||||
this.amount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
decrement(): void {
|
|
||||||
if (this.amount > 0) {
|
|
||||||
this.amount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
incrementOption(modifierId: string, optionId: string): void {
|
|
||||||
const modifier = this.modifiers.find((modifier) => modifier.idLocal === modifierId)
|
|
||||||
const option = modifier?.options.find((option) => option.idLocal === optionId)
|
|
||||||
if (!option?.quantity && option?.quantity !== 0) return
|
|
||||||
option.quantity++
|
|
||||||
}
|
|
||||||
|
|
||||||
decrementOption(modifierId: string, optionId: string): void {
|
|
||||||
const modifier = this.modifiers.find((modifier) => modifier.idLocal === modifierId)
|
|
||||||
const option = modifier?.options.find((option) => option.idLocal === optionId)
|
|
||||||
if (!option?.quantity && option?.quantity !== 0) return
|
|
||||||
option.quantity--
|
|
||||||
}
|
|
||||||
|
|
||||||
get finalPrice(): number{
|
|
||||||
const modifiersPrice = this.modifiers.reduce<number>((previousValue, currentValue) => {
|
|
||||||
return previousValue + currentValue.options.reduce<number>((previousOptionValue, currentOptionValue) => {
|
|
||||||
return previousOptionValue + Number(currentOptionValue.price ? currentOptionValue.price * (currentOptionValue.quantity ?? 0) : 0);
|
|
||||||
}, 0);
|
|
||||||
}, 0);
|
|
||||||
return (Number(this.price) + modifiersPrice) * this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// addOption(modifier: ModifiersGroup, option: Modifier): void {
|
|
||||||
// const productModifier = this.modifiers.find(value => value.id === modifier.id);
|
|
||||||
// if (productModifier) {
|
|
||||||
// const optionIndex = productModifier.options.findIndex(value => value.id === option.id);
|
|
||||||
// if (optionIndex === -1) {
|
|
||||||
// productModifier.options.push(option);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// productModifier.options.splice(optionIndex, 1)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
import { CartModifier, Modifier, Product } from '../interface/data';
|
|
||||||
|
|
||||||
export interface OrderProductToJson {
|
|
||||||
id: string;
|
|
||||||
amount: number;
|
|
||||||
price: number;
|
|
||||||
quantity: number;
|
|
||||||
name: string;
|
|
||||||
options?: OrderProductOption[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderProductOption {
|
|
||||||
option: string;
|
|
||||||
variants: {
|
|
||||||
variant: string;
|
|
||||||
id: string;
|
|
||||||
quantity: number | undefined;
|
|
||||||
}[];
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class OrderProduct implements Product {
|
|
||||||
constructor(product: Product, guid: string, amount: number = 1) {
|
|
||||||
this.category_id = product.category_id;
|
|
||||||
this.currency_symbol = product.currency_symbol;
|
|
||||||
this.description = product.description;
|
|
||||||
this.id = product.id;
|
|
||||||
this.image_gallery = product.image_gallery;
|
|
||||||
this.image = product.image;
|
|
||||||
this.modifier_data = product.modifier_data;
|
|
||||||
this.name = product.name;
|
|
||||||
this.price = product.price;
|
|
||||||
this.stock_status = product.stock_status;
|
|
||||||
this.amount = amount;
|
|
||||||
this.guid = guid;
|
|
||||||
this.short_description = product.short_description;
|
|
||||||
this.groupId = product.groupId;
|
|
||||||
this.modifiers_group = product.modifiers_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public amount: number;
|
|
||||||
public category_id: number;
|
|
||||||
public currency_symbol: string;
|
|
||||||
public description: string;
|
|
||||||
public short_description: string;
|
|
||||||
public id: string;
|
|
||||||
public image_gallery: string[];
|
|
||||||
public image: string;
|
|
||||||
public modifier_data: CartModifier[];
|
|
||||||
public name: string;
|
|
||||||
public price: number;
|
|
||||||
public stock_status: string;
|
|
||||||
public guid: string;
|
|
||||||
public groupId: string;
|
|
||||||
public modifiers_group: string[];
|
|
||||||
|
|
||||||
get finalPrice(): number {
|
|
||||||
const modifiersPrice = this.modifier_data.reduce<number>(
|
|
||||||
(previousValue, currentValue) => {
|
|
||||||
return (
|
|
||||||
previousValue +
|
|
||||||
currentValue.options.reduce<number>(
|
|
||||||
(previousOptionValue, currentOptionValue) => {
|
|
||||||
return (
|
|
||||||
previousOptionValue +
|
|
||||||
Number(
|
|
||||||
currentOptionValue.price
|
|
||||||
? currentOptionValue.price *
|
|
||||||
(currentOptionValue.quantity ?? 0)
|
|
||||||
: 0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
0
|
|
||||||
);
|
|
||||||
return (Number(this.price) + modifiersPrice) * this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
toJson(): OrderProductToJson {
|
|
||||||
const product: OrderProductToJson = {
|
|
||||||
id: this.id,
|
|
||||||
amount: this.amount * this.price,
|
|
||||||
price: this.price,
|
|
||||||
quantity: this.amount,
|
|
||||||
name: this.name,
|
|
||||||
};
|
|
||||||
const options = this.modifier_data
|
|
||||||
?.map((modifier) => {
|
|
||||||
return {
|
|
||||||
option: modifier.name,
|
|
||||||
variants:
|
|
||||||
modifier.options
|
|
||||||
.map((option) => ({
|
|
||||||
variant: option.name,
|
|
||||||
id: option.id,
|
|
||||||
quantity: option.quantity,
|
|
||||||
}))
|
|
||||||
.filter((option) => option.quantity) || null,
|
|
||||||
id: modifier.id,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.filter((modifier) => modifier.variants.length);
|
|
||||||
|
|
||||||
if (options.length) product.options = options;
|
|
||||||
return product;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
<div
|
|
||||||
[ngClass]="{
|
|
||||||
woocommerce: true,
|
|
||||||
'auth-page': showAuthoriztion
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<!-- <button *ngIf="!showAuthoriztion" class="logout" color="warn" mat-stroked-button (click)="logout()">Выйти</button> -->
|
|
||||||
<div *ngIf="!showAuthoriztion; else authEl" class="account-page">
|
|
||||||
<div *ngIf="showAuthoriztion" class="top-left-attribute"></div>
|
|
||||||
<app-bonus-program
|
|
||||||
[currentPage]="currentPage"
|
|
||||||
(deauthorization)="changePage(pageList[0])"
|
|
||||||
></app-bonus-program>
|
|
||||||
|
|
||||||
<mat-tab-group mat-stretch-tabs="false" mat-align-tabs="center" (selectedTabChange)="changeTabPage($event)" [(selectedIndex)]="selectedTabPage">
|
|
||||||
<ng-container *ngFor="let page of pageList">
|
|
||||||
<mat-tab *ngIf="page.onSideBar" label="{{ page.name }}">
|
|
||||||
<div [ngSwitch]="page.resName" class="">
|
|
||||||
<ng-container *ngSwitchCase="'transactions'">
|
|
||||||
<app-orders
|
|
||||||
[currentPage]="currentPage"
|
|
||||||
(deauthorization)="changePage(pageList[0])"
|
|
||||||
></app-orders>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchCase="'orders'">
|
|
||||||
<app-purcahses
|
|
||||||
></app-purcahses>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchCase="'user-data'">
|
|
||||||
<app-user-data></app-user-data>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngSwitchCase="'ref-system'">
|
|
||||||
<app-ref-system></app-ref-system>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</mat-tab>
|
|
||||||
</ng-container>
|
|
||||||
</mat-tab-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p-toast
|
|
||||||
position="bottom-center"
|
|
||||||
key="c"
|
|
||||||
(onClose)="onReject()"
|
|
||||||
[baseZIndex]="5000"
|
|
||||||
>
|
|
||||||
<ng-template let-message pTemplate="message">
|
|
||||||
<div class="flex flex-column" style="flex: 1">
|
|
||||||
<div class="text-center">
|
|
||||||
<i class="pi pi-exclamation-triangle" style="font-size: 3rem"></i>
|
|
||||||
<h4>{{ message.summary }}</h4>
|
|
||||||
<p style="font-weight: 600">{{ message.detail }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="grid p-fluid">
|
|
||||||
<div class="col-6">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
pButton
|
|
||||||
(click)="onConfirm()"
|
|
||||||
label="Да"
|
|
||||||
class="p-button-success"
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
pButton
|
|
||||||
(click)="onReject()"
|
|
||||||
label="Нет"
|
|
||||||
class="p-button-secondary"
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</p-toast>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #authEl>
|
|
||||||
<app-auth (phoneConfirmed)="phoneConfirmed()"></app-auth>
|
|
||||||
</ng-template>
|
|
||||||
@ -1,218 +0,0 @@
|
|||||||
:host ::ng-deep .mat-tab-body {
|
|
||||||
padding: 16px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host {
|
|
||||||
.woocommerce {
|
|
||||||
min-height: calc(100vh - 39px);
|
|
||||||
padding: 20px 18px 65px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.logout {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.auth-page {
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-menu-container {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
margin: 0;
|
|
||||||
z-index: 777;
|
|
||||||
height: 57px;
|
|
||||||
border-top: solid 1px #dfdfdf;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
li {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #b5b5b9;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.mat-icon {
|
|
||||||
color: #b5b5b9;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.cart {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: attr(data-counter);
|
|
||||||
color: #fff;
|
|
||||||
position: absolute;
|
|
||||||
right: calc(50% - 24px);
|
|
||||||
top: 3px;
|
|
||||||
background: #d7120b;
|
|
||||||
border-radius: 50px;
|
|
||||||
min-width: 1.2rem;
|
|
||||||
line-height: 1.2rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-page {
|
|
||||||
max-width: 1208px;
|
|
||||||
display: flex;
|
|
||||||
margin: 0 auto;
|
|
||||||
gap: 32px;
|
|
||||||
width: 98%;
|
|
||||||
flex-direction: row;
|
|
||||||
nav {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
margin-top: 26px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
max-width: 400px;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 6px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
li {
|
|
||||||
padding: 12px;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 81px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
background: #ffffff;
|
|
||||||
box-shadow: 0px 0px 5px rgb(0 0 0 / 15%);
|
|
||||||
color: #000;
|
|
||||||
border-radius: 15px;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
border: solid var(--orange-main) 1px;
|
|
||||||
// display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.first {
|
|
||||||
// border-radius: 7px 0 0 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.menu-item-info {
|
|
||||||
margin-left: 16px;
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 22px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #000;
|
|
||||||
display: block;
|
|
||||||
text-align-last: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 15px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li:nth-child(odd) {
|
|
||||||
background-color: #ebebeb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-tab-group {
|
|
||||||
width: calc(100% - 432px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-left-attribute {
|
|
||||||
width: 10px;
|
|
||||||
height: 5px;
|
|
||||||
background: var(--orange-main);
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 69px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.version {
|
|
||||||
opacity: 0.5;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 60px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media screen and (min-width: 550px) {
|
|
||||||
.woocommerce {
|
|
||||||
padding-bottom: 78px;
|
|
||||||
|
|
||||||
.main-menu-container {
|
|
||||||
width: 500px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
border: solid 1px #dfdfdf;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 0 6px 2px rgb(223 223 223);
|
|
||||||
transition: top 0.4s cubic-bezier(0.57, -0.43, 0.41, 1.3);
|
|
||||||
top: -60px;
|
|
||||||
|
|
||||||
&[isShow="true"] {
|
|
||||||
top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.version {
|
|
||||||
bottom: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 895px) {
|
|
||||||
.woocommerce {
|
|
||||||
.account-page {
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.mat-tab-group {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,243 +0,0 @@
|
|||||||
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
|
||||||
import { CookiesService } from '../../services/cookies.service';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { MainPageCode, Page, PageCode } from '../../interface/data';
|
|
||||||
import { environment } from '../../../environments/environment';
|
|
||||||
import { PageList, PageListMain, PageListWithBonus } from '../../app.constants';
|
|
||||||
import { HttpErrorResponse, HttpParams } from '@angular/common/http';
|
|
||||||
import { ExitComponent } from '../../components/exit/exit.component';
|
|
||||||
import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
|
|
||||||
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';
|
|
||||||
import { MatTabChangeEvent } from '@angular/material/tabs';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-account',
|
|
||||||
templateUrl: './account.component.html',
|
|
||||||
styleUrls: ['./account.component.scss'],
|
|
||||||
providers: [DialogService],
|
|
||||||
})
|
|
||||||
export class AccountComponent implements OnInit {
|
|
||||||
@Output() setUserDataOrderPage = new EventEmitter<null>();
|
|
||||||
@ViewChild('menu', { static: true}) menu!: ElementRef;
|
|
||||||
public refSystemId: string = '';
|
|
||||||
public selectedTabPage: number = 1
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private cookiesService: CookiesService,
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private dialogService: DialogService,
|
|
||||||
private jsonRpcService: JsonrpcService,
|
|
||||||
private messageService: MessageService,
|
|
||||||
private cartService: CartService,
|
|
||||||
private store: Store
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public currentPage!: Page;
|
|
||||||
public handleHttpErrorFunc = this.handleHttpError.bind(this);
|
|
||||||
private ref!: DynamicDialogRef;
|
|
||||||
public version: string = environment.version;
|
|
||||||
|
|
||||||
readonly PageCode = PageCode;
|
|
||||||
readonly pageList = environment.hasBonusProgram
|
|
||||||
? PageListWithBonus
|
|
||||||
: PageList;
|
|
||||||
|
|
||||||
readonly MainPageCode = MainPageCode;
|
|
||||||
readonly mainPageList = PageListMain;
|
|
||||||
public currentPageMain: Page = this.mainPageList[environment.production ? 1 : 1];
|
|
||||||
public cartCount = 0;
|
|
||||||
public showAuthoriztion = false;
|
|
||||||
|
|
||||||
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',
|
|
||||||
'woocommerce-page',
|
|
||||||
'woocommerce-orders'
|
|
||||||
);
|
|
||||||
this.route.queryParams.subscribe((params) => {
|
|
||||||
if (!params['activeAccountPage']) {
|
|
||||||
this.currentPage = this.pageList[0];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const currentPage = this.pageList.find((page) => {
|
|
||||||
return page.code === Number(params['activeAccountPage']);
|
|
||||||
});
|
|
||||||
if (!currentPage) {
|
|
||||||
this.currentPage = this.pageList[0];
|
|
||||||
} else {
|
|
||||||
this.currentPage = currentPage;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.cartCount = this.cartService.cartCount;
|
|
||||||
this.cartService.cartCount$.subscribe({
|
|
||||||
next: (count) => {
|
|
||||||
this.cartCount = count;
|
|
||||||
document.querySelectorAll('.cart')[0].setAttribute("data-counter", this.cartCount.toString())
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
phoneConfirmed(): void {
|
|
||||||
this.refSystem();
|
|
||||||
this.showAuthoriztion = false
|
|
||||||
this.checkAuthorization(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
async refSystem() {
|
|
||||||
const additionalInfo = (await lastValueFrom(
|
|
||||||
this.jsonRpcService.rpc({
|
|
||||||
method: 'getAdditionalInfo',
|
|
||||||
params: []
|
|
||||||
}, RpcService.authService, true)
|
|
||||||
)).data
|
|
||||||
this.route.queryParams.subscribe((params) => {
|
|
||||||
if (params['refUserId']) {
|
|
||||||
if (additionalInfo.refSystem?.code.length) {
|
|
||||||
this.messageService.add({
|
|
||||||
severity: 'custom',
|
|
||||||
summary:
|
|
||||||
'Вы уже зарегестрированы в реферальной программе!',
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.refSystemId = params['refUserId'];
|
|
||||||
this.jsonRpcService
|
|
||||||
.rpc(
|
|
||||||
{
|
|
||||||
method: 'updateAdditionalInfo',
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
refSystem: {
|
|
||||||
code: this.refSystemId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
RpcService.authService,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
.subscribe({
|
|
||||||
next: () => {
|
|
||||||
this.router.navigate([], {
|
|
||||||
queryParams: {
|
|
||||||
refUserId: null,
|
|
||||||
},
|
|
||||||
queryParamsHandling: 'merge',
|
|
||||||
});
|
|
||||||
this.messageService.add({
|
|
||||||
severity: 'custom',
|
|
||||||
summary:
|
|
||||||
'Регистрация прошла успешна! Бонусы скоро будут начислены',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.error('Error: ', err);
|
|
||||||
this.messageService.add({
|
|
||||||
severity: 'error',
|
|
||||||
summary: 'Произошла ошибка, попробуйте позже',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
changeMainPage(page: Page, event?: MouseEvent): void {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
this.currentPageMain = page;
|
|
||||||
this.router.navigate(['.'], {
|
|
||||||
relativeTo: this.route,
|
|
||||||
// queryParams: {
|
|
||||||
// activePage: this.currentPage.code,
|
|
||||||
// },
|
|
||||||
queryParamsHandling: 'merge',
|
|
||||||
});
|
|
||||||
this.checkAuthorization(true)
|
|
||||||
if (this.currentPageMain === this.mainPageList[2]) {
|
|
||||||
this.checkAuthorization(false)
|
|
||||||
}
|
|
||||||
this.menu.nativeElement.setAttribute('isShow', 'false')
|
|
||||||
}
|
|
||||||
|
|
||||||
changePage(page: Page, event?: MouseEvent): void {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
this.currentPage = page;
|
|
||||||
this.router.navigate(['.'], {
|
|
||||||
relativeTo: this.route,
|
|
||||||
queryParams: {
|
|
||||||
activeAccountPage: this.currentPage.code,
|
|
||||||
},
|
|
||||||
queryParamsHandling: 'merge',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAuthorization(showAuthoriztion: boolean, forced = false) {
|
|
||||||
if (!this.getToken() || forced) {
|
|
||||||
this.showAuthoriztion = showAuthoriztion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHttpError(error: HttpErrorResponse): void {
|
|
||||||
if (error.status === 500) {
|
|
||||||
this.logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setToken(token: string): void {
|
|
||||||
this.cookiesService.setCookie('token', token);
|
|
||||||
}
|
|
||||||
|
|
||||||
getToken(): string | void {
|
|
||||||
return this.cookiesService.getItem('token');
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteToken(): void {
|
|
||||||
this.cookiesService.deleteCookie('token');
|
|
||||||
// this.router.navigate(['.'], {
|
|
||||||
// queryParams: {},
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
onReject() {
|
|
||||||
this.messageService.clear('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfirm() {
|
|
||||||
this.deleteToken();
|
|
||||||
this.showAuthoriztion = true;
|
|
||||||
this.messageService.clear('c')
|
|
||||||
}
|
|
||||||
|
|
||||||
changeTabPage(event: MatTabChangeEvent) {
|
|
||||||
if (event.index === 2) {
|
|
||||||
this.selectedTabPage = 1
|
|
||||||
this.logout()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logout(event?: MouseEvent) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
this.messageService.add({ key: 'c', sticky: true, severity: 'warn', summary: 'Вы уверены, что хотите выйти?' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
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';
|
|
||||||
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 { 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'],
|
|
||||||
})
|
|
||||||
export class BonusProgramComponent implements OnInit {
|
|
||||||
@Input() currentPage!: Page;
|
|
||||||
@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;
|
|
||||||
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 store: Store
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.getAccountData();
|
|
||||||
this.getTypeDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
getAccountData() {
|
|
||||||
const token = this.cookiesService.getItem('token');
|
|
||||||
if (!token) {
|
|
||||||
this.cookiesService.deleteCookie('token');
|
|
||||||
this.deauthorization.emit(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.loadingBonuses = true;
|
|
||||||
this.profile$.pipe(distinctUntilChanged()).subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
if (!res) return;
|
|
||||||
if (res.errorCode === 'Customer_CustomerNotFound' || 'Error' in res) {
|
|
||||||
this.loadingBonuses = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.userName = res.name;
|
|
||||||
this.accountData = {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
this.loadingBonuses = false;
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.error('Error: ', err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTypeDevice() {
|
|
||||||
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
||||||
const ios = /iphone|ipod|ipad/.test(userAgent);
|
|
||||||
this.deviceType = ios ? 'ios' : 'android';
|
|
||||||
}
|
|
||||||
|
|
||||||
async addCardToWallet(e: any) {
|
|
||||||
e.preventDefault();
|
|
||||||
const token = this.cookiesService.getItem('token');
|
|
||||||
const accountData = (
|
|
||||||
await lastValueFrom(
|
|
||||||
this.jsonrpc.rpc(
|
|
||||||
{
|
|
||||||
method: 'getTokenData',
|
|
||||||
params: [],
|
|
||||||
},
|
|
||||||
RpcService.authService,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).data;
|
|
||||||
if (token && accountData.user_id) {
|
|
||||||
this.appleWallet.generateCard(token, accountData.user_id).subscribe({
|
|
||||||
next: (res: any) => {
|
|
||||||
this.document.location.href = res.url;
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.log('Error: ', err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
.show-more-orders {
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--orange-main);
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.not-found-data {
|
|
||||||
text-align: center;
|
|
||||||
color: var(--orange-main);
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.woocommerce-MyAccount-content {
|
|
||||||
max-width: 400px;
|
|
||||||
margin-left: calc(50vw - 200px);
|
|
||||||
}
|
|
||||||
.woocommerce-orders-table {
|
|
||||||
// border: 2px solid #dee2e6;
|
|
||||||
border-bottom: 0;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
border-collapse: separate;
|
|
||||||
text-align: left;
|
|
||||||
margin-top: 8px;
|
|
||||||
width: 100%;
|
|
||||||
// max-width: 400px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
thead {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.woocommerce-orders-table {
|
|
||||||
&__cell {
|
|
||||||
padding: 0.7rem 1.5rem;
|
|
||||||
border-bottom: 2px solid #dee2e6;
|
|
||||||
text-align: right !important;
|
|
||||||
display: block;
|
|
||||||
&::before {
|
|
||||||
content: attr(data-title) ": ";
|
|
||||||
font-weight: 700;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__row {
|
|
||||||
display: block;
|
|
||||||
&:nth-child(even) {
|
|
||||||
background: #ebebeb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// &__cell-order-actions::before {
|
|
||||||
// display: none;
|
|
||||||
// }
|
|
||||||
&__cell-order-actions {
|
|
||||||
&.red-color {
|
|
||||||
color: #ed0000;
|
|
||||||
}
|
|
||||||
&.green-color {
|
|
||||||
color: #00a700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__cell-order-number a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #009688;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-button {
|
|
||||||
display: inline-block;
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #009688;
|
|
||||||
padding: 13px;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:host {
|
|
||||||
.orders {
|
|
||||||
h2 {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
max-width: 400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,244 +0,0 @@
|
|||||||
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 * as moment from 'moment-timezone';
|
|
||||||
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';
|
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-orders',
|
|
||||||
templateUrl: './orders.component.html',
|
|
||||||
styleUrls: ['./orders.component.scss'],
|
|
||||||
})
|
|
||||||
export class OrdersComponent implements OnInit {
|
|
||||||
@Input() currentPage!: Page;
|
|
||||||
@Input() handleHttpError!: (error: HttpErrorResponse) => void;
|
|
||||||
@Output() deauthorization = new EventEmitter<boolean>(false);
|
|
||||||
public lastViewOrder: number = 3;
|
|
||||||
public ordersLoadingStatus: boolean = true;
|
|
||||||
readonly moment = moment;
|
|
||||||
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 defaultFilterType = 'currentMonth';
|
|
||||||
private startOfMonth = moment().startOf('month').format('YYYY-MM-DD HH:mm');
|
|
||||||
public filteredOfDatePurchases: Purchase[] = [];
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
private cookiesService: CookiesService,
|
|
||||||
public dialog: MatDialog,
|
|
||||||
private store: Store,
|
|
||||||
private _snackBar: MatSnackBar
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.getOrders();
|
|
||||||
}
|
|
||||||
|
|
||||||
dateFilter(dateFilter: IDateFilter) {
|
|
||||||
this.lastViewOrder = 3;
|
|
||||||
switch (dateFilter.filterType) {
|
|
||||||
case 'between':
|
|
||||||
this.ordersLoadingStatus = true;
|
|
||||||
this.filteredOfDatePurchases = []
|
|
||||||
const token = this.cookiesService.getItem('token')
|
|
||||||
this.wpJsonService.getTransactionsBetween(environment.systemId, token || '', environment.icardProxy, {
|
|
||||||
date_from: dateFilter.from?.toLocaleString() || '',
|
|
||||||
date_to: dateFilter.to?.toLocaleString() || ''
|
|
||||||
}).subscribe({
|
|
||||||
next: (value) => {
|
|
||||||
this.filteredOfDatePurchases = Object.values(value)[0] as Purchase[]
|
|
||||||
this.ordersLoadingStatus = false
|
|
||||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(
|
|
||||||
0,
|
|
||||||
this.lastViewOrder
|
|
||||||
);
|
|
||||||
console.log(value);
|
|
||||||
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.error(err);
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// this.filteredOfDatePurchases = this.purchases.filter((value) => {
|
|
||||||
// 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);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'lastMonth':
|
|
||||||
this.filteredOfDatePurchases = this.purchases.filter((value) => {
|
|
||||||
return moment(value.transactionCreateDate).isBetween(
|
|
||||||
moment(this.startOfMonth).subtract(1, 'month'),
|
|
||||||
this.startOfMonth
|
|
||||||
);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
this.filteredOfDatePurchases = this.purchases;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(
|
|
||||||
0,
|
|
||||||
this.lastViewOrder
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getOrders() {
|
|
||||||
const token = this.cookiesService.getItem('token');
|
|
||||||
if (!token) {
|
|
||||||
this.cookiesService.deleteCookie('token');
|
|
||||||
this.deauthorization.emit(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.transactionsState$.subscribe({
|
|
||||||
next: (transactions) => {
|
|
||||||
// console.log(transactions);
|
|
||||||
|
|
||||||
if (transactions) {
|
|
||||||
this.purchases = transactions.filter((purchase: Purchase) =>
|
|
||||||
['PayFromWallet', 'CancelPayFromWallet', 'RefillWallet'].includes(
|
|
||||||
purchase.transactionType
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.ordersLoadingStatus = false
|
|
||||||
this.transactionsInfoState$.subscribe({
|
|
||||||
next: (transactionsInfo) => {
|
|
||||||
if (transactionsInfo) {
|
|
||||||
this.purchases.map<Purchase>((purchase) => {
|
|
||||||
return {
|
|
||||||
...purchase,
|
|
||||||
more_info:
|
|
||||||
transactionsInfo.find(
|
|
||||||
(purchaseInfo: PurchaseInfo) =>
|
|
||||||
Number(purchaseInfo.number) === purchase.orderNumber
|
|
||||||
) || null,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// combineLatest([this.transactionsState$, this.transactionsInfoState$])
|
|
||||||
// .pipe(distinctUntilChanged())
|
|
||||||
// .subscribe({
|
|
||||||
// next: ([transactions, transactionsInfo]) => {
|
|
||||||
// console.log('####: ', transactions);
|
|
||||||
// console.log('####I: ', 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)
|
|
||||||
// );
|
|
||||||
// } else if (transactions && !transactionsInfo) {
|
|
||||||
// this.purchases = transactions.filter((purchase: Purchase) =>
|
|
||||||
// ['PayFromWallet', 'CancelPayFromWallet', 'RefillWallet'].includes(
|
|
||||||
// purchase.transactionType
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// this._snackBar.open(
|
|
||||||
// 'Произошла ошибка получения подробностей по транзакциям',
|
|
||||||
// '',
|
|
||||||
// {
|
|
||||||
// duration: 3500,
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// this._snackBar.open(
|
|
||||||
// 'Произошла ошибка получения данных по транзакциям',
|
|
||||||
// '',
|
|
||||||
// {
|
|
||||||
// duration: 3500,
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// this.ordersLoadingStatus = false;
|
|
||||||
// console.log(this.purchases);
|
|
||||||
|
|
||||||
// this.dateFilter({ filterType: this.defaultFilterType });
|
|
||||||
// },
|
|
||||||
// error: (err) => {
|
|
||||||
// console.error('Error: ', err);
|
|
||||||
// this.ordersLoadingStatus = false;
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
getMoreOrders() {
|
|
||||||
this.lastViewOrder += 4;
|
|
||||||
this.purchasesShortArray = this.filteredOfDatePurchases.slice(
|
|
||||||
0,
|
|
||||||
this.lastViewOrder
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
showPurchaseInfo(purchaseInfo: PurchaseInfo) {
|
|
||||||
const dialogRef = this.dialog.open(PurchaseInfoComponent, {
|
|
||||||
data: { purchaseInfo },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
<div class="orders">
|
|
||||||
<!-- <h2>{{ currentPage.name }}</h2> -->
|
|
||||||
<table
|
|
||||||
class="woocommerce-orders-table woocommerce-MyAccount-orders shop_table shop_table_responsive my_account_orders account-orders-table"
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-date"
|
|
||||||
>
|
|
||||||
<span class="nobr">Дата</span>
|
|
||||||
</th>
|
|
||||||
<!-- <th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-status"
|
|
||||||
>
|
|
||||||
<span class="nobr">Место покупки</span>
|
|
||||||
</th> -->
|
|
||||||
<th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-total"
|
|
||||||
>
|
|
||||||
<span class="nobr">Сумма</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-bonuses"
|
|
||||||
>
|
|
||||||
<span class="nobr">Статус</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-actions"
|
|
||||||
>
|
|
||||||
<span class="nobr">Комментарий</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-actions"
|
|
||||||
>
|
|
||||||
<span class="nobr">Магазин</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-actions"
|
|
||||||
>
|
|
||||||
<span class="nobr">Продукты</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
*ngFor="let purchase of purchases"
|
|
||||||
class="woocommerce-orders-table__row woocommerce-orders-table__row--status-processing order"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-date"
|
|
||||||
data-title="Дата"
|
|
||||||
>
|
|
||||||
<time [dateTime]="purchase.created_datetime">{{
|
|
||||||
moment(purchase.created_datetime).format("DD.MM.YYYY")
|
|
||||||
}}</time>
|
|
||||||
</td>
|
|
||||||
<!-- <td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-status"
|
|
||||||
data-title="Место покупки"
|
|
||||||
>
|
|
||||||
{{ purchase.Address }}
|
|
||||||
</td> -->
|
|
||||||
<td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-total"
|
|
||||||
data-title="Сумма"
|
|
||||||
>
|
|
||||||
<span class="woocommerce-Price-amount amount">
|
|
||||||
{{ purchase.orderAmount }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
*ngIf="purchase.status && orderStatuses[purchase.status]"
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-total"
|
|
||||||
data-title="Статус"
|
|
||||||
>
|
|
||||||
<span class="woocommerce-Price-amount amount">
|
|
||||||
{{ orderStatuses[purchase.status] }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<!-- <td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-total"
|
|
||||||
data-title="Комментарий"
|
|
||||||
>
|
|
||||||
<span class="woocommerce-Price-amount amount">
|
|
||||||
{{ purchase.data.comment }}
|
|
||||||
</span>
|
|
||||||
</td> -->
|
|
||||||
<!-- <td
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-total"
|
|
||||||
data-title="Магазин"
|
|
||||||
>
|
|
||||||
<span class="woocommerce-Price-amount amount">
|
|
||||||
{{ purchase.data.comment }}
|
|
||||||
</span>
|
|
||||||
</td> -->
|
|
||||||
<td
|
|
||||||
*ngIf="purchase.more_info"
|
|
||||||
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-actions"
|
|
||||||
data-title="Действия"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
mat-stroked-button
|
|
||||||
(click)="showPurchaseInfo(purchase.more_info)"
|
|
||||||
>
|
|
||||||
Подробнее
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<!-- <p
|
|
||||||
*ngIf="
|
|
||||||
filteredOfDatePurchases.length !== purchasesShortArray.length &&
|
|
||||||
purchasesShortArray.length
|
|
||||||
"
|
|
||||||
class="show-more-orders"
|
|
||||||
(click)="getMoreOrders()"
|
|
||||||
>
|
|
||||||
Показать больше
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
*ngIf="!purchasesShortArray.length && !ordersLoadingStatus"
|
|
||||||
class="not-found-data"
|
|
||||||
>
|
|
||||||
Данные не найдены
|
|
||||||
</p> -->
|
|
||||||
<p-progressSpinner
|
|
||||||
*ngIf="loading"
|
|
||||||
[style]="{ width: '100%' }"
|
|
||||||
strokeWidth="2"
|
|
||||||
styleClass="angular-spinner"
|
|
||||||
></p-progressSpinner>
|
|
||||||
<!-- <p
|
|
||||||
*ngIf="purchases.length === 0 && !ordersLoadingStatus"
|
|
||||||
style="width: 100%; text-align: center"
|
|
||||||
>
|
|
||||||
Нет заказов
|
|
||||||
</p> -->
|
|
||||||
</div>
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
.show-more-orders {
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--orange-main);
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.not-found-data {
|
|
||||||
text-align: center;
|
|
||||||
color: var(--orange-main);
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.woocommerce-MyAccount-content {
|
|
||||||
max-width: 400px;
|
|
||||||
margin-left: calc(50vw - 200px);
|
|
||||||
}
|
|
||||||
.woocommerce-orders-table {
|
|
||||||
// border: 2px solid #dee2e6;
|
|
||||||
border-bottom: 0;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
border-collapse: separate;
|
|
||||||
text-align: left;
|
|
||||||
margin-top: 8px;
|
|
||||||
width: 100%;
|
|
||||||
// max-width: 400px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
thead {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.woocommerce-orders-table {
|
|
||||||
&__cell {
|
|
||||||
padding: 0.7rem 1.5rem;
|
|
||||||
border-bottom: 2px solid #dee2e6;
|
|
||||||
text-align: right !important;
|
|
||||||
display: block;
|
|
||||||
min-height: 46px;
|
|
||||||
&::before {
|
|
||||||
content: attr(data-title) ": ";
|
|
||||||
font-weight: 700;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__row {
|
|
||||||
display: block;
|
|
||||||
&:nth-child(even) {
|
|
||||||
background: #ebebeb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// &__cell-order-actions::before {
|
|
||||||
// display: none;
|
|
||||||
// }
|
|
||||||
&__cell-order-actions {
|
|
||||||
&.red-color {
|
|
||||||
color: #ed0000;
|
|
||||||
}
|
|
||||||
&.green-color {
|
|
||||||
color: #00a700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&__cell-order-number a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #009688;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-button {
|
|
||||||
display: inline-block;
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #009688;
|
|
||||||
padding: 13px;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:host {
|
|
||||||
.orders {
|
|
||||||
h2 {
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 24px;
|
|
||||||
max-width: 400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { PurcahsesComponent } from './purcahses.component';
|
|
||||||
|
|
||||||
describe('PurcahsesComponent', () => {
|
|
||||||
let component: PurcahsesComponent;
|
|
||||||
let fixture: ComponentFixture<PurcahsesComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ PurcahsesComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(PurcahsesComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import moment from 'moment';
|
|
||||||
import { orderStatuses } from 'src/app/app.constants';
|
|
||||||
import { PurchaseInfoComponent } from 'src/app/components/purchase-info/purchase-info.component';
|
|
||||||
import { PurchaseInfo } from 'src/app/interface/data';
|
|
||||||
import { WpJsonService } from 'src/app/services/wp-json.service';
|
|
||||||
import { environment } from 'src/environments/environment';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-purcahses',
|
|
||||||
templateUrl: './purcahses.component.html',
|
|
||||||
styleUrls: ['./purcahses.component.scss'],
|
|
||||||
})
|
|
||||||
export class PurcahsesComponent implements OnInit {
|
|
||||||
public purchases: any;
|
|
||||||
readonly moment = moment;
|
|
||||||
public orderStatuses = orderStatuses;
|
|
||||||
public loading = true;
|
|
||||||
|
|
||||||
constructor(private wpJsonService: WpJsonService, public dialog: MatDialog) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.wpJsonService.getUserOrders(environment.webhookItRetail).subscribe({
|
|
||||||
next: (value) => {
|
|
||||||
this.purchases = value.result.map((purchase: any) => {
|
|
||||||
purchase.orderAmount = purchase.data.products.reduce(
|
|
||||||
(previous: any, current: any) => {
|
|
||||||
return previous + Number(current.amount);
|
|
||||||
},
|
|
||||||
0
|
|
||||||
);
|
|
||||||
purchase.more_info = {
|
|
||||||
date: purchase.created_datetime,
|
|
||||||
goods_list: purchase.data.products.map((product: any) => {
|
|
||||||
return {
|
|
||||||
name: product.name,
|
|
||||||
price: product.price,
|
|
||||||
quantity: product.quantity,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
number: purchase.public_id,
|
|
||||||
sum: purchase.orderAmount,
|
|
||||||
};
|
|
||||||
return purchase;
|
|
||||||
});
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showPurchaseInfo(purchaseInfo: PurchaseInfo) {
|
|
||||||
const dialogRef = this.dialog.open(PurchaseInfoComponent, {
|
|
||||||
data: { purchaseInfo },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,181 +0,0 @@
|
|||||||
<p-sidebar
|
|
||||||
[(visible)]="visibleSidebar"
|
|
||||||
[fullScreen]="isFullScreen"
|
|
||||||
[baseZIndex]="10000"
|
|
||||||
position="right"
|
|
||||||
(onHide)="hide()"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="cart"
|
|
||||||
*ngIf="!loading && order && !orderConfirmed"
|
|
||||||
[ngStyle]="{ margin: !order.products.length && 0 }"
|
|
||||||
>
|
|
||||||
<div class="widget_shopping_cart_content" style="opacity: 1">
|
|
||||||
<div
|
|
||||||
class="elementor-menu-cart__products woocommerce-mini-cart cart woocommerce-cart-form__contents"
|
|
||||||
[ngStyle]="{ margin: !order.products.length && 0 }"
|
|
||||||
>
|
|
||||||
<div *ngFor="let product of order.products; let last = last">
|
|
||||||
<div
|
|
||||||
class="elementor-menu-cart__product woocommerce-cart-form__cart-item cart_item"
|
|
||||||
style="grid-template-columns: 70px auto"
|
|
||||||
>
|
|
||||||
<div class="elementor-menu-cart__product-image product-thumbnail">
|
|
||||||
<img
|
|
||||||
*ngIf="product.image"
|
|
||||||
width="70"
|
|
||||||
height="70"
|
|
||||||
src="{{ product.image }}"
|
|
||||||
class="attachment-woocommerce_thumbnail size-woocommerce_thumbnail"
|
|
||||||
alt="{{ product.name }}"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
*ngIf="!product.image"
|
|
||||||
width="70"
|
|
||||||
height="70"
|
|
||||||
src="./assets/no-image.png"
|
|
||||||
class="attachment-woocommerce_thumbnail size-woocommerce_thumbnail"
|
|
||||||
alt="{{ product.name }}"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="elementor-menu-cart__product-name product-name"
|
|
||||||
data-title="Product"
|
|
||||||
>
|
|
||||||
<span>{{ product.name }}</span>
|
|
||||||
<dl
|
|
||||||
*ngFor="let modifier of product.modifier_data"
|
|
||||||
class="variation"
|
|
||||||
[ngStyle]="{ margin: !modifier.options.length && 0 }"
|
|
||||||
>
|
|
||||||
<ng-container *ngFor="let option of modifier.options">
|
|
||||||
<dt
|
|
||||||
*ngIf="option.quantity"
|
|
||||||
style="max-width: 160px"
|
|
||||||
class="variation-"
|
|
||||||
>
|
|
||||||
{{ option.name }}:
|
|
||||||
</dt>
|
|
||||||
<dd
|
|
||||||
*ngIf="option.quantity"
|
|
||||||
style="
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
margin-bottom: 0;
|
|
||||||
"
|
|
||||||
class="variation-"
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
{{ option.quantity }} × {{ product.currency_symbol
|
|
||||||
}}{{ (option.price ?? 0) * option.quantity }}
|
|
||||||
</p>
|
|
||||||
</dd>
|
|
||||||
</ng-container>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="elementor-menu-cart__product-price product-price"
|
|
||||||
data-title="Price"
|
|
||||||
>
|
|
||||||
<span class="quantity">
|
|
||||||
<span class="product-quantity">{{ product.amount }} × </span>
|
|
||||||
<span class="woocommerce-Price-amount amount">
|
|
||||||
<bdi>
|
|
||||||
<span class="woocommerce-Price-currencySymbol">{{
|
|
||||||
product.currency_symbol
|
|
||||||
}}</span>
|
|
||||||
{{ product.finalPrice }}
|
|
||||||
</bdi>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<div class="product-change-amount">
|
|
||||||
<div
|
|
||||||
class="product-change-amount__symbol"
|
|
||||||
(click)="setAmount(product, 'minus')"
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="product-change-amount__symbol"
|
|
||||||
(click)="setAmount(product, 'plus')"
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="elementor-menu-cart__product-remove product-remove">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="remove_from_cart_button"
|
|
||||||
aria-label="Remove this item"
|
|
||||||
(click)="removeFromCart($event, product.guid)"
|
|
||||||
></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr *ngIf="!last" />
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
*ngIf="order.products.length != 0"
|
|
||||||
class="clear-cart"
|
|
||||||
(click)="confirmClearCart()"
|
|
||||||
>
|
|
||||||
Очистить корзину
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
*ngIf="order.products.length != 0"
|
|
||||||
class="elementor-menu-cart__bottom-info"
|
|
||||||
>
|
|
||||||
<div class="elementor-menu-cart__subtotal">
|
|
||||||
<span class="products-count"
|
|
||||||
>Товаров: {{ order.products.length }}</span
|
|
||||||
>
|
|
||||||
<span class="woocommerce-Price-amount amount"
|
|
||||||
><bdi
|
|
||||||
><span class="woocommerce-Price-currencySymbol">{{
|
|
||||||
order.products[0].currency_symbol
|
|
||||||
}}</span
|
|
||||||
>{{ order.price }}</bdi
|
|
||||||
></span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="elementor-menu-cart__footer-buttons">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="elementor-button elementor-button--checkout elementor-size-md"
|
|
||||||
(click)="confirmOrder($event)"
|
|
||||||
>
|
|
||||||
<span class="elementor-button-text">Оформление заказа</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<app-user-data-order
|
|
||||||
*ngIf="orderConfirmed"
|
|
||||||
(orderSubmitted)="orderSubmitted($event)"
|
|
||||||
(userNotFound)="userNotFound($event)"
|
|
||||||
></app-user-data-order>
|
|
||||||
|
|
||||||
<div #loadingEl *ngIf="loading && !orderConfirmed">
|
|
||||||
<div
|
|
||||||
class="angular-spinner-container"
|
|
||||||
style="width: fit-content; height: 100%; margin: 16px auto"
|
|
||||||
>
|
|
||||||
<p-progressSpinner styleClass="angular-spinner"></p-progressSpinner>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div #empty *ngIf="!loading && (!order || !order.products.length)">
|
|
||||||
<div
|
|
||||||
class="woocommerce-mini-cart__empty-message jupiterx-icon-shopping-cart-6"
|
|
||||||
>
|
|
||||||
Корзина пустая.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</p-sidebar>
|
|
||||||
@ -1,235 +0,0 @@
|
|||||||
:host {
|
|
||||||
.cart {
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 100px;
|
|
||||||
max-width: 400px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.elementor-menu-cart {
|
|
||||||
&__product {
|
|
||||||
grid-template-columns: 71px auto;
|
|
||||||
grid-template-rows: var(
|
|
||||||
--price-quantity-position--grid-template-rows,
|
|
||||||
auto auto
|
|
||||||
);
|
|
||||||
position: relative;
|
|
||||||
display: grid;
|
|
||||||
padding-bottom: 0;
|
|
||||||
padding-right: 30px;
|
|
||||||
|
|
||||||
.variation {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: max-content auto;
|
|
||||||
margin: 10px 8px;
|
|
||||||
color: var(--product-variations-color, #373a3c);
|
|
||||||
|
|
||||||
dt {
|
|
||||||
grid-column-start: 1;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
grid-column-start: 2;
|
|
||||||
-webkit-margin-start: 5px;
|
|
||||||
margin-inline-start: 5px;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__product-image {
|
|
||||||
grid-row-start: 1;
|
|
||||||
grid-row-end: 3;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-radius: 6px;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__product-name {
|
|
||||||
grid-column-start: 2;
|
|
||||||
grid-column-end: 3;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__product-price {
|
|
||||||
font-size: 14px;
|
|
||||||
padding-left: 20px;
|
|
||||||
grid-column-start: 2;
|
|
||||||
grid-column-end: 3;
|
|
||||||
-ms-flex-item-align: var(--price-quantity-position--align-self, end);
|
|
||||||
align-self: var(--price-quantity-position--align-self, end);
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__product-remove {
|
|
||||||
color: #818a91;
|
|
||||||
width: var(--remove-item-button-size, 22px);
|
|
||||||
height: var(--remove-item-button-size, 22px);
|
|
||||||
border-radius: var(--remove-item-button-size, 22px);
|
|
||||||
border: 1px solid var(--remove-item-button-color, #d4d4d4);
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
right: 0;
|
|
||||||
bottom: 20px;
|
|
||||||
-webkit-transition: 0.3s;
|
|
||||||
-o-transition: 0.3s;
|
|
||||||
transition: 0.3s;
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
height: 1px;
|
|
||||||
width: 50%;
|
|
||||||
top: 50%;
|
|
||||||
left: 25%;
|
|
||||||
margin-top: -1px;
|
|
||||||
background: var(--remove-item-button-color, #d4d4d4);
|
|
||||||
z-index: 1;
|
|
||||||
-webkit-transition: 0.3s;
|
|
||||||
-o-transition: 0.3s;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-ms-transform: rotate(45deg);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
-webkit-transform: rotate(-45deg);
|
|
||||||
-ms-transform: rotate(-45deg);
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
display: block;
|
|
||||||
z-index: 2;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__bottom-info {
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
bottom: 0;
|
|
||||||
padding: 18px;
|
|
||||||
background: #fff;
|
|
||||||
z-index: 3;
|
|
||||||
border-top: solid 1px #e7e7e7;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__subtotal {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& .products-count {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer-buttons {
|
|
||||||
a {
|
|
||||||
padding: 12px;
|
|
||||||
display: block;
|
|
||||||
width: fit-content;
|
|
||||||
background: var(--orange-main);
|
|
||||||
border-radius: 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-thumbnail {
|
|
||||||
background: #eee;
|
|
||||||
border-radius: 9px;
|
|
||||||
height: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-change-amount {
|
|
||||||
width: 50px;
|
|
||||||
height: 30px;
|
|
||||||
margin-top: 4px;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: flex;
|
|
||||||
border: solid #cbcbcb 1px;
|
|
||||||
color: #525252;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&__symbol {
|
|
||||||
width: 50%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border-right: solid #cbcbcb 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-product {
|
|
||||||
&__supplements {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 26px;
|
|
||||||
padding: 8px;
|
|
||||||
background: #f9b004;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-mini-cart__empty-message {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
width: 80%;
|
|
||||||
margin: 14px auto;
|
|
||||||
border-top: solid #d1d1d1 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear-cart {
|
|
||||||
padding: 8px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: #d7120b;
|
|
||||||
color: #fff;
|
|
||||||
margin: 32px auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 650px) {
|
|
||||||
.elementor-menu-cart__bottom-info {
|
|
||||||
width: 450px;
|
|
||||||
right: 0;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { CartComponent } from './cart.component';
|
|
||||||
|
|
||||||
describe('CartComponent', () => {
|
|
||||||
let component: CartComponent;
|
|
||||||
let fixture: ComponentFixture<CartComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ CartComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(CartComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
import {
|
|
||||||
Component,
|
|
||||||
EventEmitter,
|
|
||||||
HostListener,
|
|
||||||
OnInit,
|
|
||||||
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 {
|
|
||||||
CartService,
|
|
||||||
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',
|
|
||||||
templateUrl: './cart.component.html',
|
|
||||||
styleUrls: ['./cart.component.scss'],
|
|
||||||
})
|
|
||||||
export class CartComponent implements OnInit {
|
|
||||||
@Output() showAuthoriztion = new EventEmitter<boolean>();
|
|
||||||
public loading = false;
|
|
||||||
public orderConfirmed = false;
|
|
||||||
public order!: Order;
|
|
||||||
public price!: number;
|
|
||||||
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 store: Store,
|
|
||||||
private cookiesService: CookiesService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async ngOnInit() {
|
|
||||||
this.width = window.innerWidth;
|
|
||||||
this.changeDullScreenMode();
|
|
||||||
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('Произошла ошибка!');
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Изменение размера окна
|
|
||||||
@HostListener('window:resize', ['$event'])
|
|
||||||
onResize(event: any) {
|
|
||||||
this.width = event.target.innerWidth;
|
|
||||||
this.changeDullScreenMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSideBar(): void {
|
|
||||||
this.visibleSidebar = !this.visibleSidebar;
|
|
||||||
this.orderConfirmed = false;
|
|
||||||
this.loadCart();
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.orderConfirmed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
changeDullScreenMode() {
|
|
||||||
if (this.width < 650) {
|
|
||||||
this.isFullScreen = true;
|
|
||||||
} else {
|
|
||||||
this.isFullScreen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (this.order) this.price = this.order.price;
|
|
||||||
this.store.dispatch(ProfileActions.getProfile());
|
|
||||||
}
|
|
||||||
|
|
||||||
userNotFound(event: null = null) {
|
|
||||||
this.visibleSidebar = false;
|
|
||||||
// this._snackBar.open('Пользователь не найден в системе! Обратитесь к руководству', 'Ок')
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
setAmount(product: OrderProduct, method: 'plus' | 'minus') {
|
|
||||||
if (method === 'plus') {
|
|
||||||
this.cartService.changeAmountProduct(
|
|
||||||
product.guid,
|
|
||||||
ProductAmountAction.increment
|
|
||||||
);
|
|
||||||
product.amount++;
|
|
||||||
this.price = this.price + Number(product.price);
|
|
||||||
} else if (method === 'minus' && product.amount > 1) {
|
|
||||||
this.cartService.changeAmountProduct(
|
|
||||||
product.guid,
|
|
||||||
ProductAmountAction.decrement
|
|
||||||
);
|
|
||||||
product.amount--;
|
|
||||||
this.price = this.price - Number(product.price);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orderSubmitted(orderid: number) {
|
|
||||||
this.visibleSidebar = false;
|
|
||||||
this._snackBar.open(`Заказ оформлен! Номер заказа: ${orderid}`, 'Ок');
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmClearCart() {
|
|
||||||
const snackBar = this._snackBar.openFromComponent(SnackBarComponent, {
|
|
||||||
duration: 4000,
|
|
||||||
data: {
|
|
||||||
text: 'Очистить корзину?',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
snackBar.afterDismissed().subscribe(({ dismissedByAction }) => {
|
|
||||||
if (dismissedByAction) {
|
|
||||||
this.cartService.clearCart();
|
|
||||||
this.loadCart();
|
|
||||||
this.visibleSidebar = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
<p>info works!</p>
|
|
||||||
<mdb-carousel [controls]="true" [indicators]="true" [animation]="'fade'">
|
|
||||||
<mdb-carousel-item>
|
|
||||||
<img src="https://mdbootstrap.com/img/Photos/Slides/img%20(15).webp" class="d-block w-100" alt="..." />
|
|
||||||
<div class="carousel-caption d-none d-md-block">
|
|
||||||
<h5>First slide label</h5>
|
|
||||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
|
||||||
</div>
|
|
||||||
</mdb-carousel-item>
|
|
||||||
<mdb-carousel-item>
|
|
||||||
<img src="https://mdbootstrap.com/img/Photos/Slides/img%20(22).webp" class="d-block w-100" alt="..." />
|
|
||||||
<div class="carousel-caption d-none d-md-block">
|
|
||||||
<h5>Second slide label</h5>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
|
||||||
</div>
|
|
||||||
</mdb-carousel-item>
|
|
||||||
<mdb-carousel-item>
|
|
||||||
<img src="https://mdbootstrap.com/img/Photos/Slides/img%20(23).webp" class="d-block w-100" alt="..." />
|
|
||||||
<div class="carousel-caption d-none d-md-block">
|
|
||||||
<h5>Third slide label</h5>
|
|
||||||
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>
|
|
||||||
</div>
|
|
||||||
</mdb-carousel-item>
|
|
||||||
</mdb-carousel>
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { InfoComponent } from './info.component';
|
|
||||||
|
|
||||||
describe('InfoComponent', () => {
|
|
||||||
let component: InfoComponent;
|
|
||||||
let fixture: ComponentFixture<InfoComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ InfoComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(InfoComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-info',
|
|
||||||
templateUrl: './info.component.html',
|
|
||||||
styleUrls: ['./info.component.scss']
|
|
||||||
})
|
|
||||||
export class InfoComponent implements OnInit {
|
|
||||||
public imageObject = [{
|
|
||||||
image: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/5.jpg',
|
|
||||||
thumbImage: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/5.jpg',
|
|
||||||
title: 'Hummingbirds are amazing creatures'
|
|
||||||
}, {
|
|
||||||
image: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/9.jpg',
|
|
||||||
thumbImage: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/9.jpg'
|
|
||||||
}, {
|
|
||||||
image: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/4.jpg',
|
|
||||||
thumbImage: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/4.jpg',
|
|
||||||
title: 'Example with title.'
|
|
||||||
}, {
|
|
||||||
image: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/7.jpg',
|
|
||||||
thumbImage: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/7.jpg',
|
|
||||||
title: 'Hummingbirds are amazing creatures'
|
|
||||||
}, {
|
|
||||||
image: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/1.jpg',
|
|
||||||
thumbImage: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/1.jpg'
|
|
||||||
}, {
|
|
||||||
image: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/2.jpg',
|
|
||||||
thumbImage: 'https://sanjayv.github.io/ng-image-slider/contents/assets/img/slider/2.jpg',
|
|
||||||
title: 'Example two with title.'
|
|
||||||
}];
|
|
||||||
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
<div class="not-found-page">
|
|
||||||
<div class="not-found-page__container">
|
|
||||||
<h1>404</h1>
|
|
||||||
<p>Упс, что-то пошло не так!</p>
|
|
||||||
<a href="#" (click)="routeHome($event)">Перейти на главную</a>
|
|
||||||
<!-- <button (click)="routeHome()">Вернуться на главную</button> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
:host {
|
|
||||||
.not-found-page {
|
|
||||||
height: calc(100vh - 70px);
|
|
||||||
&__container {
|
|
||||||
text-align: center;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-khtml-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
h1 {
|
|
||||||
font-size: 136px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #252525;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 48px 0;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
letter-spacing: 1px;
|
|
||||||
color: #252525;
|
|
||||||
border-bottom: 2px solid #252525;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { NotFoundComponent } from './not-found.component';
|
|
||||||
|
|
||||||
describe('NotFoundComponent', () => {
|
|
||||||
let component: NotFoundComponent;
|
|
||||||
let fixture: ComponentFixture<NotFoundComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ NotFoundComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(NotFoundComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-not-found',
|
|
||||||
templateUrl: './not-found.component.html',
|
|
||||||
styleUrls: ['./not-found.component.scss'],
|
|
||||||
})
|
|
||||||
export class NotFoundComponent implements OnInit {
|
|
||||||
constructor(private router: Router, private route: ActivatedRoute) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {}
|
|
||||||
|
|
||||||
routeHome(event: MouseEvent) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
this.router.navigate(['/'], {
|
|
||||||
relativeTo: this.route,
|
|
||||||
queryParamsHandling: 'merge',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
<p-toast position="top-center"></p-toast>
|
|
||||||
<div *ngIf="!loading; else loadingEl" class="products-container">
|
|
||||||
<div class="products-container__filters-container">
|
|
||||||
<div class="products-container__categories-container">
|
|
||||||
<div
|
|
||||||
*ngFor="let group of groups; let first = first"
|
|
||||||
(click)="changeGroup(group)"
|
|
||||||
[ngClass]="{
|
|
||||||
'group-container': true,
|
|
||||||
active: group.id === selectedGroup.id,
|
|
||||||
'non-visible': first
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
{{ group.label }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button mat-stroked-button (click)="showTerminals()">
|
|
||||||
{{ selectedTerminal.label }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
*ngIf="selectedGroup && selectedGroup.label !== 'Все'"
|
|
||||||
class="products-container__category-name-container"
|
|
||||||
>
|
|
||||||
<h1>{{ selectedGroup.label }}</h1>
|
|
||||||
<div class="bread-crumbs">
|
|
||||||
<span class="all" (click)="changeGroup(groups[0])">Все </span>
|
|
||||||
>
|
|
||||||
<span class="selected-category"> {{ selectedGroup.label }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ng-container *ngIf="selectedGroup && selectedGroup.label === 'Все'">
|
|
||||||
<div
|
|
||||||
*ngFor="let group of groups.slice(1)"
|
|
||||||
[ngClass]="{
|
|
||||||
'products-container__category-container': true
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div class="header">
|
|
||||||
<h2>{{ group.label }}</h2>
|
|
||||||
<button (click)="changeGroup(group)">В категорию</button>
|
|
||||||
</div>
|
|
||||||
<div class="products-container__items">
|
|
||||||
<div
|
|
||||||
*ngFor="let product of filterByGroup(group); trackBy: trackProducts"
|
|
||||||
(click)="addToCart($event, product)"
|
|
||||||
class="products-container__item"
|
|
||||||
#currentCategoryList
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="{{
|
|
||||||
product.image?.length ? product.image : './assets/no-image.png'
|
|
||||||
}}"
|
|
||||||
alt="{{ product.name }}"
|
|
||||||
/>
|
|
||||||
<div class="products-container__name-container">
|
|
||||||
<p>{{ product.name }}</p>
|
|
||||||
</div>
|
|
||||||
<p class="products-container__product-composition">
|
|
||||||
{{ product.description }}
|
|
||||||
</p>
|
|
||||||
<div class="products-container__item-footer">
|
|
||||||
<span>{{ product.price }}₽</span>
|
|
||||||
<button class="products-container__add-to-cart">В корзину</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="selectedGroup && selectedGroup.label !== 'Все'">
|
|
||||||
<div class="products-container__items">
|
|
||||||
<div
|
|
||||||
*ngFor="let product of filterByGroup(); trackBy: trackProducts"
|
|
||||||
(click)="addToCart($event, product)"
|
|
||||||
class="products-container__item"
|
|
||||||
#currentCategoryList
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
*ngIf="!product.image"
|
|
||||||
src="./assets/no-image.png"
|
|
||||||
alt="{{ product.name }}"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
*ngIf="product.image"
|
|
||||||
src="{{ product.image }}"
|
|
||||||
alt="{{ product.name }}"
|
|
||||||
/>
|
|
||||||
<div class="products-container__name-container">
|
|
||||||
<p>{{ product.name }}</p>
|
|
||||||
</div>
|
|
||||||
<p class="products-container__product-composition">
|
|
||||||
{{ product.description }}
|
|
||||||
</p>
|
|
||||||
<div class="products-container__item-footer">
|
|
||||||
<span>{{ product.price }}₽</span>
|
|
||||||
<button class="products-container__add-to-cart">В корзину</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
<ng-template #loadingEl>
|
|
||||||
<div
|
|
||||||
class="angular-spinner-container"
|
|
||||||
style="width: fit-content; height: 100%; margin: 16px auto"
|
|
||||||
>
|
|
||||||
<p-progressSpinner styleClass="angular-spinner"></p-progressSpinner>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
@ -1,256 +0,0 @@
|
|||||||
@import 'src/sass/mixins';
|
|
||||||
|
|
||||||
:host {
|
|
||||||
.products-container {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1208px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 0 auto 64px;
|
|
||||||
|
|
||||||
&__category-name-container {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 30px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bread-crumbs {
|
|
||||||
font-weight: 600;
|
|
||||||
color: #9d9d9d;
|
|
||||||
font-size: 16px;
|
|
||||||
|
|
||||||
.all {
|
|
||||||
margin-right: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-category {
|
|
||||||
color: var(--orange-main);
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__filters-container {
|
|
||||||
width: 100%;
|
|
||||||
margin: 12px auto 24px auto;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__categories-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
font-size: 14px;
|
|
||||||
align-items: center;
|
|
||||||
overflow-x: auto;
|
|
||||||
width: auto;
|
|
||||||
margin-right: 16px;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
-webkit-box-shadow: 5px 5px 5px -5px rgba(34, 60, 80, 0.2) inset;
|
|
||||||
background-color: #f9f9fd;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 10px;
|
|
||||||
background: linear-gradient(180deg, #00c6fb, #005bea);
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-container {
|
|
||||||
font-weight: 600;
|
|
||||||
padding: 8px 24px;
|
|
||||||
transition: all 0.5s;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
text-align: center;
|
|
||||||
background: #ededed;
|
|
||||||
border: none;
|
|
||||||
min-width: fit-content;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.non-visible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: #fff;
|
|
||||||
background: var(--orange-main);
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include hover-supported() {
|
|
||||||
color: #fff;
|
|
||||||
background: var(--orange-main);
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__items {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__category-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin: 48px 0 16px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 30px;
|
|
||||||
font-weight: 500;
|
|
||||||
max-width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 8px 26px;
|
|
||||||
background: var(--orange-main);
|
|
||||||
border: none;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
color: #fff;
|
|
||||||
transition: all 0.3s;
|
|
||||||
|
|
||||||
@include hover-supported() {
|
|
||||||
box-shadow: 0 0 10px 5px rgb(211 211 211);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
height: auto;
|
|
||||||
min-height: 200px;
|
|
||||||
width: 290px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
padding-bottom: 38px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 190px;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include hover-supported() {
|
|
||||||
scale: 1.01;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
img {
|
|
||||||
box-shadow: 0 0 10px 5px rgb(221 221 221);
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name-container {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
margin-top: 8px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__add-to-cart {
|
|
||||||
padding: 8px 26px;
|
|
||||||
background: var(--orange-main);
|
|
||||||
border: none;
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item-footer {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__product-composition {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.375;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1243px) {
|
|
||||||
.products-container {
|
|
||||||
max-width: 902px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 937px) {
|
|
||||||
.products-container {
|
|
||||||
max-width: 596px;
|
|
||||||
|
|
||||||
&__filters-container {
|
|
||||||
flex-direction: column-reverse;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 631px) {
|
|
||||||
.products-container {
|
|
||||||
max-width: 400px;
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-input-element {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-stroked-button {
|
|
||||||
border-radius: 1.125rem;
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ProductsComponent } from './products.component';
|
|
||||||
|
|
||||||
describe('ProductsComponent', () => {
|
|
||||||
let component: ProductsComponent;
|
|
||||||
let fixture: ComponentFixture<ProductsComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [ ProductsComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ProductsComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,188 +0,0 @@
|
|||||||
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 { CartService } from 'src/app/services/cart.service';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
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';
|
|
||||||
import { environment } from 'src/environments/environment';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-products',
|
|
||||||
templateUrl: './products.component.html',
|
|
||||||
styleUrls: ['./products.component.scss'],
|
|
||||||
providers: [MessageService],
|
|
||||||
})
|
|
||||||
export class ProductsComponent implements OnInit {
|
|
||||||
public products!: Product[];
|
|
||||||
public groups: Group[] = [];
|
|
||||||
public modifiersGroups!: ModifiersGroup[];
|
|
||||||
public modifiers!: Modifier[];
|
|
||||||
public selectedGroup!: Group;
|
|
||||||
public terminalList!: any;
|
|
||||||
public selectedTerminal!: any;
|
|
||||||
public loading: boolean = false;
|
|
||||||
public currentPage: number = 0;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public dialogService: DialogService,
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
public cartService: CartService,
|
|
||||||
private router: Router,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
private _bottomSheet: MatBottomSheet,
|
|
||||||
private _getTerminals: GetTerminalsService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async ngOnInit() {
|
|
||||||
this.loading = true;
|
|
||||||
await this.getTerminalList();
|
|
||||||
this.getData();
|
|
||||||
// this.messageService.add({
|
|
||||||
// severity: 'info',
|
|
||||||
// summary: 'В одном заказе могут быть товары только из выбранного пункта выдачи',
|
|
||||||
// life: 5000
|
|
||||||
// });
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTerminalList() {
|
|
||||||
const _getTerminals = await this._getTerminals.getTerminalList()
|
|
||||||
this.terminalList = _getTerminals.list
|
|
||||||
this.selectedTerminal = _getTerminals.active
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
this.wpJsonService
|
|
||||||
.getAllData(`${this.selectedTerminal.label}${this.selectedTerminal.id}`)
|
|
||||||
.subscribe({
|
|
||||||
next: (value) => {
|
|
||||||
this.products = value.products;
|
|
||||||
this.groups = value.groups;
|
|
||||||
this.groups.unshift({
|
|
||||||
id: uuidv4(),
|
|
||||||
label: 'Все',
|
|
||||||
});
|
|
||||||
this.selectedGroup = this.groups[0];
|
|
||||||
this.modifiersGroups = value.modifiers_groups;
|
|
||||||
this.modifiers = value.modifiers;
|
|
||||||
|
|
||||||
this.route.queryParams.subscribe((params) => {
|
|
||||||
if (params['group']) {
|
|
||||||
this.selectedGroup =
|
|
||||||
this.groups.find((group) => group.label === params['group']) ||
|
|
||||||
this.groups[0];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onPageChange(event: any) {
|
|
||||||
this.currentPage = event.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
filterByGroup(group?: Group) {
|
|
||||||
if (!this.selectedGroup) return [];
|
|
||||||
if (this.selectedGroup.label === 'Все') {
|
|
||||||
if (group)
|
|
||||||
return JSON.parse(
|
|
||||||
JSON.stringify(
|
|
||||||
this.products.filter((product) => product.groupId === group.id)
|
|
||||||
)
|
|
||||||
).slice(0, 4);
|
|
||||||
return this.products;
|
|
||||||
}
|
|
||||||
return JSON.parse(
|
|
||||||
JSON.stringify(
|
|
||||||
this.products.filter(
|
|
||||||
(product) => product.groupId === this.selectedGroup.id
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
cropList(list: Array<any>, quantity: number) {
|
|
||||||
return list.slice(this.currentPage, this.currentPage + quantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
addToCart(event: MouseEvent, product: Product) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
const productModalWidth = product.modifiers_group.length ? '94vw' : '50vw';
|
|
||||||
const productModalMaxWidth = product.modifiers_group.length
|
|
||||||
? '1400px'
|
|
||||||
: '500px';
|
|
||||||
const ref = this.dialogService.open(ProductModalComponent, {
|
|
||||||
header: product.name,
|
|
||||||
width: 'fit-content',
|
|
||||||
style: {
|
|
||||||
'max-width': productModalMaxWidth,
|
|
||||||
'min-width': '300px',
|
|
||||||
'max-height': '90vh',
|
|
||||||
'border-radius': '1.125rem',
|
|
||||||
width: productModalWidth,
|
|
||||||
},
|
|
||||||
contentStyle: {
|
|
||||||
'max-height': '90vh',
|
|
||||||
height: 'auto',
|
|
||||||
overflow: 'auto',
|
|
||||||
},
|
|
||||||
styleClass: 'product-modal-view',
|
|
||||||
data: {
|
|
||||||
product: product,
|
|
||||||
modifiersGroups: this.modifiersGroups,
|
|
||||||
modifiers: this.modifiers,
|
|
||||||
selectedTerminal: this.selectedTerminal
|
|
||||||
},
|
|
||||||
baseZIndex: 10000,
|
|
||||||
autoZIndex: true,
|
|
||||||
dismissableMask: true,
|
|
||||||
closeOnEscape: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showTerminals() {
|
|
||||||
const bottomSheet = this._bottomSheet.open(TerminalListComponent, {
|
|
||||||
data: {
|
|
||||||
list: this.terminalList,
|
|
||||||
active: this.selectedTerminal,
|
|
||||||
},
|
|
||||||
ariaLabel: 'Список точек',
|
|
||||||
});
|
|
||||||
bottomSheet.afterDismissed().subscribe((selectedTerminal) => {
|
|
||||||
if (!selectedTerminal) return;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.products.length = 0;
|
|
||||||
this.loading = true;
|
|
||||||
this.selectedTerminal = selectedTerminal;
|
|
||||||
this.getData();
|
|
||||||
this.cartService.changeTerminal(this.selectedTerminal);
|
|
||||||
this.loading = false;
|
|
||||||
this.router.navigate([]);
|
|
||||||
this.currentPage = 0;
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
changeGroup(group: Group) {
|
|
||||||
this.selectedGroup = group;
|
|
||||||
this.router.navigate([], {
|
|
||||||
queryParams: {
|
|
||||||
group: group.label,
|
|
||||||
},
|
|
||||||
queryParamsHandling: 'merge',
|
|
||||||
});
|
|
||||||
this.currentPage = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
trackProducts(index: number, product: Product) {
|
|
||||||
return product.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { environment } from 'src/environments/environment';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class AppleWalletService {
|
|
||||||
private url: string = environment.appleWalletEndpoint;
|
|
||||||
constructor(
|
|
||||||
private http: HttpClient,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
generateCard(token: string, user_id: string) {
|
|
||||||
let headers = new HttpHeaders();
|
|
||||||
headers = headers.set('Authorization', environment.appleWalletSecret);
|
|
||||||
const options = {
|
|
||||||
headers: headers,
|
|
||||||
};
|
|
||||||
return this.http.get(`${this.url}/client/${environment.clientName}/passUrl/${user_id}/token/${token}`, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadCard(user_id:string) {
|
|
||||||
let headers = new HttpHeaders();
|
|
||||||
headers = headers.set('Authorization', environment.appleWalletSecret);
|
|
||||||
const options = {
|
|
||||||
headers: headers,
|
|
||||||
};
|
|
||||||
const body = {
|
|
||||||
text: '',
|
|
||||||
isUpdateCard: true
|
|
||||||
}
|
|
||||||
return this.http.post(`${this.url}/sendNotification/${user_id}`, body, options)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
|
||||||
import {map} from "rxjs/operators";
|
|
||||||
import {lastValueFrom, Observable} from "rxjs";
|
|
||||||
|
|
||||||
enum CompleteType {
|
|
||||||
city,
|
|
||||||
street,
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class AutocompleteService {
|
|
||||||
|
|
||||||
private city!: string;
|
|
||||||
private cityId!: string;
|
|
||||||
private query?: string
|
|
||||||
private streets: string[] = [];
|
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
|
||||||
}
|
|
||||||
|
|
||||||
async setCity(city: string | null): Promise<boolean> {
|
|
||||||
if (city && this.city != city) {
|
|
||||||
this.city = city;
|
|
||||||
let headers = new HttpHeaders();
|
|
||||||
const cityData = await lastValueFrom(
|
|
||||||
this._request(`query=${city}&contentType=city`)
|
|
||||||
.pipe(
|
|
||||||
map(
|
|
||||||
(res: any) => res.result.filter(
|
|
||||||
(city: any) => city.id != 'Free'
|
|
||||||
)[0]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
this.cityId = cityData.id;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async queryStreet(query: string, city: string | null = null): Promise<string[]> {
|
|
||||||
let headers = new HttpHeaders();
|
|
||||||
headers = headers.set('Content-Type', 'application/json');
|
|
||||||
let newCityId = await this.setCity(city);
|
|
||||||
if (!this.cityId) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (!this.query || this.query !== query || newCityId) {
|
|
||||||
this.query = query;
|
|
||||||
this.streets = await lastValueFrom(
|
|
||||||
this._request(`query=${query}&offset=0&limit=20&cityId=${this.cityId}&contentType=street`)
|
|
||||||
.pipe(
|
|
||||||
map(
|
|
||||||
(res: any) => res.result
|
|
||||||
.filter(
|
|
||||||
(street: any) => street.id != 'Free'
|
|
||||||
)
|
|
||||||
.map(
|
|
||||||
(street: any) => street.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.streets;
|
|
||||||
}
|
|
||||||
|
|
||||||
//jsonp запрос для обхода cors кладра
|
|
||||||
_request(params: String): Observable<any> {
|
|
||||||
const src = '//kladr-api.ru/api.php?';
|
|
||||||
return this.http.jsonp(src + params, 'callback');
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { CookiesService } from "./cookies.service";
|
|
||||||
import { Cart } from "../interface/data";
|
|
||||||
import { isEqual } from 'lodash/fp';
|
|
||||||
import { CartProduct } from "../models/cart-product";
|
|
||||||
import { Subject } from "rxjs";
|
|
||||||
import { update } from 'lodash';
|
|
||||||
import { WpJsonService } from './wp-json.service';
|
|
||||||
|
|
||||||
export enum ProductAmountAction {
|
|
||||||
increment,
|
|
||||||
decrement,
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class CartService {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private cookieService: CookiesService,
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
private cart!: Cart;
|
|
||||||
|
|
||||||
public cartCount$ = new Subject<number>();
|
|
||||||
|
|
||||||
public selectedTerminal$ = new Subject<Object>();
|
|
||||||
|
|
||||||
|
|
||||||
getCart() {
|
|
||||||
return this._getCartProducts();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
addToCart(product: CartProduct): void {
|
|
||||||
const cart = this._getCartProducts();
|
|
||||||
cart.products = cart.products ?? [];
|
|
||||||
const sameProduct = cart.products.find((value) => value.id === product.id && isEqual(value.modifiers, product.modifiers));
|
|
||||||
if (sameProduct) {
|
|
||||||
sameProduct.amount++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cart.products.push(product);
|
|
||||||
this.cartCount$.next(cart.products.length);
|
|
||||||
}
|
|
||||||
localStorage.setItem('cart', JSON.stringify(cart));
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFromCart(guid: string): void {
|
|
||||||
const cart = this._getCartProducts();
|
|
||||||
if (!cart.products) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cart.products = cart.products.filter((value) => value.guid !== guid);
|
|
||||||
localStorage.setItem('cart', JSON.stringify(cart));
|
|
||||||
this.cartCount$.next(cart.products.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProductFromCart(product: CartProduct): void {
|
|
||||||
// const cart = this._getCartProducts();
|
|
||||||
// if(!cart.products){
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// const updateProduct = cart.products.find((value) => Number(value.id) === product.id)
|
|
||||||
// if (updateProduct) {
|
|
||||||
// updateProduct.modifiers = JSON.parse(JSON.stringify(product.modifiers))
|
|
||||||
// }
|
|
||||||
// localStorage.setItem('cart', JSON.stringify(cart));
|
|
||||||
}
|
|
||||||
|
|
||||||
changeAmountProduct(productTempId: string, action: ProductAmountAction): void {
|
|
||||||
const cart = this._getCartProducts();
|
|
||||||
if (!cart.products) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const product: CartProduct | undefined = cart.products.find((value) => value.guid === productTempId);
|
|
||||||
if (product && action === ProductAmountAction.increment) {
|
|
||||||
product.amount++
|
|
||||||
// product.increment();
|
|
||||||
}
|
|
||||||
else if (product && action === ProductAmountAction.decrement) {
|
|
||||||
product.amount--
|
|
||||||
// product.decrement();
|
|
||||||
}
|
|
||||||
localStorage.setItem('cart', JSON.stringify(cart));
|
|
||||||
this.cartCount$.next(cart.products.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeTerminal(terminal: any) {
|
|
||||||
if (this.cartCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.cookieService.setCookie('selectedTerminal', JSON.stringify(terminal));
|
|
||||||
this.selectedTerminal$.next(terminal)
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCart() {
|
|
||||||
this.cart = { products: [] };
|
|
||||||
localStorage.setItem('cart', JSON.stringify(this.cart));
|
|
||||||
this.cartCount$.next(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
_getCartProducts(): Cart {
|
|
||||||
if (this.cart) {
|
|
||||||
return this.cart;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cartJson = localStorage.getItem('cart');
|
|
||||||
this.cart = cartJson ? JSON.parse(cartJson) : { products: [] };
|
|
||||||
return this.cart;
|
|
||||||
}
|
|
||||||
|
|
||||||
get cartCount(): number {
|
|
||||||
return this._getCartProducts().products.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { NativeDateAdapter } from '@angular/material/core';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class DateAdapterService extends NativeDateAdapter {
|
|
||||||
override format(date: Date, displayFormat: Object): string {
|
|
||||||
if (displayFormat === 'input') {
|
|
||||||
let day: string = date.getDate().toString();
|
|
||||||
day = +day < 10 ? '0' + day : day;
|
|
||||||
let month: string = (date.getMonth() + 1).toString();
|
|
||||||
month = +month < 10 ? '0' + month : month;
|
|
||||||
let year = date.getFullYear();
|
|
||||||
return `${day}.${month}.${year}`;
|
|
||||||
}
|
|
||||||
return date.toLocaleDateString('ru-RU');
|
|
||||||
}
|
|
||||||
|
|
||||||
override getFirstDayOfWeek(): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { lastValueFrom } from 'rxjs';
|
|
||||||
import { ITerminal } from '../interface/data';
|
|
||||||
import { CartService } from './cart.service';
|
|
||||||
import { CookiesService } from './cookies.service';
|
|
||||||
import { WpJsonService } from './wp-json.service';
|
|
||||||
|
|
||||||
export interface IGetTerminalList {
|
|
||||||
list: ITerminal[];
|
|
||||||
active: ITerminal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class GetTerminalsService {
|
|
||||||
public terminalList!: ITerminal[];
|
|
||||||
public selectedTerminal!: ITerminal;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
public cartService: CartService,
|
|
||||||
private cookiesService: CookiesService,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
async getTerminalList(): Promise<IGetTerminalList> {
|
|
||||||
const terminalList = await lastValueFrom(
|
|
||||||
this.wpJsonService.getTerminalList()
|
|
||||||
);
|
|
||||||
this.terminalList = this.toTreeJson(
|
|
||||||
this.keyValue(terminalList),
|
|
||||||
terminalList
|
|
||||||
);
|
|
||||||
const terminalFromCookie = JSON.parse(
|
|
||||||
this.cookiesService.getItem('selectedTerminal') || 'null'
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionDelete = this.terminalList.find(
|
|
||||||
(terminal: any) =>
|
|
||||||
JSON.stringify(terminal) === JSON.stringify(terminalFromCookie)
|
|
||||||
);
|
|
||||||
if (!conditionDelete) {
|
|
||||||
this.cookiesService.deleteCookie('selectedTerminal');
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedTerminal = terminalFromCookie
|
|
||||||
? this.terminalList.find(
|
|
||||||
(value: any) => value.id === terminalFromCookie.id
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
if (!selectedTerminal) {
|
|
||||||
this.cartService.clearCart();
|
|
||||||
}
|
|
||||||
this.selectedTerminal = selectedTerminal || this.terminalList[0];
|
|
||||||
this.cartService.changeTerminal(this.selectedTerminal);
|
|
||||||
return {
|
|
||||||
list: this.terminalList,
|
|
||||||
active: this.selectedTerminal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toTreeJson(array: Array<string>, terminalList: any): Array<ITerminal> {
|
|
||||||
let treeJson: ITerminal[] = [];
|
|
||||||
for (const key of array) {
|
|
||||||
treeJson.push({
|
|
||||||
label: key,
|
|
||||||
id: terminalList[key],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return treeJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
keyValue(obj: Object) {
|
|
||||||
return Object.keys(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,188 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { CartService } from './cart.service';
|
|
||||||
import { WpJsonService } from './wp-json.service';
|
|
||||||
import { forkJoin, lastValueFrom, Observable, tap } from 'rxjs';
|
|
||||||
import {
|
|
||||||
Cart,
|
|
||||||
DeliveryData,
|
|
||||||
DeliveryType,
|
|
||||||
Modifier,
|
|
||||||
Product,
|
|
||||||
UserData,
|
|
||||||
} from '../interface/data';
|
|
||||||
import { Order } from '../models/order';
|
|
||||||
import { OrderProduct } from '../models/order-product';
|
|
||||||
import { JsonrpcService, RpcService } from './jsonrpc.service';
|
|
||||||
import { CookiesService } from './cookies.service';
|
|
||||||
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',
|
|
||||||
})
|
|
||||||
export class OrderService {
|
|
||||||
private order!: Order;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private cartService: CartService,
|
|
||||||
private wpJsonService: WpJsonService,
|
|
||||||
private jsonRpcService: JsonrpcService,
|
|
||||||
private cookiesService: CookiesService,
|
|
||||||
private messageService: MessageService,
|
|
||||||
private store: Store
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async getDeliveryTypes(): Promise<DeliveryType[]> {
|
|
||||||
return await lastValueFrom(this.wpJsonService.getDeliveryTypes());
|
|
||||||
}
|
|
||||||
|
|
||||||
async getOrder(refresh = false): Promise<Order> {
|
|
||||||
if (!this.order || refresh) {
|
|
||||||
const cart = this.cartService.getCart();
|
|
||||||
|
|
||||||
if (cart.products.length) {
|
|
||||||
const token = this.cookiesService.getItem('token') || '';
|
|
||||||
const products = await this.getProducts(cart);
|
|
||||||
// const additionalInfo = this.jsonRpcService.rpc(
|
|
||||||
// {
|
|
||||||
// method: 'getAdditionalInfo',
|
|
||||||
// params: [],
|
|
||||||
// },
|
|
||||||
// RpcService.authService,
|
|
||||||
// true
|
|
||||||
// );
|
|
||||||
const terminal =
|
|
||||||
JSON.parse(
|
|
||||||
this.cookiesService.getItem('selectedTerminal') || 'null'
|
|
||||||
) || this.cartService.selectedTerminal$;
|
|
||||||
if (!token.length) {
|
|
||||||
this.order = new Order({
|
|
||||||
products: products,
|
|
||||||
userData: null,
|
|
||||||
phone: '',
|
|
||||||
token: token,
|
|
||||||
terminal_id: terminal.id,
|
|
||||||
});
|
|
||||||
return this.order;
|
|
||||||
}
|
|
||||||
this.store.dispatch(ProfileActions.getProfile())
|
|
||||||
const additionalInfo = this.store.select(selectCustomerInfo);
|
|
||||||
|
|
||||||
const tokenData = this.jsonRpcService.rpc(
|
|
||||||
{
|
|
||||||
method: 'getTokenData',
|
|
||||||
params: [this.cookiesService.getItem('token')],
|
|
||||||
},
|
|
||||||
RpcService.authService,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
const info = await lastValueFrom(
|
|
||||||
forkJoin([tokenData, products])
|
|
||||||
);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.order;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getProducts(cart: Cart): Promise<OrderProduct[]> {
|
|
||||||
const terminal = JSON.parse(
|
|
||||||
this.cookiesService.getItem('selectedTerminal') || 'null'
|
|
||||||
);
|
|
||||||
const products: OrderProduct[] = [];
|
|
||||||
if (!terminal) {
|
|
||||||
return products;
|
|
||||||
}
|
|
||||||
const allData = await lastValueFrom(
|
|
||||||
this.wpJsonService.getAllData(`${terminal.label}${terminal.id}`)
|
|
||||||
);
|
|
||||||
for (let i = 0; i < cart.products.length; i++) {
|
|
||||||
const productSub = allData.products.find(
|
|
||||||
(product: any) => product.id === cart.products[i].id
|
|
||||||
);
|
|
||||||
if (!productSub) {
|
|
||||||
this.cartService.removeFromCart(cart.products[i].guid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const product = Object.assign(cloneDeep(cart.products[i]), {
|
|
||||||
category_id: 0,
|
|
||||||
price: productSub.price,
|
|
||||||
currency_symbol: '₽',
|
|
||||||
description: '',
|
|
||||||
short_description: '',
|
|
||||||
image_gallery: [],
|
|
||||||
image: productSub.image,
|
|
||||||
modifier_data: cart.products[i].modifiers,
|
|
||||||
stock_status: 'instock',
|
|
||||||
groupId: productSub.groupId,
|
|
||||||
modifiers_group: productSub.modifiers_group,
|
|
||||||
});
|
|
||||||
const orderProduct: OrderProduct = new OrderProduct(
|
|
||||||
product,
|
|
||||||
cart.products[i].guid,
|
|
||||||
cart.products[i].amount
|
|
||||||
);
|
|
||||||
products.push(orderProduct);
|
|
||||||
}
|
|
||||||
return products;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFromCart(productGuid: string): void {
|
|
||||||
this.order.products = this.order.products.filter(
|
|
||||||
(value) => value.guid !== productGuid
|
|
||||||
);
|
|
||||||
this.cartService.removeFromCart(productGuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
setUserData(userData: UserData): void {
|
|
||||||
this.order.userData = userData;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDeliveryData(deliveryData: DeliveryData): void {
|
|
||||||
this.order.deliveryData = deliveryData;
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(): Observable<any> {
|
|
||||||
return this.wpJsonService
|
|
||||||
.createOrder(this.order.toJson(), `${environment.webhookItRetail}handlers/tillda/115eaf95-bb44-4cfc-851a-fec5325b45ff`)
|
|
||||||
.pipe(
|
|
||||||
tap({
|
|
||||||
next: (_) => {
|
|
||||||
// this.jsonRpcService
|
|
||||||
// .rpc(
|
|
||||||
// {
|
|
||||||
// method: 'updateAdditionalInfo',
|
|
||||||
// params: [this.order.userData, this.order.deliveryData],
|
|
||||||
// },
|
|
||||||
// RpcService.authService,
|
|
||||||
// true
|
|
||||||
// )
|
|
||||||
// .subscribe();
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import {environment} from "../../environments/environment";
|
|
||||||
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
|
||||||
import {CookiesService} from "./cookies.service";
|
|
||||||
import {Observable} from "rxjs";
|
|
||||||
import {JsonRpcBody} from "./jsonrpc.service";
|
|
||||||
import {DeliveryType, AcceptedOrder, Product} from "../interface/data";
|
|
||||||
import {ActivatedRoute} from "@angular/router";
|
|
||||||
import {Order} from "../models/order";
|
|
||||||
|
|
||||||
export enum Method {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class WpJsonService {
|
|
||||||
|
|
||||||
protected readonly api = environment.defaultUrl;
|
|
||||||
private body!: JsonRpcBody;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private http: HttpClient,
|
|
||||||
private cookiesService: CookiesService,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
getDeliveryTypes(): Observable<DeliveryType[]>{
|
|
||||||
return this._request('orders/delivery-types', 'GET');
|
|
||||||
}
|
|
||||||
|
|
||||||
createOrder(order: any, url: string){
|
|
||||||
return this._request('', 'POST', order, false, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
getOrders(): Observable<AcceptedOrder[]>{
|
|
||||||
return this._request('orders', 'GET', null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
getProductById(id: number): Observable<Product>{
|
|
||||||
return this._request(`products/${id}`, 'GET');
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllData(fileName: string): Observable<any> {
|
|
||||||
return this._request(`/static/${fileName}.json`, 'GET')
|
|
||||||
}
|
|
||||||
|
|
||||||
getTerminalList(): Observable<any> {
|
|
||||||
return this._request('/static/terminal_list.json', 'GET')
|
|
||||||
}
|
|
||||||
|
|
||||||
getCustomerInfo(systemId: string, token: string, url: string): Observable<any> {
|
|
||||||
return this._request(`customer_info/${systemId}/${token}/`, 'GET', null, false, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactions(systemId: string, token: string, url: string, delta: number): Observable<any> {
|
|
||||||
return this._request(`trans/${systemId}/${token}/`, 'GET', null, false, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionsBetween(systemId: string, token: string, url: string, body: {date_from: string, date_to: string}): Observable<any> {
|
|
||||||
return this._request(`trans/${systemId}/${token}/`, 'POST', body, false, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransactionsInfo(systemId: string, token: string, url: string, delta: number): Observable<any> {
|
|
||||||
return this._request(`purchase/${systemId}/${token}/`, 'GET', null, false, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
getSiteConfig(): Observable<any> {
|
|
||||||
return this._request(`/assets/site-config.json`, 'GET', null, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
getSiteConfigFromIiko(): Observable<any> {
|
|
||||||
return this._request(`/static/settings.json`, 'GET', null, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserOrders(url: string): Observable<any> {
|
|
||||||
return this._request(`/api/user/orders`, 'GET', null, true, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
_request(path: string, method: string, body?: any, auth = false, baseUrl?: string): Observable<any> {
|
|
||||||
const token = decodeURI(this.cookiesService.getItem('token') ?? '');
|
|
||||||
let headers = new HttpHeaders();
|
|
||||||
headers = headers.set('Content-Type', 'application/json');
|
|
||||||
let urlToken = '';
|
|
||||||
if (token && token !== 'undefined' && auth) {
|
|
||||||
headers = headers.set('Authorization', `Bearer ${token}`)
|
|
||||||
urlToken = '?token=' + token;
|
|
||||||
}
|
|
||||||
this.body = body;
|
|
||||||
const options = {
|
|
||||||
headers: headers,
|
|
||||||
body: this.body,
|
|
||||||
};
|
|
||||||
|
|
||||||
let url = environment.production ? window.location.origin + '/' : this.api
|
|
||||||
if (baseUrl) {
|
|
||||||
url = baseUrl
|
|
||||||
}
|
|
||||||
return this.http
|
|
||||||
.request( method, url + path + urlToken, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { createAction, props } from '@ngrx/store';
|
|
||||||
|
|
||||||
export const getConfig = createAction('[Config] Get');
|
|
||||||
|
|
||||||
export const getSuccess = createAction(
|
|
||||||
'[Config] Get Success',
|
|
||||||
props<{ getSuccessResponse: any }>()
|
|
||||||
);
|
|
||||||
|
|
||||||
export const getFailure = createAction(
|
|
||||||
'[Config] Get Failure',
|
|
||||||
props<{ error: string }>()
|
|
||||||
);
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user