реализовал usersite
This commit is contained in:
Kataev Denis 2022-09-01 21:59:52 +04:00
parent 0ebf222739
commit b593ed28e7
68 changed files with 4020 additions and 509 deletions

View File

@ -25,12 +25,18 @@
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
"src/assets",
"src/manifest.webmanifest"
],
"styles": [
"node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
"node_modules/primeicons/primeicons.css",
"node_modules/primeng/resources/primeng.min.css",
"src/styles.scss"
],
"scripts": []
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"configurations": {
"production": {
@ -38,7 +44,7 @@
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumError": "2mb"
},
{
"type": "anyComponentStyle",
@ -93,7 +99,9 @@
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
"src/firebase-messaging-sw.js",
"src/assets",
"src/manifest.webmanifest"
],
"styles": [
"src/styles.scss"
@ -103,5 +111,8 @@
}
}
}
},
"cli": {
"analytics": false
}
}

30
ngsw-config.json Normal file
View File

@ -0,0 +1,30 @@
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
}

View File

@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"start": "ng serve --host 192.168.0.179",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
@ -14,18 +14,30 @@
"@angular/common": "^14.0.0",
"@angular/compiler": "^14.0.0",
"@angular/core": "^14.0.0",
"@angular/fire": "^7.4.1",
"@angular/forms": "^14.0.0",
"@angular/platform-browser": "^14.0.0",
"@angular/platform-browser-dynamic": "^14.0.0",
"@angular/router": "^14.0.0",
"@angular/service-worker": "^14.0.0",
"@types/uuid": "^8.3.4",
"angular-moment-timezone": "^1.7.1",
"barcode-2-svg": "^0.3.3",
"firebase": "^9.9.3",
"google-libphonenumber": "^3.2.30",
"jsbarcode": "^3.11.5",
"primeicons": "^5.0.0",
"primeng": "^14.0.1",
"rxjs": "~7.5.0",
"tslib": "^2.3.0",
"uuid": "^8.3.2",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^14.0.6",
"@angular/cli": "~14.0.6",
"@angular/compiler-cli": "^14.0.0",
"@types/google-libphonenumber": "^7.4.23",
"@types/jasmine": "~4.0.0",
"jasmine-core": "~4.1.0",
"karma": "~6.3.0",

View File

@ -1,484 +1 @@
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * Delete the template below * * * * * * * * * * -->
<!-- * * * * * * * to get started with your project! * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<style>
:host {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 14px;
color: #333;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 8px 0;
}
p {
margin: 0;
}
.spacer {
flex: 1;
}
.toolbar {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 60px;
display: flex;
align-items: center;
background-color: #1976d2;
color: white;
font-weight: 600;
}
.toolbar img {
margin: 0 16px;
}
.toolbar #twitter-logo {
height: 40px;
margin: 0 8px;
}
.toolbar #youtube-logo {
height: 40px;
margin: 0 16px;
}
.toolbar #twitter-logo:hover,
.toolbar #youtube-logo:hover {
opacity: 0.8;
}
.content {
display: flex;
margin: 82px auto 32px;
padding: 0 16px;
max-width: 960px;
flex-direction: column;
align-items: center;
}
svg.material-icons {
height: 24px;
width: auto;
}
svg.material-icons:not(:last-child) {
margin-right: 8px;
}
.card svg.material-icons path {
fill: #888;
}
.card-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 16px;
}
.card {
all: unset;
border-radius: 4px;
border: 1px solid #eee;
background-color: #fafafa;
height: 40px;
width: 200px;
margin: 0 8px 16px;
padding: 16px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
transition: all 0.2s ease-in-out;
line-height: 24px;
}
.card-container .card:not(:last-child) {
margin-right: 0;
}
.card.card-small {
height: 16px;
width: 168px;
}
.card-container .card:not(.highlight-card) {
cursor: pointer;
}
.card-container .card:not(.highlight-card):hover {
transform: translateY(-3px);
box-shadow: 0 4px 17px rgba(0, 0, 0, 0.35);
}
.card-container .card:not(.highlight-card):hover .material-icons path {
fill: rgb(105, 103, 103);
}
.card.highlight-card {
background-color: #1976d2;
color: white;
font-weight: 600;
border: none;
width: auto;
min-width: 30%;
position: relative;
}
.card.card.highlight-card span {
margin-left: 60px;
}
svg#rocket {
width: 80px;
position: absolute;
left: -10px;
top: -24px;
}
svg#rocket-smoke {
height: calc(100vh - 95px);
position: absolute;
top: 10px;
right: 180px;
z-index: -10;
}
a,
a:visited,
a:hover {
color: #1976d2;
text-decoration: none;
}
a:hover {
color: #125699;
}
.terminal {
position: relative;
width: 80%;
max-width: 600px;
border-radius: 6px;
padding-top: 45px;
margin-top: 8px;
overflow: hidden;
background-color: rgb(15, 15, 16);
}
.terminal::before {
content: "\2022 \2022 \2022";
position: absolute;
top: 0;
left: 0;
height: 4px;
background: rgb(58, 58, 58);
color: #c2c3c4;
width: 100%;
font-size: 2rem;
line-height: 0;
padding: 14px 0;
text-indent: 4px;
}
.terminal pre {
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
color: white;
padding: 0 1rem 1rem;
margin: 0;
}
.circle-link {
height: 40px;
width: 40px;
border-radius: 40px;
margin: 8px;
background-color: white;
border: 1px solid #eeeeee;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: 1s ease-out;
}
.circle-link:hover {
transform: translateY(-0.25rem);
box-shadow: 0px 3px 15px rgba(0, 0, 0, 0.2);
}
footer {
margin-top: 8px;
display: flex;
align-items: center;
line-height: 20px;
}
footer a {
display: flex;
align-items: center;
}
.github-star-badge {
color: #24292e;
display: flex;
align-items: center;
font-size: 12px;
padding: 3px 10px;
border: 1px solid rgba(27,31,35,.2);
border-radius: 3px;
background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%);
margin-left: 4px;
font-weight: 600;
}
.github-star-badge:hover {
background-image: linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%);
border-color: rgba(27,31,35,.35);
background-position: -.5em;
}
.github-star-badge .material-icons {
height: 16px;
width: 16px;
margin-right: 4px;
}
svg#clouds {
position: fixed;
bottom: -160px;
left: -230px;
z-index: -10;
width: 1920px;
}
/* Responsive Styles */
@media screen and (max-width: 767px) {
.card-container > *:not(.circle-link) ,
.terminal {
width: 100%;
}
.card:not(.highlight-card) {
height: 16px;
margin: 8px 0;
}
.card.highlight-card span {
margin-left: 72px;
}
svg#rocket-smoke {
right: 120px;
transform: rotate(-5deg);
}
}
@media screen and (max-width: 575px) {
svg#rocket-smoke {
display: none;
visibility: hidden;
}
}
</style>
<!-- Toolbar -->
<div class="toolbar" role="banner">
<img
width="40"
alt="Angular Logo"
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
/>
<span>Welcome</span>
<div class="spacer"></div>
<a aria-label="Angular on twitter" target="_blank" rel="noopener" href="https://twitter.com/angular" title="Twitter">
<svg id="twitter-logo" height="24" data-name="Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
<rect width="400" height="400" fill="none"/>
<path d="M153.62,301.59c94.34,0,145.94-78.16,145.94-145.94,0-2.22,0-4.43-.15-6.63A104.36,104.36,0,0,0,325,122.47a102.38,102.38,0,0,1-29.46,8.07,51.47,51.47,0,0,0,22.55-28.37,102.79,102.79,0,0,1-32.57,12.45,51.34,51.34,0,0,0-87.41,46.78A145.62,145.62,0,0,1,92.4,107.81a51.33,51.33,0,0,0,15.88,68.47A50.91,50.91,0,0,1,85,169.86c0,.21,0,.43,0,.65a51.31,51.31,0,0,0,41.15,50.28,51.21,51.21,0,0,1-23.16.88,51.35,51.35,0,0,0,47.92,35.62,102.92,102.92,0,0,1-63.7,22A104.41,104.41,0,0,1,75,278.55a145.21,145.21,0,0,0,78.62,23" fill="#fff"/>
</svg>
</a>
<a aria-label="Angular on YouTube" target="_blank" rel="noopener" href="https://youtube.com/angular" title="YouTube">
<svg id="youtube-logo" height="24" width="24" data-name="Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#fff">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M21.58 7.19c-.23-.86-.91-1.54-1.77-1.77C18.25 5 12 5 12 5s-6.25 0-7.81.42c-.86.23-1.54.91-1.77 1.77C2 8.75 2 12 2 12s0 3.25.42 4.81c.23.86.91 1.54 1.77 1.77C5.75 19 12 19 12 19s6.25 0 7.81-.42c.86-.23 1.54-.91 1.77-1.77C22 15.25 22 12 22 12s0-3.25-.42-4.81zM10 15V9l5.2 3-5.2 3z"/>
</svg>
</a>
</div>
<div class="content" role="main">
<!-- Highlight Card -->
<div class="card highlight-card card-small">
<svg id="rocket" xmlns="http://www.w3.org/2000/svg" width="101.678" height="101.678" viewBox="0 0 101.678 101.678">
<title>Rocket Ship</title>
<g id="Group_83" data-name="Group 83" transform="translate(-141 -696)">
<circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="#dd0031"/>
<g id="Group_47" data-name="Group 47" transform="translate(165.185 720.185)">
<path id="Path_33" data-name="Path 33" d="M3.4,42.615a3.084,3.084,0,0,0,3.553,3.553,21.419,21.419,0,0,0,12.215-6.107L9.511,30.4A21.419,21.419,0,0,0,3.4,42.615Z" transform="translate(0.371 3.363)" fill="#fff"/>
<path id="Path_34" data-name="Path 34" d="M53.3,3.221A3.09,3.09,0,0,0,50.081,0,48.227,48.227,0,0,0,18.322,13.437c-6-1.666-14.991-1.221-18.322,7.218A33.892,33.892,0,0,1,9.439,25.1l-.333.666a3.013,3.013,0,0,0,.555,3.553L23.985,43.641a2.9,2.9,0,0,0,3.553.555l.666-.333A33.892,33.892,0,0,1,32.647,53.3c8.55-3.664,8.884-12.326,7.218-18.322A48.227,48.227,0,0,0,53.3,3.221ZM34.424,9.772a6.439,6.439,0,1,1,9.106,9.106,6.368,6.368,0,0,1-9.106,0A6.467,6.467,0,0,1,34.424,9.772Z" transform="translate(0 0.005)" fill="#fff"/>
</g>
</g>
</svg>
<span>{{ title }} app is running!</span>
<svg id="rocket-smoke" xmlns="http://www.w3.org/2000/svg" width="516.119" height="1083.632" viewBox="0 0 516.119 1083.632">
<title>Rocket Ship Smoke</title>
<path id="Path_40" data-name="Path 40" d="M644.6,141S143.02,215.537,147.049,870.207s342.774,201.755,342.774,201.755S404.659,847.213,388.815,762.2c-27.116-145.51-11.551-384.124,271.9-609.1C671.15,139.365,644.6,141,644.6,141Z" transform="translate(-147.025 -140.939)" fill="#f5f5f5"/>
</svg>
</div>
<!-- Resources -->
<h2>Resources</h2>
<p>Here are some links to help you get started:</p>
<div class="card-container">
<a class="card" target="_blank" rel="noopener" href="https://angular.io/tutorial">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82zM12 3L1 9l11 6 9-4.91V17h2V9L12 3z"/></svg>
<span>Learn Angular</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg> </a>
<a class="card" target="_blank" rel="noopener" href="https://angular.io/cli">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>
<span>CLI Documentation</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</a>
<a class="card" target="_blank" rel="noopener" href="https://material.angular.io">
<svg xmlns="http://www.w3.org/2000/svg" style="margin-right: 8px" width="21.813" height="23.453" viewBox="0 0 21.813 23.453"><path d="M4099.584,972.736h0l-10.882,3.9,1.637,14.4,9.245,5.153,9.245-5.153,1.686-14.4Z" transform="translate(-4088.702 -972.736)" fill="#808080"/><path d="M4181.516,972.736v23.453l9.245-5.153,1.686-14.4Z" transform="translate(-4170.633 -972.736)" fill="#808080"/><path d="M4137.529,1076.127l-7.7-3.723,4.417-2.721,7.753,3.723Z" transform="translate(-4125.003 -1058.315)" fill="#ffe0b2"/><path d="M4137.529,1051.705l-7.7-3.723,4.417-2.721,7.753,3.723Z" transform="translate(-4125.003 -1036.757)" fill="#fff3e0"/><path d="M4137.529,1027.283l-7.7-3.723,4.417-2.721,7.753,3.723Z" transform="translate(-4125.003 -1015.199)" fill="#fff"/></svg>
<span>Angular Material</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</a>
<a class="card" target="_blank" rel="noopener" href="https://blog.angular.io/">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M13.5.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/></svg>
<span>Angular Blog</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</a>
<a class="card" target="_blank" rel="noopener" href="https://angular.io/devtools/">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M14.73,13.31C15.52,12.24,16,10.93,16,9.5C16,5.91,13.09,3,9.5,3S3,5.91,3,9.5C3,13.09,5.91,16,9.5,16 c1.43,0,2.74-0.48,3.81-1.27L19.59,21L21,19.59L14.73,13.31z M9.5,14C7.01,14,5,11.99,5,9.5S7.01,5,9.5,5S14,7.01,14,9.5 S11.99,14,9.5,14z"/><polygon points="10.29,8.44 9.5,6 8.71,8.44 6.25,8.44 8.26,10.03 7.49,12.5 9.5,10.97 11.51,12.5 10.74,10.03 12.75,8.44"/></g></g></svg>
<span>Angular DevTools</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</a>
</div>
<!-- Next Steps -->
<h2>Next Steps</h2>
<p>What do you want to do next with your app?</p>
<input type="hidden" #selection>
<div class="card-container">
<button class="card card-small" (click)="selection.value = 'component'" tabindex="0">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span>New Component</span>
</button>
<button class="card card-small" (click)="selection.value = 'material'" tabindex="0">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span>Angular Material</span>
</button>
<button class="card card-small" (click)="selection.value = 'pwa'" tabindex="0">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span>Add PWA Support</span>
</button>
<button class="card card-small" (click)="selection.value = 'dependency'" tabindex="0">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span>Add Dependency</span>
</button>
<button class="card card-small" (click)="selection.value = 'test'" tabindex="0">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span>Run and Watch Tests</span>
</button>
<button class="card card-small" (click)="selection.value = 'build'" tabindex="0">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
<span>Build for Production</span>
</button>
</div>
<!-- Terminal -->
<div class="terminal" [ngSwitch]="selection.value">
<pre *ngSwitchDefault>ng generate component xyz</pre>
<pre *ngSwitchCase="'material'">ng add @angular/material</pre>
<pre *ngSwitchCase="'pwa'">ng add @angular/pwa</pre>
<pre *ngSwitchCase="'dependency'">ng add _____</pre>
<pre *ngSwitchCase="'test'">ng test</pre>
<pre *ngSwitchCase="'build'">ng build</pre>
</div>
<!-- Links -->
<div class="card-container">
<a class="circle-link" title="Find a Local Meetup" href="https://www.meetup.com/find/?keywords=angular" target="_blank" rel="noopener">
<svg xmlns="http://www.w3.org/2000/svg" width="24.607" height="23.447" viewBox="0 0 24.607 23.447">
<title>Meetup Logo</title>
<path id="logo--mSwarm" d="M21.221,14.95A4.393,4.393,0,0,1,17.6,19.281a4.452,4.452,0,0,1-.8.069c-.09,0-.125.035-.154.117a2.939,2.939,0,0,1-2.506,2.091,2.868,2.868,0,0,1-2.248-.624.168.168,0,0,0-.245-.005,3.926,3.926,0,0,1-2.589.741,4.015,4.015,0,0,1-3.7-3.347,2.7,2.7,0,0,1-.043-.38c0-.106-.042-.146-.143-.166a3.524,3.524,0,0,1-1.516-.69A3.623,3.623,0,0,1,2.23,14.557a3.66,3.66,0,0,1,1.077-3.085.138.138,0,0,0,.026-.2,3.348,3.348,0,0,1-.451-1.821,3.46,3.46,0,0,1,2.749-3.28.44.44,0,0,0,.355-.281,5.072,5.072,0,0,1,3.863-3,5.028,5.028,0,0,1,3.555.666.31.31,0,0,0,.271.03A4.5,4.5,0,0,1,18.3,4.7a4.4,4.4,0,0,1,1.334,2.751,3.658,3.658,0,0,1,.022.706.131.131,0,0,0,.1.157,2.432,2.432,0,0,1,1.574,1.645,2.464,2.464,0,0,1-.7,2.616c-.065.064-.051.1-.014.166A4.321,4.321,0,0,1,21.221,14.95ZM13.4,14.607a2.09,2.09,0,0,0,1.409,1.982,4.7,4.7,0,0,0,1.275.221,1.807,1.807,0,0,0,.9-.151.542.542,0,0,0,.321-.545.558.558,0,0,0-.359-.534,1.2,1.2,0,0,0-.254-.078c-.262-.047-.526-.086-.787-.138a.674.674,0,0,1-.617-.75,3.394,3.394,0,0,1,.218-1.109c.217-.658.509-1.286.79-1.918a15.609,15.609,0,0,0,.745-1.86,1.95,1.95,0,0,0,.06-1.073,1.286,1.286,0,0,0-1.051-1.033,1.977,1.977,0,0,0-1.521.2.339.339,0,0,1-.446-.042c-.1-.092-.2-.189-.307-.284a1.214,1.214,0,0,0-1.643-.061,7.563,7.563,0,0,1-.614.512A.588.588,0,0,1,10.883,8c-.215-.115-.437-.215-.659-.316a2.153,2.153,0,0,0-.695-.248A2.091,2.091,0,0,0,7.541,8.562a9.915,9.915,0,0,0-.405.986c-.559,1.545-1.015,3.123-1.487,4.7a1.528,1.528,0,0,0,.634,1.777,1.755,1.755,0,0,0,1.5.211,1.35,1.35,0,0,0,.824-.858c.543-1.281,1.032-2.584,1.55-3.875.142-.355.28-.712.432-1.064a.548.548,0,0,1,.851-.24.622.622,0,0,1,.185.539,2.161,2.161,0,0,1-.181.621c-.337.852-.68,1.7-1.018,2.552a2.564,2.564,0,0,0-.173.528.624.624,0,0,0,.333.71,1.073,1.073,0,0,0,.814.034,1.22,1.22,0,0,0,.657-.655q.758-1.488,1.511-2.978.35-.687.709-1.37a1.073,1.073,0,0,1,.357-.434.43.43,0,0,1,.463-.016.373.373,0,0,1,.153.387.7.7,0,0,1-.057.236c-.065.157-.127.316-.2.469-.42.883-.846,1.763-1.262,2.648A2.463,2.463,0,0,0,13.4,14.607Zm5.888,6.508a1.09,1.09,0,0,0-2.179.006,1.09,1.09,0,0,0,2.179-.006ZM1.028,12.139a1.038,1.038,0,1,0,.01-2.075,1.038,1.038,0,0,0-.01,2.075ZM13.782.528a1.027,1.027,0,1,0-.011,2.055A1.027,1.027,0,0,0,13.782.528ZM22.21,6.95a.882.882,0,0,0-1.763.011A.882.882,0,0,0,22.21,6.95ZM4.153,4.439a.785.785,0,1,0,.787-.78A.766.766,0,0,0,4.153,4.439Zm8.221,18.22a.676.676,0,1,0-.677.666A.671.671,0,0,0,12.374,22.658ZM22.872,12.2a.674.674,0,0,0-.665.665.656.656,0,0,0,.655.643.634.634,0,0,0,.655-.644A.654.654,0,0,0,22.872,12.2ZM7.171-.123A.546.546,0,0,0,6.613.43a.553.553,0,1,0,1.106,0A.539.539,0,0,0,7.171-.123ZM24.119,9.234a.507.507,0,0,0-.493.488.494.494,0,0,0,.494.494.48.48,0,0,0,.487-.483A.491.491,0,0,0,24.119,9.234Zm-19.454,9.7a.5.5,0,0,0-.488-.488.491.491,0,0,0-.487.5.483.483,0,0,0,.491.479A.49.49,0,0,0,4.665,18.936Z" transform="translate(0 0.123)" fill="#f64060"/>
</svg>
</a>
<a class="circle-link" title="Join the Conversation on Discord" href="https://discord.gg/angular" target="_blank" rel="noopener">
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 245 240">
<title>Discord Logo</title>
<path d="M104.4 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1.1-6.1-4.5-11.1-10.2-11.1zM140.9 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1s-4.5-11.1-10.2-11.1z"/>
<path d="M189.5 20h-134C44.2 20 35 29.2 35 40.6v135.2c0 11.4 9.2 20.6 20.5 20.6h113.4l-5.3-18.5 12.8 11.9 12.1 11.2 21.5 19V40.6c0-11.4-9.2-20.6-20.5-20.6zm-38.6 130.6s-3.6-4.3-6.6-8.1c13.1-3.7 18.1-11.9 18.1-11.9-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.5-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.7-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.3-1.8-1-2.8-1.7-2.8-1.7s4.8 8 17.5 11.8c-3 3.8-6.7 8.3-6.7 8.3-22.1-.7-30.5-15.2-30.5-15.2 0-32.2 14.4-58.3 14.4-58.3 14.4-10.8 28.1-10.5 28.1-10.5l1 1.2c-18 5.2-26.3 13.1-26.3 13.1s2.2-1.2 5.9-2.9c10.7-4.7 19.2-6 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.6 0 0-7.9-7.5-24.9-12.7l1.4-1.6s13.7-.3 28.1 10.5c0 0 14.4 26.1 14.4 58.3 0 0-8.5 14.5-30.6 15.2z"/>
</svg>
</a>
</div>
<!-- Footer -->
<footer>
Love Angular?&nbsp;
<a href="https://github.com/angular/angular" target="_blank" rel="noopener"> Give our repo a star.
<div class="github-star-badge">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>
Star
</div>
</a>
<a href="https://github.com/angular/angular" target="_blank" rel="noopener">
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" fill="#1976d2"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</a>
</footer>
<svg id="clouds" xmlns="http://www.w3.org/2000/svg" width="2611.084" height="485.677" viewBox="0 0 2611.084 485.677">
<title>Gray Clouds Background</title>
<path id="Path_39" data-name="Path 39" d="M2379.709,863.793c10-93-77-171-168-149-52-114-225-105-264,15-75,3-140,59-152,133-30,2.83-66.725,9.829-93.5,26.25-26.771-16.421-63.5-23.42-93.5-26.25-12-74-77-130-152-133-39-120-212-129-264-15-54.084-13.075-106.753,9.173-138.488,48.9-31.734-39.726-84.4-61.974-138.487-48.9-52-114-225-105-264,15a162.027,162.027,0,0,0-103.147,43.044c-30.633-45.365-87.1-72.091-145.206-58.044-52-114-225-105-264,15-75,3-140,59-152,133-53,5-127,23-130,83-2,42,35,72,70,86,49,20,106,18,157,5a165.625,165.625,0,0,0,120,0c47,94,178,113,251,33,61.112,8.015,113.854-5.72,150.492-29.764a165.62,165.62,0,0,0,110.861-3.236c47,94,178,113,251,33,31.385,4.116,60.563,2.495,86.487-3.311,25.924,5.806,55.1,7.427,86.488,3.311,73,80,204,61,251-33a165.625,165.625,0,0,0,120,0c51,13,108,15,157-5a147.188,147.188,0,0,0,33.5-18.694,147.217,147.217,0,0,0,33.5,18.694c49,20,106,18,157,5a165.625,165.625,0,0,0,120,0c47,94,178,113,251,33C2446.709,1093.793,2554.709,922.793,2379.709,863.793Z" transform="translate(142.69 -634.312)" fill="#eee"/>
</svg>
</div>
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content above * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<router-outlet></router-outlet>

