Commit fafd66a2 by Ooh-Ao

เพิ่ม dialog

parent affd9160
......@@ -42,6 +42,7 @@
"@syncfusion/ej2-angular-layouts": "^29.2.4",
"@syncfusion/ej2-angular-maps": "^29.1.33",
"@syncfusion/ej2-angular-pivotview": "^29.2.4",
"@syncfusion/ej2-angular-popups": "^29.2.8",
"@syncfusion/ej2-angular-treemap": "^29.2.4",
"@syncfusion/ej2-base": "^29.2.4",
"@syncfusion/ej2-buttons": "^29.2.4",
......@@ -6276,6 +6277,17 @@
"@syncfusion/ej2-pivotview": "29.2.10"
}
},
"node_modules/@syncfusion/ej2-angular-popups": {
"version": "29.2.8",
"resolved": "https://registry.npmjs.org/@syncfusion/ej2-angular-popups/-/ej2-angular-popups-29.2.8.tgz",
"integrity": "sha512-DThwDsjcRF4ngaEFbr+B2mLGtOrFN/ezisgFGLiBGsKsm7HK3RPKTBMQY9xwJ1xCX48dIMVEQnhen+76hbLWOQ==",
"license": "SEE LICENSE IN license",
"dependencies": {
"@syncfusion/ej2-angular-base": "~29.2.4",
"@syncfusion/ej2-base": "~29.2.4",
"@syncfusion/ej2-popups": "29.2.8"
}
},
"node_modules/@syncfusion/ej2-angular-treemap": {
"version": "29.2.4",
"resolved": "https://registry.npmjs.org/@syncfusion/ej2-angular-treemap/-/ej2-angular-treemap-29.2.4.tgz",
......
<router-outlet></router-outlet>
<ejs-dialog #notificationDialog
[header]="notification?.title"
[content]="notification?.content"
[visible]="isNotificationVisible"
(close)="onDialogClose()"
[isModal]="true"
width="400px"
[showCloseIcon]="true"
[target]="'body'"
[animationSettings]="{ effect: 'Zoom' }">
<ng-template #header>
<div [ngClass]="getHeaderClass()">
<span class="e-dlg-title">{{ notification?.title }}</span>
</div>
</ng-template>
<ng-template #content>
<div class="dialog-content">
<p>{{ notification?.content }}</p>
</div>
</ng-template>
<ng-template #footerTemplate>
<button ejs-button (click)="onDialogClose()" cssClass="e-primary">OK</button>
</ng-template>
</ejs-dialog>
import { Component } from '@angular/core';
import { Component, OnDestroy, ViewChild, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import {
......@@ -9,21 +9,57 @@ import {
transition,
// ...
} from '@angular/animations';
import { fromEvent } from 'rxjs';
import { fromEvent, Subscription } from 'rxjs';
import { DialogComponent, DialogModule } from '@syncfusion/ej2-angular-popups';
import { Notification, NotificationService } from './shared/services/notification.service';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet],
imports: [CommonModule, RouterOutlet, DialogModule],
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
animations:[]
})
export class AppComponent {
export class AppComponent implements OnDestroy, OnInit {
title = 'ynex';
public isSpinner = true;
@ViewChild('notificationDialog') notificationDialog!: DialogComponent;
private notificationSubscription: Subscription;
public notification: Notification | null = null;
public isNotificationVisible = false;
constructor(private notificationService: NotificationService) {
this.notificationSubscription = this.notificationService.notification$.subscribe(
(notification) => {
this.notification = notification;
this.isNotificationVisible = true;
if (this.notificationDialog) {
this.notificationDialog.show();
}
}
);
}
ngOnInit() {
// this.isSpinner = false
// fromEvent(window, 'load').subscribe(() => {document.querySelector('#loader')?.classList.remove('');});
}
getHeaderClass(): string {
if (!this.notification) {
return '';
}
return `e-dlg-header-content e-dlg-${this.notification.type}`;
}
onDialogClose() {
this.isNotificationVisible = false;
}
ngOnDestroy() {
this.notificationSubscription.unsubscribe();
}
}
......@@ -14,6 +14,7 @@ import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { ToastrModule } from 'ngx-toastr';
import { DialogModule } from '@syncfusion/ej2-angular-popups';
import { NgDragDropModule } from 'ng-drag-drop';
import { HttpClientModule, HTTP_INTERCEPTORS, provideHttpClient, HttpClient, withInterceptors } from "@angular/common/http";
import { HttpRequestInterceptor } from './shared/services/http-request.interceptor';
......@@ -71,7 +72,8 @@ export const appConfig: ApplicationConfig = {
progressBar: true,
}),
NgDragDropModule.forRoot(),
HttpClientModule
HttpClientModule,
DialogModule
),
httpInterceptorProviders,
DashboardDataService,
......
......@@ -5,10 +5,11 @@ import { ActivatedRoute, RouterModule } from '@angular/router';
import { CommonModule, TitleCasePipe } from '@angular/common';
import { NgComponentOutlet } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Observable, of, forkJoin } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';
import { Observable, of, forkJoin, throwError } from 'rxjs';
import { map, switchMap, tap, catchError } from 'rxjs/operators';
import { DashboardLayoutModule, PanelModel } from '@syncfusion/ej2-angular-layouts'; // Import Syncfusion modules
import { MatDialog, MatDialogModule } from '@angular/material/dialog'; // Import MatDialog
import { NotificationService } from '../../shared/services/notification.service';
import { DashboardModel, WidgetModel, DatasetModel } from '../models/widgets.model';
import { DashboardDataService } from '../services/dashboard-data.service';
......@@ -546,11 +547,17 @@ export class DashboardManagementComponent implements OnInit {
private widgetService: WidgetService, // Inject WidgetService
private dashboardStateService: DashboardStateService,
private datasetService: DatasetService, // Inject DatasetService
private dialog: MatDialog
private dialog: MatDialog,
private notificationService: NotificationService
) { }
ngOnInit(): void {
this.dashboardDataService.getDashboards().subscribe(dashboards => {
this.dashboardDataService.getDashboards().pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to load user dashboards.');
return throwError(() => error);
})
).subscribe(dashboards => {
this.userDashboards = dashboards;
// if (this.userDashboards.length > 0) {
// this.selectedDashboardId = this.userDashboards[0];
......@@ -559,7 +566,12 @@ export class DashboardManagementComponent implements OnInit {
});
// Populate availableWidgets from WidgetService
this.widgetService.getListWidgets().subscribe(widgets => {
this.widgetService.getListWidgets().pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to load available widgets.');
return throwError(() => error);
})
).subscribe(widgets => {
this.availableWidgets = [...widgets].map(widget => ({
...widget,
config: widget.config || {} // Ensure config property exists
......@@ -587,13 +599,20 @@ export class DashboardManagementComponent implements OnInit {
loadSelectedDashboard(): void {
console.log(this.selectedDashboardId)
if (this.selectedDashboardId) {
this.dashboardDataService.getDashboardById(this.selectedDashboardId.dashboardId).subscribe(dashboard => {
this.notificationService.info('Info', 'Loading dashboard data...');
this.dashboardDataService.getDashboardById(this.selectedDashboardId.dashboardId).pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to load dashboard data.');
return throwError(() => error);
})
).subscribe(dashboard => {
if (dashboard) {
this.dashboardData = dashboard;
this.panels = this.mapWidgetsToPanels(dashboard.widgets || []);
if (dashboard.datasetId) {
this.dashboardStateService.selectDataset(dashboard.datasetId);
}
this.notificationService.success('Success', 'Dashboard loaded successfully!');
}
});
}
......@@ -608,17 +627,30 @@ export class DashboardManagementComponent implements OnInit {
application: sessionStorage.getItem('module') || '',
widgets: []
});
this.dashboardDataService.saveDashboard(newDashboard).subscribe(addedDashboard => {
this.dashboardDataService.saveDashboard(newDashboard).pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to create new dashboard.');
return throwError(() => error);
})
).subscribe(addedDashboard => {
this.userDashboards.push(addedDashboard);
this.selectedDashboardId = addedDashboard;
this.loadSelectedDashboard();
this.notificationService.success('Success', 'New dashboard created successfully!');
});
}
}
saveDashboardName(): void {
if (this.dashboardData) {
this.dashboardDataService.saveDashboard(this.dashboardData).subscribe();
this.dashboardDataService.saveDashboard(this.dashboardData).pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to save dashboard name.');
return throwError(() => error);
})
).subscribe(() => {
this.notificationService.success('Success', 'Dashboard name saved successfully!');
});
}
}
......@@ -668,11 +700,25 @@ export class DashboardManagementComponent implements OnInit {
if (dataFetchTasks.length > 0) {
forkJoin(dataFetchTasks).subscribe(() => {
console.log('All data fetched, now saving dashboard...');
this.dashboardDataService.saveDashboard(this.dashboardData!).subscribe();
this.dashboardDataService.saveDashboard(this.dashboardData!).pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to save dashboard layout.');
return throwError(() => error);
})
).subscribe(() => {
this.notificationService.success('Success', 'Dashboard layout saved successfully!');
});
});
} else {
console.log('No data to fetch, saving dashboard directly...');
this.dashboardDataService.saveDashboard(this.dashboardData).subscribe();
this.dashboardDataService.saveDashboard(this.dashboardData).pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to save dashboard layout.');
return throwError(() => error);
})
).subscribe(() => {
this.notificationService.success('Success', 'Dashboard layout saved successfully!');
});
}
}
......@@ -685,6 +731,7 @@ export class DashboardManagementComponent implements OnInit {
}
this.dashboardData.widgets.push(widget);
this.panels = this.mapWidgetsToPanels(this.dashboardData.widgets);
this.notificationService.info('Info', 'Widget added to dashboard.');
}
// Test method to add the new data-driven widget
......@@ -722,9 +769,14 @@ export class DashboardManagementComponent implements OnInit {
deleteDashboard(): void {
if (this.selectedDashboardId && confirm('Are you sure you want to delete this dashboard?')) {
this.dashboardDataService.deleteDashboard(this.dashboardData!).subscribe(result => {
this.dashboardDataService.deleteDashboard(this.dashboardData!).pipe(
catchError(error => {
this.notificationService.error('Error', 'Failed to delete dashboard.');
return throwError(() => error);
})
).subscribe(result => {
console.log(result)
this.notificationService.success('Success', 'Dashboard deleted successfully!');
});
}
}
......@@ -735,6 +787,7 @@ export class DashboardManagementComponent implements OnInit {
const updatedDashboard = { ...this.dashboardData, widgets: this.dashboardData.widgets.filter(w => w.widgetId !== panelId) };
this.dashboardData = updatedDashboard;
this.panels = this.mapWidgetsToPanels(updatedDashboard.widgets);
this.notificationService.info('Info', 'Widget removed from dashboard.');
// const updatedDashboard = { ...this.dashboardData, widgets: this.dashboardData.widgets.filter(w => w.id !== panelId) };
// this.dashboardDataService.saveDashboard(updatedDashboard).subscribe(updated => {
......
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
export interface Notification {
title: string;
content: string;
type: 'success' | 'error' | 'warning' | 'info';
}
@Injectable({
providedIn: 'root'
})
export class NotificationService {
private notificationSubject = new Subject<Notification>();
notification$ = this.notificationSubject.asObservable();
show(notification: Notification) {
this.notificationSubject.next(notification);
}
success(title: string, content: string) {
this.show({ title, content, type: 'success' });
}
error(title: string, content: string) {
this.show({ title, content, type: 'error' });
}
warning(title: string, content: string) {
this.show({ title, content, type: 'warning' });
}
info(title: string, content: string) {
this.show({ title, content, type: 'info' });
}
}
\ No newline at end of file
......@@ -7,8 +7,7 @@ Created Date : 12/02/2024
Author & Copyright Ownership : Spruko Technologies Private Limited
Author URL : https://themeforest.net/user/spruko
Support : https://support.spruko.com/
Support : https://support.spruko.com/
License Details : https://spruko.com/licenses-details
......@@ -173,3 +172,33 @@ Background Image
@import "./tailwind/progress";
/* General Dialog Header Styling */
.e-dialog .e-dlg-header-content {
padding: 10px;
color: white;
}
/* Success Notification */
.e-dialog .e-dlg-success {
background-color: #28a745; /* Green */
}
/* Error Notification */
.e-dialog .e-dlg-error {
background-color: #dc3545; /* Red */
}
/* Warning Notification */
.e-dialog .e-dlg-warning {
background-color: #ffc107; /* Yellow */
color: #212529; /* Dark text for better contrast */
}
/* Info Notification */
.e-dialog .e-dlg-info {
background-color: #17a2b8; /* Blue */
}
.dialog-content {
padding: 20px;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment