Compare commits

..

No commits in common. "sakura" and "master" have entirely different histories.

228 changed files with 1412 additions and 7858 deletions

58
.gitignore vendored
View File

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

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

View File

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

View File

@ -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": []

View File

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

View File

@ -1,5 +0,0 @@
<app-navbar></app-navbar>
<p-toast position="top-center"></p-toast>
<div class="layout">
<router-outlet></router-outlet>
</div>

View File

@ -1,5 +0,0 @@
:host {
.layout {
padding: 0 16px 16px;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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: 'Вы уверены, что хотите выйти?' });
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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