припилил СА, iikocard (но пока только customer_info), доработки
This commit is contained in:
gofnnp 2023-04-25 19:10:14 +04:00
parent 1da7556aed
commit af60b55e94
22 changed files with 773 additions and 208 deletions

View File

@ -87,7 +87,8 @@
"browserTarget": "coffee-like:build:production"
},
"development": {
"browserTarget": "coffee-like:build:development"
"browserTarget": "coffee-like:build:development",
"proxyConfig": "proxy.confi.json"
}
},
"defaultConfiguration": "development"

View File

@ -30,7 +30,9 @@
"firebase": "^9.9.3",
"google-libphonenumber": "^3.2.30",
"jsbarcode": "^3.11.5",
"libphonenumber-js": "^1.10.28",
"ng-qrcode": "^7.0.0",
"ngx-mat-intl-tel-input": "^5.0.0",
"ngx-sharebuttons": "^11.0.0",
"primeicons": "^5.0.0",
"primeng": "^14.0.1",
@ -8862,6 +8864,11 @@
"node": ">=0.10.0"
}
},
"node_modules/libphonenumber-js": {
"version": "1.10.28",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.28.tgz",
"integrity": "sha512-1eAgjLrZA0+2Wgw4hs+4Q/kEBycxQo8ZLYnmOvZ3AlM8ImAVAJgDPlZtISLEzD1vunc2q8s2Pn7XwB7I8U3Kzw=="
},
"node_modules/license-webpack-plugin": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz",
@ -9636,6 +9643,22 @@
"@angular/core": ">=14 <15"
}
},
"node_modules/ngx-mat-intl-tel-input": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ngx-mat-intl-tel-input/-/ngx-mat-intl-tel-input-5.0.0.tgz",
"integrity": "sha512-3XwA0zzcxBF/p+BQqBuGxPa7Mi+upehbrR6WvgwWcd+T9NcjImNEAf/Pd8R37OarN3fLrxFq/8g6B2zqYZtBCg==",
"dependencies": {
"tslib": "^2.x"
},
"peerDependencies": {
"@angular/common": ">=14.x",
"@angular/core": ">=14.x",
"@angular/forms": ">=14.x",
"@angular/platform-browser": ">=14.x",
"@angular/platform-browser-dynamic": ">=14.x",
"libphonenumber-js": "^1.10.11"
}
},
"node_modules/ngx-sharebuttons": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/ngx-sharebuttons/-/ngx-sharebuttons-11.0.0.tgz",
@ -20274,6 +20297,11 @@
"klona": "^2.0.4"
}
},
"libphonenumber-js": {
"version": "1.10.28",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.28.tgz",
"integrity": "sha512-1eAgjLrZA0+2Wgw4hs+4Q/kEBycxQo8ZLYnmOvZ3AlM8ImAVAJgDPlZtISLEzD1vunc2q8s2Pn7XwB7I8U3Kzw=="
},
"license-webpack-plugin": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz",
@ -20862,6 +20890,14 @@
"tslib": "^2.4.0"
}
},
"ngx-mat-intl-tel-input": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ngx-mat-intl-tel-input/-/ngx-mat-intl-tel-input-5.0.0.tgz",
"integrity": "sha512-3XwA0zzcxBF/p+BQqBuGxPa7Mi+upehbrR6WvgwWcd+T9NcjImNEAf/Pd8R37OarN3fLrxFq/8g6B2zqYZtBCg==",
"requires": {
"tslib": "^2.x"
}
},
"ngx-sharebuttons": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/ngx-sharebuttons/-/ngx-sharebuttons-11.0.0.tgz",

View File

@ -32,7 +32,9 @@
"firebase": "^9.9.3",
"google-libphonenumber": "^3.2.30",
"jsbarcode": "^3.11.5",
"libphonenumber-js": "^1.10.28",
"ng-qrcode": "^7.0.0",
"ngx-mat-intl-tel-input": "^5.0.0",
"ngx-sharebuttons": "^11.0.0",
"primeicons": "^5.0.0",
"primeng": "^14.0.1",

