Compare commits

...

61 Commits

Author SHA1 Message Date
7a9f9fc872 dev #13951
Исправил ошибки у новых пользователей
2023-03-30 12:43:42 +04:00
7bb05324a9 dev #13951
сделал суммирование бонусов со всех бонусных программ
2023-03-20 23:30:20 +04:00
5e3b211778 dev #13882
правки
2023-03-08 02:04:54 +04:00
e75999a3c1 dev #13882
правки
2023-03-08 02:02:21 +04:00
f8f500f612 dev #13882
правки
2023-03-08 01:42:44 +04:00
72808c3c7c dev #13882
правки
2023-03-08 01:36:27 +04:00
efb8095e2f dev #13882
правки
2023-03-08 01:17:48 +04:00
699db43b39 dev #13882
правки
2023-03-08 01:11:58 +04:00
5152d9ad30 dev #13882
правки
2023-03-08 00:29:44 +04:00
da340475e0 support #13704
поменял картинки
2023-02-19 23:46:28 +04:00
ef8ac5d24d support #13704
поменял картинку в apple wallet
2023-02-05 21:01:20 +04:00
fa5d29e517 support #13704
правка
2023-02-05 20:55:56 +04:00
1a5fa44abc support #13704
поменял картинки
2023-02-05 20:47:41 +04:00
Kataev Denis
bedda578c8 support #13704
поменял фавикон
2023-02-01 03:35:31 +04:00
Kataev Denis
44cf8d5074 support #13704
поменял картинку бабочки в манифесте
2023-02-01 03:29:49 +04:00
Kataev Denis
ecdd4f103e support #13704
поменял картинку бабочки
2023-02-01 03:11:59 +04:00
c0387d967d dev #13538
правка
2023-01-13 03:22:36 +04:00
b33ed15666 dev #13538
правка
2023-01-13 03:13:06 +04:00
c7ade7515c dev #13538
правка
2023-01-13 03:07:39 +04:00
e4bb1d8947 dev #13538
правка
2023-01-13 03:05:50 +04:00
c71e2d4c48 dev #13538
правка
2023-01-13 03:02:49 +04:00
88b0d92300 dev #13538
правка
2023-01-12 19:37:31 +04:00
e570e82f90 dev #13538
правка
2023-01-12 19:27:34 +04:00
85174c1fab dev #13538
правка
2023-01-12 19:22:10 +04:00
7a895c76a6 dev #13538
правка
2023-01-12 02:41:31 +04:00
dbf01e4fc5 dev #13538
правка
2023-01-12 02:38:24 +04:00
227392d7f6 dev #13538
правка
2023-01-12 02:35:56 +04:00
f8f2fe4673 dev #13538
правка
2023-01-12 02:27:14 +04:00
4d16fa4184 dev #13538
правка
2023-01-12 02:04:56 +04:00
5e69d6e5c5 dev #13538
перенес кнопку, вынес функционал в директиву
2023-01-12 01:57:32 +04:00
pumpurumer
a0de9cbb61 bump version 2022-10-27 12:34:25 +04:00
pumpurumer
192a7a5d2f поменял секреты на нормальные 2022-10-19 12:47:16 +04:00
dfd596cd56 dev #12797
Правки
2022-10-16 22:29:36 +04:00
b92b1e73ce dev #12797
Добавил обновление карты при обновлении данных пользователя
2022-10-16 22:24:38 +04:00
8ca151574a dev #12797
Доработки на фронте
2022-10-16 22:05:12 +04:00
Kataev Denis
9f4447fa79 package-lock 2022-10-12 11:46:37 +04:00
197c84f29c dev #12797
изменил расположение директорий и изменил файлы Jenkinsfile и gitignore
2022-10-11 10:40:59 +04:00
Kataev Denis
29d274e05b Merge branch 'fashion-logica' of https://git.hlcompany.ru/git/usersite into fashion-logica 2022-10-11 09:55:20 +04:00
Kataev Denis
e558fcabc0 dev #12797
генерация карты
2022-10-11 09:55:01 +04:00
1ee13ab73d dev #12618
поправил проверку на существование в реферальной системе
2022-09-30 13:07:02 +04:00
4414480d6e dev #12425
Поправил сохранения токенов для пушей
2022-09-30 13:02:57 +04:00
2ca121cbac Merge branch 'fashion-logica' of https://git.hlcompany.ru/git/usersite into fashion-logica 2022-09-29 21:47:34 +04:00
25a5db7337 dev #12401
правки по реферальной системе и версии приложения
2022-09-29 21:46:49 +04:00
Kataev Denis
134ee3f59d dev #12425
Поменял учетные данные
2022-09-29 18:41:33 +04:00
Kataev Denis
914b1ec5ed dev #12401
вернул как было
2022-09-29 10:32:06 +04:00
Kataev Denis
86eaca953e dev #12401
Страница 404 доработка
2022-09-29 10:15:21 +04:00
Kataev Denis
a22479dffd Merge branch 'fashion-logica' of https://git.hlcompany.ru/git/usersite into fashion-logica 2022-09-29 10:09:25 +04:00
Kataev Denis
bb455b2c45 dev #12401
Страница 404 и правки
2022-09-29 10:09:15 +04:00
pumpurumer
9b64746c2e test commit 2022-09-28 15:07:39 +04:00
pumpurumer
34080a0ee0 build commit 2022-09-28 14:58:06 +04:00
pumpurumer
ff0f8d6fad rebuild 2022-09-28 14:54:07 +04:00
pumpurumer
988a05e94d rebuild commit 2022-09-28 14:35:27 +04:00
pumpurumer
5b9be577e7 rebuild commit 2022-09-28 14:34:31 +04:00
pumpurumer
615f708600 rebuild commit 2022-09-28 14:29:32 +04:00
pumpurumer
ba71eee97f rebuild commit 2022-09-28 14:28:29 +04:00
pumpurumer
06e0b8efe1 rebuild commit 2022-09-28 14:27:33 +04:00
pumpurumer
7a490e4599 build commit 2022-09-28 14:25:53 +04:00
pumpurumer
8b6af5fa21 build commit 2022-09-28 14:25:16 +04:00
55486de524 dev #12738 2022-09-27 22:53:36 +04:00
Kataev Denis
836af4e1ae dev #12738 2022-09-27 20:15:18 +04:00
Kataev Denis
9352d06e73 dev #12738
Сделал бранчу и добавил в нее jenkinsfile
2022-09-27 14:17:17 +04:00
138 changed files with 894 additions and 511 deletions

