From d8ff044f226628906b16dab19b52a4a380eca009 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 21 Jun 2024 16:59:05 +0300 Subject: [PATCH] favicon YandexMetrika googleAnalytics --- package-lock.json | 26 +++++++++ package.json | 2 + src/app/_services/googleAnalytics.service.ts | 57 +++++++++++++++++++ src/app/app.component.ts | 12 +++- src/app/app.config.ts | 12 +++- src/app/request/request.component.ts | 27 +++++---- src/assets/favicon.ico | Bin 165662 -> 152126 bytes src/assets/favicon.png | Bin 481 -> 718 bytes src/assets/favicon.svg | 5 +- src/environments/environment.development.ts | 3 +- src/environments/environment.ts | 1 + 11 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 src/app/_services/googleAnalytics.service.ts diff --git a/package-lock.json b/package-lock.json index 3cb20f1..2e14467 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,8 @@ "@angular/router": "^18.0.0", "@angular/ssr": "^18.0.0", "express": "^4.18.2", + "ng-yandex-metrika": "^17.1.2", + "ngx-google-analytics": "^14.0.1", "rxjs": "~7.8.0", "swiper": "^11.1.3", "tslib": "^2.3.0", @@ -8854,6 +8856,30 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ng-yandex-metrika": { + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/ng-yandex-metrika/-/ng-yandex-metrika-17.1.2.tgz", + "integrity": "sha512-2VZCjEpEJvnMqjZfsRRzloaOWEQXqy6npzOBupqcm0o9VFl/SeEa2dmJN6V0HpD7GGdUFl7T9MQguti1rB4N7A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/compiler": "^17.0.0" + } + }, + "node_modules/ngx-google-analytics": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/ngx-google-analytics/-/ngx-google-analytics-14.0.1.tgz", + "integrity": "sha512-PfOtnshSyq15EKevKlFW9IRgH+dTtPG4Q9HJYksuRNYDzjce0eqK3Bf6hz0tAZdyqbzTCyx5g+NgWBfpqQfb2w==", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@angular/common": ">=12.0.0", + "@angular/core": ">=12.0.0" + } + }, "node_modules/nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", diff --git a/package.json b/package.json index 9a404c9..ab4b47e 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "@angular/router": "^18.0.0", "@angular/ssr": "^18.0.0", "express": "^4.18.2", + "ng-yandex-metrika": "^17.1.2", + "ngx-google-analytics": "^14.0.1", "rxjs": "~7.8.0", "swiper": "^11.1.3", "tslib": "^2.3.0", diff --git a/src/app/_services/googleAnalytics.service.ts b/src/app/_services/googleAnalytics.service.ts new file mode 100644 index 0000000..8bc5ca6 --- /dev/null +++ b/src/app/_services/googleAnalytics.service.ts @@ -0,0 +1,57 @@ +import { Injectable } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { environment } from '../../environments/environment'; + +declare var gtag: Function; + +@Injectable({ + providedIn: 'root', +}) +export class GoogleAnalyticsService { + constructor(private router: Router) {} + + public initialize() { + this.onRouteChange(); + + // dynamically add analytics scripts to document head + try { + const url = 'https://www.googletagmanager.com/gtag/js?id='; + const gTagScript = document.createElement('script'); + gTagScript.async = true; + gTagScript.src = `${url}${environment.googleAnalyticsId}`; + document.head.appendChild(gTagScript); + + const dataLayerScript = document.createElement('script'); + dataLayerScript.innerHTML = ` + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', '${environment.googleAnalyticsId}', {'send_page_view': false});`; + document.head.appendChild(dataLayerScript); + } catch (e) { + console.error('Error adding Google Analytics', e); + } + } + + // track visited routes + private onRouteChange() { + this.router.events.subscribe((event) => { + if (event instanceof NavigationEnd) { + gtag('config', environment.googleAnalyticsId, { + page_path: event.urlAfterRedirects, + }); + console.log('Sending Google Analytics tracking for: ', event.urlAfterRedirects); + console.log('Google Analytics property ID: ', environment.googleAnalyticsId); + } + }); + } + + // use gtag.js to send Google Analytics Events + public event(action: string, eventCategory?: string, eventLabel?: string, value?: string) { + gtag('event', action, { + ...(eventCategory && { event_category: eventCategory }), + ...(eventLabel && { event_label: eventLabel }), + ...(value && { value: value }), + }); + } +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index b3ed8be..00bff7f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,7 +1,9 @@ -import { Component } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import { CommonModule, DatePipe, ViewportScroller } from '@angular/common'; import { RouterOutlet, NavigationEnd, Router, RouterLink, RouterLinkActive } from '@angular/router'; import { RequestComponent } from './request/request.component'; +import {GoogleAnalyticsService} from "./_services/googleAnalytics.service"; +import {environment} from "../environments/environment"; @Component({ selector: 'app-root', @@ -10,19 +12,23 @@ import { RequestComponent } from './request/request.component'; templateUrl: './app.component.html', styleUrl: './app.component.scss' }) -export class AppComponent { +export class AppComponent implements OnInit{ title = 'NIR'; dateNow?: Date; navShow = false; - + ngOnInit(){ this.dateNow = new Date; + if (environment.production) { + this.googleAnalyticsService.initialize(); + } } constructor( readonly router: Router, readonly viewportScroller: ViewportScroller, + private readonly googleAnalyticsService: GoogleAnalyticsService ) { router.events.subscribe((event) => { diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 5da33bb..7c49e6c 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,14 +1,20 @@ -import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import {ApplicationConfig, importProvidersFrom, provideZoneChangeDetection} from '@angular/core'; import { provideRouter } from '@angular/router'; import { provideHttpClient, withFetch } from '@angular/common/http'; import { routes } from './app.routes'; import { provideClientHydration } from '@angular/platform-browser'; +import {MetrikaModule} from "ng-yandex-metrika"; export const appConfig: ApplicationConfig = { providers: [ - provideZoneChangeDetection({ eventCoalescing: true }), - provideRouter(routes), + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes), provideClientHydration(), provideHttpClient(withFetch()), + importProvidersFrom( + MetrikaModule.forRoot([ + { id: 97262465, webvisor: true, accurateTrackBounce:true, clickmap:true, trackLinks:true, } + ]) + ) ] }; diff --git a/src/app/request/request.component.ts b/src/app/request/request.component.ts index ae6f1b8..8bd5a8b 100644 --- a/src/app/request/request.component.ts +++ b/src/app/request/request.component.ts @@ -3,6 +3,7 @@ import { FormsService } from '../_services/forms.service'; import {FormGroup, ReactiveFormsModule, FormBuilder, Validators} from "@angular/forms"; import {ActivatedRoute, Router} from "@angular/router"; import {NgIf} from "@angular/common"; +import {Metrika} from "ng-yandex-metrika"; @Component({ selector: 'request', @@ -22,14 +23,14 @@ export class RequestComponent implements OnInit { public utmContent:string; public utmTerm:string; - constructor(private formBuilder:FormBuilder, private formsService: FormsService, private router: ActivatedRoute) { - this.router.queryParams.subscribe(params =>{ - this.utmSource = params['utm_source']; - this.utmMedium = params['utm_medium']; - this.utmCampaign = params['utm_campaign']; - this.utmContent = params['utm_content']; - this.utmTerm = params['utm_term'] - }) + constructor(private formBuilder:FormBuilder, private formsService: FormsService, private router: ActivatedRoute, private metrika: Metrika) { + this.router.queryParams.subscribe(params =>{ + this.utmSource = params['utm_source']; + this.utmMedium = params['utm_medium']; + this.utmCampaign = params['utm_campaign']; + this.utmContent = params['utm_content']; + this.utmTerm = params['utm_term'] + }) } ngOnInit():void{ @@ -55,6 +56,7 @@ export class RequestComponent implements OnInit { open(){ this.hidden = false; this.success = false; + this.metrika.reachGoal('form-open').then(); this.ngOnInit() } @@ -68,9 +70,10 @@ export class RequestComponent implements OnInit { this.feedbackForm.markAllAsTouched(); if (this.feedbackForm.valid) this.formsService.save('model', 'feedback-form-support', null, this.feedbackForm.value).subscribe(res => { - this.success = true; - }, error => { - console.log(error); - }); + this.metrika.reachGoal('form-sent').then(); + this.success = true; + }, error => { + console.log(error); + }); } } diff --git a/src/assets/favicon.ico b/src/assets/favicon.ico index a14185f96962e3a3427de0b54576f9e12b0d6d7f..78fe7341c626494ac741bd95a35b36283dcaf6ff 100644 GIT binary patch literal 152126 zcmeI5L5>wv5Jf*uojGtMi9?p*L>J(STpByl9bh*G(z%J1zztN_y$93S@~q;$a}F|+ zemveh{q_F+PH9>4wY`02;T$B&Qy{Pf*F zf4u#`2MlO{255i=Xn+Q2fCgxQ255i=Xn+Q2fCgxQ255i=Xn+Q2fCgxQ255i=Xn+Q2 zfCgxQ255i=Xn+Q2fCgxQ255i=Xn+Q2fCgxQ255i=Xn+Q2fCgxQ255i=Xn+Q2fCgxQ z255i=XdtVB4`tu}{{5HFf1c9I&%d_omph(6Z~OMO++NFEn=kFv^`QIOc)I+y=i7W~ zuP%Sx*T&Q3w>{tHOM7+s>%KOgF2C*hHecGS%U}1k@pSoZ&$s!~US0mWuZ^e6Z+pJY zm-g!N*L`g~U4Gm1ZN9Wum%r|7TX_dv*EizBZmNzwP-pU)rn7U-z}~bop)1xB1duUH-bSji<|R zd%n$=_UiK2eQi8le%teHzO+}DzwT?}>GIp2Z}X+Sy8Lxt8&8+t_I#T!?bYS4``UQA z{I=)Yd}*&Pf8E!{)8)54-{wnub@}VQHl8lO?fEue+N;Z7_qFkK`EAd)`O;op{<^P? zr^|19zRj2R>hjlpZ9H9m+w*O{v{#qE?rY=e^4p&O*1opi*Z%Y4cmDIb;4|~N{_6+7 zvtRhkeCU5J1U}h(@SE*-ew}}My`Ss%_YKY);FHYMc4bB_jlg$Ue*?#BO`KQ-YB! z&Kuy9%?H2Pe&^Tur`P+ret+NKya7JheDIs?cYd9JdcB|P_xBCX8{m`82fx{V=hykC z*ZaACf8XG|0Y2G$@SE*-ew}}My`Ss%_YKY);FHYMc4bB_jlg$Ue*?#BO`KQ-YB! z&Kuy9%?H2Pe&^Tur`P+ret+NKya7JheDIs?cYd9JdcB|P_xBCX8{m`82fx{V=hykC z*ZaACf8XG|0Y2G$@SE-T`RliR%a7~*T)+Rfbo=sa|6S+A{j8)9>+Xn4jbS9s3674cFPvuk%l@^SOS1-{8CfKG}Tmo9%agoqu}0pX>Mc z4bB_jlg$Ue*?#BO`KQ-YB!&Kuy9%?H2Pe&^Tu zr`P+ret+NKya7JheDIs?cYd9JdcB|P_xBCX8{m`82fx{V=hykC*ZaACf8XG|0Y2G$ z@SE*-ew}}My`Ss%_YKY);FHYMc z4bB_jlg$Ue*?#BO`KQ-YB!&Kuy9%?H2Pe&^Tu zr`P+ret+NKya7JheDIs?cYd9JdcB|P_xBCX8{m`82fx{V=hykC*ZaACf8XG|0Y2G$ z@SE*-ew}}My`Ss%_YKY);FHYMc z4bB_jGxK?Er_Wyx?vt~ZpMUzXFa7(=9nYV)efv^gukGJ&^QFDIK6GCjPnX~Je48)r z)#b1I+IYJBw&&Y?X|FDS-Pgv`<+nZG=1Y5Z`Rl$mo-V)b`8HqLtIJ>awefWMZO^y) z(q3Kuy049=%Wr$W&6oD-^4EQBJY9a<^KHJgSC_x;Yvbwi+n#UprM{tHOM7+s>%KOgF2C*hHecGS%U}1k@pSoZ z&$s!~US0mWuZ^e6Z+pJYm-g!N*L`g~U4Gm1ZN9Wum%r|7TX_dv*EizBZmNzwP-pU)rn7U-z}~ zbop)1xB1duUH-bSji<|Rd%n$=_UiK2eQi8le$2o9{O9q&0v0qt12jMbG(ZD1Km#;D z12jMbG(ZD1Km#;D12jMbG(ZD1Km#;D12jMbG(ZD1Km#;D12jMbG(ZD1Km#;D12jMb zG(ZD1Km#;D12jMbG(ZD1Km#;D12jMbG(ZD1Km#;D12jMbucd(p-yi@12tWV=5P$## SAOHafKmY;|fB*!d3H%G#{vOf* literal 165662 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 XvfT3OnBG??jvc_|7>?D0Q^Mu{9L5vv diff --git a/src/assets/favicon.png b/src/assets/favicon.png index 0ee467fcfbe41a904384a7e38f1333d7b18dea22..1ea167e959e6ed208f49ab1ce8bfd5baf706c6d4 100644 GIT binary patch literal 718 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE4M+yv$zcaloCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&di3{1(ME{-7;jBoEA>}_@sU^w{n$$sSnHy`(Fux zR3_p)iPcbu&(D0RsAIcd{Plk}C1zo@03mqmi*(}Vv-<+ShHuV~n)`NdcseDP>Av13 e&%B7Dn2Mh#C|kKpPX?4?89ZJ6T-G@yGywqPRL}$f delta 441 zcmX@d`jA<%Gr-TCmrII^fq{Y7)59eQNIL*=00$e8T)Ds4b)uq4J!6@ti(^Oy?$~>|k;6i(72&NA43Z@%3G&EB4r7wb7v{2Dd;dK+Hs#WxjdI2kJj((_bWd%X^WxQ~EBhR)8@AO59sjr}ZmxH` z+3d3mFLi3aTO{{Edb303tb4B?#qQJJuq%A?udo+KDs1Mx`TqM=?!zwbGVb~>ReM)G z71lkPw|%xJ_i?Ee>uR2!-TK~@)8f14gV)CwglANq`25FtSNIEw4|}54PFuGiz*b>( z+?J_nx8H7?FzwbEmUbDI=TSdnn7F4ltatQh_+$OYq%0ZTvr@htKWd)t`F8&aB%Bxy aJQWtqFIn%;pLbpgB;@Jp=d#Wzp$Pz54aHjk diff --git a/src/assets/favicon.svg b/src/assets/favicon.svg index 9d5bc33..dc331b2 100644 --- a/src/assets/favicon.svg +++ b/src/assets/favicon.svg @@ -1,5 +1,4 @@ - - - + + diff --git a/src/environments/environment.development.ts b/src/environments/environment.development.ts index f56418b..9d07f81 100644 --- a/src/environments/environment.development.ts +++ b/src/environments/environment.development.ts @@ -4,4 +4,5 @@ export const environment = { clientId: 2, clientSecret: 'YllFbaRHMP0kCJLb0UdCcOfpTzA23ea3AOdIfRMj', domenUrl: 'http://localhost:4200', - }; \ No newline at end of file + googleAnalyticsId: 'G-B8183299MH', + }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7f343ad..141397d 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,4 +4,5 @@ export const environment = { clientId: 2, clientSecret: 'KIWaOS7ML1ZEUmgByFN5Cf9wf0pHFWjYJ5rmOboX', domenUrl: 'https://nirgroup.ru', + googleAnalyticsId: 'G-B8183299MH', };