Skip to content

Commit e3a36e7

Browse files
committed
add cookie consent banner with conditional analytics loading
1 parent 6d41ce9 commit e3a36e7

8 files changed

Lines changed: 196 additions & 105 deletions

File tree

projects/social_platform/src/app/app.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
>
88
</mat-progress-bar>
99
<router-outlet></router-outlet>
10+
<app-cookie-consent />

projects/social_platform/src/app/app.component.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { MatProgressBarModule } from "@angular/material/progress-bar";
1919
import { AsyncPipe, NgIf } from "@angular/common";
2020
import { TokenService } from "@corelib";
2121
import { LoadingService } from "@office/services/loading.service";
22+
import { CookieConsentComponent } from "@ui/components/cookie-consent/cookie-consent.component";
2223

2324
/**
2425
* Корневой компонент приложения
@@ -31,7 +32,7 @@ import { LoadingService } from "@office/services/loading.service";
3132
templateUrl: "./app.component.html",
3233
styleUrls: ["./app.component.scss"],
3334
standalone: true,
34-
imports: [NgIf, MatProgressBarModule, RouterOutlet, AsyncPipe],
35+
imports: [NgIf, MatProgressBarModule, RouterOutlet, AsyncPipe, CookieConsentComponent],
3536
})
3637
export class AppComponent implements OnInit, OnDestroy {
3738
constructor(
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/** @format */
2+
3+
import { Injectable } from "@angular/core";
4+
5+
@Injectable({
6+
providedIn: "root",
7+
})
8+
export class AnalyticsService {
9+
private loaded = false;
10+
11+
loadAnalytics(): void {
12+
if (this.loaded) return;
13+
if (window.location.hostname !== "app.procollab.ru") return;
14+
15+
this.loaded = true;
16+
this.loadYandexMetrika();
17+
this.loadMailRuCounter("3622531");
18+
19+
if (window.location.href === "https://app.procollab.ru/auth/register") {
20+
this.loadMailRuCounter("3543687");
21+
}
22+
}
23+
24+
private loadYandexMetrika(): void {
25+
const w = window as any;
26+
w.ym =
27+
w.ym ||
28+
function (...args: any[]) {
29+
(w.ym.a = w.ym.a || []).push(args);
30+
};
31+
w.ym.l = new Date().getTime();
32+
33+
const script = document.createElement("script");
34+
script.async = true;
35+
script.src = "https://cdn.jsdelivr.net/npm/yandex-metrica-watch/tag.js";
36+
document.head.appendChild(script);
37+
38+
w.ym(91871365, "init", {
39+
clickmap: true,
40+
trackLinks: true,
41+
accurateTrackBounce: true,
42+
webvisor: true,
43+
trackHash: true,
44+
});
45+
}
46+
47+
private loadMailRuCounter(id: string): void {
48+
const w = window as any;
49+
const tmr = (w._tmr = w._tmr || []);
50+
tmr.push({ id, type: "pageView", start: new Date().getTime() });
51+
52+
if (document.getElementById("tmr-code")) return;
53+
54+
const script = document.createElement("script");
55+
script.type = "text/javascript";
56+
script.async = true;
57+
script.id = "tmr-code";
58+
script.src = "https://top-fwz1.mail.ru/js/code.js";
59+
document.head.appendChild(script);
60+
}
61+
}

projects/social_platform/src/app/ui/components/button/button.component.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
border-radius: var(--rounded-xxl);
1414
transition: all 0.2s;
1515