51
src/app/app.constants.ts Normal file
View File

@ -0,0 +1,51 @@
import {OrderStatus, Page, PageCode} 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.Orders,
name: 'Заказы',
resName: 'orders',
onSideBar: true,
},
{
code: PageCode.BonusProgram,
name: 'Бонусная карта',
resName: 'bonus-program',
onSideBar: true,
},
];
export const orderStatuses: OrderStatus = {
'Cancelled': 'Отменен',
'InProcessing': 'В обработке',
'Unconfirmed': 'Принят',
'WaitCooking': 'Принят',
'ReadyForCooking': 'Принят',
'CookingStarted': 'Готовится',
'CookingCompleted': 'Приготовлен',
'Waiting': 'В пути',
'OnWay': 'В пути',
'Delivered': 'Выполнен',
'Closed': 'Выполнен',
};

View File

@ -1,18 +1,72 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
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 { AuthComponent } from './pages/account/auth/auth.component';
import {ProgressSpinnerModule} from "primeng/progressspinner";
import { FormsModule } from '@angular/forms';
import { AccountComponent } from './pages/account/account.component';
import { ExitComponent } from './components/exit/exit.component';
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 { MessageService } from 'primeng/api';
import { FooterButtonsComponent } from './components/footer-buttons/footer-buttons.component';
@NgModule({
declarations: [
AppComponent
AppComponent,
NavbarComponent,
MainComponent,
CardComponent,
AuthComponent,
AccountComponent,
ExitComponent,
BonusProgramComponent,
OrdersComponent,
OrderInfoComponent,
FooterButtonsComponent,
],
imports: [
BrowserModule,
AppRoutingModule
AppRoutingModule,
RouterModule.forRoot([
{
path: '**',
component: MainComponent
}
]),
InputMaskModule,
ProgressSpinnerModule,
FormsModule,
HttpClientModule,
BrowserAnimationsModule,
BrowserModule,
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
// Register the ServiceWorker as soon as the application is stable
// or after 30 seconds (whichever comes first).
registrationStrategy: 'registerWhenStable:30000'
}),
AngularFireModule.initializeApp(environment.firebase),
AngularFireMessagingModule,
ToastModule,
],
providers: [],
providers: [DialogService, MessageService],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1 @@
<p>card works!</p>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CardComponent } from './card.component';
describe('CardComponent', () => {
let component: CardComponent;
let fixture: ComponentFixture<CardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ CardComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(CardComponent);
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-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.scss']
})
export class CardComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,13 @@
<div>
<H2>Вы действительно хотите выйти?</H2>
<button
class="woocommerce-button button"
style="margin-right: 1rem"
(click)="onClick(true)"
>
Да
</button>
<button class="woocommerce-button button" (click)="onClick(false)">
Нет
</button>
</div>

View File

@ -0,0 +1,9 @@
button {
margin-right: 1rem;
padding: 4px 21px;
margin-top: 8px;
background-color: #009688;
color: #fff;
border-radius: 3px;
border: none;
}

View File

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

View File

@ -0,0 +1,19 @@
import { Component, OnInit } from '@angular/core';
import { DynamicDialogRef } from 'primeng/dynamicdialog';
@Component({
selector: 'app-exit',
templateUrl: './exit.component.html',
styleUrls: ['./exit.component.scss']
})
export class ExitComponent {
constructor(
public dialogRef: DynamicDialogRef
) { }
onClick(val: boolean): void {
this.dialogRef.close(val);
}
}

View File

@ -0,0 +1,4 @@
<div class="footer-buttons-container">
<button *ngIf="deferredPrompt && token?.length" class="footer-buttons-container__button" (click)="downloadPWA()">Установить на главный экран</button>
<button *ngIf="!isPermissionNotifications" class="footer-buttons-container__button" (click)="requestPermission()" value="click to copy" >Подписаться на уведомления</button>
</div>

View File

