Merge branch 'coffee-like-test' into coffee-like

This commit is contained in:
nikolay 2023-07-25 16:52:13 +04:00
commit 8c9a7ed1c2
28 changed files with 309 additions and 192 deletions

View File

@ -1,4 +1,4 @@
# CoffeeLikeTest # CoffeeLike
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,11 +1,11 @@
{ {
"name": "coffee-like-test", "name": "coffee-like",
"version": "0.0.2", "version": "0.0.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "coffee-like-test", "name": "coffee-like",
"version": "0.0.2", "version": "0.0.2",
"dependencies": { "dependencies": {
"@angular/animations": "^15.2.9", "@angular/animations": "^15.2.9",

View File

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, HostListener, OnInit } from '@angular/core';
import { RouteConfigLoadStart, Router } from '@angular/router'; import { RouteConfigLoadStart, Router } from '@angular/router';
import { AuthService } from './services/auth.service'; import { AuthService } from './services/auth.service';
import { CookiesService } from './services/cookies.service'; import { CookiesService } from './services/cookies.service';
import { JsonrpcService, RpcService } from './services/jsonrpc.service'; import { JsonrpcService, RpcService } from './services/jsonrpc.service';
import { pwaInstalled } from './utils';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -11,12 +12,14 @@ import { JsonrpcService, RpcService } from './services/jsonrpc.service';
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
title = 'Coffee Like'; title = 'Coffee Like';
public static pwaPrompt: any;
public static pwaInstalled: boolean = true;
constructor( constructor(
private router: Router, private router: Router,
private cookiesService: CookiesService, private cookiesService: CookiesService,
private jsonRpcService: JsonrpcService, private jsonRpcService: JsonrpcService,
private authService: AuthService, private authService: AuthService
) { ) {
this.router.events.subscribe((x) => { this.router.events.subscribe((x) => {
if (x instanceof RouteConfigLoadStart && x.route.path === '') { if (x instanceof RouteConfigLoadStart && x.route.path === '') {
@ -37,6 +40,24 @@ export class AppComponent implements OnInit {
}); });
} }
@HostListener('window:beforeinstallprompt', ['$event'])
onBeforeInstallPrompt(e: any) {
e.preventDefault();
AppComponent.pwaPrompt = e;
if (AppComponent.pwaPrompt) {
AppComponent.pwaInstalled = false;
}
}
@HostListener('window:appinstalled', ['$event'])
onAppInstalled(e: any) {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
AppComponent.pwaPrompt = e;
AppComponent.pwaInstalled = true;
}
getAdditionalInfo() { getAdditionalInfo() {
return this.jsonRpcService.rpc( return this.jsonRpcService.rpc(
{ {
@ -49,16 +70,22 @@ export class AppComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
pwaInstalled().then((res) => {
AppComponent.pwaInstalled = res;
});
if (this.authService.authorized) { if (this.authService.authorized) {
this.authService.getUserInfo(); this.authService.getUserInfo();
} }
this.getAdditionalInfo().subscribe({ this.getAdditionalInfo().subscribe({
next: (value) => { next: (value) => {
this.cookiesService.setCookie('presentation-option', value?.data?.interface_id || 'default') this.cookiesService.setCookie(
'presentation-option',
value?.data?.interface_id || 'default'
);
}, },
error: (err) => { error: (err) => {
console.error(err); console.error(err);
} },
}) });
} }
} }

View File

@ -107,7 +107,7 @@ import { DirectivesModule } from './directives/directives.module';
MatSnackBarModule, MatSnackBarModule,
MatBottomSheetModule, MatBottomSheetModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
DirectivesModule DirectivesModule,
], ],
providers: [ providers: [
DialogService, DialogService,
@ -118,4 +118,4 @@ import { DirectivesModule } from './directives/directives.module';
], ],
bootstrap: [AppComponent], bootstrap: [AppComponent],
}) })
export class AppModule { } export class AppModule {}

View File

@ -7,57 +7,27 @@ import {
} from '@angular/core'; } from '@angular/core';
import { MessageService } from 'primeng/api'; import { MessageService } from 'primeng/api';
import { getTypeDevice, pwaInstalled } from 'src/app/utils'; import { AppComponent } from '../app.component';
@Directive({ @Directive({
selector: '[appDownloadApp]', selector: '[appDownloadApp]',
}) })
export class DownloadAppDirective implements OnInit { export class DownloadAppDirective implements OnInit {
public deviceType: 'ios' | 'android' | null = null;
public deferredPrompt: any;
constructor( constructor(
private messageService: MessageService, private messageService: MessageService,
public renderer: Renderer2, public renderer: Renderer2,
private el: ElementRef, private el: ElementRef
) { } ) {}
ngOnInit(): void { ngOnInit(): void {
getTypeDevice(); if (AppComponent.pwaInstalled) {
if (this.deviceType === 'ios') {
this.el.nativeElement.style.display = 'block';
}
this.checkInstalled();
}
async checkInstalled(): Promise<void> {
if (window.matchMedia('(display-mode: standalone)').matches
|| await pwaInstalled()) {
this.el.nativeElement.style.display = 'none'; this.el.nativeElement.style.display = 'none';
} }
} }
@HostListener('window:beforeinstallprompt', ['$event'])
onBeforeInstallPrompt(e: any) {
e.preventDefault();
this.deferredPrompt = e;
if (this.deferredPrompt) {
this.el.nativeElement.style.display = 'block';
}
}
@HostListener('window:appinstalled', ['$event'])
onAppInstalled(e: any) {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
this.deferredPrompt = e;
this.el.nativeElement.style.display = 'none';
}
@HostListener('click', ['$event']) @HostListener('click', ['$event'])
async downloadApp(event: MouseEvent) { async downloadApp(event: MouseEvent) {
if (!this.deferredPrompt) { if (!AppComponent.pwaPrompt) {
this.messageService.clear(); this.messageService.clear();
this.messageService.add({ this.messageService.add({
severity: 'error', severity: 'error',
@ -65,8 +35,8 @@ export class DownloadAppDirective implements OnInit {
}); });
return; return;
} }
this.deferredPrompt.prompt(); AppComponent.pwaPrompt.prompt();
this.deferredPrompt.userChoice.then((res: any) => { AppComponent.pwaPrompt.userChoice.then((res: any) => {
if (res.outcome === 'accepted') { if (res.outcome === 'accepted') {
this.messageService.clear(); this.messageService.clear();
this.messageService.add({ this.messageService.add({
@ -74,8 +44,7 @@ export class DownloadAppDirective implements OnInit {
summary: 'Спасибо за установку!', summary: 'Спасибо за установку!',
}); });
} }
this.deferredPrompt = null; AppComponent.pwaPrompt = null;
}); });
} }
} }

View File

@ -6,7 +6,7 @@ export enum PageCode {
UserData, UserData,
} }
export interface Moment extends moment.Moment { } export interface Moment extends moment.Moment {}
export interface Page { export interface Page {
code: PageCode; code: PageCode;
@ -216,7 +216,7 @@ export interface NextLevel {
} }
export interface UserInfo { export interface UserInfo {
current_level_and_cashback?: CurrentInfo; current_level_and_cashback: CurrentInfo;
last_purchase?: LastPurchase; last_purchase?: LastPurchase;
id: string; id: string;
phone: string; phone: string;

View File

@ -75,6 +75,7 @@
font-size: 16px; font-size: 16px;
line-height: 19px; line-height: 19px;
letter-spacing: -0.5px; letter-spacing: -0.5px;
color: var(--text-color);
} }
.price, .price,

View File

@ -0,0 +1,13 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safeHtml',
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(html: string) {
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}

View File

@ -14,7 +14,7 @@
line-height: 20px; line-height: 20px;
text-align: center; text-align: center;
letter-spacing: -0.24px; letter-spacing: -0.24px;
color: #6a737c; color: var(--text-color_1);
} }
.phone-number { .phone-number {
font-style: normal; font-style: normal;
@ -23,7 +23,7 @@
line-height: 22px; line-height: 22px;
text-align: center; text-align: center;
letter-spacing: -0.408px; letter-spacing: -0.408px;
color: #d9d9d9; color: var(--text-color);
text-decoration: none; text-decoration: none;
} }
} }