38
angular/proxy.confi.json Normal file
View File

@ -0,0 +1,38 @@
{
"/api": {
"target": "https://apple-push-notifications.it-retail.tech/apns/api",
"secure": false,
"pathRewrite": {
"^/api": ""
},
"changeOrigin": true,
"logLevel": "debug"
},
"/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"
},
"/it-retail": {
"target": "https://sakura.lk.crm4retail.ru/it-retail",
"secure": false,
"pathRewrite": {
"^/it-retail": ""
},
"changeOrigin": true,
"logLevel": "debug"
}
}

View File

@ -7,9 +7,9 @@ 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 { InputMaskModule } from 'primeng/inputmask';
import { AuthComponent } from './pages/account/auth/auth.component';
import {ProgressSpinnerModule} from "primeng/progressspinner";
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';
@ -23,7 +23,7 @@ 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 { 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';
@ -33,7 +33,7 @@ import { ShareIconsModule } from 'ngx-sharebuttons/icons';
import { MessagingService } from './services/messaging.service';
import { NotFoundComponent } from './pages/not-found/not-found.component';
import { DownloadAppDirective } from './directives/download-app.directive';
import {MatIconModule} from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import { GuestCardComponent } from './pages/guest-card/guest-card.component';
import { QrCodeModule } from 'ng-qrcode';
import { AccordionComponent } from './components/accordion/accordion.component';
@ -42,6 +42,16 @@ import { InviteFriendsComponent } from './components/invite-friends/invite-frien
import { FooterComponent } from './components/footer/footer.component';
import { SocialMediaButtonsComponent } from './components/social-media-buttons/social-media-buttons.component';
import { LoginComponent } from './pages/login/login.component';
import { NgxMatIntlTelInputComponent } from 'ngx-mat-intl-tel-input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { FocusNextInputDirective } from './directives/focus-next-input.directive';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import {
MAT_BOTTOM_SHEET_DATA,
MatBottomSheetModule,
MatBottomSheetRef,
} from '@angular/material/bottom-sheet';
@NgModule({
declarations: [
@ -66,7 +76,8 @@ import { LoginComponent } from './pages/login/login.component';
InviteFriendsComponent,
FooterComponent,
SocialMediaButtonsComponent,
LoginComponent
LoginComponent,
FocusNextInputDirective,
],
imports: [
BrowserModule,
@ -81,20 +92,31 @@ import { LoginComponent } from './pages/login/login.component';
enabled: environment.production,
// Register the ServiceWorker as soon as the application is stable
// or after 30 seconds (whichever comes first).
registrationStrategy: 'registerWhenStable:30000'
registrationStrategy: 'registerWhenStable:30000',
}),
AngularFireModule.initializeApp(environment.firebase),
AngularFireMessagingModule,
ToastModule,
ReactiveFormsModule,
ShareButtonsModule.withConfig({
debug: true
debug: true,
}),
ShareIconsModule,
MatIconModule,
QrCodeModule
QrCodeModule,
NgxMatIntlTelInputComponent,
MatFormFieldModule,
MatInputModule,
MatSnackBarModule,
MatBottomSheetModule,
],
providers: [DialogService, MessageService, MessagingService ],
bootstrap: [AppComponent]
providers: [
DialogService,
MessageService,
MessagingService,
{ provide: MatBottomSheetRef, useValue: {} },
{ provide: MAT_BOTTOM_SHEET_DATA, useValue: {} },
],
bootstrap: [AppComponent],
})
export class AppModule { }
export class AppModule {}

View File