@ -0,0 +1,23 @@
:host {
position: fixed;
bottom: 16px;
width: 100%;
display: flex;
justify-content: center;
.footer-buttons-container {
max-width: 400px;
width: 90vw;
&__button {
width: 100%;
height: 34px;
background: #197664;
color: #fff;
border-radius: 5px;
font-weight: 600;
letter-spacing: 2px;
border: none;
margin-top: 8px;
cursor: pointer;
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,23 @@
<div class="container">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" style="height: 100%; width: fit-content;"
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#fff" stroke="none">
<path d="M530 4151 c-55 -17 -110 -52 -144 -93 -70 -81 -66 5 -66 -1499 0
-1547 -7 -1422 86 -1516 90 -91 -109 -83 2154 -83 2211 0 2056 -5 2138 66 24
20 55 59 70 88 l27 51 0 1395 0 1395 -27 50 c-31 59 -67 94 -128 126 l-45 24
-2020 2 c-1111 1 -2031 -2 -2045 -6z m3876 -327 c57 -27 74 -74 74 -199 l0
-105 -1920 0 -1920 0 0 108 c0 124 15 166 71 194 32 17 141 18 1847 18 1660 0
1817 -1 1848 -16z m74 -1852 c0 -550 -1 -589 -18 -621 -10 -19 -34 -43 -53
-53 -32 -17 -110 -18 -1849 -18 -1708 0 -1817 1 -1850 18 -72 35 -70 17 -70
675 l0 587 1920 0 1920 0 0 -588z"/>
<path d="M960 2000 l0 -80 960 0 960 0 0 80 0 80 -960 0 -960 0 0 -80z"/>
<path d="M3520 1840 l0 -240 320 0 320 0 0 240 0 240 -320 0 -320 0 0 -240z"/>
<path d="M960 1680 l0 -80 480 0 480 0 0 80 0 80 -480 0 -480 0 0 -80z"/>
</g>
</svg>
<h1 class="title">Card Project</h1>
</div>

View File

@ -0,0 +1,18 @@
.container {
display: flex;
box-sizing: border-box;
padding: 12px 16px;
width: 100%;
flex-direction: row;
align-items: center;
white-space: nowrap;
height: 64px;
background: #008376;
color: #fff;
}
.title {
font-weight: 400;
font-size: 20px;
margin-left: 12px;
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NavbarComponent } from './navbar.component';
describe('NavbarComponent', () => {
let component: NavbarComponent;
let fixture: ComponentFixture<NavbarComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ NavbarComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(NavbarComponent);
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-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
.woocommerce-MyAccount-content {
max-width: 400px;
margin-left: calc(50vw - 200px);
}
.container-progressbar {
width: 80%;
transform: translate(0, 0);
margin: 18px 10% 90px;
}
.steps {
position: relative;
display: flex;
justify-content: space-between;
width: 100%;
}
.step {
width: 20px;
height: 20px;
background: #fff;
border: 2px solid #acaca6;
border-radius: 50%;
transition: background 1s;
position: relative;
.status-image {
width: 80px;
height: 80px;
position: absolute;
top: 25px;
left: -32px;
}
}
.step.selected {
border: 2px solid #f9b004;
}
.step.completed {
border: 2px solid #f9b004;
background: #f9b004;
}
.step.cancelled {
background: #d7120b;
border: 2px solid #d7120b;
}
.progress {
position: absolute;
width: 100%;
height: 50%;
border-bottom: 2px solid #acaca6;
z-index: -1;
}
.percent {
position: absolute;
width: 0;
top: 2px;
height: 100%;
border-bottom: 2px solid #f9b004;
z-index: 1;
transition: width 1s;
}
p {
margin: 16px 0;
}
.woocommerce-order-details {
&__title {
font-weight: 600;
font-size: 18px;
}
}
.woocommerce-table {
border: 2px solid #dee2e6;
border-radius: 0.25rem;
border-collapse: separate;
text-align: left;
margin-top: 8px;
th {
font-weight: 600;
}
th, td {
padding: 0.7rem 1.5rem;
border-bottom: 2px solid #dee2e6;
}
}
.woocommerce-column {
&__title {
margin-top: 16px;
font-weight: 600;
font-size: 18px;
}
}
address {
border: 1px solid #dee2e6;
border-bottom-width: 2px;
border-right-width: 2px;
text-align: left;
width: 100%;
border-radius: 5px;
padding: 10px 12px;
margin-top: 8px;
}

View File

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

View File

@ -0,0 +1,43 @@
import { Component, Input, OnInit } from '@angular/core';
import { orderStatuses } from 'src/app/app.constants';
import { AcceptedOrder, OrderProduct } from 'src/app/interface/data';
import * as moment from 'moment-timezone';
@Component({
selector: 'app-order-info',
templateUrl: './order-info.component.html',
styleUrls: ['./order-info.component.scss']
})
export class OrderInfoComponent implements OnInit {
@Input() order!: AcceptedOrder;
@Input() loadingStatus: boolean = false;
percent: number = 0;
readonly moment = moment;
constructor() { }
ngOnInit(): void {
this.setPercent();
}
setPercent() {
const statusIndex = this.getStatusIndex(this.order.status);
if (statusIndex !== -1 && statusIndex !== 0) {
this.percent = (statusIndex - 1) * 20;
}
}
formatStatus(status: string): string|undefined{
const key = Object.keys(orderStatuses).find((el) => status === el) ?? '';
return orderStatuses[key];
}
getStatusIndex(status: string) {
return [...new Set(Object.values(orderStatuses))].findIndex((value) => value === this.formatStatus(status));
}
getItemModifiersName(item: OrderProduct): string[]{
return Object.keys(item.modifiers);
}
}

161
src/app/interface/data.ts Normal file
View File

@ -0,0 +1,161 @@
export enum PageCode {
Auth,
Orders,
BonusProgram
}
export interface Page {
code: PageCode;
component?: any;
name: string;
getMethod?: string;
resName?: string;
onSideBar: boolean
}
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;
}
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 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;
}

View File

@ -0,0 +1,62 @@
import {Modifier, Product} from "../interface/data";
export class OrderProduct implements Product{
constructor(product: Product,guid: string, amount: number = 1) {
this.category_id = product.category_id;
this.currency_symbol = product.currency_symbol;
this.description = product.description;
this.id = product.id;
this.image_gallery = product.image_gallery;
this.image_url = product.image_url;
this.modifier_data = product.modifier_data;
this.name = product.name;
this.price = product.price;
this.stock_status = product.stock_status;
this.amount = amount;
this.guid = guid;
this.short_description = product.short_description;
}
public amount: number;
public category_id: number;
public currency_symbol: string;
public description?: string;
public short_description?: string;
public id: number;
public image_gallery: string[];
public image_url: string;
public modifier_data: Modifier[];
public name: string;
public price: string;
public stock_status: string;
public guid: string;
get finalPrice(): number{
const modifiersPrice = this.modifier_data.reduce<number>((previousValue, currentValue) => {
return previousValue + currentValue.options.reduce<number>((previousOptionValue, currentOptionValue) => {
return previousOptionValue + Number(currentOptionValue.price);
}, 0);
}, 0);
return (Number(this.price) + modifiersPrice) * this.amount;
new Date()
}
toJson(){
return {
id: this.id,
amount: this.amount,
name: this.name,
modifiers: this.modifier_data?.map(modifier => {
return {
id: modifier.id,
options: modifier.options,
}
}),
}
}
}

68
src/app/models/order.ts Normal file
View File

@ -0,0 +1,68 @@
import {DeliveryData, UserData} from "../interface/data";
import {OrderProduct} from "./order-product";
import * as moment from 'moment';
import { CookiesService } from "../services/cookies.service";
export interface OrderInfo {
products: OrderProduct[];
userData?: UserData;
deliveryData?: DeliveryData;
phone: string;
token: string | undefined;
}
export class Order {
public products: OrderProduct[];
public userData?: UserData;
public deliveryData?: DeliveryData;
public phone: string;
public token: string | undefined;
constructor(
orderInfo: OrderInfo
) {
this.products = orderInfo.products;
this.userData = orderInfo.userData;
this.deliveryData = orderInfo.deliveryData;
this.phone = orderInfo.phone;
this.token = orderInfo.token;
}
get price(): number {
return this.products.reduce<number>((previousValue, currentValue) => previousValue + currentValue.finalPrice, 0);
}
toJson(): any {
const date = moment(this.deliveryData?.deliveryDate ?? Date.now());
return {
items: this.products.map(product => {
return product.toJson();
}),
user_data: {
phone: this.phone,
...this.userData
},
payment_method: this.deliveryData?.paymentMethod.type,
delivery_time: date.format('HH:mm'),
delivery_date: date.format("YYYY-MM-DD"),
delivery_instance_id: this.deliveryData?.deliveryType?.id,
persons: 1,
payments: [
{
type: this.deliveryData?.paymentMethod.type,
summ: this.price,
},
{
type: "crm4retail",
summ: 0,
payload: {
id: "c07a10d8-ba7e-43b0-92aa-ae470060bc7d"
}
}
],
comment: this.deliveryData?.comment,
token: this.token
}
}
}

View File

@ -0,0 +1,34 @@
<div class="woocommerce">
<nav *ngIf="currentPage.code !== PageCode.Auth" class="woocommerce-MyAccount-navigation">
<ul>
<ng-container *ngFor="let page of pageList; let index = index;">
<li
*ngIf="page.onSideBar"
class="woocommerce-MyAccount-navigation-link"
[ngClass]="{
'is-active': page === currentPage,
'first': index === 1
}"
(click)="changePage($event, page)"
>
<a href="#">{{page.name}}</a>
</li>
</ng-container>
<li class="woocommerce-MyAccount-navigation-link">
<a href="#" (click)="logout($event)">Выход</a>
</li>
</ul>
</nav>
<div [ngSwitch]="currentPage.code" class="">
<ng-container *ngSwitchCase="PageCode.Auth">
<app-auth [handleHttpError]="handleHttpErrorFunc" (phoneConfirmed)="phoneConfirmed()"></app-auth>
</ng-container>
<ng-container *ngSwitchCase="PageCode.Orders">
<app-orders></app-orders>
</ng-container>
<ng-container *ngSwitchCase="PageCode.BonusProgram">
<app-bonus-program></app-bonus-program>
</ng-container>
</div>
</div>

View File

@ -0,0 +1,36 @@
:host {
.woocommerce {
min-height: calc(100vh - 64px);
padding: 24px 12px;
nav {
margin-bottom: 24px;
display: flex;
justify-content: center;
ul {
max-width: 400px;
width: 100%;
background: #161616;
border-radius: 6px;
display: flex;
justify-content: space-between;
li {
padding: 12px;
width: 100%;
white-space: nowrap;
text-align: center;
cursor: pointer;
&.is-active {
background-color: #009688;
}
&.first {
border-radius: 7px 0 0 7px;
}
a {
text-decoration: none;
color: #fff;
}
}
}
}
}
}

View File

@ -0,0 +1,102 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import {CookiesService} from "../../services/cookies.service";
import {ActivatedRoute, Router} from "@angular/router";
import {Page, PageCode} from "../../interface/data";
import {environment} from "../../../environments/environment";
import {PageList, PageListWithBonus} from "../../app.constants";
import {HttpErrorResponse} from "@angular/common/http";
import {ExitComponent} from "../../components/exit/exit.component";
import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
@Component({
selector: 'app-account',
templateUrl: './account.component.html',
styleUrls: ['./account.component.scss'],
providers:[DialogService],
})
export class AccountComponent implements OnInit {
@Output() setUserDataOrderPage = new EventEmitter<null>();
constructor(
private cookiesService: CookiesService,
private router: Router,
private route: ActivatedRoute,
private dialogService: DialogService,
) {}
public currentPage!: Page;
public handleHttpErrorFunc = this.handleHttpError.bind(this);
private ref!: DynamicDialogRef;
readonly PageCode = PageCode;
readonly pageList = environment.hasBonusProgram ? PageListWithBonus : PageList;
ngOnInit(): void {
this.currentPage = this.getToken() ? this.pageList[2] : this.pageList[0];
document.body.classList.add('woocommerce-account', 'woocommerce-page', 'woocommerce-orders');
}
phoneConfirmed(): void{
this.currentPage = this.pageList[2];
}
changePage(event: MouseEvent, page: Page): void{
event.preventDefault();
this.currentPage = page;
}
handleHttpError(error: HttpErrorResponse): void {
if (error.status === 500) {
this.logout();
}
}
setToken(token: string): void{
this.cookiesService.setCookie('token', token);
}
getToken(): string|void{
return this.cookiesService.getItem('token');
}
deleteToken(): void{
this.cookiesService.deleteCookie('token');
this.router.navigate([''], {
queryParams: {},
});
}
logout(event?: MouseEvent){
if(event){
event.preventDefault();
}
this.ref = this.dialogService.open(ExitComponent, {
width: 'auto',
style: {
'max-width': '90vw',
'max-height': '90vh',
},
contentStyle: {
'max-height': '90vh',
height: 'auto',
'max-width': '90vw',
overflow: 'auto',
'border-radius': '4px',
},
baseZIndex: 10000,
autoZIndex: true,
dismissableMask: true,
closeOnEscape: true,
showHeader: false,
});
this.ref.onClose.subscribe(
result => {
if (result) {
this.currentPage = this.pageList[0];
this.deleteToken();
}
}
);
}
}

View File

@ -0,0 +1,94 @@
<div class="woocommerce-notices-wrapper"></div>
<h2>Вход</h2>
<ng-container *ngIf="!isCodeConfirm; else confirmPhoneField">
<form
class="woocommerce-form woocommerce-form-login login"
(submit)="getCode($event)"
>
<p
class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide"
>
<label for="phone"
>Номер телефона&nbsp;<span class="required">*</span></label
>
<p-inputMask
mask="+7 (999) 999-99-99"
characterPattern="[0-9]"
styleClass="woocommerce-Input woocommerce-Input--text input-text"
name="phone"
inputId="phone"
autocomplete="phone"
placeholder="+7 (___) ___-__-__"
[unmask]="true"
[(ngModel)]="phone"
></p-inputMask>
</p>
<p class="form-row">
<button
type="submit"
class="woocommerce-button button woocommerce-form-login__submit"
name="login"
value="Получить код"
[disabled]="loading || phone.length < 10"
>
{{ loading ? "" : "Получить код" }}
<p-progressSpinner
*ngIf="loading"
[style]="{ width: '16px', height: '16px' }"
strokeWidth="2"
styleClass="angular-spinner"
></p-progressSpinner>
</button>
</p>
</form>
</ng-container>
<ng-template #confirmPhoneField>
<form
class="woocommerce-form woocommerce-form-login login"
action="false"
(submit)="confirmCode($event)"
>
<p
class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide"
>
<label for="code">
Введите 4 последних цифры позвонившего вам номера телефона. На звонок
отвечать не нужно.<br />
Например: +7 (XXX) XXX-<span style="color: #d7120b">XX</span>-<span
style="color: #d7120b"
>XX</span
>
</label>
<input
pInputText
type="text"
class="woocommerce-Input woocommerce-Input--text input-text"
name="code"
id="code"
autocomplete="code"
placeholder="****"
[(ngModel)]="code"
/>
</p>
<p class="form-row">
<button
type="submit"
class="woocommerce-button button woocommerce-form-login__submit"
name="login"
value="Войти"
[disabled]="loading"
>
{{ loading ? "" : "Войти" }}
<p-progressSpinner
*ngIf="loading"
[style]="{ width: '16px', height: '16px' }"
strokeWidth="2"
styleClass="angular-spinner"
></p-progressSpinner>
</button>
</p>
<p style="color: red; margin: 0" *ngIf="errorConfirmCode">
Пароль введен неверно
</p>
</form>
</ng-template>

View File

@ -0,0 +1,52 @@
:host{
.woocommerce-form-login__submit{
width: 150px;
}
h2 {
color: #fff;
text-align: center;
font-size: 24px;
margin-bottom: 16px;
}
.woocommerce-form {
display: flex;
flex-direction: column;
align-items: center;
}
.form-row {
width: 80%;
margin-bottom: 16px;
max-width: 400px;
.button {
width: 100%;
height: 37px;
background: #197664;
color: #fff;
border-radius: 5px;
font-weight: 600;
letter-spacing: 2px;
border: none;
}
label {
display:inline-block;
margin-bottom: 8px;
color: #fff;
}
.input-text {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 1rem;
color: #495057;
background: #ffffff;
padding: 0.5rem 0.75rem;
border: 1px solid #ced4da;
transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
-webkit-appearance: none;
appearance: none;
border-radius: 4px;
width: 100%;
}
}
}

View File

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

View File

@ -0,0 +1,76 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { CookiesService } from 'src/app/services/cookies.service';
import { FormatPhoneService } from 'src/app/services/format-phone.service';
import { JsonrpcService, RpcService } from 'src/app/services/jsonrpc.service';
@Component({
selector: 'app-auth',
templateUrl: './auth.component.html',
styleUrls: ['./auth.component.scss']
})
export class AuthComponent {
@Input() handleHttpError!: (error: HttpErrorResponse) => void;
@Output() phoneConfirmed = new EventEmitter<null>();
public phone: string = '';
public isCodeConfirm = false;
public code: string = '';
public phoneToConfirm!: string;
public loading = false;
public errorConfirmCode: boolean = false;
constructor(
private phoneFormatter: FormatPhoneService,
private jsonrpc: JsonrpcService,
private cookiesService: CookiesService,
private router: Router,
private route: ActivatedRoute,
) {
}
getCode(event: SubmitEvent): void {
event.preventDefault();
this.loading = true;
this.phoneToConfirm = '+7' + this.phone.replace(/\D/g, '');
this.jsonrpc.rpc({
method: 'sendVerifyByPhone',
params: [this.phoneToConfirm]
}, RpcService.authService, false).subscribe({
next: (result) => {
if (result.code === 0) {
this.isCodeConfirm = true;
}
this.loading = false;
},
error: this.handleHttpError
}
);
}
confirmCode(event: SubmitEvent): void {
event.preventDefault();
this.jsonrpc.rpc({
method: 'getTokenByPhone',
params: [this.phoneToConfirm, this.code]
}, RpcService.authService, false).subscribe({
next: (result) => {
if (result.code === 0) {
this.cookiesService.setCookie('token', result?.data?.token);
this.router.navigate(['/auth'], {
queryParams: {
token: result?.data?.token
},
});
this.phoneConfirmed.emit(null);
} else {
this.errorConfirmCode = true;
}
},
error: this.handleHttpError
}
);
}
}

View File

@ -0,0 +1,63 @@
<div class="woocommerce-MyAccount-content">
<span class="explanation">*Нажмите на карту, чтобы перевернуть её</span>
<div [ngClass]="{
'card-content': true,
'active_back': isCardBack
}" (click)="rotateCard()">
<div class="card-content__front">
<p-progressSpinner
*ngIf="loadingBonuses"
[style]="{ width: '100%', height: '100%' }"
strokeWidth="2"
styleClass="angular-spinner"
></p-progressSpinner>
<div *ngIf="!loadingBonuses">
<div class="card-content__logo">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" style="height: 100%; width: fit-content;"
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#03d1be" stroke="none">
<path d="M530 4151 c-55 -17 -110 -52 -144 -93 -70 -81 -66 5 -66 -1499 0
-1547 -7 -1422 86 -1516 90 -91 -109 -83 2154 -83 2211 0 2056 -5 2138 66 24
20 55 59 70 88 l27 51 0 1395 0 1395 -27 50 c-31 59 -67 94 -128 126 l-45 24
-2020 2 c-1111 1 -2031 -2 -2045 -6z m3876 -327 c57 -27 74 -74 74 -199 l0
-105 -1920 0 -1920 0 0 108 c0 124 15 166 71 194 32 17 141 18 1847 18 1660 0
1817 -1 1848 -16z m74 -1852 c0 -550 -1 -589 -18 -621 -10 -19 -34 -43 -53
-53 -32 -17 -110 -18 -1849 -18 -1708 0 -1817 1 -1850 18 -72 35 -70 17 -70
675 l0 587 1920 0 1920 0 0 -588z"/>
<path d="M960 2000 l0 -80 960 0 960 0 0 80 0 80 -960 0 -960 0 0 -80z"/>
<path d="M3520 1840 l0 -240 320 0 320 0 0 240 0 240 -320 0 -320 0 0 -240z"/>
<path d="M960 1680 l0 -80 480 0 480 0 0 80 0 80 -480 0 -480 0 0 -80z"/>
</g>
</svg>
<h3 class="title">Card Project</h3>
</div>
<div class="card-content__footer">
<div class="card-content__number">
<span>#{{accountData.CardNumber}}</span>
</div>
<div class="card-content__bonuses">
<span>Доступно:
<span class="count">
{{accountData.Bonuses}}
</span>
</span>
</div>
</div>
</div>
<!-- <div class="bonus-account__container">
<h3>Доступно</h3>
<div *ngIf="accountData" class="bonus-account__value">
{{ accountData.Bonuses }}
</div>
</div> -->
</div>
<div class="card-content__back">
<div class="card-content__barcode-container">
<svg id="barcode"></svg>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,87 @@
:host {
.woocommerce-MyAccount-content {
display: flex;
flex-direction: column;
align-items: center;
.card-content {
position: relative;
height: 200px;
width: 100%;
max-width: 400px;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
&__front, &__back {
display: block;
transition-timing-function: cubic-bezier(.175, .885, .32, 1.275);
transition-duration: .7s;
transition-property: transform, opacity;
color: #fff;
width: 100%;
height: 100%;
background: #fdfdfd;
border-radius: 12px;
border: solid #a3a3a3 1px;
box-shadow: 0 0 3px 1px #fff;
padding: 12px;
background-size: cover;
}
&__front {
transform: rotateY(0deg);
background-image: url(../../../../assets/background.svg);
}
&__back {
position: absolute;
opacity: 0;
top: 0px;
left: 0px;
transform: rotateY(-180deg);
background: #000;
}
&.active_back {
> .card-content__front {
transform: rotateY(180deg);
opacity: 0;
}
> .card-content__back {
opacity: 1;
transform: rotateY(0deg);
}
}
&__logo {
height: 30px;
display: flex;
align-items: center;
justify-content: space-between;
.title {
color: #03d1be;
font-weight: 600;
letter-spacing: 2px;
}
}
&__footer {
display: flex;
justify-content: space-between;
align-items: flex-end;
position: absolute;
bottom: 12px;
width: calc(100% - 24px);
.count {
font-size: 22px;
}
}
&__barcode-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
}
.explanation {
font-size: 12px;
margin-bottom: 8px;
}
}
}

View File

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

View File

@ -0,0 +1,93 @@
import { Component, OnInit } from '@angular/core';
import { lastValueFrom } from 'rxjs';
import { orderStatuses } from 'src/app/app.constants';
import { BonusProgramAccount, 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';
@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;
public isCardBack: boolean = false;
readonly orderStatuses = orderStatuses;
readonly moment = moment;
constructor(
private jsonrpc: JsonrpcService,
) { }
ngOnInit(): void {
this.getAccountData();
}
rotateCard() {
this.isCardBack = !this.isCardBack
}
async getAccountData(): Promise<void>{
this.loadingBonuses = true;
this.accountData = (await lastValueFrom(
this.jsonrpc.rpc({
method: 'GetAccounts',
params: []
},
RpcService.bonusService
)))['Cards'][0];
barcode("#barcode")
.options({font: "OCR-B"}) // Will affect all barcodes
.EAN13(`${this.accountData.CardNumber}`.padStart(12, "0"), {fontSize: 18, textMargin: 0})
.render();
console.log(this.accountData)
this.loadingBonuses = false;
const transactions: Transaction[] = (await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'GetAccountTransactions',
params: []
},
RpcService.bonusService
)))['Transactions'];
const purchases: Purchase[] = (await lastValueFrom(
this.jsonrpc.rpc(
{
method: 'GetAccountPurchase',
params: []
},
RpcService.bonusService
)))['Purchases'];
this.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.forEach((transaction) => {
if(!transaction.HasPurchase){
this.purchases.push({
ID: transaction.ID,
PurchaseDate: transaction.Date,
Transactions: [transaction],
IsSingleTransaction: true,
})
}
});
this.purchases = this.purchases.sort((a,b) => {
return moment(a.PurchaseDate).date() - moment(b.PurchaseDate).date();
});
}
}

