custom notifications service

This commit is contained in:
2023-01-08 16:57:21 +01:00
parent c10e925445
commit 80f09b6f18
14 changed files with 187 additions and 163 deletions

View File

@@ -14,6 +14,7 @@ import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core';
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MomentDateAdapter } from '@angular/material-moment-adapter';
import { registerLocaleData } from '@angular/common';
import localePl from '@angular/common/locales/pl';
import { NotificationsComponent } from './components/notifications/notifications.component';
registerLocaleData(localePl, 'pl-PL');
@@ -21,7 +22,8 @@ registerLocaleData(localePl, 'pl-PL');
declarations: [
AppComponent,
MainViewComponent,
LoginPageComponent
LoginPageComponent,
NotificationsComponent
],
imports: [
BrowserModule,

View File

@@ -1,9 +1,9 @@
import { Component, NgZone, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import jwt_decode from "jwt-decode";
import { AuthService } from 'src/app/auth/auth.service';
import { User } from 'src/app/models/user.model';
import { NotificationsService } from 'src/app/services/notifications.service';
import { environment } from 'src/environments/environment';
@Component({
@@ -17,14 +17,12 @@ export class LoginPageComponent implements OnInit {
private router$: Router,
private auth$: AuthService,
private ngZone$: NgZone,
private snackBar$: MatSnackBar
private notifications$: NotificationsService
) { }
loading = false;
ngOnInit(): void {
this.snackBar$.open("", "", { duration: 1 });
console.log('Envs', environment);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.onGoogleLibraryLoad = () => {
@@ -66,13 +64,20 @@ export class LoginPageComponent implements OnInit {
this.ngZone$.run(() => {
this.router$.navigate(['/app']);
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
console.error('handleCredentialResponse', e);
this.loading = false;
if (e.status === 401) {
this.snackBar$.open("Użytkownik nie istnieje w bazie danych aplikacji DiunaBI.", "", { duration: 3000 });
this.notifications$.add({
text: "Użytkownik nie istnieje w bazie danych aplikacji DiunaBI.",
duration: 2500
});
} else {
this.snackBar$.open("Błąd połączenia z serwerem. Skontaktuj się z administratorem.", "", { duration: 3000 });
this.notifications$.add({
text: "Błąd połączenia z serwerem. Skontaktuj się z administratorem.",
duration: 2500
});
}
} finally {
this.loading = false;

View File

@@ -0,0 +1,8 @@
<mat-card *ngFor="let msg of notifications$.messages">
<mat-card-content>
<span class="text">{{msg.text}}</span>
<span class="btn" *ngIf="msg.btn">
<a class="action-button" (click)="notifications$.doAction(msg)">{{msg.btn}}</a>
</span>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,17 @@
mat-card {
margin-bottom: 3px;
background-color: rgba(255, 145, 0, 0.4);
}
.action-button {
cursor: pointer;
}
.text {
display: inline-block;
width: 70%;
}
.btn {
display: inline-block;
width: 30%;
text-align: right;
color: red;
}

View File

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

View File

@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { NotificationsService } from 'src/app/services/notifications.service';
@Component({
selector: 'app-notifications',
templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.scss'],
})
export class NotificationsComponent {
constructor(
public notifications$: NotificationsService
) {}
}

View File

@@ -120,106 +120,9 @@ textarea[disabled] {
color: rgb(205, 206, 177);
font-size: larger;
}
.errorMsg {
font-size: small;
margin-top: 10px;
}
/* links */
a:link,
a:visited {
color: black;
}
.stock-state-error {
color: red;
font-weight: bold;
}
.listContainer {
height: 100%;
width: 100%;
overflow: scroll;
}
.listItem {
height: 40px;
font-size: medium;
}
.listItem:hover {
width: 100%;
cursor: pointer;
background: rgba(130, 130, 130, 0.2);
}
/* snack bars */
.snack-error {
background: #f44336;
}
.input-right {
display: block;
direction: rtl;
}
.background-red {
background-color: rgba(255, 0, 0, 0.6);
}
.background-orange {
background-color: rgba(255, 145, 0, 0.6);
}
.background-green {
background-color: rgba(0, 255, 0, 0.6);
}
.background-grey {
background-color: rgba(100, 100, 100, 0.3);
}
.mat-mdc-dialog-container {
padding: 0px !important;
}
.tab-loader {
width: 25px;
margin-right: 10px;
}
.cell-border {
border-left: 1px solid #e0e0e0;
padding-left: 4px;
}
.cell-background {
background-color: #eeeeee;
}
.breadcrumbs {
width: 100%;
text-align: right;
font-size: small;
color: gray;
margin-top: 0px;
padding-top: 0px;
}
.breadcrumbs a {
color: gray;
text-decoration: none;
}
::ng-deep snack-bar-container.custom-snackbar-error {
background: #ff3452;
}
::ng-deep snack-bar-container.custom-snackbar-success {
background: #9ad284;
}
::ng-deep .mat-mdc-simple-snack-bar {
color: #000;
}
::ng-deep .mat-mdc-snack-bar-action {
color: #000;
}

View File

@@ -9,6 +9,7 @@ import { environment } from 'src/environments/environment';
import { AuthService } from '../auth/auth.service';
import { DataService } from '../services/data.service';
import { DeviceService } from '../services/device.service';
import { NotificationsService } from '../services/notifications.service';
@Component({
selector: 'app-main-view',
@@ -30,7 +31,7 @@ export class MainViewComponent {
private router$: Router,
private swUpdate$: SwUpdate,
private ngZone$: NgZone,
public auth$: AuthService
public auth$: AuthService,
) {
this.swUpdate$.versionUpdates.subscribe(() => {
this.reloadApp();

View File

@@ -1,72 +1,72 @@
import {NgModule} from '@angular/core';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
//import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
//import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';
import { MatStepperModule } from '@angular/material/stepper';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogModule } from '@angular/material/dialog';
import { MatExpansionModule } from '@angular/material/expansion';
//import { MatCheckboxModule } from '@angular/material/checkbox';
//import { MatChipsModule } from '@angular/material/chips';
//import { MatStepperModule } from '@angular/material/stepper';
//import { MatDatepickerModule } from '@angular/material/datepicker';
//import { MatDialogModule } from '@angular/material/dialog';
//import { MatExpansionModule } from '@angular/material/expansion';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from '@angular/material/menu';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatRadioModule } from '@angular/material/radio';
import { MatRippleModule } from '@angular/material/core';
//import { MatProgressBarModule } from '@angular/material/progress-bar';
//import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
//import { MatRadioModule } from '@angular/material/radio';
//import { MatRippleModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSliderModule } from '@angular/material/slider';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatSnackBarModule } from '@angular/material/snack-bar';
//import { MatSliderModule } from '@angular/material/slider';
//import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs';
//import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import {CdkTableModule} from '@angular/cdk/table';
import {MatBadgeModule} from '@angular/material/badge';
//import { MatTooltipModule } from '@angular/material/tooltip';
//import {CdkTableModule} from '@angular/cdk/table';
//import {MatBadgeModule} from '@angular/material/badge';
import {MatBottomSheetModule} from '@angular/material/bottom-sheet';
@NgModule({
exports: [
CdkTableModule,
MatAutocompleteModule,
// CdkTableModule,
// MatAutocompleteModule,
MatButtonModule,
MatButtonToggleModule,
// MatButtonToggleModule,
MatCardModule,
MatCheckboxModule,
MatChipsModule,
MatStepperModule,
MatDatepickerModule,
MatDialogModule,
MatExpansionModule,
// MatCheckboxModule,
// MatChipsModule,
// MatStepperModule,
// MatDatepickerModule,
// MatDialogModule,
// MatExpansionModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRadioModule,
MatRippleModule,
// MatProgressBarModule,
// MatProgressSpinnerModule,
// MatRadioModule,
// MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
// MatSidenavModule,
// MatSliderModule,
// MatSlideToggleModule,
MatSortModule,
MatTableModule,
MatTabsModule,
// MatTabsModule,
MatToolbarModule,
MatTooltipModule,
// MatTooltipModule,
MatSidenavModule,
MatBadgeModule
// MatBadgeModule,
MatBottomSheetModule
],
providers: []
})

View File

@@ -2,14 +2,13 @@ import { DatePipe } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder } from '@angular/forms';
import { MatPaginator } from '@angular/material/paginator';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatSort, MatSortable } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Router, ActivatedRoute } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { AuthService } from 'src/app/auth/auth.service';
import { Layer } from 'src/app/models/layer.model';
import { Record } from 'src/app/models/record.model';
import { NotificationsService } from 'src/app/services/notifications.service';
import { environment } from 'src/environments/environment';
@Component({
@@ -29,12 +28,11 @@ export class LayerDetailComponent implements OnInit {
constructor(
private fb$: UntypedFormBuilder,
private router$: Router,
private http$: HttpClient,
private route$: ActivatedRoute,
private auth$: AuthService,
private snackBar: MatSnackBar,
private datePipe: DatePipe
private datePipe: DatePipe,
private notifications$: NotificationsService
) { }
async ngOnInit() {
@@ -55,9 +53,13 @@ export class LayerDetailComponent implements OnInit {
}
async export() {
if (await Layer.exportToGoogleSheet(this.document.id || "", this.http$)) {
this.snackBar.open("Plik został zapisany na dysku Google", "OK");
this.notifications$.add({
text: "Plik został zapisany na dysku Google.",
});
} else {
this.snackBar.open("Zapis się nie udał.", "OK");
this.notifications$.add({
text: "Zapis się nie udał.",
});
}
}
}

View File

@@ -1,7 +1,6 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Router, ActivatedRoute } from '@angular/router';

View File

@@ -0,0 +1,59 @@
import { Injectable } from '@angular/core';
import { MatBottomSheet, MatBottomSheetRef } from '@angular/material/bottom-sheet';
import { NotificationsComponent } from '../components/notifications/notifications.component';
import { v4 as uuidv4 } from 'uuid';
import moment, { Moment } from 'moment';
@Injectable({
providedIn: 'root'
})
export class NotificationsService {
public messages: Message[] = [];
private handler?: MatBottomSheetRef;
constructor(
private bottomSheet$: MatBottomSheet
) { }
public add(message: Message) {
message.id = uuidv4();
message.createdAt = moment();
this.messages.push(message);
this.sortMessages();
if (this.messages.length === 1) {
this.handler = this.bottomSheet$.open(NotificationsComponent, {
hasBackdrop: false,
disableClose: true
});
}
setTimeout(() => {
this.remove(message);
}, message.duration ? message.duration : 5000);
}
private remove(message: Message) {
this.messages = this.messages.filter(x => x.id!==message.id);
this.sortMessages();
if (this.messages.length === 0 && this.handler) {
this.handler.dismiss();
}
}
private sortMessages() {
this.messages = this.messages.sort((a, b) => {
return a.createdAt && a.createdAt.isAfter(b.createdAt) ? 1 : -1;
})
}
doAction(message: Message) {
if (message.action) { message.action(); }
this.remove(message);
}
}
interface Message {
id?: string;
text: string;
duration?: number;
btn?: string;
// eslint-disable-next-line @typescript-eslint/ban-types
action?: Function;
createdAt?: Moment
}

View File

@@ -44,14 +44,6 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
z-index: 100;
}
.snackbar-success {
background: #BEFF33;
}
.snackbar-error {
background: #e7334b;
}
:root {
--avatar-size: 30px;
}