View File

@ -2,10 +2,10 @@
<ng-container *ngIf="lastOrder"> <ng-container *ngIf="lastOrder">
<h2>Ваш предыдущий заказ</h2> <h2>Ваш предыдущий заказ</h2>
<p class="flex"><span>Дата: </span> <p class="flex"><span>Дата: </span>
<span *ngIf="!loading">{{lastOrder!.last_purchase_date}}</span> <span class="info" *ngIf="!loading">{{lastOrder!.last_purchase_date}}</span>
</p> </p>
<p class="flex"><span>На сумму: </span> <p class="flex"><span>На сумму: </span>
<span *ngIf="!loading">{{lastOrder?.last_purchase_sum}}₽</span> <span class="info" *ngIf="!loading">{{lastOrder?.last_purchase_sum}}₽</span>
</p> </p>
</ng-container> </ng-container>
<ng-container *ngIf="!lastOrder"> <ng-container *ngIf="!lastOrder">

View File

@ -22,6 +22,9 @@
flex-direction: row; flex-direction: row;
gap: 8px; gap: 8px;
} }
.info {
font-size: 14px;
}
} }
.evaluate-order { .evaluate-order {

View File

@ -8,18 +8,26 @@
<div *ngIf="showDropdown" class="backdrop" (click)="closeMenu()"></div> <div *ngIf="showDropdown" class="backdrop" (click)="closeMenu()"></div>
<div class="menu"> <div class="menu">
<button mat-button (click)="toggleMenu()"> <button mat-button (click)="toggleMenu()">
<span class="material-icons" style="color: white !important"> <span class="material-icons" style="color: var(--button-text-color) !important">
more_horiz more_horiz
</span> </span>
</button> </button>
<div class="menu__dropdown" *ngIf="showDropdown"> <div class="menu__dropdown" *ngIf="showDropdown">
<ul> <ul>
<menu-item [handler]="handler(aboutApp)"> <!-- <menu-item [handler]="handler(aboutApp)">
<span class="material-icons icon" style="color: var(--main-color)"> <span class="material-icons icon" style="color: var(--main-color_2)">
info info
</span> </span>
<span class="item_title">О приложении</span> <span class="item_title">О приложении</span>
</menu-item> -->
<menu-item [handler]="handler(navigateToLoyality)">
<span class="material-icons icon" style="color: var(--main-color_2)">
info
</span>
<span class="item_title">
О программе лояльности
</span>
</menu-item> </menu-item>
<ng-container *ngIf="isios"> <ng-container *ngIf="isios">
<menu-item [handler]="handler(addToWallet)"> <menu-item [handler]="handler(addToWallet)">
@ -34,8 +42,8 @@
Установить приложение Установить приложение
</span> </span>
</menu-item> </menu-item>
<menu-item *ngIf="!messagingService.checkRequestPermission()" [handler]="handler(messagingService.requestPermission)"> <menu-item *ngIf="!notified()" [handler]="handler(notify)">
<span class="material-icons" style="color: var(--main-color)"> <span class="material-icons" style="color: var(--main-color_2)">
notifications notifications
</span> </span>
<span class="item_title"> <span class="item_title">
@ -44,7 +52,7 @@
</menu-item> </menu-item>
</ng-container> </ng-container>
<menu-item [handler]="handler(logout)"> <menu-item [handler]="handler(logout)">
<span class="material-icons" style="color: var(--main-color)"> <span class="material-icons" style="color: var(--main-color_2)">
logout logout
</span> </span>
<span class="item_title">Выйти</span> <span class="item_title">Выйти</span>

View File

@ -15,8 +15,7 @@
box-sizing: border-box; box-sizing: border-box;
padding: 12px 16px; padding: 12px 16px;
width: 100%; width: 100%;
background: var(--button-color); background: var(--main-color_2);
color: var(--button-text-color);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
@ -33,6 +32,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: var(--button-text-color);
} }
.plug { .plug {
height: 24px; height: 24px;
@ -44,6 +44,7 @@
font-size: 17px; font-size: 17px;
line-height: 22px; line-height: 22px;
margin: 0 auto; margin: 0 auto;
color: var(--button-text-color);
} }
.menu { .menu {
position: relative; position: relative;
@ -52,12 +53,13 @@
.menu__dropdown { .menu__dropdown {
z-index: 110; z-index: 110;
position: absolute; position: absolute;
background-color: white; background-color: var(--background-color_1);
width: 250px; width: 250px;
height: fit-content; height: fit-content;
right: 20px; right: 20px;
border-radius: 6px; border-radius: 6px;
box-shadow: 0px 2px 5px -3px black; box-shadow: 0px 2px 5px -3px black;
overflow: hidden;
.item_title { .item_title {
color: var(--text-color); color: var(--text-color);

View File

@ -6,14 +6,15 @@ import { CookiesService } from 'src/app/services/cookies.service';
import { MatBottomSheet } from '@angular/material/bottom-sheet'; import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { ExitComponent } from 'src/app/components/exit/exit.component'; import { ExitComponent } from 'src/app/components/exit/exit.component';
import { AuthService } from 'src/app/services/auth.service'; import { AuthService } from 'src/app/services/auth.service';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-navbar[title]', selector: 'app-navbar[title]',
templateUrl: './navbar.component.html', templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss'] styleUrls: ['./navbar.component.scss'],
}) })
export class NavbarComponent implements OnInit { export class NavbarComponent implements OnInit {
@Input() title: string = 'Название не задано' @Input() title: string = 'Название не задано';
@Input() backEvent?: () => void; @Input() backEvent?: () => void;
showDropdown: boolean = false; showDropdown: boolean = false;
@ -25,16 +26,17 @@ export class NavbarComponent implements OnInit {
private cookiesService: CookiesService, private cookiesService: CookiesService,
private _bottomSheet: MatBottomSheet, private _bottomSheet: MatBottomSheet,
private authService: AuthService, private authService: AuthService,
) { } private router: Router
) {}
handler(cb: () => void): (e: any) => void { handler(cb: () => void): (e: any) => void {
return (e: any) => { return (e: any) => {
cb(); cb();
this.closeMenu(); this.closeMenu();
} };
} }
aboutApp() { } aboutApp() {}
ngOnInit(): void { ngOnInit(): void {
this.isios = getTypeDevice() == DeviceType.ios; this.isios = getTypeDevice() == DeviceType.ios;
@ -50,7 +52,7 @@ export class NavbarComponent implements OnInit {
closeMenu = () => { closeMenu = () => {
this.showDropdown = false; this.showDropdown = false;
} };
back() { back() {
if (this.backEvent) { if (this.backEvent) {
@ -60,11 +62,11 @@ export class NavbarComponent implements OnInit {
addToWallet = () => { addToWallet = () => {
this.appleWalletService.addCardToWallet(); this.appleWalletService.addCardToWallet();
} };
deleteToken = (): void => { deleteToken = (): void => {
this.cookiesService.logout(); this.cookiesService.logout();
} };
logout = () => { logout = () => {
const bottomSheet = this._bottomSheet.open(ExitComponent); const bottomSheet = this._bottomSheet.open(ExitComponent);
@ -75,8 +77,19 @@ export class NavbarComponent implements OnInit {
} }
}, },
}); });
} };
installApp = () => { } installApp = () => {};
notified = () => {
return this.messagingService.checkRequestPermission();
};
notify = () => {
this.messagingService.requestPermission();
};
navigateToLoyality = () => {
this.router.navigate(['loyality-program']);
};
} }

View File

@ -7,7 +7,7 @@
width: 48px; width: 48px;
height: 48px; height: 48px;
border-radius: 100%; border-radius: 100%;
background: var(--button-color); background: var(--main-color_2);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@ -22,7 +22,7 @@ import { DirectivesModule } from 'src/app/directives/directives.module';
import { LoyalityProgramComponent } from './pages/loyality-program/loyality-program.component'; import { LoyalityProgramComponent } from './pages/loyality-program/loyality-program.component';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { ToastModule } from 'primeng/toast'; import { ToastModule } from 'primeng/toast';
import { SafeHtmlPipe } from 'src/app/pipes/safe-html.pipe';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -37,6 +37,7 @@ import { ToastModule } from 'primeng/toast';
LoginComponent, LoginComponent,
LoyalityProgramComponent, LoyalityProgramComponent,
MenuItemComponent, MenuItemComponent,
SafeHtmlPipe,
], ],
imports: [ imports: [
ToastModule, ToastModule,
@ -51,8 +52,8 @@ import { ToastModule } from 'primeng/toast';
ReactiveFormsModule, ReactiveFormsModule,
MatInputModule, MatInputModule,
DirectivesModule, DirectivesModule,
MatButtonModule MatButtonModule,
], ],
bootstrap: [IndexComponent], bootstrap: [IndexComponent],
}) })
export class DefaultOptionModule { } export class DefaultOptionModule {}