View File

@ -0,0 +1,118 @@
<ng-container
*ngIf="orders.length !== 0 && !ordersLoadingStatus && selectedOrder === null"
>
<app-order-info [order]="orders[0]!" [loadingStatus]="true"></app-order-info>
</ng-container>
<div
*ngIf="selectedOrder === null; else orderInfo"
class="woocommerce-MyAccount-content"
>
<table
class="woocommerce-orders-table woocommerce-MyAccount-orders shop_table shop_table_responsive my_account_orders account-orders-table"
>
<thead>
<tr>
<th
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-number"
>
<span class="nobr">Заказ</span>
</th>
<th
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-date"
>
<span class="nobr">Дата</span>
</th>
<th
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-status"
>
<span class="nobr">Статус</span>
</th>
<th
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-total"
>
<span class="nobr">Итого</span>
</th>
<th
class="woocommerce-orders-table__header woocommerce-orders-table__header-order-actions"
>
<span class="nobr">Действия</span>
</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="let order of ordersShortArray"
class="woocommerce-orders-table__row woocommerce-orders-table__row--status-processing order"
>
<td
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-number"
data-title="Заказ"
>
<a href="#" (click)="showOrderDetails($event, order.id)">{{
order.id
}}</a>
</td>
<td
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-date"
data-title="Дата"
>
<time [dateTime]="order.date_created">{{
moment(order.date_created).format("DD.MM.YYYY")
}}</time>
</td>
<td
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-status"
data-title="Статус"
>
{{ formatStatus(order.status) }}
</td>
<td
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-total"
data-title="Итого"
>
<span class="woocommerce-Price-amount amount"
><span class="woocommerce-Price-currencySymbol">{{
order.currency_symbol
}}</span
>{{ order.total }}</span
>
</td>
<td
class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-actions"
data-title="Действия"
>
<a
href="#"
class="woocommerce-button button view"
(click)="showOrderDetails($event, order.id)"
>Просмотр</a
>
</td>
</tr>
</tbody>
</table>
<p
*ngIf="orders.length !== ordersShortArray.length"
class="show-more-orders"
(click)="getMoreOrders()"
>
Показать больше
</p>
<div
*ngIf="ordersLoadingStatus"
class="angular-spinner-container"
style="width: 100%; height: 100%; position: static"
>
<p-progressSpinner styleClass="angular-spinner"></p-progressSpinner>
</div>
<p
*ngIf="orders.length === 0 && !ordersLoadingStatus"
style="width: 100%; text-align: center"
>
Нет заказов
</p>
</div>
<ng-template #orderInfo>
<app-order-info [order]="selectedOrder!"></app-order-info>
</ng-template>

View File

@ -0,0 +1,56 @@
.show-more-orders {
text-align: center;
cursor: pointer;
color: #009688;
margin-top: 8px;
}
.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%;
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;
}
&__cell-order-actions::before {
display: none;
}
&__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;
}
}

View File

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

View File

@ -0,0 +1,98 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AcceptedOrder } from 'src/app/interface/data';
import { WpJsonService } from 'src/app/services/wp-json.service';
import * as moment from 'moment-timezone';
import { orderStatuses } from 'src/app/app.constants';
@Component({
selector: 'app-orders',
templateUrl: './orders.component.html',
styleUrls: ['./orders.component.scss']
})
export class OrdersComponent implements OnInit {
@Input() handleHttpError!: (error: HttpErrorResponse) => void;
public orders: AcceptedOrder[] = [];
public ordersShortArray: AcceptedOrder[] = [];
public lastViewOrder: number = 4;
public selectedOrder: AcceptedOrder|null = null;
public selectedOrderId: number|null = null;
public ordersLoadingStatus: boolean = true;
readonly moment = moment;
private timer!: any;
constructor(
private wpJson: WpJsonService,
private route: ActivatedRoute,
private router: Router,
) { }
ngOnInit(): void {
this.getOrders();
this.route.queryParams.subscribe({
next: (queryParams:any) => {
this.setSelectedOrder(queryParams.order);
}
});
// this.requestTimer(1);
}
requestTimer(interval: number) {
this.timer = setInterval(() => {
if (this.permissionToRequest()) this.getOrders()
}, interval * 60000);
}
permissionToRequest() {
for (let order of this.ordersShortArray) {
if (order.status !== 'Delivered' && order.status !== 'Closed' && order.status !== 'Cancelled' ) {
return true
}
}
return false
}
getOrders(): void{
this.wpJson.getOrders().subscribe({
next: (result) => {
this.orders = result;
this.ordersShortArray = this.orders.slice(0, this.lastViewOrder);
this.setSelectedOrder(this.selectedOrderId);
},
error: this.handleHttpError
}
);
this.ordersLoadingStatus = false;
}
setSelectedOrder(orderId?:number|null): void{
this.selectedOrderId = orderId ?? null;
this.selectedOrder = this.orders.find((el) => el.id == this.selectedOrderId) ?? null;
}
showOrderDetails(event: MouseEvent, orderId: number): void{
event.preventDefault();
this.router.navigate([], {
relativeTo: this.route,
queryParams: {
order: orderId
},
queryParamsHandling: 'merge',
})
}
formatStatus(status: string): string|undefined{
const key = Object.keys(orderStatuses).find((el) => status === el) ?? '';
if (key === '') {
return orderStatuses['InProcessing']
}
return orderStatuses[key];
}
getMoreOrders() {
this.lastViewOrder += 4;
this.ordersShortArray = this.orders.slice(0, this.lastViewOrder);
}
}

View File

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

View File

@ -0,0 +1,6 @@
.main-container {
width: 100vw;
min-height: 100vh;
background-image: url(../../../assets/background.svg);
background-position: center;
}

View File

@ -0,0 +1,130 @@
import { Component, ComponentRef, ElementRef, EmbeddedViewRef, OnInit, Renderer2, ViewContainerRef } from "@angular/core";
import { AngularFireMessaging } from "@angular/fire/compat/messaging";
import { ActivatedRoute } from "@angular/router";
import { CardComponent } from "src/app/components/card/card.component";
import { AccountComponent } from "../account/account.component";
import {MessageService} from 'primeng/api';
@Component({
selector: 'app-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit {
private cardComponent!: ComponentRef<CardComponent>;
private accountComponent!: ComponentRef<AccountComponent>;
public messagingToken!: string | null;
public deferredPrompt: any;
public isPermissionNotifications: boolean = false;
public token = ''
constructor(
private route: ActivatedRoute,
private viewContainerRef: ViewContainerRef,
private afMessaging: AngularFireMessaging,
public el: ElementRef,
public renderer: Renderer2,
private messageService: MessageService
) {
renderer.listen('window', 'appinstalled', (evt) => {
console.log('INSTALLED!!!')
})
renderer.listen('window', 'beforeinstallprompt', (e) => {
e.preventDefault()
this.deferredPrompt = e
})
route.queryParams.subscribe( (params) => {
console.log('####: ', params)
this.token = params['token']
});
}
ngOnInit(): void {
this.appendAccount();
this.checkRequestPermission()
}
downloadPWA() {
this.deferredPrompt.prompt();
this.deferredPrompt.userChoice.then((res: any) => {
if (res.outcome === 'accepted') {
this.messageService.add({severity:'success', summary:'Спасибо за установку!'});
console.log('User Accepted!!!')
}
this.deferredPrompt = null;
})
}
checkRequestPermission() {
this.isPermissionNotifications = Notification.permission !== 'granted' ? false : true
}
requestPermission() {
if (!('serviceWorker' in navigator)) {
this.messageService.add({severity:'error', summary:'Не поддерживается в Вашем браузере!'});
return;
}
if (!('PushManager' in window)) {
// Браузер не поддерживает push-уведомления.
this.messageService.add({severity:'error', summary:'Не поддерживается в Вашем браузере!'});
return;
}
this.afMessaging.requestPermission.subscribe({
next: () => {
console.log('Permission granted! Save to the server!')
},
error: e => console.error(e)
})
this.afMessaging.requestToken.subscribe({
next: (token) => {
this.messagingToken = token;
if (this.messagingToken) {
this.messageService.add({severity:'success', summary:'Спасибо за подписку!'});
this.isPermissionNotifications = true;
}
console.log(token)
},
error: e => console.error(e)
})
}
// test function
copyMessage(val: string | null){
const selBox = document.createElement('textarea');
selBox.style.position = 'fixed';
selBox.style.left = '0';
selBox.style.top = '0';
selBox.style.opacity = '0';
if (val) selBox.value = val;
document.body.appendChild(selBox);
selBox.focus();
selBox.select();
document.execCommand('copy');
document.body.removeChild(selBox);
}
appendCard(): void {
const route = this.route.snapshot.url[0]?.path;
const element = document.getElementsByClassName('main-container');
if (!route && element[0]) {
this.cardComponent = this.viewContainerRef.createComponent(CardComponent);
const domElem = (this.cardComponent.hostView as EmbeddedViewRef<any>)
.rootNodes[0] as HTMLElement;
element[0].appendChild(domElem);
}
}
appendAccount(): void {
const route = this.route.snapshot.url[0]?.path;
const element = document.getElementsByClassName('main-container');
if (element[0]) {
this.accountComponent = this.viewContainerRef.createComponent(AccountComponent);
const domElem = (this.accountComponent.hostView as EmbeddedViewRef<any>)
.rootNodes[0] as HTMLElement;
element[0].appendChild(domElem);
}
}
}

View File

@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CookiesService {
constructor() {}
getItem(key: string): string|undefined {
const matches = document.cookie.match(new RegExp(
'(?:^|; )' + key.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)'
));
return matches ? decodeURIComponent(matches[1]) : undefined;
}
setCookie(key: string, value: string, options: any = {}): void {
const now = new Date();
const time = now.getTime();
const expireTime = time + 1000*36000*4*365*3;
now.setTime(expireTime);
options = { path: '/', ...options, expires: now.toUTCString() };
if (options.expires instanceof Date) {
options.expires = options.expires.toUTCString();
}
let updatedCookie = encodeURIComponent(key) + '=' + encodeURIComponent(value);
for (const optionKey of Object.keys(options)) {
updatedCookie += '; ' + optionKey;
const optionValue = options[optionKey];
if (optionValue !== true) {
updatedCookie += '=' + optionValue;
}
}
document.cookie = updatedCookie;
}
deleteCookie(key: string): void {
this.setCookie(key, '', { 'max-age': -1 });
}
}

View File

@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { AsYouTypeFormatter } from 'google-libphonenumber';
@Injectable({
providedIn: 'root'
})
export class FormatPhoneService {
constructor() { }
formatPhoneNumber(phoneNumber: string): string{
const formatter = new AsYouTypeFormatter('RU');
if (!phoneNumber || phoneNumber.length < 2){
return '+7';
}
else{
let formattedNumber = '';
phoneNumber = phoneNumber.replace(/[^\d]/g, '');
phoneNumber = '+' + phoneNumber;
for (let i = 0; i < phoneNumber.length; i++) {
if (i === phoneNumber.length - 1){
formattedNumber = formatter.inputDigit(phoneNumber.charAt(i)).trim();
}
else {
formatter.inputDigit(phoneNumber.charAt(i));
}
}
formatter.clear();
return formattedNumber;
}
}
}

View File

@ -0,0 +1,71 @@
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CookiesService } from './cookies.service';
import { v4 as uuidv4 } from 'uuid';
export enum RpcService{
authService,
bonusService
}
export interface JsonRpcBody {
id: string;
jsonrpc: string;
method: string;
params: any;
}
@Injectable({
providedIn: 'root'
})
export class JsonrpcService {
protected readonly api = environment.appAuthEndpoint;
private jsonrpc = '2.0';
private body!: JsonRpcBody;
constructor(
private http: HttpClient,
private cookiesService: CookiesService
) { }
rpc(data: {method: string, params: any[]},service: RpcService, auth = false): Observable<any> {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json-rpc');
const options = {
headers: headers,
};
const token = decodeURI(this.cookiesService.getItem('token') ?? '');
switch (service) {
case RpcService.authService:
this.body = {
id: uuidv4(),
jsonrpc: this.jsonrpc,
method: data.method,
params: auth ? [environment.systemId, token, ...data.params] : [environment.systemId, ...data.params],
};
return this.http
.post(environment.appAuthEndpoint, this.body, options)
.pipe(map((res: any) => res.result[0]));
case RpcService.bonusService:
this.body = {
id: uuidv4(),
jsonrpc: this.jsonrpc,
method: data.method,
params: [token, ...data.params],
};
return this.http
.post(environment.appBonusEndpoint, this.body, options)
.pipe(map((res: any) => res.result));
}
}
handleHttpError(error: HttpErrorResponse): void {
console.log(error.message);
}
}

View File

View File

@ -0,0 +1,64 @@
import { Injectable } from '@angular/core';
import {environment} from "../../environments/environment";
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {CookiesService} from "./cookies.service";
import {Observable} from "rxjs";
import {JsonRpcBody} from "./jsonrpc.service";
import {DeliveryType, AcceptedOrder, Product} from "../interface/data";
import {ActivatedRoute} from "@angular/router";
import {Order} from "../models/order";
export enum Method {
}
@Injectable({
providedIn: 'root'
})
export class WpJsonService {
protected readonly api = environment.appWPEndpoint;
private body!: JsonRpcBody;
constructor(
private http: HttpClient,
private cookiesService: CookiesService,
private route: ActivatedRoute,
) { }
getDeliveryTypes(): Observable<DeliveryType[]>{
return this._request('orders/delivery-types', 'GET');
}
createOrder(order: any){
return this._request('orders', 'POST', order);
}
getOrders(): Observable<AcceptedOrder[]>{
return this._request('orders', 'GET', null, true);
}
getProductById(id: number): Observable<Product>{
return this._request(`products/${id}`, 'GET');
}
_request(path: string, method: string, body?: any, auth = false): Observable<any> {
const token = decodeURI(this.cookiesService.getItem('token') ?? '');
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json');
let urlToken = '';
if (token && token !== 'undefined' && auth) {
urlToken = '?token=' + token;
}
this.body = body;
const options = {
headers: headers,
body: this.body,
};
const url = environment.production ? window.location.origin + '/wp-json/woofood/v1/' : this.api
return this.http
.request( method, url + path + urlToken, options);
}
}

601
src/assets/background.svg Normal file
View File