58
.gitignore vendored
View File

@ -1,42 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
angular/dist
angular/tmp
angular/out-tsc
angular/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
angular/node_modules
angular/npm-debug.log
angular/yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
angular/.idea/
angular/.project
angular/.classpath
angular/.c9/
angular/*.launch
angular/.settings/
angular/*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
angular/.vscode/*
angular/!.vscode/settings.json
angular/!.vscode/tasks.json
angular/!.vscode/launch.json
angular/!.vscode/extensions.json
angular/.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
angular/.angular/cache
angular/.sass-cache/
angular/connect.lock
angular/coverage
angular/libpeerconnection.log
angular/testem.log
angular/typings
# System files
.DS_Store
Thumbs.db
angular/.DS_Store
angular/Thumbs.db

View File

@ -1,4 +0,0 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"]
}

20
.vscode/launch.json vendored
View File

@ -1,20 +0,0 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "pwa-chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
}
]
}

42
.vscode/tasks.json vendored
View File

@ -1,42 +0,0 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
},
{
"type": "npm",
"script": "test",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
}
]
}

33
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,33 @@
env.HL_BUILD_MODE = "jenkins"
node('Lithium'){
stage('get new version to repo') {
checkout scm
if (lastCommitIsBumpCommit()) {
currentBuild.result = 'ABORTED'
error('Последний коммит - результат сборки jenkins')
}
sh "git checkout ${env.BRANCH_NAME}"
sh "git checkout -- ."
sh "git pull"
//sh "git submodule update --init --recursive"
//sh "git submodule update --remote --merge"
}
stage("build and publish"){
dir('angular'){
sh label: '', script: 'npm i'
sh label: '', script: 'npm run build'
}
}
}
private boolean lastCommitIsBumpCommit() {
lastCommit = sh([script: 'git log -1', returnStdout: true])
if (lastCommit.contains("Author: jenkins")) {
return true
} else {
return false
}
}

View File

@ -1,4 +1,5 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
@ -10,6 +11,7 @@
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
@ -17,8 +19,8 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "/var/www/lk/fashion-logica",
"baseHref": "/fashion-logica/",
"outputPath": "/var/www/html/lk.crm4retail.ru/fashion-logica",
"baseHref": "/",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
@ -28,7 +30,9 @@
"src/favicon.ico",
"src/assets",
"src/manifest.webmanifest",
"src/firebase-messaging-sw.js"
"src/firebase-messaging-sw.js",
"src/sw-master.js",
"src/sw-custom.js"
],
"styles": [
"node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",

View File

@ -1,12 +1,12 @@
{
"name": "fashion-logica",
"version": "0.0.0",
"version": "0.0.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "fashion-logica",
"version": "0.0.0",
"version": "0.0.2",
"dependencies": {
"@angular/animations": "^14.0.0",
"@angular/cdk": "^14.2.1",

View File

@ -1,9 +1,9 @@
{
"name": "fashion-logica",
"version": "0.0.1",
"version": "0.0.4",
"scripts": {
"ng": "ng",
"start": "ng serve --host 192.168.0.179",
"start": "ng serve --host 192.168.0.14",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"

View File

@ -6,5 +6,5 @@ import { Component } from '@angular/core';
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'fashion-logica';
title = 'Fashionlogica';
}

View File

@ -49,7 +49,7 @@ export const PageListWithBonus: Page[] = [
description: '',
resName: 'ref-system',
onSideBar: true,
},
}
];
export const orderStatuses: OrderStatus = {

View File

@ -32,6 +32,8 @@ import { QRCodeModule } from 'angularx-qrcode';
import { ShareButtonsModule } from 'ngx-sharebuttons/buttons';
import { ShareIconsModule } from 'ngx-sharebuttons/icons';
import { MessagingService } from './services/messaging.service';
import { NotFoundComponent } from './pages/not-found/not-found.component';
import { DownloadAppDirective } from './directives/download-app.directive';
@NgModule({
declarations: [
@ -47,7 +49,9 @@ import { MessagingService } from './services/messaging.service';
OrderInfoComponent,
FooterButtonsComponent,
UserDataComponent,
RefSystemComponent
RefSystemComponent,
NotFoundComponent,
DownloadAppDirective
],
imports: [
BrowserModule,
@ -56,7 +60,8 @@ import { MessagingService } from './services/messaging.service';
{
path: '**',
component: MainComponent
}
},
// { path: '**', component: NotFoundComponent }
]),
InputMaskModule,
ProgressSpinnerModule,
@ -64,7 +69,7 @@ import { MessagingService } from './services/messaging.service';
HttpClientModule,
BrowserAnimationsModule,
BrowserModule,
ServiceWorkerModule.register('ngsw-worker.js', {
ServiceWorkerModule.register('/sw-master.js', {
enabled: environment.production,
// Register the ServiceWorker as soon as the application is stable
// or after 30 seconds (whichever comes first).

View File

@ -1,12 +1,11 @@
<div class="footer-buttons-container">
<!-- *ngIf="deferredPrompt && token?.length" -->
<button
<!-- <button
*ngIf="((deviceType == 'android' && deferredPrompt) || deviceType == 'ios') && token?.length"
class="footer-buttons-container__button download"
(click)="downloadPWA()"
>
<img src="./assets/download.svg" alt="download" />
</button>
</button> -->
<button
*ngIf="!isPermissionNotifications && token?.length"
class="footer-buttons-container__button"

View File

@ -0,0 +1,24 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { MessageService } from 'primeng/api';
@Component({
selector: 'app-footer-buttons',
templateUrl: './footer-buttons.component.html',
styleUrls: ['./footer-buttons.component.scss']
})
export class FooterButtonsComponent implements OnInit {
@Input() token!: string;
@Input() isPermissionNotifications!: boolean;
@Output() requestingPermission = new EventEmitter<null>();
public deviceType: 'ios' | 'android' | null = null;
constructor(
) { }
ngOnInit(): void {
}
requestPermission() {
this.requestingPermission.emit(null)
}
}

View File

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

View File

@ -0,0 +1,85 @@
import {
Directive,
ElementRef,
HostListener,
OnInit,
Renderer2,
} from '@angular/core';
import { MessageService } from 'primeng/api';
@Directive({
selector: '[appDownloadApp]',
})
export class DownloadAppDirective implements OnInit {
public deviceType: 'ios' | 'android' | null = null;
public deferredPrompt: any;
constructor(
private messageService: MessageService,
public renderer: Renderer2,
private el: ElementRef
) {}
ngOnInit(): void {
this.getTypeDevice();
if (this.deviceType === 'ios') {
this.el.nativeElement.style.display = 'block';
}
}
@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';
}
getTypeDevice() {
const userAgent = window.navigator.userAgent.toLowerCase();
const ios = /iphone|ipod|ipad/.test(userAgent);
this.deviceType = ios ? 'ios' : 'android';
}
@HostListener('click', ['$event'])
downloadApp(event: MouseEvent) {
if (event) {
event.preventDefault();
}
if (this.deviceType === 'ios') {
this.messageService.add({
severity: 'custom',
summary: `Для установки нажмите на кнопку поделиться в Вашем браузере и выберите пункт 'На экран «Домой»'`,
life: 5000,
});
return;
}
if (!this.deferredPrompt) {
this.messageService.add({
severity: 'error',
summary: 'Не поддерживается в Вашем браузере!',
});
return;
}
this.deferredPrompt.prompt();
this.deferredPrompt.userChoice.then((res: any) => {
if (res.outcome === 'accepted') {
this.messageService.add({
severity: 'custom',
summary: 'Спасибо за установку!',
});
}
this.deferredPrompt = null;
});
}
}

View File

@ -1,4 +1,9 @@
<div class="woocommerce">
<div
[ngClass]="{
woocommerce: true,
'auth-page': currentPage.code === PageCode.Auth
}"
>
<div
*ngIf="currentPage.code !== PageCode.Auth"
class="top-left-attribute"
@ -40,6 +45,7 @@
>
<div class="container">
<img
style="width: 36px"
src="{{ './assets/menu-icons/' + page.resName + '.png' }}"
alt="Иконка меню"
/>
@ -50,6 +56,22 @@
</div>
</li>
</ng-container>
<li
class="woocommerce-MyAccount-navigation-link download-app"
appDownloadApp
>
<div class="container">
<img
style="width: 36px"
src="./assets/menu-icons/download-app.png"
alt="Иконка меню"
/>
<div class="menu-item-info">
<a href="#">Установить приложение</a>
<!-- <p>{{ page.description }}</p> -->
</div>
</div>
</li>
<li
class="woocommerce-MyAccount-navigation-link"
(click)="logout($event)"
@ -66,8 +88,7 @@
<span
class="version"
[ngClass]="{
version: true,
bottom: currentPage.code === PageCode.Auth
version: true
}"
>
v{{ version }}

View File

@ -2,11 +2,19 @@
.woocommerce {
min-height: calc(100vh - 39px);
padding: 20px 18px;
&.auth-page {
display: flex;
flex-direction: column;
justify-content: space-between;
}
nav {
margin-bottom: 24px;
margin-top: 26px;
display: flex;
justify-content: center;
ul {
max-width: 400px;
width: 100%;
@ -14,6 +22,7 @@
display: flex;
justify-content: space-between;
flex-direction: column;
li {
padding: 12px;
width: 100%;
@ -25,20 +34,29 @@
box-shadow: 0px 0px 5px rgb(0 0 0 / 15%);
color: #000;
border-radius: 15px;
&.is-active {
border: solid #09467f 1px;
// display: none;
}
&.first {
// border-radius: 7px 0 0 7px;
}
&.download-app {
display: none;
}
.container {
display: flex;
align-items: center;
height: 100%;
.menu-item-info {
margin-left: 16px;
& > a {
&>a {
font-style: normal;
font-weight: 700;
font-size: 18px;
@ -48,7 +66,8 @@
display: block;
text-align-last: left;
}
& > p {
&>p {
font-style: normal;
font-weight: 400;
font-size: 12px;
@ -58,11 +77,13 @@
}
}
}
li:nth-child(odd) {
background-color: #ebebeb;
}
}
}
.top-left-attribute {
width: 10px;
height: 5px;
@ -71,12 +92,9 @@
position: absolute;
top: 69px;
}
.version {
opacity: 0.5;
&.bottom {
position: absolute;
bottom: 8px;
}
}
}
}
}

View File

@ -9,6 +9,7 @@ import { ExitComponent } from '../../components/exit/exit.component';
import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
import { MessageService } from 'primeng/api';
import { lastValueFrom } from 'rxjs';
@Component({
selector: 'app-account',
@ -70,10 +71,24 @@ export class AccountComponent implements OnInit {
this.currentPage = this.pageList[1];
}
refSystem() {
async refSystem() {
const additionalInfo = (await lastValueFrom(
this.jsonRpcService.rpc({
method: 'getAdditionalInfo',
params: []
}, RpcService.authService, true)
)).data
this.route.queryParams.subscribe((params) => {
if (params['refCardNumber']) {
this.refSystemId = params['refCardNumber'];
if (params['refUserId']) {
if (additionalInfo.refSystem?.code.length) {
this.messageService.add({
severity: 'custom',
summary:
'Вы уже зарегестрированы в реферальной программе!',
});
return;
}
this.refSystemId = params['refUserId'];
this.jsonRpcService
.rpc(
{
@ -93,7 +108,7 @@ export class AccountComponent implements OnInit {
next: () => {
this.router.navigate([], {
queryParams: {
refCardNumber: null,
refUserId: null,
},
queryParamsHandling: 'merge',
});
@ -117,6 +132,10 @@ export class AccountComponent implements OnInit {
changePage(event: MouseEvent, page: Page): void {
event.preventDefault();
if (page.resName === 'download-app') {
return
}
this.currentPage = page;
// let params = new HttpParams();
// params = params.append('activePage', this.currentPage.code);

View File

@ -40,7 +40,7 @@
></p-progressSpinner>
</button>
</p>
<div class="decoration-pattern" style="background: url('./assets/card-decorative-pattern.png') no-repeat;"></div>
<div class="decoration-pattern"></div>
</form>
</ng-container>
<ng-template #confirmPhoneField>
@ -54,8 +54,7 @@
class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide"
>
<label for="code">
Введите 4 последних цифры позвонившего вам номера телефона. На звонок
отвечать не нужно.
Введите 4 цифры из смс, которое пришло на Ваш номер телефона
</label>
<input
pInputText
@ -94,6 +93,6 @@
<p style="color: red; margin: 0" *ngIf="errorConfirmCode">
Пароль введен неверно
</p>
<div class="decoration-pattern" style="background: url('./assets/card-decorative-pattern.png') no-repeat;"></div>
<div class="decoration-pattern"></div>
</form>
</ng-template>

View File

@ -102,5 +102,8 @@
.decoration-pattern {
width: calc(100% - 24px);
height: 34px;
background-image: url('../../../../assets/card-decorative-pattern.png');
background-repeat: no-repeat;
background-size: contain;
}
}

View File

@ -11,22 +11,19 @@
<!-- <div class="imgs-row"></div>
<div class="imgs-row" style="background-position-x: -22px;"></div>
<div class="imgs-row"></div> -->
<img src="./assets/card-decorative-pattern.svg" alt="" />
<img src="./assets/card-decorative-pattern.png" alt="" />
</div>
<div class="card-container__content">
<div class="info">
<div *ngIf="accountData" class="row">
<span class="key">Имя</span>
<span class="value" *ngIf="userName.length">{{
userName
<span class="value">{{
userName && userName.length ? userName : 'Не задано'
}}</span>
<span class="value" *ngIf="!userName.length"
>Не задано</span
>
</div>
<div *ngIf="accountData" class="row">
<span class="key">Баланс карты</span>
<span class="value">{{ accountData.Bonuses }}</span>
<span class="value">{{ bonuses }}</span>
</div>
</div>
<div class="card-container__barcode-container">
@ -47,4 +44,5 @@
</div>
</div>
</div>
<button *ngIf="deviceType == 'ios'" class="add-to-wallet" (click)="addCardToWallet($event)">Добавить в Apple Wallet</button>
</div>

View File

@ -3,14 +3,14 @@
display: flex;
flex-direction: column;
&>h2 {
& > h2 {
font-style: normal;
font-weight: 700;
font-size: 20px;
line-height: 24px;
}
&>p {
& > p {
font-style: normal;
font-weight: 400;
font-size: 15px;
@ -154,12 +154,12 @@
}
&.active_back {
>.card-content__front {
> .card-content__front {
transform: rotateY(180deg);
opacity: 0;
}
>.card-content__back {
> .card-content__back {
opacity: 1;
transform: rotateY(0deg);
}
@ -196,5 +196,16 @@
font-size: 12px;
margin-bottom: 8px;
}
.add-to-wallet {
height: 36px;
border-radius: 8px;
background: #09467f;
border-color: #09467f;
color: #fff;
max-width: 400px;
width: 100%;
margin: 12px auto 0;
}
}
}
}

View File

@ -0,0 +1,192 @@
import { Component, Inject, OnInit } from '@angular/core';
import { lastValueFrom } from 'rxjs';
import {
orderStatuses,
PageList,
PageListWithBonus,
} from 'src/app/app.constants';
import {
BonusProgramAccount,
Page,
Purchase,
Transaction,
} from 'src/app/interface/data';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
import * as moment from 'moment-timezone';
import * as barcode from 'jsbarcode';
import { environment } from 'src/environments/environment';
import { AppleWalletService } from 'src/app/services/apple-wallet.service';
import { CookiesService } from 'src/app/services/cookies.service';
import { DOCUMENT } from '@angular/common';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { MessageService } from 'primeng/api';
@Component({
selector: 'app-bonus-program',
templateUrl: './bonus-program.component.html',
styleUrls: ['./bonus-program.component.scss'],
})
export class BonusProgramComponent implements OnInit {
public accountData!: BonusProgramAccount;
public purchases: Purchase[] = [];
public loadingBonuses: boolean = false;
readonly orderStatuses = orderStatuses;
readonly moment = moment;
readonly pageList = environment.hasBonusProgram
? PageListWithBonus
: PageList;
public currentPage: Page = this.pageList[1];
public userName: string = '';
public deviceType: 'ios' | 'android' | null = null;
public bonuses: number = 0
constructor(
private jsonrpc: JsonrpcService,
private appleWallet: AppleWalletService,
private cookiesService: CookiesService,
@Inject(DOCUMENT) private document: Document,
private http: HttpClient,
private messageService: MessageService,
) {}
ngOnInit(): void {
this.getAccountData();
this.getTypeDevice();
}
getTypeDevice() {
const userAgent = window.navigator.userAgent.toLowerCase();
const ios = /iphone|ipod|ipad/.test(userAgent);
this.deviceType = ios ? 'ios' : 'android';
}
async getAccountData(): Promise<void> {
this.loadingBonuses = true;
this.jsonrpc
.rpc(
{
method: 'getAdditionalInfo',
params: [],
},
RpcService.authService,
true
)
.subscribe({
next: (res) => {
this.userName = res?.data?.first_name;
},
error: (err) => {
console.error('Error: ', err);
},
});
const getAccount = await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'GetAccounts',
params: [],
},
RpcService.bonusService
)
);
this.accountData = getAccount && getAccount['Cards'][0];
this.bonuses = this.accountData.BonusProgramAccounts?.reduce((previous, {Bonuses}) => {
return previous + Bonuses
}, 0) || this.accountData.Bonuses
this.loadingBonuses = false;
if (this.accountData) {
barcode('#barcode')
.options({ font: 'OCR-B' }) // Will affect all barcodes
.EAN13(`${this.accountData.CardNumber}`.padStart(12, '0'), {
fontSize: 18,
textMargin: 0,
})
.render();
}
const getTransactions = (
await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'GetAccountTransactions',
params: [],
},
RpcService.bonusService
)
)
)
if (!getTransactions) {
this.messageService.add({severity:'error', summary:'Произошла ошибка, попробуйте позже'});
return
}
const transactions: Transaction[] = getTransactions && getTransactions['Transactions'];
const getPurchases = (
await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'GetAccountPurchase',
params: [],
},
RpcService.bonusService
)
)
)
if (!getPurchases) {
this.messageService.add({severity:'error', summary:'Произошла ошибка, попробуйте позже'});
return
}
const purchases: Purchase[] = getPurchases && getPurchases['Purchases'];
this.purchases = purchases && purchases.map<Purchase>((purchase) => {
const id = purchase.ID.slice(0, 36).toLowerCase();
purchase.Transactions = transactions.filter((transaction) => {
const same = transaction.Purchase === id;
transaction.HasPurchase = same;
return same;
});
return purchase;
});
transactions && transactions.forEach((transaction) => {
if (!transaction.HasPurchase) {
this.purchases.push({
ID: transaction.ID,
PurchaseDate: transaction.Date,
Transactions: [transaction],
IsSingleTransaction: true,
});
}
});
this.purchases = this.purchases && this.purchases.sort((a, b) => {
return moment(a.PurchaseDate).date() - moment(b.PurchaseDate).date();
});
}
async addCardToWallet(e: any) {
e.preventDefault();
const token = this.cookiesService.getItem('token');
const accountData = (
await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'getTokenData',
params: [],
},
RpcService.authService,
true
)
)
).data;
if (token && accountData.user_id) {
this.appleWallet.generateCard(token, accountData.user_id).subscribe({
next: (res: any) => {
this.document.location.href = res.url;
},
error: (err) => {
console.log('Error: ', err);
},
});
}
}
}

View File

@ -67,7 +67,7 @@
</tbody>
</table>
<p
*ngIf="purchases.length !== purchasesShortArray.length"
*ngIf="purchases?.length !== purchasesShortArray?.length"
class="show-more-orders"
(click)="getMoreOrders()"
>
@ -75,12 +75,13 @@
</p>
<p-progressSpinner
*ngIf="ordersLoadingStatus"
[style]="{ width: '100%' }"
[style]="{ display: 'block' }"
strokeWidth="2"
styleClass="angular-spinner"
></p-progressSpinner>
<p
*ngIf="purchases.length === 0 && !ordersLoadingStatus"
*ngIf="purchases?.length === 0 && !ordersLoadingStatus"
class="no-orders"
style="width: 100%; text-align: center"
>
Нет заказов

View File

@ -0,0 +1,76 @@
.show-more-orders {
text-align: center;
cursor: pointer;
color: #09467f;
margin-top: 16px;
}
.woocommerce-MyAccount-content {
max-width: 400px;
margin-left: calc(50vw - 200px);
}
.woocommerce-orders-table {
border: 2px solid #dee2e6;
border-bottom: 0;
border-radius: 0.25rem;
border-collapse: separate;
text-align: left;
margin-top: 8px;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
thead {
display: none;
}
.woocommerce-orders-table {
&__cell {
padding: 0.7rem 1.5rem;
border-bottom: 2px solid #dee2e6;
text-align: right !important;
display: block;
&::before {
content: attr(data-title) ": ";
font-weight: 700;
float: left;
}
}
&__row {
display: block;
&:nth-child(even) {
background: #ebebeb;
}
}
// &__cell-order-actions::before {
// display: none;
// }
&__cell-order-actions {
&.red-color {
color: #ed0000;
}
&.green-color {
color: #00a700;
}
}
&__cell-order-number a {
text-decoration: none;
color: #009688;
}
}
.woocommerce-button {
display: inline-block;
color: #ffffff;
background-color: #009688;
padding: 13px;
border-radius: 4px;
text-decoration: none;
width: 100%;
text-align: center;
}
}
.no-orders {
width: 100%;
text-align: center;
margin-top: 16px;
}

View File

@ -5,11 +5,12 @@ import { Purchase } from 'src/app/interface/data';
import * as moment from 'moment-timezone';
import { lastValueFrom } from 'rxjs';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
import { MessageService } from 'primeng/api';
@Component({
selector: 'app-orders',
templateUrl: './orders.component.html',
styleUrls: ['./orders.component.scss']
styleUrls: ['./orders.component.scss'],
})
export class OrdersComponent implements OnInit {
@Input() handleHttpError!: (error: HttpErrorResponse) => void;
@ -23,24 +24,31 @@ export class OrdersComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private jsonrpc: JsonrpcService,
) { }
private messageService: MessageService,
) {}
ngOnInit(): void {
this.getOrders()
this.getOrders();
}
async getOrders(){
const purchases: Purchase[] = (await lastValueFrom(
async getOrders() {
const getPurchases = await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'GetAccountPurchase',
params: []
params: [],
},
RpcService.bonusService
)))['Purchases'];
)
);
if (!getPurchases) {
this.messageService.add({severity:'error', summary:'Произошла ошибка, попробуйте позже'});
return
}
const purchases: Purchase[] = getPurchases && getPurchases['Purchases'];
this.purchases = purchases.map<Purchase>((purchase) => {
const id = purchase.ID.slice(0,36).toLowerCase();
this.purchases = purchases && purchases.map<Purchase>((purchase) => {
const id = purchase.ID.slice(0, 36).toLowerCase();
// purchase.Transactions = transactions.filter((transaction) => {
// const same = transaction.Purchase === id;
// transaction.HasPurchase = same;
@ -48,7 +56,7 @@ export class OrdersComponent implements OnInit {
// });
return purchase;
});
this.purchasesShortArray = this.purchases.slice(0, this.lastViewOrder)
this.purchasesShortArray = this.purchases && this.purchases.slice(0, this.lastViewOrder);
this.ordersLoadingStatus = false;
}

View File

@ -13,6 +13,7 @@
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
img {
height: 26px;
}
@ -25,6 +26,7 @@
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
}
}

View File

@ -11,7 +11,7 @@ import { environment } from 'src/environments/environment';
styleUrls: ['./ref-system.component.scss']
})
export class RefSystemComponent implements OnInit {
public refUrl: string = `${environment.defaultUrl}/?refCardNumber=`
public refUrl: string = `${environment.defaultUrl}/?refUserId=`
public loading: boolean = true;
constructor(
@ -21,13 +21,18 @@ export class RefSystemComponent implements OnInit {
async ngOnInit() {
const accountData = (await lastValueFrom(
this.jsonrpc.rpc({
method: 'GetAccounts',
params: []
},
RpcService.bonusService
)))['Cards'][0]
this.refUrl += accountData.CardNumber
this.jsonrpc
.rpc(
{
method: 'getTokenData',
params: [],
},
RpcService.authService,
true
)
)).data
this.refUrl += accountData.user_id
this.loading = false
}
@ -35,30 +40,30 @@ export class RefSystemComponent implements OnInit {
if (navigator.share) {
navigator.share({
title: document.title,
text: "Fashion Logica",
text: "Fashionlogica",
url: this.refUrl
})
.then(() => console.log('Successful share'))
.catch((error) => {
console.log('Error sharing:', error)
});
.then(() => console.log('Successful share'))
.catch((error) => {
console.log('Error sharing:', error)
});
}
}
copyUrl() {
navigator.clipboard.writeText(this.refUrl)
.then(() => {
this.messageService.add({
severity: 'custom',
summary: 'Ссылка скопирована!',
.then(() => {
this.messageService.add({
severity: 'custom',
summary: 'Ссылка скопирована!',
});
})
.catch(err => {
this.messageService.add({
severity: 'error',
summary: 'Произошла ошибка!',
});
});
})
.catch(err => {
this.messageService.add({
severity: 'error',
summary: 'Произошла ошибка!',
});
});
}
}

View File

@ -75,12 +75,12 @@
<div class="decoration-pattern">
<img
style="height: 34px"
src="./assets/card-decorative-pattern.svg"
src="./assets/card-decorative-pattern.png"
alt=""
/>
<img
style="height: 16px; margin-left: 2px"
src="./assets/card-decorative-pattern.svg"
src="./assets/card-decorative-pattern.png"
alt=""
/>
</div>

View File

@ -1,7 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MessageService } from 'primeng/api';
import { lastValueFrom } from 'rxjs';
import { UserDataForm } from 'src/app/interface/data';
import { AppleWalletService } from 'src/app/services/apple-wallet.service';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
@Component({
@ -21,6 +23,8 @@ export class UserDataComponent implements OnInit {
constructor(
private jsonRpcService: JsonrpcService,
private messageService: MessageService,
private appleWallet: AppleWalletService,
private jsonrpc: JsonrpcService,
) { }
ngOnInit(): void {
@ -30,6 +34,14 @@ export class UserDataComponent implements OnInit {
params: []
}, RpcService.authService, true).subscribe({
next: (res) => {
if (res.code === 45) {
this.messageService.add({severity:'warn', summary:'Данные не найдены, заполните их на этой странице'});
return
}
if (!res.data) {
this.messageService.add({severity:'error', summary:'Произошла ошибка, попробуйте позже'});
return
}
const { first_name, birthdate, gender } = res.data
this.userData = { first_name, birthdate, gender }
this.createUserDataForm({...this.userData})
@ -59,8 +71,29 @@ export class UserDataComponent implements OnInit {
method: 'updateAdditionalInfo',
params: [this.userData]
}, RpcService.authService, true).subscribe({
next: () => {
next: async () => {
this.messageService.add({severity:'custom', summary:'Данные успешно обновлены!'});
const accountData = (await lastValueFrom(
this.jsonrpc
.rpc(
{
method: 'getTokenData',
params: [],
},
RpcService.authService,
true
)
)).data
if (accountData.user_id) {
this.appleWallet.reloadCard(accountData.user_id).subscribe({
next: (value) => {
console.log(value);
},
error: (err) => {
console.error(err);
}
})
}
},
error: (err) => {
console.error('Error: ', err)

View File

@ -1,7 +1,7 @@
<div class="main-container">
<app-navbar></app-navbar>
<p-toast position="top-center"></p-toast>
<app-footer-buttons [token]="token" [deferredPrompt]="deferredPrompt"
[isPermissionNotifications]="isPermissionNotifications" (downloadingPWA)="downloadPWA()"
<app-footer-buttons [token]="token"
[isPermissionNotifications]="isPermissionNotifications"
(requestingPermission)="requestPermission()"></app-footer-buttons>
</div>

View File

@ -24,7 +24,6 @@ export class MainComponent implements OnInit {
private cardComponent!: ComponentRef<CardComponent>;
private accountComponent!: ComponentRef<AccountComponent>;
public messagingToken!: string | null;
public deferredPrompt: any;
public isPermissionNotifications: boolean = false;
public token = '';
public message: any;
@ -32,20 +31,12 @@ export class MainComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private viewContainerRef: ViewContainerRef,
private afMessaging: AngularFireMessaging,
public el: ElementRef,
public renderer: Renderer2,
private messageService: MessageService,
private messagingService: MessagingService,
private messageService: MessageService,
private cookiesService: CookiesService,
) {
renderer.listen('window', 'appinstalled', (evt) => {
console.log('INSTALLED!!!');
});
renderer.listen('window', 'beforeinstallprompt', (e) => {
e.preventDefault();
this.deferredPrompt = e;
});
route.queryParams.subscribe((params) => {
if (params['token']) {
this.token = params['token']
@ -61,35 +52,20 @@ export class MainComponent implements OnInit {
// this.checkRequestPermission()
}
downloadPWA() {
if (!this.deferredPrompt) {
this.messageService.add({
severity: 'error',
summary: 'Не поддерживается в Вашем браузере!',
});
return;
}
this.deferredPrompt.prompt();
this.deferredPrompt.userChoice.then((res: any) => {
if (res.outcome === 'accepted') {
this.messageService.add({
severity: 'custom',
summary: 'Спасибо за установку!',
});
console.log('User Accepted!!!');
}
this.deferredPrompt = null;
});
}
checkRequestPermission() {
this.isPermissionNotifications =
Notification.permission !== 'granted' ? false : true;
}
requestPermission() {
if ('safari' in window) {
console.log('safari');
const userAgent = window.navigator.userAgent.toLowerCase();
const ios = /iphone|ipod|ipad/.test(userAgent);
if (ios) {
this.messageService.add({
severity: 'custom',
summary: `Чтобы получать уведомления, добавьте карту в Apple Wallet`,
life: 5000,
});
// var permissionData = window.safari.pushNotification.permission('web.com.example.domain');
// $scope.checkRemotePermission(permissionData);
@ -100,20 +76,6 @@ export class MainComponent implements OnInit {
this.message = this.messagingService.currentMessage;
}
}
// test function
copyMessage(val: string | null) {
const selBox = document.createElement('textarea');
selBox.style.position = 'fixed';
selBox.style.left = '0';
selBox.style.top = '0';
selBox.style.opacity = '0';
if (val) selBox.value = val;
document.body.appendChild(selBox);
selBox.focus();
selBox.select();
document.execCommand('copy');
document.body.removeChild(selBox);
}
appendCard(): void {
const route = this.route.snapshot.url[0]?.path;

View File

@ -0,0 +1,8 @@
<div class="not-found-page">
<app-navbar></app-navbar>
<div class="not-found-page__container">
<h1>404</h1>
<p>Упс, что-то пошло не так!</p>
<button (click)="routeHome()">Вернуться на главную</button>
</div>
</div>

View File

@ -0,0 +1,28 @@
:host {
.not-found-page {
&__container {
text-align: center;
margin-top: 32px;
h1 {
font-size: 108px;
font-weight: 600;
color: #09467f;
}
p {
margin: 16px 0;
font-size: 14px;
}
button {
background-color: #09467f;
color: #fff;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
padding: 12px;
margin: 0 auto;
border: 0;
}
}
}
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NotFoundComponent } from './not-found.component';
describe('NotFoundComponent', () => {
let component: NotFoundComponent;
let fixture: ComponentFixture<NotFoundComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NotFoundComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(NotFoundComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,20 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-not-found',
templateUrl: './not-found.component.html',
styleUrls: ['./not-found.component.scss']
})
export class NotFoundComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit(): void {
}
routeHome() {
this.router.navigate(['/']);
}
}

View File

@ -0,0 +1,35 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
@Injectable({
providedIn: 'root',
})
export class AppleWalletService {
private url: string = environment.appleWalletEndpoint;
constructor(
private http: HttpClient,
) {}
generateCard(token: string, user_id: string) {
let headers = new HttpHeaders();
headers = headers.set('Authorization', environment.appleWalletSecret);
const options = {
headers: headers,
};
return this.http.get(`${this.url}/client/${environment.clientName}/passUrl/${user_id}/token/${token}`, options)
}
reloadCard(user_id:string) {
let headers = new HttpHeaders();
headers = headers.set('Authorization', environment.appleWalletSecret);
const options = {
headers: headers,
};
const body = {
text: '',
isUpdateCard: true
}
return this.http.post(`${this.url}/sendNotification/${user_id}`, body, options)
}
}

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { AngularFireMessaging } from '@angular/fire/compat/messaging';
import { MessageService } from 'primeng/api';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, lastValueFrom } from 'rxjs';
import { JsonrpcService, RpcService } from './jsonrpc.service';
@Injectable()
@ -19,15 +19,29 @@ export class MessagingService {
});
}
updateToken(token: string | null) {
async updateToken(token: string | null) {
if (!token) return;
const additionalInfo = (await lastValueFrom(
this.jsonRpcService.rpc({
method: 'getAdditionalInfo',
params: []
}, RpcService.authService, true)
)).data
let tokens: string[] = []
if (typeof additionalInfo['fmc-token'] === 'string') {
tokens.push(additionalInfo['fmc-token'], token)
} else if (typeof additionalInfo['fmc-token'] === 'object') {
tokens = [...additionalInfo['fmc-token'], token]
} else {
tokens = [token]
}
this.jsonRpcService
.rpc(
{
method: 'updateAdditionalInfo',
params: [
{
'fmc-token': token,
'fmc-token': tokens,
},
],
},
@ -70,6 +84,11 @@ export class MessagingService {
receiveMessage() {
this.angularFireMessaging.messages.subscribe((payload: any) => {
console.log('new message received. ', payload);
const NotificationOptions = {
body: payload.notification.body,
data: payload.data,
icon: payload.notification.icon
}
this.currentMessage.next(payload);
});
}

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

Before

Width:  |  Height:  |  Size: 861 B

After

Width:  |  Height:  |  Size: 861 B

View File

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 992 B

Some files were not shown because too many files have changed in this diff Show More