View File

@ -19,28 +19,21 @@
</ng-container> </ng-container>
</div> </div>
<div class="guest-card__qr" (click)="qrCodeClick()"> <div class="guest-card__qr" (click)="qrCodeClick()">
<qr-code <div class="qr-code-wrapper">
<qr-code
[value]="phone || 'Данные не найдены'" [value]="phone || 'Данные не найдены'"
[margin]="0" [margin]="0"
[size]="qrCodeSize" [size]="qrCodeSize"
errorCorrectionLevel="H" errorCorrectionLevel="H"
></qr-code> ></qr-code>
<span class="material-icons zoom">
zoom_in
</span>
</div>
<span>Покажи бариста</span>
</div> </div>
<div class="guest-card__user-description"> <div class="guest-card__user-description">
<p> <p [innerHtml]="getLevelDescription() | safeHtml"></p>
Осталось купить на сумму
<span class="price">{{
authService.error ? '--' : authService.userInfo.next_level.sum_for_next_level
}}</span>
рублей, тогда кэшбек будет
<span class="percent">{{ authService.error ? '--' : authService.userInfo.next_level.cashback}}%</span>
с
{{
authService.currentPeriod[1]
.locale("ru")
.format("D MMMM")
}}
</p>
</div> </div>
<ng-container *ngIf="!authService.error"> <ng-container *ngIf="!authService.error">
<span id="bonuses-condition"></span> <span id="bonuses-condition"></span>
@ -49,11 +42,6 @@
[loading]="authService.loading" [loading]="authService.loading"
></app-last-order> ></app-last-order>
<a class="guest-card__loyalty-program" routerLink="loyality-program">
Подробнее о правилах
<br />
Программы лояльности
</a>
</ng-container> </ng-container>
<ng-container *ngIf="authService.error"> <ng-container *ngIf="authService.error">
<img src="./assets/broken.jpg" alt="" /> <img src="./assets/broken.jpg" alt="" />

