Compare commits

...

165 Commits
master ... more

Author SHA1 Message Date
nikolay
ea66abfcd1 dev #14607 Море. Правки по сайту: add href to doc on word "условия" on login page 2023-08-11 10:06:12 +04:00
7c48e1dc1e #14726
изменил фоновую картинку в карте валлет
2023-07-12 16:03:19 +04:00
feeed2c640 Merge branch 'more' of https://git.hlcompany.ru/git/usersite into more 2023-07-11 14:24:09 +04:00
46059461db #14726
изменил картинки в карте валлет
2023-07-11 14:23:55 +04:00
nikolay
14c2af863b dev #14607 Море. Правки по сайту: change size of agree info on login page 2023-07-06 11:16:58 +04:00
nikolay
cc192a6b0f dev #14607 Море. Правки по сайту: fix input border color on hover 2023-07-05 16:17:48 +04:00
nikolay
1b8cb2b185 dev #14607 Море. Правки по сайту: remove date input blur 2023-07-05 15:38:42 +04:00
nikolay
eb15e47328 dev #14607 Море. Правки по сайту: set cursor position at beginning of date input on focus 2023-07-05 15:25:58 +04:00
nikolay
73de9ea6b7 dev #14607 Море. Правки по сайту: fix mask 2023-07-05 14:50:43 +04:00
nikolay
c1219e1637 dev #14607 Море. Правки по сайту: remove datepicker and add date mask 2023-07-05 14:21:19 +04:00
nikolay
9fd031f423 dev #14607 Море. Правки по сайту:
change agree info;
remove add to apple wallet notification;
fix apple wallet generation;
2023-07-04 15:45:43 +04:00
nikolay
7fe4b6de52 dev #14607 Море. Правки по сайту:
add agree information;
remove uncessary user update;
2023-07-04 15:03:57 +04:00
nikolay
55c98f5aa1 dev #14607 Море. Правки по сайту: remove menu item "about app" 2023-07-04 11:27:29 +04:00
nikolay
75ddd847f3 dev #14607 Море. Правки по сайту: add app to apple wallet on login and register 2023-07-04 10:41:12 +04:00
nikolay
e5c2e0efe4 dev #14607 Море. Правки по сайту: add icons and fix some styles 2023-07-03 12:18:09 +04:00
nikolay
54795be75a dev #14607 Море. Правки по сайту: add registration form 2023-07-03 09:46:22 +04:00
nikolay
0e5e7e1d84 dev #14607 Море. Правки по сайту: fixes 2023-06-30 13:38:43 +04:00
nikolay
4c7b5437df dev #14607 Море. Правки по сайту: show all bonuses 2023-06-29 16:09:56 +04:00
nikolay
e640539d96 dev #14607 Море. Правки по сайту: fix notification and auth new_customer 2023-06-29 15:35:34 +04:00
nikolay
7808270bb4 dev #14607 Море. Правки по сайту: some fixes 2023-06-29 14:22:29 +04:00
nikolay
e12eb7a542 dev #14607 Море. Правки по сайту: add apple wallet and logo 2023-06-29 12:53:32 +04:00
nikolay
0abdb264f5 dev #14607 Море. Правки по сайту: change interface and api 2023-06-29 11:53:38 +04:00
tosandriy
06f668cd3d changed system id 2023-06-28 15:17:11 +04:00
b6483f78a7 dev #14600
изменил путь сборки
2023-06-28 13:17:36 +04:00
9b3488775c dev #14600
изменил названия для новой ветки
2023-06-28 11:56:16 +04:00
nikolay
e5ae004a29 dev #14384 Правка ошибок отображения WPA КофеЛайк: show only one message at a time and fix header 2023-06-27 16:01:12 +04:00
nikolay
142ece15de dev #14384 Правка ошибок отображения WPA КофеЛайк: add banner 2023-06-27 15:37:52 +04:00
nikolay
c9bcf3fc15 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix login form 2023-06-27 14:22:52 +04:00
nikolay
9e7394e848 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix last purchase 2023-06-26 10:40:10 +04:00
nikolay
8ea4a41786 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix last purchase 2023-06-26 10:24:18 +04:00
nikolay
7fa882e423 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix mistake 2023-06-23 14:36:24 +04:00
nikolay
03771d2012 dev #14384 Правка ошибок отображения WPA КофеЛайк: show info when wallet balance is negative 2023-06-23 13:33:02 +04:00
nikolay
3ff34525ed dev #14384 Правка ошибок отображения WPA КофеЛайк: fix logout and login, change ios header 2023-06-23 11:06:28 +04:00
nikolay
4e0a41b644 dev #14384 Правка ошибок отображения WPA КофеЛайк: add auth service to store information about user and fix getUserInfo 2023-06-23 09:32:20 +04:00
nikolay
e20cd30a54 dev #14562 Добавить меню для iOS WPA: fix z index of menu 2023-06-22 12:48:08 +04:00
nikolay
abdb5b790c dev #14562 Добавить меню для iOS WPA: remove back arrow on ios on guest card 2023-06-22 12:32:02 +04:00
nikolay
10e180613f dev #14562 Добавить меню для iOS WPA: remove install app 2023-06-22 11:56:00 +04:00
nikolay
6d55ca2b14 dev #14384 Правка ошибок отображения WPA КофеЛайк: check if app is in installed apps 2023-06-22 11:48:12 +04:00
nikolay
fcdb3d8fc7 dev #14384 Правка ошибок отображения WPA КофеЛайк: add getInstalledrelatedApps log 2023-06-22 11:35:06 +04:00
nikolay
0ae4e31cfd dev #14562 Добавить меню для iOS WPA 2023-06-22 11:09:52 +04:00
nikolay
50ae2b601e dev #14384 Правка ошибок отображения WPA КофеЛайк: fix install button 2023-06-21 11:41:50 +04:00
nikolay
798ec5e21a dev #14384 Правка ошибок отображения WPA КофеЛайк: change keydown to input on code enter listener 2023-06-21 10:27:05 +04:00
nikolay
15e9fe7ec4 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix sms enter code in safari 2023-06-21 10:06:11 +04:00
nikolay
26b2e8eb13 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix sms enter code on ios 2023-06-20 12:28:35 +04:00
nikolay
7b5200d9f8 auto fill sms 2023-06-20 10:12:32 +04:00
nikolay
d66f72dc2e dev #14537 Добавить кнопку подписки на уведомления CL 2023-06-19 10:04:45 +04:00
nikolay
0ca219c7fa dev #14525 Заменить текст WPA CoffeeLike 2023-06-15 17:09:03 +04:00
nikolay
1a6345431d change firebase config 2023-06-15 16:49:41 +04:00
nikolay
bef4ed1a48 dev #14494 WPA CoffeeLike изменить апи для получения последней транзакции 2023-06-15 15:49:33 +04:00
nikolay
eef97fd35f dev #14494 WPA CoffeeLike изменить апи для получения последней транзакции 2023-06-15 15:40:19 +04:00
nikolay
a8062667df fix jenkinsfile 2023-06-15 15:07:28 +04:00
nikolay
46d10e50ea change jenkins node 2023-06-15 14:35:43 +04:00
nikolay
ccaa41ddf9 dev #14490 WPA CoffeeLike добавление в wallet вместо установки для iOS: fix url 2023-06-15 11:44:35 +04:00
nikolay
0e38321526 dev #14507 Авто подписка на уведомления для андроид WPA Кофелайк 2023-06-14 15:36:02 +04:00
nikolay
4e52e180d8 add logging 2023-06-14 09:18:49 +04:00
nikolay
30854f4cb9 dev #14490 WPA CoffeeLike добавление в wallet вместо установки для iOS 2023-06-13 15:31:04 +04:00
nikolay
425ef99af2 dev #14495 WPA CoffeeLike добавить ссылку на Правила 2023-06-13 13:33:35 +04:00
nikolay
b29f2e1fdf dev #14490 WPA CoffeeLike добавление в wallet вместо установки для iOS 2023-06-09 12:18:09 +04:00
nikolay
5c3e4a0368 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix dependencies 2023-05-31 16:07:16 +04:00
nikolay
077b60fc87 dev #14384 Правка ошибок отображения WPA КофеЛайк: upgrade angular to 15 2023-05-31 15:57:54 +04:00
nikolay
e06d703b69 dev #14384 Правка ошибок отображения WPA КофеЛайк: change build command 2023-05-31 09:40:59 +04:00
nikolay
cfe370e3e3 Merge branch 'coffee-like-test' of https://git.hlcompany.ru/git/usersite into coffee-like-test 2023-05-29 16:16:39 +04:00
nikolay
e3fd36b881 dev #14384 Правка ошибок отображения WPA КофеЛайк: fix issue 2023-05-29 16:16:12 +04:00
1b1dcd9b50 Merge branch 'coffee-like-test' of https://git.hlcompany.ru/git/usersite into coffee-like-test 2023-05-26 10:42:13 +04:00
bb7e39f885 Поменял логотип для светлой темы 2023-05-26 10:41:49 +04:00
nikolay
b31bd30161 dev #14305 Изменение дизайна WPA Кофе-лайка: change styles 2023-05-25 16:57:04 +04:00
nikolay
7d098d1798 dev #14305 Изменение дизайна WPA Кофе-лайка: change styles 2023-05-25 16:43:27 +04:00
nikolay
7bade7caea dev #14305 Изменение дизайна WPA Кофе-лайка: fix infinity loading when login (typescript error) 2023-05-23 12:36:10 +04:00
238b70e95b dev #14338
Правка стилей
2023-05-20 21:51:07 +04:00
877cf018af dev #14338
добавил кнопку установки pwa
2023-05-20 16:09:36 +04:00
nikolay
24edd456db dev #14328 Добавить префикс в формирование QR: remove + 2023-05-18 15:33:22 +04:00
nikolay
cff512c561 Merge branch 'coffee-like-test' of https://git.hlcompany.ru/git/usersite into coffee-like-test 2023-05-18 09:55:11 +04:00
nikolay
6b60c4d8c4 dev #14328 Добавить префикс в формирование QR: change phone value in qr 2023-05-18 09:50:20 +04:00
04884bd0d9 Merge branch 'coffee-like-test' of https://git.hlcompany.ru/git/usersite into coffee-like-test 2023-05-17 12:12:41 +04:00
6c283812e7 dev #14318
добавил регистрацию юзера в айкокард, если его нет
2023-05-17 12:12:25 +04:00
nikolay
c5e4f3c229 dev #14305 Изменение дизайна WPA Кофе-лайка: block user with no info 2023-05-17 11:42:50 +04:00
nikolay
2fa05b391e dev #14305 Изменение дизайна WPA Кофе-лайка: change loyality program page 2023-05-16 15:38:21 +04:00
nikolay
ff9e04ecbd dev #14305 Изменение дизайна WPA Кофе-лайка: fix manifest 2023-05-16 11:53:23 +04:00
nikolay
28ab33248d dev #14305 Изменение дизайна WPA Кофе-лайка: fix manifest 2023-05-16 11:51:02 +04:00
nikolay
659e9d50bf dev #14305 Изменение дизайна WPA Кофе-лайка: fix manifest 2023-05-16 11:45:31 +04:00
nikolay
43980516ff dev #14305 Изменение дизайна WPA Кофе-лайка: change icons 2023-05-16 11:40:12 +04:00
nikolay
ca0fa2bfa6 dev #14305 Изменение дизайна WPA Кофе-лайка: change loading 2023-05-16 11:04:25 +04:00
nikolay
b81ee7f713 dev #14305 Изменение дизайна WPA Кофе-лайка: change qr code color to white 2023-05-16 09:11:28 +04:00
nikolay
044144735d dev #14305 Изменение дизайна WPA Кофе-лайка: change qr code color 2023-05-15 14:32:32 +04:00
nikolay
6feeec80f2 dev #14305 Изменение дизайна WPA Кофе-лайка: round bonuses count 2023-05-15 13:45:49 +04:00
e062f05f36 Merge remote-tracking branch 'remotes/origin/coffee-like' into coffee-like-test 2023-05-15 12:20:24 +04:00
bf3fd7e0a4 dev #13995
убарл очепятку
2023-05-15 12:10:26 +04:00
37ad910e75 dev #13995
добавил обновление имени и даты рождения(заглшка, чтобы работал костыль в СА) при авторизации
2023-05-15 12:08:22 +04:00
4a492f16e8 dev #13995
перенес изменения Николая из основной директории в дефолтный вариант представления
2023-05-15 11:52:27 +04:00
1e7175e3b5 dev #13995
сделал тестовую ветку , поменял в ней названия
2023-05-15 10:43:44 +04:00
be7c62a12b dev #13995
поменял иконки
2023-05-15 10:30:20 +04:00
6a075ec773 Merge branch 'coffee-like' of https://git.hlcompany.ru/git/usersite into coffee-like 2023-05-12 20:18:37 +04:00
86ac20f5e5 dev #13995
изменил структуру под аб тестирование, сделал 2 различных вариант (один дефолтный, другой с красным текстом)
модули загружаются лениво, для оптимизации загрузки приложения
пофиксил подсчет суммы транзакций за периоды
2023-05-12 20:10:06 +04:00
nikolay
2131e052c6 issue 14305: change styles 2023-05-12 16:21:46 +04:00
nikolay
787bc65691 change styles 2023-05-12 15:10:44 +04:00
04ecbb837c dev #13995
Исправил баги, доработал таймер для отправки повторного кода и сделал обработку ошибок при авторизации
2023-05-10 13:11:41 +04:00
77ecb32411 dev #13995
правка
2023-05-10 11:07:00 +04:00
9e1cad31f3 dev #13995
поменял версию
2023-05-10 02:40:47 +04:00
7c3a4168c4 dev #13995
поменял фавикон и другие доработки
2023-05-10 02:39:33 +04:00
76f1799b22 dev #14249
Информация по транзакциям
2023-05-10 02:38:17 +04:00
42b46bc478 dev #13995 2023-05-02 11:39:19 +04:00
af60b55e94 dev #13995
припилил СА, iikocard (но пока только customer_info), доработки
2023-04-25 19:10:14 +04:00
1da7556aed dev #13995
первоначальная верстка
2023-04-18 15:05:02 +04:00
f460954bc8 initial 2023-04-06 23:48:00 +04:00
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
295 changed files with 15245 additions and 6245 deletions