16+
&:disabled {
17+
opacity: 0.5;
18+
cursor: not-allowed;
19+
}
20+
1621
&.button--inline {
1722
font-weight: 400;
1823
color: var(--white);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!-- @format -->
2+
3+
@if (visible) {
4+
<div class="cookie-consent text-body-12">
5+
<p class="cookie-consent__text">
6+
мы используем файлы cookie для аналитики и улучшения сайта
7+
</p>
8+
9+
<div class="cookie-consent__controls">
10+
<div class="cookie-consent__label" (click)="onAcceptedChange(!accepted)">
11+
<app-checkbox [checked]="accepted" />
12+
<span>я согласен</span>
13+
</div>
14+
15+
<div class="cookie-consent__buttons">
16+
<app-button
17+
size="big"
18+
customTypographyClass="text-body-12"
19+
[disabled]="!accepted"
20+
(click)="confirm()"
21+
>
22+
принять
23+
</app-button>
24+
<app-button
25+
size="big"
26+
appearance="outline"
27+
customTypographyClass="text-body-12"
28+
(click)="decline()"
29+
>
30+
отклонить
31+
</app-button>
32+
</div>
33+
</div>
34+
</div>
35+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/** @format */
2+
3+
.cookie-consent {
4+
position: fixed;
5+
bottom: 20px;
6+
right: 20px;
7+
z-index: 9999;
8+
max-width: 320px;
9+
padding: 24px;
10+
background-color: var(--light-white);
11+
border: 0.5px solid var(--gray);
12+
border-radius: var(--rounded-lg);
13+
14+
&__text {
15+
margin: 0 0 12px;
16+
color: var(--dark-gray);
17+
}
18+
19+
&__controls {
20+
display: flex;
21+
flex-direction: column;
22+
gap: 10px;
23+
}
24+
25+
&__label {
26+
display: inline-flex;
27+
align-items: center;
28+
gap: 10px;
29+
cursor: pointer;
30+
color: var(--dark-gray);
31+
}
32+
33+
&__buttons {
34+
display: flex;
35+
align-items: center;
36+
justify-content: space-between;
37+
gap: 10px;
38+
39+
app-button {
40+
flex: 1;
41+
}
42+
}
43+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/** @format */
2+
3+
import { Component, OnInit } from "@angular/core";
4+
import { CheckboxComponent } from "@ui/components/checkbox/checkbox.component";
5+
import { ButtonComponent } from "@ui/components/button/button.component";
6+
import { AnalyticsService } from "../../../office/services/analytics.service";
7+
8+
@Component({
9+
selector: "app-cookie-consent",
10+
templateUrl: "./cookie-consent.component.html",
11+
styleUrl: "./cookie-consent.component.scss",
12+
standalone: true,
13+
imports: [CheckboxComponent, ButtonComponent],
14+
})
15+
export class CookieConsentComponent implements OnInit {
16+
visible = false;
17+
accepted = false;
18+
19+
private readonly storageKey = "cookieConsent";
20+
21+
constructor(private analyticsService: AnalyticsService) {}
22+
23+
ngOnInit(): void {
24+
const consent = localStorage.getItem(this.storageKey);
25+
26+
if (consent === "accepted") {
27+
this.analyticsService.loadAnalytics();
28+
} else {
29+
this.visible = true;
30+
}
31+
}
32+
33+
onAcceptedChange(value: boolean): void {
34+
this.accepted = value;
35+
}
36+
37+
confirm(): void {
38+
if (!this.accepted) return;
39+
40+
localStorage.setItem(this.storageKey, "accepted");
41+
this.analyticsService.loadAnalytics();
42+
this.visible = false;
43+
}
44+
45+
decline(): void {
46+
localStorage.setItem(this.storageKey, "declined");
47+
this.visible = false;
48+
}
49+
}

projects/social_platform/src/index.html

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -15,110 +15,6 @@
1515
rel="stylesheet"
1616
/>
1717
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
18-
19-
<!-- Yandex.Metrika counter -->
20-
<script type="text/javascript">
21-
if (window.location.hostname === "app.procollab.ru") {
22-
(function (m, e, t, r, i, k, a) {
23-
m[i] =
24-
m[i] ||
25-
function () {
26-
(m[i].a = m[i].a || []).push(arguments);
27-
};
28-
m[i].l = 1 * new Date();
29-
for (var j = 0; j < document.scripts.length; j++) {
30-
if (document.scripts[j].src === r) {
31-
return;
32-
}
33-
}
34-
(k = e.createElement(t)),
35-
(a = e.getElementsByTagName(t)[0]),
36-
(k.async = 1),
37-
(k.src = r),
38-
a.parentNode.insertBefore(k, a);
39-
})(
40-
window,
41-
document,
42-
"script",
43-
"https://cdn.jsdelivr.net/npm/yandex-metrica-watch/tag.js",
44-
"ym"
45-
);
46-
ym(91871365, "init", {
47-
clickmap: true,
48-
trackLinks: true,
49-
accurateTrackBounce: true,
50-
webvisor: true,
51-
trackHash: true,
52-
});
53-
}
54-
</script>
55-
<!-- /Yandex.Metrika counter -->
56-
57-
<!-- Top.Mail.Ru counter -->
58-
<script type="text/javascript">
59-
if (window.location.href === "https://app.procollab.ru/auth/register") {
60-
var _tmr = window._tmr || (window._tmr = []);
61-
_tmr.push({ id: "3543687", type: "pageView", start: new Date().getTime() });
62-
(function (d, w, id) {
63-
if (d.getElementById(id)) return;
64-
var ts = d.createElement("script");
65-
ts.type = "text/javascript";
66-
ts.async = true;
67-
ts.id = id;
68-
ts.src = "https://top-fwz1.mail.ru/js/code.js";
69-
var f = function () {
70-
var s = d.getElementsByTagName("script")[0];
71-
s.parentNode.insertBefore(ts, s);
72-
};
73-
if (w.opera == "[object Opera]") {
74-
d.addEventListener("DOMContentLoaded", f, false);
75-
} else {
76-
f();
77-
}
78-
})(document, window, "tmr-code");
79-
}
80-
</script>
81-
<noscript
82-
><div>
83-
<img
84-
src="https://top-fwz1.mail.ru/counter?id=3543687;js=na"
85-
style="position: absolute; left: -9999px"
86-
alt="Top.Mail.Ru"
87-
/></div
88-
></noscript>
89-
<!-- /Top.Mail.Ru counter -->
90-
91-
<!-- Top.Mail.Ru counter -->
92-
<script type="text/javascript">
93-
var _tmr = window._tmr || (window._tmr = []);
94-
_tmr.push({ id: "3622531", type: "pageView", start: new Date().getTime() });
95-
(function (d, w, id) {
96-
if (d.getElementById(id)) return;
97-
var ts = d.createElement("script");
98-
ts.type = "text/javascript";
99-
ts.async = true;
100-
ts.id = id;
101-
ts.src = "https://top-fwz1.mail.ru/js/code.js";
102-
var f = function () {
103-
var s = d.getElementsByTagName("script")[0];
104-
s.parentNode.insertBefore(ts, s);
105-
};
106-
if (w.opera == "[object Opera]") {
107-
d.addEventListener("DOMContentLoaded", f, false);
108-
} else {
109-
f();
110-
}
111-
})(document, window, "tmr-code");
112-
</script>
113-
<noscript
114-
><div>
115-
<img
116-
src="https://top-fwz1.mail.ru/counter?id=3622531;js=na"
117-
style="position: absolute; left: -9999px"
118-
alt="Top.Mail.Ru"
119-
/></div
120-
></noscript>
121-
<!-- /Top.Mail.Ru counter -->
12218
</head>
12319
<body>
12420
<app-root></app-root>

0 commit comments

Comments
 (0)