@ -1,13 +1,7 @@
<div>
<H2>Вы действительно хотите выйти?</H2>
<button
class="woocommerce-button button"
style="margin-right: 1rem"
(click)="onClick(true)"
>
Да
</button>
<button class="woocommerce-button button" (click)="onClick(false)">
Нет
</button>
<span class="example-pizza-party" matSnackBarLabel>
Вы действительно хотите выйти?
</span>
<div class="buttons-container">
<button mat-button (click)="rejection()" style="background: red;">Нет</button>
<button mat-button (click)="logout()">Да</button>
</div>

View File

@ -1,9 +1,22 @@
:host {
display: flex;
flex-direction: column;
align-items: center;
.buttons-container {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
}
button {
margin-right: 1rem;
padding: 4px 21px;
padding: 10px 62px;
margin-top: 8px;
background-color: var(--main-color);
color: #fff;
border-radius: 3px;
border: none;
width: calc(50% - 12px);
}

View File

@ -1,19 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { DynamicDialogRef } from 'primeng/dynamicdialog';
import { Component } from '@angular/core';
import { MatBottomSheetRef } from '@angular/material/bottom-sheet';
@Component({
selector: 'app-exit',
templateUrl: './exit.component.html',
styleUrls: ['./exit.component.scss']
styleUrls: ['./exit.component.scss'],
})
export class ExitComponent {
constructor(
public dialogRef: DynamicDialogRef
) { }
private _bottomSheetRef: MatBottomSheetRef<ExitComponent>
) {}
onClick(val: boolean): void {
this.dialogRef.close(val);
rejection() {
this._bottomSheetRef.dismiss(false)
}
logout() {
this._bottomSheetRef.dismiss(true)
}
}

View File

@ -1,5 +1,5 @@
<div class="container">
<mat-icon aria-hidden="false" aria-label="Назад" fontIcon="arrow_back_ios" class="back-arrow"></mat-icon>
<mat-icon aria-hidden="false" aria-label="Назад" fontIcon="arrow_back_ios" class="back-arrow" (click)="back()"></mat-icon>
<h1 class="title">{{title}}</h1>
<div class="plug"></div>
</div>

View File

@ -1,3 +1,7 @@
:host {
width: 100%;
}
.container {
box-sizing: border-box;
padding: 12px 16px;

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
@Component({
selector: 'app-navbar[title]',
@ -7,10 +7,15 @@ import { Component, Input, OnInit } from '@angular/core';
})
export class NavbarComponent implements OnInit {
@Input() title: string = 'Название не задано'
@Output() backEvent = new EventEmitter<null>();
constructor() { }
ngOnInit(): void {
}
back() {
this.backEvent.emit(null)
}
}

View File

@ -0,0 +1,8 @@
import { FocusNextInputDirective } from './focus-next-input.directive';
describe('FocusNextInputDirective', () => {
it('should create an instance', () => {
const directive = new FocusNextInputDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -0,0 +1,23 @@
import { Directive, EventEmitter, Input, Renderer2 } from '@angular/core';
@Directive({
selector: '[appFocusNextInput]'
})
export class FocusNextInputDirective {
@Input('appFocusNextInput') eventEmitter!: EventEmitter<string>;
constructor(private renderer: Renderer2) { }
ngOnInit() {
this.eventEmitter.subscribe(elementId => {
try {
this.renderer.selectRootElement(elementId).focus();
this.renderer.selectRootElement(elementId).click();
} catch (ex) {
(document.activeElement as HTMLElement).blur();
// If the element doesn't exist or if the element disappears when this called then no need to do anything
}
});
}
}

View File

@ -1,20 +1,28 @@
<app-navbar title="Карта гостя"></app-navbar>
<div class="guest-card">
<app-navbar title="Карта гостя" (backEvent)="logout()"></app-navbar>
<ng-container
*ngTemplateOutlet="appTpl; context: { user: customerInfo | async }"
></ng-container>
<ng-template #appTpl let-user="user">
<div class="guest-card">
<div class="guest-card__qr" (click)="qrCodeClick()">
<qr-code
value="9917997225"
[value]="user?.customer_info?.phone.substr(2) || 'Данные не найдены'"
[margin]="0"
[size]="qrCodeSize"
errorCorrectionLevel="M"
></qr-code>
</div>
<div class="guest-card__user-description">
За период с 11.01.2023 по 31.03.2023 вам начислено <span>360 бонусов</span>
За период с 11.01.2023 по 31.03.2023 вам начислено
<span>360 бонусов</span>
</div>
<app-accordion header="Условия начисления бонусов">
<p>
Расчет начисления бонусов - 10% от суммы покупок за период с 11.01.2023г.
по 31.03.2023 г.
Расчет начисления бонусов - 10% от суммы покупок за период с
11.01.2023г. по 31.03.2023 г.
</p>
<p>
За период с 11.01.2023г. по 31.03.2023 г. сумма ваших покупок составила
@ -29,14 +37,14 @@
</p>
<p>
Списание Бонусов происходит из расчета 1:1 (один Бонус дает скидку 1
российский рубль / 1 тенге / 1 белорусский рубль. Скидка, предоставляемая
Участнику при списании Бонусов, уменьшает цену товаров в заказе в
соответствии с условиями ПЛ.
российский рубль / 1 тенге / 1 белорусский рубль. Скидка,
предоставляемая Участнику при списании Бонусов, уменьшает цену товаров в
заказе в соответствии с условиями ПЛ.
</p>
<p>
Для списания Бонусов Участник должен попросить об этом в кофе-баре сети
«COFFEE LIKE» кассира до момента пробития фискального чека, после чего им
будет проверена возможность списания Бонусов.
«COFFEE LIKE» кассира до момента пробития фискального чека, после чего
им будет проверена возможность списания Бонусов.
</p>
<p>
Для всех Участников возможно списание без использования мобильного
@ -66,8 +74,8 @@
Возврат покупки, которая была оплачена бонусами:
<li>
В случае предъявления Участником кассового или товарного чека, сумма
бонусов, списанная для оплаты возвращаемого товара, зачисляется на счет
участника.
бонусов, списанная для оплаты возвращаемого товара, зачисляется на
счет участника.
</li>
<li>
В случае возврата товара с применением оплаты бонусами, клиенту
@ -116,19 +124,30 @@
До следующего уровня за период с 01.04.2023 по 30.06.2023г осталось
совершить покупки на 401 рублей
</h2>
<input type="range" [(ngModel)]="discountLevel" [min]="3" [max]="6" [step]="0.1" [ngStyle]="{
'background-size': (discountLevel - 3) / (6 - 3) * 100 + '% 100%'
}">
<input
type="range"
[(ngModel)]="discountLevel"
[min]="3"
[max]="6"
[step]="0.1"
[ngStyle]="{
'background-size': ((discountLevel - 3) / (6 - 3)) * 100 + '% 100%'
}"
/>
<p class="show-more">Узнать условия начисления бонусов</p>
</div>
<hr>
<hr />
<app-last-order></app-last-order>
<hr>
<hr />
<app-invite-friends></app-invite-friends>
<hr>
<hr />
<div class="guest-card__download-app">
<img src="/assets/download-app.svg" alt="Скачай приложение">
<img src="/assets/download-app.svg" alt="Скачай приложение" />
</div>
<a class="guest-card__loyalty-program" routerLink="loyalty-program">Подробнее о правилах <br> Программы лояльности</a>
</div>
<a class="guest-card__loyalty-program" routerLink="loyalty-program"
>Подробнее о правилах <br />
Программы лояльности</a
>
</div>
</ng-template>

View File

@ -1,5 +1,16 @@
import { Component, OnInit } from '@angular/core';
import { IAccordionData } from 'src/app/components/accordion/accordion.component';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { ExitComponent } from 'src/app/components/exit/exit.component';
import { CookiesService } from 'src/app/services/cookies.service';
import { WpJsonService } from 'src/app/services/wp-json.service';
import { environment } from 'src/environments/environment';
import moment from 'moment';
interface Moment extends moment.Moment {
}
@Component({
selector: 'app-guest-card',
@ -9,15 +20,49 @@ import { IAccordionData } from 'src/app/components/accordion/accordion.component
export class GuestCardComponent implements OnInit {
public qrCodeSize: number = 85;
private isQrCodeClicked: boolean = false;
public customerInfo!: Observable<any>;
public purchases!: Observable<any>;
public discountLevel: number = 4.2;
constructor() {}
constructor(
private _bottomSheet: MatBottomSheet,
private cookiesService: CookiesService,
private router: Router,
private wpJsonService: WpJsonService
) {}
ngOnInit(): void {}
ngOnInit(): void {
const token = this.cookiesService.getItem('token')
this.customerInfo = this.wpJsonService.getCustomerInfo(environment.systemId, token || '', environment.icardProxy)
this.purchases = this.getPurchases()
// this.purchases.subscribe((value) => console.log(value));
}
qrCodeClick() {
this.isQrCodeClicked = !this.isQrCodeClicked;
this.qrCodeSize = this.isQrCodeClicked ? 180 : 85;
}
deleteToken(): void {
this.cookiesService.deleteCookie('token');
}
logout() {
const bottomSheet = this._bottomSheet.open(ExitComponent)
bottomSheet.afterDismissed().subscribe({
next: (val) => {
if (val) {
this.deleteToken();
this.router.navigate(['/login']);
}
}
})
}
getPurchases(start: Date | Moment = moment().startOf('month'), end: Date | Moment = moment()): Observable<any> {
const token = this.cookiesService.getItem('token')
const delta = moment(end).diff(moment(start), 'days')
return this.wpJsonService.getTransactionsInfo(environment.systemId, token ?? '', environment.icardProxy)
}
}

View File

@ -1,26 +1,99 @@
<app-navbar
*ngIf="phoneForm.value.phone && !isShowNumber"
[title]="phoneForm.value.phone"
(backEvent)="backToPhoneForm()"
[ngStyle]="{
position: 'absolute',
top: 0
}"
></app-navbar>
<h1>Участвуй в программе лояльности COFFEE LIKE</h1>
<p class="description">Начни получать бонусы прямо сейчас</p>
<form *ngIf="isShowNumber; else smsCode" (ngSubmit)="submitNumber()" action="">
<form
*ngIf="isShowNumber; else smsCode"
(ngSubmit)="submitNumber()"
[formGroup]="phoneForm"
>
<!-- <div class="input-container"> -->
<mat-form-field appearance="outline">
<mat-label>Ваше имя</mat-label>
<input formControlName="name" matInput type="text" />
</mat-form-field>
<!-- </div> -->
<div class="input-container">
<label for="name">Ваше имя</label>
<input id="name" type="text" placeholder="Введите ваше имя" />
</div>
<div class="input-container">
<label for="number">Номер телефона</label>
<input id="number" type="text" placeholder="Введите номер" />
<!-- <label for="number">Номер телефона</label>
<input id="number" type="text" placeholder="Введите номер" /> -->
<mat-form-field appearance="outline">
<mat-label>Номер телефона</mat-label>
<ngx-mat-intl-tel-input
formControlName="phone"
[enablePlaceholder]="true"
[enableSearch]="false"
[onlyCountries]="['ru', 'kg', 'by', 'kz', 'fi', 'de']"
[preferredCountries]="['ru']"
name="phone"
#phone
>
</ngx-mat-intl-tel-input>
</mat-form-field>
</div>
<p class="offer">
Используя приложение, вы принимаете условия в <span>соглашениях</span> и
соглашаетесь на получение рекламно-информационных сообщений
</p>
<button>Принять участие</button>
<button [disabled]="phoneForm.invalid">Принять участие</button>
</form>
<ng-template #smsCode>
<h2>Введите код из SMS</h2>
<form class="code-form" action="" (ngSubmit)="submitCode()">
<input type="text" placeholder="Код" />
<form class="code-form" [formGroup]="codeForm" (ngSubmit)="submitCode()">
<div class="inputs-container">
<label class="box"
><input
class="field"
id="field"
type="tel"
placeholder="•"
#field
[appFocusNextInput]="inputFocusEmitter"
formControlName="code"
maxlength="1"
/></label>
<label class="box"
><input
class="field"
id="field1"
type="tel"
placeholder="•"
#field1
[appFocusNextInput]="inputFocusEmitter"
formControlName="code1"
maxlength="1"
/></label>
<label class="box"
><input
class="field"
id="field2"
type="tel"
placeholder="•"
#field2
[appFocusNextInput]="inputFocusEmitter"
formControlName="code2"
maxlength="1"
/></label>
<label class="box"
><input
class="field"
id="field3"
type="tel"
placeholder="•"
#field3
[appFocusNextInput]="inputFocusEmitter"
formControlName="code3"
maxlength="1"
/></label>
</div>
<button>Войти</button>
</form>
<p class="resend-code" >Не пришло SMS?<br>Отправим повторно через секунд</p>
<p class="resend-code">Не пришло SMS?<br />Отправим повторно через секунд</p>
</ng-template>

View File

@ -7,6 +7,7 @@
margin: 0 auto 52px;
h1 {
margin-top: 20px;
width: 302px;
font-style: normal;
font-weight: 700;
@ -106,24 +107,92 @@
font-weight: 700;
font-size: 17px;
line-height: 22px;
&:disabled {
background-color: #344a3a;
}
}
}
.code-form {
width: 100%;
input {
// input {
// width: 100%;
// padding: 24px 16px 8px;
// background-color: #252323;
// margin-bottom: 16px;
// border: none;
// border-top: solid #6a737c 1px;
// border-bottom: solid #6a737c 1px;
// color: #6a737c;
// font-style: normal;
// font-weight: 400;
// font-size: 22px;
// line-height: 28px;
// }
.inputs-container {
width: 102px;
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 40px;
// code
.box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 42px;
width: 42px;
border-radius: 6px;
// box-shadow: 0 0 6px 1px hsla(240, 54%, 61%, 0.2);
overflow: hidden;
will-change: transform;
}
.box:focus-within {
box-shadow: 0 0 6px 1px rgba($color: #28af49, $alpha: 0.2),
0 0 0 2px rgba($color: #28af49, $alpha: 0.6);
}
.box::before,
.box::after {
content: "";
position: absolute;
height: 100%;
width: 100%;
padding: 24px 16px 8px;
background-color: #252323;
margin-bottom: 16px;
border: none;
border-top: solid #6a737c 1px;
border-bottom: solid #6a737c 1px;
color: #6a737c;
font-style: normal;
font-weight: 400;
font-size: 22px;
line-height: 28px;
top: 0;
left: 0;
border-radius: 6px;
overflow: hidden;
}
.box::before {
// background: hsl(240, 54%, 97%);
z-index: 1;
transition: background-color 450ms cubic-bezier(0.25, 0.01, 0.25, 1);
}
.box::after {
transform: translateY(100%);
background-color: hsl(145, 0%, 42%);
opacity: 0;
z-index: 10;
transition: transform 450ms cubic-bezier(0.25, 0.01, 0.25, 1),
opacity 450ms cubic-bezier(0.25, 0.01, 0.25, 1),
background-color 450ms cubic-bezier(0.25, 0.01, 0.25, 1);
}
.field {
position: relative;
border: 0;
outline: 0;
font-size: 25.21px;
line-height: 42px;
color: #fff;
background-color: transparent;
text-align: center;
z-index: 100;
}
.field::placeholder {
color: #fff;
}
}
}
@ -133,5 +202,10 @@
font-size: 12px;
line-height: 16px;
text-align: center;
margin-top: 23px;
}
}
mat-form-field {
width: 100%;
}

View File

@ -1,25 +1,158 @@
import { Component, OnInit } from '@angular/core';
import {
AfterViewInit,
Component,
EventEmitter,
HostListener,
OnInit
} from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { MessageService } from 'primeng/api';
import { CookiesService } from 'src/app/services/cookies.service';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
})
export class LoginComponent implements OnInit {
isShowNumber: boolean = true;
export class LoginComponent implements OnInit, AfterViewInit {
public isShowNumber: boolean = true;
public phoneForm = new FormGroup({
name: new FormControl('', [Validators.required]),
phone: new FormControl('', [Validators.required]),
});
public codeForm = new FormGroup({
code: new FormControl('', [Validators.required]),
code1: new FormControl('', [Validators.required]),
code2: new FormControl('', [Validators.required]),
code3: new FormControl('', [Validators.required]),
});
private inputIds = ['field', 'field1', 'field2', 'field3'];
constructor(private cookiesService: CookiesService, private router: Router) {}
constructor(
private cookiesService: CookiesService,
private router: Router,
private jsonrpc: JsonrpcService,
private messageService: MessageService
) {}
ngOnInit(): void {}
ngAfterViewInit() {
setTimeout(() => {
this.inputFocusEmitter.emit(`#${this.inputIds[0]}`);
}, 1000)
}
public inputFocusEmitter = new EventEmitter<string>();
@HostListener('window:keyup', ['$event'])
HandlKeyEvents(event: any) {
if (!event.target.classList.contains('field')) return;
const key = event.key.toLocaleLowerCase();
let elementId = '';
switch (key) {
case 'backspace':
elementId = event.target.id;
event.target.value = '';
const prevInputIndex = this.inputIds.indexOf(elementId) - 1;
if (prevInputIndex >= 0) {
this.inputFocusEmitter.emit(`#${this.inputIds[prevInputIndex]}`);
}
break;
default:
elementId = event.target.id;
const index = this.inputIds.indexOf(elementId);
const nextInputIndex = index + 1;
if (event.target.value.length > 1) {
event.target.value = event.target.value.slice(-1);
}
if (nextInputIndex > 0 && nextInputIndex <= this.inputIds.length) {
this.inputFocusEmitter.emit(`#${this.inputIds[nextInputIndex]}`);
}
break;
}
}
submitNumber() {
const data = this.phoneForm.value;
console.log(data);
this.isShowNumber = false;
this.jsonrpc.rpc({
method: 'sendVerifyByPhone',
params: [data.phone]
}, RpcService.authService, false).subscribe({
next: (result) => {
if (result.code === -1) {
this.messageService.add({
severity: 'error',
summary: 'Произошла ошибка, попробуйте позже!',
});
}
// if (result.code === 0) {
// this.isCodeConfirm = true;
// this.timeLeft = 60;
// const interval = setInterval(() => {
// if(this.timeLeft > 0) {
// this.timeLeft--;
// } else {
// clearInterval(interval);
// }
// },1000)
// }
// this.loading = false;
this.isShowNumber = false;
},
error: (error) => {
console.error('Error: ', error);
}
}
);
setTimeout(() => {
this.inputFocusEmitter.emit(`#${this.inputIds[0]}`);
}, 0)
}
submitCode() {
this.cookiesService.setCookie('token', 'test')
this.router.navigate(['/'])
const data = this.codeForm.value;
this.jsonrpc.rpc({
method: 'getTokenByPhone',
params: [this.phoneForm.value.phone, Object.values(data).join('')]
}, RpcService.authService, false).subscribe({
next: (result) => {
if (result.code === 0) {
this.cookiesService.setCookie('token', result?.data?.token);
this.router.navigate(['/'], {
queryParams: {
token: result?.data?.token
},
});
// this.phoneConfirmed.emit(null);
} else {
// this.errorConfirmCode = true;
}
},
error: (error) => {
console.error(error);
}
}
);
}
backToPhoneForm() {
this.codeForm.setValue({
code: '',
code1: '',
code2: '',
code3: ''
})
this.isShowNumber = true
}
}

View File

@ -42,7 +42,27 @@ export class WpJsonService {
return this._request(`products/${id}`, 'GET');
}
_request(path: string, method: string, body?: any, auth = false): Observable<any> {
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}/${delta || ''}`, 'GET', null, false, url)
}
getTransactionsInfo(systemId: string, token: string, url: string, delta?: number): Observable<any> {
return this._request(`purchase/${systemId}/${token}/${delta || ''}`, '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)
// }
_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');
@ -56,8 +76,10 @@ export class WpJsonService {
body: this.body,
};
const url = environment.production ? window.location.origin + '/wp-json/woofood/v1/' : this.api
let url = environment.production ? window.location.origin + '/' : this.api
if (baseUrl) {
url = baseUrl
}
return this.http
.request( method, url + path + urlToken, options);
}

View File

@ -6,7 +6,7 @@ export const environment = {
appBonusEndpoint: 'https://customerapi2.mi.crm4retail.ru/json.rpc/',
appWPEndpoint: 'http://213.239.210.240:4500/wp-json/woofood/v1/',
hasBonusProgram: true,
systemId: 'g6zyv8tj53w28ov7cl',
systemId: 'tsQ2cu59Xz9qgGTm3z',
defaultUrl: 'https://coffee-like.lk.crm4retail.ru',
firebase: {
apiKey: "AIzaSyCnKvln5itnrBj62POCPHxshAN_Vmd0zds",
@ -19,6 +19,7 @@ export const environment = {
},
version: packageJson.version,
appleWalletEndpoint: 'https://apple-push-notifications.it-retail.tech/apns/api',
icardProxy: 'https://coffee-like.lk.crm4retail.ru/api/icard-proxy/',
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
clientName: 'coffeeLike'
}

View File

@ -6,7 +6,7 @@ export const environment = {
appBonusEndpoint: 'https://customerapi2.mi.crm4retail.ru/json.rpc/',
appWPEndpoint: 'http://192.168.0.179:4200/wp-json/woofood/v1/',
hasBonusProgram: true,
systemId: 'g6zyv8tj53w28ov7cl',
systemId: 'tsQ2cu59Xz9qgGTm3z',
defaultUrl: 'http://192.168.0.179:4200',
firebase: {
apiKey: 'AIzaSyCnKvln5itnrBj62POCPHxshAN_Vmd0zds',
@ -19,6 +19,7 @@ export const environment = {
},
version: packageJson.version,
appleWalletEndpoint: 'http://192.168.0.179:4200/apns/api',
icardProxy: 'http://192.168.0.14:4200/icard-proxy/',
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
clientName: 'coffeeLike'
};

View File

@ -30,6 +30,55 @@ hr {
border-top: 1px solid#BDBDBD;
}
.mat-form-field-wrapper {
padding: 0;
}
.mat-form-field-outline-start, .mat-form-field-outline-end {
border-radius: 0 !important;
}
.mat-form-field-outline-start {
border-left: none !important;
}
.mat-form-field-outline-end {
border-right: none !important;
}
.mat-focused .mat-form-field-outline > div {
border-color: #28af49;
}
.mat-focused .mat-form-field-label {
color: #fff !important;
}
.mat-form-field-invalid .mat-form-field-outline > div {
border-color: red;
}
.country-list-button {
color: #fff !important;
}
.mat-menu-panel {
background: #231f20;
border-radius: 0;
}
.country-selector {
opacity: 1 !important;
display: none !important;
}
.ngx-floating .country-selector {
display: block !important;
}
.country-selector-code {
color: #fff;
}
qr-code canvas {
transition: all 0.3s ease 0s;
}