Merge pull request #22 from HideyoshiNakazone/devel

Devel - Implements Cookie Consent Popup
This commit is contained in:
2023-09-07 04:08:30 -03:00
committed by GitHub
13 changed files with 358 additions and 147 deletions

View File

@@ -1,145 +1,147 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"frontend-hideyoshi.com": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "src/webpack.config.ts"
},
"outputPath": "dist/frontend-hideyoshi.com",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"allowedCommonJsDependencies": [
"ts-interface-checker"
],
"assets": [
"src/assets",
"src/manifest.webmanifest",
"src/manifest.webmanifest"
],
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/normalize.css/normalize.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"frontend-hideyoshi.com": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "src/webpack.config.ts"
},
"outputPath": "dist/frontend-hideyoshi.com",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"allowedCommonJsDependencies": [
"ts-interface-checker"
],
"assets": [
"src/assets",
"src/manifest.webmanifest",
"src/manifest.webmanifest"
],
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/normalize.css/normalize.css",
"node_modules/cookieconsent/build/cookieconsent.min.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/cookieconsent/build/cookieconsent.min.js"
],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all",
"serviceWorker": true
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "frontend-hideyoshi.com:build:build"
},
"configurations": {
"production": {
"browserTarget": "frontend-hideyoshi.com:build:production",
"proxyConfig": "src/proxy.conf.json"
},
"development": {
"browserTarget": "frontend-hideyoshi.com:build:development",
"proxyConfig": "src/proxy.conf.json"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "frontend-hideyoshi.com:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/assets",
"src/manifest.webmanifest",
"src/manifest.webmanifest"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all",
"serviceWorker": true
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "frontend-hideyoshi.com:build:build"
},
"configurations": {
"production": {
"browserTarget": "frontend-hideyoshi.com:build:production",
"proxyConfig": "src/proxy.conf.json"
},
"development": {
"browserTarget": "frontend-hideyoshi.com:build:development",
"proxyConfig": "src/proxy.conf.json"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "frontend-hideyoshi.com:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/assets",
"src/manifest.webmanifest",
"src/manifest.webmanifest"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"cli": {
"schematicCollections": [
"@angular-eslint/schematics"
],
"analytics": false
},
"schematics": {
"@angular-eslint/schematics:application": {
"setParserOptionsProject": true
},
"@angular-eslint/schematics:library": {
"setParserOptionsProject": true
"cli": {
"schematicCollections": [
"@angular-eslint/schematics"
],
"analytics": false
},
"schematics": {
"@angular-eslint/schematics:application": {
"setParserOptionsProject": true
},
"@angular-eslint/schematics:library": {
"setParserOptionsProject": true
}
}
}
}

34
package-lock.json generated
View File

@@ -25,9 +25,12 @@
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"bootstrap": "^4.6.2",
"cookieconsent": "^3.1.1",
"cors": "^2.8.5",
"express": "^4.18.1",
"jquery": "^3.6.0",
"ngx-cookie-service": "^16.0.1",
"ngx-cookieconsent": "^4.0.2",
"normalize.css": "^8.0.1",
"rxjs": "~7.5.0",
"ts-interface-checker": "^1.0.2",
@@ -6711,6 +6714,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/cookieconsent": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/cookieconsent/-/cookieconsent-3.1.1.tgz",
"integrity": "sha512-v8JWLJcI7Zs9NWrs8hiVldVtm3EBF70TJI231vxn6YToBGj0c9dvdnYwltydkAnrbBMOM/qX1xLFrnTfm5wTag=="
},
"node_modules/copy-anything": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
@@ -11381,6 +11389,32 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"node_modules/ngx-cookie-service": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-16.0.1.tgz",
"integrity": "sha512-q8i5eX2b6SIIZcu9wy+lvOU65cLJhHD9EVz5TGGkKi8Y7X/aZbUyQ9U4CgNOfKDWtPUDFOMD8IW/cijoVKe59Q==",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/common": "^16.0.0",
"@angular/core": "^16.0.0"
}
},
"node_modules/ngx-cookieconsent": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/ngx-cookieconsent/-/ngx-cookieconsent-4.0.2.tgz",
"integrity": "sha512-KREGRd53LV0SrFlJsk1XwgzZIEf7GAeLD3/znYF/CzTYml+SFqWrYleXA3aMtFLGqUHwbGS/fMA6cHwpvxT5JA==",
"dependencies": {
"tslib": "^2.1.0"
},
"peerDependencies": {
"@angular/common": ">=14.0.0",
"@angular/core": ">=14.0.0",
"cookieconsent": "^3.1.1",
"rxjs": "^7.5.0"
}
},
"node_modules/nice-napi": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",

View File

@@ -32,9 +32,12 @@
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"bootstrap": "^4.6.2",
"cookieconsent": "^3.1.1",
"cors": "^2.8.5",
"express": "^4.18.1",
"jquery": "^3.6.0",
"ngx-cookie-service": "^16.0.1",
"ngx-cookieconsent": "^4.0.2",
"normalize.css": "^8.0.1",
"rxjs": "~7.5.0",
"ts-interface-checker": "^1.0.2",