@ -0,0 +1,601 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1920.000000pt" height="1080.000000pt" viewBox="0 0 1920.000000 1080.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,1080.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M0 5400 l0 -5400 9600 0 9600 0 0 5400 0 5400 -9600 0 -9600 0 0
-5400z m8975 2115 c33 -8 80 -15 105 -16 125 -3 132 -39 14 -69 -61 -15 -94
-50 -94 -99 0 -35 -4 -43 -42 -68 -25 -17 -46 -41 -52 -60 -6 -18 -18 -39 -26
-46 -18 -17 -129 -54 -191 -63 -24 -4 -66 -19 -94 -34 -27 -15 -75 -35 -105
-43 -49 -14 -62 -24 -118 -91 -35 -41 -71 -78 -81 -81 -11 -3 -44 6 -77 22
-53 26 -59 32 -75 78 -26 75 -24 127 6 164 20 22 24 36 19 56 -4 15 -1 44 6
64 19 58 2 81 -59 81 -58 0 -137 26 -146 47 -9 25 15 42 75 53 30 6 81 24 112
40 46 25 81 34 175 45 255 32 560 41 648 20z m2572 -134 c114 -8 137 -19 131
-63 l-5 -28 66 -2 c36 -2 122 -3 192 -3 l125 0 57 -39 c49 -34 59 -37 73 -25
19 16 95 28 220 35 68 4 104 2 145 -11 30 -9 102 -21 162 -26 73 -6 120 -15
147 -29 45 -23 162 -28 216 -8 41 14 216 -9 344 -45 47 -14 119 -28 160 -32
101 -9 157 -50 143 -103 -7 -27 -52 -30 -106 -7 -20 8 -46 15 -58 15 -19 0
-18 -3 11 -30 38 -35 34 -47 -35 -95 -39 -28 -58 -35 -96 -35 -82 0 -88 -8
-39 -50 38 -32 45 -44 51 -91 5 -30 11 -69 15 -87 7 -35 -8 -62 -35 -62 -23 1
-221 196 -221 219 0 10 9 30 21 45 20 25 20 26 1 26 -10 0 -27 9 -37 20 -23
26 -70 28 -60 3 18 -48 13 -50 -146 -58 l-151 -7 -14 -34 c-28 -68 -23 -74 64
-75 42 -1 87 -4 99 -7 12 -4 58 -46 103 -95 82 -90 96 -121 65 -147 -14 -11
-23 -7 -59 29 l-44 43 11 -40 c9 -33 7 -51 -13 -113 -25 -81 -43 -103 -78 -94
-16 4 -24 0 -28 -12 -3 -10 -12 -31 -20 -47 -15 -29 -14 -30 15 -54 17 -13 43
-43 57 -67 30 -53 23 -77 -30 -95 -49 -16 -76 0 -76 44 0 26 -8 41 -32 61 -18
15 -36 36 -40 46 -6 15 -18 19 -56 19 -26 0 -53 5 -59 11 -8 8 -13 8 -18 0 -6
-10 49 -41 73 -41 17 0 43 -37 37 -52 -3 -8 -18 -21 -32 -27 l-26 -12 40 -42
c68 -71 93 -116 93 -169 0 -26 -4 -57 -9 -70 -4 -13 -11 -35 -14 -49 -6 -23
-4 -26 17 -22 37 7 51 -26 31 -72 -11 -29 -19 -36 -37 -33 -20 3 -23 9 -23 43
l0 41 -33 -33 c-41 -41 -85 -63 -187 -92 -129 -37 -128 -37 -121 -72 3 -19 23
-46 46 -68 36 -32 41 -43 49 -101 10 -80 5 -94 -53 -148 -55 -50 -88 -55 -113
-14 -38 61 -86 80 -97 38 -8 -32 38 -120 75 -147 19 -13 34 -37 43 -70 8 -27
24 -61 35 -75 25 -32 17 -54 -20 -54 -27 0 -29 -2 -19 -20 6 -11 17 -20 24
-20 7 0 23 -11 35 -24 18 -19 22 -33 20 -76 -2 -35 2 -54 11 -60 8 -5 52 -14
99 -20 47 -6 111 -22 142 -36 49 -21 72 -24 170 -24 121 0 143 -6 137 -36 -3
-17 -18 -20 -138 -27 -110 -7 -145 -6 -190 7 -30 8 -76 18 -101 21 -96 12
-176 49 -240 111 -34 33 -69 78 -79 100 -28 65 -126 211 -149 224 -24 12 -27
42 -6 60 11 9 22 9 49 -1 37 -13 96 -63 96 -81 0 -6 3 -9 6 -5 3 3 -15 45 -40
94 -29 55 -46 102 -46 124 0 36 -24 171 -36 202 -4 12 -12 16 -23 11 -50 -22
-91 5 -91 61 0 36 -59 136 -87 146 -31 11 -84 -25 -179 -123 l-92 -93 -6 -80
c-4 -44 -15 -95 -25 -114 -21 -43 -64 -76 -86 -68 -17 7 -108 193 -125 257
-22 80 -59 149 -89 165 -33 17 -81 64 -81 80 0 5 -15 26 -33 46 -33 36 -33 36
-138 42 -62 3 -119 12 -143 22 -63 27 -58 12 17 -48 58 -47 62 -80 18 -148
-42 -68 -271 -222 -366 -248 -57 -16 -73 -27 -58 -42 9 -9 31 -8 95 5 128 25
128 25 128 -33 0 -77 -80 -219 -173 -308 -85 -81 -129 -136 -168 -206 -25 -47
-26 -53 -13 -78 8 -16 14 -43 14 -62 0 -18 4 -37 9 -43 12 -12 14 -31 12 -123
l-1 -74 -91 -88 c-67 -64 -90 -92 -85 -104 14 -37 18 -93 7 -113 -6 -12 -25
-29 -41 -39 -22 -13 -30 -25 -30 -45 0 -54 -105 -187 -195 -249 -51 -34 -62
-38 -151 -44 -117 -9 -130 -1 -144 91 -5 39 -19 79 -39 111 -17 28 -36 74 -41
104 -13 71 -35 138 -72 226 l-30 71 16 66 c9 36 26 86 38 112 17 40 19 53 9
79 -6 17 -11 38 -11 46 0 18 -41 97 -92 176 -31 48 -39 70 -35 90 3 16 10 50
16 76 15 68 2 91 -45 82 -31 -5 -39 -2 -75 35 -36 36 -45 40 -72 35 -18 -4
-50 -16 -72 -28 -31 -16 -62 -21 -140 -24 -161 -4 -184 9 -313 187 -74 101
-77 107 -76 160 0 30 6 74 12 98 9 31 10 60 2 108 l-11 65 41 74 c37 68 75
112 139 162 13 11 33 44 45 74 16 38 33 61 59 79 44 30 73 78 57 94 -6 6 -25
16 -43 22 l-32 11 1 72 c4 152 16 171 109 171 69 0 115 15 115 37 0 23 -20 56
-47 80 -34 27 -25 48 24 57 21 4 52 13 68 20 l30 14 -36 1 c-20 1 -51 -4 -68
-10 -27 -10 -36 -9 -49 4 -13 14 -13 18 -1 33 7 9 12 27 11 39 -2 12 4 28 12
35 22 17 20 33 -5 56 -52 47 -41 92 30 132 44 25 61 22 61 -8 0 -10 5 -22 11
-26 6 -3 9 -19 6 -34 -5 -20 1 -35 23 -61 16 -19 29 -38 30 -43 0 -5 7 -17 16
-27 12 -14 13 -22 4 -38 -10 -19 -9 -20 13 -10 25 11 127 121 127 137 0 21 46
51 69 45 18 -4 22 -2 19 8 -3 8 -26 17 -57 21 -68 8 -101 37 -101 89 0 43 31
75 105 108 25 11 45 24 45 29 0 6 20 33 45 60 41 46 56 54 140 81 112 37 166
39 295 11 181 -40 224 -81 130 -127 -44 -21 -44 -21 -19 -28 28 -7 76 12 98
39 7 8 41 29 75 46 47 23 76 30 120 30 31 0 82 9 113 20 33 11 83 20 118 20
69 0 77 4 90 45 16 46 56 55 107 26 l41 -23 61 27 c34 15 72 33 86 41 59 32
94 45 163 59 39 8 90 21 112 29 22 9 49 13 60 10 11 -3 66 -9 122 -13z m-4551
-105 c86 -32 127 -69 122 -113 -2 -18 -2 -33 0 -33 15 0 65 36 102 75 71 73
121 92 155 58 12 -12 16 -27 12 -54 -5 -40 6 -59 34 -59 14 0 17 6 12 33 -4
26 0 38 22 60 35 35 81 47 178 47 81 0 135 -15 172 -49 11 -10 37 -24 57 -30
46 -15 62 -34 54 -66 -5 -20 -1 -27 25 -40 22 -12 29 -22 27 -38 -3 -24 -57
-56 -95 -57 -18 0 -23 -6 -23 -25 0 -30 -41 -75 -67 -75 -38 0 -126 30 -147
49 -11 10 -34 21 -51 23 -41 4 -48 43 -11 58 34 12 33 28 -1 36 -41 11 -98
-26 -98 -62 0 -42 -34 -57 -115 -48 -36 3 -74 6 -84 6 -32 -1 -217 -95 -228
-115 -12 -23 -2 -67 15 -67 6 0 26 -7 42 -16 17 -9 52 -24 79 -33 28 -10 55
-26 60 -37 6 -10 12 -21 13 -23 1 -2 16 8 33 23 17 14 37 26 44 26 7 0 25 13
40 29 21 22 27 36 23 52 -6 22 7 42 82 127 49 55 201 4 201 -68 l0 -30 46 30
c25 16 52 26 59 24 14 -6 35 -77 35 -121 0 -21 11 -38 42 -64 l42 -36 -11 -49
c-10 -43 -8 -55 13 -113 27 -72 20 -97 -25 -87 -155 32 -179 52 -118 101 l32
26 -30 -5 c-16 -3 -63 -8 -103 -12 -60 -5 -71 -9 -61 -20 6 -8 8 -26 4 -44
l-7 -31 49 3 c44 3 48 1 51 -20 4 -27 -14 -52 -37 -52 -9 0 -38 -12 -66 -25
-51 -25 -105 -33 -105 -15 0 16 -29 11 -70 -12 -27 -16 -40 -30 -40 -44 0 -26
-14 -38 -65 -54 -54 -18 -155 -114 -155 -149 0 -37 -6 -42 -93 -91 -117 -67
-122 -74 -122 -182 0 -77 -3 -92 -19 -104 -11 -8 -24 -14 -28 -14 -16 0 -48
66 -48 100 0 41 -13 65 -29 55 -7 -4 -23 0 -36 9 -33 22 -49 20 -83 -9 -26
-22 -40 -25 -101 -25 -108 0 -140 -20 -173 -107 -40 -104 -41 -108 -18 -157
32 -66 40 -71 99 -51 37 12 51 22 53 38 4 27 42 47 89 47 50 0 66 -20 45 -57
-13 -24 -56 -120 -56 -127 0 -1 25 -2 55 -2 44 0 60 -4 77 -22 21 -20 21 -25
10 -67 -15 -55 -15 -100 -2 -125 8 -16 21 -19 58 -19 26 1 62 -2 79 -5 27 -6
34 -3 49 19 9 14 39 37 66 51 39 20 52 22 69 13 16 -8 24 -7 38 5 23 21 30 20
61 -9 20 -19 37 -25 75 -26 28 -1 61 2 75 6 21 5 34 -1 74 -37 64 -57 87 -80
108 -106 10 -12 34 -23 60 -27 70 -11 131 -45 143 -81 6 -17 15 -37 22 -45 6
-8 13 -30 15 -49 3 -33 5 -35 60 -46 32 -6 72 -22 90 -36 18 -13 64 -32 103
-41 48 -12 79 -26 100 -46 16 -16 41 -31 55 -33 29 -4 70 -68 70 -112 0 -16
-12 -44 -28 -65 -75 -97 -92 -135 -92 -203 0 -36 -4 -78 -9 -94 -5 -16 -17
-55 -25 -86 -19 -68 -34 -84 -89 -99 -23 -6 -61 -22 -84 -36 -42 -24 -43 -26
-43 -76 0 -42 -7 -63 -35 -107 -19 -30 -47 -80 -61 -110 -28 -60 -38 -70 -71
-70 -29 0 -37 -15 -23 -41 21 -39 4 -68 -55 -95 -40 -19 -59 -34 -69 -57 -20
-45 -29 -87 -27 -120 2 -18 -4 -33 -15 -41 -16 -12 -16 -14 8 -30 35 -23 39
-46 16 -95 -17 -37 -17 -44 -4 -68 19 -37 52 -66 104 -92 46 -24 52 -35 23
-51 -52 -27 -181 5 -264 66 -49 36 -127 143 -127 175 0 10 5 30 10 44 13 35
-4 100 -36 138 -13 16 -24 39 -24 52 0 14 -8 46 -19 72 -14 36 -16 54 -9 73
14 36 10 151 -7 217 -10 38 -15 107 -15 206 0 183 -5 196 -98 257 -90 60 -116
90 -190 233 -36 67 -73 133 -83 146 -23 29 -24 79 -3 109 12 18 13 26 4 37 -7
9 -9 26 -6 40 7 26 80 140 97 151 22 13 1 154 -23 154 -5 0 -18 -5 -30 -11
-50 -27 -143 28 -184 108 -29 58 -44 72 -85 83 -21 6 -59 26 -84 46 -38 29
-52 34 -78 29 -57 -11 -167 40 -267 124 -32 27 -35 34 -33 78 2 41 -5 60 -45
130 -26 46 -50 83 -54 83 -13 0 -9 -31 8 -77 9 -23 14 -49 11 -58 -11 -26 -46
-17 -67 18 -29 46 -70 176 -70 219 0 52 -16 87 -57 130 -36 37 -37 40 -40 125
-3 83 -2 89 26 128 15 22 38 60 51 85 12 25 30 54 40 65 22 26 64 261 57 321
-5 50 -40 108 -75 123 -29 14 -110 14 -165 1 -23 -5 -63 -12 -89 -15 -34 -4
-59 -16 -89 -41 -30 -25 -50 -34 -77 -34 -50 0 -87 20 -88 48 -1 13 -13 35
-28 51 -14 15 -26 32 -26 39 0 14 67 64 109 81 17 8 32 23 35 37 7 25 22 34
92 53 40 11 58 24 92 69 13 17 36 27 88 37 39 7 111 26 159 40 78 24 95 26
139 17 246 -52 286 -56 411 -43 149 16 177 23 244 63 29 18 63 39 75 45 35 21
138 16 212 -11z m2039 -213 c9 -8 14 -22 11 -30 -3 -8 -6 -19 -6 -24 0 -20
-80 -49 -135 -49 -65 0 -95 13 -95 40 0 10 -4 22 -10 25 -13 8 -13 42 1 47 6
2 58 5 115 6 83 1 106 -2 119 -15z m124 -359 c27 -35 26 -56 -4 -92 -32 -38
-69 -48 -102 -27 -19 13 -23 22 -18 38 7 27 13 50 14 59 1 9 64 48 78 48 6 0
21 -12 32 -26z m4066 -325 c113 -39 132 -72 69 -114 l-31 -21 28 -32 c22 -24
28 -39 23 -57 -3 -13 2 -47 11 -76 21 -64 19 -66 -97 -104 -81 -26 -88 -30
-98 -61 -11 -34 -39 -45 -65 -26 -18 13 -45 61 -45 80 0 28 72 99 109 107 17
3 44 19 60 34 l30 28 -19 59 c-10 32 -22 70 -28 84 -27 71 -31 94 -21 107 14
16 4 17 74 -8z m-6265 -754 c66 -34 120 -77 120 -95 0 -48 -96 -49 -151 -2
-25 21 -43 26 -89 27 -68 2 -95 17 -80 46 20 36 146 52 200 24z m249 -118 c34
-17 49 -43 33 -59 -14 -14 -126 -29 -165 -21 -44 9 -44 30 -1 68 33 30 44 34
74 29 19 -3 46 -11 59 -17z m5755 -49 c9 -12 16 -42 16 -66 0 -32 4 -44 18
-49 37 -13 102 -87 108 -123 3 -19 13 -57 21 -85 17 -59 8 -95 -31 -120 -24
-16 -27 -16 -59 4 -61 37 -71 56 -72 128 0 59 -2 67 -30 90 -16 14 -36 42 -44
62 -15 35 -19 136 -7 166 9 24 62 19 80 -7z m-1194 -330 c11 -18 20 -43 20
-55 0 -46 -83 -69 -92 -25 -2 9 0 38 5 65 12 58 37 63 67 15z m1102 -75 c38
-37 48 -66 27 -79 -8 -4 -9 -28 -5 -70 4 -41 3 -64 -4 -64 -5 0 -10 -5 -10
-11 0 -5 -11 -27 -25 -47 -14 -20 -25 -47 -25 -59 0 -35 -28 -55 -69 -50 -51
6 -133 40 -141 57 -54 109 -53 180 1 180 41 0 155 99 181 156 15 32 26 30 70
-13z m502 -257 c30 -34 32 -34 65 -20 53 22 83 17 177 -32 49 -25 113 -58 142
-72 54 -27 65 -49 37 -72 -24 -20 -18 -39 31 -86 25 -25 44 -50 41 -57 -10
-33 -132 -4 -167 40 l-21 26 -40 -22 c-36 -21 -44 -22 -92 -11 -102 24 -121
40 -96 86 17 32 3 47 -76 79 -43 17 -68 36 -96 72 -43 53 -48 77 -21 92 37 22
83 13 116 -23z m-59 -352 c13 -9 39 -16 57 -17 31 -2 33 -4 31 -37 -1 -19 -5
-49 -8 -67 -7 -29 -4 -33 35 -53 39 -20 43 -20 60 -5 10 9 26 42 35 73 24 83
33 102 50 108 22 9 42 -12 55 -54 7 -20 20 -55 30 -77 10 -22 21 -59 25 -83 4
-23 17 -55 30 -70 13 -16 35 -53 49 -83 13 -30 34 -63 45 -73 18 -16 21 -31
21 -90 0 -92 -18 -125 -124 -236 -45 -47 -95 -102 -110 -123 -18 -23 -54 -51
-90 -69 -60 -30 -63 -31 -134 -21 -81 12 -110 31 -143 95 -10 20 -28 43 -39
51 -11 7 -26 30 -34 49 -15 36 -37 48 -87 48 -33 0 -133 -32 -186 -59 -22 -11
-68 -23 -103 -27 -35 -4 -75 -13 -89 -20 -35 -19 -71 -17 -93 3 -23 20 -23 36
-1 70 15 22 17 46 15 136 -5 187 20 248 116 283 127 45 189 81 223 129 19 26
50 65 70 87 36 42 39 43 128 37 22 -1 37 3 39 11 7 19 82 100 94 100 5 0 20
-7 33 -16z m-2528 -56 c25 -23 29 -60 14 -112 -5 -17 -16 -58 -24 -91 -19 -79
-83 -227 -104 -242 -30 -23 -79 -16 -98 13 -26 41 -30 97 -10 136 10 18 19 59
20 91 2 64 13 80 78 121 23 15 52 45 65 66 12 22 26 40 29 40 4 0 17 -10 30
-22z m3492 -794 c39 -57 39 -70 -1 -90 -18 -9 -51 -33 -73 -53 -22 -21 -71
-56 -110 -78 -116 -67 -131 -76 -185 -120 -28 -24 -62 -43 -74 -43 -36 0 -58
22 -54 55 3 27 13 35 95 75 51 25 112 62 136 82 24 20 73 50 109 66 64 29 66
31 73 73 15 97 36 105 84 33z m-850 -168 c18 -11 13 -37 -14 -71 -43 -57 -115
-54 -115 3 0 26 22 69 43 83 10 7 67 -4 86 -15z"/>
<path d="M8520 7478 c-80 -5 -159 -11 -177 -14 l-31 -5 66 -89 67 -90 136 0
136 0 7 77 c11 133 11 133 -26 131 -18 -1 -98 -5 -178 -10z"/>
<path d="M8745 7392 c-4 -55 -4 -105 0 -111 3 -6 39 -11 82 -11 99 0 143 24
143 76 0 49 14 70 63 96 l42 22 -45 9 c-25 4 -97 11 -161 14 l-117 5 -7 -100z"/>
<path d="M8240 7451 c-14 -5 -47 -20 -75 -34 -27 -15 -74 -31 -103 -38 -29 -6
-51 -14 -47 -17 3 -3 40 -9 83 -13 75 -8 101 -21 114 -60 2 -6 42 -9 105 -7
l102 3 -66 88 c-36 48 -70 87 -77 86 -6 0 -22 -4 -36 -8z"/>
<path d="M8206 7224 c-12 -26 -14 -40 -7 -47 14 -14 14 -57 1 -57 -6 0 -19
-15 -30 -32 -16 -25 -19 -42 -14 -72 8 -49 31 -106 43 -106 5 0 53 69 107 153
54 83 104 162 112 175 l14 22 -104 0 -104 0 -18 -36z"/>
<path d="M8450 7245 c-7 -8 -59 -88 -117 -177 -95 -149 -103 -164 -87 -175 10
-7 23 -13 29 -13 7 0 40 33 74 73 55 65 70 76 119 91 32 10 80 30 107 45 28
16 66 31 86 35 41 7 49 22 49 94 l0 42 -124 0 c-97 0 -126 -3 -136 -15z"/>
<path d="M8735 7246 c-2 -6 -5 -32 -7 -58 -4 -55 -1 -56 77 -29 39 14 54 25
67 52 18 38 22 36 -71 42 -39 2 -64 -1 -66 -7z"/>
<path d="M11368 7349 c-10 -5 -51 -16 -91 -24 -84 -16 -125 -30 -148 -51 -9
-8 -29 -18 -44 -22 -22 -6 -34 -24 -70 -107 -24 -55 -42 -101 -41 -103 2 -1
90 32 197 73 107 42 237 92 289 112 100 37 196 92 183 104 -7 6 -214 30 -249
29 -5 0 -17 -5 -26 -11z"/>
<path d="M11940 7251 c-14 -4 -94 -6 -177 -3 -84 3 -153 2 -153 -1 0 -4 17
-44 39 -89 21 -46 48 -103 59 -128 11 -25 36 -80 56 -122 19 -43 39 -78 45
-78 12 0 608 107 661 118 l35 8 -165 110 c-91 60 -181 117 -200 127 -19 10
-55 30 -80 43 -45 24 -75 28 -120 15z"/>
<path d="M11480 7215 c-47 -19 -184 -72 -305 -119 l-219 -84 -83 -187 c-46
-103 -83 -190 -83 -194 0 -4 30 -12 68 -18 37 -7 125 -21 195 -34 74 -12 132
-18 137 -13 4 5 54 92 110 194 56 102 119 214 140 250 52 91 132 240 128 239
-2 -1 -41 -16 -88 -34z"/>
<path d="M10832 7228 c-7 -7 -12 -22 -12 -35 0 -30 -28 -43 -97 -43 -34 0 -90
-11 -136 -25 -43 -14 -100 -25 -128 -25 -54 0 -109 -23 -169 -71 -47 -38 -78
-48 -117 -37 -35 9 -56 37 -47 62 3 9 25 21 47 27 38 10 40 12 23 24 -20 15
-172 53 -245 62 -25 3 -61 1 -79 -4 l-34 -8 172 -213 c95 -116 175 -210 179
-208 5 4 54 23 321 126 41 16 140 54 220 85 80 30 161 62 180 71 35 15 39 21
107 181 l13 33 -44 -22 -45 -21 -40 26 c-46 30 -52 32 -69 15z"/>
<path d="M11506 7090 l-77 -139 109 -238 110 -238 118 -21 c66 -12 137 -25
158 -29 36 -7 39 -6 32 11 -20 54 -362 794 -367 794 -3 0 -41 -63 -83 -140z"/>
<path d="M12335 7220 c-11 -5 -38 -9 -61 -9 -22 -1 -48 -7 -58 -14 -16 -12 0
-25 151 -125 l169 -112 304 55 c581 104 550 98 505 107 -22 5 -83 15 -137 23
-85 13 -100 13 -133 0 -46 -20 -170 -12 -237 16 -26 11 -84 21 -135 25 -48 3
-108 12 -133 19 -56 16 -208 26 -235 15z"/>
<path d="M9760 7130 c-58 -18 -131 -79 -129 -109 0 -9 47 -58 104 -109 l103
-93 76 57 c50 37 73 60 68 68 -33 42 -164 206 -166 205 0 -1 -26 -9 -56 -19z"/>
<path d="M13250 7070 c-151 -29 -220 -42 -538 -98 -99 -18 -149 -31 -143 -37
5 -6 82 -156 171 -333 152 -304 163 -323 179 -308 10 9 31 16 48 16 27 0 31 5
46 51 23 71 21 111 -8 170 -14 27 -23 54 -20 59 9 14 38 12 55 -2 7 -7 -1 6
-19 30 -35 45 -27 43 -172 47 -47 1 -79 17 -79 39 0 7 7 36 16 65 13 45 21 55
51 67 19 9 50 14 67 13 17 -1 68 -1 114 0 l82 1 0 35 c0 28 4 36 24 41 29 7
64 -2 88 -23 10 -9 24 -13 32 -10 17 7 46 -17 46 -37 0 -7 -9 -25 -21 -40 -11
-14 -19 -32 -17 -39 4 -18 177 -181 184 -174 3 3 1 14 -5 25 -6 12 -11 41 -11
66 0 41 -4 48 -45 82 -75 61 -55 103 48 104 43 1 62 9 109 45 l26 20 -36 31
c-66 57 -7 90 98 54 68 -23 70 -23 70 -10 0 22 -59 45 -139 56 -47 7 -99 14
-116 17 -16 3 -100 -7 -185 -23z"/>
<path d="M9563 6970 c-96 -47 -115 -81 -67 -119 18 -14 41 -21 70 -21 61 0 78
-27 68 -106 -8 -66 -15 -67 104 21 44 32 79 62 76 66 -2 3 -48 46 -101 95
l-98 89 -52 -25z"/>
<path d="M10840 6966 c-47 -18 -182 -70 -300 -116 -301 -116 -298 -115 -306
-123 -4 -4 -2 -7 4 -7 7 0 128 -20 269 -45 141 -25 257 -44 258 -43 2 2 25 55
53 118 27 63 64 145 81 183 16 37 29 67 28 67 -1 -1 -40 -16 -87 -34z"/>
<path d="M12390 6913 c-121 -21 -215 -38 -462 -83 l-117 -22 25 -56 c86 -195
149 -320 166 -331 11 -6 83 -23 161 -37 78 -14 174 -31 214 -38 83 -15 78 -19
88 80 3 38 18 161 31 273 14 112 24 211 22 220 -3 15 -13 15 -128 -6z"/>
<path d="M12517 6703 c-15 -125 -31 -260 -35 -300 l-8 -72 50 -10 c90 -18 340
-61 354 -61 8 0 -52 128 -153 328 -92 180 -170 331 -174 335 -4 4 -20 -95 -34
-220z"/>
<path d="M9815 6777 c-187 -140 -190 -143 -197 -187 -14 -79 -11 -82 52 -56
30 13 111 45 180 71 69 27 167 65 218 85 l93 36 -77 95 c-42 52 -77 95 -78 96
-1 2 -87 -61 -191 -140z"/>
<path d="M11313 6743 c-54 -98 -99 -181 -101 -184 -1 -4 37 -14 85 -22 48 -9
139 -26 202 -37 62 -12 115 -19 117 -17 4 4 -39 100 -167 375 -16 34 -31 62
-33 62 -3 0 -49 -80 -103 -177z"/>
<path d="M9212 6794 c-29 -20 -28 -33 8 -74 l29 -35 0 50 c1 66 -8 80 -37 59z"/>
<path d="M9544 6718 c-6 -21 -30 -49 -102 -123 -33 -34 -81 -67 -129 -90 -31
-14 -33 -19 -33 -65 0 -28 4 -50 8 -50 10 0 261 97 282 109 16 9 38 122 39
199 1 40 0 42 -28 42 -22 0 -32 -6 -37 -22z"/>
<path d="M10110 6685 c-30 -12 -122 -48 -203 -80 -82 -31 -146 -59 -144 -62 3
-2 72 -37 155 -78 l150 -73 52 155 c28 85 50 156 48 157 -2 2 -28 -7 -58 -19z"/>
<path d="M10207 6692 c19 -48 299 -612 304 -612 3 0 21 33 39 73 126 280 199
451 195 455 -4 5 -122 27 -354 67 -79 14 -154 28 -167 31 -21 5 -23 4 -17 -14z"/>
<path d="M9270 6690 c0 -5 5 -10 10 -10 6 0 10 5 10 10 0 6 -4 10 -10 10 -5 0
-10 -4 -10 -10z"/>
<path d="M10112 6461 l-73 -218 20 -59 c28 -85 42 -93 158 -90 106 2 123 -5
123 -53 0 -37 -26 -110 -47 -133 -12 -14 -31 -19 -67 -19 -28 1 -75 -2 -103
-5 l-53 -6 0 -90 c0 -84 1 -88 18 -76 66 47 412 323 412 328 0 8 -309 640
-313 640 -1 0 -35 -98 -75 -219z"/>
<path d="M9277 6653 c-9 -15 5 -73 17 -73 7 0 20 6 30 13 18 13 18 15 1 40
-17 26 -39 35 -48 20z"/>
<path d="M9232 6638 c-15 -18 -11 -58 5 -58 19 0 25 22 15 49 -7 19 -10 20
-20 9z"/>
<path d="M10723 6493 c-28 -65 -84 -193 -125 -284 l-74 -165 85 -22 c254 -63
432 -102 441 -97 6 3 10 14 10 24 0 10 11 67 25 127 14 60 40 177 59 259 19
83 37 161 41 175 l6 25 -198 34 c-109 19 -203 36 -208 38 -6 2 -33 -50 -62
-114z"/>
<path d="M9664 6512 l-61 -24 -7 -52 c-12 -99 -13 -97 77 -173 72 -61 85 -69
100 -58 15 11 12 16 -35 46 -69 46 -116 104 -102 127 18 29 36 24 115 -27 89
-57 111 -82 133 -152 10 -28 24 -62 33 -75 14 -23 16 -23 38 -6 23 17 23 17 4
38 -29 31 -23 51 21 70 34 15 42 25 55 68 9 28 18 56 21 63 6 12 -15 24 -216
123 l-115 56 -61 -24z"/>
<path d="M13105 6520 c10 -11 20 -20 23 -20 3 0 -3 9 -13 20 -10 11 -20 20
-23 20 -3 0 3 -9 13 -20z"/>
<path d="M11201 6493 c-21 -79 -131 -576 -128 -579 2 -2 85 -23 185 -47 l183
-44 48 51 c103 110 471 516 471 520 0 4 -102 23 -430 81 -113 20 -227 40 -253
45 -67 14 -65 14 -76 -27z"/>
<path d="M9246 6465 c4 -8 8 -15 10 -15 2 0 4 7 4 15 0 8 -4 15 -10 15 -5 0
-7 -7 -4 -15z"/>
<path d="M9430 6421 l-145 -56 -3 -78 c-2 -42 0 -77 3 -77 14 0 95 64 95 75 0
19 35 45 60 45 13 0 47 8 76 17 l52 18 7 53 c4 30 5 55 3 57 -2 1 -68 -23
-148 -54z"/>
<path d="M12013 6379 c8 -20 168 -371 267 -588 l85 -185 17 130 c39 302 67
569 60 575 -4 3 -92 20 -197 38 -104 18 -201 36 -214 39 -18 4 -23 1 -18 -9z"/>
<path d="M11967 6288 c-32 -103 -143 -485 -208 -715 -27 -95 -52 -179 -55
-187 -3 -7 39 31 93 86 141 142 195 166 249 108 38 -40 73 -107 81 -153 6 -39
10 -41 54 -22 40 16 71 -56 88 -211 6 -53 19 -93 50 -155 51 -102 56 -108 77
-87 19 19 8 47 -29 71 -13 8 -36 41 -51 72 -23 46 -27 64 -21 101 7 49 30 63
75 46 27 -10 80 -59 80 -73 0 -13 33 -10 53 5 9 7 17 20 17 28 0 8 -40 102
-89 209 -48 107 -166 365 -261 574 -95 209 -174 381 -175 383 -2 2 -15 -34
-28 -80z"/>
<path d="M9711 6317 c26 -23 62 -51 80 -62 52 -31 50 -59 -11 -118 -6 -7 -22
-23 -35 -35 -18 -18 -30 -22 -47 -17 -57 18 -63 50 -13 71 24 9 33 19 29 29
-4 8 -9 15 -13 15 -4 0 -40 28 -81 62 -71 60 -74 61 -104 48 -17 -7 -46 -15
-64 -17 -23 -4 -37 -13 -44 -29 -6 -13 -28 -35 -49 -49 -23 -15 -39 -33 -39
-44 0 -45 -59 -89 -140 -105 -14 -2 -5 -3 20 -2 25 2 72 10 105 19 33 9 111
21 174 27 122 12 147 6 135 -32 -3 -11 -3 -35 0 -54 5 -26 13 -35 34 -40 37
-7 72 -22 102 -42 41 -27 94 -43 99 -30 8 25 51 58 74 58 14 0 50 -12 82 -26
36 -17 73 -26 99 -25 167 6 159 4 178 36 9 17 19 46 20 65 3 34 2 35 -37 36
-154 2 -163 4 -193 29 -21 17 -33 38 -37 66 -7 40 -24 57 -45 44 -7 -4 -2 -16
15 -31 30 -27 30 -57 0 -62 -11 -2 -28 -13 -38 -23 -10 -10 -24 -19 -32 -19
-19 0 -64 68 -85 128 -8 26 -20 54 -25 63 -10 16 -141 109 -153 109 -4 0 14
-19 39 -43z"/>
<path d="M11840 6228 c-181 -197 -191 -208 -283 -311 -56 -61 -83 -99 -75
-102 23 -8 302 -74 304 -72 2 2 95 320 166 565 5 19 7 36 5 38 -2 3 -55 -51
-117 -118z"/>
<path d="M9240 6320 c-8 -5 -45 -10 -81 -10 -71 0 -83 -7 -91 -52 l-5 -28 98
0 99 0 0 50 c0 28 -1 50 -2 50 -2 0 -10 -5 -18 -10z"/>
<path d="M12466 6273 c-9 -55 -44 -368 -42 -370 3 -3 397 -83 409 -83 4 0 7
10 7 23 0 29 -46 101 -94 146 -41 40 -46 73 -13 96 19 13 20 17 7 25 -8 5 -20
10 -27 10 -7 0 -24 5 -38 12 -27 12 -35 54 -13 76 15 15 54 16 63 2 3 -5 26
-10 50 -10 29 0 49 -6 57 -16 7 -9 30 -32 51 -52 28 -27 37 -43 37 -69 0 -28
3 -33 24 -33 14 0 28 4 31 10 10 16 -23 67 -65 101 -39 31 -51 61 -30 74 23
14 6 23 -67 35 -43 7 -136 23 -207 36 -71 13 -130 24 -131 24 -2 0 -6 -17 -9
-37z"/>
<path d="M9057 6198 c-2 -7 -2 -27 0 -44 7 -44 54 -64 123 -53 66 10 80 23 80
70 l0 39 -99 0 c-70 0 -100 -4 -104 -12z"/>
<path d="M9490 6079 c-123 -17 -195 -30 -223 -42 l-29 -12 74 -50 c40 -27 140
-96 221 -154 82 -57 149 -102 151 -100 2 2 -7 53 -18 112 -20 101 -24 109 -54
127 -30 18 -32 23 -32 75 0 38 -4 55 -12 54 -7 -1 -42 -5 -78 -10z"/>
<path d="M9118 5995 c-6 -14 -27 -35 -45 -46 -33 -21 -63 -64 -63 -93 0 -8
-33 -44 -72 -80 -40 -36 -70 -67 -67 -71 3 -3 183 -4 400 -3 l394 3 -225 157
c-205 143 -229 158 -268 158 -36 0 -44 -4 -54 -25z"/>
<path d="M10540 6016 c0 -7 298 -617 304 -623 4 -5 98 59 134 91 13 12 33 38
43 59 23 44 15 68 -29 91 -15 8 -42 33 -61 56 -26 33 -32 46 -24 59 16 25 42
25 86 0 33 -18 60 -23 146 -27 80 -3 114 -9 139 -23 18 -10 34 -19 36 -19 7 0
108 121 104 125 -2 3 -175 45 -384 95 -342 81 -420 100 -476 116 -10 3 -18 3
-18 0z"/>
<path d="M10285 5841 l-210 -167 -3 -142 -3 -142 375 0 375 0 -43 93 c-102
218 -261 527 -270 526 -6 0 -105 -76 -221 -168z"/>
<path d="M9719 5665 l54 -276 136 3 136 3 3 245 2 245 -61 27 c-47 21 -66 25
-80 17 -11 -5 -19 -14 -19 -19 0 -6 -9 -19 -19 -29 -18 -18 -22 -18 -67 -3
-27 8 -63 26 -80 39 -64 48 -64 45 -5 -252z"/>
<path d="M12420 5873 c0 -5 -9 -75 -19 -156 l-19 -148 55 -122 c30 -67 66
-146 79 -175 32 -70 48 -60 40 22 -6 55 -10 64 -47 97 -34 30 -42 44 -46 81
-4 38 -2 49 18 67 12 11 30 21 39 21 29 0 173 50 215 75 23 13 49 35 58 48 16
25 41 106 34 113 -3 4 -388 84 -401 84 -3 0 -6 -3 -6 -7z"/>
<path d="M11391 5735 c-63 -68 -71 -85 -47 -104 8 -7 17 -23 20 -36 4 -15 21
-32 44 -44 49 -25 55 -32 86 -116 15 -38 36 -92 47 -120 12 -27 31 -74 43
-102 22 -56 31 -64 39 -35 3 9 22 73 42 142 91 308 114 395 107 401 -4 3 -70
21 -147 38 -77 18 -147 34 -156 37 -11 3 -38 -18 -78 -61z"/>
<path d="M8833 5648 c-32 -54 -34 -67 -27 -159 l7 -89 133 0 134 0 73 77 c39
43 99 106 131 140 l59 63 -245 0 -246 0 -19 -32z"/>
<path d="M9239 5542 l-127 -137 85 -6 c128 -9 553 -11 553 -3 0 5 -12 70 -27
146 l-27 138 -165 -1 -166 0 -126 -137z"/>
<path d="M8790 5350 c-9 -21 -10 -40 -4 -60 9 -29 94 -155 145 -213 l25 -30
171 159 170 159 -106 6 c-58 4 -170 7 -247 8 l-142 1 -12 -30z"/>
<path d="M9354 5348 c3 -13 12 -85 22 -160 13 -111 20 -139 34 -143 9 -3 26
-19 38 -35 19 -25 29 -30 67 -30 34 0 47 -5 59 -22 20 -28 20 -83 1 -138 -13
-37 -13 -45 0 -70 8 -16 18 -31 23 -34 4 -2 68 90 142 205 74 115 170 263 212
329 l77 120 -340 0 -339 0 4 -22z"/>
<path d="M10070 5286 l0 -84 33 -5 c17 -3 88 -9 156 -13 l123 -7 -5 39 c-3 22
-9 65 -12 97 l-6 57 -145 0 -144 0 0 -84z"/>
<path d="M10380 5358 c0 -16 69 -595 76 -636 l5 -32 59 77 c32 43 77 96 99
118 l41 39 0 128 c0 127 0 128 -23 128 -31 0 -67 27 -67 50 0 23 28 42 95 64
28 9 73 30 100 46 l50 30 -217 0 c-162 0 -218 -3 -218 -12z"/>
<path d="M9240 5287 c-41 -40 -119 -114 -174 -164 l-99 -91 28 -18 c38 -25
221 -25 259 -1 13 9 45 22 71 28 l47 12 -6 41 c-3 23 -11 92 -18 154 -7 63
-17 112 -23 112 -5 0 -44 -33 -85 -73z"/>
<path d="M9999 5285 c-162 -246 -379 -590 -379 -601 0 -7 93 -99 208 -204
l207 -191 7 348 c5 191 7 431 5 533 l-2 185 -46 -70z"/>
<path d="M11662 5237 c-12 -42 -25 -84 -28 -94 -4 -13 2 -10 19 9 18 19 28 44
32 82 11 85 1 86 -23 3z"/>
<path d="M10740 5196 l-55 -12 -3 -112 c-4 -148 6 -148 83 3 41 79 57 137 38
134 -5 -1 -33 -7 -63 -13z"/>
<path d="M10070 4880 l0 -300 48 37 c26 21 104 85 175 142 121 99 127 106 123
135 -3 17 -10 72 -16 121 -6 50 -13 102 -16 116 l-5 27 -137 6 c-75 4 -145 10
-154 12 -17 5 -18 -14 -18 -296z"/>
<path d="M12261 4920 c34 -48 45 -58 56 -49 11 10 11 15 -4 31 -87 95 -112
104 -52 18z"/>
<path d="M12365 4890 l-48 -49 24 -51 c17 -36 28 -49 39 -44 8 3 27 8 43 11
l27 6 -25 23 c-30 28 -34 77 -6 90 16 8 17 13 7 36 l-12 28 -49 -50z"/>
<path d="M10240 4693 c-114 -94 -167 -144 -171 -162 -4 -14 -7 -79 -8 -144
l-1 -118 78 -73 c42 -40 101 -94 131 -122 l54 -49 -8 52 c-7 51 -6 54 34 101
22 27 58 61 79 76 22 15 44 38 51 52 14 31 15 161 1 169 -5 3 -10 22 -10 41 0
19 -6 47 -14 62 -7 15 -16 71 -20 125 -7 100 -13 128 -25 126 -3 0 -80 -62
-171 -136z"/>
<path d="M12445 4740 c-9 -15 24 -112 43 -127 26 -21 34 -15 11 8 -16 16 -20
30 -17 72 2 41 0 52 -14 55 -9 2 -19 -2 -23 -8z"/>
<path d="M12380 4720 c0 -12 51 -62 57 -57 2 2 -2 18 -8 35 -7 21 -18 32 -30
32 -10 0 -19 -5 -19 -10z"/>
<path d="M12560 4584 c19 -9 64 -20 100 -26 36 -5 87 -16 113 -25 27 -8 51
-12 54 -9 4 3 0 6 -8 6 -8 0 -30 8 -49 19 -30 16 -85 28 -215 46 -30 5 -30 5
5 -11z"/>
<path d="M9686 4549 c27 -76 28 -122 6 -172 -11 -25 -26 -70 -32 -100 -11 -48
-10 -61 5 -103 10 -27 22 -54 26 -59 11 -15 49 -155 49 -181 0 -11 18 -55 40
-97 22 -42 43 -98 47 -124 3 -26 10 -54 16 -61 10 -12 68 -11 165 4 l32 5 0
298 0 298 -167 154 c-217 199 -204 190 -187 138z"/>
<path d="M10060 3955 l0 -276 33 25 c71 56 147 162 147 205 0 29 9 42 61 83
15 11 3 26 -104 123 -66 61 -124 112 -129 113 -4 2 -8 -121 -8 -273z"/>
<path d="M6800 7257 c-14 -8 -51 -30 -83 -50 -66 -40 -71 -41 -212 -59 -118
-14 -178 -16 -222 -6 l-33 8 0 -105 c0 -58 3 -105 8 -105 4 0 103 -10 220 -21
124 -13 217 -18 222 -13 4 5 58 87 119 182 100 156 108 172 87 172 -13 0 -36
2 -52 5 -16 3 -40 0 -54 -8z"/>
<path d="M6896 7171 l-55 -86 311 -3 c299 -2 313 -1 355 19 24 11 51 18 60 15
22 -9 159 124 140 136 -17 11 -125 10 -167 -2 -59 -16 -73 -32 -74 -81 -1 -42
-2 -44 -34 -47 -19 -2 -44 4 -59 13 -21 14 -24 23 -21 63 5 68 -16 65 -100
-12 -100 -92 -146 -113 -172 -81 -10 12 -10 21 -1 42 11 23 9 29 -13 51 -14
14 -45 33 -70 43 l-45 17 -55 -87z"/>
<path d="M7716 7211 c-16 -16 -26 -34 -22 -39 9 -16 140 -118 158 -125 19 -7
78 10 78 23 0 4 -14 13 -31 19 -29 10 -31 14 -26 45 5 32 4 35 -38 50 -23 9
-51 26 -60 36 -23 26 -26 25 -59 -9z"/>
<path d="M5895 7164 c-65 -19 -132 -34 -147 -34 -19 0 -41 -14 -75 -49 -36
-36 -59 -51 -88 -56 -22 -4 -46 -11 -53 -14 -7 -4 144 -20 335 -35 192 -16
351 -30 356 -33 4 -2 7 45 7 105 l0 110 -79 11 c-43 7 -92 15 -108 20 -21 6
-59 -1 -148 -25z"/>
<path d="M7638 7134 c-25 -25 -25 -27 -9 -55 15 -26 15 -30 -1 -45 -15 -16
-14 -18 17 -40 19 -13 57 -30 84 -38 65 -19 91 -4 88 51 -3 31 -12 44 -72 94
-39 32 -72 59 -75 59 -3 0 -17 -12 -32 -26z"/>
<path d="M6771 6978 l-51 -83 92 -12 c146 -18 197 -16 216 7 10 10 67 42 128
70 l112 50 86 -6 86 -7 0 32 0 31 -308 0 -309 0 -52 -82z"/>
<path d="M5516 6971 c-4 -6 -31 -23 -59 -37 -79 -40 -80 -41 -52 -78 14 -18
25 -38 25 -44 0 -18 39 -34 63 -26 12 4 37 19 54 35 18 15 50 31 70 34 21 3
77 13 125 21 108 19 158 12 204 -28 49 -43 58 -64 64 -143 l5 -70 105 -36 c58
-20 108 -34 111 -30 3 3 3 85 0 181 l-6 175 -80 7 c-84 8 -389 33 -536 44 -61
5 -88 3 -93 -5z"/>
<path d="M7497 6904 c-12 -15 -32 -37 -45 -51 -15 -16 -20 -31 -16 -47 7 -28
-33 -79 -80 -103 -17 -9 -46 -29 -64 -45 -41 -35 -65 -33 -72 6 -4 23 -14 32
-54 47 -28 10 -50 17 -51 16 -1 -1 -16 -24 -34 -50 -18 -27 -31 -50 -29 -51 5
-4 467 -116 479 -116 6 0 9 6 6 14 -8 22 14 36 55 36 22 0 41 5 43 13 11 28
31 237 24 244 -4 4 -9 21 -11 37 -4 35 -38 62 -91 71 -33 5 -40 3 -60 -21z"/>
<path d="M6250 6773 c0 -82 4 -154 8 -160 5 -9 47 35 126 133 65 80 116 147
114 149 -3 3 -212 25 -235 25 -10 0 -13 -36 -13 -147z"/>
<path d="M6540 6887 c0 -3 70 -121 156 -262 l157 -256 119 180 c66 99 119 183
117 188 -1 4 -16 13 -33 18 -24 8 -34 19 -44 50 l-13 41 -182 18 c-100 10
-203 20 -229 23 -27 3 -48 3 -48 0z"/>
<path d="M6390 6724 c-69 -85 -126 -159 -128 -163 -2 -7 531 -191 553 -191 4
0 5 7 2 15 -7 17 -286 477 -296 486 -3 4 -62 -63 -131 -147z"/>
<path d="M7719 6825 c-36 -26 -36 -26 -48 -137 -6 -61 -10 -112 -9 -114 2 -1
38 2 81 7 43 5 82 7 87 4 19 -12 9 -45 -20 -67 -35 -25 -38 -38 -10 -38 11 0
36 -7 55 -14 19 -8 35 -14 35 -13 0 1 -9 26 -20 55 -16 40 -19 66 -14 102 6
47 5 51 -30 83 -27 26 -36 43 -37 68 -1 44 -12 82 -24 86 -6 2 -26 -8 -46 -22z"/>
<path d="M5996 6563 c-4 -27 -10 -73 -15 -103 -5 -30 -7 -56 -6 -58 1 -1 61
-27 134 -56 l131 -54 0 123 0 123 -108 36 c-59 20 -112 36 -118 36 -6 0 -14
-21 -18 -47z"/>
<path d="M6955 6488 c-44 -67 -80 -126 -80 -131 0 -10 347 -127 375 -127 11 0
21 4 25 9 3 5 18 12 34 16 21 4 30 13 34 34 5 21 19 35 65 59 67 36 90 39 107
16 10 -15 16 -14 60 8 47 24 47 25 22 32 -26 6 -46 44 -33 64 3 6 -106 37
-252 72 -141 35 -262 64 -267 67 -6 2 -46 -52 -90 -119z"/>
<path d="M6260 6324 c0 -161 3 -205 13 -201 95 40 391 162 454 187 46 19 81
36 78 38 -3 3 -535 182 -542 182 -2 0 -3 -93 -3 -206z"/>
<path d="M5938 6363 c-9 -10 -18 -27 -22 -38 -3 -11 -22 -44 -41 -73 -32 -50
-35 -60 -35 -130 0 -74 2 -79 35 -115 19 -20 38 -44 43 -53 8 -14 30 -6 166
62 l156 79 -2 89 -3 89 -130 54 c-71 29 -134 53 -140 53 -7 0 -19 -8 -27 -17z"/>
<path d="M6755 6300 c-38 -16 -157 -65 -264 -109 -193 -79 -195 -79 -150 -85
40 -4 573 -26 575 -22 3 6 -79 246 -84 246 -4 0 -38 -14 -77 -30z"/>
<path d="M6865 6309 c5 -13 30 -93 56 -178 27 -85 51 -156 53 -159 3 -2 35 13
72 34 55 32 68 46 79 78 8 21 33 58 56 82 l42 43 -24 9 c-13 5 -89 31 -169 57
-80 26 -151 50 -159 53 -10 4 -11 -1 -6 -19z"/>
<path d="M6260 5983 c0 -60 3 -145 6 -190 l7 -81 36 -7 c20 -3 46 -9 58 -12
18 -4 24 1 34 36 24 82 103 128 199 117 49 -6 59 -4 75 14 27 30 84 43 112 25
12 -8 31 -15 42 -15 32 0 51 -28 51 -73 0 -23 7 -51 15 -61 17 -23 16 -27 18
86 2 60 6 82 23 104 20 27 20 31 5 79 -8 27 -16 51 -16 52 -1 2 -100 7 -221
13 -120 5 -270 12 -331 15 l-113 5 0 -107z"/>
<path d="M6077 5992 l-149 -77 6 -50 c7 -69 29 -138 34 -108 2 12 10 27 17 33
28 23 59 3 98 -64 l38 -65 62 28 c48 21 63 33 66 52 5 37 -10 329 -18 328 -3
0 -73 -35 -154 -77z"/>
<path d="M6178 5667 c-38 -18 -46 -25 -38 -37 5 -8 10 -36 10 -62 0 -42 4 -52
36 -80 66 -60 64 -63 64 77 0 94 -3 125 -12 124 -7 0 -34 -10 -60 -22z"/>
<path d="M6270 5585 c0 -61 4 -105 10 -105 5 0 73 -25 150 -55 77 -30 147 -55
154 -55 8 0 16 12 19 28 8 35 -34 77 -67 67 -53 -16 -96 -17 -112 -4 -24 20
-64 109 -64 142 0 16 4 37 10 47 8 15 4 19 -35 29 -24 6 -49 11 -54 11 -7 0
-11 -38 -11 -105z"/>
<path d="M6614 5540 c-28 -11 -38 -60 -16 -77 10 -7 20 -13 23 -13 6 0 39 78
39 93 0 9 -19 8 -46 -3z"/>
<path d="M6270 5440 c0 -29 76 -60 148 -60 46 0 60 -4 82 -25 17 -16 33 -23
43 -19 18 7 23 24 7 24 -5 0 -67 23 -137 50 -70 28 -131 50 -135 50 -4 0 -8
-9 -8 -20z"/>
<path d="M6615 5344 c45 -35 55 -36 55 -9 0 22 -4 25 -37 25 -36 -1 -37 -1
-18 -16z"/>
<path d="M6690 5331 c0 -20 8 -35 23 -46 21 -15 23 -14 35 16 15 37 3 59 -34
59 -20 0 -24 -5 -24 -29z"/>
<path d="M6570 5330 c-13 -9 -13 -11 0 -20 8 -5 21 -10 28 -10 8 0 27 -9 43
-21 20 -14 29 -16 29 -7 0 7 -10 19 -22 27 -13 8 -32 20 -43 27 -14 9 -25 10
-35 4z"/>
<path d="M6700 5227 c0 -36 6 -48 33 -74 51 -49 72 -56 104 -38 l28 15 -30 -1
c-16 -1 -38 -1 -47 0 -21 1 -48 50 -48 88 0 17 -8 33 -20 41 -19 11 -20 10
-20 -31z"/>
<path d="M7149 5204 c-14 -17 -41 -18 -56 -3 -15 15 -85 -22 -107 -55 -11 -18
-25 -26 -46 -26 -29 0 -29 0 -15 -32 7 -18 16 -54 20 -80 4 -27 9 -48 11 -48
4 0 205 159 261 205 8 7 3 16 -22 32 -29 18 -36 19 -46 7z"/>
<path d="M7313 5167 l-31 -11 -6 -150 c-7 -168 -12 -376 -10 -376 1 0 30 44
65 98 34 53 91 141 126 195 35 53 63 101 63 105 0 11 -58 71 -98 102 -18 14
-39 31 -47 38 -15 13 -17 13 -62 -1z"/>
<path d="M7110 5054 c-80 -64 -152 -122 -160 -130 -13 -12 4 -33 135 -164 82
-83 153 -150 156 -150 5 0 20 551 15 557 -1 1 -67 -50 -146 -113z"/>
<path d="M7406 4808 c-91 -142 -131 -214 -123 -219 23 -11 307 -72 312 -67 7
7 30 476 24 482 -2 2 -20 6 -40 10 l-37 7 -136 -213z"/>
<path d="M7636 4853 c-3 -76 -8 -178 -11 -228 l-4 -90 84 90 c47 50 99 107
116 128 l31 37 -34 0 c-40 0 -78 30 -78 62 0 52 -56 138 -90 138 -4 0 -11 -62
-14 -137z"/>
<path d="M6875 4845 c-36 -54 -38 -59 -26 -91 11 -30 10 -37 -8 -60 -27 -34
-26 -52 2 -87 22 -26 33 -29 192 -51 94 -13 173 -22 177 -19 5 2 12 12 17 22
8 14 -18 45 -153 180 l-163 163 -38 -57z"/>
<path d="M7752 4647 l-120 -132 141 -6 c78 -4 202 -8 276 -10 134 -4 134 -4
153 21 17 23 17 30 6 65 -10 32 -20 42 -47 51 -19 6 -42 21 -52 32 -20 25 -54
40 -123 53 -28 5 -59 18 -70 28 -12 10 -26 21 -32 24 -6 4 -64 -52 -132 -126z"/>
<path d="M6890 4536 c19 -51 102 -196 112 -196 6 0 50 39 97 87 l86 88 -125
17 c-69 9 -137 19 -152 22 -25 5 -27 4 -18 -18z"/>
<path d="M7188 4493 l-67 -67 207 -78 c114 -43 211 -78 216 -78 5 0 -16 25
-48 55 -32 30 -99 95 -150 144 l-92 90 -66 -66z"/>
<path d="M7432 4414 c81 -81 149 -146 152 -144 2 3 7 55 11 116 l7 110 -58 12
c-33 6 -88 19 -124 27 -151 36 -151 44 12 -121z"/>
<path d="M7615 4386 c-4 -59 -5 -110 -2 -113 6 -5 450 43 475 52 6 2 12 15 12
27 0 13 14 43 30 68 l30 45 -38 6 c-20 4 -141 10 -268 14 l-231 7 -8 -106z"/>
<path d="M7062 4367 c-23 -23 -42 -47 -42 -52 0 -6 30 -30 66 -55 119 -81 139
-123 132 -282 -3 -54 -2 -98 2 -98 3 0 17 12 30 28 12 15 90 95 172 178 l148
150 -222 84 c-123 46 -228 85 -233 87 -6 2 -29 -16 -53 -40z"/>
<path d="M7970 4290 c-30 -4 -122 -15 -205 -25 -82 -9 -151 -18 -153 -20 -4
-3 7 -15 156 -159 l102 -99 52 26 c29 14 67 28 85 32 34 7 33 6 77 141 9 29
16 66 16 83 0 29 -2 31 -37 30 -21 -1 -63 -5 -93 -9z"/>
<path d="M7405 4040 c-99 -99 -175 -180 -169 -180 10 0 133 27 284 63 l55 12
8 125 c4 69 6 133 5 143 -2 12 -56 -36 -183 -163z"/>
<path d="M7607 4158 c-4 -29 -7 -96 -7 -148 l0 -95 84 -84 c75 -74 87 -83 101
-71 34 28 59 94 60 157 l1 62 -116 116 -117 117 -6 -54z"/>
<path d="M7380 3872 c-85 -20 -157 -37 -159 -38 -2 -2 2 -32 9 -67 11 -62 14
-66 80 -120 110 -90 96 -88 183 -21 l77 59 0 60 c0 33 3 84 6 113 8 64 18 63
-196 14z"/>
<path d="M7596 3839 c-7 -59 -16 -349 -11 -349 2 0 20 8 40 17 35 17 49 53 25
68 -5 3 -10 17 -10 30 0 18 7 26 25 30 14 3 36 7 49 10 17 4 28 16 36 41 l12
36 -80 81 -80 80 -6 -44z"/>
<path d="M7246 3621 c4 -31 2 -56 -6 -71 -10 -18 -10 -31 0 -61 7 -22 17 -39
22 -39 13 0 128 91 128 100 0 8 -135 120 -145 120 -3 0 -3 -22 1 -49z"/>
<path d="M7492 3602 l-74 -57 6 -155 c3 -85 6 -206 6 -268 l0 -112 33 -20 c30
-19 64 -31 132 -45 l30 -7 -30 20 c-40 25 -83 77 -91 108 -4 14 1 44 11 70
l17 44 -31 29 c-36 34 -38 46 -12 63 15 9 18 19 14 44 -3 18 0 34 6 38 6 4 11
18 11 31 0 14 8 39 18 57 12 22 21 65 25 126 4 50 6 92 4 91 -1 0 -35 -26 -75
-57z"/>
<path d="M7328 3470 c-38 -29 -68 -58 -68 -64 0 -7 11 -27 25 -46 34 -47 47
-98 39 -163 -6 -50 -4 -59 24 -99 61 -88 62 -87 61 68 -1 77 -4 188 -8 247
l-6 109 -67 -52z"/>
<path d="M8835 7040 c3 -5 11 -10 16 -10 6 0 7 5 4 10 -3 6 -11 10 -16 10 -6
0 -7 -4 -4 -10z"/>
<path d="M8915 7040 c-14 -6 -4 -9 38 -9 36 -1 56 3 52 9 -7 12 -62 12 -90 0z"/>
<path d="M8850 7000 c18 -12 88 -12 115 0 14 6 -4 9 -55 9 -52 1 -70 -2 -60
-9z"/>
<path d="M9105 6680 c-3 -5 3 -10 15 -10 12 0 18 5 15 10 -3 6 -10 10 -15 10
-5 0 -12 -4 -15 -10z"/>
<path d="M9076 6634 c-9 -23 -2 -28 27 -20 38 9 43 36 8 36 -18 0 -31 -6 -35
-16z"/>
<path d="M13200 6321 c0 -36 4 -39 48 -32 50 8 47 31 -5 46 l-43 13 0 -27z"/>
<path d="M13230 6213 c0 -14 15 -29 35 -37 17 -6 17 -4 -4 18 -26 28 -31 31
-31 19z"/>
<path d="M13250 6140 c0 -28 -40 -66 -93 -89 -24 -10 -57 -33 -74 -50 -32 -31
-32 -32 -15 -61 21 -36 32 -38 32 -6 0 28 52 66 91 66 13 0 33 7 43 15 11 8
31 15 44 15 22 0 23 3 17 28 -4 15 -11 42 -14 61 -7 39 -31 55 -31 21z"/>
<path d="M6830 5600 c-22 -7 -21 -8 13 -9 20 -1 37 4 37 9 0 11 -14 11 -50 0z"/>
<path d="M6905 5590 c-3 -5 -1 -10 5 -10 7 0 25 -11 42 -25 17 -15 42 -25 60
-25 30 0 29 1 -21 35 -52 36 -75 43 -86 25z"/>
<path d="M7109 5473 c-13 -15 -11 -16 26 -10 22 4 47 7 55 8 22 1 -20 17 -46
18 -12 1 -28 -6 -35 -16z"/>
<path d="M12917 5443 c-18 -18 -2 -66 49 -143 55 -84 55 -85 52 -46 -2 32 -9
43 -33 56 -26 15 -30 23 -33 67 -3 48 -21 81 -35 66z"/>
<path d="M12940 5291 c0 -6 4 -13 10 -16 6 -3 7 1 4 9 -7 18 -14 21 -14 7z"/>
<path d="M13040 5225 c0 -30 5 -44 21 -53 21 -13 21 -13 15 25 -4 21 -14 45
-22 53 -12 12 -14 9 -14 -25z"/>
<path d="M13004 5146 c1 -31 9 -62 16 -69 10 -10 11 -1 6 48 -9 80 -26 96 -22
21z"/>
<path d="M13047 5107 c7 -61 16 -75 38 -57 25 21 19 64 -15 88 l-29 22 6 -53z"/>
<path d="M11730 5084 c0 -14 5 -24 11 -22 6 2 10 7 10 11 -1 4 -1 14 -1 22 0
8 -4 15 -10 15 -5 0 -10 -12 -10 -26z"/>
<path d="M12791 4988 c-25 -28 -59 -59 -78 -70 -32 -19 -32 -20 -18 -48 l15
-29 70 31 c63 28 70 34 70 60 0 15 6 37 12 48 11 17 9 23 -7 40 -20 20 -20 20
-64 -32z"/>
<path d="M12633 4873 c-24 -5 -30 -27 -14 -52 8 -12 14 -12 39 -2 28 12 30 15
20 37 -6 13 -14 23 -17 23 -3 -1 -16 -4 -28 -6z"/>
<path d="M12778 4852 c-32 -15 -58 -29 -58 -33 0 -4 12 -32 26 -63 21 -47 28
-55 40 -45 8 6 14 21 14 33 0 11 14 41 30 65 32 47 38 72 18 70 -7 -1 -39 -13
-70 -27z"/>
<path d="M12662 4798 c-17 -8 -21 -17 -16 -32 4 -12 7 -22 8 -23 2 -3 86 -31
86 -28 0 11 -42 95 -48 94 -4 0 -17 -5 -30 -11z"/>
<path d="M13284 4788 c-4 -6 2 -18 13 -27 10 -9 24 -24 30 -34 5 -11 36 -29
67 -42 83 -34 99 -51 93 -100 l-6 -40 25 30 c28 34 94 131 94 138 0 2 -22 14
-49 26 -46 19 -52 20 -91 6 -60 -21 -70 -19 -106 20 -32 36 -57 44 -70 23z"/>
<path d="M13562 4616 l-52 -74 32 -11 c45 -16 66 -14 96 10 17 13 34 18 50 14
22 -5 21 -3 -14 52 -58 93 -54 93 -112 9z"/>
<path d="M13650 4686 c0 -15 122 -195 136 -200 10 -4 6 6 -10 25 -27 32 -33
67 -16 100 9 16 7 21 -17 29 -40 15 -45 18 -70 36 -13 9 -23 14 -23 10z"/>
<path d="M13232 4364 l-51 -57 -52 7 c-45 6 -55 4 -75 -15 -13 -12 -24 -25
-24 -29 0 -4 53 -12 118 -19 64 -6 131 -14 148 -17 26 -3 33 0 42 21 7 14 12
35 12 46 0 11 7 35 14 54 14 32 13 35 -2 35 -9 0 -30 7 -46 15 -15 8 -29 15
-30 15 -2 0 -26 -25 -54 -56z"/>
<path d="M13577 4384 c-17 -93 -64 -164 -109 -164 -12 0 -40 11 -63 24 l-41
25 -58 -116 -57 -116 34 -36 c18 -20 49 -53 68 -74 l35 -39 132 146 c149 166
154 177 107 271 -13 28 -25 57 -25 65 0 8 -4 21 -9 29 -6 9 -10 5 -14 -15z"/>
<path d="M12979 4202 c-35 -49 -106 -93 -198 -122 -35 -12 -74 -28 -87 -37
-24 -15 -44 -67 -44 -114 l0 -26 287 73 c204 52 291 78 301 91 24 30 71 136
66 145 -3 4 -24 8 -47 9 -23 0 -88 6 -144 12 l-103 12 -31 -43z"/>
<path d="M13535 4025 c-66 -74 -120 -141 -120 -149 0 -8 46 -62 103 -120 l104
-106 42 37 c62 55 104 106 121 147 20 48 20 130 -1 147 -9 7 -31 42 -50 78
-37 74 -57 101 -70 101 -5 -1 -63 -61 -129 -135z"/>
<path d="M12970 3964 c-357 -91 -320 -75 -320 -138 l0 -53 78 -22 c187 -54
167 -51 240 -31 37 11 78 21 92 24 21 4 37 30 93 142 37 75 67 137 65 138 -2
2 -113 -26 -248 -60z"/>
<path d="M13172 3885 c-64 -129 -70 -145 -51 -145 6 0 23 -8 37 -18 24 -17
192 -46 392 -69 l45 -5 -101 103 c-56 57 -134 139 -174 182 -40 42 -76 77 -79
77 -4 0 -34 -56 -69 -125z"/>
<path d="M12650 3731 c0 -11 -8 -36 -17 -56 -23 -49 -7 -65 42 -42 20 9 61 20
93 23 31 4 68 12 81 19 24 12 20 14 -60 38 -138 42 -139 42 -139 18z"/>
<path d="M13190 3666 c0 -8 9 -20 19 -25 11 -6 34 -34 51 -63 39 -64 39 -64
113 -77 56 -10 62 -9 116 19 47 23 111 83 111 103 0 2 -28 7 -62 11 -35 4
-101 13 -148 21 -163 26 -200 28 -200 11z"/>
<path d="M10732 4319 c-18 -21 -48 -46 -65 -55 -43 -22 -47 -30 -47 -92 0 -31
-7 -63 -16 -77 -29 -44 -14 -135 21 -135 9 0 22 8 31 18 25 30 86 183 93 237
4 28 13 67 21 87 21 57 2 65 -38 17z"/>
<path d="M14228 3549 c-5 -32 0 -35 24 -16 14 11 13 14 -2 29 -17 15 -18 14
-22 -13z"/>
<path d="M14124 3451 c-43 -20 -65 -41 -42 -41 14 0 88 47 88 55 0 7 0 7 -46
-14z"/>
<path d="M14019 3380 c-13 -10 -19 -19 -13 -20 7 0 22 9 35 20 13 10 19 19 13
20 -7 0 -22 -9 -35 -20z"/>
<path d="M13880 3304 c-58 -27 -76 -44 -57 -56 14 -8 59 17 94 54 33 34 32 34
-37 2z"/>
<path d="M13342 3385 c-16 -34 -15 -35 6 -35 11 0 27 9 38 21 16 17 16 22 4
29 -24 15 -36 12 -48 -15z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

