Compare commits

..

82 Commits

Author SHA1 Message Date
b00896d407 validasi mandatory hari 2024-08-28 15:16:05 +07:00
7c443080d6 perbaikan UI scheduler 2024-08-27 16:41:09 +07:00
98159a1584 penambahan label detail 2024-08-26 14:13:37 +07:00
5c5ca65f53 perbaikan label 2024-08-26 11:54:17 +07:00
ecef25f30d integrasi edit scheduler 2024-08-26 11:43:22 +07:00
45e280c007 penyesuaian scheduler 2024-08-26 11:21:56 +07:00
ca5f0c8c0c integrasi add dan delete scheduler 2024-08-26 11:04:02 +07:00
b1ee612602 penambahan UI scheduler list 2024-08-23 00:27:24 +07:00
9654cf92e8 perbakan UI scheduler 2024-08-22 15:45:48 +07:00
a2d166ac1a penambahan UI control scheduler 2024-08-22 14:09:13 +07:00
a9a7e6edd3 warning perubahan data pada list monitoring 2024-08-22 10:42:01 +07:00
b5e0962079 perbaikan logic save device 2024-08-22 10:10:38 +07:00
633effdb9b penambahan pop up table dan export chart 2024-08-21 15:29:28 +07:00
7a28e52e89 perbaikan service 2024-08-21 11:51:04 +07:00
c54fdd0f55 perbaikan alert watt 2024-08-21 10:53:06 +07:00
04972e33b1 validasi device 2024-08-21 10:20:59 +07:00
f81dc7bf66 perubahan icon back 2024-08-20 16:27:49 +07:00
2b1f6c0cfe logic save ketika room di remove semua 2024-08-20 16:12:48 +07:00
9529da581a alert mandatory monitoring list 2024-08-20 16:04:45 +07:00
b195055651 perbaikan validasi penempatan device dalam ruangan 2024-08-20 15:37:50 +07:00
2a4135c966 perbaikan monitoring list search 2024-08-20 11:45:47 +07:00
cd1f56e07b filter floor status aktif 2024-08-20 11:37:45 +07:00
9377bebcb4 perbaikan UI 2024-08-20 11:02:10 +07:00
57bcbcccde hapus validasi name floor 2024-08-20 10:30:31 +07:00
d753a3a634 perbaikan onchange select floor 2024-08-19 15:16:33 +07:00
a9d135f8ef integrasi select floor per building id 2024-08-19 14:58:00 +07:00
0aac2ff194 perbaikan tampilan cost management 2024-08-19 13:08:35 +07:00
379bdb24da perbaikan routing see more 2024-08-19 12:48:09 +07:00
21b75ca610 klik detail per floor dan room 2024-08-19 11:29:59 +07:00
b5cf71d008 penambahan route floor dan room 2024-08-19 10:06:37 +07:00
cd777f11ad penambahan ui tidak ada data 2024-08-19 09:32:57 +07:00
f4036b1a06 penambahan filter 2024-08-19 09:26:56 +07:00
4fdaa8c1bd penambahan filter dashboard 2024-08-14 12:45:13 +07:00
5410d966d0 update versi 2024-08-13 10:16:21 +07:00
irfan.ms
bfb828c15c Fixing select Room 2024-08-12 16:13:40 +07:00
124f3eef4c penambahan UI pada setiap inputan monitoring list 2024-08-12 13:54:40 +07:00
9b4ac3b992 penambahan floor pada room building dan code pada mster floor 2024-08-08 16:19:07 +07:00
d70edcebd8 perubahan backgound login 2024-07-26 10:16:28 +07:00
a458f2ce3c update versi 2024-07-26 09:42:03 +07:00
db9a9e415a perbaikan master 2024-07-26 09:41:23 +07:00
a9f3da867f update versi 2024-07-25 09:47:13 +07:00
03c7e54bc8 penambahan search code 2024-07-25 09:46:28 +07:00
df1cd2339e perbaikan master room dan detail monitoring 2024-07-23 13:25:47 +07:00
2a6cf6410d perbaikan edit master 2024-07-22 15:21:50 +07:00
3b3757e2a7 pernambahan code pada master room 2024-07-22 15:09:38 +07:00
95fa99799c perbaikan cost management 2024-07-22 13:41:58 +07:00
8cc1a2b9fb perubahan background maintenance 2024-07-22 11:35:51 +07:00
9d8e31e7fe update UI profil 2024-07-22 11:15:05 +07:00
c04cafa384 perbaikan tampilan device edit 2024-07-22 11:01:46 +07:00
e3be28b4b6 perubahan tampilan detail 2024-07-22 09:38:57 +07:00
da4100993b perbaikan master layout button 2024-07-18 15:15:40 +07:00
0c1dd29554 perbaikan master 2024-07-18 14:56:37 +07:00
f86dfb7829 penjagaan double room 2024-07-18 14:35:07 +07:00
9a29e2e4e0 update versi 2024-07-18 14:03:54 +07:00
721d4e9af9 penambahan UI untuk room building ID 2024-07-18 14:02:57 +07:00
153b47eaaa perbaikan detail building 2024-07-17 17:44:41 +07:00
c337a8941c penambahan temperature, air quality dan humidity 2024-07-17 15:40:55 +07:00
bd1cd42ed6 slicing design baru 2024-07-17 11:51:29 +07:00
7bc1fa5fe9 slicing cost manager 2024-07-16 16:33:20 +07:00
768c9ee6ca perbaikan service 2024-07-16 15:53:22 +07:00
efb6ae0060 slicing device 2024-07-16 15:04:12 +07:00
d22eaa50e1 slicing see all control device 2024-07-16 14:24:45 +07:00
60d14b2fce perbaikan service 2024-07-16 13:48:21 +07:00
6b91c937ab implement refresh token 2024-07-16 13:46:58 +07:00
fa12fcec50 kwh max lenght 2024-07-16 11:43:08 +07:00
9570b77e32 update versi 2024-07-16 11:40:31 +07:00
dd1deb0812 perbaikan master dan ngecek token jika ada kegiatan 2024-07-16 11:39:44 +07:00
751c36209e slicing dashboard 2024-07-15 21:39:12 +07:00
4c2d40986e perbaikan master building 2024-07-14 13:56:25 +07:00
5782af4c75 perbaikan master edit 2024-07-13 22:47:01 +07:00
5b3c9bcba4 perbaikan list building 2024-07-12 16:53:04 +07:00
45f3c9b86b perbaikan css 2024-07-12 16:04:47 +07:00
9a0d0d919e perbaikan label master room 2024-07-12 15:25:32 +07:00
13e5ee01d2 perbaikan master 2024-07-12 15:16:53 +07:00
a9034c1a32 perbaikan profil, update password dan master 2024-07-11 14:39:06 +07:00
28067d1704 penambahan maxleght 2024-07-11 11:45:53 +07:00
4ae3b51530 perbaiki kwh 2024-07-11 11:28:41 +07:00
dc4be31103 perbaikan kwh 2024-07-11 11:23:42 +07:00
0b37bcd8ee update versi 2024-07-11 10:26:13 +07:00
a79493d329 edit room building 2024-07-11 10:24:59 +07:00
52481cbc4b salah posisi validator 2024-07-11 10:04:48 +07:00
d43a26513e perbaikan edit building 2024-07-11 10:03:08 +07:00
110 changed files with 5602 additions and 2184 deletions

1
package-lock.json generated
View File

@@ -57,6 +57,7 @@
"jspdf": "^2.5.1", "jspdf": "^2.5.1",
"jspdf-autotable": "^3.5.28", "jspdf-autotable": "^3.5.28",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"ng-chartist": "^4.1.0", "ng-chartist": "^4.1.0",
"ng-multiselect-dropdown": "^0.3.9", "ng-multiselect-dropdown": "^0.3.9",

View File

@@ -63,6 +63,7 @@
"jspdf": "^2.5.1", "jspdf": "^2.5.1",
"jspdf-autotable": "^3.5.28", "jspdf-autotable": "^3.5.28",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"ng-chartist": "^4.1.0", "ng-chartist": "^4.1.0",
"ng-multiselect-dropdown": "^0.3.9", "ng-multiselect-dropdown": "^0.3.9",

View File

@@ -9,23 +9,23 @@
class="btn btn-icon btn-pure secondary mr-1" class="btn btn-icon btn-pure secondary mr-1"
routerLink="{{ breadcrumb.linkBack }}" routerLink="{{ breadcrumb.linkBack }}"
> >
<i class="feather ft-chevron-left" style="color: #ffffff"></i> <i class="feather ft-chevron-left" style="color: #242222"></i>
</button> </button>
<h3 class="content-header-title mb-0 d-inline-block" style="color: #ffffff"> <h3 class="content-header-title mb-0 d-inline-block" style="color: #242222">
{{ breadcrumb.mainlabel }} {{ breadcrumb.mainlabel }}
</h3> </h3>
<div class="row breadcrumbs-top d-inline-block"> <div class="row breadcrumbs-top d-inline-block">
<div class="breadcrumb-wrapper col-12"> <div class="breadcrumb-wrapper col-12">
<ol class="breadcrumb"> <ol class="breadcrumb">
<ng-container *ngFor="let link of breadcrumb.links; let last = last"> <ng-container *ngFor="let link of breadcrumb.links; let last = last">
<li class="breadcrumb-item" style="color: #ffffff"> <li class="breadcrumb-item" style="color: #242222">
<ng-container *ngIf="link.isLink; else notLink"> <ng-container *ngIf="link.isLink; else notLink">
<a routerLink="{{ link.link }}" style="color: #ffffff">{{ link.name }}</a> <a routerLink="{{ link.link }}" style="color: #242222">{{ link.name }}</a>
</ng-container> </ng-container>
<ng-template #notLink> <ng-template #notLink>
<span style="color: #ffffff">{{ link.name }}</span> <span style="color: #242222">{{ link.name }}</span>
</ng-template> </ng-template>
<span *ngIf="!last" class="breadcrumb-arrow" style="color: #ffffff; margin: 0 5px;"> <span *ngIf="!last" class="breadcrumb-arrow" style="color: #242222; margin: 0 5px;">
<i class="feather ft-chevron-right"></i> <i class="feather ft-chevron-right"></i>
</span> </span>
</li> </li>

View File

@@ -2,18 +2,18 @@
id="footer" id="footer"
class="footer footer-static footer-light navbar-border navbar-shadow" class="footer footer-static footer-light navbar-border navbar-shadow"
*ngIf="showFooter" *ngIf="showFooter"
style="background-color: #000000 !important; border: none !important;" style="border: none !important;"
> >
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2" style="background-color: #000000 !important;"> <p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2">
<span class="float-md-ceter d-block d-md-inline-block" style="background-color: #000000 !important;" <span class="float-md-ceter d-block d-md-inline-block"
>Copyright &copy; 2024 >Copyright &copy; 2024
<a <a
[routerLink]="" [routerLink]=""
class="text-bold-800 grey darken-2" class="text-bold-800 grey darken-2"
href="https://allbestsistem.com/" href="https://allbestsistem.com/"
target="_blank" target="_blank"
style="background-color: #000000 !important;" style="background-color: #ffffff !important;"
>Smart Building Management Systems (V@2024-07-11.01) >Smart Building Management Systems (V@2024-08-28.1)
</a></span </a></span
> >
</p> </p>

View File

@@ -1,7 +1,6 @@
<nav <nav
class="header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow fixed-top navbar-shadow" class="header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow fixed-top navbar-shadow"
[ngClass]="selectedHeaderNavBarClass" [ngClass]="selectedHeaderNavBarClass"
style="background-color: #000000 !important"
> >
<div class="navbar-wrapper"> <div class="navbar-wrapper">
<div <div
@@ -10,7 +9,7 @@
[ngClass]="selectedNavBarHeaderClass" [ngClass]="selectedNavBarHeaderClass"
(mouseenter)="mouseEnter($event)" (mouseenter)="mouseEnter($event)"
(mouseleave)="mouseLeave($event)" (mouseleave)="mouseLeave($event)"
style="background-color: #252525 !important" style="background-color: #fbfbfb !important"
> >
<ul class="nav navbar-nav flex-row"> <ul class="nav navbar-nav flex-row">
<!-- Remove position relative in responsive --> <!-- Remove position relative in responsive -->
@@ -24,9 +23,9 @@
</li> </li>
<li class="nav-item mr-auto"> <li class="nav-item mr-auto">
<a <a
[routerLink]="['/dashboard/sales']" [routerLink]="['/monitoring']"
class="navbar-brand" class="navbar-brand"
routerLink="/dashboard/sales" routerLink="/monitoring"
> >
<img <img
class="brand-logo" class="brand-logo"
@@ -43,7 +42,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
" "
> >
<h3 class="brand-text" style="color: #ffffff; margin: 0"> <h3 class="brand-text" style="color: #242222; margin: 0">
Smart Building Smart Building
</h3> </h3>
</div> </div>
@@ -54,6 +53,7 @@
[routerLink]="" [routerLink]=""
class="nav-link modern-nav-toggle pr-0" class="nav-link modern-nav-toggle pr-0"
data-toggle="collapse" data-toggle="collapse"
(click)="toggleFixMenu($event)" (click)="toggleFixMenu($event)"
> >
<i <i
@@ -119,7 +119,7 @@
<span class="badge badge-pill badge-danger badge-up badge-glow">5</span> <span class="badge badge-pill badge-danger badge-up badge-glow">5</span>
</a> --> </a> -->
<a class="nav-link nav-link-label"> <a class="nav-link nav-link-label">
<i class="ficon la la-bell" style="color: #bef264"></i> <i class="ficon la la-bell" style="color: #242424"></i>
<!-- <span class="badge badge-pill badge-danger badge-up badge-glow">5</span> --> <!-- <span class="badge badge-pill badge-danger badge-up badge-glow">5</span> -->
</a> </a>
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu> <ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
@@ -321,7 +321,7 @@
<span <span
*ngIf="currentUser.displayName" *ngIf="currentUser.displayName"
class="mr-1 user-name text-bold-700" class="mr-1 user-name text-bold-700"
style="color: #ffffff" style="color: #242222"
>{{ currentUser.displayName }}</span >{{ currentUser.displayName }}</span
> >
<span <span

View File

@@ -1,8 +1,8 @@
<div (mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)" id="main-menu" <div (mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)" id="main-menu"
class="main-menu menu-fixed menu-dark menu-accordion menu-shadow" data-scroll-to-active="true" style="background-color: #252525 !important;"> class="main-menu menu-fixed menu-dark menu-accordion menu-shadow" data-scroll-to-active="true" style="background-color: #fbfbfb !important; box-shadow: none !important; border-right: 3px solid #f4f4f4;">
<div id="main-menu-content" class="main-menu-content ps-container ps-theme-light" fxFlex="auto" <div id="main-menu-content" class="main-menu-content ps-container ps-theme-light" fxFlex="auto"
[perfectScrollbar]="config" > [perfectScrollbar]="config" >
<ul class="navigation navigation-main" id="main-menu-navigation" data-menu="menu-navigation" style="background-color: #252525 !important;"> <ul class="navigation navigation-main" id="main-menu-navigation" data-menu="menu-navigation" style="background-color: #fbfbfb !important;">
<!-- Menu --> <!-- Menu -->
{{child?child.title:''}} {{child?child.title:''}}
<li *ngFor="let child of _menuSettingsConfig.vertical_menu.items" class="" [ngClass]="{ <li *ngFor="let child of _menuSettingsConfig.vertical_menu.items" class="" [ngClass]="{
@@ -17,16 +17,16 @@
<!-- Section --> <!-- Section -->
<span class="menu-title" *ngIf="child.section">{{child.section}}</span> <span class="menu-title" *ngIf="child.section">{{child.section}}</span>
<i class="la" *ngIf="child.section" [ngClass]="child.icon" data-toggle="tooltip" data-placement="right" <i class="la" *ngIf="child.section" [ngClass]="child.icon" data-toggle="tooltip" data-placement="right"
data-original-title="Support"></i> data-original-title="Support" style="color: #242222;"></i>
<!-- Root Menu --> <!-- Root Menu -->
<a *ngIf="child.title && !child.submenu && !child.excludeInVertical && !child.isExternalLink && !child.issupportExternalLink && !child.isStarterkitExternalLink" <a *ngIf="child.title && !child.submenu && !child.excludeInVertical && !child.isExternalLink && !child.issupportExternalLink && !child.isStarterkitExternalLink"
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)" routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)"
style="background-color: #252525 !important;"> style="background-color: #fbfbfb !important;">
<i class="la" [ngClass]="child.icon"></i> <i class="la" [ngClass]="child.icon" style="color: #242222;"></i>
<span class="menu-title" data-i18n="">{{child.title}}</span> <span class="menu-title" data-i18n="" style="color: #242222;">{{child.title}}</span>
<span *ngIf="child.badge" class="badge badge-pill float-right" <span *ngIf="child.badge" class="badge badge-pill float-right"
[ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}"> [ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}" style="color: #242222;">
{{child.badge.value}} {{child.badge.value}}
</span> </span>
</a> </a>
@@ -53,15 +53,15 @@
<!-- Submenu --> <!-- Submenu -->
<a *ngIf="child.title && child.submenu && !child.excludeInVertical" <a *ngIf="child.title && child.submenu && !child.excludeInVertical"
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)" style="background-color: #252525 !important;"> routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)" style="background-color: #fbfbfb !important;">
<i class="la" [ngClass]="child.icon"></i> <i class="la" [ngClass]="child.icon" style="color: #242222;"></i>
<span class="menu-title" data-i18n="">{{child.title}}</span> <span class="menu-title" data-i18n="" style="color: #242222;">{{child.title}}</span>
<span *ngIf="child.badge" class="badge badge-pill float-right" <span *ngIf="child.badge" class="badge badge-pill float-right"
[ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}"> [ngClass]="{'badge-info mr-2': child.badge.type==='badge-info' , 'badge-danger':child.badge.type==='badge-danger'}" style="color: #242222;">
{{child.badge.value}} {{child.badge.value}}
</span> </span>
</a> </a>
<ul *ngIf="child.submenu" class="menu-content" [@popOverState]="child.isOpen" style="background-color: #252525 !important;"> <ul *ngIf="child.submenu" class="menu-content" [@popOverState]="child.isOpen" style="background-color: #fbfbfb !important;">
<!-- Submenu of Submenu --> <!-- Submenu of Submenu -->
<li *ngFor="let subchild of child.submenu.items" class="isShown" <li *ngFor="let subchild of child.submenu.items" class="isShown"
[ngClass]="{'has-sub':(subchild.submenu),'active': subchild.isSelected && !subchild.submenu, 'open': subchild.isOpen && subchild.submenu}"> [ngClass]="{'has-sub':(subchild.submenu),'active': subchild.isSelected && !subchild.submenu, 'open': subchild.isOpen && subchild.submenu}">
@@ -69,7 +69,7 @@
(click)="toggleMenu($event, subchild, true)" (click)="toggleMenu($event, subchild, true)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}" routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}"
[ngClass]="{'active': subchild.isSelected}" [ngClass]="{'active': subchild.isSelected}"
style="background-color: #252525 !important;">{{subchild.title}}</a> style="background-color: #fbfbfb !important; color: #242222;">{{subchild.title}}</a>
<a class="menu-item" *ngIf="subchild.submenu && !subchild.excludeInVertical" (click)="toggleMenu($event, subchild, true)" <a class="menu-item" *ngIf="subchild.submenu && !subchild.excludeInVertical" (click)="toggleMenu($event, subchild, true)"
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}">{{subchild.title}}</a> routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}">{{subchild.title}}</a>
<ul *ngIf="subchild.submenu && !subchild.excludeInVertical" class="menu-content"> <ul *ngIf="subchild.submenu && !subchild.excludeInVertical" class="menu-content">

View File

@@ -1018,10 +1018,7 @@ export const MenuSettingsConfig: MenuConfig = {
page: "null", page: "null",
submenu: { submenu: {
items: [ items: [
// {
// title: "Monitoring List",
// page: "/list-monitoring",
// },
{ {
title: "Master Category", title: "Master Category",
page: "/master/master-category", page: "/master/master-category",
@@ -1062,6 +1059,10 @@ export const MenuSettingsConfig: MenuConfig = {
title: "Master Building", title: "Master Building",
page: "/master/master-building", page: "/master/master-building",
}, },
{
title: "Master Monitoring List",
page: "/list-monitoring",
},
], ],
}, },
}, },

View File

@@ -208,4 +208,73 @@ export class TableexcelService {
}); });
this.saveAsExcelFile(excelBuffer, excelFileName); this.saveAsExcelFile(excelBuffer, excelFileName);
} }
public exportAsExcelFileMonitoringDetail(
json: any[],
excelFileName: string,
columns: string[],
mode: any
): void {
const filteredJson = json.map((item) => {
const filteredItem = {};
columns.forEach((column) => {
filteredItem[column] = item[column];
});
return filteredItem;
});
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(filteredJson);
let columnWidths = [];
if (mode === "building") {
columnWidths = [
{ wch: 30 },
{ wch: 40 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
];
} else if (mode === "floor") {
columnWidths = [
{ wch: 40 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
];
} else if (mode === "room") {
columnWidths = [{ wch: 30 }, { wch: 30 }, { wch: 30 }, { wch: 30 }];
}
worksheet["!cols"] = columnWidths;
let header = [];
if (mode === "building") {
header = [
"Floor",
"Room",
"Device",
"Duration",
"Price Kwh",
"Estimation Cost",
];
} else if (mode === "floor") {
header = ["Room", "Device", "Duration", "Price Kwh", "Estimation Cost"];
} else if (mode === "room") {
header = ["Device", "Duration", "Price Kwh", "Estimation Cost"];
}
XLSX.utils.sheet_add_aoa(worksheet, [header]);
const workbook: XLSX.WorkBook = {
Sheets: { data: worksheet },
SheetNames: ["data"],
};
const excelBuffer: any = XLSX.write(workbook, {
bookType: "xlsx",
type: "array",
});
this.saveAsExcelFile(excelBuffer, excelFileName);
}
} }

View File

@@ -1,4 +1,4 @@
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; /* color: #ffffff !important; */
background-color: #252525 !important; /* background-color: #252525 !important; */
} }

View File

@@ -31,6 +31,5 @@ export class SelectIconComponent {
} else { } else {
this.iconSelected.emit(undefined); this.iconSelected.emit(undefined);
} }
} }
} }

View File

