diff --git a/Frontend/src/app/app.module.ts b/Frontend/src/app/app.module.ts
index 397f87e..908df17 100644
--- a/Frontend/src/app/app.module.ts
+++ b/Frontend/src/app/app.module.ts
@@ -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,
diff --git a/Frontend/src/app/components/login-page/login-page.component.ts b/Frontend/src/app/components/login-page/login-page.component.ts
index 90a05cf..b4bb825 100644
--- a/Frontend/src/app/components/login-page/login-page.component.ts
+++ b/Frontend/src/app/components/login-page/login-page.component.ts
@@ -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;
diff --git a/Frontend/src/app/components/notifications/notifications.component.html b/Frontend/src/app/components/notifications/notifications.component.html
new file mode 100644
index 0000000..7195276
--- /dev/null
+++ b/Frontend/src/app/components/notifications/notifications.component.html
@@ -0,0 +1,8 @@
+
+
+ {{msg.text}}
+
+ {{msg.btn}}
+
+
+
\ No newline at end of file
diff --git a/Frontend/src/app/components/notifications/notifications.component.scss b/Frontend/src/app/components/notifications/notifications.component.scss
new file mode 100644
index 0000000..98dcdbf
--- /dev/null
+++ b/Frontend/src/app/components/notifications/notifications.component.scss
@@ -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;
+}
\ No newline at end of file
diff --git a/Frontend/src/app/components/notifications/notifications.component.spec.ts b/Frontend/src/app/components/notifications/notifications.component.spec.ts
new file mode 100644
index 0000000..07f2f87
--- /dev/null
+++ b/Frontend/src/app/components/notifications/notifications.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NotificationsComponent } from './notifications.component';
+
+describe('NotificationsComponent', () => {
+ let component: NotificationsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ NotificationsComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(NotificationsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/Frontend/src/app/components/notifications/notifications.component.ts b/Frontend/src/app/components/notifications/notifications.component.ts
new file mode 100644
index 0000000..ebb4747
--- /dev/null
+++ b/Frontend/src/app/components/notifications/notifications.component.ts
@@ -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
+ ) {}
+}
diff --git a/Frontend/src/app/main-view/main-view.component.scss b/Frontend/src/app/main-view/main-view.component.scss
index 30d86e0..f21e659 100644
--- a/Frontend/src/app/main-view/main-view.component.scss
+++ b/Frontend/src/app/main-view/main-view.component.scss
@@ -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;
}
\ No newline at end of file
diff --git a/Frontend/src/app/main-view/main-view.component.ts b/Frontend/src/app/main-view/main-view.component.ts
index 8b771e7..0a7aae5 100644
--- a/Frontend/src/app/main-view/main-view.component.ts
+++ b/Frontend/src/app/main-view/main-view.component.ts
@@ -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();
diff --git a/Frontend/src/app/material.module.ts b/Frontend/src/app/material.module.ts
index 423f680..1b3c04a 100644
--- a/Frontend/src/app/material.module.ts
+++ b/Frontend/src/app/material.module.ts
@@ -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: []
})
diff --git a/Frontend/src/app/modules/layers/layer-detail/layer-detail.component.ts b/Frontend/src/app/modules/layers/layer-detail/layer-detail.component.ts
index ecc7286..85c02eb 100644
--- a/Frontend/src/app/modules/layers/layer-detail/layer-detail.component.ts
+++ b/Frontend/src/app/modules/layers/layer-detail/layer-detail.component.ts
@@ -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ł.",
+ });
}
}
}
diff --git a/Frontend/src/app/modules/layers/layer-edit/layer-edit.component.ts b/Frontend/src/app/modules/layers/layer-edit/layer-edit.component.ts
index 87c2225..f804d0d 100644
--- a/Frontend/src/app/modules/layers/layer-edit/layer-edit.component.ts
+++ b/Frontend/src/app/modules/layers/layer-edit/layer-edit.component.ts
@@ -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';
diff --git a/Frontend/src/app/services/notifications.service.ts b/Frontend/src/app/services/notifications.service.ts
new file mode 100644
index 0000000..b893880
--- /dev/null
+++ b/Frontend/src/app/services/notifications.service.ts
@@ -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
+}
diff --git a/Frontend/src/styles.scss b/Frontend/src/styles.scss
index 298db6a..4e60916 100644
--- a/Frontend/src/styles.scss
+++ b/Frontend/src/styles.scss
@@ -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;
}
diff --git a/WebAPI/appsettings.Development.json b/WebAPI/appsettings.Development.json
index 860df4c..93a022c 100644
--- a/WebAPI/appsettings.Development.json
+++ b/WebAPI/appsettings.Development.json
@@ -8,7 +8,7 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
- "SQLDatabase": "Server=tcp:127.0.0.1,1433;Initial Catalog=diuna;Persist Security Info=False;User ID=SA;Password=v](8Lc|RfG;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;Connection Timeout=30;"
+ "SQLDatabase": "Server=tcp:127.0.0.1,1433;Initial Catalog=diunabi-morska;Persist Security Info=False;User ID=SA;Password=v](8Lc|RfG;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;Connection Timeout=30;"
},
"GoogleClientId": "107631825312-bkfe438ehr9k9ecb2h76g802tj6advma.apps.googleusercontent.com",
"Secret": "8393AF8EAEF8478CB738D44858690F9C7E2D19F65896DD9FBAA3EB2A6F493E80",