View File

@ -1,3 +1,16 @@
export const environment = {
production: true
};
production: true,
appAuthEndpoint: 'https://testauth.crm4retail.ru/tnt',
appBonusEndpoint: 'https://customerapi2.mi.crm4retail.ru/json.rpc/',
appWPEndpoint: 'http://213.239.210.240:4500/wp-json/woofood/v1/',
hasBonusProgram: true,
systemId: 'dfe16ca16a3598b812',
firebase: {
apiKey: "AIzaSyCujHg9GtN8Uxi-JcCN8zggvXlfNQRKc04",
authDomain: "push-notification-test2-56dac.firebaseapp.com",
projectId: "push-notification-test2-56dac",
storageBucket: "push-notification-test2-56dac.appspot.com",
messagingSenderId: "1004369687552",
appId: "1:1004369687552:web:a6cc20625e05520a37d4e5"
}
}

View File

@ -1,16 +1,16 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
production: false,
appAuthEndpoint: 'https://testauth.crm4retail.ru/tnt',
appBonusEndpoint: 'https://customerapi2.mi.crm4retail.ru/json.rpc/',
appWPEndpoint: 'http://192.168.0.179:4200/wp-json/woofood/v1/',
hasBonusProgram: true,
systemId: 'dfe16ca16a3598b812',
firebase: {
apiKey: "AIzaSyCujHg9GtN8Uxi-JcCN8zggvXlfNQRKc04",
authDomain: "push-notification-test2-56dac.firebaseapp.com",
projectId: "push-notification-test2-56dac",
storageBucket: "push-notification-test2-56dac.appspot.com",
messagingSenderId: "1004369687552",
appId: "1:1004369687552:web:a6cc20625e05520a37d4e5"
}
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.