@@ -364,19 +364,21 @@ input[type="month"]::-webkit-calendar-picker-indicator {
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -404,21 +406,38 @@ input[type="month"]::-webkit-calendar-picker-indicator {
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important; height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.modal-open .content { .text-custom-label{
filter: blur(5px); color: #242222 !important;
transition: filter 0.3s ease-in-out; font-family: "Open Sans", sans-serif !important;
font-size: 16px;
} }
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,21 +7,20 @@
<section> <section>
<div class="row"> <div class="row">
<div class="col-12 col-sm-6 col-md-6 col-lg-6"> <div class="col-12 col-sm-6 col-md-6 col-lg-6">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #DDE1E6 !important">
<div <div
class="card-header" class="card-header"
style="background-color: #252525 !important" style="background-color: #DDE1E6 !important"
> >
<h4 <h4
class="card-title text-center" class="card-title text-center text-custom-label"
style="color: #ffffff !important"
> >
Comparison of Previous Month Costs Comparison of Previous Month Costs
</h4> </h4>
<hr <hr
style=" style="
border-top: 4px solid #ffffff; border-top: 4px solid #242222;
border-color: #ffffff !important; border-color: #242222 !important;
" "
/> />
</div> </div>
@@ -36,21 +35,20 @@
</div> </div>
</div> </div>
<div class="col-12 col-sm-6 col-md-6 col-lg-6"> <div class="col-12 col-sm-6 col-md-6 col-lg-6">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #DDE1E6 !important">
<div <div
class="card-header" class="card-header"
style="background-color: #252525 !important" style="background-color: #DDE1E6 !important"
> >
<h4 <h4
class="card-title text-center" class="card-title text-center text-custom-label"
style="color: #ffffff !important"
> >
Comparison of Actual Costs and Estimated Costs Comparison of Actual Costs and Estimated Costs
</h4> </h4>
<hr <hr
style=" style="
border-top: 4px solid #ffffff; border-top: 4px solid #242222;
border-color: #ffffff !important; border-color: #242222 !important;
" "
/> />
</div> </div>
@@ -67,7 +65,7 @@
</div> </div>
</section> </section>
<section id="configuration"> <section id="configuration">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
@@ -115,8 +113,9 @@
class="btn btn-outline-success" class="btn btn-outline-success"
(click)="doFilter()" (click)="doFilter()"
style=" style="
background-color: #252525 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #ffffff;
" "
[disabled]="spinnerFilterActive" [disabled]="spinnerFilterActive"
> >
@@ -148,13 +147,13 @@
/> />
<div <div
class="input-group-append" class="input-group-append"
style="background-color: #252525 !important" style="background-color: #FBFBFB !important"
> >
<span <span
class="input-group-text" class="input-group-text"
style=" style="
background-color: #252525 !important; background-color: #FBFBFB !important;
color: #ffffff; color: #242222;
height: 40px !important; height: 40px !important;
" "
>Kwh</span >Kwh</span
@@ -177,13 +176,13 @@
/> />
<div <div
class="input-group-append" class="input-group-append"
style="background-color: #252525 !important" style="background-color: #FBFBFB !important"
> >
<span <span
class="input-group-text" class="input-group-text"
style=" style="
background-color: #252525 !important; background-color: #FBFBFB !important;
color: #ffffff; color: #242222;
height: 40px !important; height: 40px !important;
" "
>IDR</span >IDR</span
@@ -199,9 +198,9 @@
class="btn btn-secondary mr-2" class="btn btn-secondary mr-2"
style=" style="
width: 100%; width: 100%;
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
(click)="export()" (click)="export()"
[disabled]="spinnerExportActive" [disabled]="spinnerExportActive"
@@ -218,9 +217,9 @@
class="btn btn-secondary mr-2" class="btn btn-secondary mr-2"
style=" style="
width: 100%; width: 100%;
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
(click)="syncData()" (click)="syncData()"
[disabled]="spinnerActive" [disabled]="spinnerActive"
@@ -236,9 +235,9 @@
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
width: 100%; width: 100%;
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
(click)="addFieldValue()" (click)="addFieldValue()"
> >
@@ -252,7 +251,7 @@
<div class="card-dashboard"> <div class="card-dashboard">
<ngx-datatable <ngx-datatable
class="bootstrap table-bordered" class="bootstrap table-bordered"
[limit]="5" [limit]="10"
[rows]="data_cost" [rows]="data_cost"
[columnMode]="'force'" [columnMode]="'force'"
[headerHeight]="50" [headerHeight]="50"
@@ -270,7 +269,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ rowIndex + 1 }} {{ rowIndex + 1 }}
</p> </p>
</ng-template> </ng-template>
@@ -281,10 +280,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Building</span> <span class="style-custom-label">Building</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -293,10 +292,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Category</span> <span class="style-custom-label">Category</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -305,10 +304,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Room</span> <span class="style-custom-label">Room</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -317,12 +316,12 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important" <span class="style-custom-label"
>Estimation Cost</span >Estimation Cost</span
> >
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ {{
value.toLocaleString("id-ID", { value.toLocaleString("id-ID", {
style: "currency", style: "currency",
@@ -338,10 +337,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Total Kwh</span> <span class="style-custom-label">Total Kwh</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
kWh kWh
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -351,10 +350,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Tanggal</span> <span class="style-custom-label">Tanggal</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ value | date : "MM/yyyy" }} {{ value | date : "MM/yyyy" }}
</p> </p>
</ng-template> </ng-template>
@@ -365,10 +364,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template ngx-datatable-cell-template let-value="value"> <ng-template ngx-datatable-cell-template let-value="value">
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ value === 2 ? "Aktif" : "Tidak Aktif" }} {{ value === 2 ? "Aktif" : "Tidak Aktif" }}
</p> </p>
</ng-template> </ng-template>
@@ -379,7 +378,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -389,14 +388,14 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; background-color: #DDE1E6 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
" "
(click)="viewRow(row)" (click)="viewRow(row)"
> >
<i <i
class="ficon ri-export-line" class="ficon ri-export-line"
style="color: #bef264 !important" style="color: #37A647 !important"
></i> ></i>
</button> </button>
</ng-template> </ng-template>

View File

@@ -54,7 +54,8 @@ export class CostManagementComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Cost Management", mainlabel: "Cost Management",
links: [ links: [
@@ -91,7 +92,9 @@ export class CostManagementComponent implements OnInit {
.subscribe((response) => { .subscribe((response) => {
this.data = response.results.data; this.data = response.results.data;
this.filteredRows = this.data; this.filteredRows = this.data;
this.kwhTerm = response.results.kwh; let kwhData = parseFloat(response.results.kwh);
this.kwhTerm = kwhData.toFixed(1);
this.costTerm = response.results.cost; this.costTerm = response.results.cost;
this.data_cost = this.filteredRows.map((item) => ({ this.data_cost = this.filteredRows.map((item) => ({
@@ -99,7 +102,7 @@ export class CostManagementComponent implements OnInit {
roomName: item.room_name, roomName: item.room_name,
categoryName: item.category_name, categoryName: item.category_name,
estimationCost: item.estimation_cost, estimationCost: item.estimation_cost,
totalUse: item.total_use, totalUse: item.total_use.toFixed(1),
endDate: this.convertToUTC7(item.end_date), endDate: this.convertToUTC7(item.end_date),
// endDate: item.end_date, // endDate: item.end_date,
statusId: item.status_id, statusId: item.status_id,
@@ -132,7 +135,9 @@ export class CostManagementComponent implements OnInit {
dataListBuilding() { dataListBuilding() {
this.monitoringApiService.getBuildingList().subscribe((data) => { this.monitoringApiService.getBuildingList().subscribe((data) => {
this.dataBuildingList = data.data.filter((item) => item.statusId === 2); this.dataBuildingList = data.data.filter(
(item) => item.statusName.toLowerCase() === "aktif"
);
}); });
} }
@@ -140,88 +145,90 @@ export class CostManagementComponent implements OnInit {
this.costService.getCompPrevMonthCost(buildingId).subscribe((data) => { this.costService.getCompPrevMonthCost(buildingId).subscribe((data) => {
this.dataCompPrev = data.data; this.dataCompPrev = data.data;
this.chartOption = { this.chartOption = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
formatter: function (params) {
var tar = params[1];
return tar.name + "<br/>" + tar.seriesName + " : " + tar.value;
},
},
grid: { grid: {
left: "25%", left: "25%",
right: "25%", right: "25%",
top: "20%", top: "20%",
bottom: "20%", bottom: "20%",
}, },
color: ["#37A647"],
// Add tooltip xAxis: {
tooltip: { type: "category",
trigger: "axis", splitLine: { show: false },
enterable: false, data: [this.dataCompPrev[0].name, this.dataCompPrev[1].name],
formatter: function (params) { axisLine: {
return `${params[0].name}<br/>${ show: true,
params[0].seriesName lineStyle: {
}: Rp. ${params[0].value.toLocaleString()}`; color: "#37A647",
width: 7,
},
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
}, },
}, },
// Add legend yAxis: {
legend: false, type: "value",
axisLine: {
// Add custom colors show: false,
color: ["#BEF264"],
// Horizontal axis
xAxis: [
{
type: "category",
data: [this.dataCompPrev[0].name, this.dataCompPrev[1].name],
axisLine: {
show: true,
lineStyle: {
color: "#BEF264",
width: 4,
},
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
}, },
], axisTick: {
show: false,
// Vertical axis
yAxis: [
{
type: "value",
axisLine: {
show: false,
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
}, },
], splitLine: {
show: false,
},
axisLabel: {
show: false,
},
},
// Add series
series: [ series: [
// {
// name: "Placeholder",
// type: "bar",
// stack: "Total",
// itemStyle: {
// borderColor: "transparent",
// color: "transparent",
// },
// emphasis: {
// itemStyle: {
// borderColor: "transparent",
// color: "transparent",
// },
// },
// data: [1000, 1000],
// },
{ {
name: "Cost", name: "Cost",
type: "bar", type: "bar",
data: [this.dataCompPrev[0].rupiah, this.dataCompPrev[1].rupiah], stack: "Total",
label: { label: {
show: true, show: true,
position: "top", position: "top",
color: "#ffffff", color: "#242222",
formatter: function (params) { formatter: function (params) {
return `Rp. ${params.value.toLocaleString()}`; return `Rp. ${params.value.toLocaleString()}`;
}, },
}, },
barWidth: "50%", // barWidth: "50%",
data: [this.dataCompPrev[0].rupiah, this.dataCompPrev[1].rupiah],
}, },
], ],
}; };
@@ -232,88 +239,90 @@ export class CostManagementComponent implements OnInit {
this.costService.getCompActEstCost(buildingId).subscribe((data) => { this.costService.getCompActEstCost(buildingId).subscribe((data) => {
this.dataCompAct = data.data[0]; this.dataCompAct = data.data[0];
this.chartOption2 = { this.chartOption2 = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
formatter: function (params) {
var tar = params[1];
return tar.name + "<br/>" + tar.seriesName + " : " + tar.value;
},
},
grid: { grid: {
left: "25%", left: "25%",
right: "25%", right: "25%",
top: "20%", top: "20%",
bottom: "20%", bottom: "20%",
}, },
color: ["#37A647"],
// Add tooltip xAxis: {
tooltip: { type: "category",
trigger: "axis", splitLine: { show: false },
enterable: false, data: ["Estimation Cost", "Actual Cost"],
formatter: function (params) { axisLine: {
return `${params[0].name}<br/>${ show: true,
params[0].seriesName lineStyle: {
}: Rp. ${params[0].value.toLocaleString()}`; color: "#37A647",
width: 7,
},
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
}, },
}, },
// Add legend yAxis: {
legend: false, type: "value",
axisLine: {
// Add custom colors show: false,
color: ["#BEF264"],
// Horizontal axis
xAxis: [
{
type: "category",
data: ["Estimation Cost", "Actual Cost"],
axisLine: {
show: true,
lineStyle: {
color: "#BEF264",
width: 4,
},
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
}, },
], axisTick: {
show: false,
// Vertical axis
yAxis: [
{
type: "value",
axisLine: {
show: false,
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
}, },
], splitLine: {
show: false,
},
axisLabel: {
show: false,
},
},
// Add series
series: [ series: [
// {
// name: "Placeholder",
// type: "bar",
// stack: "Total",
// itemStyle: {
// borderColor: "transparent",
// color: "transparent",
// },
// emphasis: {
// itemStyle: {
// borderColor: "transparent",
// color: "transparent",
// },
// },
// data: [2500, 2500],
// },
{ {
name: "Cost", name: "Cost",
type: "bar", type: "bar",
data: [this.dataCompAct.est_cost, this.dataCompAct.real_cost], stack: "Total",
label: { label: {
show: true, show: true,
position: "top", position: "top",
color: "#ffffff", color: "#242222",
formatter: function (params) { formatter: function (params) {
return `Rp. ${params.value.toLocaleString()}`; return `Rp. ${params.value.toLocaleString()}`;
}, },
}, },
barWidth: "50%", // Adjust bar width // barWidth: "50%",
data: [this.dataCompAct.est_cost, this.dataCompAct.real_cost],
}, },
], ],
}; };

View File

@@ -1,20 +1,20 @@
<div class="modal-body" style="background-color: #252525 !important"> <div class="modal-body" style="background-color: #FBFBFB !important">
<h4 style="color: #ffffff">Input the actual cost of your expenses</h4> <h4 style="color: #242222">Input the actual cost of your expenses</h4>
<p style="color: #ffffff">Building : {{ buildingName }}</p> <p style="color: #242222">Building : {{ buildingName }}</p>
<p style="color: #ffffff">Periode : {{ formattedDate }}</p> <p style="color: #242222">Periode : {{ formattedDate }}</p>
<form [formGroup]="myForm"> <form [formGroup]="myForm">
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">
<div <div
class="input-group-prepend" class="input-group-prepend"
style="background-color: #252525 !important" style="background-color: #FBFBFB !important"
> >
<span <span
class="input-group-text" class="input-group-text"
id="basic-addon1" id="basic-addon1"
style=" style="
background-color: #252525 !important; background-color: #FBFBFB !important;
color: #ffffff; color: #242222;
height: calc(1.5em + 0.75rem + 2px) !important; height: calc(1.5em + 0.75rem + 2px) !important;
" "
>Rp</span >Rp</span
@@ -34,15 +34,15 @@
</div> </div>
</form> </form>
</div> </div>
<div class="modal-footer justify-content-between" style="background-color: #252525 !important; border-style: none !important;"> <div class="modal-footer justify-content-between" style="background-color: #FBFBFB !important; border-style: none !important;">
<button <button
type="button" type="button"
class="btn btn-secondary" class="btn"
style=" style="
color: #c3f164; color: #242222;
width: 25%; width: 25%;
background-color: #252525 !important; background-color: #FBFBFB !important;
border-color: #c3f164 !important; border-color: #FBFBFB !important;
border-radius: 10px; border-radius: 10px;
" "
(click)="activeModal.dismiss('Cross click')" (click)="activeModal.dismiss('Cross click')"
@@ -51,12 +51,12 @@
</button> </button>
<button <button
type="button" type="button"
class="btn btn-primary" class="btn"
style=" style="
color: #252525 !important; color: #242222 !important;
width: 25%; width: 25%;
background-color: #c3f164 !important; background-color: #DDE1E6 !important;
border-color: #c3f164 !important; border-color: #DDE1E6 !important;
border-radius: 10px; border-radius: 10px;
" "
(click)="addRow()" (click)="addRow()"

View File

@@ -30,7 +30,8 @@ export class ModalAddActualComponent {
} }
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
const currentDate = new Date(); const currentDate = new Date();
this.dateCurrent = currentDate.toISOString().slice(0, 7); this.dateCurrent = currentDate.toISOString().slice(0, 7);
this.dateFormat(); this.dateFormat();

View File

@@ -367,13 +367,15 @@ input[type="month"]::-webkit-calendar-picker-indicator {
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -401,17 +403,40 @@ input[type="month"]::-webkit-calendar-picker-indicator {
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important; height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
}
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
} }
::ng-deep .modal-backdrop.show { ::ng-deep .modal-backdrop.show {

View File

@@ -1,9 +1,9 @@
<div class="modal-body" style="background-color: #5b5b5b !important"> <div class="modal-body" style="background-color: #FBFBFB !important">
<h4 style="color: #ffffff; margin-bottom: 20px !important"> <h4 style="color: #242222; margin-bottom: 20px !important">
Comparison of Water and Electricity Costs > {{ dataRow.building }} Comparison of Water and Electricity Costs > {{ dataRow.building }}
</h4> </h4>
<p style="color: #ffffff">Room : {{ dataRow?.roomName }}</p> <p style="color: #242222">Room : {{ dataRow?.roomName }}</p>
<p style="color: #ffffff">Category : {{ dataRow?.categoryName }}</p> <p style="color: #242222">Category : {{ dataRow?.categoryName }}</p>
<div class="card-dashboard"> <div class="card-dashboard">
<ngx-datatable <ngx-datatable
@@ -19,43 +19,43 @@
> >
<ngx-datatable-column name="#" [flexGrow]="0.5" [minWidth]="30"> <ngx-datatable-column name="#" [flexGrow]="0.5" [minWidth]="30">
<ng-template ngx-datatable-cell-template let-rowIndex="rowIndex"> <ng-template ngx-datatable-cell-template let-rowIndex="rowIndex">
<p style="color: #ffffff !important"> <p style="color: #242222 !important">
{{ rowIndex + 1 }} {{ rowIndex + 1 }}
</p> </p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="periode" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="periode" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Tanggal</span> <span style="color: #242222 !important">Tanggal</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important"> <p style="color: #242222 !important">
{{ value | date : "dd/MM/yyyy" }} {{ value | date : "dd/MM/yyyy" }}
</p> </p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="deviceName" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="deviceName" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Device</span> <span style="color: #242222 !important">Device</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p style="color: #242222 !important">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="roomName" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="roomName" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Room</span> <span style="color: #242222 !important">Room</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p style="color: #242222 !important">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="categoryName" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="categoryName" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Category</span> <span style="color: #242222 !important">Category</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p style="color: #242222 !important">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -64,10 +64,10 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Estimation Cost</span> <span style="color: #242222 !important">Estimation Cost</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important"> <p style="color: #242222 !important">
{{ {{
value.toLocaleString("id-ID", { value.toLocaleString("id-ID", {
style: "currency", style: "currency",
@@ -79,34 +79,34 @@
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="totalKwh" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="totalKwh" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Total Kwh</span> <span style="color: #242222 !important">Total Kwh</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p style="color: #242222 !important">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="watt" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="watt" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Watt</span> <span style="color: #242222 !important">Watt</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p style="color: #242222 !important">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="duration" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="duration" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Duration</span> <span style="color: #242222 !important">Duration</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important">{{ value }}</p> <p style="color: #242222 !important">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column name="priceKwh" [flexGrow]="1" [minWidth]="90"> <ngx-datatable-column name="priceKwh" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Price Kwh</span> <span style="color: #242222 !important">Price Kwh</span>
</ng-template> </ng-template>
<ng-template let-value="value" ngx-datatable-cell-template> <ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #ffffff !important"> <p style="color: #242222 !important">
{{ {{
value.toLocaleString("id-ID", { value.toLocaleString("id-ID", {
style: "currency", style: "currency",
@@ -121,16 +121,16 @@
</div> </div>
<div <div
class="modal-footer justify-content-between" class="modal-footer justify-content-between"
style="background-color: #252525 !important; border-style: none !important" style="background-color: #FBFBFB !important; border-style: none !important"
> >
<button <button
type="button" type="button"
class="btn btn-secondary" class="btn"
style=" style="
color: #c3f164; color: #242222;
width: 25%; width: 25%;
background-color: #252525 !important; background-color: #FBFBFB !important;
border-color: #c3f164 !important; border-color: #242222 !important;
border-radius: 10px; border-radius: 10px;
" "
(click)="activeModal.dismiss('Cross click')" (click)="activeModal.dismiss('Cross click')"
@@ -139,12 +139,12 @@
</button> </button>
<button <button
type="button" type="button"
class="btn btn-primary" class="btn"
style=" style="
color: #252525 !important; color: #242222 !important;
width: 25%; width: 25%;
background-color: #c3f164 !important; background-color: #DDE1E6 !important;
border-color: #c3f164 !important; border-color: #DDE1E6 !important;
border-radius: 10px; border-radius: 10px;
" "
[disabled]="spinnerExportActive" [disabled]="spinnerExportActive"

View File

@@ -30,7 +30,8 @@ export class ModalExportComponent {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
const dateRow = this.convertToUTC7(this.dataRow.endDate) const dateRow = this.convertToUTC7(this.dataRow.endDate)
this.formattedEndDate = dateRow.slice(0, 7); this.formattedEndDate = dateRow.slice(0, 7);
} }

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #fbfbfb !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,13 +7,13 @@
<section id="basic-form-layouts"> <section id="basic-form-layouts">
<div class="row"> <div class="row">
<div class="col-12" *blockUI="'projectInfo'; message: 'Loading'"> <div class="col-12" *blockUI="'projectInfo'; message: 'Loading'">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #fbfbfb !important">
<div class="card-content"> <div class="card-content">
<div <div
class="card-header" class="card-header"
style="background-color: #252525 !important" style="background-color: #fbfbfb !important"
> >
<h2 style="color: #ffffff"> <h2 style="color: #242222">
{{ {{
isEditMode() isEditMode()
? "Edit Device" ? "Edit Device"
@@ -29,14 +29,14 @@
(ngSubmit)="onProjectInfoSubmit()" (ngSubmit)="onProjectInfoSubmit()"
> >
<div class="form-body"> <div class="form-body">
<h4 class="form-section" style="color: #ffffff"> <h4 class="form-section" style="color: #242222">
<i class="feather ft-user" style="color: #ffffff"></i> <i class="feather ft-user" style="color: #242222"></i>
General Information General Information
</h4> </h4>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="name" style="color: #ffffff" <label for="name" style="color: #242222"
>Device Name *</label >Device Name *</label
> >
<input <input
@@ -63,13 +63,13 @@
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="categoryId" style="color: #ffffff" <label for="categoryId" style="color: #242222"
>Category *</label >Category *</label
> >
<div class="input-group"> <div class="input-group">
<select <select
id="categoryId" id="categoryId"
class="form-control" class="form-control custom-select"
formControlName="categoryId" formControlName="categoryId"
[ngClass]="{ [ngClass]="{
'is-invalid': submitted && f.categoryId.errors 'is-invalid': submitted && f.categoryId.errors
@@ -83,26 +83,28 @@
</option> </option>
</select> </select>
</div> </div>
<small <div
class="form-text text-muted danger" *ngIf="
*ngIf="submitted && f.categoryId.errors" projectInfo.get('categoryId').invalid &&
class="invalid-feedback" projectInfo.get('categoryId').touched
"
class="text-danger"
> >
<div *ngIf="f.categoryId.errors.required"> <small class="text-danger"
Category is required >Category is required.</small
</div> >
</small> </div>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="voltageId" style="color: #ffffff" <label for="voltageId" style="color: #242222"
>Voltage *</label >Voltage *</label
> >
<div class="input-group"> <div class="input-group">
<select <select
id="voltageId" id="voltageId"
class="form-control" class="form-control custom-select"
formControlName="voltageId" formControlName="voltageId"
[ngClass]="{ [ngClass]="{
'is-invalid': submitted && f.voltageId.errors 'is-invalid': submitted && f.voltageId.errors
@@ -116,25 +118,27 @@
</option> </option>
</select> </select>
</div> </div>
<small <div
class="form-text text-muted danger" *ngIf="
*ngIf="submitted && f.voltageId.errors" projectInfo.get('voltageId').invalid &&
class="invalid-feedback" projectInfo.get('voltageId').touched
"
class="text-danger"
> >
<div *ngIf="f.voltageId.errors.required"> <small class="text-danger"
Voltage is required >Voltage is required.</small
</div> >
</small> </div>
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="typeId" style="color: #ffffff" <label for="typeId" style="color: #242222"
>Type *</label >Type *</label
> >
<select <select
id="typeId" id="typeId"
class="form-control" class="form-control custom-select"
formControlName="typeId" formControlName="typeId"
[ngClass]="{ [ngClass]="{
'is-invalid': submitted && f.typeId.errors 'is-invalid': submitted && f.typeId.errors
@@ -160,12 +164,12 @@
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="durationId" style="color: #ffffff" <label for="durationId" style="color: #242222"
>Duration Use *</label >Duration Use *</label
> >
<select <select
id="durationId" id="durationId"
class="form-control" class="form-control custom-select"
formControlName="durationId" formControlName="durationId"
[ngClass]="{ [ngClass]="{
'is-invalid': submitted && f.durationId.errors 'is-invalid': submitted && f.durationId.errors
@@ -191,12 +195,12 @@
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="roomBuildingId" style="color: #ffffff" <label for="roomBuildingId" style="color: #242222"
>Location Room *</label >Location Room *</label
> >
<select <select
id="roomBuildingId" id="roomBuildingId"
class="form-control" class="form-control custom-select"
formControlName="roomBuildingId" formControlName="roomBuildingId"
[ngClass]="{ [ngClass]="{
'is-invalid': 'is-invalid':
@@ -223,7 +227,7 @@
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="watt" style="color: #ffffff" <label for="watt" style="color: #242222"
>Watt *</label >Watt *</label
> >
<input <input
@@ -237,15 +241,15 @@
'is-invalid': submitted && f.watt.errors 'is-invalid': submitted && f.watt.errors
}" }"
/> />
<small <div
class="form-text text-muted danger" *ngIf="
*ngIf="submitted && f.watt.errors" projectInfo.get('watt').invalid &&
class="invalid-feedback" projectInfo.get('watt').touched
"
class="text-danger"
> >
<div *ngIf="f.watt.errors.required"> <small class="text-danger">Please enter a valid Watt.</small>
watt is required </div>
</div>
</small>
</div> </div>
</div> </div>
</div> </div>
@@ -255,21 +259,22 @@
type="button" type="button"
class="btn btn-warning mr-1" class="btn btn-warning mr-1"
style=" style="
color: #c3f164 !important; color: #242222 !important;
background-color: #000000 !important; background-color: #fbfbfb !important;
border-color: #c3f164 !important; border-color: #fbfbfb !important;
" "
(click)="cancel()" (click)="cancel()"
> >
<i class="feather ft-x"></i> <i *ngIf="mode === 'edit'" class="feather ft-x"></i>
<i *ngIf="mode === 'view'" class="la la-arrow-left"></i>
{{ mode === "edit" ? "Cancel" : "Back" }} {{ mode === "edit" ? "Cancel" : "Back" }}
</button> </button>
<button <button
type="submit" type="submit"
class="btn btn-primary" class="btn btn-primary"
style=" style="
color: #000000 !important; color: #ffffff !important;
background-color: #c3f164 !important; background-color: #37a647 !important;
" "
(click)="saveEdit()" (click)="saveEdit()"
*ngIf="mode === 'edit'" *ngIf="mode === 'edit'"

View File

@@ -4,13 +4,14 @@ import { ActivatedRoute, Router } from "@angular/router";
import { BlockUI, NgBlockUI } from "ng-block-ui"; import { BlockUI, NgBlockUI } from "ng-block-ui";
import { BuildingService } from "../../service/monitoring-api.service"; import { BuildingService } from "../../service/monitoring-api.service";
import { LoginService } from "../../service/login.service"; import { LoginService } from "../../service/login.service";
import Swal from "sweetalert2";
@Component({ @Component({
selector: "app-add-edit-device", selector: "app-add-edit-device",
templateUrl: "./add-edit-device.component.html", templateUrl: "./add-edit-device.component.html",
styleUrls: ["./add-edit-device.component.css"], styleUrls: ["./add-edit-device.component.css"],
}) })
export class AddEditDeviceComponent implements OnInit{ export class AddEditDeviceComponent implements OnInit {
@ViewChild("f", { read: true }) userProfileForm: NgForm; @ViewChild("f", { read: true }) userProfileForm: NgForm;
dataMasterCategori: any; dataMasterCategori: any;
dataMasterVoltage: any; dataMasterVoltage: any;
@@ -41,9 +42,10 @@ export class AddEditDeviceComponent implements OnInit{
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.route.params.subscribe(params => { this.authService.startTrackingActivity();
const id = params['id']; this.route.params.subscribe((params) => {
const id = params["id"];
this.deviceId = id; this.deviceId = id;
if (id) { if (id) {
this.loadDevice(id); this.loadDevice(id);
@@ -51,7 +53,7 @@ export class AddEditDeviceComponent implements OnInit{
this.dataListRoomBuilding(); this.dataListRoomBuilding();
} }
}); });
this.setBreadcrumb() this.setBreadcrumb();
this.route.data.subscribe((data) => { this.route.data.subscribe((data) => {
this.mode = data.mode; this.mode = data.mode;
}); });
@@ -63,57 +65,79 @@ export class AddEditDeviceComponent implements OnInit{
typeId: ["", Validators.required], typeId: ["", Validators.required],
durationId: ["", Validators.required], durationId: ["", Validators.required],
roomBuildingId: ["", Validators.required], roomBuildingId: ["", Validators.required],
watt: ["", Validators.required], watt: ["", [Validators.required, Validators.maxLength(15), Validators.pattern(/^[0-9]{1,7}$/)]],
}); });
} }
loadDevice(deviceId: string) { loadDevice(deviceId: string) {
this.monitoringApiService.getDeviceById(deviceId).subscribe(data => { this.monitoringApiService.getDeviceById(deviceId).subscribe((data) => {
this.dataDevice = data; this.dataDevice = data;
this.formGetDevice(data) console.log(this.dataDevice);
this.formGetDevice(data);
}); });
} }
dataListMaster() { dataListMaster() {
this.monitoringApiService.getMasterListData().subscribe(data => { this.monitoringApiService.getMasterListData().subscribe((data) => {
const dataCategory = data.data.find( const dataCategory = data.data.find(
(item) => item.name === "master_category" (item) => item.name === "master_category"
).headerDetailParam; ).headerDetailParam;
this.dataMasterCategori = dataCategory.filter(item => item.statusName.toLowerCase() === "aktif") this.dataMasterCategori = dataCategory.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" ||
item.status.toLowerCase() === "71"
);
const dataVoltage = data.data.find( const dataVoltage = data.data.find(
(item) => item.name === "master_voltage" (item) => item.name === "master_voltage"
).headerDetailParam; ).headerDetailParam;
this.dataMasterVoltage = dataVoltage.filter(item => item.statusName.toLowerCase() === "aktif") this.dataMasterVoltage = dataVoltage.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" ||
item.status.toLowerCase() === "71"
);
const dataType = data.data.find( const dataType = data.data.find(
(item) => item.name === "master_type" (item) => item.name === "master_type"
).headerDetailParam; ).headerDetailParam;
this.dataMasterType = dataType.filter(item => item.statusName.toLowerCase() === "aktif") this.dataMasterType = dataType.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" ||
item.status.toLowerCase() === "71"
);
const dataDuration = data.data.find( const dataDuration = data.data.find(
(item) => item.name === "master_duration" (item) => item.name === "master_duration"
).headerDetailParam; ).headerDetailParam;
this.dataMasterDuration = dataDuration.filter(item => item.statusName.toLowerCase() === "aktif") this.dataMasterDuration = dataDuration.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" ||
item.status.toLowerCase() === "71"
);
const dataStatus = data.data.find( const dataStatus = data.data.find(
(item) => item.name === "master_status" (item) => item.name === "master_status"
).headerDetailParam; ).headerDetailParam;
this.dataMasterStatus = dataStatus.filter(item => item.statusName.toLowerCase() === "aktif") this.dataMasterStatus = dataStatus.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" ||
item.status.toLowerCase() === "71"
);
}); });
} }
dataListRoomBuilding() { dataListRoomBuilding() {
this.monitoringApiService.getBuildingRoomList().subscribe(data => { this.monitoringApiService.getBuildingRoomList().subscribe((data) => {
const newArray = data.results.data.map(item => ({ const newArray = data.results.data.map((item) => ({
id: item.id, id: item.id,
name: `${item.buildingEntity.name} (${item.roomEntity.name})` name: `${item.buildingEntity.name} (${item.roomEntity.name})`,
})); }));
this.dataBuildingRoomList = newArray this.dataBuildingRoomList = newArray;
}); });
} }
formGetDevice(data){ formGetDevice(data) {
this.projectInfo.patchValue({ this.projectInfo.patchValue({
name: data.data.name, name: data.data.name,
categoryId: data.data.categoryId, categoryId: data.data.categoryId,
@@ -121,21 +145,24 @@ export class AddEditDeviceComponent implements OnInit{
typeId: data.data.typeId, typeId: data.data.typeId,
durationId: data.data.durationId, durationId: data.data.durationId,
roomBuildingId: data.data.roomBuildingId, roomBuildingId: data.data.roomBuildingId,
watt: data.data.watt watt: data.data.watt,
}); });
if (this.mode === 'view') { if (this.mode === "view") {
this.formDisable(); this.formDisable();
} }
if (this.projectInfo.get("roomBuildingId").value) {
this.projectInfo.get("roomBuildingId").disable();
}
} }
formDisable(){ formDisable() {
this.projectInfo.get('name').disable() this.projectInfo.get("name").disable();
this.projectInfo.get('categoryId').disable() this.projectInfo.get("categoryId").disable();
this.projectInfo.get('voltageId').disable() this.projectInfo.get("voltageId").disable();
this.projectInfo.get('typeId').disable() this.projectInfo.get("typeId").disable();
this.projectInfo.get('durationId').disable() this.projectInfo.get("durationId").disable();
this.projectInfo.get('roomBuildingId').disable() this.projectInfo.get("roomBuildingId").disable();
this.projectInfo.get('watt').disable() this.projectInfo.get("watt").disable();
} }
setBreadcrumb() { setBreadcrumb() {
@@ -225,11 +252,53 @@ export class AddEditDeviceComponent implements OnInit{
if (event.keyCode !== 8 && !pattern.test(inputChar)) { if (event.keyCode !== 8 && !pattern.test(inputChar)) {
event.preventDefault(); event.preventDefault();
} }
} }
saveEdit() { saveEdit() {
this.monitoringApiService.putDevice(this.projectInfo.value, this.deviceId).subscribe(data => { if (this.projectInfo.valid) {
this.router.navigate(["/device"]); if (this.dataDevice.data.roomBuildingId) {
this.monitoringApiService
.putDevice(this.projectInfo.value, this.deviceId)
.subscribe((data) => {
this.router.navigate(["/device"]);
});
} else {
Swal.fire({
title: "Apakah kamu yakin?",
text: "Data lokasi device tidak dapat diubah!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#37a647",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, save it!",
allowOutsideClick: false,
}).then((result) => {
if (result.isConfirmed) {
this.monitoringApiService
.putDevice(this.projectInfo.value, this.deviceId)
.subscribe((data) => {
this.router.navigate(["/device"]);
});
Swal.fire({
title: "Saved!",
text: "Data berhasil disimpan.",
icon: "success",
});
}
});
}
} else {
this.markFormGroupTouched(this.projectInfo)
}
}
markFormGroupTouched(formGroup: FormGroup) {
(Object as any).values(formGroup.controls).forEach((control) => {
control.markAsTouched();
if (control.controls) {
this.markFormGroupTouched(control);
}
}); });
} }

View File

@@ -0,0 +1,3 @@
::ng-deep .modal-backdrop.show {
z-index: auto !important;
}

View File

@@ -0,0 +1,144 @@
<div class="modal-header" style="background-color: #fbfbfb !important">
<h4 class="modal-title" style="color: #242222">{{ labelModal }}</h4>
<button
type="button"
class="close"
aria-label="Close"
(click)="activeModal.dismiss('Cross click')"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="background-color: #fbfbfb !important">
<form [formGroup]="myForm">
<div class="form-row">
<div class="form-group col-md-12">
<label for="name" style="color: #242222">Name:</label>
<input
type="text"
class="form-control"
id="name"
formControlName="name"
maxlength="50"
/>
<div
*ngIf="myForm.get('name').touched && myForm.get('name').invalid"
class="text-danger"
>
Name is required.
</div>
</div>
<div class="form-group col-md-12">
<label for="timeset" style="color: #242222">Time</label>
<input
type="time"
class="form-control"
formControlName="timeset"
id="timeset"
/>
<div
*ngIf="myForm.get('timeset').touched && myForm.get('timeset').invalid"
class="text-danger"
>
Time On is required.
</div>
</div>
<div class="form-group col-md-12">
<label for="switch" style="color: #242222">Switch:</label>
<select
id="switch"
class="form-control custom-select"
formControlName="switch"
>
<option *ngFor="let data of dataSwitch" [value]="data.value">
{{ data.label }}
</option>
</select>
<div
*ngIf="myForm.get('switch').touched && myForm.get('switch').invalid"
class="text-danger"
>
Switch is required.
</div>
</div>
<!-- Checkbox for Days of the Week -->
<div class="form-group col-md-12">
<label style="color: #242222">Select Days:</label>
<div *ngFor="let day of daysOfWeek">
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
[formControlName]="day.value"
(change)="onDayChange(day.value, $event.target.checked)"
/>
<label class="form-check-label" style="color: #242222">{{
day.label
}}</label>
</div>
</div>
<div *ngIf="myForm.hasError('noDaySelected') && myForm.touched" class="text-danger">
Please select at least one day.
</div>
</div>
<!-- Checkbox for Repeat -->
<div class="form-group col-md-12">
<label style="color: #242222">Repeat:</label>
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
formControlName="recurring"
/>
<label class="form-check-label" style="color: #242222">Yes</label>
</div>
</div>
<!-- <div class="form-group col-md-12">
<label for="active" style="color: #242222">Active:</label>
<select
id="active"
class="form-control custom-select"
formControlName="active"
>
<option *ngFor="let data of dataActive" [value]="data.value">
{{ data.label }}
</option>
</select>
<div
*ngIf="myForm.get('active').touched && myForm.get('active').invalid"
class="text-danger"
>
Active is required.
</div>
</div> -->
</div>
</form>
</div>
<div class="modal-footer" style="background-color: #fbfbfb !important">
<button
type="button"
class="btn btn-secondary"
style="
color: #242222 !important;
background-color: #fbfbfb !important;
border-color: #fbfbfb !important;
"
(click)="activeModal.dismiss('Cross click')"
>
Close
</button>
<button
type="button"
style="color: #ffffff !important; background-color: #37a647 !important"
class="btn btn-primary"
(click)="save()"
>
Save
</button>
</div>

View File

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

View File

@@ -0,0 +1,175 @@
import { Component, Input } from "@angular/core";
import {
FormBuilder,
FormControl,
FormGroup,
Validators,
} from "@angular/forms";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { DeviceService } from "../../service/device.service";
@Component({
selector: "app-control-scheduler",
templateUrl: "./control-scheduler.component.html",
styleUrls: ["./control-scheduler.component.css"],
})
export class ControlSchedulerComponent {
@Input() deviceId: any;
@Input() data: any;
@Input() mode: any;
labelModal: string = "";
myForm: FormGroup;
dataSwitch = [
{
label: "On",
value: true,
},
{
label: "Off",
value: false,
},
];
dataActive = [
{
label: "Active",
value: true,
},
{
label: "Non Active",
value: false,
},
];
daysOfWeek = [
{ label: "Monday", value: "monday" },
{ label: "Tuesday", value: "tuesday" },
{ label: "Wednesday", value: "wednesday" },
{ label: "Thursday", value: "thursday" },
{ label: "Friday", value: "friday" },
{ label: "Saturday", value: "saturday" },
{ label: "Sunday", value: "sunday" },
];
selectedDays: string[] = [];
constructor(
public activeModal: NgbActiveModal,
private fb: FormBuilder,
private deviceService: DeviceService
) {}
ngOnInit() {
this.createForm();
if (this.mode === "add") {
this.labelModal = "Add Scheduler";
} else if (this.mode === "edit") {
this.editForm();
this.labelModal = "Edit Scheduler";
}
}
createForm() {
const controls = {
name: ["", Validators.required],
timeset: ["", Validators.required],
active: [true],
switch: [false],
recurring: [true], // Default value for repeat checkbox
device_id: this.deviceId,
};
// Initialize checkboxes for each day of the week
this.daysOfWeek.forEach((day) => {
controls[day.value] = [false]; // Each day starts as unchecked
});
this.myForm = this.fb.group(controls);
this.myForm.setValidators(this.atLeastOneDaySelectedValidator());
}
editForm() {
this.selectedDays = this.data.days || [];
this.myForm.patchValue({
name: this.data.name,
timeset: this.data.timeset,
recurring: this.data.recurring,
active: this.data.active,
switch: this.data.switch,
});
// Patch the form with the selected days
this.selectedDays.forEach((day) => {
this.myForm.patchValue({
[day]: true,
});
});
}
atLeastOneDaySelectedValidator() {
return (formGroup: FormGroup) => {
const selectedDays = this.daysOfWeek.some(
(day) => formGroup.get(day.value)?.value
);
return selectedDays ? null : { noDaySelected: true };
};
}
onDayChange(day: string, isChecked: boolean) {
if (isChecked) {
this.selectedDays.push(day);
} else {
this.selectedDays = this.selectedDays.filter((d) => d !== day);
}
}
save() {
if (this.myForm.valid) {
const formValues = this.myForm.value;
// Collect selected days' labels
const selectedDays = this.daysOfWeek
.filter((day) => formValues[day.value])
.map((day) => day.value);
// Construct the final output
let result = {};
if (this.mode === "add") {
result = {
name: formValues.name,
device_id: formValues.device_id,
timeset: formValues.timeset,
recurring: formValues.recurring,
active: formValues.active,
switch: formValues.switch,
days: selectedDays,
};
} else {
result = {
id: this.data.id,
name: formValues.name,
device_id: formValues.device_id,
timeset: formValues.timeset,
recurring: formValues.recurring,
active: formValues.active,
switch: formValues.switch,
days: selectedDays,
};
}
this.activeModal.close(result);
} else {
this.markFormGroupTouched(this.myForm);
}
}
markFormGroupTouched(formGroup: FormGroup) {
(Object as any).values(formGroup.controls).forEach((control) => {
control.markAsTouched();
if (control.controls) {
this.markFormGroupTouched(control);
}
});
}
}

View File

@@ -1,15 +1,54 @@
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important; height: 40px !important;
border-radius: 12px !important; /* Menambahkan border-radius */ border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
} }
.background-round { .background-round {
background-color: #252525 !important; background-color: #252525 !important;
padding: 8px; padding: 8px;
border-radius: 50%; border-radius: 50%;
border: 2px solid #BEF264; border: 2px solid #BEF264;
border-color: #BEF264 !important; border-color: #BEF264 !important;
} }
.text-custom-name{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
font-weight: 600;
}
.text-custom-category{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 12px;
}
.menu-popup {
position: absolute;
right: 0;
top: 30px;
background-color: white;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
}
.menu-popup ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.menu-popup ul li {
padding: 10px 20px;
cursor: pointer;
}
.menu-popup ul li:hover {
background-color: #f0f0f0;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important;"> <div class="app-content content" style="background-color: #fbfbfb !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,13 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div
class="card"
style="
background-color: #fbfbfb !important;
box-shadow: none !important;
"
>
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
@@ -21,7 +27,7 @@
bindValue="id" bindValue="id"
placeholder="Select Building" placeholder="Select Building"
[(ngModel)]="buildingSelected" [(ngModel)]="buildingSelected"
style="width: 100% !important;" style="width: 100% !important"
> >
</ng-select> </ng-select>
</div> </div>
@@ -58,12 +64,13 @@
<div class="d-flex"> <div class="d-flex">
<button <button
type="button" type="button"
class="btn btn-outline-success ml-2" class="btn ml-2"
(click)="doFilter()" (click)="doFilter()"
style=" style="
background-color: #252525 !important; background-color: #37a647 !important;
border-color: #ffffff !important; border-color: #ffffff !important;
border-radius: 12px; border-radius: 12px;
color: #ffffff;
" "
[disabled]="spinnerFilterActive" [disabled]="spinnerFilterActive"
> >
@@ -83,9 +90,9 @@
class="btn btn-outline-success ml-2" class="btn btn-outline-success ml-2"
(click)="doCancelFilter()" (click)="doCancelFilter()"
style=" style="
background-color: #252525 !important; background-color: #fbfbfb !important;
border-color: #ffffff !important; border-color: #6b6b6b !important;
color: #ffffff; color: #6b6b6b;
border-radius: 12px; border-radius: 12px;
" "
> >
@@ -103,10 +110,18 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12" *ngIf="filteredRows?.length === 0"> <div class="col-12" *ngIf="filteredRows?.length === 0">
<div class="card" style="background-color: #252525; min-height: 200px;"> <div
class="card"
style="
background-color: #fbfbfb !important;
box-shadow: none !important;
"
>
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<p class="text-center" style="color: #ffffff;">No data available</p> <p class="text-center" style="color: #242222">
No data available
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -114,7 +129,7 @@
<div class="col-lg-4 col-12" *ngFor="let item of filteredDeviceRows"> <div class="col-lg-4 col-12" *ngFor="let item of filteredDeviceRows">
<div <div
class="card" class="card"
style="background-color: #252525; position: relative" style="background-color: #dde1e6; position: relative"
> >
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
@@ -122,7 +137,7 @@
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414F2B; background-color: #37a647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -131,29 +146,51 @@
justify-content: center; justify-content: center;
" "
> >
<i class="{{item.category_icon}} font-large-1 blue-grey d-block" <i
style="color: #bef264 !important" class="{{
item.category_icon
}} font-large-1 blue-grey d-block"
style="color: #ffffff !important"
></i> ></i>
</div> </div>
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<span <span class="text-custom-name">{{ item.name }}</span>
class="text-muted"
style="color: #ffffff !important"
>{{ item.name }}</span
>
<br /> <br />
<span <span class="text-custom-category">{{
class="text-muted" item.category_name
>{{item.category_name}}</span }}</span>
>
</div> </div>
</div> </div>
<div class="ui-switch-container" style="position: absolute; bottom: 10px; right: 10px;">
<div style="position: absolute; top: 10px; right: 10px">
<button
(click)="toggleMenu(item.id)"
class="btn"
style="
background: none;
border: none;
font-size: 20px;
padding: 0;
"
>
&#x22EE;
</button>
<div *ngIf="item.menuOpen" class="menu-popup">
<ul>
<li (click)="schedulerItem(item)">scheduler</li>
</ul>
</div>
</div>
<div
class="ui-switch-container"
style="position: absolute; bottom: 10px; right: 10px"
>
<ui-switch <ui-switch
style="border-color: #bef264 !important" style="border-color: #bef264 !important"
class="switchery" class="switchery"
switchColor="black" switchColor="black"
color="rgb(190, 242, 100)" color="rgb(55, 166, 71)"
size="small" size="small"
[checked]="item.status_id === 2" [checked]="item.status_id === 2"
(change)="switchChanged($event, item)" (change)="switchChanged($event, item)"

View File

@@ -1,9 +1,11 @@
import { Component } from "@angular/core"; import { Component, HostListener } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { BuildingService } from "../../service/monitoring-api.service"; import { BuildingService } from "../../service/monitoring-api.service";
import { DeviceService } from "../../service/device.service"; import { DeviceService } from "../../service/device.service";
import { ToastrService } from "ngx-toastr"; import { ToastrService } from "ngx-toastr";
import { LoginService } from "../../service/login.service"; import { LoginService } from "../../service/login.service";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { ControlSchedulerComponent } from "../control-scheduler/control-scheduler.component";
@Component({ @Component({
selector: "app-device-control", selector: "app-device-control",
@@ -34,11 +36,13 @@ export class DeviceControlComponent {
private deviceService: DeviceService, private deviceService: DeviceService,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private toastr: ToastrService, private toastr: ToastrService,
private authService: LoginService private authService: LoginService,
private modalService: NgbModal,
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Device", mainlabel: "Device",
links: [ links: [
@@ -77,7 +81,7 @@ export class DeviceControlComponent {
filterDevices(devices: any[]): any[] { filterDevices(devices: any[]): any[] {
return devices.filter((device) => return devices.filter((device) =>
device.mapping.some( device.mapping.some(
(map) => map.name.startsWith("switch") && map.type === "Boolean" (map) => map.code.startsWith("switch") && map.type === "Boolean"
) )
); );
} }
@@ -99,7 +103,7 @@ export class DeviceControlComponent {
dataListBuilding() { dataListBuilding() {
this.monitoringApiService.getBuildingList().subscribe((data) => { this.monitoringApiService.getBuildingList().subscribe((data) => {
this.dataBuildingList = data.data.filter((item) => item.statusId === 2); this.dataBuildingList = data.data.filter((item) => item.statusName.toLowerCase() === "aktif");
}); });
} }
@@ -150,8 +154,8 @@ export class DeviceControlComponent {
switchChanged(ev, data) { switchChanged(ev, data) {
const requestData = { const requestData = {
device_id: data.device_id, id: data.id,
switch: data.mapping[0].switch, code: data.mapping[0].code,
value: ev, value: ev,
command_type: "on_off", command_type: "on_off",
}; };
@@ -160,7 +164,50 @@ export class DeviceControlComponent {
}); });
} }
addFieldValue() {} toggleMenu(itemId) {
this.filteredDeviceRows.forEach(item => {
if (item.id === itemId) {
item.menuOpen = !item.menuOpen;
} else {
item.menuOpen = false; // Close other menus
}
});
}
addDevice(): void {} schedulerItem(row) {
console.log(row);
this.router.navigate(["/device/scheduler", row.id]);
}
// schedulerItem(item) {
// const modalRef = this.modalService.open(ControlSchedulerComponent, {
// size: "md",
// backdrop: "static",
// keyboard: false,
// centered: true
// });
// modalRef.componentInstance.device = item;
// modalRef.result.then(
// (result) => {
// if (result) {
// console.log(result);
// }
// },
// (reason) => {
// console.log(`Dismissed: ${reason}`);
// }
// );
// // Handle edit action
// }
@HostListener('document:click', ['$event'])
clickout(event) {
if (!event.target.closest('.menu-popup') && !event.target.closest('.btn')) {
this.filteredDeviceRows.forEach(item => {
item.menuOpen = false;
});
}
}
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,20 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important; height: 40px !important;
border-radius: 12px; border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
} }
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input { :host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #ffffff !important; color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,22 +7,22 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-lg-4 col-12"> <div class="col-lg-4 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #DDE1E6 !important; box-shadow: none !important;">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h6 class="text-muted" style="color: #ffffff !important"> <h6 class="text-custom-label">
Total Device Total Device
</h6> </h6>
<h3 style="color: #ffffff !important"> <h3 class="text-custom-data">
{{ summaryTotal?.length }} {{ summaryTotal?.length }}
</h3> </h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37A647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -33,7 +33,7 @@
> >
<i <i
class="ri-device-line primary font-large-1 float-right" class="ri-device-line primary font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -43,20 +43,20 @@
</div> </div>
</div> </div>
<div class="col-lg-4 col-12"> <div class="col-lg-4 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #DDE1E6 !important; box-shadow: none !important;">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h6 class="text-light" style="color: #ffffff !important"> <h6 class="text-custom-label">
Total Device Active Total Device Active
</h6> </h6>
<h3 style="color: #ffffff !important">{{ totalOn }}</h3> <h3 class="text-custom-data">{{ totalOn }}</h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37A647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -67,7 +67,7 @@
> >
<i <i
class="feather ft-wifi primary font-large-1 float-right" class="feather ft-wifi primary font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -77,20 +77,20 @@
</div> </div>
</div> </div>
<div class="col-lg-4 col-12"> <div class="col-lg-4 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #DDE1E6 !important; box-shadow: none !important;">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h6 class="text-muted" style="color: #ffffff !important"> <h6 class="text-custom-label">
Total Device Non-Active Total Device Non-Active
</h6> </h6>
<h3 style="color: #ffffff !important">{{ totalOff }}</h3> <h3 class="text-custom-data">{{ totalOff }}</h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37A647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -101,7 +101,7 @@
> >
<i <i
class="feather ft-wifi-off primary font-large-1 float-right" class="feather ft-wifi-off primary font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -116,7 +116,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important; box-shadow: none;">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -169,12 +169,13 @@
<div class="d-flex"> <div class="d-flex">
<button <button
type="button" type="button"
class="btn btn-outline-success ml-2" class="btn ml-2"
(click)="doFilter()" (click)="doFilter()"
style=" style="
background-color: #252525 !important; background-color: #37A647 !important;
border-color: #ffffff !important; border-color: #37A647 !important;
border-radius: 12px; border-radius: 12px;
color: #ffffff;
" "
[disabled]="spinnerFilterActive || newDeviceActive" [disabled]="spinnerFilterActive || newDeviceActive"
> >
@@ -191,12 +192,12 @@
</button> </button>
<button <button
type="button" type="button"
class="btn btn-outline-success ml-2" class="btn ml-2"
(click)="doCancelFilter()" (click)="doCancelFilter()"
style=" style="
background-color: #252525 !important; background-color: #FBFBFB !important;
border-color: #ffffff !important; border-color: #242222 !important;
color: #ffffff; color: #242222;
border-radius: 12px; border-radius: 12px;
" "
> >
@@ -213,9 +214,9 @@
[disabled]="spinnerActive" [disabled]="spinnerActive"
(click)="addDevice()" (click)="addDevice()"
style=" style="
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
> >
<i <i
@@ -233,9 +234,9 @@
[disabled]="spinnerExportActive" [disabled]="spinnerExportActive"
(click)="exportDevice()" (click)="exportDevice()"
style=" style="
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
> >
<i <i
@@ -257,9 +258,9 @@
[disabled]="spinnerNewDeviceActive" [disabled]="spinnerNewDeviceActive"
(click)="newDevice()" (click)="newDevice()"
style=" style="
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
> >
<i <i
@@ -279,9 +280,9 @@
[disabled]="spinnerNewDeviceActive" [disabled]="spinnerNewDeviceActive"
(click)="allDevice()" (click)="allDevice()"
style=" style="
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
> >
<i <i
@@ -328,7 +329,7 @@
[minWidth]="20" [minWidth]="20"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Image</span> <span class="style-custom-label">Image</span>
</ng-template> </ng-template>
<ng-template ngx-datatable-cell-template let-row="row"> <ng-template ngx-datatable-cell-template let-row="row">
<span class="avatar avatar-sm rounded-circle"> <span class="avatar avatar-sm rounded-circle">
@@ -342,7 +343,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important" <span class="style-custom-label"
>Device Name</span >Device Name</span
> >
</ng-template> </ng-template>
@@ -350,7 +351,7 @@
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -359,7 +360,7 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important" <span class="style-custom-label"
>Building</span >Building</span
> >
</ng-template> </ng-template>
@@ -367,7 +368,7 @@
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -376,7 +377,7 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important" <span class="style-custom-label"
>Category</span >Category</span
> >
</ng-template> </ng-template>
@@ -384,7 +385,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -395,13 +396,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Watt</span> <span class="style-custom-label">Watt</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff !important">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -410,13 +411,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Type</span> <span class="style-custom-label">Type</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -427,13 +428,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Voltage</span> <span class="style-custom-label">Voltage</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff !important"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -461,7 +462,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff !important">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -471,27 +472,27 @@
<button <button
class="btn btn-sm btn-info mr-1" class="btn btn-sm btn-info mr-1"
style=" style="
background-color: #000000 !important; background-color: #DDE1E6 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
" "
(click)="viewRow(row)" (click)="viewRow(row)"
> >
<i <i
class="ficon feather ft-eye" class="ficon feather ft-eye"
style="color: #bef264 !important" style="color: #37A647 !important"
></i> ></i>
</button> </button>
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; background-color: #DDE1E6 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
<i <i
class="ficon feather ft-edit" class="ficon feather ft-edit"
style="color: #bef264 !important" style="color: #37A647 !important"
></i> ></i>
</button> </button>
<!-- <button <!-- <button

View File

@@ -53,7 +53,8 @@ export class DeviceComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Device", mainlabel: "Device",
links: [ links: [
@@ -169,7 +170,7 @@ export class DeviceComponent implements OnInit {
dataListBuilding() { dataListBuilding() {
this.monitoringApiService.getBuildingList().subscribe((data) => { this.monitoringApiService.getBuildingList().subscribe((data) => {
this.dataBuildingList = data.data.filter((item) => item.statusId === 2); this.dataBuildingList = data.data.filter((item) => item.statusName.toLowerCase() === "aktif");
}); });
} }

View File

@@ -16,6 +16,8 @@ import { AddEditDeviceComponent } from './add-edit-device/add-edit-device.compon
import { ModalAddEditComponent } from './modal-add-edit/modal-add-edit.component'; import { ModalAddEditComponent } from './modal-add-edit/modal-add-edit.component';
import { DeviceControlComponent } from './device-control/device-control.component'; import { DeviceControlComponent } from './device-control/device-control.component';
import { UiSwitchModule } from 'ngx-ui-switch'; import { UiSwitchModule } from 'ngx-ui-switch';
import { ControlSchedulerComponent } from './control-scheduler/control-scheduler.component';
import { SchedulerListComponent } from './scheduler-list/scheduler-list.component';
@@ -24,7 +26,9 @@ import { UiSwitchModule } from 'ngx-ui-switch';
DeviceComponent, DeviceComponent,
AddEditDeviceComponent, AddEditDeviceComponent,
ModalAddEditComponent, ModalAddEditComponent,
DeviceControlComponent DeviceControlComponent,
ControlSchedulerComponent,
SchedulerListComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@@ -63,8 +67,15 @@ import { UiSwitchModule } from 'ngx-ui-switch';
path: 'view/:id', path: 'view/:id',
component: AddEditDeviceComponent, component: AddEditDeviceComponent,
data: { mode: 'view' } data: { mode: 'view' }
},
{
path: 'scheduler/:id',
component: SchedulerListComponent,
data: { mode: 'scheduler' }
} }
]) ]),
] ]
}) })
export class DeviceModule { } export class DeviceModule { }

View File

@@ -0,0 +1,54 @@
.app-content {
padding-top: 20px;
}
.card {
border-radius: 15px;
overflow: hidden;
}
.card-header {
padding: 1.5rem;
border-bottom: 1px solid #ddd;
}
.card-body {
padding: 2rem;
}
.list-group-item {
background-color: #f7f8fa;
margin-bottom: 10px;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.list-group-item:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.list-group-item h5 {
margin-bottom: 5px;
}
.list-group-item .btn-outline-secondary,
.list-group-item .btn-outline-danger {
border-radius: 20px;
padding: 0.25rem 0.75rem;
}
.btn-light {
background-color: #e8eaf6;
color: #3f51b5;
border: none;
border-radius: 20px;
padding: 0.5rem 1.25rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.btn-light:hover {
background-color: #d1d9ff;
color: #303f9f;
}

View File

@@ -0,0 +1,113 @@
<div class="app-content content" style="background-color: #fbfbfb !important">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<section id="basic-form-layouts">
<div class="row">
<div class="col-6" *blockUI="'projectInfo'; message: 'Loading'">
<div class="card" style="background-color: #fbfbfb !important">
<div class="card-content">
<div
class="card-header d-flex justify-content-between align-items-center"
style="background-color: #fbfbfb !important"
>
<h4 class="form-section m-0" style="color: #242222">
<i class="feather ft-calendar" style="color: #242222"></i>
{{ deviceName ? deviceName : '' }}
</h4>
<button
class="btn"
style="
background-color: #37a647 !important;
border-color: #37a647 !important;
color: #ffffff !important;
"
(click)="addSchedulerItem()"
>
<span style="font-weight: 600">Add Schedule</span>
</button>
</div>
<div class="card-body">
<div class="form-body">
<div class="row">
<div class="col-md-12">
<div *ngIf="schedules.length > 0; else noSchedules">
<ul class="list-group">
<li
class="list-group-item d-flex justify-content-between align-items-center mb-3"
*ngFor="let schedule of listScheduler"
>
<!-- Tambahkan checkbox di sini -->
<div class="d-flex align-items-center">
<div class="mr-2">
<input
type="checkbox"
[(ngModel)]="schedule.selected"
(change)="checkSelected()"
/>
</div>
<div (click)="editSchedule(schedule)">
<h5 style="color: #242222">
{{ schedule.name }} ({{
schedule.switch ? "On" : "Off"
}})
</h5>
<h2 class="mb-0" style="color: #242222">
{{ schedule.timeset }}
</h2>
</div>
</div>
<div>
<ui-switch
style="border-color: #bef264 !important"
class="switchery"
switchColor="white"
color="rgb(55, 166, 71)"
size="small"
[checked]="schedule.active"
(change)="switchChanged($event, schedule)"
></ui-switch>
</div>
</li>
</ul>
<!-- Tambahkan tombol delete di sini -->
<div class="d-flex justify-content-center">
<button
*ngIf="hasSelected"
class="btn btn-danger mt-2"
(click)="deleteSelectedSchedules()"
style="
background-color: transparent !important;
border-color: #37a647 !important;
"
>
<i
class="ficon la la-trash"
style="color: #37a647 !important"
></i>
</button>
</div>
</div>
<ng-template #noSchedules>
<div class="alert alert-info text-center">
<strong>No schedules available.</strong> Click the
"Add Schedule" button to create one.
</div>
</ng-template>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</div>

View File

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

View File

@@ -0,0 +1,192 @@
import { Component } from "@angular/core";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { ControlSchedulerComponent } from "../control-scheduler/control-scheduler.component";
import { ActivatedRoute } from "@angular/router";
import { DeviceService } from "../../service/device.service";
import Swal from "sweetalert2";
@Component({
selector: "app-scheduler-list",
templateUrl: "./scheduler-list.component.html",
styleUrls: ["./scheduler-list.component.css"],
})
export class SchedulerListComponent {
public breadcrumb: any;
listScheduler: any;
deviceId: any;
deviceName: any;
hasSelected: boolean = false;
schedules = [
{
id: 1,
title: "Lampu Depan ON",
time: "08:55",
},
{
id: 2,
title: "Lampu Depan OFF",
time: "09:50",
},
];
constructor(
private modalService: NgbModal,
private route: ActivatedRoute,
private deviceService: DeviceService
) {}
ngOnInit(): void {
this.route.params.subscribe((params) => {
const id = params["id"];
this.deviceId = id;
if (id) {
this.dataListScheduler(id);
this.dataDevice(id);
}
});
this.breadcrumb = {
mainlabel: "Scheduler List",
linkBack: "/device/control-device",
isLinkBack: true,
links: [
{
name: "Home",
isLink: false,
link: "/dashboard/sales",
},
{
name: "Control Device",
isLink: false,
},
{
name: "Scheduler List",
isLink: false,
},
],
};
}
dataListScheduler(id) {
this.deviceService.getDeviceScheduler(id).subscribe((data) => {
this.listScheduler = data.results;
console.log(this.listScheduler);
});
}
dataDevice(id) {
this.deviceService.getDeviceByid(id).subscribe((data) => {
this.deviceName = data.data.name
});
}
switchChanged(e, item) {
const data = {
id: item.id,
active: e,
};
this.deviceService.putDeviceSchedulerActive(data, item.id).subscribe((res) => {
this.dataListScheduler(this.deviceId);
});
}
addSchedulerItem() {
const modalRef = this.modalService.open(ControlSchedulerComponent, {
size: "md",
backdrop: "static",
keyboard: false,
centered: true,
});
modalRef.componentInstance.deviceId = this.deviceId;
modalRef.componentInstance.mode = "add";
modalRef.result.then(
(result) => {
if (result) {
this.deviceService.postDeviceScheduler(result).subscribe((res) => {
this.dataListScheduler(this.deviceId);
});
}
},
(reason) => {
console.log(`Dismissed: ${reason}`);
}
);
// Handle edit action
}
editSchedule(data) {
const modalRef = this.modalService.open(ControlSchedulerComponent, {
size: "md",
backdrop: "static",
keyboard: false,
centered: true,
});
modalRef.componentInstance.deviceId = this.deviceId;
modalRef.componentInstance.data = data;
modalRef.componentInstance.mode = "edit";
modalRef.result.then(
(result) => {
if (result) {
this.deviceService
.putDeviceScheduler(result, data.id)
.subscribe((res) => {
this.dataListScheduler(this.deviceId);
});
}
},
(reason) => {
console.log(`Dismissed: ${reason}`);
}
);
}
checkSelected() {
this.hasSelected = this.listScheduler.some((schedule) => schedule.selected);
}
deleteSelectedSchedules() {
const selectedSchedules = this.listScheduler.filter(
(schedule) => schedule.selected
);
if (selectedSchedules.length > 0) {
Swal.fire({
title: "Apakah kamu yakin ingin menghapus jadwal yang dipilih?",
text: "Tindakan ini tidak dapat dibatalkan.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#37a647",
cancelButtonColor: "#d33",
confirmButtonText: "Ya, hapus!",
cancelButtonText: "Batal",
allowOutsideClick: false,
}).then((result) => {
if (result.isConfirmed) {
selectedSchedules.forEach((schedule) => {
this.deleteSchedule(schedule.id);
});
Swal.fire({
title: "Terhapus!",
text: "Jadwal yang dipilih berhasil dihapus.",
icon: "success",
});
}
});
} else {
Swal.fire({
title: "Tidak ada jadwal yang dipilih!",
text: "Pilih setidaknya satu jadwal untuk dihapus.",
icon: "info",
});
}
}
deleteSchedule(id) {
this.deviceService.deleteDeviceScheduler(id).subscribe(() => {
this.dataListScheduler(this.deviceId);
this.hasSelected = false;
});
}
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #fbfbfb !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,13 +7,13 @@
<section id="basic-form-layouts"> <section id="basic-form-layouts">
<div class="row"> <div class="row">
<div class="col-12" *blockUI="'projectInfo'; message: 'Loading'"> <div class="col-12" *blockUI="'projectInfo'; message: 'Loading'">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #fbfbfb !important">
<div class="card-content"> <div class="card-content">
<div <div
class="card-header" class="card-header"
style="background-color: #252525 !important" style="background-color: #fbfbfb !important"
> >
<h2 style="color: #ffffff"> <h2 style="color: #242222">
{{ {{
isEditMode() isEditMode()
? "Edit List Monitoring" ? "Edit List Monitoring"
@@ -29,14 +29,14 @@
(ngSubmit)="onProjectInfoSubmit()" (ngSubmit)="onProjectInfoSubmit()"
> >
<div class="form-body"> <div class="form-body">
<h4 class="form-section" style="color: #ffffff"> <!-- <h4 class="form-section" style="color: #242222">
<i class="feather ft-user" style="color: #ffffff"></i> <i class="feather ft-user" style="color: #242222"></i>
General Information General Information
</h4> </h4> -->
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="buildingId" style="color: #ffffff" <label for="buildingId" style="color: #242222"
>Building *</label >Building *</label
> >
<div class="input-group"> <div class="input-group">
@@ -55,49 +55,59 @@
{{ data.name }} {{ data.name }}
</option> </option>
</select> </select>
<button
class="btn btn-danger ml-2"
type="button"
style="
color: #ffffff !important;
border-color: #37a647 !important;
background-color: #37a647 !important;
"
(click)="modalAddBuilding()"
>
<i class="feather ft-plus"> New Building</i>
</button>
</div>
<div *ngIf="projectInfo.get('buildingId').touched && projectInfo.get('buildingId').invalid" class="text-danger">
Building is required.
</div> </div>
<small
class="form-text text-muted danger"
*ngIf="submitted && f.buildingId.errors"
class="invalid-feedback"
>
<div *ngIf="f.buildingId.errors.required">
Building is required
</div>
</small>
</div> </div>
</div>
<div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="statusId" style="color: #ffffff" <label for="floorId" style="color: #242222"
>Status *</label >Floor *</label
> >
<div class="input-group"> <div class="input-group">
<select <select
id="statusId" id="floorId"
class="form-control" class="form-control"
formControlName="statusId" formControlName="floorId"
[ngClass]="{ [ngClass]="{
'is-invalid': submitted && f.statusId.errors 'is-invalid': submitted && f.floorId.errors
}" }"
> >
<option <option
*ngFor="let data of dataMasterStatus" *ngFor="let data of dataFloorList"
[value]="data.id" [value]="data.id"
> >
{{ data.name }} {{ data.name }}
</option> </option>
</select> </select>
<button
class="btn btn-danger ml-2"
type="button"
style="
color: #ffffff !important;
border-color: #37a647 !important;
background-color: #37a647 !important;
"
(click)="modalAddFloor()"
>
<i class="feather ft-plus"> New Floor</i>
</button>
</div>
<div *ngIf="projectInfo.get('floorId').touched && projectInfo.get('floorId').invalid" class="text-danger">
Floor is required.
</div> </div>
<small
class="form-text text-muted danger"
*ngIf="submitted && f.statusId.errors"
class="invalid-feedback"
>
<div *ngIf="f.statusId.errors.required">
Status is required
</div>
</small>
</div> </div>
</div> </div>
</div> </div>
@@ -115,16 +125,17 @@
<div [formGroupName]="i" class=""> <div [formGroupName]="i" class="">
<div class="input-group mb-1"> <div class="input-group mb-1">
<select <select
id="roomId" id="roomId{{i}}"
class="form-control" class="form-control"
formControlName="roomId" formControlName="roomId"
(change)="validateDouble($event, i)"
[ngClass]="{ [ngClass]="{
'is-invalid': 'is-invalid':
submitted && f.roomId.errors submitted && f.roomId.errors
}" }"
> >
<option <option
*ngFor="let list of dataRoomList" *ngFor="let list of dataRoomList; trackBy: trackByFn"
[value]="list.id" [value]="list.id"
> >
{{ list.name }} {{ list.name }}
@@ -134,9 +145,9 @@
class="btn btn-danger" class="btn btn-danger"
type="button" type="button"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #a64f37 !important;
background-color: #bef264 !important; background-color: #a64f37 !important;
" "
(click)="removePhone(i)" (click)="removePhone(i)"
> >
@@ -149,15 +160,28 @@
<button <button
type="button" type="button"
class="btn btn-primary" class="btn btn-primary"
[disabled]="disableButton"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37a647 !important;
background-color: #bef264 !important; background-color: #37a647 !important;
" "
(click)="addPhone()" (click)="addPhone()"
> >
<i class="feather ft-plus"></i> Add Room <i class="feather ft-plus"></i> Add Room
</button> </button>
<button
type="button"
class="btn btn-primary ml-2"
style="
color: #ffffff !important;
border-color: #37a647 !important;
background-color: #37a647 !important;
"
(click)="modalAddNewRoom()"
>
New Room
</button>
</div> </div>
<div class="form-group" *ngIf="mode !== 'add'"> <div class="form-group" *ngIf="mode !== 'add'">
<label for="roomId">Room *</label> <label for="roomId">Room *</label>
@@ -188,6 +212,32 @@
</div> </div>
</small> </small>
</div> </div>
<div class="form-group">
<label for="statusId" style="color: #242222"
>Status *</label
>
<div class="input-group">
<select
id="statusId"
class="form-control"
formControlName="statusId"
[ngClass]="{
'is-invalid': submitted && f.statusId.errors
}"
>
<option
*ngFor="let data of dataMasterStatus"
[value]="data.id"
>
{{ data.name }}
</option>
</select>
</div>
<div *ngIf="projectInfo.get('statusId').touched && projectInfo.get('statusId').invalid" class="text-danger">
Status is required.
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -196,9 +246,9 @@
type="button" type="button"
class="btn btn-warning mr-1" class="btn btn-warning mr-1"
style=" style="
color: #bef264 !important; color: #242222 !important;
border-color: #bef264 !important; border-color: #242222 !important;
background-color: #000000 !important; background-color: #fbfbfb !important;
" "
(click)="cancel()" (click)="cancel()"
> >
@@ -207,12 +257,12 @@
<button <button
type="submit" type="submit"
class="btn btn-primary" class="btn btn-primary"
[disabled]="disableButtonSave"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37a647 !important;
background-color: #bef264 !important; background-color: #37a647 !important;
" "
*ngIf="mode !== 'view'"
(click)="save()" (click)="save()"
> >
<i class="la la-check"></i> Save <i class="la la-check"></i> Save

View File

@@ -1,14 +1,26 @@
import { Component, ViewChild } from '@angular/core'; import { Component, ViewChild } from "@angular/core";
import { FormArray, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; import {
import { ActivatedRoute, Router } from '@angular/router'; FormArray,
import { BlockUI, NgBlockUI } from 'ng-block-ui'; FormBuilder,
import { BuildingService } from '../../service/monitoring-api.service'; FormGroup,
import { LoginService } from '../../service/login.service'; NgForm,
Validators,
} from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { BlockUI, NgBlockUI } from "ng-block-ui";
import { BuildingService } from "../../service/monitoring-api.service";
import { LoginService } from "../../service/login.service";
import { ToastrService } from "ngx-toastr";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { AddEditMasterBuildingComponent } from "../../master/master-building/add-edit-master-building/add-edit-master-building.component";
import { AddEditMasterComponent } from "../../master/add-edit-master/add-edit-master.component";
import { AddEditMasterRoomComponent } from "../../master/master-room/add-edit-master-room/add-edit-master-room.component";
import Swal from "sweetalert2";
@Component({ @Component({
selector: 'app-add-edit-list', selector: "app-add-edit-list",
templateUrl: './add-edit-list.component.html', templateUrl: "./add-edit-list.component.html",
styleUrls: ['./add-edit-list.component.css'] styleUrls: ["./add-edit-list.component.css"],
}) })
export class AddEditListComponent { export class AddEditListComponent {
// @ViewChild("f", { read: true }) userProfileForm: NgForm; // @ViewChild("f", { read: true }) userProfileForm: NgForm;
@@ -21,15 +33,20 @@ export class AddEditListComponent {
dataBuildingList: any; dataBuildingList: any;
dataRoomList: any; dataRoomList: any;
dataRoomListSementara: any;
dataFloorList: any;
dataMasterStatus: any; dataMasterStatus: any;
roombuildingId: any; roombuildingId: any;
dataRoomBuilding: any; dataRoomBuilding: any;
disableButton: boolean = true;
disableButtonSave: boolean = true;
lewatModal: boolean = false;
// userProfileForm: FormGroup; // userProfileForm: FormGroup;
public userList: FormArray; public userList: FormArray;
@BlockUI("projectInfo") blockUIProjectInfo: NgBlockUI; @BlockUI("projectInfo") blockUIProjectInfo: NgBlockUI;
get userFormGroup() { get userFormGroup() {
return this.projectInfo.get('userArray') as FormArray; return this.projectInfo.get("userArray") as FormArray;
} }
constructor( constructor(
@@ -37,100 +54,124 @@ export class AddEditListComponent {
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService,
private modalService: NgbModal
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.route.data.subscribe((data) => { this.route.data.subscribe((data) => {
this.mode = data.mode; this.mode = data.mode;
}); });
this.route.params.subscribe(params => { this.route.params.subscribe((params) => {
const id = params['id']; const id = params["id"];
this.roombuildingId = id; this.roombuildingId = id;
if (id) { if (id) {
this.loadRoomBuilding(id); this.loadRoomBuilding(id);
} }
}); });
this.setBreadcrumb(); this.setBreadcrumb();
this.dataListBuilding();
this.dataListRoom();
this.dataListMaster();
this.projectInfo = this.formBuilder.group({ this.projectInfo = this.formBuilder.group({
buildingId: ["", Validators.required], buildingId: ["", Validators.required],
roomId: [""], roomId: [""],
statusId: ["", Validators.required], statusId: ["", Validators.required],
floorId: ["", Validators.required],
userArray: this.formBuilder.array([this.createRoom()]), userArray: this.formBuilder.array([this.createRoom()]),
}); });
this.userList = this.projectInfo.get('userArray') as FormArray; this.userList = this.projectInfo.get("userArray") as FormArray;
this.dataListBuilding();
this.dataListRoom();
this.dataListMaster();
this.dataListFloor();
} }
createRoom(): FormGroup { createRoom(): FormGroup {
return this.formBuilder.group({ return this.formBuilder.group({
roomId: ['', Validators.required] roomId: ["", Validators.required],
}); });
} }
addPhone() { addPhone() {
this.userList.push(this.createRoom()); this.userList.push(this.createRoom());
this.disableButton = true;
this.disableButtonSave = true;
} }
removePhone(index) { removePhone(index) {
this.userList.removeAt(index); this.userList.removeAt(index);
this.isRoomDuplicate(index);
if (this.userList.value.length === 0) {
this.disableButtonSave = true;
}
}
validateDouble(event: any, index: number) {
const selectedRoomId = (event.target as HTMLSelectElement).value;
if (this.isRoomDuplicate(index)) {
this.disableButton = true;
this.disableButtonSave = true;
this.toastr.error("Room", "Data yang ada masukan double!", {
timeOut: 2000,
closeButton: true,
});
} else {
this.disableButton = false;
this.disableButtonSave = false;
}
}
isRoomDuplicate(index: number): boolean {
const selectedRooms = this.userFormGroup.value.map((room) => room.roomId);
const currentRoomId = selectedRooms[index];
const roomOccurrences = selectedRooms.filter(
(roomId) => roomId === currentRoomId
).length;
if (roomOccurrences === 0) {
this.disableButton = false;
this.disableButtonSave = false;
}
return roomOccurrences > 1;
} }
setBreadcrumb() { setBreadcrumb() {
if (this.isAddMode()) { if (this.isAddMode()) {
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Cost Management", mainlabel: "List Monitoring",
links: [ links: [
{ {
name: "Home", name: "Home",
isLink: false, isLink: false,
}, },
{ {
name: "Cost Management", name: "List Monitoring",
isLink: false, isLink: false,
}, },
{ {
name: "Add New Cost Management", name: "Add New List Monitoring",
isLink: false, isLink: false,
}, },
], ],
}; };
} else if (this.isEditMode()) { } else if (this.isEditMode()) {
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Cost Management", mainlabel: "List Monitoring",
links: [ links: [
{ {
name: "Home", name: "Home",
isLink: false, isLink: false,
}, },
{ {
name: "Cost Management", name: "List Monitoring",
isLink: false, isLink: false,
}, },
{ {
name: "Edit New Cost Management", name: "Edit New List Monitoring",
isLink: false,
},
],
};
} else if (this.isViewMode()) {
this.breadcrumb = {
mainlabel: "Cost Management",
links: [
{
name: "Home",
isLink: false,
},
{
name: "Cost Management",
isLink: false,
},
{
name: "View New Cost Management",
isLink: false, isLink: false,
}, },
], ],
@@ -139,28 +180,31 @@ export class AddEditListComponent {
} }
loadRoomBuilding(deviceId: string) { loadRoomBuilding(deviceId: string) {
this.monitoringApiService.getRoomBuildingById(deviceId).subscribe(data => { this.monitoringApiService
this.dataRoomBuilding = data; .getRoomBuildingById(deviceId)
this.formGetDevice(data) .subscribe((data) => {
}); this.dataRoomBuilding = data;
this.formGetDevice(data);
});
} }
formGetDevice(data){ formGetDevice(data) {
this.projectInfo.patchValue({ this.projectInfo.patchValue({
buildingId: data.data.buildingId, buildingId: data.data.buildingId,
roomId: data.data.roomId, roomId: data.data.roomId,
floorId: data.data.floorId,
statusId: data.data.statusId, statusId: data.data.statusId,
}); });
if (this.mode === 'view') { if (this.mode === "view") {
this.formDisable(); this.formDisable();
} }
} }
formDisable(){ formDisable() {
this.projectInfo.get('buildingId').disable() this.projectInfo.get("buildingId").disable();
this.projectInfo.get('roomId').disable() this.projectInfo.get("roomId").disable();
this.projectInfo.get('statusId').disable() this.projectInfo.get("statusId").disable();
} }
isEditMode() { isEditMode() {
@@ -195,49 +239,227 @@ export class AddEditListComponent {
} }
dataListBuilding() { dataListBuilding() {
this.monitoringApiService.getBuildingList().subscribe(data => { this.monitoringApiService.getBuildingList().subscribe((data) => {
this.dataBuildingList = data.data.filter(item => item.statusId === 2) this.dataBuildingList = data.data
.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" || item.status_id === 71
)
.sort((a, b) => b.id - a.id);
if (this.lewatModal) {
this.projectInfo.patchValue({
buildingId: this.dataBuildingList[0],
});
this.lewatModal = false;
}
}); });
} }
dataListRoom() { dataListRoom() {
this.monitoringApiService.getListRoomData().subscribe(data => { this.monitoringApiService.getListRoomDataUnmap().subscribe((data) => {
this.dataRoomList = data.data const newArray = data.data.map((item) => ({
id: item.id,
name: `${item.name} (${item.code})`,
})).sort((a, b) => b.id - a.id);
this.dataRoomList = newArray;
});
}
trackByFn(index: number, option: any): any {
return option.id;
}
dataListFloor() {
this.monitoringApiService.getListFloorDataUnmap(6).subscribe((data) => {
const newArray = data.data.map((item) => ({
id: item.id,
name: `${item.name} (${item.code})`,
status: item.status_name
})).sort((a, b) => b.id - a.id);
this.dataFloorList = newArray.filter((item) => item.status.toLowerCase() === "aktif");
if (this.lewatModal) {
this.projectInfo.patchValue({
floorId: this.dataFloorList[0],
});
this.lewatModal = false;
}
}); });
} }
dataListMaster() { dataListMaster() {
this.monitoringApiService.getMasterListData().subscribe(data => { this.monitoringApiService.getMasterListData().subscribe((data) => {
const dataStatus = data.data.find( const dataStatus = data.data.find(
(item) => item.name === "master_status" (item) => item.name === "master_status"
).headerDetailParam; ).headerDetailParam;
this.dataMasterStatus = dataStatus.filter(item => item.statusName.toLowerCase() === "aktif") this.dataMasterStatus = dataStatus.filter(
(item) =>
item.statusName.toLowerCase() === "aktif" ||
item.status.toLowerCase() === "71"
);
}); });
} }
save() { save() {
if (this.mode === 'add') { if (this.mode === "add") {
if (this.projectInfo.invalid) { if (this.projectInfo.invalid) {
this.markFormGroupTouched(this.projectInfo)
return; return;
} }
const formData = this.projectInfo.value; const formData = this.projectInfo.value;
const transformedData = { const transformedData = {
buildingId: formData.buildingId, buildingId: formData.buildingId,
roomId: formData.userArray.map(room => room.roomId), roomId: formData.userArray.map((room) => room.roomId),
statusId: formData.statusId statusId: formData.statusId,
floorId: formData.floorId,
}; };
this.monitoringApiService.postBatchBuilding(transformedData).subscribe((res) => { this.monitoringApiService
this.router.navigate(["/list-monitoring"]); .postBatchBuilding(transformedData)
}); .subscribe((res) => {
this.router.navigate(["/list-monitoring"]);
});
} else { } else {
delete this.projectInfo.value.userArray; delete this.projectInfo.value.userArray;
this.monitoringApiService.puttBuildingRoom(this.projectInfo.value, this.roombuildingId).subscribe(data => { this.monitoringApiService
this.router.navigate(["/list-monitoring"]); .putBuildingRoom(this.projectInfo.value, this.roombuildingId)
}); .subscribe((data) => {
this.router.navigate(["/list-monitoring"]);
});
} }
} }
markFormGroupTouched(formGroup: FormGroup) {
(Object as any).values(formGroup.controls).forEach((control) => {
control.markAsTouched();
if (control.controls) {
this.markFormGroupTouched(control);
}
});
}
cancel() { cancel() {
this.router.navigate(["/list-monitoring"]); if (this.projectInfo.dirty) { // Check if form has unsaved changes
Swal.fire({
title: 'Are you sure?',
text: "You have unsaved changes. Do you really want to leave?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#37a647',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, leave',
cancelButtonText: 'No, stay'
}).then((result) => {
if (result.isConfirmed) {
this.router.navigate(["/list-monitoring"]);
}
});
} else {
this.router.navigate(["/list-monitoring"]);
}
}
modalAddBuilding() {
const modalRef = this.modalService.open(AddEditMasterBuildingComponent, {
size: "lg",
backdrop: "static",
keyboard: false,
});
modalRef.componentInstance.mode = "add";
modalRef.result.then(
(result) => {
if (result) {
if (
this.dataBuildingList.some(
(value) =>
value.name.trim().toLowerCase() ===
result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
} else {
this.monitoringApiService
.postMasterBuildingParam(result)
.subscribe((res) => {
this.dataListBuilding();
this.lewatModal = true;
});
}
}
},
(reason) => {
console.log(`Dismissed: ${reason}`);
}
);
}
modalAddFloor() {
const modalRef = this.modalService.open(AddEditMasterComponent, {
size: "lg",
backdrop: "static",
keyboard: false,
});
modalRef.componentInstance.headerId = 6;
modalRef.componentInstance.mode = "add";
modalRef.componentInstance.floor = true;
modalRef.result.then(
(result) => {
if (result) {
this.monitoringApiService
.postHeaderDetailParam(result)
.subscribe((res) => {
this.dataListFloor();
this.lewatModal = true;
if (res.status === 400) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
});
}
},
(reason) => {
console.log(`Dismissed: ${reason}`);
}
);
}
modalAddNewRoom(){
const modalRef = this.modalService.open(AddEditMasterRoomComponent, {
size: "lg",
backdrop: "static",
keyboard: false,
});
modalRef.componentInstance.mode = "add";
modalRef.result.then(
(result) => {
if (result) {
const filteredData = {
name: result.name,
code: result.code.trim(),
description: result.description,
};
this.monitoringApiService
.postMasterRoomParam(filteredData)
.subscribe((res) => {
this.dataListRoom();
}, (error) => {
this.toastr.error("Error", error.error.message, {
timeOut: 2000,
closeButton: true,
});
});
}
},
(reason) => {
console.log(`Dismissed: ${reason}`);
}
);
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,53 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important; height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
/* Tambahkan ini ke styles.css atau CSS komponen */ .text-custom-label{
color: #242222 !important;
/* Custom styles for Swal buttons */ font-family: "Open Sans", sans-serif !important;
.div:where(.swal2-container) button:where(.swal2-styled).swal2-confirm { font-size: 16px;
background-color: #bef264 !important;
color: white !important;
border: none !important;
padding: 10px 20px !important;
border-radius: 5px !important;
font-size: 16px !important;
} }
.swal2-cancel.btn-cancel { .text-custom-data{
background-color: #dc3545 !important; color: #242222 !important;
color: white !important; font-family: "Open Sans", sans-serif !important;
border: none !important; font-size: 24px;
padding: 10px 20px !important; font-weight: 700;
border-radius: 5px !important;
font-size: 16px !important;
} }
.swal2-confirm.btn-confirm:hover { .style-custom-label{
background-color: #218838 !important; color: #242222 !important;
} }
.swal2-cancel.btn-cancel:hover {
background-color: #c82333 !important;
}
/* Custom Swal background */
.swal2-popup.custom-swal-background {
background-color: #000000 !important; /* Warna background hitam */
color: white !important; /* Warna teks putih */
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper" style="height: 900px !important;"> <div class="content-wrapper" style="height: 900px !important;">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -26,9 +26,9 @@
class="btn btn-secondary" class="btn btn-secondary"
[routerLink]="['/list-monitoring/add-row']" [routerLink]="['/list-monitoring/add-row']"
style=" style="
background-color: #bef264 !important; background-color: #37A647 !important;
border-color: #bef264 !important; border-color: #37A647 !important;
color: #000000 !important; color: #ffffff !important;
" "
> >
<i class="feather ft-plus" style="color: #ffffff"></i <i class="feather ft-plus" style="color: #ffffff"></i
@@ -40,7 +40,7 @@
<div class="card-dashboard"> <div class="card-dashboard">
<ngx-datatable <ngx-datatable
class="bootstrap table-bordered" class="bootstrap table-bordered"
[limit]="5" [limit]="10"
[rows]="filteredRows" [rows]="filteredRows"
[columnMode]="'force'" [columnMode]="'force'"
[headerHeight]="50" [headerHeight]="50"
@@ -58,7 +58,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -68,13 +68,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Building</span> <span class="style-custom-label">Building</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value.name }}</p> <p class="style-custom-label">{{ value.name }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -84,13 +84,29 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Room</span> <span class="style-custom-label">Room</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff">{{ value.name }}</p> <p class="style-custom-label">{{ value.name }}</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="floorEntity"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span class="style-custom-label">Floor</span>
</ng-template>
<ng-template
ngx-datatable-cell-template
let-value="value"
>
<p class="style-custom-label">{{ value.name }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -100,13 +116,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff">{{ value.name }}</p> <p class="style-custom-label">{{ value.name }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -116,33 +132,30 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
let-row="row" let-row="row"
> >
<button <!-- <button
class="btn btn-sm btn-info mr-1"
style="background-color: #000000 !important; border-color: #BEF264 !important;"
(click)="viewRow(row)"
>
<i class="ficon feather ft-eye" style="color: #BEF264 !important;"></i>
</button>
<button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style="background-color: #000000 !important; border-color: #BEF264 !important;" style="background-color: #FBFBFB !important; border-color: #37A647 !important;"
(click)="editRow(row)" (click)="editRow(row)"
> >
<i class="ficon feather ft-edit" style="color: #BEF264 !important;"></i> <i class="ficon feather ft-edit" style="color: #37A647 !important;"></i>
</button> </button> -->
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style="background-color: #000000 !important; border-color: #BEF264 !important;" style="
color: #37a647 !important;
border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
"
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >
<i class="ficon feather ft-trash-2" style="color: #BEF264 !important;"></i> <i class="ficon feather ft-trash-2" style="color: #37A647 !important;"></i>
</button> </button>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>

View File

@@ -4,6 +4,7 @@ import { TableApiService } from "src/app/_services/table-api.service";
import { BuildingService } from "../service/monitoring-api.service"; import { BuildingService } from "../service/monitoring-api.service";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import { LoginService } from "../service/login.service"; import { LoginService } from "../service/login.service";
import { ToastrService } from "ngx-toastr";
@Component({ @Component({
selector: "app-list-monitoring", selector: "app-list-monitoring",
@@ -18,23 +19,24 @@ export class ListMonitoringComponent {
rows: any = []; rows: any = [];
constructor( constructor(
private tableApiservice: TableApiService,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService,
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Cost Management", mainlabel: "List Monitoring",
links: [ links: [
{ {
name: "Home", name: "Home",
isLink: false, isLink: false,
}, },
{ {
name: "Cost Management", name: "List Monitoring",
isLink: false, isLink: false,
}, },
], ],
@@ -45,25 +47,28 @@ export class ListMonitoringComponent {
fetchData() { fetchData() {
this.monitoringApiService.getBuildingRoomList().subscribe((res) => { this.monitoringApiService.getBuildingRoomList().subscribe((res) => {
this.data = res; this.data = res;
this.filteredRows = this.data.results.data; // this.filteredRows = this.data.results.data;
this.filteredRows = this.data.results.data.sort((a, b) => b.id - a.id);
}); });
} }
filterRows() { filterRows() {
if (!this.searchTerm) { if (!this.searchTerm) {
this.filteredRows = [...this.data.rows]; this.filteredRows = [...this.data.results.data];
} else { } else {
this.filteredRows = this.data.rows.filter((row) => const searchTermLC = this.searchTerm.toLowerCase();
this.rowContainsSearchTerm(row) this.filteredRows = this.data.results.data.filter((row) =>
this.rowContainsSearchTerm(row, searchTermLC)
); );
} }
} }
rowContainsSearchTerm(row: any): boolean { rowContainsSearchTerm(row: any, searchTermLC: string): boolean {
const searchTermLC = this.searchTerm.toLowerCase(); return (
return Object.values(row).some( row.buildingEntity.name.toLowerCase().includes(searchTermLC) ||
(value) => row.roomEntity.name.toLowerCase().includes(searchTermLC) ||
value !== null && value.toString().toLowerCase().includes(searchTermLC) row.statusEntity.name.toLowerCase().includes(searchTermLC) ||
row.floorEntity?.name.toLowerCase().includes(searchTermLC)
); );
} }
@@ -76,59 +81,25 @@ export class ListMonitoringComponent {
} }
deleteRow(row) { deleteRow(row) {
const swalWithBootstrapButtons = Swal.mixin({ const confirmDelete = confirm("Are you sure you want to delete this item?");
customClass: { if (confirmDelete) {
confirmButton: "btn-confirm", this.monitoringApiService.deleteRoomBuilding(row.id).subscribe(
cancelButton: "btn-cancel", (res) => {
popup: "custom-swal-background", this.fetchData();
}, this.toastr.success("Success", "Delete Completed.", {
}); timeOut: 2000,
swalWithBootstrapButtons.fire({ closeButton: true,
title: "Are you sure?", });
text: "Do you want to delete?", },
icon: "question", (error) => {
showCancelButton: true, console.error(error);
confirmButtonText: "Yes", this.toastr.error("Error", "Data sedang digunakan!", {
cancelButtonText: "No", timeOut: 2000,
}).then((result) => { closeButton: true,
if (result.isConfirmed) { });
Swal.fire({ }
title: "Loading...", );
text: "Please wait", }
allowOutsideClick: false,
customClass: {
popup: "custom-swal-background",
},
didOpen: () => {
Swal.showLoading();
},
});
setTimeout(() => {
this.monitoringApiService
.deleteRoomBuilding(row.id)
.subscribe((data) => {
Swal.fire({
title: "Confirmed!",
text: "You clicked Yes.",
icon: "success",
customClass: {
popup: "custom-swal-background",
},
});
this.fetchData();
});
}, 2000);
} else if (result.isDismissed) {
Swal.fire({
title: "Cancelled",
text: "You clicked No.",
icon: "error",
customClass: {
popup: "custom-swal-background",
},
});
}
});
} }
onTouchStart(event: Event) { onTouchStart(event: Event) {

View File

@@ -1,56 +1,54 @@
/* modal-add-edit.component.css */ /* modal-add-edit.component.css */
::ng-deep .modal-backdrop.show { ::ng-deep .modal-backdrop.show {
z-index: auto !important; z-index: auto !important;
} }
/*
::ng-deep .input-group-append .btn { ::ng-deep .input-group-append .btn {
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
border-radius: 0; border-radius: 0;
border-left: 0; border-left: 0;
flex-grow: 0; flex-grow: 0;
border-left: 1px solid #ced4da; border-left: 1px solid #ced4da;
padding: 0.375rem 0.75rem; padding: 0.375rem 0.75rem;
} }
::ng-deep .input-group { ::ng-deep .input-group {
display: flex; display: flex;
flex-wrap: nowrap; /* Prevents wrapping of the items */ flex-wrap: nowrap;
align-items: center; align-items: center;
} }
::ng-deep .form-control { ::ng-deep .form-control {
flex-grow: 1; /* Ensures select takes up available space */ flex-grow: 1;
padding-right: 0.5rem; padding-right: 0.5rem;
} }
::ng-deep .input-group select, ::ng-deep .input-group select,
::ng-deep .input-group .input-group-append .btn { ::ng-deep .input-group .input-group-append .btn {
padding-right: 5px; /* Adjust padding if necessary */ padding-right: 5px;
} }
::ng-deep .input-group .form-control { ::ng-deep .input-group .form-control {
margin-right: 2px; /* Adjust margin to make space */ margin-right: 2px;
} }
.form-group {
.form-group { margin-bottom: 1rem;
margin-bottom: 1rem; }
}
.form-control {
.form-control { display: block;
display: block; width: 100%;
width: 100%; height: calc(1.5em + 0.75rem + 2px);
height: calc(1.5em + 0.75rem + 2px); padding: 0.375rem 0.75rem;
padding: 0.375rem 0.75rem; font-size: 1rem;
font-size: 1rem; font-weight: 400;
font-weight: 400; line-height: 1.5;
line-height: 1.5; color: #495057;
color: #495057; background-color: #fff;
background-color: #fff; background-clip: padding-box;
background-clip: padding-box; border: 1px solid #ced4da;
border: 1px solid #ced4da; border-radius: 0.25rem;
border-radius: 0.25rem; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } */
}

View File

@@ -1,14 +1,14 @@
<div class="modal-header" style="background-color: #000000 !important"> <div class="modal-header" style="background-color: #FBFBFB !important">
<h4 class="modal-title" style="color: #ffffff">{{labelModal}}</h4> <h4 class="modal-title" style="color: #242222">{{labelModal}}</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"> <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div class="modal-body" style="background-color: #000000 !important"> <div class="modal-body" style="background-color: #FBFBFB !important">
<form [formGroup]="myForm"> <form [formGroup]="myForm">
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="name" style="color: #ffffff">Name:</label> <label for="name" style="color: #242222">Name:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
@@ -20,18 +20,32 @@
Name is required. Name is required.
</div> </div>
</div> </div>
<div class="form-group col-md-6" *ngIf="floor">
<label for="code" style="color: #242222">Code:</label>
<input
type="text"
class="form-control"
id="code"
formControlName="code"
maxlength="10"
(input)="toUppercase($event)"
/>
<div *ngIf="myForm.get('code').touched && myForm.get('code').invalid" class="text-danger">
code is required.
</div>
</div>
<div class="form-group col-md-6" *ngIf="category"> <div class="form-group col-md-6" *ngIf="category">
<label for="icon" style="color: #ffffff">Icon:</label> <label for="icon" style="color: #242222">Icon:</label>
<app-select-icon [selectedIcon]="selectedIcon" (iconSelected)="onIconSelected($event)"></app-select-icon> <app-select-icon [selectedIcon]="selectedIcon" (iconSelected)="onIconSelected($event)"></app-select-icon>
<div *ngIf="myForm.get('icon').touched && myForm.get('icon').invalid" class="text-danger"> <div *ngIf="myForm.get('icon').touched && myForm.get('icon').invalid" class="text-danger">
Icon is required. Icon is required.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="status" style="color: #ffffff">Status:</label> <label for="status" style="color: #242222">Status:</label>
<select <select
id="projectinput5" id="projectinput5"
class="form-control" class="form-control custom-select"
formControlName="status" formControlName="status"
> >
<option *ngFor="let data of dataMasterStatus" [value]="data.id"> <option *ngFor="let data of dataMasterStatus" [value]="data.id">
@@ -45,18 +59,18 @@
</div> </div>
</form> </form>
</div> </div>
<div class="modal-footer" style="background-color: #000000 !important"> <div class="modal-footer" style="background-color: #FBFBFB !important">
<button <button
type="button" type="button"
class="btn btn-secondary" class="btn btn-secondary"
style="color: #c3f164 !important; background-color: #000000 !important; border-color: #c3f164 !important;" style="color: #242222 !important; background-color: #FBFBFB !important; border-color: #FBFBFB !important;"
(click)="activeModal.dismiss('Cross click')" (click)="activeModal.dismiss('Cross click')"
> >
Close Close
</button> </button>
<button <button
type="button" type="button"
style="color: #000000 !important; background-color: #c3f164 !important" style="color: #ffffff !important; background-color: #37A647 !important"
class="btn btn-primary" class="btn btn-primary"
(click)="addRow()" (click)="addRow()"
> >

View File

@@ -14,6 +14,7 @@ export class AddEditMasterComponent implements OnInit {
@Input() dataRow: any; @Input() dataRow: any;
@Input() mode: any; @Input() mode: any;
@Input() category: boolean = false; @Input() category: boolean = false;
@Input() floor: boolean = false;
myForm: FormGroup; myForm: FormGroup;
dataMasterStatus: any; dataMasterStatus: any;
selectedIcon: string = ''; selectedIcon: string = '';
@@ -27,7 +28,8 @@ export class AddEditMasterComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.createForm(); this.createForm();
this.dataListMaster(); this.dataListMaster();
if (this.mode === "add") { if (this.mode === "add") {
@@ -52,12 +54,21 @@ export class AddEditMasterComponent implements OnInit {
formControls['icon'] = [undefined, Validators.required]; formControls['icon'] = [undefined, Validators.required];
} }
if (this.floor) {
formControls['code'] = ['', Validators.required];
}
this.myForm = this.fb.group(formControls); this.myForm = this.fb.group(formControls);
} }
toUppercase(event: Event) {
const input = event.target as HTMLInputElement;
input.value = input.value.toUpperCase();
this.myForm.get('code').setValue(input.value);
}
editForm() { editForm() {
console.log(this.dataRow);
const formControls = { const formControls = {
id: this.dataRow.id, id: this.dataRow.id,
name: [this.dataRow.name, Validators.required], name: [this.dataRow.name, Validators.required],
@@ -70,6 +81,9 @@ export class AddEditMasterComponent implements OnInit {
this.selectedIcon = this.dataRow.icon || undefined; this.selectedIcon = this.dataRow.icon || undefined;
} }
if (this.floor) {
formControls['code'] = [this.dataRow.code || '' , Validators.required];
}
this.myForm = this.fb.group(formControls); this.myForm = this.fb.group(formControls);
} }
@@ -78,7 +92,7 @@ export class AddEditMasterComponent implements OnInit {
const dataCategory = data.data.find( const dataCategory = data.data.find(
(item) => item.name === "master_status" (item) => item.name === "master_status"
).headerDetailParam; ).headerDetailParam;
this.dataMasterStatus = dataCategory.filter(item => item.statusName.toLowerCase() === "aktif"); this.dataMasterStatus = dataCategory.filter(item => item.statusName.toLowerCase() === "aktif" || item.status.toLowerCase() === "71" || item.status.toLowerCase() === "71");
}); });
} }
@@ -107,8 +121,6 @@ export class AddEditMasterComponent implements OnInit {
} }
onIconSelected(icon: string): void { onIconSelected(icon: string): void {
console.log(icon);
this.selectedIcon = icon; this.selectedIcon = icon;
this.myForm.get('icon').setValue(icon); // Set nilai icon ke dalam form this.myForm.get('icon').setValue(icon); // Set nilai icon ke dalam form
} }

View File

@@ -1,42 +1,59 @@
<div class="modal-header" style="background-color: #000000 !important"> <div class="modal-header" style="background-color: #fbfbfb !important">
<h4 class="modal-title" style="color: #ffffff">{{labelModal}}</h4> <h4 class="modal-title" style="color: #242222">{{ labelModal }}</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"> <button
type="button"
class="close"
aria-label="Close"
(click)="activeModal.dismiss('Cross click')"
>
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div class="modal-body" style="background-color: #000000 !important"> <div class="modal-body" style="background-color: #fbfbfb !important">
<form [formGroup]="myForm"> <form [formGroup]="myForm">
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="name" style="color: #ffffff">Name Building:</label> <label for="name" style="color: #242222">Name Building:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
id="name" id="name"
formControlName="name" formControlName="name"
maxlength="50" maxlength="50"
[ngClass]="{'is-invalid': myForm.get('name').invalid && myForm.get('name').touched}" [ngClass]="{
'is-invalid':
myForm.get('name').invalid && myForm.get('name').touched
}"
/> />
<div *ngIf="myForm.get('name').invalid && myForm.get('name').touched" class="text-danger"> <div
*ngIf="myForm.get('name').invalid && myForm.get('name').touched"
class="text-danger"
>
Name is required. Name is required.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="email" style="color: #ffffff">Email:</label> <label for="email" style="color: #242222">Email:</label>
<input <input
type="email" type="email"
class="form-control" class="form-control"
id="email" id="email"
formControlName="email" formControlName="email"
maxlength="50" maxlength="50"
[ngClass]="{'is-invalid': myForm.get('email').invalid && myForm.get('email').touched}" [ngClass]="{
'is-invalid':
myForm.get('email').invalid && myForm.get('email').touched
}"
/> />
<div *ngIf="myForm.get('email').invalid && myForm.get('email').touched" class="text-danger"> <div
*ngIf="myForm.get('email').invalid && myForm.get('email').touched"
class="text-danger"
>
Please enter a valid email. Please enter a valid email.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="phone" style="color: #ffffff">Phone:</label> <label for="phone" style="color: #242222">Phone:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
@@ -44,81 +61,112 @@
formControlName="phone" formControlName="phone"
pattern="^[0-9]*$" pattern="^[0-9]*$"
maxlength="13" maxlength="13"
[ngClass]="{'is-invalid': myForm.get('phone').invalid && myForm.get('phone').touched}" [ngClass]="{
'is-invalid':
myForm.get('phone').invalid && myForm.get('phone').touched
}"
/> />
<div *ngIf="myForm.get('phone').invalid && myForm.get('phone').touched" class="text-danger"> <div
*ngIf="myForm.get('phone').invalid && myForm.get('phone').touched"
class="text-danger"
>
Please enter a valid phone number. Please enter a valid phone number.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="owner" style="color: #ffffff">Owner:</label> <label for="owner" style="color: #242222">Owner:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
id="owner" id="owner"
maxlength="30" maxlength="30"
formControlName="owner" formControlName="owner"
[ngClass]="{'is-invalid': myForm.get('owner').invalid && myForm.get('owner').touched}" [ngClass]="{
'is-invalid':
myForm.get('owner').invalid && myForm.get('owner').touched
}"
/> />
<div *ngIf="myForm.get('owner').invalid && myForm.get('owner').touched" class="text-danger"> <div
*ngIf="myForm.get('owner').invalid && myForm.get('owner').touched"
class="text-danger"
>
Owner is required. Owner is required.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="address" style="color: #ffffff">Address:</label> <label for="address" style="color: #242222">Address:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
id="address" id="address"
formControlName="address" formControlName="address"
maxlength="90" maxlength="90"
[ngClass]="{'is-invalid': myForm.get('address').invalid && myForm.get('address').touched}" [ngClass]="{
'is-invalid':
myForm.get('address').invalid && myForm.get('address').touched
}"
/> />
<div *ngIf="myForm.get('address').invalid && myForm.get('address').touched" class="text-danger"> <div
*ngIf="myForm.get('address').invalid && myForm.get('address').touched"
class="text-danger"
>
Address is required. Address is required.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="kwh" style="color: #ffffff">KWH:</label> <label for="kwh" style="color: #242222">KWH:</label>
<input <input
type="number" type="text"
class="form-control no-arrow" class="form-control no-arrow"
id="kwh" id="kwh"
formControlName="kwh" formControlName="kwh"
maxlength="20" maxlength="15"
[ngClass]="{'is-invalid': myForm.get('kwh').invalid && myForm.get('kwh').touched}" [ngClass]="{
'is-invalid': myForm.get('kwh').invalid && myForm.get('kwh').touched
}"
/> />
<div *ngIf="myForm.get('kwh').invalid && myForm.get('kwh').touched" class="text-danger"> <div
KWH is required. *ngIf="myForm.get('kwh').invalid && myForm.get('kwh').touched"
class="text-danger"
>
Please enter a valid KWH.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="statusId" style="color: #ffffff">Status:</label> <label for="statusId" style="color: #242222">Status:</label>
<select <select
id="statusId" id="statusId"
class="form-control" class="form-control custom-select"
formControlName="statusId" formControlName="statusId"
[ngClass]="{'is-invalid': myForm.get('statusId').invalid && myForm.get('statusId').touched}" [ngClass]="{
'is-invalid':
myForm.get('statusId').invalid && myForm.get('statusId').touched
}"
> >
<option *ngFor="let data of filteredDataStatus" [value]="data.id"> <option *ngFor="let data of filteredDataStatus" [value]="data.id">
{{ data.name }} {{ data.name }}
</option> </option>
</select> </select>
<div *ngIf="myForm.get('statusId').invalid && myForm.get('statusId').touched" class="text-danger"> <div
*ngIf="
myForm.get('statusId').invalid && myForm.get('statusId').touched
"
class="text-danger"
>
Status is required. Status is required.
</div> </div>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<div class="modal-footer" style="background-color: #000000 !important"> <div class="modal-footer" style="background-color: #fbfbfb !important">
<button <button
type="button" type="button"
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #c3f164 !important; color: #242222 !important;
background-color: #000000 !important; background-color: #fbfbfb !important;
border-color: #c3f164 !important; border-color: #fbfbfb !important;
" "
(click)="activeModal.dismiss('Cross click')" (click)="activeModal.dismiss('Cross click')"
> >
@@ -126,7 +174,7 @@
</button> </button>
<button <button
type="button" type="button"
style="color: #000000 !important; background-color: #c3f164 !important" style="color: #ffffff !important; background-color: #37a647 !important"
class="btn btn-primary" class="btn btn-primary"
(click)="addRow()" (click)="addRow()"
> >

View File

@@ -27,7 +27,8 @@ export class AddEditMasterBuildingComponent {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.createForm(); this.createForm();
this.listDataStatus(); this.listDataStatus();
if (this.mode === "add") { if (this.mode === "add") {
@@ -48,7 +49,7 @@ export class AddEditMasterBuildingComponent {
owner: ["", Validators.required], owner: ["", Validators.required],
address: ["", Validators.required], address: ["", Validators.required],
phone: ["", [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]], phone: ["", [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
kwh: ["", Validators.required], kwh: ["", [Validators.required, Validators.maxLength(15), Validators.pattern(/^[0-9]{1,7}$/)]],
}); });
} }
@@ -58,13 +59,10 @@ export class AddEditMasterBuildingComponent {
name: [this.dataRow.name, Validators.required], name: [this.dataRow.name, Validators.required],
statusId: [this.dataRow.status_id, Validators.required], statusId: [this.dataRow.status_id, Validators.required],
email: [this.dataRow.email, [Validators.required, Validators.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)]], email: [this.dataRow.email, [Validators.required, Validators.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)]],
owner: [this.dataRow.owner, Validators.required], address: [this.dataRow.address, Validators.required],
address: [this.dataRow.address, [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]], phone: [this.dataRow.phone, [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
phone: [ owner: [this.dataRow.owner,Validators.required],
this.dataRow.phone, kwh: [this.dataRow.kwh, [Validators.required, Validators.maxLength(15), Validators.pattern(/^[0-9]{1,7}$/)]],
[Validators.required, Validators.pattern("^[0-9]*$")],
],
kwh: [this.dataRow.kwh, Validators.required],
}); });
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #fbfbfb !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #fbfbfb !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37a647 !important;
background-color: #bef264 !important; background-color: #37a647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -60,7 +60,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -69,13 +69,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Building Name</span> <span class="style-custom-label">Building Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -84,13 +84,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Email</span> <span class="style-custom-label">Email</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -99,13 +99,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Phone</span> <span class="style-custom-label">Phone</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -114,13 +114,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Owner</span> <span class="style-custom-label">Owner</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -129,13 +129,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Address</span> <span class="style-custom-label">Address</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -144,13 +144,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -161,7 +161,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -171,8 +171,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -181,8 +182,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -1,16 +1,17 @@
import { Component } from '@angular/core'; import { Component } from "@angular/core";
import { AddEditMasterComponent } from '../add-edit-master/add-edit-master.component'; import { AddEditMasterComponent } from "../add-edit-master/add-edit-master.component";
import { TableApiService } from 'src/app/_services/table-api.service'; import { TableApiService } from "src/app/_services/table-api.service";
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { Router } from '@angular/router'; import { Router } from "@angular/router";
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from "../../service/monitoring-api.service";
import { AddEditMasterBuildingComponent } from './add-edit-master-building/add-edit-master-building.component'; import { AddEditMasterBuildingComponent } from "./add-edit-master-building/add-edit-master-building.component";
import { LoginService } from '../../service/login.service'; import { LoginService } from "../../service/login.service";
import { ToastrService } from "ngx-toastr";
@Component({ @Component({
selector: 'app-master-building', selector: "app-master-building",
templateUrl: './master-building.component.html', templateUrl: "./master-building.component.html",
styleUrls: ['./master-building.component.css'] styleUrls: ["./master-building.component.css"],
}) })
export class MasterBuildingComponent { export class MasterBuildingComponent {
data: any; data: any;
@@ -24,11 +25,13 @@ export class MasterBuildingComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Building", mainlabel: "Master Building",
links: [ links: [
@@ -74,20 +77,38 @@ export class MasterBuildingComponent {
openAddMasterModal() { openAddMasterModal() {
const modalRef = this.modalService.open(AddEditMasterBuildingComponent, { const modalRef = this.modalService.open(AddEditMasterBuildingComponent, {
size: "lg", size: "lg",
backdrop: 'static', backdrop: "static",
keyboard: false keyboard: false,
}); });
modalRef.componentInstance.mode = "add"; modalRef.componentInstance.mode = "add";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
if (result) { if (result) {
this.monitoringApiService if (
.postMasterBuildingParam(result) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
this.fetchData(); )
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
}); });
} else {
this.monitoringApiService
.postMasterBuildingParam(result)
.subscribe((res) => {
this.fetchData();
});
}
} }
// if (result) {
// this.monitoringApiService
// .postMasterBuildingParam(result)
// .subscribe((res) => {
// this.fetchData();
// });
// }
}, },
(reason) => { (reason) => {
console.log(`Dismissed: ${reason}`); console.log(`Dismissed: ${reason}`);
@@ -98,8 +119,8 @@ export class MasterBuildingComponent {
editRow(row) { editRow(row) {
const modalRef = this.modalService.open(AddEditMasterBuildingComponent, { const modalRef = this.modalService.open(AddEditMasterBuildingComponent, {
size: "lg", size: "lg",
backdrop: 'static', backdrop: "static",
keyboard: false keyboard: false,
}); });
modalRef.componentInstance.dataRow = row; modalRef.componentInstance.dataRow = row;
@@ -107,12 +128,64 @@ export class MasterBuildingComponent {
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
if (result) { if (result) {
this.monitoringApiService if (
.putMasterBuildingParam(result, row.id) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
this.fetchData(); )
}); ) {
if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
this.monitoringApiService
.putMasterBuildingParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
} else {
if (
this.filteredRows.some(
(value) =>
value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}
} else {
this.monitoringApiService
.putMasterBuildingParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
// if (result) {
// console.log(result);
// console.log(this.filteredRows);
// if (this.filteredRows.some(value => value.name.toLowerCase() === result.name.toLowerCase() && value.status_id === result.statusId)) {
// this.toastr.error("Warning", "Nama Gedung yang anda masukan double.", {
// timeOut: 5000,
// closeButton: true,
// });
// } else {
// this.monitoringApiService
// .putMasterBuildingParam(result, row.id)
// .subscribe((res) => {
// this.fetchData();
// });
// }
// }
// if (result) {
// this.monitoringApiService
// .putMasterBuildingParam(result, row.id)
// .subscribe((res) => {
// this.fetchData();
// });
// }
}, },
(reason) => { (reason) => {
console.log(`Dismissed: ${reason}`); console.log(`Dismissed: ${reason}`);
@@ -127,6 +200,12 @@ export class MasterBuildingComponent {
.deleteMasterBuildingParam(row.id) .deleteMasterBuildingParam(row.id)
.subscribe((res) => { .subscribe((res) => {
this.fetchData(); this.fetchData();
}, (error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}); });
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -60,7 +60,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -69,13 +69,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -84,13 +84,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Icon</span> <span class="style-custom-label">Icon</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -99,13 +99,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff">{{ value}}</p> <p class="style-custom-label">{{ value}}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -114,7 +114,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -124,8 +124,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -134,8 +135,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -33,7 +33,8 @@ export class MasterCategoryComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Category", mainlabel: "Master Category",
links: [ links: [
@@ -57,7 +58,9 @@ export class MasterCategoryComponent implements OnInit {
(item) => item.name === "master_category" (item) => item.name === "master_category"
); );
// this.filteredRows = this.dataMasterCategori.headerDetailParam; // this.filteredRows = this.dataMasterCategori.headerDetailParam;
this.filteredRows = this.dataMasterCategori.headerDetailParam.sort((a, b) => b.id - a.id); this.filteredRows = this.dataMasterCategori.headerDetailParam.sort(
(a, b) => b.id - a.id
);
}); });
} }
@@ -77,7 +80,7 @@ export class MasterCategoryComponent implements OnInit {
rowContainsSearchTerm(row: any): boolean { rowContainsSearchTerm(row: any): boolean {
const searchTermLC = this.searchTerm.toLowerCase(); const searchTermLC = this.searchTerm.toLowerCase();
console.log(searchTermLC); console.log(searchTermLC);
return Object.values(row).some( return Object.values(row).some(
(value) => (value) =>
value !== null && value.toString().toLowerCase().includes(searchTermLC) value !== null && value.toString().toLowerCase().includes(searchTermLC)
@@ -87,8 +90,8 @@ export class MasterCategoryComponent implements OnInit {
openAddMasterModal() { openAddMasterModal() {
const modalRef = this.modalService.open(AddEditMasterComponent, { const modalRef = this.modalService.open(AddEditMasterComponent, {
size: "lg", size: "lg",
backdrop: 'static', // Add this line backdrop: "static", // Add this line
keyboard: false // Add this line keyboard: false, // Add this line
}); });
modalRef.componentInstance.headerId = this.dataMasterCategori.id; modalRef.componentInstance.headerId = this.dataMasterCategori.id;
@@ -96,24 +99,24 @@ export class MasterCategoryComponent implements OnInit {
modalRef.componentInstance.category = true; modalRef.componentInstance.category = true;
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService.postHeaderDetailParam(result).subscribe( if (
(res) => { this.filteredRows.some(
this.fetchData(); (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
this.toastr.success("Success", "Save Completed.", { )
timeOut: 2000, ) {
closeButton: true, this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
} else {
this.monitoringApiService
.postHeaderDetailParam(result)
.subscribe((res) => {
console.log(res);
this.fetchData();
}); });
}, }
(error) => {
console.error(error);
this.toastr.error("Error", "Something went wrong!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
}, },
(reason) => { (reason) => {
@@ -123,10 +126,12 @@ export class MasterCategoryComponent implements OnInit {
} }
editRow(row) { editRow(row) {
console.log(row);
const modalRef = this.modalService.open(AddEditMasterComponent, { const modalRef = this.modalService.open(AddEditMasterComponent, {
size: "lg", size: "lg",
backdrop: 'static', // Add this line backdrop: "static",
keyboard: false // Add this line keyboard: false,
}); });
modalRef.componentInstance.headerId = this.dataMasterCategori.id; modalRef.componentInstance.headerId = this.dataMasterCategori.id;
@@ -135,26 +140,38 @@ export class MasterCategoryComponent implements OnInit {
modalRef.componentInstance.category = true; modalRef.componentInstance.category = true;
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (
.putHeaderDetailParam(result, row.id) this.filteredRows.some(
.subscribe( (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
(res) => { )
this.fetchData(); ) {
this.toastr.success("Success", "Update Completed.", { if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
timeOut: 2000, this.monitoringApiService
closeButton: true, .putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
}); });
}, } else {
(error) => { if (
console.error(error); this.filteredRows.some(
this.toastr.error("Error", "Something went wrong!", { (value) =>
timeOut: 2000, value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true, closeButton: true,
}); });
} }
); }
} else {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
}, },
(reason) => { (reason) => {
@@ -176,7 +193,7 @@ export class MasterCategoryComponent implements OnInit {
}, },
(error) => { (error) => {
console.error(error); console.error(error);
this.toastr.error("Error", "Something went wrong!", { this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000, timeOut: 2000,
closeButton: true, closeButton: true,
}); });

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -60,7 +60,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -69,13 +69,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -84,13 +84,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -106,8 +106,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -116,8 +117,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -5,6 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from '../../service/monitoring-api.service';
import { LoginService } from '../../service/login.service'; import { LoginService } from '../../service/login.service';
import { ToastrService } from 'ngx-toastr';
@Component({ @Component({
selector: 'app-master-duration-use', selector: 'app-master-duration-use',
@@ -24,11 +25,13 @@ export class MasterDurationUseComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Duration Use", mainlabel: "Master Duration Use",
links: [ links: [
@@ -90,12 +93,27 @@ export class MasterDurationUseComponent {
(result) => { (result) => {
console.log(result); console.log(result);
if (result) { if (result) {
this.monitoringApiService if (result) {
.postHeaderDetailParam(result) if (this.filteredRows.some(value => value.name.trim().toLowerCase() === result.name.trim().toLowerCase())) {
.subscribe((res) => { this.toastr.error("Warning", "Data yang anda masukan double.", {
console.log(res); timeOut: 5000,
this.fetchData(); closeButton: true,
}); });
} else {
this.monitoringApiService
.postHeaderDetailParam(result)
.subscribe((res) => {
console.log(res);
this.fetchData();
});
}
}
// this.monitoringApiService
// .postHeaderDetailParam(result)
// .subscribe((res) => {
// console.log(res);
// this.fetchData();
// });
} }
}, },
(reason) => { (reason) => {
@@ -116,14 +134,38 @@ export class MasterDurationUseComponent {
modalRef.componentInstance.mode = "edit"; modalRef.componentInstance.mode = "edit";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (
.putHeaderDetailParam(result, row.id) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
console.log(res); )
this.fetchData(); ) {
}); if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
} else {
if (
this.filteredRows.some(
(value) =>
value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}
} else {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
}, },
(reason) => { (reason) => {
@@ -135,11 +177,22 @@ export class MasterDurationUseComponent {
deleteRow(row) { deleteRow(row) {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService.deleteHeaderDetailParam(row.id).subscribe(
.deleteHeaderDetailParam(row.id) (res) => {
.subscribe((res) => {
this.fetchData(); this.fetchData();
}); this.toastr.success("Success", "Delete Completed.", {
timeOut: 2000,
closeButton: true,
});
},
(error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -55,7 +55,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -64,13 +64,30 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="code"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span class="style-custom-label">Code</span>
</ng-template>
<ng-template
ngx-datatable-cell-template
let-value="value"
>
<p class="style-custom-label">
{{ value }}
</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -79,13 +96,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -96,7 +113,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -106,8 +123,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -116,8 +134,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -1,15 +1,16 @@
import { Component } from '@angular/core'; import { Component } from "@angular/core";
import { AddEditMasterComponent } from '../add-edit-master/add-edit-master.component'; import { AddEditMasterComponent } from "../add-edit-master/add-edit-master.component";
import { TableApiService } from 'src/app/_services/table-api.service'; import { TableApiService } from "src/app/_services/table-api.service";
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { Router } from '@angular/router'; import { Router } from "@angular/router";
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from "../../service/monitoring-api.service";
import { LoginService } from '../../service/login.service'; import { LoginService } from "../../service/login.service";
import { ToastrService } from "ngx-toastr";
@Component({ @Component({
selector: 'app-master-floor', selector: "app-master-floor",
templateUrl: './master-floor.component.html', templateUrl: "./master-floor.component.html",
styleUrls: ['./master-floor.component.css'] styleUrls: ["./master-floor.component.css"],
}) })
export class MasterFloorComponent { export class MasterFloorComponent {
data: any; data: any;
@@ -24,11 +25,13 @@ export class MasterFloorComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Floor", mainlabel: "Master Floor",
links: [ links: [
@@ -52,7 +55,9 @@ export class MasterFloorComponent {
(item) => item.name === "master_floor" (item) => item.name === "master_floor"
); );
// this.filteredRows = this.dataMasterCategori.headerDetailParam; // this.filteredRows = this.dataMasterCategori.headerDetailParam;
this.filteredRows = this.dataMasterCategori.headerDetailParam.sort((a, b) => b.id - a.id); this.filteredRows = this.dataMasterCategori.headerDetailParam.sort(
(a, b) => b.id - a.id
);
}); });
} }
@@ -80,12 +85,13 @@ export class MasterFloorComponent {
openAddMasterModal() { openAddMasterModal() {
const modalRef = this.modalService.open(AddEditMasterComponent, { const modalRef = this.modalService.open(AddEditMasterComponent, {
size: "lg", size: "lg",
backdrop: 'static', // Add this line backdrop: "static", // Add this line
keyboard: false // Add this line keyboard: false, // Add this line
}); });
modalRef.componentInstance.headerId = this.dataMasterCategori.id; modalRef.componentInstance.headerId = this.dataMasterCategori.id;
modalRef.componentInstance.mode = "add"; modalRef.componentInstance.mode = "add";
modalRef.componentInstance.floor = true;
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result); console.log(result);
@@ -93,10 +99,23 @@ export class MasterFloorComponent {
this.monitoringApiService this.monitoringApiService
.postHeaderDetailParam(result) .postHeaderDetailParam(result)
.subscribe((res) => { .subscribe((res) => {
console.log(res);
this.fetchData(); this.fetchData();
if (res.status === 400) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}); });
} }
// if (result) {
// this.monitoringApiService
// .postHeaderDetailParam(result)
// .subscribe((res) => {
// console.log(res);
// this.fetchData();
// });
// }
}, },
(reason) => { (reason) => {
console.log(`Dismissed: ${reason}`); console.log(`Dismissed: ${reason}`);
@@ -107,22 +126,27 @@ export class MasterFloorComponent {
editRow(row) { editRow(row) {
const modalRef = this.modalService.open(AddEditMasterComponent, { const modalRef = this.modalService.open(AddEditMasterComponent, {
size: "lg", size: "lg",
backdrop: 'static', // Add this line backdrop: "static", // Add this line
keyboard: false // Add this line keyboard: false, // Add this line
}); });
modalRef.componentInstance.headerId = this.dataMasterCategori.id; modalRef.componentInstance.headerId = this.dataMasterCategori.id;
modalRef.componentInstance.dataRow = row; modalRef.componentInstance.dataRow = row;
modalRef.componentInstance.mode = "edit"; modalRef.componentInstance.mode = "edit";
modalRef.componentInstance.floor = true;
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService this.monitoringApiService
.putHeaderDetailParam(result, row.id) .putHeaderDetailParam(result, row.id)
.subscribe((res) => { .subscribe((res) => {
console.log(res);
this.fetchData(); this.fetchData();
if (res.status === 400) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}); });
} }
}, },
@@ -135,11 +159,22 @@ export class MasterFloorComponent {
deleteRow(row) { deleteRow(row) {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService.deleteHeaderDetailParam(row.id).subscribe(
.deleteHeaderDetailParam(row.id) (res) => {
.subscribe((res) => {
this.fetchData(); this.fetchData();
}); this.toastr.success("Success", "Delete Completed.", {
timeOut: 2000,
closeButton: true,
});
},
(error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -10,7 +10,7 @@
class="col-12" class="col-12"
*blockUI="'zeroConfiguration'; message: 'Loading'" *blockUI="'zeroConfiguration'; message: 'Loading'"
> >
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -28,9 +28,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -64,7 +64,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -73,13 +73,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -88,13 +88,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -105,7 +105,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -115,8 +115,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -125,8 +126,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -5,6 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from '../../service/monitoring-api.service';
import { LoginService } from '../../service/login.service'; import { LoginService } from '../../service/login.service';
import { ToastrService } from 'ngx-toastr';
@Component({ @Component({
selector: 'app-master-role', selector: 'app-master-role',
@@ -24,11 +25,13 @@ export class MasterRoleComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService,
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Role", mainlabel: "Master Role",
links: [ links: [
@@ -90,13 +93,28 @@ export class MasterRoleComponent {
(result) => { (result) => {
console.log(result); console.log(result);
if (result) { if (result) {
this.monitoringApiService if (this.filteredRows.some(value => value.name.trim().toLowerCase() === result.name.trim().toLowerCase())) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
} else {
this.monitoringApiService
.postHeaderDetailParam(result) .postHeaderDetailParam(result)
.subscribe((res) => { .subscribe((res) => {
console.log(res); console.log(res);
this.fetchData(); this.fetchData();
}); });
}
} }
// if (result) {
// this.monitoringApiService
// .postHeaderDetailParam(result)
// .subscribe((res) => {
// console.log(res);
// this.fetchData();
// });
// }
}, },
(reason) => { (reason) => {
console.log(`Dismissed: ${reason}`); console.log(`Dismissed: ${reason}`);
@@ -116,14 +134,38 @@ export class MasterRoleComponent {
modalRef.componentInstance.mode = "edit"; modalRef.componentInstance.mode = "edit";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (
.putHeaderDetailParam(result, row.id) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
console.log(res); )
this.fetchData(); ) {
}); if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
} else {
if (
this.filteredRows.some(
(value) =>
value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}
} else {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
}, },
(reason) => { (reason) => {
@@ -135,11 +177,22 @@ export class MasterRoleComponent {
deleteRow(row) { deleteRow(row) {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService.deleteHeaderDetailParam(row.id).subscribe(
.deleteHeaderDetailParam(row.id) (res) => {
.subscribe((res) => {
this.fetchData(); this.fetchData();
}); this.toastr.success("Success", "Delete Completed.", {
timeOut: 2000,
closeButton: true,
});
},
(error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
} }
} }

View File

@@ -1,14 +1,19 @@
<div class="modal-header" style="background-color: #000000 !important"> <div class="modal-header" style="background-color: #fbfbfb !important">
<h4 class="modal-title" style="color: #ffffff">{{labelRoom}}</h4> <h4 class="modal-title" style="color: #242222">{{ labelRoom }}</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"> <button
type="button"
class="close"
aria-label="Close"
(click)="activeModal.dismiss('Cross click')"
>
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div> </div>
<div class="modal-body" style="background-color: #000000 !important"> <div class="modal-body" style="background-color: #fbfbfb !important">
<form [formGroup]="myForm"> <form [formGroup]="myForm">
<div class="form-row"> <div class="form-row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="name" style="color: #ffffff">Name Room:</label> <label for="name" style="color: #242222">Name Room:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
@@ -24,7 +29,24 @@
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="statusId" style="color: #ffffff">Building:</label> <label for="name" style="color: #242222">Room Code:</label>
<input
type="text"
class="form-control"
id="code"
formControlName="code"
maxlength="10"
(input)="toUppercase($event)"
/>
<div
*ngIf="myForm.get('code').touched && myForm.get('code').invalid"
class="text-danger"
>
Code is required.
</div>
</div>
<!-- <div class="form-group col-md-6">
<label for="statusId" style="color: #242222">Building:</label>
<select <select
id="projectinput5" id="projectinput5"
class="form-control" class="form-control"
@@ -42,9 +64,9 @@
> >
Building is required. Building is required.
</div> </div>
</div> </div> -->
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="description" style="color: #ffffff">Description:</label> <label for="description" style="color: #242222">Description:</label>
<input <input
type="text" type="text"
class="form-control" class="form-control"
@@ -52,12 +74,18 @@
formControlName="description" formControlName="description"
maxlength="50" maxlength="50"
/> />
<div *ngIf="myForm.get('description').touched && myForm.get('description').invalid" class="text-danger"> <div
*ngIf="
myForm.get('description').touched &&
myForm.get('description').invalid
"
class="text-danger"
>
Description is required. Description is required.
</div> </div>
</div> </div>
<div class="form-group col-md-6"> <!-- <div class="form-group col-md-6">
<label for="statusId" style="color: #ffffff">Status:</label> <label for="statusId" style="color: #242222">Status:</label>
<select <select
id="projectinput5" id="projectinput5"
class="form-control" class="form-control"
@@ -70,18 +98,18 @@
<div *ngIf="myForm.get('statusId').touched && myForm.get('statusId').invalid" class="text-danger"> <div *ngIf="myForm.get('statusId').touched && myForm.get('statusId').invalid" class="text-danger">
Status is required. Status is required.
</div> </div>
</div> </div> -->
</div> </div>
</form> </form>
</div> </div>
<div class="modal-footer" style="background-color: #000000 !important"> <div class="modal-footer" style="background-color: #fbfbfb !important">
<button <button
type="button" type="button"
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #c3f164 !important; color: #242222 !important;
background-color: #000000 !important; background-color: #fbfbfb !important;
border-color: #c3f164 !important; border-color: #fbfbfb !important;
" "
(click)="activeModal.dismiss('Cross click')" (click)="activeModal.dismiss('Cross click')"
> >
@@ -90,7 +118,7 @@
<button <button
type="button" type="button"
class="btn btn-primary" class="btn btn-primary"
style="color: #000000 !important; background-color: #c3f164 !important" style="color: #ffffff !important; background-color: #37a647 !important"
(click)="addRow()" (click)="addRow()"
> >
Save Save

View File

@@ -30,15 +30,15 @@ export class AddEditMasterRoomComponent {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.createForm(); this.createForm();
this.listDataStatus(); this.listDataStatus();
this.listDataBuilding(); this.listDataBuilding();
console.log(this.dataRow); if (this.mode === "add") {
if (this.mode) {
this.labelRoom = "Add New Row" this.labelRoom = "Add New Row"
} else { } else {
this.labelRoom = "Add New Row" this.labelRoom = "Edit Row"
} }
if (this.dataRow) { if (this.dataRow) {
this.editForm(); this.editForm();
@@ -48,8 +48,7 @@ export class AddEditMasterRoomComponent {
createForm() { createForm() {
this.myForm = this.fb.group({ this.myForm = this.fb.group({
name: ["", Validators.required], name: ["", Validators.required],
statusId: ["", Validators.required], code: ["", Validators.required],
buildingId: ["", Validators.required],
description: ["", Validators.required], description: ["", Validators.required],
}); });
} }
@@ -59,13 +58,18 @@ export class AddEditMasterRoomComponent {
this.myForm = this.fb.group({ this.myForm = this.fb.group({
id: this.dataRow.id, id: this.dataRow.id,
name: [this.dataRow.roomEntity.name, Validators.required], name: [this.dataRow.name, Validators.required],
statusId: [this.dataRow.statusId, Validators.required], code: [this.dataRow.code, Validators.required],
buildingId: [this.dataRow.buildingId, Validators.required], description: [this.dataRow.description, Validators.required],
description: [this.dataRow.roomEntity.description, Validators.required],
}); });
} }
toUppercase(event: Event) {
const input = event.target as HTMLInputElement;
input.value = input.value.toUpperCase();
this.myForm.get('code').setValue(input.value);
}
listDataStatus() { listDataStatus() {
this.monitoringApiService.getMasterData().subscribe((res) => { this.monitoringApiService.getMasterData().subscribe((res) => {
this.data = res.results.data; this.data = res.results.data;

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -42,7 +42,7 @@
<div class="card-dashboard"> <div class="card-dashboard">
<ngx-datatable <ngx-datatable
class="bootstrap table-bordered" class="bootstrap table-bordered"
[limit]="5" [limit]="10"
[rows]="filteredRows" [rows]="filteredRows"
[columnMode]="'force'" [columnMode]="'force'"
[headerHeight]="50" [headerHeight]="50"
@@ -60,79 +60,64 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
name="roomEntity" name="name"
[flexGrow]="1" [flexGrow]="1"
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Room</span> <span class="style-custom-label">Room</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value.name }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
name="buildingEntity" name="code"
[flexGrow]="1" [flexGrow]="1"
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Building</span> <span class="style-custom-label">Code Room</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value.name }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
name="roomEntity" name="description"
[flexGrow]="1" [flexGrow]="1"
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Description</span> <span class="style-custom-label">Description</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template
let-value="value" let-value="value"
ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value.description }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column
name="statusEntity"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span>
</ng-template>
<ng-template
ngx-datatable-cell-template
let-value="value"
>
<p style="color: #ffffff">{{ value.name }}</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
name="Actions" name="Actions"
[flexGrow]="1" [flexGrow]="1"
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -142,8 +127,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -152,8 +138,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -5,6 +5,7 @@ import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { BuildingService } from "../../service/monitoring-api.service"; import { BuildingService } from "../../service/monitoring-api.service";
import { LoginService } from "../../service/login.service"; import { LoginService } from "../../service/login.service";
import { ToastrService } from "ngx-toastr";
@Component({ @Component({
selector: "app-master-room", selector: "app-master-room",
@@ -21,11 +22,13 @@ export class MasterRoomComponent {
constructor( constructor(
private modalService: NgbModal, private modalService: NgbModal,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Room", mainlabel: "Master Room",
links: [ links: [
@@ -43,7 +46,7 @@ export class MasterRoomComponent {
} }
fetchData() { fetchData() {
this.monitoringApiService.getBuildingRoomList().subscribe((res) => { this.monitoringApiService.getMasterRoomData().subscribe((res) => {
this.data = res; this.data = res;
this.filteredRows = this.data.results.data.sort((a, b) => b.id - a.id); this.filteredRows = this.data.results.data.sort((a, b) => b.id - a.id);
// this.data.results.data.sort((a, b) => b.id - a.id); // this.data.results.data.sort((a, b) => b.id - a.id);
@@ -64,18 +67,17 @@ export class MasterRoomComponent {
rowContainsSearchTerm(row: any, searchTermLC: string): boolean { rowContainsSearchTerm(row: any, searchTermLC: string): boolean {
return ( return (
row.roomEntity.name.toLowerCase().includes(searchTermLC) || row.name.toLowerCase().includes(searchTermLC) ||
row.roomEntity.description.toLowerCase().includes(searchTermLC) || row.description.toLowerCase().includes(searchTermLC) ||
row.buildingEntity.name.toLowerCase().includes(searchTermLC) || row.code.toLowerCase().includes(searchTermLC)
row.statusEntity.name.toLowerCase().includes(searchTermLC)
); );
} }
openAddMasterModal() { openAddMasterModal() {
const modalRef = this.modalService.open(AddEditMasterRoomComponent, { const modalRef = this.modalService.open(AddEditMasterRoomComponent, {
size: "lg", size: "lg",
backdrop: "static", // Add this line backdrop: "static",
keyboard: false, // Add this line keyboard: false,
}); });
modalRef.componentInstance.mode = "add"; modalRef.componentInstance.mode = "add";
@@ -84,21 +86,19 @@ export class MasterRoomComponent {
if (result) { if (result) {
const filteredData = { const filteredData = {
name: result.name, name: result.name,
code: result.code.trim(),
description: result.description, description: result.description,
}; };
this.monitoringApiService this.monitoringApiService
.postMasterRoomParam(filteredData) .postMasterRoomParam(filteredData)
.subscribe((res) => { .subscribe((res) => {
const transformedData = { this.fetchData();
buildingId: result.buildingId, }, (error) => {
roomId: [res.data.id], console.error(error);
statusId: result.statusId, this.toastr.error("Error", error.error.message, {
}; timeOut: 2000,
this.monitoringApiService closeButton: true,
.postBatchBuilding(transformedData) });
.subscribe((res) => {
this.fetchData();
});
}); });
} }
}, },
@@ -109,8 +109,6 @@ export class MasterRoomComponent {
} }
editRow(row) { editRow(row) {
console.log(row);
const modalRef = this.modalService.open(AddEditMasterRoomComponent, { const modalRef = this.modalService.open(AddEditMasterRoomComponent, {
size: "lg", size: "lg",
backdrop: "static", // Add this line backdrop: "static", // Add this line
@@ -122,26 +120,22 @@ export class MasterRoomComponent {
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
if (result) { if (result) {
console.log(result);
const filteredData = { const filteredData = {
id: result.id, id: result.roomId,
name: result.name, name: result.name,
code: result.code.trim(),
description: result.description, description: result.description,
}; };
this.monitoringApiService this.monitoringApiService
.putMasterRoomParam(filteredData, row.id) .putMasterRoomParam(filteredData, row.id)
.subscribe((res) => { .subscribe((res) => {
console.log(res); this.fetchData();
const transformedData = { }, (error) => {
buildingId: result.buildingId, console.error(error);
roomId: res.data.id, this.toastr.error("Error", error.error.message, {
statusId: result.statusId, timeOut: 2000,
}; closeButton: true,
this.monitoringApiService });
.puttBuildingRoom(transformedData, row.id)
.subscribe((res) => {
this.fetchData();
});
}); });
} }
}, },
@@ -155,14 +149,19 @@ export class MasterRoomComponent {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService
.deleteHeaderDetailParam(row.roomEntity.id) .deleteRoom(row.id)
.subscribe((res) => { .subscribe(
this.monitoringApiService (res) => {
.deleteRoomBuilding(row.id) this.fetchData();
.subscribe((res) => { },
this.fetchData(); (error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
}); });
}); }
);
} }
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -60,7 +60,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -69,13 +69,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -84,13 +84,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff"> <p class="style-custom-label">
{{ value }} {{ value }}
</p> </p>
</ng-template> </ng-template>
@@ -101,7 +101,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -111,8 +111,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -121,8 +122,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -5,6 +5,7 @@ import { TableApiService } from 'src/app/_services/table-api.service';
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from '../../service/monitoring-api.service';
import { AddEditMasterComponent } from '../add-edit-master/add-edit-master.component'; import { AddEditMasterComponent } from '../add-edit-master/add-edit-master.component';
import { LoginService } from '../../service/login.service'; import { LoginService } from '../../service/login.service';
import { ToastrService } from 'ngx-toastr';
@Component({ @Component({
selector: 'app-master-status', selector: 'app-master-status',
@@ -24,11 +25,13 @@ export class MasterStatusComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService,
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Status", mainlabel: "Master Status",
links: [ links: [
@@ -90,13 +93,28 @@ export class MasterStatusComponent {
(result) => { (result) => {
console.log(result); console.log(result);
if (result) { if (result) {
this.monitoringApiService if (this.filteredRows.some(value => value.name.trim().toLowerCase() === result.name.trim().toLowerCase())) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
} else {
this.monitoringApiService
.postHeaderDetailParam(result) .postHeaderDetailParam(result)
.subscribe((res) => { .subscribe((res) => {
console.log(res); console.log(res);
this.fetchData(); this.fetchData();
}); });
}
} }
// if (result) {
// this.monitoringApiService
// .postHeaderDetailParam(result)
// .subscribe((res) => {
// console.log(res);
// this.fetchData();
// });
// }
}, },
(reason) => { (reason) => {
console.log(`Dismissed: ${reason}`); console.log(`Dismissed: ${reason}`);
@@ -116,14 +134,38 @@ export class MasterStatusComponent {
modalRef.componentInstance.mode = "edit"; modalRef.componentInstance.mode = "edit";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (
.putHeaderDetailParam(result, row.id) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
console.log(res); )
this.fetchData(); ) {
}); if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
} else {
if (
this.filteredRows.some(
(value) =>
value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}
} else {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
}, },
(reason) => { (reason) => {
@@ -135,11 +177,22 @@ export class MasterStatusComponent {
deleteRow(row) { deleteRow(row) {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService.deleteHeaderDetailParam(row.id).subscribe(
.deleteHeaderDetailParam(row.id) (res) => {
.subscribe((res) => {
this.fetchData(); this.fetchData();
}); this.toastr.success("Success", "Delete Completed.", {
timeOut: 2000,
closeButton: true,
});
},
(error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -60,7 +60,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -69,13 +69,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -84,14 +84,14 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff"> <p class="style-custom-label">
{{ value === "2" ? "Aktif" : "Nonaktif" }} {{ value }}
</p> </p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -101,7 +101,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -111,8 +111,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -121,8 +122,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -5,6 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from '../../service/monitoring-api.service';
import { LoginService } from '../../service/login.service'; import { LoginService } from '../../service/login.service';
import { ToastrService } from 'ngx-toastr';
@Component({ @Component({
selector: 'app-master-type', selector: 'app-master-type',
@@ -24,11 +25,13 @@ export class MasterTypeComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Type", mainlabel: "Master Type",
links: [ links: [
@@ -88,15 +91,29 @@ export class MasterTypeComponent {
modalRef.componentInstance.mode = "add"; modalRef.componentInstance.mode = "add";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (this.filteredRows.some(value => value.name.trim().toLowerCase() === result.name.trim().toLowerCase())) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
} else {
this.monitoringApiService
.postHeaderDetailParam(result) .postHeaderDetailParam(result)
.subscribe((res) => { .subscribe((res) => {
console.log(res); console.log(res);
this.fetchData(); this.fetchData();
}); });
}
} }
// if (result) {
// this.monitoringApiService
// .postHeaderDetailParam(result)
// .subscribe((res) => {
// console.log(res);
// this.fetchData();
// });
// }
}, },
(reason) => { (reason) => {
console.log(`Dismissed: ${reason}`); console.log(`Dismissed: ${reason}`);
@@ -116,14 +133,38 @@ export class MasterTypeComponent {
modalRef.componentInstance.mode = "edit"; modalRef.componentInstance.mode = "edit";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (
.putHeaderDetailParam(result, row.id) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
console.log(res); )
this.fetchData(); ) {
}); if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
} else {
if (
this.filteredRows.some(
(value) =>
value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}
} else {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
}, },
(reason) => { (reason) => {
@@ -135,11 +176,22 @@ export class MasterTypeComponent {
deleteRow(row) { deleteRow(row) {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService.deleteHeaderDetailParam(row.id).subscribe(
.deleteHeaderDetailParam(row.id) (res) => {
.subscribe((res) => {
this.fetchData(); this.fetchData();
}); this.toastr.success("Success", "Delete Completed.", {
timeOut: 2000,
closeButton: true,
});
},
(error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
} }
} }

View File

@@ -271,19 +271,21 @@
ul ul
li:not(.disabled):hover li:not(.disabled):hover
a { a {
background-color: #252525; background-color: #37A647;
font-weight: bold; font-weight: bold;
color: white; color: white;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer { :host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #252525; background: #DDE1E6;
color: #ededed; color: #242222;
margin-top: -1px; margin-top: -1px;
overflow: inherit; overflow: inherit;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header { :host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold; font-weight: bold;
height: unset !important; height: unset !important;
overflow: inherit; overflow: inherit;
@@ -311,14 +313,38 @@
} }
:host ::ng-deep .ng-select .ng-select-container { :host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; color: #242222 !important;
background-color: #252525 !important; background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: rgba(190, 242, 100, 0.11); /* Black color for table rows */ background-color: #FBFBFB; /* Black color for table rows */
} }
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover { :host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #1a1a1a; /* Darker black for hover effect */ background-color: #DDE1E6; /* Darker black for hover effect */
} }
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB !important">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row mb-2"> <div class="row mb-2">
@@ -24,9 +24,9 @@
<button <button
class="btn btn-secondary" class="btn btn-secondary"
style=" style="
color: #000000 !important; color: #ffffff !important;
border-color: #bef264 !important; border-color: #37A647 !important;
background-color: #bef264 !important; background-color: #37A647 !important;
" "
(click)="openAddMasterModal()" (click)="openAddMasterModal()"
> >
@@ -60,7 +60,7 @@
ngx-datatable-cell-template ngx-datatable-cell-template
let-rowIndex="rowIndex" let-rowIndex="rowIndex"
> >
<p style="color: #ffffff">{{ rowIndex + 1 }}</p> <p class="style-custom-label">{{ rowIndex + 1 }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -69,13 +69,13 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Name</span> <span class="style-custom-label">Name</span>
</ng-template> </ng-template>
<ng-template <ng-template
let-value="value" let-value="value"
ngx-datatable-cell-template ngx-datatable-cell-template
> >
<p style="color: #ffffff">{{ value }}</p> <p class="style-custom-label">{{ value }}</p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
<ngx-datatable-column <ngx-datatable-column
@@ -84,14 +84,14 @@
[minWidth]="90" [minWidth]="90"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Status</span> <span class="style-custom-label">Status</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
let-value="value" let-value="value"
> >
<p style="color: #ffffff"> <p class="style-custom-label">
{{ value === "2" ? "Aktif" : "Nonaktif" }} {{ value }}
</p> </p>
</ng-template> </ng-template>
</ngx-datatable-column> </ngx-datatable-column>
@@ -101,7 +101,7 @@
[minWidth]="150" [minWidth]="150"
> >
<ng-template ngx-datatable-header-template> <ng-template ngx-datatable-header-template>
<span style="color: #ffffff">Actions</span> <span class="style-custom-label">Actions</span>
</ng-template> </ng-template>
<ng-template <ng-template
ngx-datatable-cell-template ngx-datatable-cell-template
@@ -111,8 +111,9 @@
<button <button
class="btn btn-sm btn-warning mr-1" class="btn btn-sm btn-warning mr-1"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="editRow(row)" (click)="editRow(row)"
> >
@@ -121,8 +122,9 @@
<button <button
class="btn btn-sm btn-danger" class="btn btn-sm btn-danger"
style=" style="
background-color: #000000 !important; color: #37a647 !important;
border-color: #bef264 !important; border-color: #DDE1E6 !important;
background-color: #DDE1E6 !important;
" "
(click)="deleteRow(row)" (click)="deleteRow(row)"
> >

View File

@@ -5,6 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BuildingService } from '../../service/monitoring-api.service'; import { BuildingService } from '../../service/monitoring-api.service';
import { LoginService } from '../../service/login.service'; import { LoginService } from '../../service/login.service';
import { ToastrService } from 'ngx-toastr';
@Component({ @Component({
selector: 'app-master-voltage', selector: 'app-master-voltage',
@@ -24,11 +25,13 @@ export class MasterVoltageComponent {
private modalService: NgbModal, private modalService: NgbModal,
private router: Router, private router: Router,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private authService: LoginService private authService: LoginService,
private toastr: ToastrService,
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Master Voltage", mainlabel: "Master Voltage",
links: [ links: [
@@ -88,14 +91,20 @@ export class MasterVoltageComponent {
modalRef.componentInstance.mode = "add"; modalRef.componentInstance.mode = "add";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (this.filteredRows.some(value => value.name.trim().toLowerCase() === result.name.trim().toLowerCase())) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
} else {
this.monitoringApiService
.postHeaderDetailParam(result) .postHeaderDetailParam(result)
.subscribe((res) => { .subscribe((res) => {
console.log(res); console.log(res);
this.fetchData(); this.fetchData();
}); });
}
} }
}, },
(reason) => { (reason) => {
@@ -116,14 +125,38 @@ export class MasterVoltageComponent {
modalRef.componentInstance.mode = "edit"; modalRef.componentInstance.mode = "edit";
modalRef.result.then( modalRef.result.then(
(result) => { (result) => {
console.log(result);
if (result) { if (result) {
this.monitoringApiService if (
.putHeaderDetailParam(result, row.id) this.filteredRows.some(
.subscribe((res) => { (value) => value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
console.log(res); )
this.fetchData(); ) {
}); if (row.name.trim().toLowerCase() === result.name.trim().toLowerCase()) {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
} else {
if (
this.filteredRows.some(
(value) =>
value.name.trim().toLowerCase() === result.name.trim().toLowerCase()
)
) {
this.toastr.error("Warning", "Data yang anda masukan double.", {
timeOut: 5000,
closeButton: true,
});
}
}
} else {
this.monitoringApiService
.putHeaderDetailParam(result, row.id)
.subscribe((res) => {
this.fetchData();
});
}
} }
}, },
(reason) => { (reason) => {
@@ -135,11 +168,22 @@ export class MasterVoltageComponent {
deleteRow(row) { deleteRow(row) {
const confirmDelete = confirm("Are you sure you want to delete this item?"); const confirmDelete = confirm("Are you sure you want to delete this item?");
if (confirmDelete) { if (confirmDelete) {
this.monitoringApiService this.monitoringApiService.deleteHeaderDetailParam(row.id).subscribe(
.deleteHeaderDetailParam(row.id) (res) => {
.subscribe((res) => {
this.fetchData(); this.fetchData();
}); this.toastr.success("Success", "Delete Completed.", {
timeOut: 2000,
closeButton: true,
});
},
(error) => {
console.error(error);
this.toastr.error("Error", "Data sedang digunakan!", {
timeOut: 2000,
closeButton: true,
});
}
);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
:host ::ng-deep .gap_fl_btn { :host ::ng-deep .gap_fl_btn {
margin: 0 0.3rem; margin: 0 0.3rem;
} }
:host ::ng-deep .block-ui-wrapper { :host ::ng-deep .block-ui-wrapper {
@@ -7,20 +7,70 @@
} }
:host ::ng-deep .donut-chart1 .ct-series-a .ct-slice-donut { :host ::ng-deep .donut-chart1 .ct-series-a .ct-slice-donut {
stroke: #BEF264; stroke: #37A647;
stroke-width: 35px !important; stroke-width: 50px !important;
} }
:host ::ng-deep .donut-chart1 .ct-series-b .ct-slice-donut { :host ::ng-deep .donut-chart1 .ct-series-b .ct-slice-donut {
stroke: #ffffff; stroke: #ffffff;
stroke-width: 35px !important; stroke-width: 50px !important;
} }
.btn-no-hover { .btn-no-hover {
border: none !important; border: none !important;
} }
.btn-no-hover:hover { .custom-card-header {
background-color: #dde1e6 !important;
}
.header-title {
font-family: "Open Sans", sans-serif !important;
color: #242222 !important;
font-weight: 600 !important;
font-size: 20px !important;
}
.header-subtitle {
font-family: "Open Sans", sans-serif !important;
color: #242222 !important;
font-weight: 600 !important;
font-size: 24px !important;
}
.custom-divider {
border-top: 6px solid rgb(0, 0, 0);
}
.custom-total {
font-family: "Open Sans", sans-serif !important;
font-size: 40px !important;
color: #242222 !important;
font-weight: 800 !important;
}
.custom-label-chart {
font-family: "Open Sans", sans-serif !important;
font-size: 20px !important;
color: #242222 !important;
}
.btn-room {
background-color: #2f5137 !important;
color: #ffffff;
width: 163px;
border-radius: 16px;
}
.btn-detail {
background-color: transparent !important;
border-color: #242222 !important;
color: #242222;
width: 163px;
border-radius: 16px;
}
/* .btn-no-hover:hover {
background-color: transparent !important; background-color: transparent !important;
color: inherit !important; color: inherit !important;
} }
@@ -28,4 +78,4 @@
.btn-primary.round:hover { .btn-primary.round:hover {
color: #BEF264 !important; color: #BEF264 !important;
border-color: #BEF264 !important; border-color: #BEF264 !important;
} } */

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important;"> <div class="app-content content" style="background-color: #fbfbfb">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -6,41 +6,98 @@
<div class="content-body"> <div class="content-body">
<section id="social-cards"> <section id="social-cards">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-md-6"> <div class="col-3">
<input <div class="form-group">
type="text" <ng-select
class="form-control" class="select-custom"
placeholder="Search..." [items]="dataBuildingList"
[(ngModel)]="searchTerm" [searchable]="true"
(input)="filterRows()" bindLabel="name"
/> bindValue="id"
placeholder="Select Building"
[(ngModel)]="buildingSelected"
(change)="buildingChange($event)"
>
</ng-select>
</div>
</div>
<div class="col-3">
<div class="form-group">
<ng-select
class="select-custom"
[items]="dataFloorList"
[searchable]="true"
[disabled]="disableFloorList"
bindLabel="name"
bindValue="id"
placeholder="Select Floor"
[(ngModel)]="floorSelected"
>
</ng-select>
</div>
</div>
<div class="col-3 text-left">
<div class="d-flex">
<button
type="button"
class="btn ml-2"
(click)="doFilter()"
style="
background-color: #37a647 !important;
border-color: #37a647 !important;
border-radius: 12px;
color: #ffffff;
"
[disabled]="spinnerFilterActive"
>
<i
class="la la-search"
style="color: #ffffff !important"
*ngIf="!spinnerFilterActive"
></i>
<i
class="la la-spinner spinner"
style="color: #ffffff !important"
*ngIf="spinnerFilterActive"
></i>
</button>
<button
type="button"
class="btn ml-2"
style="
background-color: #fbfbfb !important;
border-color: #242222 !important;
color: #242222;
border-radius: 12px;
"
>
Cancel
</button>
</div>
</div> </div>
</div> </div>
<div class="row mt-2"> <div class="row mt-2">
<div <div
class="col-xl-4 col-md-6 col-12" class="col-12 col-sm-12 col-md-12 col-lg-6 col-xl-4"
*ngFor="let data of filteredRows" *ngFor="let data of filteredRows"
> >
<div class="card" style="background-color: #252525 !important; border-radius: 10px;"> <div
<div class="card-header mb-2" style="background-color: #252525 !important;"> class="card"
style="background-color: #dde1e6 !important; border-radius: 10px"
>
<div class="card-header mb-2 custom-card-header">
<div class="row"> <div class="row">
<div class="col-12 text-center"> <div class="col-12 text-center">
<h4 <h4 class="header-title">{{labelData}}</h4>
class="text-muted mb-1 font-weight-bold" <h3 class="header-subtitle">
style="font-family: Montserrat, sans-serif; color: #ffffff !important;"
>
Building
</h4>
<h3
class="text-muted mb-0 open-sans"
style="font-family: Open Sans, sans-serif; color: #ffffff !important; font-weight: 600;"
>
{{ data.build_name ? data.build_name : data.name }} {{ data.build_name ? data.build_name : data.name }}
</h3> </h3>
</div> </div>
</div> </div>
<hr style="border-top: 4px solid #ffffff; border-color: #ffffff !important;" /> <hr class="custom-divider" />
</div> </div>
<div class="card-content"> <div class="card-content">
<div class="donut-chart1"> <div class="donut-chart1">
<x-chartist <x-chartist
@@ -57,36 +114,27 @@
class="text-center" class="text-center"
style=" style="
position: absolute; position: absolute;
top: 65%; top: 73%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
" "
> >
<h3 <h3 class="custom-total">{{ data.total }} KWH</h3>
class="display-4 blue-grey darken-1" <h6 class="custom-label-chart">Consumption</h6>
style="font-size: 2em; color: #ffffff !important;"
>
{{ data.total }} kWh
</h3>
<h6 style="color: #ffffff !important;">Consumption</h6>
</div> </div>
<div class="form-group text-center"> <div class="form-group text-center">
<button <!-- <button
type="button" type="button"
class="btn btn-primary round btn-min-width mr-1 mb-1" class="btn btn-min-width mr-1 mb-1 btn-room"
(click)="viewRoom(data)" (click)="viewRoom(data)"
ngbTooltip="Room"
style="background-color: #ffffff !important; color: #000000;"
> >
Room Room
</button> </button> -->
<button <button
type="button" type="button"
class="btn btn-success round btn-min-width mr-1 mb-1" class="btn btn-min-width mr-1 mb-1 btn-room"
(click)="viewRow(data)" (click)="viewDetail(data)"
ngbTooltip="Detail"
style="background-color: #BEF264 !important; color: #000000;"
> >
Detail Detail
</button> </button>
@@ -96,6 +144,20 @@
</div> </div>
</div> </div>
</section> </section>
<section id="configuration">
<div class="row">
<div class="col-12" *ngIf="filteredRows?.length === 0">
<div class="card" style="background-color: #DDE1E6; min-height: 200px;">
<div class="card-content">
<div class="card-body">
<p class="text-center" style="color: #242222;">No data available</p>
</div>
</div>
</div>
</div>
</div>
</section>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,6 +3,7 @@ import { TableMonitoringService } from "../monitoring.service";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { BuildingService } from "../../service/monitoring-api.service"; import { BuildingService } from "../../service/monitoring-api.service";
import { LoginService } from "../../service/login.service"; import { LoginService } from "../../service/login.service";
import { DeviceService } from "../../service/device.service";
@Component({ @Component({
selector: "app-building", selector: "app-building",
@@ -10,7 +11,6 @@ import { LoginService } from "../../service/login.service";
styleUrls: ["./building.component.css"], styleUrls: ["./building.component.css"],
}) })
export class BuildingComponent { export class BuildingComponent {
data: any;
public breadcrumb: any; public breadcrumb: any;
feedbacksdonutChart: any; feedbacksdonutChart: any;
donutChart1: any; donutChart1: any;
@@ -18,16 +18,27 @@ export class BuildingComponent {
topUseData: any; topUseData: any;
searchTerm: string = ""; searchTerm: string = "";
colorChart: string = ""; colorChart: string = "";
spinnerFilterActive = false;
typeData: any;
labelData: any;
disableFloorList = true;
dataBuildingList: any;
buildingSelected: any;
dataFloorList: any;
floorSelected: any;
constructor( constructor(
private monitoringService: TableMonitoringService, private monitoringService: TableMonitoringService,
private monitoringApiService: BuildingService, private monitoringApiService: BuildingService,
private deviceService: DeviceService,
private router: Router, private router: Router,
private authService: LoginService private authService: LoginService
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Dashboard", mainlabel: "Dashboard",
links: [ links: [
@@ -50,42 +61,83 @@ export class BuildingComponent {
showLabel: false, showLabel: false,
}, },
}; };
this.listBuilding();
this.dataListBuilding();
this.listBuilding(this.buildingSelected, this.floorSelected);
} }
listBuilding() { dataListBuilding() {
this.monitoringApiService.listBuilding().subscribe((res) => { this.monitoringApiService.getBuildingList().subscribe((data) => {
this.data = res.data; this.dataBuildingList = data.data.filter(
this.filteredRows = res.data; (item) => item.statusName.toLowerCase() === "aktif"
);
}); });
} }
// buildingData() { buildingChange(e) {
// this.monitoringApiService.getBuildingData().subscribe((res) => { if (e) {
// console.log(res); this.dataListFloor(e.id);
// }); this.disableFloorList = false;
// } this.floorSelected = null;
filterRows() {
if (!this.searchTerm) {
this.filteredRows = [...this.data];
} else { } else {
this.filteredRows = this.data.filter((row) => this.floorSelected = null;
this.rowContainsSearchTerm(row) this.disableFloorList = true;
);
} }
} }
rowContainsSearchTerm(row: any): boolean { dataListFloor(buildingId) {
const searchTermLC = this.searchTerm.toLowerCase(); this.monitoringApiService
return Object.values(row).some( .getMasterDataListFloor(buildingId)
(value) => .subscribe((data) => {
value !== null && value.toString().toLowerCase().includes(searchTermLC) const newArray = data.data
); .map((item) => ({
id: item.id,
name: `${item.name} (${item.code})`,
}))
.sort((a, b) => b.id - a.id);
this.dataFloorList = newArray;
});
} }
viewRow(row) { listBuilding(buildingId, floorId) {
this.router.navigate(["/monitoring/view-new-building", row.id]); this.deviceService.filterDashboard(buildingId, floorId).subscribe((res) => {
this.filteredRows = res.data;
this.typeData = this.filteredRows[0].type;
if (this.typeData === "building") {
this.labelData = "Building";
} else if (this.typeData === "floor") {
this.labelData = "Floor";
} else if (this.typeData === "room") {
this.labelData = "Room";
}
});
}
doFilter() {
this.spinnerFilterActive = true;
this.listBuilding(this.buildingSelected, this.floorSelected);
setTimeout(() => {
this.spinnerFilterActive = false;
}, 3000);
}
viewDetail(row) {
if (row.building_id !== undefined && row.floor_id === undefined) {
this.router.navigate([
"/monitoring/view-detail-floor",
row.building_id,
row.id,
]);
} else if (row.building_id !== undefined && row.floor_id !== undefined) {
this.router.navigate([
"/monitoring/view-detail-room",
row.building_id,
row.floor_id,
row.id,
]);
} else {
this.router.navigate(["/monitoring/view-detail-building", row.id]);
}
} }
editRow(row) { editRow(row) {

View File

@@ -1,14 +1,37 @@
:host ::ng-deep .ng-select .ng-select-container {
color: #ffffff !important; /* :host ::ng-deep .ng-select .ng-select-container {
background-color: #252525 !important; color: #242222 !important;
background-color: #FBFBFB !important;
height: 40px !important; height: 40px !important;
border-radius: 12px; border-radius: 12px !important;
} */
:host ::ng-deep .ng-select .ng-select-container {
color: #242222 !important;
background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
} }
.background-round { .background-round {
background-color: #252525 !important; background-color: #252525 !important;
padding: 8px; padding: 8px;
border-radius: 50%; border-radius: 50%;
border: 2px solid #bef264; border: 2px solid #BEF264;
border-color: #bef264 !important; border-color: #BEF264 !important;
} }
.text-custom-name{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
font-weight: 600;
}
.text-custom-category{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 12px;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #FBFBFB;">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -7,7 +7,7 @@
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #FBFBFB !important; box-shadow: none !important;">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
@@ -21,6 +21,7 @@
bindValue="id" bindValue="id"
placeholder="Select Building" placeholder="Select Building"
[(ngModel)]="buildingSelected" [(ngModel)]="buildingSelected"
style="width: 100% !important;"
> >
</ng-select> </ng-select>
</div> </div>
@@ -35,6 +36,7 @@
bindValue="id" bindValue="id"
placeholder="Select Category" placeholder="Select Category"
[(ngModel)]="categorySelected" [(ngModel)]="categorySelected"
style="width: 100% !important;"
> >
</ng-select> </ng-select>
</div> </div>
@@ -49,6 +51,7 @@
bindValue="id" bindValue="id"
placeholder="Select Status" placeholder="Select Status"
[(ngModel)]="statusSelected" [(ngModel)]="statusSelected"
style="width: 100% !important;"
> >
</ng-select> </ng-select>
</div> </div>
@@ -57,12 +60,13 @@
<div class="d-flex"> <div class="d-flex">
<button <button
type="button" type="button"
class="btn btn-outline-success ml-2" class="btn ml-2"
(click)="doFilter()" (click)="doFilter()"
style=" style="
background-color: #252525 !important; background-color: #37A647 !important;
border-color: #ffffff !important; border-color: #37A647 !important;
border-radius: 12px; border-radius: 12px;
color: #ffffff;
" "
[disabled]="spinnerFilterActive" [disabled]="spinnerFilterActive"
> >
@@ -82,9 +86,9 @@
class="btn btn-outline-success ml-2" class="btn btn-outline-success ml-2"
(click)="doFilterCancel()" (click)="doFilterCancel()"
style=" style="
background-color: #252525 !important; background-color: #FBFBFB !important;
border-color: #ffffff !important; border-color: #6B6B6B !important;
color: #ffffff !important; color: #6B6B6B !important;
border-radius: 12px; border-radius: 12px;
" "
>Cancel >Cancel
@@ -100,10 +104,19 @@
</section> </section>
<section id="configuration"> <section id="configuration">
<div class="row"> <div class="row">
<div class="col-12" *ngIf="filteredRows?.length === 0">
<div class="card" style="background-color: #DDE1E6; min-height: 200px;">
<div class="card-content">
<div class="card-body">
<p class="text-center" style="color: #242222;">No data available</p>
</div>
</div>
</div>
</div>
<div class="col-lg-4 col-12" *ngFor="let item of filteredDeviceRows"> <div class="col-lg-4 col-12" *ngFor="let item of filteredDeviceRows">
<div <div
class="card" class="card"
style="background-color: #252525; position: relative" style="background-color: #DDE1E6; position: relative"
> >
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
@@ -111,7 +124,7 @@
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414F2B; background-color: #37A647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -121,29 +134,28 @@
" "
> >
<i <i
class="ri-lightbulb-flash-fill font-large-1 blue-grey d-block" class="{{item.category_icon}} font-large-1 blue-grey d-block"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<span <span
class="text-muted" class="text-custom-name"
style="color: #ffffff !important"
>{{ item.name }}</span >{{ item.name }}</span
> >
<br /> <br />
<span <span
class="text-muted" class="text-custom-category"
>{{item.category_name}}</span >{{item.category_name}}</span
> >
</div> </div>
</div> </div>
<div class="ui-switch-container" style="position: absolute; bottom: 10px; right: 10px;"> <div class="ui-switch-container" style="position: absolute; bottom: 10px; right: 10px;">
<ui-switch <ui-switch
style="border-color: #bef264 !important" style="border-color: #ffffff !important"
class="switchery" class="switchery"
switchColor="black" switchColor="black"
color="rgb(190, 242, 100)" color="rgb(55, 166, 71)"
size="small" size="small"
[checked]="item.status_id === 2" [checked]="item.status_id === 2"
(change)="switchChanged($event, item)" (change)="switchChanged($event, item)"

View File

@@ -23,7 +23,10 @@ export class ControlDeviceSeemoreComponent {
dataMasterStatus: any; dataMasterStatus: any;
spinnerFilterActive = false; spinnerFilterActive = false;
switchState: boolean; switchState: boolean;
paramsId: any; buildingId: any;
floorId: any;
roomId: any;
modeRoute: any;
public breadcrumb: any; public breadcrumb: any;
spinnerActive: boolean = false; spinnerActive: boolean = false;
@@ -37,16 +40,18 @@ export class ControlDeviceSeemoreComponent {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.route.params.subscribe((params) => { this.route.params.subscribe((params) => {
const buildingId = params["id"]; this.modeRoute = params["mode"];
this.paramsId = buildingId ? buildingId: 0; this.buildingId = params["buildingId"] ? params["buildingId"] : 0;
this.buildingSelected = parseInt(this.paramsId); this.floorId = params["floorId"] ? params["floorId"] : 0;
this.roomId = params["roomId"] ? params["roomId"] : 0;
this.buildingSelected = parseInt(this.buildingId);
}); });
this.breadcrumb = { this.breadcrumb = {
mainlabel: "Control Device", mainlabel: "Control Device",
linkBack: `/monitoring/view-new-building/${this.buildingSelected}`, linkBack: this.routeBack(''),
isLinkBack: true, isLinkBack: true,
links: [ links: [
{ {
@@ -76,6 +81,17 @@ export class ControlDeviceSeemoreComponent {
this.dataListBuilding(); this.dataListBuilding();
} }
routeBack(route){
if (this.modeRoute === 'building') {
route = `/monitoring/view-detail-building/${this.buildingId}`;
} else if (this.modeRoute === 'floor') {
route = `/monitoring/view-detail-floor/${this.buildingId}/${this.floorId}`;
} else if (this.modeRoute === 'room') {
route = `/monitoring/view-detail-room/${this.buildingId}/${this.floorId}/${this.roomId}`;
}
return route
}
fetchData(buildingSelected, categorySelected, statusSelected) { fetchData(buildingSelected, categorySelected, statusSelected) {
this.deviceService this.deviceService
.getDeviceData(buildingSelected, categorySelected, statusSelected) .getDeviceData(buildingSelected, categorySelected, statusSelected)
@@ -89,7 +105,7 @@ export class ControlDeviceSeemoreComponent {
filterDevices(devices: any[]): any[] { filterDevices(devices: any[]): any[] {
return devices.filter((device) => return devices.filter((device) =>
device.mapping.some( device.mapping.some(
(map) => map.name.startsWith("switch") && map.type === "Boolean" (map) => map.code.startsWith("switch") && map.type === "Boolean"
) )
); );
} }
@@ -105,13 +121,13 @@ export class ControlDeviceSeemoreComponent {
this.dataMasterCategori = dataCategory.filter( this.dataMasterCategori = dataCategory.filter(
(item) => item.statusName.toLowerCase() === "aktif" (item) => item.statusName.toLowerCase() === "aktif"
); );
this.dataMasterStatus = dataStatus.filter((item) => item.statusName.toLowerCase() === "aktif"); this.dataMasterStatus = dataStatus.filter((item) => item.statusName.toLowerCase() === "aktif" || item.status === "71");
}); });
} }
dataListBuilding() { dataListBuilding() {
this.monitoringApiService.getBuildingList().subscribe((data) => { this.monitoringApiService.getBuildingList().subscribe((data) => {
this.dataBuildingList = data.data.filter((item) => item.statusId === 2); this.dataBuildingList = data.data.filter((item) => item.statusName.toLowerCase() === "aktif" || item.status_id === 71);
}); });
} }
@@ -136,7 +152,7 @@ export class ControlDeviceSeemoreComponent {
} }
doFilterCancel(){ doFilterCancel(){
this.buildingSelected = parseInt(this.paramsId); this.buildingSelected = parseInt(this.buildingId);
this.categorySelected = undefined; this.categorySelected = undefined;
this.statusSelected = undefined; this.statusSelected = undefined;
this.fetchData(this.buildingSelected, 0, 0); this.fetchData(this.buildingSelected, 0, 0);
@@ -162,13 +178,13 @@ export class ControlDeviceSeemoreComponent {
switchChanged(ev, data) { switchChanged(ev, data) {
const requestData = { const requestData = {
device_id: data.device_id, id: data.id,
switch: data.mapping[0].switch, code: data.mapping[0].code,
value: ev, value: ev,
command_type: "on_off", command_type: "on_off",
}; };
this.deviceService.deviceSwitch(requestData).subscribe((res) => { this.deviceService.deviceSwitch(requestData).subscribe((res) => {
console.log(res);
}); });
} }
} }

View File

@@ -51,7 +51,7 @@ canvas {
} }
:host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut { :host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut {
stroke: #BEF264; stroke: #37A647;
stroke-width: 20px !important; stroke-width: 20px !important;
} }
@@ -67,28 +67,110 @@ canvas {
line-height: 1; line-height: 1;
} }
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-point{ :host ::ng-deep .sp-line-total-cost .ct-series-a .ct-point {
stroke: #BEF264; stroke: #37A647;
} }
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-line{ :host ::ng-deep .sp-line-total-cost .ct-series-a .ct-line {
stroke: #BEF264; stroke: #37A647;
} }
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-area{ :host ::ng-deep .sp-line-total-cost .ct-series-a .ct-area {
fill: #BEF264; fill: #37A647;
fill-opacity: 1; fill-opacity: 1;
} }
:host ::ng-deep .sp-line-total-cost .ct-point{ :host ::ng-deep .sp-line-total-cost .ct-point {
stroke-width: 0px; stroke-width: 0px;
} }
:host ::ng-deep .progress-bar { :host ::ng-deep .progress-bar {
background-color: #BEF264 !important; background-color: #37A647 !important;
} }
.background-round { .background-round {
background-color: #252525 !important; background-color: #37A647 !important;
padding: 8px; padding: 8px;
border-radius: 50%; border-radius: 50%;
border: 2px solid #BEF264; border: 2px solid #37A647;
border-color: #BEF264 !important; border-color: #37A647 !important;
} }
.custom-label {
font-family: "Open Sans", sans-serif !important;
color: #242222;
font-size: 16px;
}
.custom-value {
font-family: "Open Sans", sans-serif !important;
color: #242222;
font-weight: 800;
font-size: 24px;
}
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
font-weight: 800;
}
.custom-style-header{
background-color: #DDE1E6 !important;
border-bottom: 3px solid #242222;
}
/* day */
.days-container {
display: flex;
justify-content: space-around;
}
.day {
font-family: "Nunito Sans", sans-serif;
color: #242222;
padding: 2px;
border-radius: 5px;
}
.current-day {
color: #37A647;
}
.temperature-container {
text-align: center;
margin-top: 50px;
height: 100px;
}
.temperature {
font-family: "Nunito Sans", sans-serif;
font-size: 36px;
font-weight: bold;
color: #242222;
}
.date-time-container {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.current-date,
.current-time {
font-family: "Nunito Sans", sans-serif;
font-size: 16px;
color: #242222;
}
.custom-card-temp{
height: 300px;
}
/* echart */
.custom-card-air {
background-color: #dde1e6 !important;
}
.echart-container {
height: 200px; /* Tinggi awal untuk menentukan tinggi chart */
width: 100%; /* Lebar maksimal */
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content" style="background-color: #fbfbfb">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -6,20 +6,25 @@
<div class="content-body"> <div class="content-body">
<div class="row"> <div class="row">
<div class="col-xl-3 col-md-6 col-12"> <div class="col-xl-3 col-md-6 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #dde1e6 !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h5 style="color: #ffffff">Kwh Consumption</h5> <h5 class="custom-label">Kwh Consumption</h5>
<h3 style="color: #ffffff"> <h3 class="custom-value">
{{ topCard?.kwh_consumption ? topCard?.kwh_consumption.toFixed(3) : 0 }} Kwh {{
topCard?.kwh_consumption
? topCard?.kwh_consumption.toFixed(1)
: 0
}}
Kwh
</h3> </h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37a647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -30,7 +35,7 @@
> >
<i <i
class="icon-energy primary font-large-1 float-right" class="icon-energy primary font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -40,18 +45,18 @@
</div> </div>
</div> </div>
<div class="col-xl-3 col-md-6 col-12"> <div class="col-xl-3 col-md-6 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #dde1e6 !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h5 style="color: #ffffff">Device</h5> <h5 class="custom-label">Device</h5>
<h3 style="color: #ffffff">{{ topCard?.total_device }}</h3> <h3 class="custom-value">{{ topCard?.total_device }}</h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37a647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -62,7 +67,7 @@
> >
<i <i
class="ri-device-line primary font-large-1 float-right" class="ri-device-line primary font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -72,18 +77,18 @@
</div> </div>
</div> </div>
<div class="col-xl-3 col-md-6 col-12"> <div class="col-xl-3 col-md-6 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #dde1e6 !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h5 style="color: #ffffff">Room</h5> <h5 class="custom-label">Room</h5>
<h3 style="color: #ffffff">{{ topCard?.total_room }}</h3> <h3 class="custom-value">{{ topCard?.total_room }}</h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37a647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -94,7 +99,7 @@
> >
<i <i
class="ri-building-2-line font-large-1 float-right" class="ri-building-2-line font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -104,23 +109,25 @@
</div> </div>
</div> </div>
<div class="col-xl-3 col-md-6 col-12"> <div class="col-xl-3 col-md-6 col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #dde1e6 !important">
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<h5 style="color: #ffffff">Summary Cost</h5> <h5 class="custom-label">Summary Cost</h5>
<h3 style="color: #ffffff"> <h3 class="custom-value">
{{ {{
summaryCost?.summary_cost summaryCost?.summary_cost
| currency : "Rp " : "symbol" : "1.0-0" ? (summaryCost?.summary_cost
| currency : "Rp " : "symbol" : "1.0-0")
: 0
}} }}
</h3> </h3>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
<div <div
style=" style="
background-color: #414f2b; background-color: #37a647;
border-radius: 50%; border-radius: 50%;
width: 50px; width: 50px;
height: 50px; height: 50px;
@@ -131,7 +138,7 @@
> >
<i <i
class="ri-money-dollar-box-line font-large-1 float-right" class="ri-money-dollar-box-line font-large-1 float-right"
style="color: #bef264 !important" style="color: #ffffff !important"
></i> ></i>
</div> </div>
</div> </div>
@@ -141,54 +148,126 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #dde1e6 !important">
<div class="card-content"> <div class="card-body">
<div class="card-body"> <div
<canvas (chartClick)="onChartClick($event)"
style=" echarts
background-color: #252525 !important; [options]="chartOptionBar"
border-color: #252525; class="echart-container"
color: #ffffff; style="height: 400px !important; display: block"
" ></div>
class="barchart" </div>
height="400" </div>
width="1900" </div>
baseChart </div>
[datasets]="barChartData" <div class="row">
[labels]="barChartLabels" <div class="col-xl-4 col-md-6 col-12">
[options]="barChartOptions" <div
[legend]="barChartLegend" class="card custom-card-temp"
chartType="bar" style="background-color: #dde1e6 !important"
>
<div class="card-header custom-style-header">
<h4 class="card-title text-center text-custom-label">
Temperature
</h4>
</div>
<div class="card-body">
<div class="days-container">
<div
*ngFor="let day of days"
[ngClass]="{ 'current-day': day.isToday }"
class="day"
> >
</canvas> {{ day.name }}
</div>
</div>
<div class="temperature-container">
<span class="temperature">{{ roomTemperature }}°C</span>
</div>
<div class="date-time-container">
<span class="current-time">Time :{{ currentTime }}</span>
<span class="current-date">{{ currentDate }}</span>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-md-6 col-12">
<div class="card custom-card-air">
<div class="card-header custom-style-header">
<h4 class="card-title text-center text-custom-label">
Air Quality
</h4>
</div>
<div class="card-body">
<div
echarts
[options]="chartOption"
class="echart-container"
></div>
</div>
</div>
</div>
<div class="col-xl-4 col-md-6 col-12">
<div
class="card custom-card-temp"
style="background-color: #dde1e6 !important"
>
<div class="card-header custom-style-header">
<h4 class="card-title text-center text-custom-label">Humidity</h4>
</div>
<div class="card-body">
<div class="days-container">
<div
*ngFor="let day of days"
[ngClass]="{ 'current-day': day.isToday }"
class="day"
>
{{ day.name }}
</div>
</div>
<div class="temperature-container">
<span class="temperature">{{ roomHumidity }}%</span>
</div>
<div class="date-time-container">
<span class="current-time">Time :{{ currentTime }}</span>
<span class="current-date">{{ currentDate }}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-6" *ngFor="let item of deviceCategory?.usesd"> <div class="col-6" *ngFor="let item of deviceCategory?.used">
<div <div
class="card overflow-hidden" class="card"
style="background-color: #000000 !important" style="
background-color: transparent !important;
border: none;
box-shadow: none;
"
> >
<div class="card-content"> <div class="card-content">
<div class="card-body clearfix"> <div class="card-body clearfix">
<div class="media align-items-stretch mb-2"> <div class="media align-items-stretch mb-2">
<div class="align-self-center"> <div class="align-self-center">
<i <i
class="{{item.icon}} background-round info font-large-1 mr-2" class="{{
style="color: #bff264 !important" item.icon
}} background-round info font-large-1 mr-2"
style="color: #ffffff !important"
></i> ></i>
</div> </div>
<div class="media-body"> <div class="media-body">
<p style="color: #ffffff !important"> <p style="color: #242222 !important">
{{ item.category_device }} {{ item.category_device }}
<span <span
class="float-right text-bold-600" class="float-right text-bold-600"
style="color: #ffffff" style="color: #242222"
>{{ item.value.toFixed(1) }}%</span >{{ item.value.toFixed(1) }}%</span
> >
</p> </p>
@@ -214,13 +293,13 @@
<button <button
class="btn btn-primary" class="btn btn-primary"
style=" style="
background-color: #c3f164 !important; background-color: #37a647 !important;
color: #000000 !important; color: #ffffff !important;
border-radius: 10px; border-radius: 10px;
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
font-weight: 700; font-weight: 700;
" "
(click)="seeMore(paramsId)" (click)="seeMore(buildingId, floorId, roomId)"
> >
See More See More
</button> </button>

View File

@@ -1,9 +1,12 @@
import { Component, ElementRef, ViewChild } from "@angular/core"; import { Component, ElementRef, ViewChild } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router"; import { ActivatedRoute, Router } from "@angular/router";
import { ChartOptions, ChartType, ChartDataset } from "chart.js";
import { EnergyMonitoringService } from "../../service/energy-monitoring.service"; import { EnergyMonitoringService } from "../../service/energy-monitoring.service";
import { CurrencyPipe } from "@angular/common"; import { CurrencyPipe } from "@angular/common";
import { LoginService } from "../../service/login.service"; import { LoginService } from "../../service/login.service";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { ModalExportComponent } from "../modal-export/modal-export.component";
import { CostManagementService } from "../../service/cost-management.service";
import { BuildingService } from "../../service/monitoring-api.service";
@Component({ @Component({
selector: "app-detail", selector: "app-detail",
@@ -15,111 +18,45 @@ export class DetailComponent {
data: any; data: any;
mode: string; mode: string;
breadcrumb: any; breadcrumb: any;
donutChart1: any;
donutChart2: any;
dataChart = { // temperature
donut: { days = [
series: [20, 20, 20, 20, 20], { name: "Sun", isToday: false },
}, { name: "Mon", isToday: false },
}; { name: "Tue", isToday: false },
{ name: "Wed", isToday: false },
dataChart2 = { { name: "Thu", isToday: false },
donut: { { name: "Fri", isToday: false },
series: [50, 50], { name: "Sat", isToday: false },
}, ];
}; roomTemperature: number = 0;
roomHumidity: number = 0;
valueAirQuality: number = 0;
currentDate: string;
currentTime: string;
chartOption: any;
chartOptionBar: any;
// chart bar // chart bar
public barChartOptions: ChartOptions = {
responsive: true,
animation: {
duration: 0
},
scales: {
x: {
stacked: true,
},
y: {
stacked: true,
beginAtZero: true
},
},
};
public barChartLabels: string[] = []; public barChartLabels: string[] = [];
public barChartType: ChartType = "bar"; public barChartData: number[] = [];
public barChartLegend = true; public barChartData2: number[] = [];
public barChartData: ChartDataset[] = [
{
data: [],
label: "KWH Consumption",
backgroundColor: "#C3F164",
borderColor: "#C3F164",
pointBackgroundColor: "#C3F164",
pointBorderColor: "#C3F164",
pointHoverBackgroundColor: "#ffffff",
pointHoverBorderColor: "#C3F164",
barPercentage: 0.5,
categoryPercentage: 0.5,
},
// {
// data: [],
// label: "Water Consumption",
// backgroundColor: "#64CFF1",
// borderColor: "#64CFF1",
// pointBackgroundColor: "#64CFF1",
// pointBorderColor: "#64CFF1",
// pointHoverBackgroundColor: "#ffffff",
// pointHoverBorderColor: "#64CFF1",
// barPercentage: 0.5,
// categoryPercentage: 0.5,
// },
{
type: "line",
data: [],
label: "Weekly Kwh Average",
backgroundColor: "rgba(0,255,255,0)",
borderColor: "#ffffff",
fill: false,
pointBorderColor: "#ffffff",
pointBackgroundColor: "#FFF",
pointBorderWidth: 2,
pointHoverBorderWidth: 2,
pointRadius: 4,
tension: 0.3,
spanGaps: true
},
// {
// type: "line",
// data: [],
// label: "Weekly Water Average",
// backgroundColor: "rgba(0,255,255,0)",
// borderColor: "#ffffff",
// fill: false,
// pointBorderColor: "#ffffff",
// pointBackgroundColor: "#FFF",
// pointBorderWidth: 2,
// pointHoverBorderWidth: 2,
// pointRadius: 4,
// tension: 0.3,
// spanGaps: true
// },
];
//.......................... //..........................
// integrasi // integrasi
electric: any;
water: any;
device: any; device: any;
room: any; room: any;
topCard: any; topCard: any;
summaryCost: any; summaryCost: any;
airQuality: any;
temperature: any; temperature: any;
deviceCategory: any; deviceCategory: any;
chartKwhWater: any; chartKwhWater: any;
paramsId: any; buildingId: any;
floorId: any;
roomId: any;
buildingName: any;
floorName: any;
roomName: any;
//...... //......
constructor( constructor(
@@ -127,7 +64,10 @@ export class DetailComponent {
private energyMonitoringService: EnergyMonitoringService, private energyMonitoringService: EnergyMonitoringService,
private currencyPipe: CurrencyPipe, private currencyPipe: CurrencyPipe,
private router: Router, private router: Router,
private authService: LoginService private authService: LoginService,
private modalService: NgbModal,
private costService: CostManagementService,
private buildingService: BuildingService
) {} ) {}
get formattedSummaryCost(): string { get formattedSummaryCost(): string {
@@ -140,195 +80,396 @@ export class DetailComponent {
} }
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.route.data.subscribe((data) => { this.route.data.subscribe((data) => {
this.mode = data.mode; this.mode = data.mode;
}); });
this.breadcrumbLink();
this.route.params.subscribe((params) => { this.route.params.subscribe((params) => {
const buildingId = params["id"]; this.buildingId = params["buildingId"] ? params["buildingId"] : 0;
this.paramsId = params["id"]; this.floorId = params["floorId"] ? params["floorId"] : 0;
if (buildingId) { this.roomId = params["roomId"] ? params["roomId"] : 0;
this.dataEnergyMonitoringTopCard(buildingId); this.dataBuilding(this.buildingId);
this.dataEnergyMonitoringSummary(buildingId); if (
this.dataEnergyMonitoringSAir(buildingId); this.buildingId !== undefined &&
this.dataEnergyMonitoringSTemperature(buildingId); this.floorId === undefined &&
this.dataEnergyDeviceCategory(buildingId); this.roomId === undefined
this.dataEnergyChartKwhWater(buildingId); ) {
this.dataEnergyMonitoringTopCard(this.buildingId, 0, 0);
this.dataEnergyMonitoringSummary(this.buildingId, 0, 0);
this.dataEnergyDeviceCategory(this.buildingId, 0, 0);
this.dataEnergyChartKwhWater(this.buildingId, 0, 0);
} else if (
this.buildingId !== undefined &&
this.floorId !== undefined &&
this.roomId === undefined
) {
this.dataEnergyMonitoringTopCard(this.buildingId, this.floorId, 0);
this.dataEnergyMonitoringSummary(this.buildingId, this.floorId, 0);
this.dataEnergyDeviceCategory(this.buildingId, this.floorId, 0);
this.dataEnergyChartKwhWater(this.buildingId, this.floorId, 0);
} else if (
this.buildingId !== undefined &&
this.floorId !== undefined &&
this.roomId !== undefined
) {
this.dataEnergyMonitoringTopCard(
this.buildingId,
this.floorId,
this.roomId
);
this.dataEnergyMonitoringSummary(
this.buildingId,
this.floorId,
this.roomId
);
this.dataEnergyDeviceCategory(
this.buildingId,
this.floorId,
this.roomId
);
this.dataEnergyChartKwhWater(
this.buildingId,
this.floorId,
this.roomId
);
} }
});
this.donutChart1 = { this.dataDeviceIr();
type: "Pie", this.getAirQualityData();
data: this.dataChart.donut, });
options: {
fullwidth: true,
height: "300px",
donut: true,
donutWidth: 70,
startAngle: 270,
total: 200,
showLabel: true,
},
};
} }
breadcrumbLink() { breadcrumbLink() {
this.breadcrumb = { if (this.mode === "building") {
mainlabel: "Energy Monitoring", this.breadcrumb = {
linkBack: "/monitoring", mainlabel: "Energy Monitoring",
isLinkBack: true, linkBack: "/monitoring",
links: [ isLinkBack: true,
links: [
{
name: this.buildingName,
isLink: false,
link: "",
},
],
};
} else if (this.mode === "floor") {
this.breadcrumb = {
mainlabel: "Energy Monitoring",
linkBack: "/monitoring",
isLinkBack: true,
links: [
{
name: this.buildingName,
isLink: false,
link: "",
},
{
name: this.floorName,
isLink: false,
link: "",
},
],
};
} else if (this.mode === "room") {
this.breadcrumb = {
mainlabel: "Energy Monitoring",
linkBack: "/monitoring",
isLinkBack: true,
links: [
{
name: this.buildingName,
isLink: false,
link: "",
},
{
name: this.floorName,
isLink: false,
link: "",
},
{
name: this.roomName,
isLink: false,
link: "",
},
],
};
}
}
getAirQualityData() {
this.valueAirQuality = Math.floor(Math.random() * 501);
this.chartOption = {
series: [
{ {
name: "Dashboard", type: "gauge",
isLink: false, startAngle: 180,
link: "", endAngle: 0,
}, center: ["50%", "75%"],
{ radius: "130%", // Adjust the radius to make the chart smaller
name: "Energy Monitoring", min: 0,
isLink: false, max: 500,
link: "", splitNumber: 5,
axisLine: {
lineStyle: {
width: 20,
color: [
[1 / 6, "#6BD67C"], // 0 - 50: Green
[2 / 6, "#A2D856"], // 51 - 100: Light Green
[3 / 6, "#FFE45E"], // 101 - 150: Yellow
[4 / 6, "#FFA644"], // 151 - 200: Orange
[5 / 6, "#FF6E76"], // 201 - 300: Light Red
[6 / 6, "#E768A7"], // 301 - 500: Purple
],
},
},
pointer: {
icon: "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z",
length: "12%",
width: 15,
offsetCenter: [0, "-50%"],
itemStyle: {
color: "auto",
},
},
axisTick: {
length: 10,
lineStyle: {
color: "auto",
width: 2,
},
},
splitLine: {
length: 15,
lineStyle: {
color: "auto",
width: 5,
},
},
axisLabel: {
color: "#464646",
fontSize: 16, // Adjust font size
distance: -40, // Adjust distance
rotate: "tangential",
formatter: function (value: number) {
// return Math.round(value) === 100 ? "100" : Math.round(value) + "";
return value.toString();
},
},
title: {
offsetCenter: [0, " 15%"],
fontSize: 18, // Adjust font size
},
detail: {
fontSize: 24, // Adjust font size
offsetCenter: [0, "-25%"], // Adjust offset
valueAnimation: true,
formatter: function (value: number) {
return Math.round(value) + "";
},
color: "#242222",
},
data: [
{
value: this.valueAirQuality,
name: this.getGradeName(this.valueAirQuality),
},
],
}, },
], ],
}; };
} }
getGradeName(value: number): string {
if (value <= 50) {
return "Good";
} else if (value <= 100) {
return "Moderate";
} else if (value <= 150) {
return "Unhealthy for Sensitive Groups";
} else if (value <= 200) {
return "Unhealthy";
} else if (value <= 300) {
return "Very Unhealthy";
} else {
return "Hazardous";
}
}
dataDeviceIr() {
const today = new Date().getDay();
this.days[today].isToday = true;
const now = new Date();
this.currentDate = now.toLocaleDateString();
this.currentTime = now.toLocaleTimeString();
this.energyMonitoringService.getDeviceStatus(452).subscribe((res) => {
this.roomTemperature = res.result[0].value;
this.roomHumidity = res.result[1].value;
});
}
//integrasi //integrasi
dataEnergyMonitoringTopCard(buildingId) { dataEnergyMonitoringTopCard(buildingId, floorId, roomId) {
this.energyMonitoringService this.energyMonitoringService
.getDashboardTopCard(buildingId) .getDashboardTopCard(buildingId, floorId, roomId)
.subscribe((res) => { .subscribe((res) => {
this.topCard = res.data; this.topCard = res.data;
}); });
} }
dataEnergyMonitoringSummary(buildingId) {
dataBuilding(buildingId) {
this.costService.getBUildingById(buildingId).subscribe((res) => {
this.buildingName = res.data.name
this.breadcrumbLink();
if (this.floorId) {
this.dataFloor(this.floorId)
}
if (this.roomId) {
this.dataRoom(this.roomId)
}
});
}
dataFloor(floorId) {
this.buildingService.getHeaderDetailParam(floorId).subscribe((res) => {
this.floorName = res.data.name;
this.breadcrumbLink();
});
}
dataRoom(roomId) {
this.buildingService.getRoom(roomId).subscribe((res) => {
this.roomName = res.data.name;
this.breadcrumbLink();
});
}
dataEnergyMonitoringSummary(buildingId, floorId, roomId) {
this.energyMonitoringService this.energyMonitoringService
.getDashboardSummary(buildingId) .getDashboardSummary(buildingId, floorId, roomId)
.subscribe((res) => { .subscribe((res) => {
this.summaryCost = res.data; this.summaryCost = res.data;
}); });
} }
dataEnergyMonitoringSAir(buildingId) {
dataEnergyDeviceCategory(buildingId, floorId, roomId) {
this.energyMonitoringService this.energyMonitoringService
.getDashboardAirQuality(buildingId) .getDashboardDeviceCategory(buildingId, floorId, roomId)
.subscribe((res) => {
this.airQuality = res.data;
});
}
dataEnergyMonitoringSTemperature(buildingId) {
this.energyMonitoringService
.getDashboardTemperature(buildingId)
.subscribe((res) => {
this.temperature = res.data;
this.donutChart2 = {
type: "Pie",
data: this.dataChart2.donut,
options: {
chartPadding: 0,
fullwidth: true,
height: "150px",
donut: true,
showLabel: true,
startAngle: 0,
labelInterpolationFnc: (value) => {
const total = this.temperature;
return total + "°C";
},
},
events: {
draw: (data: any) => {
if (data.type === "label") {
if (data.index === 0) {
data.element.attr({
dx: data.element.root().width() / 2,
dy: data.element.root().height() / 2,
});
} else {
data.element.remove();
}
}
},
},
};
});
}
dataEnergyDeviceCategory(buildingId) {
this.energyMonitoringService
.getDashboardDeviceCategory(buildingId)
.subscribe((res) => { .subscribe((res) => {
this.deviceCategory = res.data[0]; this.deviceCategory = res.data[0];
}); });
} }
dataEnergyChartKwhWater(buildingId) {
dataEnergyChartKwhWater(buildingId, floorId, roomId) {
this.energyMonitoringService this.energyMonitoringService
.getDashboardChartKwhWater(buildingId) .getDashboardChartKwhWater(buildingId, floorId, roomId)
.subscribe((res) => { .subscribe((res) => {
this.chartKwhWater = res.data; this.chartKwhWater = res.data;
this.barChartData[0].data = [];
// this.barChartData[1].data = [];
this.chartKwhWater.forEach((entry) => { this.chartKwhWater.forEach((entry) => {
this.barChartData[0].data.push(entry.kwh); this.barChartData.push(entry.kwh.toFixed(1));
// this.barChartData[1].data.push(entry.water); this.barChartData2.push(entry.cost);
this.barChartLabels.push(entry.day); this.barChartLabels.push(entry.day);
}); });
const weeklyKwh = this.aggregateKwhWeekly(this.chartKwhWater); this.chartOptionBar = {
// const weeklyWater = this.aggregateWaterWeekly(this.chartKwhWater); tooltip: {
trigger: "axis",
// Populate Appointment data at every multiple of 7 axisPointer: {
let weekIndex = 0; type: "shadow",
for (let i = 0; i < this.barChartData[0].data.length; i++) { },
if (i % 7 === 6 && weekIndex < weeklyKwh.length) { },
this.barChartData[2].data[i] = weeklyKwh[weekIndex++]; legend: {},
} else { toolbox: {
this.barChartData[2].data[i] = null; show: true,
} orient: "vertical",
} feature: {
dataView: { show: true, readOnly: false },
// let weekIndexWater = 0; magicType: { show: true, type: ["line", "bar"] },
// for (let i = 0; i < this.barChartData[0].data.length; i++) { restore: { show: true },
// if (i % 7 === 6 && weekIndexWater < weeklyWater.length) { saveAsImage: { show: true },
// this.barChartData[3].data[i] = weeklyWater[weekIndexWater++]; },
// } else { },
// this.barChartData[3].data[i] = null; grid: {
// } left: "3%",
// } right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: [
{
type: "category",
data: this.barChartLabels,
},
],
yAxis: [
{
type: "value",
},
],
series: [
{
name: "KWH Consumption",
type: "bar",
color: "#242222",
stack: "Ad",
emphasis: {
focus: "series",
},
data: this.barChartData,
},
{
name: "Summary Cost",
type: "bar",
stack: "Ad",
color: "#37a647",
emphasis: {
focus: "series",
},
data: this.barChartData2,
},
],
};
onClick: (params) => {
this.onChartClick(params);
};
}); });
} }
aggregateKwhWeekly(data: any[]): number[] {
const weeks = [];
let weekSum = 0;
let dayCount = 0;
data.forEach((entry, index) => { onChartClick(params) {
weekSum += entry.kwh; console.log(params);
dayCount++; const modalRef = this.modalService.open(ModalExportComponent, {
if (dayCount === 7 || index === data.length - 1) { size: "xl",
weeks.push(weekSum); centered: true,
weekSum = 0;
dayCount = 0;
}
}); });
modalRef.componentInstance.dataIndex = params.dataIndex;
modalRef.componentInstance.buildingId = this.buildingId;
modalRef.componentInstance.floorId = this.floorId;
modalRef.componentInstance.roomId = this.roomId;
modalRef.componentInstance.mode = this.mode;
return weeks; modalRef.result.then(
} (result) => {
aggregateWaterWeekly(data: any[]): number[] { if (result) {
const weeks = []; console.log(result);
let weekSum = 0; }
let dayCount = 0; },
(reason) => {
data.forEach((entry, index) => { console.log(`Dismissed: ${reason}`);
weekSum += entry.water;
dayCount++;
if (dayCount === 7 || index === data.length - 1) {
weeks.push(weekSum);
weekSum = 0;
dayCount = 0;
} }
}); );
return weeks; // Show popup with details
// alert(`Day: ${params.name}\nKWH Consumption: ${params.value}`);
} }
seeMore(paramsId){
this.router.navigate(["/monitoring/control-device-see-more/", paramsId]); seeMore(buildingId, floorId, roomId) {
this.router.navigate([
"/monitoring/control-device-see-more/",
buildingId,
floorId,
roomId,
this.mode,
]);
} }
} }

View File

@@ -0,0 +1,444 @@
:host ::ng-deep .progress-bar {
background-color: #bef264 !important;
}
:host ::ng-deep .donut-chart2 .ct-series-a .ct-slice-donut {
stroke: #8a8a8a;
stroke-width: 20px !important;
}
:host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut {
stroke: #bef264;
stroke-width: 20px !important;
}
:host ::ng-deep .donut-chart2 .ct-label {
fill: #ffffff;
color: rgb(255, 255, 255);
font-size: 12px;
line-height: 1;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-point {
stroke: #bef264;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-line {
stroke: #bef264;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-area {
fill: #bef264;
fill-opacity: 1;
}
:host ::ng-deep .sp-line-total-cost .ct-point {
stroke-width: 0px;
}
.ct-chart-bar .ct-series .ct-bar {
stroke-width: 20px !important; /* Atur lebar bar sesuai kebutuhan */
}
.ct-chart-bar .ct-label.ct-horizontal {
margin-left: -10px !important; /* Mengatur margin label horizontal */
margin-right: -10px !important;
}
:host ::ng-deep .donut-chart3 .ct-series-a .ct-bar {
stroke: #bef264;
fill: none;
stroke-width: 30px;
}
:host ::ng-deep .donut-chart3 .ct-series-b .ct-bar {
stroke: #bef264;
fill: none;
stroke-width: 30px;
}
:host ::ng-deep .donut-chart3 .ct-label {
fill: #ffffff;
color: rgb(255, 255, 255);
font-size: 12px;
line-height: 1;
margin-right: 20px;
}
:host ::ng-deep .ct-label.ct-horizontal {
font-size: 12px; /* Adjust font size */
transform: rotate(-45deg); /* Rotate labels if needed for better fit */
text-anchor: end;
margin-top: 10px;
}
:host ::ng-deep .ct-chart-bar .ct-labels .ct-label.ct-horizontal {
margin-right: 20px; /* Adjust margin for labels */
}
.chart-title {
font-size: 18px;
margin-bottom: 10px;
font-weight: bold;
}
/* Hide the default calendar icon */
input[type="month"]::-webkit-calendar-picker-indicator {
background-color: #ffffff;
}
/* table */
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-header
.datatable-header-cell
.datatable-header-cell-label {
font-family: inherit;
font-size: medium;
font-weight: bold;
color: #6b6f82;
}
:host ::ng-deep .ngx-datatable .datatable-row-center,
.ngx-datatable .datatable-row-group,
.ngx-datatable .datatable-row-right {
position: relative;
height: 50px !important;
}
:host ::ng-deep .datatable-icon-right:before {
font-family: "icofont";
font-style: normal;
}
:host ::ng-deep .datatable-icon-skip:before {
font-family: "icofont";
font-style: normal;
}
:host ::ng-deep .datatable-icon-left:before {
font-family: "icofont";
font-style: normal;
}
:host ::ng-deep .datatable-icon-left:before {
content: "\2039";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-prev:before {
content: "\00AB";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-right:before {
content: "\203A";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-skip:before {
content: "\00BB";
font-size: x-large;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-left,
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-right,
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-prev {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-right,
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-right {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-skip {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-prev {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host
::ng-deep
.datatable-footer
.datatable-pager
ul
li:not(.disabled).active
a,
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
ul[_ngcontent-c11]
li[_ngcontent-c11]:not(.disabled):hover
a[_ngcontent-c11] {
background-color: #d4d2e7;
font-weight: bold;
font-size: larger;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager a {
height: 32px;
min-width: 34px;
line-height: 22px;
padding: 0;
border-radius: 3px;
margin: 0 3px;
text-align: center;
vertical-align: top;
padding-top: 3px;
text-decoration: none;
vertical-align: bottom;
color: #7c8091;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-left,
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-prev[_ngcontent-c11] {
font-size: 14px;
line-height: 9px;
padding: 0px 08px;
background-color: #ffffff;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-left,
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-right,
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-skip,
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
.datatable-icon-prev,
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11]
.datatable-footer[_ngcontent-c11]
.datatable-pager[_ngcontent-c11]
.datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
ul
li:not(.disabled):hover
a {
background-color: #545454;
font-weight: bold;
color: white;
}
:host
::ng-deep
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
ul
li:not(.disabled).active
a,
.ngx-datatable.bootstrap
.datatable-footer
.datatable-pager
ul
li:not(.disabled):hover
a {
background-color: #252525;
font-weight: bold;
color: white;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #DDE1E6;
color: #242222;
margin-top: -1px;
overflow: inherit;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
background: #DDE1E6;
color: #242222;
font-weight: bold;
height: unset !important;
overflow: inherit;
}
:host ::ng-deep .ngx-datatable .datatable-footer .datatable-pager {
flex: 0 0 0%;
}
:host ::ng-deep .ngx-datatable .datatable-footer .datatable-pager .pager {
display: flex;
}
:host
::ng-deep
.ngx-datatable
.datatable-footer
.selected-count
.datatable-pager {
flex: 0 0 0%;
}
:host ::ng-deep .ngx-datatable {
display: -webkit-box;
}
:host ::ng-deep .ng-select .ng-select-container {
color: #242222 !important;
background-color: #FBFBFB !important;
height: 40px !important;
border-radius: 12px !important;
box-shadow: 0 2px 4px rgba(36, 34, 34, 0.2) !important; /* Bayangan lebih tipis */
}
:host ::ng-deep .ng-select .ng-select-container .ng-value-container .ng-input>input {
color: #242222 !important;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row {
background-color: #FBFBFB; /* Black color for table rows */
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-body-row:hover {
background-color: #DDE1E6; /* Darker black for hover effect */
}
.text-custom-label{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 16px;
}
.text-custom-data{
color: #242222 !important;
font-family: "Open Sans", sans-serif !important;
font-size: 24px;
font-weight: 700;
}
.style-custom-label{
color: #242222 !important;
}
::ng-deep .modal-backdrop.show {
z-index: auto !important;
}

View File

@@ -0,0 +1,162 @@
<div class="modal-body" style="background-color: #fbfbfb !important">
<h4 style="color: #242222; margin-bottom: 20px !important">
<div *ngIf="buildingOnly">
<strong>{{ data_cost[0].BuildingName }}</strong>
</div>
<div *ngIf="floorOnly">
{{data_cost[0].BuildingName}} > <strong>{{ data_cost[0].floorName }}</strong>
</div>
<div *ngIf="roomOnly">
{{data_cost[0].BuildingName}} > {{data_cost[0].floorName}} > <strong>{{ data_cost[0].roomName }}</strong>
</div>
</h4>
<!-- <p style="color: #242222">Room : dfd</p>
<p style="color: #242222">Category : gdfg</p> -->
<div class="card-dashboard">
<ngx-datatable
class="bootstrap table-bordered"
[limit]="10"
[rows]="data_cost"
[columnMode]="'force'"
[headerHeight]="50"
[footerHeight]="50"
[rowHeight]="50"
fxFlex="auto"
[scrollbarH]="true"
>
<ngx-datatable-column name="#" [flexGrow]="0.5" [minWidth]="30">
<ng-template ngx-datatable-cell-template let-rowIndex="rowIndex">
<p style="color: #242222 !important">
{{ rowIndex + 1 }}
</p>
</ng-template>
</ngx-datatable-column>
<!-- <ngx-datatable-column name="periode" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Tanggal</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">
{{ value | date : "dd/MM/yyyy" }}
</p>
</ng-template>
</ngx-datatable-column> -->
<ngx-datatable-column name="floorName" [flexGrow]="1" [minWidth]="90" *ngIf="buildingOnly">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Floor</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">{{ value }}</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="roomName" [flexGrow]="1" [minWidth]="90" *ngIf="buildingOnly || floorOnly">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Room</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">{{ value }}</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="deviceName" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Device</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">{{ value }}</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="duration" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Duration</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">{{ value }}</p>
</ng-template>
</ngx-datatable-column>
<!-- <ngx-datatable-column name="priceKwh" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Price Kwh</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">{{ value }}</p>
</ng-template>
</ngx-datatable-column> -->
<ngx-datatable-column name="priceKwh" [flexGrow]="1" [minWidth]="90">
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Price Kwh</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">
{{
value.toLocaleString("id-ID", {
style: "currency",
currency: "IDR"
})
}}
</p>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="estimationCost"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span style="color: #242222 !important">Estimation Cost</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
<p style="color: #242222 !important">
{{
value.toLocaleString("id-ID", {
style: "currency",
currency: "IDR"
})
}}
</p>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<div
class="modal-footer "
style="background-color: #fbfbfb !important; border-style: none !important"
>
<button
type="button"
class="btn"
style="
color: #242222;
width: 10%;
background-color: #fbfbfb !important;
border-color: #242222 !important;
border-radius: 10px;
"
(click)="activeModal.dismiss('Cross click')"
>
Close
</button>
<button
type="button"
class="btn"
style="
color: #ffffff !important;
width: 10%;
background-color: #37a647 !important;
border-color: #37a647 !important;
border-radius: 10px;
"
[disabled]="spinnerExportActive"
(click)="export()"
>
<i class="la la-spinner spinner" *ngIf="spinnerExportActive"></i>
Export
</button>
</div>

View File

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

View File

@@ -0,0 +1,146 @@
import { Component, Input } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
import { TableexcelService } from "src/app/_services/tableexcel.service";
import { LoginService } from "../../service/login.service";
import { BuildingService } from "../../service/monitoring-api.service";
@Component({
selector: "app-modal-export",
templateUrl: "./modal-export.component.html",
styleUrls: ["./modal-export.component.css"],
})
export class ModalExportComponent {
@Input() buildingId: any = 0;
@Input() dataIndex: any = 0;
@Input() floorId: any = 0;
@Input() roomId: any = 0;
@Input() mode: any = "";
buildingOnly = false;
floorOnly = false;
roomOnly = false;
data: any;
filteredRows: any[];
data_device: any[];
kwhTerm: string = "";
costTerm: string = "";
data_cost: any;
dataExport: any;
formattedEndDate: any;
spinnerExportActive = false;
constructor(
public activeModal: NgbActiveModal,
private tableexcelService: TableexcelService,
private authService: LoginService,
private monitoringService: BuildingService
) {}
ngOnInit() {
this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.fetchData();
}
ngAfterViewInit(): void {
if (this.buildingId !== 0 && this.floorId === 0 && this.roomId === 0) {
this.buildingOnly = true;
this.floorOnly = false;
this.roomOnly = false;
} else if (
this.buildingId !== 0 &&
this.floorId !== 0 &&
this.roomId === 0
) {
this.buildingOnly = false;
this.floorOnly = true;
this.roomOnly = false;
} else if (
this.buildingId !== 0 &&
this.floorId !== 0 &&
this.roomId !== 0
) {
this.buildingOnly = false;
this.floorOnly = false;
this.roomOnly = true;
}
}
fetchData() {
this.monitoringService
.getDetailChart(
this.dataIndex + 1,
this.buildingId,
this.floorId,
this.roomId
)
.subscribe((response) => {
this.dataExport = response.data;
this.data_cost = response.data.map((item) => ({
BuildingName: item.building_name,
floorName: item.floor_name,
roomName: item.room_name,
deviceName: item.device_name,
duration: item.duration,
priceKwh: item.price_kwh,
estimationCost: item.estimation_cost,
// periode: this.convertToUTC7(item.periode)
}));
console.log(this.data_cost);
});
}
convertToUTC7(dateString: string): string {
const date = new Date(dateString);
const utc7Offset = 7 * 60; // UTC+7 in minutes
const localOffset = date.getTimezoneOffset();
const totalOffset = utc7Offset - localOffset;
const utc7Date = new Date(date.getTime() + totalOffset * 60 * 1000);
return utc7Date.toISOString();
}
export() {
this.spinnerExportActive = true;
setTimeout(() => {
let columnsToExport = [];
let exportText = "";
if (this.mode === "building") {
columnsToExport = [
"floorName",
"roomName",
"deviceName",
"duration",
"priceKwh",
"estimationCost",
];
exportText = "export_detail_monitoring_building";
} else if (this.mode === "floor") {
columnsToExport = [
"roomName",
"deviceName",
"duration",
"priceKwh",
"estimationCost",
];
exportText = "export_detail_monitoring_floor";
} else if (this.mode === "room") {
columnsToExport = [
"deviceName",
"duration",
"priceKwh",
"estimationCost",
];
exportText = "export_detail_monitoring_room";
}
this.tableexcelService.exportAsExcelFileMonitoringDetail(
this.data_cost,
exportText,
columnsToExport,
this.mode
);
this.spinnerExportActive = false;
this.activeModal.close("Export completed");
}, 3000);
}
}

View File

@@ -29,6 +29,8 @@ import { NgSelectModule } from '@ng-select/ng-select';
import { ControlDeviceSeemoreComponent } from './control-device-seemore/control-device-seemore.component'; import { ControlDeviceSeemoreComponent } from './control-device-seemore/control-device-seemore.component';
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptorService } from 'src/app/interceptors/http-error-interceptor.service'; import { HttpErrorInterceptorService } from 'src/app/interceptors/http-error-interceptor.service';
import { ClipboardModule } from 'ngx-clipboard';
import { ModalExportComponent } from './modal-export/modal-export.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -39,7 +41,8 @@ import { HttpErrorInterceptorService } from 'src/app/interceptors/http-error-int
FilterTopUsePipe, FilterTopUsePipe,
SurveillanceComponent, SurveillanceComponent,
WaterComponent, WaterComponent,
ControlDeviceSeemoreComponent ControlDeviceSeemoreComponent,
ModalExportComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@@ -59,6 +62,7 @@ import { HttpErrorInterceptorService } from 'src/app/interceptors/http-error-int
NgxMasonryModule, NgxMasonryModule,
UiSwitchModule, UiSwitchModule,
NgSelectModule, NgSelectModule,
ClipboardModule,
NgxEchartsModule.forRoot({ NgxEchartsModule.forRoot({
echarts: () => import('echarts') echarts: () => import('echarts')
}), }),
@@ -79,7 +83,7 @@ import { HttpErrorInterceptorService } from 'src/app/interceptors/http-error-int
component: WaterComponent, component: WaterComponent,
}, },
{ {
path: 'control-device-see-more/:id', path: 'control-device-see-more/:buildingId/:floorId/:roomId/:mode',
component: ControlDeviceSeemoreComponent, component: ControlDeviceSeemoreComponent,
}, },
{ {
@@ -88,10 +92,21 @@ import { HttpErrorInterceptorService } from 'src/app/interceptors/http-error-int
data: { mode: 'room' } data: { mode: 'room' }
}, },
{ {
path: 'view-new-building/:id', path: 'view-detail-building/:buildingId',
component: DetailComponent, component: DetailComponent,
data: { mode: 'build' } data: { mode: 'building' }
}, },
{
path: 'view-detail-floor/:buildingId/:floorId',
component: DetailComponent,
data: { mode: 'floor' }
},
{
path: 'view-detail-room/:buildingId/:floorId/:roomId',
component: DetailComponent,
data: { mode: 'room' }
},
{ {
path: 'view-new-room/:id', path: 'view-new-room/:id',
component: DetailComponent, component: DetailComponent,

View File

@@ -6,5 +6,10 @@
background: rgba(255, 249, 249, 0.5) !important; background: rgba(255, 249, 249, 0.5) !important;
} }
:host ::ng-deep .progress-bar { :host ::ng-deep .progress-bar {
background-color: #bef264 !important; background-color: #2f5137 !important;
} }
.room-custom{
font-family: Montserrat, sans-serif;
color: #ffffff !important;
}

View File

@@ -1,4 +1,4 @@
<div class="app-content content" style="background-color: #000000 !important"> <div class="app-content content">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="content-header row mb-1"> <div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb> <app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
@@ -24,20 +24,20 @@
class="col-xl-3 col-lg-6 col-12" class="col-xl-3 col-lg-6 col-12"
*ngFor="let data of filteredRows" *ngFor="let data of filteredRows"
> >
<div class="card pull-up" style="background-color: #252525 !important"> <div class="card pull-up" style="background-color: #DDE1E6 !important">
<div class="card-content"> <div class="card-content">
<div class="card-header mb-2" style="background-color: #252525 !important"> <div class="card-header mb-2" style="background-color: #DDE1E6 !important">
<div class="row"> <div class="row">
<div class="col-12 text-center"> <div class="col-12 text-center">
<h5 <h5
class="text-muted mb-1" class="text-muted mb-1 room-custom"
style="font-family: Montserrat, sans-serif; color: #ffffff !important;" style="color: #242222 !important;"
> >
Room Room
</h5> </h5>
<h4 <h4
class="text-muted mb-0" class="text-muted mb-0"
style="font-family: Montserrat, sans-serif; color: #ffffff !important;" style="font-family: Montserrat, sans-serif; color: #242222 !important;"
> >
{{ data.name }} {{ data.name }}
</h4> </h4>
@@ -49,13 +49,13 @@
<div class="media d-flex"> <div class="media d-flex">
<div class="media-body text-left"> <div class="media-body text-left">
<!-- <h3 class="info">{{ data.value }} kWh</h3> --> <!-- <h3 class="info">{{ data.value }} kWh</h3> -->
<h3 style="color: #ffffff;">{{data.totalKwh}} kWh</h3> <h3 style="color: #242222;">{{data.totalKwh}} kWh</h3>
<h6 style="color: #ffffff;">Consumption</h6> <h6 style="color: #242222;">Consumption</h6>
</div> </div>
<div> <div>
<i <i
class="feather ft-server info font-large-2 float-right" class="feather ft-server info font-large-2 float-right"
style="color: #bef264 !important;" style="color: #2f5137 !important;"
></i> ></i>
</div> </div>
</div> </div>

View File

@@ -25,7 +25,8 @@ export class RoomComponent implements OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.route.data.subscribe((data) => { this.route.data.subscribe((data) => {
this.mode = data.mode; this.mode = data.mode;
console.log(this.mode); console.log(this.mode);

View File

@@ -71,7 +71,7 @@ export class DeviceService {
deviceSwitch(data): Observable<any> { deviceSwitch(data): Observable<any> {
const endpoint = `/devices`; const endpoint = `/devices`;
const url = `${BASE_URL}${endpoint}/device-switch`; const url = `${BASE_URL}${endpoint}/device-command`;
const headers = new HttpHeaders({ const headers = new HttpHeaders({
"Content-Type": "application/json", "Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", "x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
@@ -88,4 +88,91 @@ export class DeviceService {
}); });
return this.http.get<any>(url, { headers }); return this.http.get<any>(url, { headers });
} }
getDeviceStatus(id): Observable<any> {
const endpoint = `/devices`;
const url = `${BASE_URL}${endpoint}/status?id=${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
getDeviceByid(id): Observable<any> {
const endpoint = `/devices`;
const url = `${BASE_URL}${endpoint}/${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
filterDashboard(building, floor): Observable<any> {
const endpoint = `/building/dashboard/list`;
const params = new URLSearchParams({
building_id: building ? building : 0,
floor_id: floor ? floor :0,
});
// if (category) {
// params.append("category_id", category);
// }
const url = `${BASE_URL}${endpoint}?${params.toString()}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
getDeviceScheduler(id): Observable<any> {
const endpoint = `/device-scheduler`;
const url = `${BASE_URL}${endpoint}?device_id=${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
postDeviceScheduler(data): Observable<any> {
const endpoint = `/device-scheduler`;
const url = `${BASE_URL}${endpoint}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
}
putDeviceScheduler(data, id): Observable<any> {
const endpoint = `/device-scheduler/${id}`;
const url = `${BASE_URL}${endpoint}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.put<any>(url, data, { headers });
}
putDeviceSchedulerActive(data, id): Observable<any> {
const endpoint = `/device-scheduler/${id}/Active`;
const url = `${BASE_URL}${endpoint}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.put<any>(url, data, { headers });
}
deleteDeviceScheduler(id): Observable<any> {
const endpoint = `/device-scheduler/${id}`;
const url = `${BASE_URL}${endpoint}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.delete<any>(url, { headers });
}
} }

View File

@@ -1,71 +1,46 @@
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http"; import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
@Injectable({ @Injectable({
providedIn: "root", providedIn: "root",
}) })
export class EnergyMonitoringService { export class EnergyMonitoringService {
private readonly baseUrl = 'https://kapi.absys.ninja/hemat';
private readonly apiKey = 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT';
private readonly headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': this.apiKey
});
constructor(private http: HttpClient) {} constructor(private http: HttpClient) {}
private get<T>(endpoint: string, params: any = {}): Observable<T> {
const url = `${this.baseUrl}/${endpoint}`;
return this.http.get<T>(url, { headers: this.headers, params });
}
getListRoomData(): Observable<any> { getListRoomData(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room/list`; return this.get<any>('room/list');
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
} }
getDashboardTopCard(id): Observable<any> { getDashboardTopCard(buildingId: string, floorId: string, roomId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/dashboard/top-card?building_id=${id}`; return this.get<any>('dashboard/top-card', { building_id: buildingId, floor_id: floorId, room_id: roomId });
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
} }
getDashboardSummary(id): Observable<any> { getDashboardSummary(buildingId: string, floorId: string, roomId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/dashboard/summary-cost?building_id=${id}`; return this.get<any>('dashboard/summary-cost', { building_id: buildingId, floor_id: floorId, room_id: roomId });
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
} }
getDashboardAirQuality(id): Observable<any> { getDashboardDeviceCategory(buildingId: string, floorId: string, roomId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/dashboard/air-quality?building_id=${id}`; return this.get<any>('dashboard/device-category-use', { building_id: buildingId, floor_id: floorId, room_id: roomId });
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
} }
getDashboardTemperature(id): Observable<any> { getDashboardChartKwhWater(buildingId: string, floorId: string, roomId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/dashboard/temperature-humidity?building_id=${id}`; return this.get<any>('dashboard/chartKwhWater', { building_id: buildingId, floor_id: floorId, room_id: roomId });
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
} }
getDashboardDeviceCategory(id): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/dashboard/device-category-use?building_id=${id}`; getDeviceStatus(deviceId: any): Observable<any> {
const headers = new HttpHeaders({ return this.get<any>('devices/status', { id: deviceId });
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
getDashboardChartKwhWater(id): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/dashboard/chartKwhWater?building_id=${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
} }
} }

View File

@@ -1,9 +1,20 @@
import { Injectable } from "@angular/core"; // src/app/services/login.service.ts
import { Injectable, NgZone } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http"; import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs"; import {
BehaviorSubject,
Observable,
of,
Subject,
timer,
fromEvent,
merge,
} from "rxjs";
import { jwtDecode } from "jwt-decode"; import { jwtDecode } from "jwt-decode";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { switchMap, debounceTime, mapTo, startWith } from "rxjs/operators";
import { AuthService } from "src/app/_services/auth.service"; import { AuthService } from "src/app/_services/auth.service";
import { error } from "console";
const BASE_URL = "https://kapi.absys.ninja/hemat"; const BASE_URL = "https://kapi.absys.ninja/hemat";
interface CustomJwtPayload { interface CustomJwtPayload {
@@ -23,11 +34,28 @@ interface CustomJwtPayload {
}) })
export class LoginService { export class LoginService {
private readonly tokenKey = "currentUser"; private readonly tokenKey = "currentUser";
private tabSelected = new BehaviorSubject<string | null>(null);
public _tabSelected = this.tabSelected.asObservable();
private activitySubject = new Subject<boolean>();
public activity$: Observable<boolean> = this.activitySubject.asObservable();
currentUser: any;
constructor( constructor(
private http: HttpClient, private http: HttpClient,
private router: Router, private router: Router,
public logoutService: AuthService private authService: AuthService,
) {} private ngZone: NgZone
) {
this.startTrackingActivity();
this.startTokenCheck();
this.currentUser = JSON.parse(localStorage.getItem("currentUser"));
}
setTabsSelected(e: string) {
this.tabSelected.next(e);
}
updatePassword(data: any): Observable<any> { updatePassword(data: any): Observable<any> {
const endpoint = `/users`; const endpoint = `/users`;
@@ -39,7 +67,7 @@ export class LoginService {
return this.http.put<any>(url, data, { headers }); return this.http.put<any>(url, data, { headers });
} }
getDataProfil(id): Observable<any> { getDataProfil(id: string): Observable<any> {
const endpoint = `/users`; const endpoint = `/users`;
const url = `${BASE_URL}${endpoint}/byUserid/${id}`; const url = `${BASE_URL}${endpoint}/byUserid/${id}`;
const headers = new HttpHeaders({ const headers = new HttpHeaders({
@@ -56,7 +84,7 @@ export class LoginService {
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", "x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
}); });
return this.http.post(`${url}`, data, { headers }); return this.http.post<any>(`${url}`, data, { headers });
} }
updateUserProfile(data: any): Observable<any> { updateUserProfile(data: any): Observable<any> {
@@ -67,36 +95,113 @@ export class LoginService {
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", "x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
}); });
return this.http.post(`${url}`, body, { headers }); return this.http.post<any>(`${url}`, body, { headers });
} }
isTokenExpired(): boolean { isTokenExpired(): Observable<boolean> {
const tokenData = localStorage.getItem(this.tokenKey); const tokenData = localStorage.getItem(this.tokenKey);
if (tokenData) { if (tokenData) {
const tokenInfo = JSON.parse(tokenData); const tokenInfo = JSON.parse(tokenData);
const decodedToken = jwtDecode<CustomJwtPayload>(tokenInfo.refresh_token); const decodedToken = jwtDecode<CustomJwtPayload>(tokenInfo.refresh_token);
const expiryDate = decodedToken.exp * 1000; const expiryDate = decodedToken.exp * 1000;
const now = new Date().getTime(); const now = new Date().getTime();
return now > expiryDate; const timeLeft = expiryDate - now;
return of(timeLeft <= 2 * 60 * 1000);
} }
return true; return of(true);
} }
checkTokenAndRedirect(): void { checkTokenAndRedirect(): void {
if (this.isTokenExpired()) { this.isTokenExpired().subscribe((isExpired) => {
// Token sudah kedaluwarsa, arahkan ke halaman login if (isExpired) {
// console.log("Token expired, redirecting to login page..."); this.authService.doLogout().then(
this.logoutService.doLogout().then( () => {
(res) => { this.router.navigate(["/login"]);
this.router.navigate(["/login"]); window.location.reload();
}, },
(err) => { (err) => {
console.log(err); console.log(err);
}
);
this.router.navigate(["/login"]);
window.location.reload();
} else {
console.log("Token is valid, continuing...");
}
});
}
startTokenCheck(): void {
timer(0, 2 * 60 * 1000) // Check every 5 minutes
.pipe(switchMap(() => this.isTokenExpired()))
.subscribe((isExpired) => {
// console.log(isExpired);
if (isExpired) {
this.activity$.subscribe((isActive) => {
// console.log(isActive);
if (!isActive) {
this.checkTokenAndRedirect();
} else {
console.log(
"Token expired but user is active. Refresh token not implemented."
);
this.updateUserProfile(this.currentUser.refresh_token).subscribe(
(resp) => {
const decodedToken = jwtDecode<CustomJwtPayload>(
resp.access_token
);
localStorage.setItem(
"account_info",
JSON.stringify(decodedToken)
);
const userProfile = {
access_token: resp.access_token,
refresh_token: resp.refresh_token,
displayName: decodedToken.name,
buildingId: 4,
};
localStorage.setItem(
"currentUser",
JSON.stringify(userProfile)
);
window.location.reload();
}, (error) => {
console.error(error);
this.checkTokenAndRedirect();
}
);
}
});
} }
});
}
startTrackingActivity(): void {
this.ngZone.runOutsideAngular(() => {
const activityEvents$ = merge(
fromEvent(window, "mousemove"),
fromEvent(window, "click"),
fromEvent(window, "keypress"),
fromEvent(window, "scroll")
); );
this.router.navigate(["/login"]);
} else { activityEvents$
console.log("Token is valid, continuing..."); .pipe(
} startWith(null),
switchMap(() =>
merge(
timer(0).pipe(mapTo(true)),
timer(5 * 60 * 1000).pipe(mapTo(false)) // 5 minutes of inactivity
)
),
debounceTime(300)
)
.subscribe((active) => {
this.ngZone.run(() => this.activitySubject.next(active));
});
});
} }
} }

View File

@@ -14,131 +14,6 @@ export class MasterService {
this.loadDataIcon = `${this.apiBaseURL}/hemat/remixicons.json`; this.loadDataIcon = `${this.apiBaseURL}/hemat/remixicons.json`;
} }
getMasterListData(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-param/list`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
getMasterData(page: number = 1, limit: number = 100): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-param?page=${page}&limit=${limit}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
postHeaderDetailParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.post<any>(url, data, { headers });
}
putHeaderDetailParam(data: any, id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param/${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.put<any>(url, data, { headers });
}
deleteHeaderDetailParam(id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param/${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.delete<any>(url, { headers });
}
postMasterBuildingParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.post<any>(url, data, { headers });
}
getMasterBuildingData(page: number = 1, limit: number = 100): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building?page=${page}&limit=${limit}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
getBuildingList(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/list`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
putMasterBuildingParam(data: any, id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.put<any>(url, data, { headers });
}
deleteMasterBuildingParam(id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.delete<any>(url, { headers });
}
postMasterRoomParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.post<any>(url, data, { headers });
}
putMasterRoomParam(data: any, id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room/${id}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.put<any>(url, data, { headers });
}
getListRoomData(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room/list`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
getMasterRoomData(page: number = 1, limit: number = 100): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room?page=${page}&limit=${limit}`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
getIconData(): Observable<any> { getIconData(): Observable<any> {
return this.http.get(this.loadDataIcon, httpOptions); return this.http.get(this.loadDataIcon, httpOptions);
} }

View File

@@ -2,252 +2,175 @@ import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http"; import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable({ @Injectable({
providedIn: "root", providedIn: "root",
}) })
export class BuildingService { export class BuildingService {
private readonly apiBaseURL = 'https://kapi.absys.ninja/hemat';
private readonly apiKey = 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT';
private readonly headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": this.apiKey,
});
loadDataIcon = null;
constructor(private http: HttpClient) {} constructor(private http: HttpClient) {}
private get<T>(endpoint: string, params: any = {}): Observable<T> {
const url = `${this.apiBaseURL}/${endpoint}`;
return this.http.get<T>(url, { headers: this.headers, params });
}
private post<T>(endpoint: string, data: any): Observable<T> {
const url = `${this.apiBaseURL}/${endpoint}`;
return this.http.post<T>(url, data, { headers: this.headers });
}
private put<T>(endpoint: string, data: any): Observable<T> {
const url = `${this.apiBaseURL}/${endpoint}`;
return this.http.put<T>(url, data, { headers: this.headers });
}
private delete<T>(endpoint: string, params: any = {}): Observable<T> {
const url = `${this.apiBaseURL}/${endpoint}`;
return this.http.delete<T>(url, { headers: this.headers, params });
}
postLogin(data: any): Observable<any> { postLogin(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/users/login`; return this.post<any>('users/login', data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
} }
listBuilding(): Observable<any> { listBuilding(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/dashboard/list`; return this.get<any>('building/dashboard/list');
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getBuildingData(page: number = 1, limit: number = 10): Observable<any> { getRoomByBuildingId(buildingId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building?page=${page}&limit=${limit}`; return this.get<any>('room-building/list/byIds', { buildingId });
// const headers = new HttpHeaders().set('Content-Type', 'application/json');
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getRoomByBuildingId(buildingId: any): Observable<any> { getDeviceById(deviceId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room-building/list/byIds?buildingId=${buildingId}`; return this.get<any>(`devices/${deviceId}`);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
getDeviceById(deviceId: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/devices/${deviceId}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getMasterListData(): Observable<any> { getMasterListData(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-param/list`; return this.get<any>('header-param/list');
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getMasterData(page: number = 1, limit: number = 100): Observable<any> { getMasterData(page: number = 1, limit: number = 100): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-param?page=${page}&limit=${limit}`; return this.get<any>('header-param', { page, limit });
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getMasterBuildingData( getMasterDataListFloor(buildingId: string): Observable<any> {
page: number = 1, return this.get<any>('header-detail-param/list', { headerId: 6, building_id: buildingId });
limit: number = 100 }
): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building?page=${page}&limit=${limit}`; getMasterBuildingData(page: number = 1, limit: number = 100): Observable<any> {
const headers = new HttpHeaders({ return this.get<any>('building', { page, limit });
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getBuildingList(): Observable<any> { getBuildingList(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/list`; return this.get<any>('building/list');
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getListRoomData(): Observable<any> { getListRoomData(): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room/list`; return this.get<any>('room/list');
const headers = new HttpHeaders({ }
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", getRoom(id: any): Observable<any> {
}); return this.get<any>(`room/${id}`);
return this.http.get<any>(url, { headers }); }
getListRoomDataUnmap(): Observable<any> {
return this.get<any>('room/list/unmap');
}
getListFloorDataUnmap(id: any): Observable<any> {
return this.get<any>('header-detail-param/list/unmap-room-building', { headerId: id });
} }
getMasterRoomData(page: number = 1, limit: number = 100): Observable<any> { getMasterRoomData(page: number = 1, limit: number = 100): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room?page=${page}&limit=${limit}`; return this.get<any>('room', { page, limit });
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
getCostManagement(page: number = 1, limit: number = 100): Observable<any> { getCostManagement(page: number = 1, limit: number = 100): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/cost_management?page=${page}&limit=${limit}&building_id=4&periode=2024-06`; return this.get<any>('cost_management', { page, limit, building_id: 4, periode: '2024-06' });
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
postHeaderDetailParam(data: any): Observable<any> { postHeaderDetailParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param`; return this.post<any>('header-detail-param', data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
}
putHeaderDetailParam(data: any, id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param/${id}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.put<any>(url, data, { headers });
} }
deleteHeaderDetailParam(id: any): Observable<any> { putHeaderDetailParam(data: any, id: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param/${id}`; return this.put<any>(`header-detail-param/${id}`, data);
const headers = new HttpHeaders({ }
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", getHeaderDetailParam(id: any): Observable<any> {
}); return this.get<any>(`header-detail-param/${id}`);
return this.http.delete<any>(url, { headers }); }
deleteHeaderDetailParam(id: string): Observable<any> {
return this.delete<any>(`header-detail-param/${id}`);
} }
postMasterBuildingParam(data: any): Observable<any> { postMasterBuildingParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building`; return this.post<any>('building', data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
}
putMasterBuildingParam(data: any, id: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/${id}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.put<any>(url, data, { headers });
} }
deleteMasterBuildingParam(id: any): Observable<any> { putMasterBuildingParam(data: any, id: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/building/${id}`; return this.put<any>(`building/${id}`, data);
const headers = new HttpHeaders({ }
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", deleteMasterBuildingParam(id: string): Observable<any> {
}); return this.delete<any>(`building/${id}`);
return this.http.delete<any>(url, { headers });
} }
postMasterRoomParam(data: any): Observable<any> { postMasterRoomParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room`; return this.post<any>('room', data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
} }
putMasterRoomParam(data: any, id: any): Observable<any> { putMasterRoomParam(data: any, id: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room/${id}`; return this.put<any>(`room/${id}`, data);
const headers = new HttpHeaders({ }
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT", deleteRoom(id: string): Observable<any> {
}); return this.delete<any>(`room/${id}`);
return this.http.put<any>(url, data, { headers });
} }
postBatchBuilding(data: any): Observable<any> { postBatchBuilding(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room-building/post-batch/room`; return this.post<any>('room-building/post-batch/room', data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
} }
getBuildingRoomList(page: number = 1, limit: number = 1000): Observable<any> { getBuildingRoomList(page: number = 1, limit: number = 1000): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room-building?page=${page}&limit=${limit}`; return this.get<any>('room-building', { page, limit });
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
puttBuildingRoom(data: any, id: any): Observable<any> { putBuildingRoom(data: any, id: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room-building/${id}`; return this.put<any>(`room-building/${id}`, data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.put<any>(url, data, { headers });
} }
putDevice(data: any, id: any): Observable<any> { putDevice(data: any, id: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/devices/${id}`; return this.put<any>(`devices/${id}`, data);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.put<any>(url, data, { headers });
} }
getRoomBuildingById(roomBuildingId: any): Observable<any> { getRoomBuildingById(roomBuildingId: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room-building/${roomBuildingId}`; return this.get<any>(`room-building/${roomBuildingId}`);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
} }
deleteRoomBuilding(id: any): Observable<any> { deleteRoomBuilding(id: string): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/room-building/${id}`; return this.delete<any>(`room-building/${id}`);
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.delete<any>(url, { headers });
} }
getDevicesWithSwitchMapping(devices: any[]): any[] { getIconData(): Observable<any> {
return devices.filter((device) => return this.http.get(this.loadDataIcon, httpOptions);
device.mapping.some((map: any) => map.name.includes('switch'))
// device.mapping.some((map: any) => console.log(map))
);
} }
getDetailChart(date_index: any, building_id: any, floor_id: any, room_id: any): Observable<any> {
return this.get<any>(`/dashboard/chartKwhWater/detail?date_index=${date_index}&building_id=${building_id}&floor_id=${floor_id}&room_id=${room_id}`);
}
} }

View File

@@ -0,0 +1,33 @@
import { Injectable, NgZone } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserActivityService {
private activitySubject = new Subject<boolean>();
private timeoutId: any;
constructor(private ngZone: NgZone) {
this.setupActivityListeners();
}
private setupActivityListeners(): void {
const events = ['click', 'mousemove', 'keypress'];
events.forEach(event => {
window.addEventListener(event, () => this.resetTimeout(), true);
});
}
private resetTimeout(): void {
this.ngZone.runOutsideAngular(() => {
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => this.activitySubject.next(false), 300000); // 5 minutes
this.activitySubject.next(true);
});
}
get activity$(): Observable<boolean> {
return this.activitySubject.asObservable();
}
}

View File

@@ -1,7 +1,7 @@
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #fbfbfb !important">
<div class="card-content"> <div class="card-content">
<div class="card-header" style="background-color: #252525 !important"> <div class="card-header" style="background-color: #fbfbfb !important">
<h2 style="color: #ffffff"></h2> <h2 style="color: #242222"></h2>
</div> </div>
<div class="card-body"> <div class="card-body">
<form [formGroup]="profilInfo" (ngSubmit)="onProjectInfoSubmit()"> <form [formGroup]="profilInfo" (ngSubmit)="onProjectInfoSubmit()">
@@ -9,14 +9,13 @@
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<div class="form-group"> <div class="form-group">
<label for="firstName" style="color: #ffffff">First Name</label> <label for="firstName" style="color: #242222">First Name</label>
<input <input
type="text" type="text"
id="firstName" id="firstName"
class="form-control" class="form-control"
formControlName="firstName" formControlName="firstName"
maxlength="20" maxlength="20"
placeholder="John Vander"
[ngClass]="{'is-invalid': profilInfo.get('firstName').invalid && profilInfo.get('firstName').touched}" [ngClass]="{'is-invalid': profilInfo.get('firstName').invalid && profilInfo.get('firstName').touched}"
/> />
<div *ngIf="profilInfo.get('firstName').invalid && profilInfo.get('firstName').touched" class="text-danger"> <div *ngIf="profilInfo.get('firstName').invalid && profilInfo.get('firstName').touched" class="text-danger">
@@ -24,14 +23,13 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="lastName" style="color: #ffffff">Last Name</label> <label for="lastName" style="color: #242222">Last Name</label>
<input <input
type="text" type="text"
id="lastName" id="lastName"
class="form-control" class="form-control"
formControlName="lastName" formControlName="lastName"
maxlength="20" maxlength="20"
placeholder="John Vander"
[ngClass]="{'is-invalid': profilInfo.get('lastName').invalid && profilInfo.get('lastName').touched}" [ngClass]="{'is-invalid': profilInfo.get('lastName').invalid && profilInfo.get('lastName').touched}"
/> />
<div *ngIf="profilInfo.get('firstName').invalid && profilInfo.get('firstName').touched" class="text-danger"> <div *ngIf="profilInfo.get('firstName').invalid && profilInfo.get('firstName').touched" class="text-danger">
@@ -39,13 +37,12 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="email" style="color: #ffffff">Email</label> <label for="email" style="color: #242222">Email</label>
<input <input
type="text" type="text"
id="email" id="email"
class="form-control" class="form-control"
formControlName="email" formControlName="email"
placeholder="email@email.com"
maxlength="50" maxlength="50"
[ngClass]="{'is-invalid': profilInfo.get('email').invalid && profilInfo.get('email').touched}" [ngClass]="{'is-invalid': profilInfo.get('email').invalid && profilInfo.get('email').touched}"
/> />
@@ -54,14 +51,13 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="phone" style="color: #ffffff">Phone</label> <label for="phone" style="color: #242222">Phone</label>
<input <input
type="text" type="text"
id="phone" id="phone"
class="form-control" class="form-control"
formControlName="phone" formControlName="phone"
maxlength="13" maxlength="13"
placeholder="08**************"
pattern="^[0-9]*$" pattern="^[0-9]*$"
[ngClass]="{'is-invalid': profilInfo.get('phone').invalid && profilInfo.get('phone').touched}" [ngClass]="{'is-invalid': profilInfo.get('phone').invalid && profilInfo.get('phone').touched}"
/> />
@@ -117,9 +113,9 @@
type="button" type="button"
class="btn btn-warning mr-1" class="btn btn-warning mr-1"
style=" style="
color: #ffffff !important; color: #242222 !important;
background-color: transparent !important; background-color: transparent !important;
border-color: #ffffff !important; border-color: #fbfbfb !important;
border-radius: 10px; border-radius: 10px;
width: 145px; width: 145px;
" "
@@ -131,8 +127,8 @@
type="submit" type="submit"
class="btn btn-primary" class="btn btn-primary"
style=" style="
color: #000000 !important; color: #ffffff !important;
background-color: #c3f164 !important; background-color: #37a647 !important;
border-radius: 10px; border-radius: 10px;
width: 145px; width: 145px;
" "

View File

@@ -5,6 +5,7 @@ import { ToastrService } from "ngx-toastr";
import { jwtDecode } from "jwt-decode"; import { jwtDecode } from "jwt-decode";
import { AuthService } from "src/app/_services/auth.service"; import { AuthService } from "src/app/_services/auth.service";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import * as _ from "lodash"
interface CustomJwtPayload { interface CustomJwtPayload {
exp: number; exp: number;
scope: string; scope: string;
@@ -30,7 +31,7 @@ export class ProfilInformationComponent {
storedData: any; storedData: any;
currentUser: any; currentUser: any;
disableButton: boolean = false; disableButton: boolean = false;
oldData: any;
url: any = "https://www.w3schools.com/howto/img_avatar.png"; url: any = "https://www.w3schools.com/howto/img_avatar.png";
fileSelected: any = null; fileSelected: any = null;
@@ -40,19 +41,35 @@ export class ProfilInformationComponent {
private toastr: ToastrService, private toastr: ToastrService,
public logoutService: AuthService, public logoutService: AuthService,
private router: Router private router: Router
) {} ) {
this.authService._tabSelected.subscribe(res => {
console.log(res);
console.log(this.oldData);
console.log(this.profilInfo.value);
if (res === "update-password") {
if (this.oldData !== this.profilInfo.value) {
console.log('ada perubahan');
return false
} else {
console.log('tidak ada perubahan');
}
}
})
}
ngOnInit(): void { ngOnInit(): void {
this.storedData = JSON.parse(localStorage.getItem("account_info")); this.storedData = JSON.parse(localStorage.getItem("account_info"));
this.currentUser = JSON.parse(localStorage.getItem("currentUser")); this.currentUser = JSON.parse(localStorage.getItem("currentUser"));
this.authService.checkTokenAndRedirect(); this.authService.startTokenCheck();
this.authService.startTrackingActivity();
this.profilInfo = this.formBuilder.group({ this.profilInfo = this.formBuilder.group({
firstName: ["", Validators.required], firstName: ["", Validators.required],
lastName: ["", Validators.required], lastName: ["", Validators.required],
email: ["", [Validators.required, Validators.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)]], email: ["", [Validators.required, Validators.pattern(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)]],
phone: ["", [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]], phone: ["", [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
image: [null], image: [null, Validators.required],
}); });
this.dataProfil(this.storedData.sub); this.dataProfil(this.storedData.sub);
this.profilInfo.valueChanges.subscribe(() => { this.profilInfo.valueChanges.subscribe(() => {
@@ -69,6 +86,10 @@ export class ProfilInformationComponent {
phone: data.data.phone, phone: data.data.phone,
image: [null], image: [null],
}); });
// this.oldData._.cloneDeep(this.profilInfo.value);
this.oldData = _.cloneDeep(this.profilInfo.value)
console.log(this.oldData);
if ( if (
data.data.image_path !== "https://kapi.absys.ninja/hemat/image/null" data.data.image_path !== "https://kapi.absys.ninja/hemat/image/null"
) { ) {

View File

@@ -1,10 +1,10 @@
<section id="update-password"> <section id="update-password">
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
<div class="card" style="background-color: #252525 !important"> <div class="card" style="background-color: #fbfbfb !important">
<div class="card-content"> <div class="card-content">
<div class="card-header" style="background-color: #252525 !important"> <div class="card-header" style="background-color: #fbfbfb !important">
<h2 style="color: #ffffff">Update Password</h2> <h2 style="color: #242222">Update Password</h2>
</div> </div>
<div class="card-body"> <div class="card-body">
<form [formGroup]="profilInfo" (ngSubmit)="onProjectInfoSubmit()"> <form [formGroup]="profilInfo" (ngSubmit)="onProjectInfoSubmit()">
@@ -49,7 +49,9 @@
</button> </button>
</div> --> </div> -->
<div class="form-group"> <div class="form-group">
<label for="newPass" style="color: #ffffff">New Password</label> <label for="newPass" style="color: #242222"
>New Password</label
>
<div class="input-group"> <div class="input-group">
<input <input
[type]="showNewPass ? 'text' : 'password'" [type]="showNewPass ? 'text' : 'password'"
@@ -67,29 +69,38 @@
type="button" type="button"
class="btn btn-link" class="btn btn-link"
(click)="toggleNewPassVisibility()" (click)="toggleNewPassVisibility()"
style="color: #c3f164 !important;" style="color: #37a647 !important"
> >
<i [class]="showNewPass ? 'fa fa-eye-slash' : 'fa fa-eye'"></i> <i
[class]="
showNewPass ? 'fa fa-eye-slash' : 'fa fa-eye'
"
></i>
</button> </button>
</div> </div>
<small
class="form-text text-muted danger"
*ngIf="submitted && f.newPass.errors"
class="invalid-feedback"
>
<div *ngIf="f.newPass.errors.required">
New Password is required
</div>
<div *ngIf="f.newPass.errors.minlength">
New Password must be at least 8 characters long
</div>
<div *ngIf="f.newPass.errors.pattern">
New Password must contain at least one uppercase
letter, one lowercase letter, and one number
</div>
</small>
</div> </div>
<small
class="form-text text-muted danger"
*ngIf="submitted && f.newPass.errors"
class="invalid-feedback"
>
<div *ngIf="f.newPass.errors.required">New Password is required</div>
<div *ngIf="f.newPass.errors.minlength">
New Password must be at least 8 characters long
</div>
<div *ngIf="f.newPass.errors.pattern">
New Password must contain at least one uppercase letter, one lowercase letter, and one number
</div>
</small>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="confirmPass" style="color: #ffffff">Confirm Password</label> <label for="confirmPass" style="color: #242222"
>Confirm Password</label
>
<div class="input-group"> <div class="input-group">
<input <input
[type]="showConfirmPass ? 'text' : 'password'" [type]="showConfirmPass ? 'text' : 'password'"
@@ -107,22 +118,30 @@
type="button" type="button"
class="btn btn-link" class="btn btn-link"
(click)="toggleConfirmPassVisibility()" (click)="toggleConfirmPassVisibility()"
style="color: #c3f164 !important;" style="color: #37a647 !important"
> >
<i [class]="showConfirmPass ? 'fa fa-eye-slash' : 'fa fa-eye'"></i> <i
[class]="
showConfirmPass
? 'fa fa-eye-slash'
: 'fa fa-eye'
"
></i>
</button> </button>
</div> </div>
<small
class="form-text text-muted danger"
*ngIf="submitted && f.confirmPass.errors"
class="invalid-feedback"
>
<div *ngIf="f.confirmPass.errors.required">
Confirm Password is required
</div>
<div *ngIf="f.confirmPass.errors.matchPassword">
Confirm Password must match the New Password
</div>
</small>
</div> </div>
<small
class="form-text text-muted danger"
*ngIf="submitted && f.confirmPass.errors"
class="invalid-feedback"
>
<div *ngIf="f.confirmPass.errors.required">Confirm Password is required</div>
<div *ngIf="f.confirmPass.errors.matchPassword">
Confirm Password must match the New Password
</div>
</small>
</div> </div>
</div> </div>
</div> </div>
@@ -132,9 +151,9 @@
type="button" type="button"
class="btn btn-warning mr-1" class="btn btn-warning mr-1"
style=" style="
color: #ffffff !important; color: #242222 !important;
background-color: transparent !important; background-color: transparent !important;
border-color: #ffffff !important; border-color: #fbfbfb !important;
border-radius: 10px; border-radius: 10px;
width: 145px; width: 145px;
" "
@@ -146,8 +165,8 @@
type="submit" type="submit"
class="btn btn-primary" class="btn btn-primary"
style=" style="
color: #000000 !important; color: #fff !important;
background-color: #c3f164 !important; background-color: #37a647 !important;
border-radius: 10px; border-radius: 10px;
width: 145px; width: 145px;
" "

Some files were not shown because too many files have changed in this diff Show More