View File

@ -12,6 +12,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
font-size: 16px;
&__level { &__level {
width: 100%; width: 100%;
@ -20,48 +21,42 @@
align-items: center; align-items: center;
justify-content: space-around; justify-content: space-around;
font-size: 16px;
} }
& p { & p {
color: var(--button-color); color: var(--button-color);
} }
p.top-info__bonus {
font-size: 20px;
}
} }
&__qr { &__qr {
margin: 10px; margin: 10px;
padding: 5px; padding: 5px;
width: fit-content; width: fit-content;
// background-image: linear-gradient( border-radius: 6px;
// #008251 33%, align-items: center;
// transparent 0px, display: flex;
// transparent 67%, flex-direction: column;
// #008251 0px
// ),
// linear-gradient(
// 90deg,
// #008251 33%,
// transparent 0px,
// transparent 66%,
// #008251 0px
// ),
// linear-gradient(#008251 33%, transparent 0px, transparent 67%, #008251 0),
// linear-gradient(90deg, #008251 33%, transparent 0, transparent 66%, #008251 0);
// background-size: 3px 100%, 100% 3px, 3px 100%, 100% 3px;
// background-position: 0 0, 0 0, 100% 100%, 100% 100%;
// background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
cursor: pointer; cursor: pointer;
.qr-code-wrapper {
position: relative;
}
.zoom {
position: absolute;
bottom: 5px;
right: -35px;
color: var(--button-color);
}
} }
&__user-description { &__user-description {
padding: 14px 24px; padding: 14px 24px;
p { p {
width: 60%; width: 80%;
text-align: center; text-align: center;
margin: 0 auto; margin: 0 auto;
font-style: normal; font-style: normal;
@ -69,11 +64,12 @@
font-size: 16px; font-size: 16px;
line-height: 19px; line-height: 19px;
letter-spacing: -0.5px; letter-spacing: -0.5px;
}
.price, #price,
.percent { .percent {
font-weight: bold; font-weight: bold;
color: var(--button-color);
}
} }
} }

View File

@ -1,10 +1,38 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatBottomSheet } from '@angular/material/bottom-sheet'; import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { ExitComponent } from 'src/app/components/exit/exit.component'; import { ExitComponent } from 'src/app/components/exit/exit.component';
import { CookiesService } from 'src/app/services/cookies.service'; import { CookiesService } from 'src/app/services/cookies.service';
import { MessageService } from 'primeng/api'; import { MessageService } from 'primeng/api';
import { MessagingService } from 'src/app/services/messaging.service'; import { MessagingService } from 'src/app/services/messaging.service';
import { AuthService } from 'src/app/services/auth.service'; import { AuthService } from 'src/app/services/auth.service';
import { format } from 'src/app/utils';
const levelDescriptionsTable = [
[
'Поднимай свой уровень!<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и твой кешбек будет <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">6%</span> с {1}!',
'А ты хорош!<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и получай кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">10%</span> с {1}',
'Ты крут!<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
'Ты сделал это!<br/>Получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
],
[
'Oops! Ты можешь оказаться на 1 уровне.<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и твой кешбек будет <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">6%</span> с {1}!',
'Ты можешь стать круче!<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и получай кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">10%</span> с {1}',
'Ого! Ты уже здесь! Хочешь еще больше кешбека?<br/>Купи на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
'Ты потрясающий!<br/>Получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
],
[
'Oops! Ты можешь оказаться на 1 уровне.<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и твой кешбек будет <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">6%</span> с {1}!',
'Для сохранения 3 уровня осталось немного.<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span и получай кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">10%</span> с {1}',
'Ты почти на последнем уровне!<br/>Купи на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
'Ты лучший!<br/>Получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
],
[
'Oops! Ты можешь оказаться на 1 уровне.<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и твой кешбек будет <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">6%</span> с {1}!',
'Для сохранения 3 уровня осталось немного.<br/>Купи еще на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span и получай кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">10%</span> с {1}',
'Оу! Ты можешь остаться без максимального кешбека.<br/>Купи на <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">{0}₽</span> и возвращай себе кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
'Ты наш герой!<br/>Получай максимальный кешбек <span style="color: var(--button-color); font-weight: bold; font-size: 17px;">15%</span> с {1}',
],
];
@Component({ @Component({
selector: 'app-guest-card', selector: 'app-guest-card',
@ -22,11 +50,13 @@ export class GuestCardComponent implements OnInit {
public cookiesService: CookiesService, public cookiesService: CookiesService,
private messagingService: MessagingService, private messagingService: MessagingService,
private messageService: MessageService, private messageService: MessageService,
public authService: AuthService, public authService: AuthService
) { } ) {}
ngOnInit(): void { ngOnInit(): void {
this.phone = this.cookiesService.getItem('phone-number') || this.authService.userInfo?.phone; this.phone =
this.cookiesService.getItem('phone-number') ||
this.authService.userInfo?.phone;
this.requestPermission(); this.requestPermission();
} }
@ -69,5 +99,24 @@ export class GuestCardComponent implements OnInit {
} }
}, },
}); });
};
getLevelDescription() {
let curLevel = 0;
let nextLevel = 0;
if (this.authService.userInfo) {
curLevel =
this.authService.userInfo.current_level_and_cashback.current_level - 1;
nextLevel = this.authService.userInfo.next_level.next_level - 1;
}
const template = levelDescriptionsTable[curLevel][nextLevel];
return format(
template,
`${this.authService.userInfo?.next_level.sum_for_next_level}`,
`${this.authService.currentPeriod[1].locale('ru').format('D MMMM')}`
);
} }
} }

