parent
b5fd880379
commit
aea275e705
@ -1,4 +1,4 @@
|
|||||||
import {MainPageCode, OrderStatus, Page, PageCode} from "./interface/data";
|
import {MainPageCode, OrderStatus, Page, PageCode, PaymentMethod} from "./interface/data";
|
||||||
|
|
||||||
export const PageList: Page[] = [
|
export const PageList: Page[] = [
|
||||||
{
|
{
|
||||||
@ -85,4 +85,15 @@ export const orderStatuses: OrderStatus = {
|
|||||||
'OnWay': 'В пути',
|
'OnWay': 'В пути',
|
||||||
'Delivered': 'Выполнен',
|
'Delivered': 'Выполнен',
|
||||||
'Closed': 'Выполнен',
|
'Closed': 'Выполнен',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const paymentMethods: PaymentMethod[] = [
|
||||||
|
{
|
||||||
|
type: 'Card',
|
||||||
|
label: 'Безналичный расчет'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Cash',
|
||||||
|
label: 'Наличными'
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -38,6 +38,10 @@ import { CartComponent } from './pages/cart/cart.component';
|
|||||||
import {ListboxModule} from 'primeng/listbox';
|
import {ListboxModule} from 'primeng/listbox';
|
||||||
import { ProductModalComponent } from './components/product-modal/product-modal.component';
|
import { ProductModalComponent } from './components/product-modal/product-modal.component';
|
||||||
import { CheckboxGroupComponent } from './components/checkbox-group/checkbox-group.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';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -58,7 +62,8 @@ import { CheckboxGroupComponent } from './components/checkbox-group/checkbox-gro
|
|||||||
ProductsComponent,
|
ProductsComponent,
|
||||||
CartComponent,
|
CartComponent,
|
||||||
ProductModalComponent,
|
ProductModalComponent,
|
||||||
CheckboxGroupComponent
|
CheckboxGroupComponent,
|
||||||
|
UserDataOrderComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -91,7 +96,10 @@ import { CheckboxGroupComponent } from './components/checkbox-group/checkbox-gro
|
|||||||
debug: true
|
debug: true
|
||||||
}),
|
}),
|
||||||
ShareIconsModule,
|
ShareIconsModule,
|
||||||
ListboxModule
|
ListboxModule,
|
||||||
|
TreeSelectModule,
|
||||||
|
DropdownModule,
|
||||||
|
SelectButtonModule
|
||||||
],
|
],
|
||||||
providers: [DialogService, MessageService, MessagingService ],
|
providers: [DialogService, MessageService, MessagingService ],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
<div *ngIf="mainFormGroup && !loading; else loadingEl" class="woocommerce-shipping-fields__field-wrapper">
|
||||||
|
<form (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>
|
||||||
|
<p *ngIf="deliverData.deliveryType?.title === 'Доставка'" сlass="form-row form-row-wide">
|
||||||
|
<input formControlName="street" id="street" pInputText placeholder="Улица" type="text">
|
||||||
|
</p>
|
||||||
|
<p *ngIf="deliverData.deliveryType?.title === 'Доставка'" сlass="form-row form-row-first">
|
||||||
|
<input formControlName="house" id="house" pInputText placeholder="Номер дома" type="text">
|
||||||
|
</p>
|
||||||
|
<p *ngIf="deliverData.deliveryType?.title === 'Доставка'" сlass="form-row form-row-last">
|
||||||
|
<input formControlName="flat" id="flat" pInputText placeholder="Квартира" type="number" min="1">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div formGroupName="deliveryDataForm">
|
||||||
|
<p сlass="form-row form-row-wide">
|
||||||
|
<p-dropdown [options]="deliveryTypes" formControlName="deliveryType" placeholder="Доставка"
|
||||||
|
optionLabel="title" (onChange)="changeDeliveryType($event)"></p-dropdown>
|
||||||
|
</p>
|
||||||
|
<p сlass="form-row form-row-wide">
|
||||||
|
<p-selectButton [options]="paymentMethods" formControlName="paymentMethod" optionLabel="label">
|
||||||
|
</p-selectButton>
|
||||||
|
</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>
|
||||||
|
<button [disabled]="!mainFormGroup.valid" class="elementor-button elementor-button--checkout elementor-size-md"
|
||||||
|
(click)="submit()">
|
||||||
|
<span class="elementor-button-text">Оформить заказ</span>
|
||||||
|
</button>
|
||||||
|
<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>
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
:host {
|
||||||
|
.woocommerce-shipping-fields__field-wrapper {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.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 .15s, border-color .15s, box-shadow .15s;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 .15s, border-color .15s, box-shadow .15s;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
&>button {
|
||||||
|
background-color: #09467f;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: calc(100% - 66px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,200 @@
|
|||||||
|
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { DeliveryData, DeliveryType, 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 { HttpClientModule } from '@angular/common/http';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-user-data-order',
|
||||||
|
templateUrl: './user-data-order.component.html',
|
||||||
|
styleUrls: ['./user-data-order.component.scss']
|
||||||
|
})
|
||||||
|
export class UserDataOrderComponent implements OnInit {
|
||||||
|
|
||||||
|
@Output() orderSubmitted = new EventEmitter<void>();
|
||||||
|
readonly cities = environment.cities;
|
||||||
|
readonly paymentMethods = paymentMethods;
|
||||||
|
public loading = false;
|
||||||
|
public hasError = false;
|
||||||
|
public mainFormGroup!: FormGroup;
|
||||||
|
public deliveryTypes: DeliveryType[] = [];
|
||||||
|
public minDate!: Date;
|
||||||
|
public new_street!: string | null;
|
||||||
|
public street!: string;
|
||||||
|
public new_house!: string | null;
|
||||||
|
public checkAddress: boolean = true;
|
||||||
|
public showMyMessage: boolean = false;
|
||||||
|
|
||||||
|
public userData: UserData = {
|
||||||
|
first_name: null,
|
||||||
|
last_name: null,
|
||||||
|
street: null,
|
||||||
|
house: null,
|
||||||
|
flat: null,
|
||||||
|
city: this.cities[0],
|
||||||
|
phone: null,
|
||||||
|
};
|
||||||
|
public deliverData: DeliveryData = {
|
||||||
|
deliveryDate: null,
|
||||||
|
deliveryType: null,
|
||||||
|
paymentMethod: paymentMethods[0],
|
||||||
|
comment: '',
|
||||||
|
persons: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private orderService: OrderService,
|
||||||
|
private autoCompleteService: AutocompleteService,
|
||||||
|
private streetValidator: StreetValidator,
|
||||||
|
private cartService: CartService,
|
||||||
|
private messageService: MessageService,
|
||||||
|
private wpJsonService: WpJsonService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.minDate = new Date();
|
||||||
|
this._createMainForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
changeDeliveryType(event: any) {
|
||||||
|
this.deliverData.deliveryType = event.value;
|
||||||
|
if (this.deliverData.deliveryType?.title) {
|
||||||
|
this.changeValidators(this.deliverData.deliveryType.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changeValidators(title: string) {
|
||||||
|
const comment = this.mainFormGroup.controls['deliveryDataForm'].value.comment;
|
||||||
|
const streetValidators = title === 'Доставка' ? [Validators.required, Validators.minLength(2), Validators.maxLength(255),] : []
|
||||||
|
const houseValidators = title === 'Доставка' ? [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(mainControls).forEach(controlName => {
|
||||||
|
childGroupControls[controlName].markAsTouched();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.submitOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
submitOrder(): void {
|
||||||
|
this.loading = true;
|
||||||
|
const userData: UserData = this.mainFormGroup.controls['userDataForm'].value;
|
||||||
|
userData.phone = this.userData.phone;
|
||||||
|
this.orderService.setUserData(userData);
|
||||||
|
this.orderService.setDeliveryData(this.mainFormGroup.controls['deliveryDataForm'].value);
|
||||||
|
this.orderService.submit().subscribe({
|
||||||
|
next: (_) => {
|
||||||
|
this.loading = false;
|
||||||
|
this.cartService.clearCart();
|
||||||
|
this.orderSubmitted.next();
|
||||||
|
},
|
||||||
|
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('Erroe: ', e);
|
||||||
|
|
||||||
|
this.messageService.add({
|
||||||
|
severity: 'error',
|
||||||
|
summary: 'Произошла ошибка',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _createUserDataForm(): Promise<FormGroup> {
|
||||||
|
const order = await this.orderService.getOrder(true);
|
||||||
|
this.userData = Object.assign({}, this.userData, order.userData);
|
||||||
|
this.userData.city = this.cities[0];
|
||||||
|
this.userData.phone = order.phone;
|
||||||
|
// await this.autoCompleteService.setCity(this.userData.city);
|
||||||
|
return 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, [Validators.required, Validators.minLength(2), Validators.maxLength(255),]],
|
||||||
|
house: [this.userData.house, [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 = [
|
||||||
|
{
|
||||||
|
"cost": 100,
|
||||||
|
"title": "Доставка",
|
||||||
|
"id": 11,
|
||||||
|
"type": "delivery"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cost": 0,
|
||||||
|
"title": "Самовывоз",
|
||||||
|
"id": 16,
|
||||||
|
"type": "self_delivery"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this.deliverData.deliveryType = this.deliveryTypes[0];
|
||||||
|
return 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: [this.deliverData.comment, [Validators.maxLength(255),]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { CartProduct } from "../models/cart-product";
|
||||||
|
|
||||||
|
|
||||||
export enum PageCode {
|
export enum PageCode {
|
||||||
@ -79,6 +80,7 @@ export interface DeliveryType {
|
|||||||
cost: number;
|
cost: number;
|
||||||
title: string;
|
title: string;
|
||||||
id: number;
|
id: number;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AcceptedOrder {
|
export interface AcceptedOrder {
|
||||||
@ -111,7 +113,7 @@ export interface Product {
|
|||||||
description: string;
|
description: string;
|
||||||
stock_status: string;
|
stock_status: string;
|
||||||
currency_symbol: string;
|
currency_symbol: string;
|
||||||
modifier_data: Modifier[];
|
modifier_data: CartModifier[];
|
||||||
short_description: string;
|
short_description: string;
|
||||||
guid: string;
|
guid: string;
|
||||||
groupId: string;
|
groupId: string;
|
||||||
@ -129,7 +131,7 @@ export interface AllData {
|
|||||||
|
|
||||||
export interface Group {
|
export interface Group {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModifiersGroup {
|
export interface ModifiersGroup {
|
||||||
@ -147,6 +149,7 @@ export interface Modifier {
|
|||||||
id: string,
|
id: string,
|
||||||
name: string,
|
name: string,
|
||||||
groupId: string,
|
groupId: string,
|
||||||
|
price?: number,
|
||||||
restrictions: {
|
restrictions: {
|
||||||
minQuantity: number,
|
minQuantity: number,
|
||||||
maxQuantity: number,
|
maxQuantity: number,
|
||||||
@ -155,6 +158,16 @@ export interface Modifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CartModifier {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
options: Modifier[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Cart {
|
||||||
|
products: CartProduct[];
|
||||||
|
}
|
||||||
|
|
||||||
// export interface Modifier {
|
// export interface Modifier {
|
||||||
// id: number;
|
// id: number;
|
||||||
// name: string;
|
// name: string;
|
||||||
@ -170,9 +183,13 @@ export interface Modifier {
|
|||||||
export interface Option {
|
export interface Option {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
price: string;
|
groupId: string;
|
||||||
prechecked: string;
|
restrictions: {
|
||||||
active?: boolean;
|
minQuantity: number,
|
||||||
|
maxQuantity: number,
|
||||||
|
freeQuantity: number,
|
||||||
|
byDefault: number
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderProduct {
|
export interface OrderProduct {
|
||||||
|
|||||||
44
angular/src/app/models/cart-product.ts
Normal file
44
angular/src/app/models/cart-product.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {CartModifier, Modifier, ModifiersGroup, Option} from "../interface/data";
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export class CartProduct {
|
||||||
|
|
||||||
|
|
||||||
|
constructor(id: string, name: string, modifiers: ModifiersGroup[] = [], options: Modifier[], amount: number = 1) {
|
||||||
|
this.id = id;
|
||||||
|
this.guid = uuidv4();
|
||||||
|
this.amount = amount;
|
||||||
|
this.name = name;
|
||||||
|
this.modifiers = modifiers.map(modifier => ({name: modifier.name, id: modifier.id, options: []}));
|
||||||
|
}
|
||||||
|
|
||||||
|
id: string;
|
||||||
|
guid: string;
|
||||||
|
amount: number;
|
||||||
|
name: string;
|
||||||
|
modifiers: CartModifier[];
|
||||||
|
|
||||||
|
|
||||||
|
increment(): void{
|
||||||
|
this.amount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrement(): void{
|
||||||
|
if (this.amount > 0){
|
||||||
|
this.amount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addOption(modifier: ModifiersGroup, option: Modifier): void{
|
||||||
|
const productModifier = this.modifiers.find(value => value.id === modifier.id);
|
||||||
|
if (productModifier){
|
||||||
|
const optionIndex = productModifier.options.findIndex(value => value.id === option.id);
|
||||||
|
if(optionIndex === -1){
|
||||||
|
productModifier.options.push(option);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
productModifier.options.splice(optionIndex, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import {Modifier, Product} from "../interface/data";
|
import {CartModifier, Modifier, Product} from "../interface/data";
|
||||||
export class OrderProduct implements Product{
|
export class OrderProduct implements Product{
|
||||||
|
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ export class OrderProduct implements Product{
|
|||||||
public id: string;
|
public id: string;
|
||||||
public image_gallery: string[];
|
public image_gallery: string[];
|
||||||
public image: string;
|
public image: string;
|
||||||
public modifier_data: Modifier[];
|
public modifier_data: CartModifier[];
|
||||||
public name: string;
|
public name: string;
|
||||||
public price: number;
|
public price: number;
|
||||||
public stock_status: string;
|
public stock_status: string;
|
||||||
@ -39,29 +39,27 @@ export class OrderProduct implements Product{
|
|||||||
|
|
||||||
|
|
||||||
get finalPrice(): number{
|
get finalPrice(): number{
|
||||||
// const modifiersPrice = this.modifier_data.reduce<number>((previousValue, currentValue) => {
|
const modifiersPrice = this.modifier_data.reduce<number>((previousValue, currentValue) => {
|
||||||
// return previousValue + currentValue.options.reduce<number>((previousOptionValue, currentOptionValue) => {
|
return previousValue + currentValue.options.reduce<number>((previousOptionValue, currentOptionValue) => {
|
||||||
// return previousOptionValue + Number(currentOptionValue.price);
|
return previousOptionValue + Number(currentOptionValue.price ? currentOptionValue.price : 0);
|
||||||
// }, 0);
|
}, 0);
|
||||||
// }, 0);
|
}, 0);
|
||||||
// return (Number(this.price) + modifiersPrice) * this.amount;
|
return (Number(this.price) + modifiersPrice) * this.amount;
|
||||||
return 1
|
|
||||||
new Date()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson(){
|
toJson(){
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
amount: this.amount,
|
amount: this.amount * this.price,
|
||||||
name: this.name,
|
price: this.price,
|
||||||
modifiers: this.modifier_data?.map(modifier => {
|
options: this.modifier_data?.map((modifier) => {
|
||||||
return {
|
return {
|
||||||
id: modifier.id,
|
option: modifier.name,
|
||||||
// options: modifier.options,
|
variant: modifier.options[0]?.name || null
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
quantity: this.amount,
|
||||||
|
name: this.name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import {DeliveryData, UserData} from "../interface/data";
|
|||||||
import {OrderProduct} from "./order-product";
|
import {OrderProduct} from "./order-product";
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import { CookiesService } from "../services/cookies.service";
|
import { CookiesService } from "../services/cookies.service";
|
||||||
|
import { environment } from "src/environments/environment";
|
||||||
|
|
||||||
export interface OrderInfo {
|
export interface OrderInfo {
|
||||||
products: OrderProduct[];
|
products: OrderProduct[];
|
||||||
@ -36,33 +37,23 @@ export class Order {
|
|||||||
toJson(): any {
|
toJson(): any {
|
||||||
const date = moment(this.deliveryData?.deliveryDate ?? Date.now());
|
const date = moment(this.deliveryData?.deliveryDate ?? Date.now());
|
||||||
return {
|
return {
|
||||||
items: this.products.map(product => {
|
formname: "Cart",
|
||||||
return product.toJson();
|
paymentsystem: this.deliveryData?.paymentMethod.type,
|
||||||
}),
|
phone: this.phone,
|
||||||
user_data: {
|
|
||||||
phone: this.phone,
|
|
||||||
...this.userData
|
|
||||||
},
|
|
||||||
payment_method: this.deliveryData?.paymentMethod.type,
|
|
||||||
delivery_time: date.format('HH:mm'),
|
|
||||||
delivery_date: date.format("YYYY-MM-DD"),
|
|
||||||
delivery_instance_id: this.deliveryData?.deliveryType?.id,
|
|
||||||
persons: 1,
|
persons: 1,
|
||||||
payments: [
|
name: "31",
|
||||||
{
|
payment: {
|
||||||
type: this.deliveryData?.paymentMethod.type,
|
delivery_price: 100,
|
||||||
summ: this.price,
|
products: this.products.map(product => {
|
||||||
},
|
return product.toJson();
|
||||||
{
|
}),
|
||||||
type: "crm4retail",
|
delivery_fio: this.userData?.first_name,
|
||||||
summ: 0,
|
subtotal: this.price,
|
||||||
payload: {
|
delivery_comment: this.deliveryData?.comment,
|
||||||
id: "c07a10d8-ba7e-43b0-92aa-ae470060bc7d"
|
delivery: this.deliveryData?.deliveryType?.type,
|
||||||
}
|
delivery_address: `${environment.cities[0]}, ул ${this.userData?.street}, ${this.userData?.house}`,
|
||||||
}
|
amount: this.price + 100
|
||||||
],
|
},
|
||||||
comment: this.deliveryData?.comment,
|
|
||||||
token: this.token
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,12 +7,14 @@
|
|||||||
<ng-container *ngFor="let page of mainPageList; let index = index; let last = last; let first = first;">
|
<ng-container *ngFor="let page of mainPageList; let index = index; let last = last; let first = first;">
|
||||||
<li *ngIf="page.onSideBar" class="main-menu-container__item"
|
<li *ngIf="page.onSideBar" class="main-menu-container__item"
|
||||||
[ngClass]="{
|
[ngClass]="{
|
||||||
|
'cart': page.resName === 'cart',
|
||||||
'is-active': page === currentPageMain
|
'is-active': page === currentPageMain
|
||||||
}"
|
}"
|
||||||
[ngStyle]="{
|
[ngStyle]="{
|
||||||
border: last && 0,
|
border: last && 0,
|
||||||
'border-radius': first ? '6px 0 0 6px' : (last ? '0 6px 6px 0' : 0)
|
'border-radius': first ? '6px 0 0 6px' : (last ? '0 6px 6px 0' : 0)
|
||||||
}"
|
}"
|
||||||
|
[attr.data-counter]="page.resName === 'cart' ? cartCount : null"
|
||||||
(click)="changeMainPage(page, $event)">
|
(click)="changeMainPage(page, $event)">
|
||||||
<span>
|
<span>
|
||||||
{{page.name}}
|
{{page.name}}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
.woocommerce {
|
.woocommerce {
|
||||||
min-height: calc(100vh - 39px);
|
min-height: calc(100vh - 39px);
|
||||||
padding: 20px 18px;
|
padding: 20px 18px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&.auth-page {
|
&.auth-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -13,6 +14,7 @@
|
|||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin: -20px auto 0 auto;
|
margin: -20px auto 0 auto;
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -20,16 +22,36 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-right: solid #e1e1e1 1px;
|
border-right: solid #e1e1e1 1px;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
background: #0d457e;
|
background: #0d457e;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.cart {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: attr(data-counter);
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
right: 3px;
|
||||||
|
top: 1px;
|
||||||
|
background: #D7120B;
|
||||||
|
border-radius: 50px;
|
||||||
|
min-width: 1.2rem;
|
||||||
|
line-height: 1.2rem;
|
||||||
|
font-size: .8rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,6 +140,8 @@
|
|||||||
|
|
||||||
.version {
|
.version {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,6 +10,7 @@ import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
|
|||||||
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
|
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
|
||||||
import { MessageService } from 'primeng/api';
|
import { MessageService } from 'primeng/api';
|
||||||
import { lastValueFrom } from 'rxjs';
|
import { lastValueFrom } from 'rxjs';
|
||||||
|
import { CartService } from 'src/app/services/cart.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-account',
|
selector: 'app-account',
|
||||||
@ -27,7 +28,8 @@ export class AccountComponent implements OnInit {
|
|||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private jsonRpcService: JsonrpcService,
|
private jsonRpcService: JsonrpcService,
|
||||||
private messageService: MessageService
|
private messageService: MessageService,
|
||||||
|
private cartService: CartService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public currentPage!: Page;
|
public currentPage!: Page;
|
||||||
@ -42,7 +44,8 @@ export class AccountComponent implements OnInit {
|
|||||||
|
|
||||||
readonly MainPageCode = MainPageCode;
|
readonly MainPageCode = MainPageCode;
|
||||||
readonly mainPageList = PageListMain;
|
readonly mainPageList = PageListMain;
|
||||||
public currentPageMain: Page = this.mainPageList[0];
|
public currentPageMain: Page = this.mainPageList[environment.production ? 0 : 1];
|
||||||
|
public cartCount = 0;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.getToken()) {
|
if (!this.getToken()) {
|
||||||
@ -62,6 +65,13 @@ export class AccountComponent implements OnInit {
|
|||||||
this.currentPage = currentPage;
|
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())
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
document.body.classList.add(
|
document.body.classList.add(
|
||||||
'woocommerce-account',
|
'woocommerce-account',
|
||||||
|
|||||||
@ -8,6 +8,9 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&>p {
|
&>p {
|
||||||
|
|||||||
@ -1 +1,77 @@
|
|||||||
<p>cart works!</p>
|
<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"
|
||||||
|
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 style="max-width: 160px;" class="variation-">{{option.name}}:</dt>
|
||||||
|
<dd style="display: flex; align-items: flex-end; margin-bottom: 0;" class="variation-"><p>{{product.currency_symbol}}{{option.price ?? 0}}</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>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="order.products.length != 0" class="elementor-menu-cart__bottom-info">
|
||||||
|
<div class="elementor-menu-cart__subtotal">
|
||||||
|
<strong>К оплате: </strong>
|
||||||
|
<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()"></app-user-data-order>
|
||||||
|
|
||||||
|
<div #loadingEl *ngIf="loading">
|
||||||
|
<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>
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
:host {
|
||||||
|
.cart {
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 20px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__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: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__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: .3s;
|
||||||
|
-o-transition: .3s;
|
||||||
|
transition: .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: .3s;
|
||||||
|
-o-transition: .3s;
|
||||||
|
transition: .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: flex-start;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 18px;
|
||||||
|
background: #fff;
|
||||||
|
border-top: solid #d9d9d9 1px;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtotal {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer-buttons {
|
||||||
|
a {
|
||||||
|
padding: 12px;
|
||||||
|
display: block;
|
||||||
|
width: fit-content;
|
||||||
|
background: #09467f;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,8 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
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';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cart',
|
selector: 'app-cart',
|
||||||
@ -6,10 +10,52 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
styleUrls: ['./cart.component.scss']
|
styleUrls: ['./cart.component.scss']
|
||||||
})
|
})
|
||||||
export class CartComponent implements OnInit {
|
export class CartComponent implements OnInit {
|
||||||
|
public loading = false;
|
||||||
|
public orderConfirmed = false;
|
||||||
|
public order!: Order;
|
||||||
|
public price!: number;
|
||||||
|
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private orderService: OrderService,
|
||||||
|
private cartService: CartService
|
||||||
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.loadCart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadCart(): Promise<void> {
|
||||||
|
this.loading = true;
|
||||||
|
this.order = await this.orderService.getOrder(true);
|
||||||
|
if (this.order) this.price = this.order.price
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFromCart(event: Event, guid: string): void{
|
||||||
|
event.preventDefault();
|
||||||
|
this.orderService.removeFromCart(guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmOrder(event: Event): void{
|
||||||
|
event.preventDefault();
|
||||||
|
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() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
77
angular/src/app/services/autocomplete.service.ts
Normal file
77
angular/src/app/services/autocomplete.service.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
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');
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
111
angular/src/app/services/cart.service.ts
Normal file
111
angular/src/app/services/cart.service.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
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>();
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
this.cookieService.setCookie('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);
|
||||||
|
this.cookieService.setCookie('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))
|
||||||
|
// }
|
||||||
|
// this.cookieService.setCookie('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();
|
||||||
|
}
|
||||||
|
this.cookieService.setCookie('cart', JSON.stringify(cart));
|
||||||
|
this.cartCount$.next(cart.products.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCart(){
|
||||||
|
this.cart = {products: []};
|
||||||
|
this.cookieService.setCookie('cart', JSON.stringify(this.cart));
|
||||||
|
this.cartCount$.next(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getCartProducts(): Cart{
|
||||||
|
if(this.cart){
|
||||||
|
return this.cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cartJson = this.cookieService.getItem('cart');
|
||||||
|
this.cart = cartJson ? JSON.parse(cartJson) : {products: []};
|
||||||
|
return this.cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
get cartCount(): number{
|
||||||
|
return this._getCartProducts().products.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
113
angular/src/app/services/order.service.ts
Normal file
113
angular/src/app/services/order.service.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
@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,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
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 products = await this.getProducts(cart);
|
||||||
|
const additionalInfo = this.jsonRpcService.rpc({
|
||||||
|
method: 'getAdditionalInfo',
|
||||||
|
params: []
|
||||||
|
}, RpcService.authService, true);
|
||||||
|
|
||||||
|
const tokenData = this.jsonRpcService.rpc({
|
||||||
|
method: 'getTokenData',
|
||||||
|
params: [this.cookiesService.getItem('token')],
|
||||||
|
}, RpcService.authService, true);
|
||||||
|
|
||||||
|
const info = await lastValueFrom(forkJoin([additionalInfo, tokenData, products]));
|
||||||
|
const token = this.cookiesService.getItem('token')
|
||||||
|
this.order = new Order({products: products, userData: info[0]?.data, phone: info[1].data?.mobile_number, token: token});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.order;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProducts(cart: Cart): Promise<OrderProduct[]> {
|
||||||
|
const allData = await lastValueFrom(this.wpJsonService.getAllData())
|
||||||
|
const products: OrderProduct[] = []
|
||||||
|
for (let i = 0; i < cart.products.length; i++) {
|
||||||
|
const productSub = allData.products.find((product: any) => product.id === cart.products[i].id)
|
||||||
|
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).pipe(
|
||||||
|
tap({
|
||||||
|
next: (_) => {
|
||||||
|
this.jsonRpcService.rpc({
|
||||||
|
method: 'updateAdditionalInfo',
|
||||||
|
params: [this.order.userData, this.order.deliveryData]
|
||||||
|
}, RpcService.authService, true).subscribe();
|
||||||
|
this.messageService.add({
|
||||||
|
severity:'success',
|
||||||
|
summary: 'Заказ создан',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -30,8 +30,8 @@ export class WpJsonService {
|
|||||||
return this._request('orders/delivery-types', 'GET');
|
return this._request('orders/delivery-types', 'GET');
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrder(order: any){
|
createOrder(order: any, url: string){
|
||||||
return this._request('orders', 'POST', order);
|
return this._request('', 'POST', order);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrders(): Observable<AcceptedOrder[]>{
|
getOrders(): Observable<AcceptedOrder[]>{
|
||||||
@ -46,7 +46,7 @@ export class WpJsonService {
|
|||||||
return this._request('static/nomen_1eb3fb56-3c4c-43b7-9a04-ce532ab7548f.json', 'GET')
|
return this._request('static/nomen_1eb3fb56-3c4c-43b7-9a04-ce532ab7548f.json', 'GET')
|
||||||
}
|
}
|
||||||
|
|
||||||
_request(path: string, method: string, body?: any, auth = false): Observable<any> {
|
_request(path: string, method: string, body?: any, auth = false, baseUrl = null): Observable<any> {
|
||||||
const token = decodeURI(this.cookiesService.getItem('token') ?? '');
|
const token = decodeURI(this.cookiesService.getItem('token') ?? '');
|
||||||
let headers = new HttpHeaders();
|
let headers = new HttpHeaders();
|
||||||
headers = headers.set('Content-Type', 'application/json');
|
headers = headers.set('Content-Type', 'application/json');
|
||||||
@ -60,8 +60,10 @@ export class WpJsonService {
|
|||||||
body: this.body,
|
body: this.body,
|
||||||
};
|
};
|
||||||
|
|
||||||
const url = environment.production ? window.location.origin + '/' : this.api
|
let url = environment.production ? window.location.origin + '/' : this.api
|
||||||
|
if (baseUrl) {
|
||||||
|
url = baseUrl
|
||||||
|
}
|
||||||
return this.http
|
return this.http
|
||||||
.request( method, url + path + urlToken, options);
|
.request( method, url + path + urlToken, options);
|
||||||
}
|
}
|
||||||
|
|||||||
25
angular/src/app/validators/street.validator.ts
Normal file
25
angular/src/app/validators/street.validator.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {AbstractControl, ValidationErrors, AsyncValidator} from '@angular/forms';
|
||||||
|
import {AutocompleteService} from "../services/autocomplete.service";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class StreetValidator implements AsyncValidator {
|
||||||
|
constructor(private autocompleteService: AutocompleteService) {}
|
||||||
|
|
||||||
|
async validate(
|
||||||
|
control: AbstractControl
|
||||||
|
): Promise<ValidationErrors | null> {
|
||||||
|
try{
|
||||||
|
const streets = await this.autocompleteService.queryStreet(control.value);
|
||||||
|
if(streets.includes(control.value)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { validStreet: false }
|
||||||
|
}
|
||||||
|
catch (e){
|
||||||
|
return { validStreet: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,5 +20,7 @@ export const environment = {
|
|||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
appleWalletEndpoint: 'https://apple-push-notifications.it-retail.tech/apns/api',
|
appleWalletEndpoint: 'https://apple-push-notifications.it-retail.tech/apns/api',
|
||||||
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
|
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
|
||||||
clientName: 'Sakura'
|
webhookItRetail: 'https://webhook.it-retail.tech/handlers/tillda/1eb3fb56-3c4c-43b7-9a04-ce532ab7548f',
|
||||||
|
clientName: 'Sakura',
|
||||||
|
cities: ['Менделеевск'],
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export const environment = {
|
|||||||
production: false,
|
production: false,
|
||||||
appAuthEndpoint: 'https://auth.crm4retail.ru/tnt',
|
appAuthEndpoint: 'https://auth.crm4retail.ru/tnt',
|
||||||
appBonusEndpoint: 'https://customerapi2.mi.crm4retail.ru/json.rpc/',
|
appBonusEndpoint: 'https://customerapi2.mi.crm4retail.ru/json.rpc/',
|
||||||
appWPEndpoint: './assets/',
|
appWPEndpoint: './',
|
||||||
hasBonusProgram: true,
|
hasBonusProgram: true,
|
||||||
systemId: 'g6zyv8tj53w28ov7cl',
|
systemId: 'g6zyv8tj53w28ov7cl',
|
||||||
defaultUrl: 'http://192.168.0.179:4200',
|
defaultUrl: 'http://192.168.0.179:4200',
|
||||||
@ -20,5 +20,7 @@ export const environment = {
|
|||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
appleWalletEndpoint: 'http://192.168.0.179:4200/apns/api',
|
appleWalletEndpoint: 'http://192.168.0.179:4200/apns/api',
|
||||||
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
|
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
|
||||||
clientName: 'Sakura'
|
webhookItRetail: 'https://webhook.it-retail.tech/handlers/tillda/1eb3fb56-3c4c-43b7-9a04-ce532ab7548f',
|
||||||
|
clientName: 'Sakura',
|
||||||
|
cities: ['Менделеевск'],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,6 +22,29 @@ table{border-collapse:collapse;border-spacing:0}
|
|||||||
border-color: red;
|
border-color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-dropdown {
|
||||||
|
width: 100%;
|
||||||
|
height: 39px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-selectbutton {
|
||||||
|
display: flex;
|
||||||
|
&>.p-button{
|
||||||
|
flex: 1;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-selectbutton .p-button.p-highlight {
|
||||||
|
background: #f9b004;
|
||||||
|
border-color: #f9b004;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-selectbutton .p-button.p-highlight:hover {
|
||||||
|
background: #f9b004;
|
||||||
|
border-color: #f9b004;
|
||||||
|
}
|
||||||
|
|
||||||
mark {
|
mark {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background: #009688;
|
background: #009688;
|
||||||
@ -64,3 +87,16 @@ button {
|
|||||||
input::-webkit-date-and-time-value {
|
input::-webkit-date-and-time-value {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-treeselect {
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tree .p-tree-container .p-treenode {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tree .p-tree-container .p-treenode .p-treenode-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user