View File

@ -0,0 +1,13 @@
importScripts('https://www.gstatic.com/firebasejs/7.4.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.4.1/firebase-messaging.js');
firebase.initializeApp({
apiKey: "AIzaSyCujHg9GtN8Uxi-JcCN8zggvXlfNQRKc04",
authDomain: "push-notification-test2-56dac.firebaseapp.com",
projectId: "push-notification-test2-56dac",
storageBucket: "push-notification-test2-56dac.appspot.com",
messagingSenderId: "1004369687552",
appId: "1:1004369687552:web:a6cc20625e05520a37d4e5"
});
const messaging = firebase.messaging();

View File

@ -5,9 +5,16 @@
<title>CardProject</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="apple-touch-icon" href="./assets/icons/apple-icon-180x180.png">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@200;400&amp;display=swap" rel="stylesheet">
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
</head>
<body>
<body style="background: #161616;">
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>

60
src/manifest.webmanifest Normal file
View File

@ -0,0 +1,60 @@
{
"name": "card-project",
"short_name": "card-project",
"theme_color": "#1976d2",
"background_color": "#fafafa",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
],
"gcm_sender_id": "1004369687552"
}

View File

@ -1 +1,27 @@
/* You can add global styles to this file, and also import other style files */
// Сброс стилей
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:middle}
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}
html{height:100%;color:#fff;}
body{line-height:1}
ol,ul{list-style:none}
blockquote,q{quotes:none}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}
table{border-collapse:collapse;border-spacing:0}
* {
font-family: 'Raleway', sans-serif;
}
.p-inputtext {
width: 100%;
}
mark {
padding: 4px;
background: #009688;
color: #fff;
}
::-webkit-scrollbar {
width: 0;
}