View File

@ -4,7 +4,7 @@
[backEvent]="backToPhoneForm" [backEvent]="backToPhoneForm"
></app-navbar> ></app-navbar>
<h1>Участвуй в программе лояльности COFFEE LIKE</h1> <h1>Участвуй в программе лояльности COFFEE LIKE</h1>
<p class="description">Начни получать бонусы прямо сейчас</p> <p class="description">Начни получать бонусы прямо сейчас!</p>
<form <form
*ngIf="isShowNumber; else smsCode" *ngIf="isShowNumber; else smsCode"
(ngSubmit)="submitNumber()" (ngSubmit)="submitNumber()"

View File

@ -57,6 +57,7 @@
a { a {
text-decoration: none; text-decoration: none;
color: var(--button-color); color: var(--button-color);
text-decoration: underline;
} }
} }
@ -153,8 +154,8 @@
will-change: transform; will-change: transform;
} }
.box:focus-within { .box:focus-within {
box-shadow: 0 0 6px 1px rgba(rgb(127, 32, 97), 0.2), box-shadow: 0 0 6px 1px rgba(rgb(0, 92, 80), 0.2),
0 0 0 2px rgba(rgb(127, 32, 97), 0.6); 0 0 0 2px rgba(rgb(0, 92, 80), 0.6);
} }
.box::before, .box::before,
.box::after { .box::after {

View File

@ -1,4 +1,4 @@
import { environment } from "src/environments/environment.prod"; import { environment } from 'src/environments/environment.prod';
export enum DeviceType { export enum DeviceType {
ios, ios,
@ -12,7 +12,9 @@ export function getTypeDevice(): DeviceType {
} }
export async function pwaInstalled(): Promise<boolean> { export async function pwaInstalled(): Promise<boolean> {
if ("getInstalledRelatedApps" in navigator) { if (window.matchMedia('(display-mode: standalone)').matches) return true;
if ('getInstalledRelatedApps' in navigator) {
const apps = await (window.navigator as any).getInstalledRelatedApps(); const apps = await (window.navigator as any).getInstalledRelatedApps();
for (const app of apps) { for (const app of apps) {
if (app.url == environment.manifestUrl) { if (app.url == environment.manifestUrl) {
@ -22,3 +24,9 @@ export async function pwaInstalled(): Promise<boolean> {
} }
return false; return false;
} }
export function format(s: string, ...args: string[]) {
return s.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

After

Width:  |  Height:  |  Size: 288 KiB

View File

@ -7,19 +7,19 @@ export const environment = {
appWPEndpoint: 'http://213.239.210.240:4500/wp-json/woofood/v1/', appWPEndpoint: 'http://213.239.210.240:4500/wp-json/woofood/v1/',
hasBonusProgram: true, hasBonusProgram: true,
systemId: 'tsQ2cu59Xz9qgGTm3z', systemId: 'tsQ2cu59Xz9qgGTm3z',
defaultUrl: 'https://club.coffee-like.com', defaultUrl: 'https://coffee-like.lk.crm4retail.ru',
manifestUrl: 'https://club.coffee-like.com/manifest.webmanifest', manifestUrl: 'https://coffee-like.lk.crm4retail.ru/manifest.webmanifest',
firebase: { firebase: {
apiKey: "AIzaSyDTb_xuMz2vDx8xGs34AJiltraKVlwmrtY", apiKey: 'AIzaSyDTb_xuMz2vDx8xGs34AJiltraKVlwmrtY',
authDomain: "coffee-like-77bfe.firebaseapp.com", authDomain: 'coffee-like-77bfe.firebaseapp.com',
projectId: "coffee-like-77bfe", projectId: 'coffee-like-77bfe',
storageBucket: "coffee-like-77bfe.appspot.com", storageBucket: 'coffee-like-77bfe.appspot.com',
messagingSenderId: "1094726277369", messagingSenderId: '1094726277369',
appId: "1:1094726277369:web:8af560662da7700e7a2a28" appId: '1:1094726277369:web:8af560662da7700e7a2a28',
}, },
version: packageJson.version, version: packageJson.version,
appleWalletEndpoint: 'https://apple-wallet-iiko.it-retail.tech/apns/api', appleWalletEndpoint: 'https://apple-wallet-iiko.it-retail.tech/apns/api',
icardProxy: 'https://club.coffee-like.com/api/icard-proxy/', icardProxy: 'https://coffee-like.lk.crm4retail.ru/api/icard-proxy/',
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l', appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
clientName: 'coffeelike' clientName: 'coffeelike',
} };

View File

@ -8,18 +8,18 @@ export const environment = {
hasBonusProgram: true, hasBonusProgram: true,
systemId: 'tsQ2cu59Xz9qgGTm3z', systemId: 'tsQ2cu59Xz9qgGTm3z',
defaultUrl: 'http://192.168.0.179:4200', defaultUrl: 'http://192.168.0.179:4200',
manifestUrl: 'https://club.coffee-like.com/manifest.webmanifest', manifestUrl: 'https://coffee-like.lk.crm4retail.ru/manifest.webmanifest',
firebase: { firebase: {
apiKey: "AIzaSyDTb_xuMz2vDx8xGs34AJiltraKVlwmrtY", apiKey: 'AIzaSyDTb_xuMz2vDx8xGs34AJiltraKVlwmrtY',
authDomain: "coffee-like-77bfe.firebaseapp.com", authDomain: 'coffee-like-77bfe.firebaseapp.com',
projectId: "coffee-like-77bfe", projectId: 'coffee-like-77bfe',
storageBucket: "coffee-like-77bfe.appspot.com", storageBucket: 'coffee-like-77bfe.appspot.com',
messagingSenderId: "1094726277369", messagingSenderId: '1094726277369',
appId: "1:1094726277369:web:8af560662da7700e7a2a28" appId: '1:1094726277369:web:8af560662da7700e7a2a28',
}, },
version: packageJson.version, version: packageJson.version,
appleWalletEndpoint: 'https://apple-wallet-iiko.it-retail.tech/apns/api', appleWalletEndpoint: 'https://apple-wallet-iiko.it-retail.tech/apns/api',
icardProxy: 'https://club.coffee-like.com/api/icard-proxy/', icardProxy: 'https://coffee-like.lk.crm4retail.ru/api/icard-proxy/',
appleWalletSecret: 'Token F5mbzEERAznGKVbB6l', appleWalletSecret: 'Token F5mbzEERAznGKVbB6l',
clientName: 'coffeelike' clientName: 'coffeelike',
}; };

View File

@ -53,6 +53,6 @@
"gcm_sender_id": "99855572145", "gcm_sender_id": "99855572145",
"related_applications": [{ "related_applications": [{
"platform": "webapp", "platform": "webapp",
"url": "https://club.coffee-like.com/manifest.webmanifest" "url": "https://coffee-like.lk.crm4retail.ru/manifest.webmanifest"
}] }]
} }

View File

@ -3,20 +3,20 @@
@include mat.core(); @include mat.core();
$primary: ( $primary: (
50 : #f0e4ec, 50 : #e0ebea,
100 : #d9bcd0, 100 : #b3cecb,
200 : #bf90b0, 200 : #80aea8,
300 : #a56390, 300 : #4d8d85,
400 : #924179, 400 : #26746a,
500 : #7f2061, 500 : #005c50,
600 : #771c59, 600 : #005449,
700 : #6c184f, 700 : #004a40,
800 : #621345, 800 : #004137,
900 : #4f0b33, 900 : #003027,
A100 : #ff85c7, A100 : #69ffdb,
A200 : #ff52b0, A200 : #36ffce,
A400 : #ff1f99, A400 : #03ffc2,
A700 : #ff068d, A700 : #00e8b0,
contrast: ( contrast: (
50 : #000000, 50 : #000000,
100 : #000000, 100 : #000000,
@ -30,8 +30,8 @@ $primary: (
900 : #ffffff, 900 : #ffffff,
A100 : #000000, A100 : #000000,
A200 : #000000, A200 : #000000,
A400 : #ffffff, A400 : #000000,
A700 : #ffffff, A700 : #000000,
) )
); );
@ -111,24 +111,52 @@ body {
} }
:root { :root {
--main-color: #7F2061; --main-color: #28AF49;
--main-color_2: #005C50;
--main-border-radius: 35px; --main-border-radius: 35px;
--background-color: #ffffff; --background-color: #ffffff;
--background-color_1: #ffffff;
--text-color: #222222; --text-color: #000000;
--text-color_1: #666666; --text-color_1: #8d8d8d;
--button-color: #7F2061; --button-color: #005C50;
--button-color_disabled: #4a0d37; --button-color_disabled: rgb(0, 92, 80, 0.9);
--button-text-color: #ffffff; --button-text-color: #ffffff;
--button-text-color_disabled: #cccccc; --button-text-color_disabled: #cccccc;
--main-color_hover: rgba(127, 32, 97, 0.3); --main-color_hover: rgba(0, 92, 80, 0.3);
} }
.mdc-button__label { .mdc-text-field--outlined:not(.mdc-text-field--disabled, .mdc-text-field--invalid, .mat-focused) .mdc-notched-outline__leading,
color: var(--button-text-color) !important; .mdc-text-field--outlined:not(.mdc-text-field--disabled, .mdc-text-field--invalid, .mat-focused) .mdc-notched-outline__notch,
.mdc-text-field--outlined:not(.mdc-text-field--disabled, .mdc-text-field--invalid, .mat-focused) .mdc-notched-outline__trailing {
border-color: var(--main-color_2) !important;
}
.mat-mdc-outlined-button:not(:disabled) {
border-color: var(--text-color) !important;
.mdc-button__label {
color: var(--text-color);
}
}
.mdc-text-field:not(.mdc-text-field--disabled, .mdc-text-field--invalid) .mdc-floating-label {
color: var(--main-color_2);
}
.mdc-text-field span {
color: inherit !important;
}
.mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input {
color: var(--text-color);
}
.mdc-button__label span {
color: var(--text-color) !important;
} }
.mat-mdc-outlined-button:not(:disabled) { .mat-mdc-outlined-button:not(:disabled) {
@ -143,6 +171,10 @@ body {
font-family: Montserrat; font-family: Montserrat;
} }
p, span, h1, h2, h3, h4, h5, h6 {
color: var(--text-color);
}
.mat-h2, .mat-h2,
.mat-headline-6, .mat-headline-6,
.mat-typography .mat-h2, .mat-typography .mat-h2,
@ -151,6 +183,12 @@ body {
font-family: Montserrat, sans-serif; font-family: Montserrat, sans-serif;
} }
.mat-bottom-sheet-container {
background: var(--background-color_1);
color: var(--text-color);
}
hr { hr {
width: 100%; width: 100%;
border-top: 1px solid #BDBDBD; border-top: 1px solid #BDBDBD;