View File

@ -1,16 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

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

30
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,30 @@
env.HL_BUILD_MODE = "jenkins"
node('Palladium'){
stage('get new version to repo') {
checkout scm
if (lastCommitIsBumpCommit()) {
currentBuild.result = 'ABORTED'
error('Последний коммит - результат сборки jenkins')
}
//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,122 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"fashion-logica": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "/var/www/lk/fashion-logica",
"baseHref": "/fashion-logica/",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets",
"src/manifest.webmanifest",
"src/firebase-messaging-sw.js"
],
"styles": [
"node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
"node_modules/primeicons/primeicons.css",
"node_modules/primeng/resources/primeng.min.css",
"node_modules/ngx-sharebuttons/themes/modern.scss",
"node_modules/ngx-sharebuttons/themes/material.scss",
"src/styles.scss"
],
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "4mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "fashion-logica:build:production"
},
"development": {
"browserTarget": "fashion-logica:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "fashion-logica:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/firebase-messaging-sw.js",
"src/assets",
"src/manifest.webmanifest"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
},
"cli": {
"analytics": false
}
}

View File

@ -1,4 +1,4 @@
# FashionLogica
# CoffeeLikeMore
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.0.6.

131
angular/angular.json Normal file
View File

@ -0,0 +1,131 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"coffee-like-more": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"i18n": {
"sourceLocale": "ru-RU"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "/var/www/html/lk.crm4retail.ru/more",
"baseHref": "/",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets",
"src/manifest.webmanifest",
"src/firebase-messaging-sw.js",
"src/sw-master.js",
"src/sw-custom.js"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
"node_modules/primeicons/primeicons.css",
"node_modules/primeng/resources/primeng.min.css",
"node_modules/ngx-sharebuttons/themes/modern.scss",
"node_modules/ngx-sharebuttons/themes/material.scss",
"src/styles.scss"
],
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "4mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "coffee-like-more:build:production"
},
"development": {
"browserTarget": "coffee-like-more:build:development",
"proxyConfig": "proxy.confi.json"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "coffee-like-more:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/firebase-messaging-sw.js",
"src/assets",
"src/manifest.webmanifest"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/purple-green.css",
"src/styles.scss"
],
"scripts": []
}
}
}
}
},
"cli": {
"analytics": false
}
}