View File

@@ -1,6 +1,14 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnDestroy, OnInit} from '@angular/core';
import { AuthService } from './shared/auth/auth.service';
import {UpdateService} from "./shared/service-worker/update.service";
import {
NgcCookieConsentService,
NgcInitializationErrorEvent,
NgcInitializingEvent,
NgcNoCookieLawEvent, NgcStatusChangeEvent
} from "ngx-cookieconsent";
import {Subscription} from "rxjs";
import {CookieConsertService} from "./shared/cookie-consent/cookie-consert.service";
@Component({
selector: 'app-root',
@@ -11,12 +19,34 @@ export class AppComponent implements OnInit {
title = 'frontend-hideyoshi.com';
constructor(private authService: AuthService, private serviceWorker: UpdateService) {
cookieStatusChangeSubscription!: Subscription;
constructor(
private authService: AuthService,
private ccService: NgcCookieConsentService,
private cookieConsentService: CookieConsertService,
private serviceWorker: UpdateService) {
this.serviceWorker.checkForUpdates();
}
ngOnInit(): void {
this.authService.autoLogin();
let cookieConsentStatus = this.cookieConsentService.getCookieConsentStatusFromLocalStorage();
if (cookieConsentStatus) {
this.ccService.fadeOut();
}
this.cookieStatusChangeSubscription = this.ccService.statusChange$.subscribe(
(event: NgcStatusChangeEvent) => {
if (event.status === 'allow') {
this.cookieConsentService.consent();
} else if (event.status === 'deny') {
this.cookieConsentService.decline();
}
}
);
}
}

View File

@@ -46,13 +46,19 @@
<div class="col-lg-6 authentication-body">
<button mat-button
class="oauth-button d-flex justify-content-center align-items-center"
[disabled]="isCookieBlocked"
(click)="onGoogleLogin()">
<mat-icon style="width: 50px; height:30px"
<mat-icon *ngIf="!isCookieBlocked"
style="width: 50px; height:30px"
svgIcon="google-logo"></mat-icon>
<mat-icon *ngIf="isCookieBlocked"
style="width: 50px; height:30px"
svgIcon="google-disabled-logo"></mat-icon>
Login With Google
</button>
<button mat-button
class="oauth-button d-flex justify-content-center align-items-center"
[disabled]="isCookieBlocked"
(click)="onGithubLogin()">
<mat-icon style="width: 50px; height:30px"
svgIcon="github-logo"></mat-icon>

View File

@@ -12,9 +12,12 @@ import { User } from 'src/app/shared/model/user/user.model';
import {animate, animateChild, group, query, state, style, transition, trigger} from "@angular/animations";
import {ValidatePasswordValidator} from "../../../shared/validators/validate-password.validator";
import {ValidateNotEmptyValidator} from "../../../shared/validators/validate-not-empty.validator";
import {NgcCookieConsentService, NgcStatusChangeEvent} from "ngx-cookieconsent";
import {CookieConsertService} from "../../../shared/cookie-consent/cookie-consert.service";
const GOOGLE_LOGO_SVG = "assets/img/providers/google.svg";
const GOOGLE_DISABLED_LOGO_SVG = "assets/img/providers/google-disabled.svg";
const GITHUB_LOGO_SVG = "assets/img/providers/github.svg";
@Component({
@@ -100,8 +103,12 @@ export class LoginComponent implements OnInit, AfterViewInit, OnDestroy {
authSubject!: Subscription;
cookieStatusChangeSubscription!: Subscription;
errorMessage!: string | null;
isCookieBlocked = false;
isShowErrorMessage = false;
_userIcon = faUser;
@@ -110,6 +117,8 @@ export class LoginComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(
private authService: AuthService,
private ccService: NgcCookieConsentService,
private cookieConsentService: CookieConsertService,
private changeDetectorRef: ChangeDetectorRef,
private matIconRegistry: MatIconRegistry,
private domSanitizer: DomSanitizer) {
@@ -117,6 +126,10 @@ export class LoginComponent implements OnInit, AfterViewInit, OnDestroy {
"google-logo",
this.domSanitizer.bypassSecurityTrustResourceUrl(GOOGLE_LOGO_SVG)
);
this.matIconRegistry.addSvgIcon(
"google-disabled-logo",
this.domSanitizer.bypassSecurityTrustResourceUrl(GOOGLE_DISABLED_LOGO_SVG)
)
this.matIconRegistry.addSvgIcon(
"github-logo",
this.domSanitizer.bypassSecurityTrustResourceUrl(GITHUB_LOGO_SVG)
@@ -134,6 +147,17 @@ export class LoginComponent implements OnInit, AfterViewInit, OnDestroy {
this.validateLogin(res);
}
);
this.cookieStatusChangeSubscription = this.cookieConsentService.cookieStatusChangeSubscription.subscribe(
(status: boolean) => {
this.isCookieBlocked = !status;
console.log("Cookie status: " + status);
}
);
if (this.isCookieBlocked) {
this.ccService.fadeIn();
}
}
ngAfterViewInit(): void {
@@ -142,6 +166,7 @@ export class LoginComponent implements OnInit, AfterViewInit, OnDestroy {
ngOnDestroy(): void {
this.authSubject.unsubscribe();
this.cookieStatusChangeSubscription.unsubscribe();
}
onStateChange(state: boolean) {

View File

@@ -0,0 +1,44 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {NgcCookieConsentConfig, NgcCookieConsentModule} from "ngx-cookieconsent";
const cookieConfig: NgcCookieConsentConfig = {
"cookie": {
"domain": "tinesoft.github.io"
},
"position": "bottom-right",
"theme": "classic",
"palette": {
"popup": {
"background": "#4e4e4e",
"text": "#ffffff",
"link": "#ffffff"
},
"button": {
"background": "#fa2f22",
"text": "#ffffff",
"border": "transparent"
}
},
"type": "opt-in",
"content": {
"message": "This website uses cookies to ensure you get the best experience on our website.",
"dismiss": "Got it!",
"deny": "Refuse cookies",
"link": "",
"href": "",
"policy": "Cookie Policy"
}
};
@NgModule({
declarations: [],
imports: [
CommonModule,
NgcCookieConsentModule.forRoot(cookieConfig)
]
})
export class CookieConsentModule {
}

View File

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

View File

@@ -0,0 +1,52 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject, Subject, Subscription} from "rxjs";
import {CookieService} from "ngx-cookie-service";
@Injectable({
providedIn: 'root'
})
export class CookieConsertService {
private storage: Storage;
cookieStatusChangeSubscription!: BehaviorSubject<boolean>
constructor(private cookieService: CookieService) {
this.storage = window.localStorage
this.cookieStatusChangeSubscription = new BehaviorSubject<boolean>(
this.getCookieConsentStatusFromLocalStorage()
);
}
consent() {
let status = true;
this.cookieStatusChangeSubscription.next(status);
this.setCookieConsentStatusToLocalStorage(status);
}
decline() {
let status = false;
this.cookieStatusChangeSubscription.next(status);
this.setCookieConsentStatusToLocalStorage(status);
this.cookieService.deleteAll();
}
setCookieConsentStatusToLocalStorage(status: boolean) {
this.storage.setItem('cookieConsentStatus', status.toString());
}
getCookieConsentStatusFromLocalStorage(): boolean {
let status = this.storage.getItem('cookieConsentStatus');
if (status === null) {
return false;
}
return status === 'true';
}
}

View File

@@ -6,6 +6,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { PopupComponent } from './components/popup/popup.component';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import {CookieConsentModule} from "./cookie-consent/cookie-consent.module";
@NgModule({
declarations: [
@@ -18,6 +19,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
HttpClientModule,
BrowserAnimationsModule,
FontAwesomeModule,
CookieConsentModule
],
exports: [
ClickedOutsideDirective,

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="210px" width="210px" viewBox="0 0 210 210">
<path d="M0,105C0,47.103,47.103,0,105,0c23.383,0,45.515,7.523,64.004,21.756l-24.4,31.696C133.172,44.652,119.477,40,105,40 c-35.841,0-65,29.159-65,65s29.159,65,65,65c28.867,0,53.398-18.913,61.852-45H105V85h105v20c0,57.897-47.103,105-105,105 S0,162.897,0,105z"></path>
</svg>

After

Width:  |  Height:  |  Size: 370 B

View File

@@ -1,9 +1,4 @@
<svg enable-background="new 0 0 533.5 544.3" version="1.1" viewBox="0 0 533.5 544.3" xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ns="&amp;ns_sfw;"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<svg viewBox="0 0 533.5 544.3" xmlns="http://www.w3.org/2000/svg">
<path d="m533.5 278.4c0-18.5-1.5-37.1-4.7-55.3h-256.7v104.8h147c-6.1 33.8-25.7 63.7-54.4 82.7v68h87.7c51.5-47.4 81.1-117.4 81.1-200.2z" style="fill:#4285f4"/>
<path d="m272.1 544.3c73.4 0 135.3-24.1 180.4-65.7l-87.7-68c-24.4 16.6-55.9 26-92.6 26-71 0-131.2-47.9-152.8-112.3h-90.5v70.1c46.2 91.9 140.3 149.9 243.2 149.9z" style="fill:#34a853"/>
<path d="M119.3,324.3c-11.4-33.8-11.4-70.4,0-104.2V150H28.9c-38.6,76.9-38.6,167.5,0,244.4L119.3,324.3z" style="fill:#fbbc04"/>

Before

Width:  |  Height:  |  Size: 1008 B

After

Width:  |  Height:  |  Size: 747 B

View File

@@ -25,5 +25,4 @@
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>