File diff suppressed because it is too large Load Diff

63
angular/package.json Normal file
View File

@ -0,0 +1,63 @@
{
"name": "coffee-like-more",
"version": "0.0.2",
"scripts": {
"ng": "ng",
"start": "ng serve --host 192.168.0.14",
"build": "ng build --aot --configuration production --output-hashing none",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^15.2.9",
"@angular/cdk": "^15.2.9",
"@angular/common": "^15.2.9",
"@angular/compiler": "^15.2.9",
"@angular/core": "^15.2.9",
"@angular/fire": "^7.5.0",
"@angular/forms": "^15.2.9",
"@angular/material": "^15.2.9",
"@angular/material-moment-adapter": "^15.2.9",
"@angular/platform-browser": "^15.2.9",
"@angular/platform-browser-dynamic": "^15.2.9",
"@angular/router": "^15.2.9",
"@angular/service-worker": "^15.2.9",
"@fortawesome/angular-fontawesome": "^0.12.1",
"@fortawesome/fontawesome-svg-core": "^6.2.0",
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@types/uuid": "^8.3.4",
"@types/web": "^0.0.99",
"angular-moment-timezone": "^1.7.1",
"angular2-text-mask": "^9.0.0",
"barcode-2-svg": "^0.3.3",
"firebase": "^9.9.3",
"google-libphonenumber": "^3.2.30",
"jsbarcode": "^3.11.5",
"libphonenumber-js": "^1.10.28",
"ng-qrcode": "^8.0.1",
"ngx-mat-intl-tel-input": "^5.0.0",
"ngx-sharebuttons": "^11.0.0",
"primeicons": "^5.0.0",
"primeng": "^15.4.1",
"rxjs": "~7.5.0",
"tslib": "^2.3.0",
"uuid": "^8.3.2",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^15.2.8",
"@angular/cli": "~15.2.8",
"@angular/compiler-cli": "^15.2.9",
"@types/google-libphonenumber": "^7.4.23",
"@types/jasmine": "~4.0.0",
"jasmine-core": "~4.1.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "4.8"
}
}

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

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MainComponent } from './pages/main/main.component';
import { AuthGuard } from './guards/auth-guard.guard';
const routes: Routes = [
{
path: '',
loadChildren: () => null as any,
// component: GuestCardComponent,
// canActivate: [AuthGuard]
},
// { path: '**', component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

@ -0,0 +1,2 @@
<router-outlet></router-outlet>
<p-toast position="top-center"></p-toast>

View File

@ -20,16 +20,16 @@ describe('AppComponent', () => {
expect(app).toBeTruthy();
});
it(`should have as title 'fashion-logica'`, () => {
it(`should have as title 'coffee-like-more'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('fashion-logica');
expect(app.title).toEqual('coffee-like-more');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('fashion-logica app is running!');
expect(compiled.querySelector('.content span')?.textContent).toContain('coffee-like-more app is running!');
});
});

View File

@ -0,0 +1,64 @@
import { Component, OnInit } from '@angular/core';
import { RouteConfigLoadStart, Router } from '@angular/router';
import { AuthService } from './services/auth.service';
import { CookiesService } from './services/cookies.service';
import { JsonrpcService, RpcService } from './services/jsonrpc.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
title = 'Coffee Like More';
constructor(
private router: Router,
private cookiesService: CookiesService,
private jsonRpcService: JsonrpcService,
private authService: AuthService,
) {
this.router.events.subscribe((x) => {
if (x instanceof RouteConfigLoadStart && x.route.path === '') {
x.route.loadChildren = () => {
switch (this.cookiesService.getItem('presentation-option')) {
case 'first':
return import(
'./presentation-options/first-option/first-option.module'
).then((mod) => mod.FirstOptionModule);
default:
return import(
'./presentation-options/default-option/default-option.module'
).then((mod) => mod.DefaultOptionModule);
}
};
}
});
}
getAdditionalInfo() {
return this.jsonRpcService.rpc(
{
method: 'getAdditionalInfo',
params: [],
},
RpcService.authService,
true
);
}
ngOnInit(): void {
if (this.authService.authorized) {
this.authService.getUserInfo();
}
this.getAdditionalInfo().subscribe({
next: (value) => {
this.cookiesService.setCookie('presentation-option', value?.data?.interface_id || 'default')
},
error: (err) => {
console.error(err);
}
})
}
}

View File

@ -0,0 +1,93 @@
import { OrderStatus, Page, PageCode, lvlPeriod } from "./interface/data";
export const PageList: Page[] = [
{
code: PageCode.Auth,
name: 'Вход',
resName: 'auth',
onSideBar: false,
},
{
code: PageCode.Orders,
name: 'Заказы',
resName: 'orders',
onSideBar: true,
},
];
export const PageListWithBonus: Page[] = [
{
code: PageCode.Auth,
name: 'Вход',
resName: 'auth',
onSideBar: false,
},
{
code: PageCode.BonusProgram,
name: 'Ваша карта лояльности',
description: '',
resName: 'bonus-program',
onSideBar: true,
},
{
code: PageCode.Orders,
name: 'Ваши чеки',
description: '',
resName: 'orders',
onSideBar: true,
},
{
code: PageCode.UserData,
name: 'Заполнить анкету',
description: '',
resName: 'user-data',
onSideBar: true
},
{
code: PageCode.RefSystem,
name: 'Пригласить друга',
description: '',
resName: 'ref-system',
onSideBar: true,
}
];
export const orderStatuses: OrderStatus = {
'Cancelled': 'Отменен',
'InProcessing': 'В обработке',
'Unconfirmed': 'Принят',
'WaitCooking': 'Принят',
'ReadyForCooking': 'Принят',
'CookingStarted': 'Готовится',
'CookingCompleted': 'Приготовлен',
'Waiting': 'В пути',
'OnWay': 'В пути',
'Delivered': 'Выполнен',
'Closed': 'Выполнен',
};
export const lvlPeriods: lvlPeriod[] = [
{
percent: 3,
start: 0,
end: 1600,
color: '#f2c94c'
},
{
percent: 6,
start: 1601,
end: 3600,
color: '#f2994a'
},
{
percent: 10,
start: 3601,
end: 8600,
color: '#6fcf97'
},
{
percent: 15,
start: 8601,
color: '#6fcf97'
},
]

View File

@ -1,15 +1,14 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { LoyalityProgramComponent } from './pages/loyality-program/loyality-program.component';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MainComponent } from './pages/main/main.component';
import { NavbarComponent } from './components/navbar/navbar.component';
import { CardComponent } from './components/card/card.component';
import {InputMaskModule} from "primeng/inputmask";
import { 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';
@ -17,21 +16,40 @@ import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DialogService } from 'primeng/dynamicdialog';
import { BonusProgramComponent } from './pages/account/bonus-program/bonus-program.component';
import { OrdersComponent } from './pages/account/orders/orders.component';
import { OrderInfoComponent } from './components/order-info/order-info.component';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireMessagingModule } from '@angular/fire/compat/messaging';
import {ToastModule} from 'primeng/toast';
import { ToastModule } from 'primeng/toast';
import { MessageService } from 'primeng/api';
import { FooterButtonsComponent } from './components/footer-buttons/footer-buttons.component';
import { UserDataComponent } from './pages/account/user-data/user-data.component';
import { RefSystemComponent } from './pages/account/ref-system/ref-system.component';
import { QRCodeModule } from 'angularx-qrcode';
import { ShareButtonsModule } from 'ngx-sharebuttons/buttons';
import { 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 { 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';
import { LastOrderComponent } from './components/last-order/last-order.component';
import { InviteFriendsComponent } from './components/invite-friends/invite-friends.component';
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 { MatSnackBarModule } from '@angular/material/snack-bar';
import {
MAT_BOTTOM_SHEET_DATA,
MatBottomSheetModule,
MatBottomSheetRef,
} from '@angular/material/bottom-sheet';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { DirectivesModule } from './directives/directives.module';
@NgModule({
declarations: [
@ -43,44 +61,61 @@ import { MessagingService } from './services/messaging.service';
AccountComponent,
ExitComponent,
BonusProgramComponent,
OrdersComponent,
OrderInfoComponent,
FooterButtonsComponent,
UserDataComponent,
RefSystemComponent
RefSystemComponent,
NotFoundComponent,
GuestCardComponent,
AccordionComponent,
LastOrderComponent,
InviteFriendsComponent,
FooterComponent,
SocialMediaButtonsComponent,
LoginComponent,
// FocusNextInputDirective,
LoyalityProgramComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
RouterModule.forRoot([
{
path: '**',
component: MainComponent
}
]),
InputMaskModule,
ProgressSpinnerModule,
FormsModule,
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).
registrationStrategy: 'registerWhenStable:30000'
registrationStrategy: 'registerWhenStable:30000',
}),
AngularFireModule.initializeApp(environment.firebase),
AngularFireMessagingModule,
ToastModule,
ReactiveFormsModule,
QRCodeModule,
ShareButtonsModule.withConfig({
debug: true
debug: true,
}),
ShareIconsModule
ShareIconsModule,
MatIconModule,
QrCodeModule,
NgxMatIntlTelInputComponent,
MatFormFieldModule,
MatInputModule,
MatSnackBarModule,
MatBottomSheetModule,
MatProgressSpinnerModule,
DirectivesModule,
],
providers: [DialogService, MessageService, MessagingService ],
bootstrap: [AppComponent]
providers: [
DialogService,
MessageService,
MessagingService,
{ provide: MatBottomSheetRef, useValue: {} },
{ provide: MAT_BOTTOM_SHEET_DATA, useValue: {} },
],
bootstrap: [AppComponent],
})
export class AppModule { }

View File

@ -0,0 +1,7 @@
<div class="tab">
<input [id]="'tab-' + guid" type="checkbox" name="tabs" />
<label [for]="'tab-' + guid">{{ header }}</label>
<div class="tab-content">
<ng-content></ng-content>
</div>
</div>

View File

@ -0,0 +1,85 @@
:host {
width: 100%;
}
.tab {
position: relative;
margin-bottom: 1px;
width: 100%;
color: var(--text-color);
overflow: hidden;
border-bottom: solid 1px #bdbdbd;
}
.tab input {
position: absolute;
opacity: 0;
z-index: -1;
}
.tab label {
display: block;
padding: 20px 26px;
position: relative;
background: #ffffff00;
font-weight: 400;
font-size: 12px;
line-height: 14px;
letter-spacing: -0.5px;
cursor: pointer;
}
// .tab label:before {
// display: block;
// content: " ";
// padding-top: 5px;
// }
.tab-content {
max-height: 0;
overflow: hidden;
background: #292929;
-webkit-transition: all 0.35s;
-o-transition: all 0.35s;
transition: all 0.35s;
border-top: solid 1px #bdbdbd;
font-style: normal;
font-weight: 400;
font-size: 12px;
p {
margin: 0;
}
}
.tab-content p {
margin: 1em;
}
/* :checked */
.tab input:checked ~ .tab-content {
padding: 16px 26px;
max-height: 100vh;
}
/* Icon */
.tab label::after {
position: absolute;
right: 0;
top: 0;
line-height: 3;
text-align: center;
-webkit-transition: all 0.35s;
-o-transition: all 0.35s;
transition: all 0.35s;
height: 100%;
margin-right: 12px;
display: flex;
align-items: center;
}
.tab input[type="checkbox"] + label::after {
content: "+";
}
.tab input[type="radio"] + label::after {
content: "\25BC";
}
.tab input[type="checkbox"]:checked + label::after {
transform: rotate(315deg);
}
.tab input[type="radio"]:checked + label::after {
transform: rotateX(180deg);
}

View File

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

View File

@ -0,0 +1,23 @@
import { Component, Input, OnInit } from '@angular/core';
import { v4 as uuidv4 } from 'uuid';
export interface IAccordionData {
header: string;
body: string;
}
@Component({
selector: 'app-accordion[header]',
templateUrl: './accordion.component.html',
styleUrls: ['./accordion.component.scss']
})
export class AccordionComponent implements OnInit {
@Input() header!: string
public guid: string = uuidv4()
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,7 @@
<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

@ -0,0 +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 {
padding: 10px 62px;
margin-top: 8px;
background-color: var(--button-color);
color: var(--button-text-color);
border-radius: 3px;
border: none;
width: calc(50% - 12px);
}

View File

@ -0,0 +1,21 @@
import { Component } from '@angular/core';
import { MatBottomSheetRef } from '@angular/material/bottom-sheet';
@Component({
selector: 'app-exit',
templateUrl: './exit.component.html',
styleUrls: ['./exit.component.scss'],
})
export class ExitComponent {
constructor(
private _bottomSheetRef: MatBottomSheetRef<ExitComponent>
) {}
rejection() {
this._bottomSheetRef.dismiss(false)
}
logout() {
this._bottomSheetRef.dismiss(true)
}
}

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

@ -15,9 +15,9 @@
align-items: center;
width: 60px;
height: 60px;
background: #09467f;
border: solid #fff 1px !important;
color: #fff;
background: var(--text-color);
border: solid var(--text-color) 1px !important;
color: var(--text-color);
border-radius: 100%;
font-weight: 600;
letter-spacing: 2px;

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,4 @@
<img src="/assets/logo.svg" alt="Логотип">
<h3>Горячая линия</h3>
<a class="phone-number" href="tel:88003334130">8 (800) 333-41-30</a>
<app-social-media-buttons></app-social-media-buttons>

View File

@ -0,0 +1,28 @@
:host {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding-bottom: 100px;
h3 {
margin: 0;
font-family: Montserrat;
font-style: normal;
font-weight: 400;
font-size: 15px;
line-height: 20px;
text-align: center;
letter-spacing: -0.24px;
color: #6a737c;
}
.phone-number {
font-style: normal;
font-weight: 700;
font-size: 17px;
line-height: 22px;
text-align: center;
letter-spacing: -0.408px;
color: #d9d9d9;
text-decoration: none;
}
}

View File

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

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss']
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,25 @@
<h2>Пригласи друзей!</h2>
<div class="container">
<p>
Пригласи друзей зарегистрироваться в приложении по твоему уникальному коду и
получи бонусы, когда они совершат первую покупку.
</p>
<button class="share" (click)="share()" [disabled]="loading">
<ng-container *ngIf="loading">
<ng-container
*ngTemplateOutlet="spinner; context: { $implicit: 24 }"
></ng-container>
</ng-container>
<mat-icon
*ngIf="!loading"
aria-hidden="false"
aria-label="Share"
fontIcon="share"
style="color: #fff"
></mat-icon>
</button>
</div>
<ng-template #spinner let-diameter>
<mat-spinner [strokeWidth]="3" [diameter]="diameter"></mat-spinner>
</ng-template>

View File

@ -0,0 +1,34 @@
:host {
padding: 16px;
h2 {
font-family: Montserrat;
font-style: normal;
font-weight: 700;
font-size: 17px;
line-height: 22px;
letter-spacing: -0.408px;
}
& .container {
width: 100%;
display: flex;
flex-direction: row;
gap: 16px;
p {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: var(--text-color);
}
.share {
width: 72px;
height: 48px;
background: var(--button-color);
padding: 8px 26px;
border: none;
}
}
}

View File

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

View File

@ -0,0 +1,54 @@
import { Component, OnInit } from '@angular/core';
import { MessageService } from 'primeng/api';
import { lastValueFrom } from 'rxjs';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
import { environment } from 'src/environments/environment';
@Component({
selector: 'app-invite-friends',
templateUrl: './invite-friends.component.html',
styleUrls: ['./invite-friends.component.scss']
})
export class InviteFriendsComponent implements OnInit {
public refUrl: string = `${environment.defaultUrl}/?refUserId=`
public loading: boolean = true;
private shareData: ShareData = {
title: ''
}
constructor(
private jsonrpc: JsonrpcService,
private messageService: MessageService
) { }
async ngOnInit() {
const accountData = (await lastValueFrom(
this.jsonrpc
.rpc(
{
method: 'getTokenData',
params: [],
},
RpcService.authService,
true
)
)).data
this.refUrl += accountData.user_id
this.loading = false
}
share() {
if (navigator.share) {
navigator.share({
title: document.title,
text: "Coffee Like More",
url: this.refUrl
})
.then(() => console.log('Successful share'))
.catch((error) => {
console.log('Error sharing:', error)
});
}
}
}

View File

@ -0,0 +1,31 @@
<h2>Ваш предыдущий заказ</h2>
<div class="info-order">
<p class="flex"><span>Дата: </span>
<span *ngIf="!loading">{{(lastOrder?.transactionCreateDate | date:'dd.MM.yyyyг.') || 'Данные не найдены'}}</span>
<ng-container *ngIf="loading">
<ng-container
*ngTemplateOutlet="spinner; context: { $implicit: 24 }"
></ng-container>
</ng-container>
</p>
<p class="flex"><span>На сумму: </span>
<span *ngIf="!loading">{{lastOrder?.orderSum ? lastOrder?.orderSum + ' ₽' : 'Данные не найдены'}}</span>
<ng-container *ngIf="loading">
<ng-container
*ngTemplateOutlet="spinner; context: { $implicit: 24 }"
></ng-container>
</ng-container>
</p>
</div>
<a href="https://yandex.ru/profile/151770398186" target="_blank">
<button class="evaluate-order">Оценить заказ</button>
</a>
<p class="info">
Списание бонусов возможно на любые категории. Бонусами можно оплатить 100%
суммы покупки. Бонусы начисляются только на напитки с учётом добавок.
Неиспользованные бонусы сгорают в течение 90 дней.
</p>
<ng-template #spinner let-diameter>
<mat-spinner [strokeWidth]="3" [diameter]="diameter"></mat-spinner>
</ng-template>

View File

@ -0,0 +1,52 @@
:host {
padding: 24px 16px 0px;
& > h2 {
font-family: Montserrat;
font-style: normal;
font-weight: 700;
font-size: 15px;
line-height: 20px;
letter-spacing: -0.24px;
}
& > .info-order {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 16px;
span {
color: #828282;
}
.flex {
display: flex;
align-items: center;
flex-direction: row;
gap: 8px;
}
}
.evaluate-order {
margin: 24px 0;
width: 100%;
padding: 12px;
text-align: center;
border: 2px solid #28af49;
border-radius: 6px;
font-style: normal;
font-weight: 700;
font-size: 17px;
line-height: 22px;
letter-spacing: -0.408px;
background-color: transparent;
color: #28af49;
}
.info {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: rgba(255, 255, 255, 0.5);
}
}

View File

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

View File

@ -0,0 +1,18 @@
import { Component, Input, OnInit } from '@angular/core';
import { Purchase } from 'src/app/interface/data';
@Component({
selector: 'app-last-order[lastOrder]',
templateUrl: './last-order.component.html',
styleUrls: ['./last-order.component.scss']
})
export class LastOrderComponent implements OnInit {
@Input() lastOrder!: Purchase;
@Input() loading!: boolean;
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,5 @@
<div class="container">
<mat-icon style="cursor: pointer;" 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

@ -0,0 +1,33 @@
:host {
width: 100%;
}
.container {
box-sizing: border-box;
padding: 12px 16px;
width: 100%;
background: #231f20;
box-shadow: 0px 8px 16px rgba(17, 17, 17, 0.5);
color: var(--text-color);
display: flex;
align-items: center;
justify-content: space-between;
.back-arrow {
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.plug {
height: 24px;
width: 24px;
visibility: hidden;
}
.title {
font-family: "Montserrat", sans-serif;
font-weight: 700;
font-size: 17px;
line-height: 22px;
margin: 0;
}
}

View File

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

View File

@ -15,8 +15,7 @@
}
.step {
width: 20px;
height: 20px;
background: #fff;
height: 20px;
border: 2px solid #acaca6;
border-radius: 50%;
transition: background 1s;

View File

@ -0,0 +1,3 @@
<a *ngFor="let link of links" [href]="link.url" target="_blank">
<img [src]="link.imgUrl" [alt]="link.label" />
</a>

View File

@ -0,0 +1,15 @@
:host {
display: flex;
flex-direction: row;
gap: 16px;
justify-content: space-between;
a {
width: 48px;
height: 48px;
border-radius: 100%;
background: #333333;
display: flex;
align-items: center;
justify-content: center;
}
}

View File

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

View File

@ -0,0 +1,38 @@
import { Component, OnInit } from '@angular/core';
export interface ISocialMediaLink {
url: string;
imgUrl: string;
label: string;
}
@Component({
selector: 'app-social-media-buttons',
templateUrl: './social-media-buttons.component.html',
styleUrls: ['./social-media-buttons.component.scss']
})
export class SocialMediaButtonsComponent implements OnInit {
public links: ISocialMediaLink[] = [
{
label: 'Инстаграм',
url: 'https://www.instagram.com/',
imgUrl: '/assets/social-media-icons/instagram.svg'
},
{
label: 'ВК',
url: 'https://vk.com/coffeelike_com',
imgUrl: '/assets/social-media-icons/vk.svg'
},
{
label: 'Youtube',
url: 'https://www.youtube.com/c/coffeelikeru',
imgUrl: '/assets/social-media-icons/youtube.svg'
}
]
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FocusNextInputDirective } from './focus-next-input.directive';
import { DownloadAppDirective } from './download-app.directive';
@NgModule({
imports: [
CommonModule
],
declarations: [FocusNextInputDirective, DownloadAppDirective],
exports: [FocusNextInputDirective, DownloadAppDirective]
})
export class DirectivesModule { }

View File

@ -0,0 +1,81 @@
import {
Directive,
ElementRef,
HostListener,
OnInit,
Renderer2,
} from '@angular/core';
import { MessageService } from 'primeng/api';
import { getTypeDevice, pwaInstalled } from 'src/app/utils';
@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 {
getTypeDevice();
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';
}
}
@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'])
async downloadApp(event: MouseEvent) {
if (!this.deferredPrompt) {
this.messageService.clear();
this.messageService.add({
severity: 'error',
summary: 'Не поддерживается в Вашем браузере!',
});
return;
}
this.deferredPrompt.prompt();
this.deferredPrompt.userChoice.then((res: any) => {
if (res.outcome === 'accepted') {
this.messageService.clear();
this.messageService.add({
severity: 'success',
summary: 'Спасибо за установку!',
});
}
this.deferredPrompt = null;
});
}
}

View File

@ -0,0 +1,29 @@
import { Directive, EventEmitter, Input, Renderer2 } from '@angular/core';
@Directive({
selector: '[appFocusNextInput]'
})
export class FocusNextInputDirective {
@Input('appFocusNextInput') eventEmitter!: EventEmitter<string>;
constructor(private renderer: Renderer2) { }
ngOnInit() {
// TODO:
// 1: don't need to listen all events
// 2: not working in safari
this.eventEmitter.subscribe(elementId => {
try {
const element = this.renderer.selectRootElement(elementId)
setTimeout(() => {
element.focus();
element.click();
}, 0);
} 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

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth-guard.guard';
describe('AuthGuardGuard', () => {
let guard: AuthGuard;
beforeEach(() => {
TestBed.configureTestingModule({});
guard = TestBed.inject(AuthGuard);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

View File

@ -0,0 +1,47 @@
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
CanActivateChild,
Router,
RouterStateSnapshot,
UrlTree,
} from '@angular/router';
import { Observable, of } from 'rxjs';
import { CookiesService } from '../services/cookies.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate, CanActivateChild {
constructor(private cookiesService: CookiesService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
):
| Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>
| boolean
| UrlTree
{
if (this.cookiesService.getItem('token')) {
return of(true);
} else {
this.router.navigate(['/login']);
return of(false);
}
}
canActivateChild(
childRoute: ActivatedRouteSnapshot,
state: RouterStateSnapshot
):
| boolean
| UrlTree
| Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>
{
return this.canActivate(childRoute, state);
}
}

View File

@ -0,0 +1,222 @@
export enum PageCode {
Auth,
Orders,
BonusProgram,
RefSystem,
UserData,
}
export interface Moment extends moment.Moment { }
export interface Page {
code: PageCode;
component?: any;
name: string;
description?: string;
getMethod?: string;
resName?: string;
onSideBar: boolean;
}
export interface UserDataForm {
first_name: string;
birthdate: string;
gender: string;
}
export interface BonusProgramAccount {
BonusProgramName: string;
BonusProgramTypeID: string;
CardNumber: number;
Bonuses: number;
HoldedBonuses: number;
BonusProgramAccounts: BonusProgramAccount[];
DateBonusBurn: string;
_links: any[];
_embedded: any;
}
export interface Purchase {
PurchaseId?: string;
CustomerId?: string;
PurchaseDate: string;
PurchaseState?: number;
CardNumber?: number;
Address?: string;
CheckSummary?: number;
BonusSummary?: number;
ID: string;
Transactions: Transaction[];
IsSingleTransaction?: boolean;
transactionCreateDate?: string;
transactionType?: 'CancelPayFromWallet' | 'PayFromWallet' | 'RefillWallet';
transactionSum: number;
orderSum?: number;
}
export interface Transaction {
User: string;
Purchase: string;
Date: string;
Value: number;
TransactionType: number;
UserBonusesSnapshot: number;
BonusPercent: number;
DateActiveBonus: string;
AccountBonus: string;
Bonus: string;
ID: string;
HasPurchase?: boolean;
}
export interface OrderStatus {
[key: string]: string;
}
export interface lvlPeriod {
percent: number;
start: number;
end?: number;
color: string;
}
export interface DeliveryType {
cost: number;
title: string;
id: number;
}
export interface AcceptedOrder {
id: number;
status: string;
currency_symbol: string;
total: number;
address: {
city: string;
street: string;
house: number;
flat: number;
};
payment_method: string;
shipping: {
name: string;
total: number;
};
date_created: string;
items: OrderProduct[];
}
export interface Product {
id: number;
name: string;
price: string;
image_url: string;
image_gallery: string[];
category_id: number;
description?: string;
stock_status: string;
currency_symbol: string;
modifier_data: Modifier[];
short_description?: string;
guid?: string;
}
export interface Modifier {
id: number;
name: string;
category_type: string;
minimum_options: number;
maximum_options: number;
global_categories: string;
required: number;
options: Option[];
allOptions?: Option[];
}
export interface Option {
id: number;
name: string;
price: string;
prechecked: string;
active?: boolean;
}
export interface OrderProduct {
id: number;
amount: number;
name: string;
price: number;
modifiers: {
[name: string]: OrderModifier[];
};
}
export interface OrderModifier {
name: string;
id: number;
price: number;
}
export interface DeliveryData {
paymentMethod: PaymentMethod;
deliveryDate: Date | null;
deliveryType: DeliveryType | null;
persons: number;
comment: string;
}
export interface PaymentMethod {
type: string;
label: string;
}
export interface UserData {
first_name: string | null;
last_name: string | null;
street: string | null;
house: string | null;
flat: string | null;
city: string;
phone: string | null;
}
export interface UserInfoCategory {
id: string;
isActive: boolean;
isDefaultForNewGuests: boolean;
name: string;
}
export interface UserInfoWallet {
id: string;
name: string;
programType: string;
type: string;
}
export interface UserInfoWalletBalance {
balance: number;
wallet: UserInfoWallet;
}
export interface UserInfo {
OrdersSum: number;
categories: UserInfoCategory[];
customer_level: number;
birthday: string;
id: string;
name: string | null;
phone: string;
walletBalances: UserInfoWalletBalance[] | { error: ResponseError };
}
export interface ResponseError {
code: number;
msg: string;
}
export interface UpdateNewCustomerRequest {
name: string;
sex: string;
birthday: string;
}

View File

@ -1,5 +1,10 @@
<div class="woocommerce">
<div
<div
[ngClass]="{
woocommerce: true,
'auth-page': currentPage.code === PageCode.Auth
}"
>
<!-- <div
*ngIf="currentPage.code !== PageCode.Auth"
class="top-left-attribute"
></div>
@ -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)"
@ -62,12 +84,11 @@
</div>
</li>
</ul>
</nav>
</nav> -->
<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;
border: solid var(--main-color) 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,25 +77,24 @@
}
}
}
li:nth-child(odd) {
background-color: #ebebeb;
}
}
}
.top-left-attribute {
width: 10px;
height: 5px;
background: #09467f;
background: var(--main-color);
left: 0;
position: absolute;
top: 69px;
top: 103px;
}
.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);
@ -147,7 +166,7 @@ export class AccountComponent implements OnInit {
}
deleteToken(): void {
this.cookiesService.deleteCookie('token');
this.cookiesService.logout();
// this.router.navigate(['.'], {
// queryParams: {},
// });

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,18 @@
display: flex;
flex-direction: column;
&>h2 {
& > h2 {
font-style: normal;
font-weight: 700;
font-size: 20px;
line-height: 24px;
max-width: 400px;
width: 100%;
margin: 0 auto;
text-align: center;
}
&>p {
& > p {
font-style: normal;
font-weight: 400;
font-size: 15px;
@ -19,7 +23,7 @@
}
.card-container {
background: #09467f;
background: var(--main-color);
box-shadow: 0px 0px 5px rgb(0 0 0 / 15%);
border-radius: 15px;
height: 466px;
@ -67,7 +71,7 @@
}
&__content {
background-color: #09467f;
background-color: var(--main-color);
color: #fff;
.info {
@ -154,12 +158,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 +200,16 @@
font-size: 12px;
margin-bottom: 8px;
}
.add-to-wallet {
height: 36px;
border-radius: 8px;
background: var(--main-color);
border-color: var(--main-color);
color: #fff;
max-width: 400px;
width: 100%;
margin: 12px auto 0;
}
}
}
}

View File

@ -0,0 +1,193 @@
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,
transactionSum: 0
});
}
});
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: var(--main-color);
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

@ -1,10 +1,10 @@
<div class="ref-system">
<qrcode
<!-- <qrcode
*ngIf="!loading"
[qrdata]="refUrl"
[width]="256"
[errorCorrectionLevel]="'M'"
></qrcode>
></qrcode> -->
<p-progressSpinner
*ngIf="loading"
[style]="{ width: '100%' }"

View File

@ -8,23 +8,25 @@
margin: 0 auto;
.share {
width: 50px;
background-color: #09467f;
background-color: var(--main-color);
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
img {
height: 26px;
}
}
.copy {
background-color: #09467f;
background-color: var(--main-color);
color: #fff;
border-radius: 8px;
width: calc(100% - 66px);
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,32 @@ export class RefSystemComponent implements OnInit {
if (navigator.share) {
navigator.share({
title: document.title,
text: "Fashion Logica",
text: "Coffee Like More",
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.clear();
this.messageService.add({
severity: 'custom',
summary: 'Ссылка скопирована!',
});
})
.catch(err => {
this.messageService.clear();
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

@ -186,4 +186,4 @@
*/
// input[type="date"]:focus::before,
// input[type="date"]:valid::before { display: none }
}
}

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

@ -0,0 +1,82 @@
<app-navbar title="Карта гостя" (backEvent)="logout()"></app-navbar>
<div class="guest-card">
<div class="top-info">
<div class="top-info__level">
<p id="level">Уровень {{ currentLvl }}</p>
<p id="level-percent">Кэшбек {{ currentLvlPeriod.percent }}%</p>
</div>
<p class="top-info__bonus">{{ getBalanceAmount(customerInfo?.walletBalances) }} бонусов</p>
</div>
<div class="guest-card__qr" (click)="qrCodeClick()">
<ng-container *ngIf="customerInfo">
<qr-code
[value]="customerInfo?.phone.substr(2) || 'Данные не найдены'"
[margin]="0"
[size]="qrCodeSize"
errorCorrectionLevel="M"
></qr-code>
</ng-container>
<ng-container *ngIf="!customerInfo">
<ng-container
*ngTemplateOutlet="spinner; context: { $implicit: 85 }"
></ng-container>
</ng-container>
</div>
<div class="guest-card__user-description">
<p>
<ng-container *ngIf="currentLvlPeriod.end">
Осталось купить на сумму <span class="price">{{ currentLvlPeriod.end - (purchaseData.currentAmount || 0) + 1 }}</span>
рублей, тогда кэшбек будет <span class="percent">{{ getNextLevel().percent }}%</span> с
{{ purchaseData.currentPeriod[1].locale('ru').format('D MMMM')}}
</ng-container>
<ng-container *ngIf="!currentLvlPeriod.end">
У Вас последний уровень бонусной программы. Процент начисляемых бонусов:
{{currentLvlPeriod.percent}}%
</ng-container>
</p>
</div>
<span id="bonuses-condition"></span>
<!-- <div class="guest-card__level-info"> -->
<!-- <ng-container *ngIf="!purchaseData.$loading"> -->
<!-- <ng-container *ngIf="currentLvlPeriod.end"> -->
<!-- <\!-- <input -\-> -->
<!-- <\!-- type="range" -\-> -->
<!-- <\!-- [value]="purchaseData.currentAmount" -\-> -->
<!-- <\!-- [min]="currentLvlPeriod.start" -\-> -->
<!-- <\!-- [max]="currentLvlPeriod.end" -\-> -->
<!-- <\!-- [step]="0.01" -\-> -->
<!-- <\!-- disabled="true" -\-> -->
<!-- <\!-- [ngStyle]="{ -\-> -->
<!-- <\!-- 'background-size': ((purchaseData.currentAmount! - currentLvlPeriod.start) / (currentLvlPeriod.end - currentLvlPeriod.start + 1)) * 100 + '% 100%' -\-> -->
<!-- <\!-- }" -\-> -->
<!-- <\!-- /> -\-> -->
<!-- </ng-container> -->
<!-- <ng-container *ngIf="!currentLvlPeriod.end"> -->
<!-- <h2> -->
<!-- У Вас последний уровень бонусной программы. Процент начисляемых бонусов: {{currentLvlPeriod.percent}}% -->
<!-- </h2> -->
<!-- </ng-container> -->
<!-- </ng-container> -->
<!-- <ng-container *ngIf="purchaseData.$loading"> -->
<!-- <ng-container -->
<!-- *ngTemplateOutlet="spinner; context: { $implicit: 48 }" -->
<!-- ></ng-container> -->
<!-- </ng-container> -->
<!-- </div> -->
<app-last-order
[lastOrder]="lastPurchase"
[loading]="purchaseData.$loading"
></app-last-order>
<a class="guest-card__loyalty-program" routerLink="loyality-program"
>Подробнее о правилах <br />
Программы лояльности</a
>
</div>
<ng-template #spinner let-diameter>
<mat-spinner [strokeWidth]="3" [diameter]="diameter"></mat-spinner>
</ng-template>

View File

@ -0,0 +1,221 @@
:host {
.guest-card {
display: flex;
flex-direction: column;
align-items: center;
max-width: 600px;
margin: 0 auto;
.top-info {
padding: 8px 0 0;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
background-color: #292929;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border: 1px solid #000000;
border-top: 1px solid #888888;
&__level {
width: 100%;
display: flex;
align-items: center;
justify-content: space-around;
font-size: 16px;
}
& p {
color: var(--button-color);
}
p.top-info__bonus{
font-size: 20px;
}
}
&__qr {
margin: 10px;
padding: 10px;
width: fit-content;
background-image: linear-gradient(
#fff 33%,
transparent 0px,
transparent 67%,
#fff 0px
),
linear-gradient(
90deg,
#ffe 33%,
transparent 0px,
transparent 66%,
#fff 0px
),
linear-gradient(#fff 33%, transparent 0px, transparent 67%, #fff 0),
linear-gradient(90deg, #fff 33%, transparent 0, transparent 66%, #fff 0);
background-size: 1px 100%, 100% 1px, 1px 100%, 100% 1px;
background-position: 0 0, 0 0, 100% 100%, 100% 100%;
background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
cursor: pointer;
}
&__user-description {
background-color: #292929;
padding: 14px 24px;
p {
width: 60%;
text-align: center;
margin: 0 auto;
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 19px;
letter-spacing: -0.5px;
}
.price,
.percent {
font-weight: bold;
}
}
&__purchases-description {
margin: 0;
padding: 14px 24px;
width: 100%;
text-align: center;
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 19px;
letter-spacing: -0.5px;
grid-template-columns: calc(100% - 24px) 24px;
span {
color: #219653;
}
}
&__level-info {
padding-top: 36px;
padding-left: 36px;
padding-right: 36px;
display: flex;
flex-direction: column;
align-items: center;
h2 {
font-style: normal;
font-family: Montserrat;
font-weight: 700;
font-size: 17px;
line-height: 22px;
text-align: center;
letter-spacing: -0.408px;
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 6px;
border-radius: 5px;
display: block;
position: relative;
background: #231f20;
box-shadow: 0px 0px 3px #f2c94c59;
background-image: linear-gradient(#f2c94c, #f2c94c);
background-size: 70% 100%;
background-repeat: no-repeat;
&::before,
&::after {
content: " ";
display: block;
width: 16px;
height: 16px;
border-radius: 100%;
position: absolute;
top: -5px;
}
&::before {
background-color: #f2c94c;
left: 0px;
}
&::after {
background-color: #f2c94c;
right: 0px;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
background: #f2c94c;
width: 16px;
height: 16px;
border-radius: 100%;
display: none;
}
&::-ms-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
border-radius: 50%;
background: #f2c94c;
cursor: ew-resize;
box-shadow: 0 0 2px 0 #555;
transition: background 0.3s ease-in-out;
}
&::-moz-range-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
border-radius: 50%;
background: #f2c94c;
cursor: ew-resize;
box-shadow: 0 0 2px 0 #555;
transition: background 0.3s ease-in-out;
}
}
}
&__download-app {
width: 100%;
position: relative;
margin-top: 32px;
display: flex;
justify-content: flex-end;
img {
width: 100%;
max-width: calc(100% - 16px);
}
}
&__loyalty-program {
text-align: center;
color: #7F2061;
font-style: normal;
font-weight: bold;
font-size: 12px;
line-height: 16px;
text-decoration: none;
margin: 17px 0 22px;
}
}
}
app-accordion {
ul {
li {
list-style-type: disc;
margin-left: 16px;
}
}
}

View File

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

View File

@ -0,0 +1,193 @@
import { Component, OnInit } from '@angular/core';
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';
import { Purchase, lvlPeriod } from 'src/app/interface/data';
import { lvlPeriods } from 'src/app/app.constants';
interface Moment extends moment.Moment {}
export interface IPurchaseData {
currentPeriod: Moment[];
lastPeriod: Moment[];
lastPurchases: Purchase[];
currentPurchases: Purchase[];
lastAmount?: number;
currentAmount?: number;
$loading: boolean;
}
@Component({
selector: 'app-guest-card',
templateUrl: './guest-card.component.html',
styleUrls: ['./guest-card.component.scss'],
})
export class GuestCardComponent implements OnInit {
public qrCodeSize: number = 85;
private isQrCodeClicked: boolean = false;
public customerInfo!: any;
public purchases!: Purchase[];
public lastPurchase!: Purchase;
public purchaseData: IPurchaseData = {
currentPeriod: [],
lastPeriod: [],
lastPurchases: [],
currentPurchases: [],
$loading: true,
get currentAmount():number {
const amount = this.currentPurchases.reduce((accumulator, currentValue) => {
if (currentValue.transactionType !== 'PayFromWallet') return accumulator;
return accumulator + currentValue.orderSum!;
}, 0);
return amount * 1
},
get lastAmount():number {
const amount = this.lastPurchases.reduce((accumulator, currentValue) => {
if (currentValue.transactionType !== 'PayFromWallet') return accumulator;
return accumulator + currentValue.orderSum!;
}, 0);
return amount * 1
}
};
public discountLevel: number = 4.2;
public lvlPeriods: lvlPeriod[] = lvlPeriods;
public currentLvlPeriod!: lvlPeriod;
public currentLvl: number = 1;
constructor(
private _bottomSheet: MatBottomSheet,
private cookiesService: CookiesService,
private router: Router,
private wpJsonService: WpJsonService
) {}
ngOnInit(): void {
const token = this.cookiesService.getItem('token');
this.getCurrentQuarterOfYear();
this.wpJsonService
.getCustomerInfo(
environment.systemId,
token || '',
environment.icardProxy
)
.subscribe({
next: (value) => {
this.customerInfo = value.customer_info;
this.getPurchases().subscribe((value) => {
this.purchases = value[this.customerInfo?.id].filter(
(purchase: Purchase) =>
[
'PayFromWallet',
'CancelPayFromWallet',
'RefillWallet',
'RefillWalletFromOrder'
].includes(purchase.transactionType || '')
);
this.lastPurchase = this.purchases.filter(
(purchase: Purchase) =>
[
'PayFromWallet',
'RefillWalletFromOrder'
].includes(purchase.transactionType || '')
)[0]
this.purchaseData.lastPurchases = this.purchases.filter((value: Purchase) => {
return moment(value.transactionCreateDate).isBetween(this.purchaseData.lastPeriod[0], this.purchaseData.lastPeriod[1])
})
this.purchaseData.currentPurchases = this.purchases.filter((value: Purchase) => {
return moment(value.transactionCreateDate).isBetween(this.purchaseData.currentPeriod[0], this.purchaseData.currentPeriod[1])
})
const currentAmount = this.purchaseData.currentAmount || 0
const index = this.lvlPeriods.findIndex((item) => item.start <= currentAmount && currentAmount <= (item.end || Infinity))!
if(index != -1) {
this.currentLvlPeriod = this.lvlPeriods[index];
this.currentLvl = index + 1;
this.purchaseData.$loading = false;
}
});
},
});
}
getNextLevel(): lvlPeriod {
if(this.currentLvl == this.lvlPeriods.length) {
return lvlPeriods[this.currentLvl - 1];
}
return lvlPeriods[this.currentLvl];
}
qrCodeClick() {
this.isQrCodeClicked = !this.isQrCodeClicked;
this.qrCodeSize = this.isQrCodeClicked ? 180 : 85;
}
deleteToken(): void {
this.cookiesService.logout();
}
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().subtract(1, 'months').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.getTransactions(
environment.systemId,
token ?? '',
environment.icardProxy
);
}
getCurrentQuarterOfYear() {
const quarters = [
[
moment().subtract(1, 'years').endOf('year').subtract(3, 'months'),
moment().subtract(1, 'years').endOf('year'),
],
[moment().startOf('year'), moment().startOf('year').add(3, 'months')],
[
moment().startOf('year').add(3, 'months'),
moment().startOf('year').add(6, 'months'),
],
[
moment().startOf('year').add(6, 'months'),
moment().startOf('year').add(9, 'months'),
],
[
moment().startOf('year').add(9, 'months'),
moment().startOf('year').add(12, 'months'),
],
];
for (let i = 0; i < 4; i++) {
if (moment().isBetween(quarters[i][0], quarters[i][1])) {
this.purchaseData.lastPeriod = quarters[i - 1];
this.purchaseData.currentPeriod = quarters[i];
}
}
}
getBalanceAmount(loyaltyPrograms: any[]) {
return loyaltyPrograms.reduce((accumulator, currentValue) => {
return accumulator + currentValue.balance;
}, 0);
}
}

View File

@ -0,0 +1,107 @@
<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()"
[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="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 [disabled]="phoneForm.invalid">Принять участие</button>
</form>
<ng-template #smsCode>
<h2>Введите код из SMS</h2>
<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 />
<ng-container *ngIf="timeLeft">
Отправим повторно через {{timeLeft}}с
</ng-container>
<ng-container *ngIf="!timeLeft">
<span class="resend" (click)="submitNumber()">Отправить повторно</span>
</ng-container>
</p>
</ng-template>

View File

@ -0,0 +1,214 @@
:host {
padding-top: 48px;
display: flex;
flex-direction: column;
align-items: center;
max-width: 600px;
margin: 0 auto 52px;
h1 {
margin-top: 20px;
width: 302px;
font-style: normal;
font-weight: 700;
font-size: 17px;
line-height: 22px;
text-align: center;
letter-spacing: -0.408px;
}
h2 {
margin-top: 44px;
font-style: normal;
font-weight: 700;
font-size: 20px;
line-height: 24px;
text-align: center;
letter-spacing: 0.38px;
}
.description {
width: 180px;
font-style: normal;
font-weight: 400;
font-size: 15px;
line-height: 20px;
text-align: center;
letter-spacing: -0.24px;
margin-top: 16px;
}
form {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 35px;
.offer {
margin-top: 10px;
padding: 0 16px;
font-family: "Gowun Dodum";
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 17px;
text-align: center;
span {
color: #13a538;
}
}
.input-container {
position: relative;
width: 100%;
label {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #6a737c;
text-align: left;
position: absolute;
top: 10px;
left: 16px;
}
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;
}
}
button {
height: 46px;
width: calc(100% - 32px);
padding: 10px 24px;
background: #28af49;
border-radius: 6px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
border: none;
letter-spacing: -0.408px;
color: #ffffff;
font-style: normal;
font-weight: 700;
font-size: 17px;
line-height: 22px;
&:disabled {
background-color: #344a3a;
}
}
}
.code-form {
width: 100%;
// 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%;
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;
}
}
}
.resend-code {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 16px;
text-align: center;
margin-top: 23px;
.resend {
cursor: pointer;
}
}
}
mat-form-field {
width: 100%;
}

View File

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

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