Compare commits
236 Commits
Author | SHA1 | Date |
---|---|---|
|
b00896d407 | |
|
7c443080d6 | |
|
98159a1584 | |
|
5c5ca65f53 | |
|
ecef25f30d | |
|
45e280c007 | |
|
ca5f0c8c0c | |
|
b1ee612602 | |
|
9654cf92e8 | |
|
a2d166ac1a | |
|
a9a7e6edd3 | |
|
b5e0962079 | |
|
633effdb9b | |
|
7a28e52e89 | |
|
c54fdd0f55 | |
|
04972e33b1 | |
|
f81dc7bf66 | |
|
2b1f6c0cfe | |
|
9529da581a | |
|
b195055651 | |
|
2a4135c966 | |
|
cd1f56e07b | |
|
9377bebcb4 | |
|
57bcbcccde | |
|
d753a3a634 | |
|
a9d135f8ef | |
|
0aac2ff194 | |
|
379bdb24da | |
|
21b75ca610 | |
|
b5cf71d008 | |
|
cd777f11ad | |
|
f4036b1a06 | |
|
4fdaa8c1bd | |
|
5410d966d0 | |
|
bfb828c15c | |
|
124f3eef4c | |
|
9b4ac3b992 | |
|
d70edcebd8 | |
|
a458f2ce3c | |
|
db9a9e415a | |
|
a9f3da867f | |
|
03c7e54bc8 | |
|
df1cd2339e | |
|
2a6cf6410d | |
|
3b3757e2a7 | |
|
95fa99799c | |
|
8cc1a2b9fb | |
|
9d8e31e7fe | |
|
c04cafa384 | |
|
e3be28b4b6 | |
|
da4100993b | |
|
0c1dd29554 | |
|
f86dfb7829 | |
|
9a29e2e4e0 | |
|
721d4e9af9 | |
|
153b47eaaa | |
|
c337a8941c | |
|
bd1cd42ed6 | |
|
7bc1fa5fe9 | |
|
768c9ee6ca | |
|
efb6ae0060 | |
|
d22eaa50e1 | |
|
60d14b2fce | |
|
6b91c937ab | |
|
fa12fcec50 | |
|
9570b77e32 | |
|
dd1deb0812 | |
|
751c36209e | |
|
4c2d40986e | |
|
5782af4c75 | |
|
5b3c9bcba4 | |
|
45f3c9b86b | |
|
9a0d0d919e | |
|
13e5ee01d2 | |
|
a9034c1a32 | |
|
28067d1704 | |
|
4ae3b51530 | |
|
dc4be31103 | |
|
0b37bcd8ee | |
|
a79493d329 | |
|
52481cbc4b | |
|
d43a26513e | |
|
06a7c9b249 | |
|
876f039603 | |
|
a455f43df6 | |
|
3ef7dab91f | |
|
8d9840acec | |
|
2194d2f720 | |
|
d5c34a5c64 | |
|
1ed4ad5da0 | |
|
f86f727ac7 | |
|
d8dc510742 | |
|
1edfbc7149 | |
|
15ae21bf9c | |
|
4c229e994a | |
|
978127f2c4 | |
|
daef6aafdc | |
|
79b6300bf0 | |
|
ae74cf2332 | |
|
5913980330 | |
|
8403bafcd1 | |
|
3172ba70b2 | |
|
ccf656dfce | |
|
4b023b2527 | |
|
a1b259ac9f | |
|
b095f870dd | |
|
b2d8a8e2f6 | |
|
71377f79cf | |
|
84dae31196 | |
|
123c39e5a2 | |
|
5afb289070 | |
|
04e8abc487 | |
|
97b2445d4f | |
|
be071b75b1 | |
|
ca30a991ae | |
|
be40cea2a1 | |
|
563165d09c | |
|
86239f03eb | |
|
99391c88bb | |
|
8e0a1abcda | |
|
f6934579ed | |
|
798babdb8a | |
|
4456b3a3f8 | |
|
197b428d18 | |
|
530b64cb10 | |
|
2a5c1ef7b9 | |
|
b5c35ab541 | |
|
4630bd2265 | |
|
f04515fb41 | |
|
f36c8d0240 | |
|
89203b9984 | |
|
fc9947da15 | |
|
8ea2f9f23b | |
|
6261b36074 | |
|
19b43b8a2d | |
|
5cbd0f09dc | |
|
e27493171e | |
|
873e24a6ac | |
|
30726d44b4 | |
|
20859bd463 | |
|
e1f42b5378 | |
|
113221db7f | |
|
b968e8e434 | |
|
23154e6862 | |
|
efaf30d55e | |
|
25559ee299 | |
|
2bc467b381 | |
|
1433c55fce | |
|
547e6ddc8f | |
|
169be42e81 | |
|
024eb6bfc7 | |
|
1ebe1acc12 | |
|
b9012f5544 | |
|
7b9935585a | |
|
49d37ee7e1 | |
|
d1393d6ec5 | |
|
1f98cbc791 | |
|
60ee717b8b | |
|
6b962028db | |
|
2180311f4e | |
|
6a0b6f4f73 | |
|
31bda7fb98 | |
|
fb1ba66cd0 | |
|
863a493b66 | |
|
33007acc77 | |
|
7a07bf5b07 | |
|
f6db135ac6 | |
|
fc10a44d5d | |
|
11184e4a46 | |
|
fe740dc3c1 | |
|
a42d328222 | |
|
6f928e2ca4 | |
|
8b2849104e | |
|
468045384e | |
|
ef118ad33e | |
|
70d8993141 | |
|
ad91c844d6 | |
|
38c936b389 | |
|
3f1c97ebe4 | |
|
4578a5db61 | |
|
a3bfd7b328 | |
|
0f1c3d6c33 | |
|
6061f4e58e | |
|
a72ca4ef59 | |
|
a6c77fe052 | |
|
b2c1020c22 | |
|
6a9451c2b5 | |
|
eaea625b4b | |
|
ded0ca21a1 | |
|
c6a51e91b1 | |
|
461735705d | |
|
e76948bb0a | |
|
b250a39d6e | |
|
690dd7ac57 | |
|
f2d277389d | |
|
608c53ab66 | |
|
bb10d57139 | |
|
c5834d5a85 | |
|
c7cb4f30ea | |
|
ca9b129494 | |
|
258d4f9cdb | |
|
4deb8d057f | |
|
1a11e3f50c | |
|
7bf0474fbb | |
|
e92c576844 | |
|
cfa140b6ea | |
|
6239e473b3 | |
|
066c40b78c | |
|
0844add2de | |
|
3aed024f71 | |
|
5ce07dc3fd | |
|
ee2b7e35e6 | |
|
3bd4e1df1c | |
|
e894196ebd | |
|
457504442e | |
|
5fa8e2314d | |
|
3cd43f3cc5 | |
|
fcc9a97d99 | |
|
a1f3069c05 | |
|
49dc5613d2 | |
|
074b1f9674 | |
|
dc987d78c9 | |
|
970c903ff4 | |
|
fcdafc8aea | |
|
5187f4e29f | |
|
3c7deac1b0 | |
|
d2e11581db | |
|
4dc2c3f1a7 | |
|
4f4dde0d07 | |
|
7b4f471047 | |
|
e3315bd761 | |
|
dc74154a27 | |
|
6c9b4f18b4 | |
|
8f0c2fb913 | |
|
dbc89d326f | |
|
14ad53025f |
File diff suppressed because it is too large
Load Diff
|
@ -62,6 +62,8 @@
|
|||
"js-datepicker": "^5.18.2",
|
||||
"jspdf": "^2.5.1",
|
||||
"jspdf-autotable": "^3.5.28",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"ng-chartist": "^4.1.0",
|
||||
"ng-multiselect-dropdown": "^0.3.9",
|
||||
|
@ -71,6 +73,7 @@
|
|||
"ngx-echarts": "^15.0.1",
|
||||
"ngx-google-places-autocomplete": "^2.0.5",
|
||||
"ngx-image-cropper": "^6.3.2",
|
||||
"ngx-mask": "^14.2.4",
|
||||
"ngx-masonry": "^14.0.1",
|
||||
"ngx-perfect-scrollbar": "^10.1.1",
|
||||
"ngx-quill": "^20.0.1",
|
||||
|
@ -82,13 +85,16 @@
|
|||
"quill": "^1.3.7",
|
||||
"quill-delta": "^5.0.0",
|
||||
"quill-mention": "^3.1.0",
|
||||
"remixicon": "^4.3.0",
|
||||
"rxjs": "^7.5.5",
|
||||
"sass": "^1.57.1",
|
||||
"save": "^2.9.0",
|
||||
"sweetalert2": "^11.11.0",
|
||||
"tree-ngx": "^4.3.0",
|
||||
"tslib": "^2.4.1",
|
||||
"util": "^0.12.5",
|
||||
"uuid": "^9.0.0",
|
||||
"video.js": "^8.12.0",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -18,3 +18,12 @@
|
|||
transform: translate(40px, 40px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-item::before {
|
||||
content: none !important; /* Removes any default content, such as "-" */
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: none !important; /* Removes any default content, such as "-" */
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,37 @@
|
|||
<div class="row">
|
||||
<div class="content-header-left col-md-6 col-12 mb-2 breadcrumb-new" *ngIf="breadcrumb">
|
||||
<h3 class="content-header-title mb-0 d-inline-block">{{breadcrumb.mainlabel}}</h3>
|
||||
<div
|
||||
class="content-header-left col-md-6 col-12 mb-2 breadcrumb-new"
|
||||
*ngIf="breadcrumb"
|
||||
>
|
||||
<button
|
||||
*ngIf="breadcrumb.isLinkBack"
|
||||
type="button"
|
||||
class="btn btn-icon btn-pure secondary mr-1"
|
||||
routerLink="{{ breadcrumb.linkBack }}"
|
||||
>
|
||||
<i class="feather ft-chevron-left" style="color: #242222"></i>
|
||||
</button>
|
||||
<h3 class="content-header-title mb-0 d-inline-block" style="color: #242222">
|
||||
{{ breadcrumb.mainlabel }}
|
||||
</h3>
|
||||
<div class="row breadcrumbs-top d-inline-block">
|
||||
<div class="breadcrumb-wrapper col-12">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item" *ngFor="let link of breadcrumb.links">
|
||||
<a *ngIf="link.isLink" routerLink="{{link.link}}">{{link.name}}</a>
|
||||
<span *ngIf="!link.isLink">{{link.name}}</span>
|
||||
</li>
|
||||
<ng-container *ngFor="let link of breadcrumb.links; let last = last">
|
||||
<li class="breadcrumb-item" style="color: #242222">
|
||||
<ng-container *ngIf="link.isLink; else notLink">
|
||||
<a routerLink="{{ link.link }}" style="color: #242222">{{ link.name }}</a>
|
||||
</ng-container>
|
||||
<ng-template #notLink>
|
||||
<span style="color: #242222">{{ link.name }}</span>
|
||||
</ng-template>
|
||||
<span *ngIf="!last" class="breadcrumb-arrow" style="color: #242222; margin: 0 5px;">
|
||||
<i class="feather ft-chevron-right"></i>
|
||||
</span>
|
||||
</li>
|
||||
</ng-container>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-header-right col-md-6 col-12">
|
||||
<div class="d-inline-block float-md-right" ngbDropdown>
|
||||
<button class="btn btn-info" id="dropdownBasic1" ngbDropdownToggle>Action</button>
|
||||
<div ngbDropdownMenu class="arrow _dropdown_mob dropdown-menu-right" aria-labelledby="dropdownBasic1">
|
||||
<button class="dropdown-item">Calender</button>
|
||||
<button class="dropdown-item">Cart</button>
|
||||
<button class="dropdown-item">Support</button>
|
||||
<div class="dropdown-divider"></div>
|
||||
<button class="dropdown-item">Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,29 +1,68 @@
|
|||
<footer id="footer" class="footer footer-static footer-light navbar-border navbar-shadow" *ngIf="showFooter">
|
||||
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2"><span
|
||||
class="float-md-left d-block d-md-inline-block">Copyright © 2022 <a [routerLink]=""
|
||||
class="text-bold-800 grey darken-2" href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
|
||||
target="_blank">PIXINVENT </a></span><span *ngIf="!hideMadeWithLove"
|
||||
class="float-md-right d-block d-md-inline-block d-none d-lg-block">Hand-crafted & Made with <i
|
||||
class="feather ft-heart pink"></i>
|
||||
<span id="scroll-top"></span></span></p>
|
||||
<footer
|
||||
id="footer"
|
||||
class="footer footer-static footer-light navbar-border navbar-shadow"
|
||||
*ngIf="showFooter"
|
||||
style="border: none !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"
|
||||
>Copyright © 2024
|
||||
<a
|
||||
[routerLink]=""
|
||||
class="text-bold-800 grey darken-2"
|
||||
href="https://allbestsistem.com/"
|
||||
target="_blank"
|
||||
style="background-color: #ffffff !important;"
|
||||
>Smart Building Management Systems (V@2024-08-28.1)
|
||||
</a></span
|
||||
>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<footer id="footer" class="footer fixed-bottom footer-light navbar-border navbar-shadow" *ngIf="fixedFooter">
|
||||
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2"><span
|
||||
class="float-md-left d-block d-md-inline-block">Copyright © 2022 <a [routerLink]=""
|
||||
class="text-bold-800 grey darken-2" href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
|
||||
target="_blank">PIXINVENT </a></span><span *ngIf="!hideMadeWithLove"
|
||||
class="float-md-right d-block d-md-inline-block d-none d-lg-block">Hand-crafted & Made with <i
|
||||
class="feather ft-heart pink"></i>
|
||||
<span id="scroll-top"></span></span></p>
|
||||
<footer
|
||||
id="footer"
|
||||
class="footer fixed-bottom footer-light navbar-border navbar-shadow"
|
||||
*ngIf="fixedFooter"
|
||||
>
|
||||
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2">
|
||||
<span class="float-md-left d-block d-md-inline-block"
|
||||
>Copyright © 2022
|
||||
<a
|
||||
[routerLink]=""
|
||||
class="text-bold-800 grey darken-2"
|
||||
href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
|
||||
target="_blank"
|
||||
>PIXINVENT
|
||||
</a></span
|
||||
><span
|
||||
*ngIf="!hideMadeWithLove"
|
||||
class="float-md-right d-block d-md-inline-block d-none d-lg-block"
|
||||
>Hand-crafted & Made with <i class="feather ft-heart pink"></i>
|
||||
<span id="scroll-top"></span
|
||||
></span>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<footer id="footer" class="footer fixed-bottom footer-dark navbar-border navbar-shadow" *ngIf="darkFooter">
|
||||
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2"><span
|
||||
class="float-md-left d-block d-md-inline-block">Copyright © 2022 <a [routerLink]=""
|
||||
class="text-bold-800 grey darken-2" href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
|
||||
target="_blank">PIXINVENT </a></span><span *ngIf="!hideMadeWithLove"
|
||||
class="float-md-right d-block d-md-inline-block d-none d-lg-block">Hand-crafted & Made with <i
|
||||
class="feather ft-heart pink"></i>
|
||||
<span id="scroll-top"></span></span></p>
|
||||
<footer
|
||||
id="footer"
|
||||
class="footer fixed-bottom footer-dark navbar-border navbar-shadow"
|
||||
*ngIf="darkFooter"
|
||||
>
|
||||
<p class="clearfix blue-grey lighten-2 text-sm-center mb-0 px-2">
|
||||
<span class="float-md-left d-block d-md-inline-block"
|
||||
>Copyright © 2022
|
||||
<a
|
||||
[routerLink]=""
|
||||
class="text-bold-800 grey darken-2"
|
||||
href="https://themeforest.net/user/pixinvent/portfolio?ref=pixinvent"
|
||||
target="_blank"
|
||||
>PIXINVENT
|
||||
</a></span
|
||||
><span
|
||||
*ngIf="!hideMadeWithLove"
|
||||
class="float-md-right d-block d-md-inline-block d-none d-lg-block"
|
||||
>Hand-crafted & Made with <i class="feather ft-heart pink"></i>
|
||||
<span id="scroll-top"></span
|
||||
></span>
|
||||
</p>
|
||||
</footer>
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
<nav
|
||||
class="top-header header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow navbar-static-top navbar-light navbar-brand-center"
|
||||
id="top-header" [ngClass]="selectedHeaderNavBarClass">
|
||||
<div class="navbar-wrapper">
|
||||
<div class="navbar-wrapper" style="background-color: #2c343b !important;">
|
||||
<div id="navbar-header" class="navbar-header">
|
||||
<ul class="nav navbar-nav flex-row">
|
||||
<li class="nav-item mobile-menu d-md-none mr-auto" ><a
|
||||
class="nav-link nav-menu-main menu-toggle hidden-xs11" (click)="toggleNavigation($event)"><i
|
||||
class="feather ft-menu font-large-1" ></i></a></li>
|
||||
<li class="nav-item"><a [routerLink]="['/dashboard/sales']" class="navbar-brand"><img class="brand-logo" alt="modern admin logo"
|
||||
<li class="nav-item"><a [routerLink]="['/monitoring']" class="navbar-brand"><img class="brand-logo" alt="modern admin logo"
|
||||
src="../../../../assets/images/logo/logo.png">
|
||||
<h3 class="brand-text">{{_themeSettingsConfig.brand.brand_name}}</h3>
|
||||
<!-- <h3 class="brand-text">{{_themeSettingsConfig.brand.brand_name}}</h3> -->
|
||||
<!-- <h3 class="brand-text">{{_themeSettingsConfig.brand.brand_name}}</h3> -->
|
||||
<h3 class="brand-text" style="color: aliceblue;">Hemat</h3>
|
||||
</a></li>
|
||||
|
||||
<li class="nav-item d-md-none"><a class="nav-link open-navbar-container" data-toggle="collapse"
|
||||
|
@ -20,7 +22,7 @@
|
|||
<div class="navbar-container content">
|
||||
<div class="collapse navbar-collapse show" id="navbar-mobile">
|
||||
<ul class="nav navbar-nav mr-auto float-left">
|
||||
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-menu-main menu-toggle hidden-xs"
|
||||
<!-- <li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-menu-main menu-toggle hidden-xs"
|
||||
(click)="toggleFixMenu($event)" ><i class="feather ft-menu"></i></a></li>
|
||||
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand"
|
||||
(click)="toggleFullScreen()" *ngIf ="maximize === 'on'"><i class="ficon feather ft-maximize"></i></a></li>
|
||||
|
@ -29,10 +31,10 @@
|
|||
<div class="search-input" [ngClass]="{'open': isHeaderSearchOpen}">
|
||||
<input class="input" type="text" placeholder="Explore Modern...">
|
||||
</div>
|
||||
</li>
|
||||
</li> -->
|
||||
</ul>
|
||||
<ul class="nav navbar-nav float-right" >
|
||||
<li class="dropdown-language nav-item" ngbDropdown *ngIf ="internationalization === 'on'">
|
||||
<!-- <li class="dropdown-language nav-item" ngbDropdown *ngIf ="internationalization === 'on'">
|
||||
<a [routerLink]="" class="dropdown-toggle nav-link" ngbDropdownToggle id="dropdown-flag">
|
||||
<i class="flag-icon flag-icon-gb"></i><span class="selected-language"></span>
|
||||
</a>
|
||||
|
@ -50,8 +52,8 @@
|
|||
<i class="flag-icon flag-icon-de"></i> German
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf ="notification === 'on'">
|
||||
</li> -->
|
||||
<!-- <li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf ="notification === 'on'">
|
||||
<a class="nav-link nav-link-label" ngbDropdownToggle>
|
||||
<i class="ficon feather ft-bell"></i>
|
||||
<span class="badge badge-pill badge-danger badge-up badge-glow">5</span>
|
||||
|
@ -124,8 +126,8 @@
|
|||
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
|
||||
href="javascript:void(0)">Read all notifications</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown-notification nav-item" ngbDropdown *ngIf ="email === 'on'">
|
||||
</li> -->
|
||||
<!-- <li class="dropdown-notification nav-item" ngbDropdown *ngIf ="email === 'on'">
|
||||
<a class="nav-link nav-link-label" ngbDropdownToggle><i class="ficon feather ft-mail"></i></a>
|
||||
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
|
||||
<li class="dropdown-menu-header">
|
||||
|
@ -185,7 +187,7 @@
|
|||
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
|
||||
href="javascript:void(0)">Read all messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</li> -->
|
||||
|
||||
<li class="dropdown-user nav-item" ngbDropdown>
|
||||
<a class="nav-link dropdown-user-link" ngbDropdownToggle>
|
||||
|
|
|
@ -33,3 +33,9 @@
|
|||
.header-navbar .navbar-header .navbar-brand .brand-text {
|
||||
padding-left: 11px !important;
|
||||
}
|
||||
|
||||
.brand-text-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,44 +1,96 @@
|
|||
<nav class="header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow fixed-top navbar-shadow"
|
||||
[ngClass]="selectedHeaderNavBarClass">
|
||||
<nav
|
||||
class="header-navbar navbar-expand-md navbar navbar-with-menu navbar-without-dd-arrow fixed-top navbar-shadow"
|
||||
[ngClass]="selectedHeaderNavBarClass"
|
||||
>
|
||||
<div class="navbar-wrapper">
|
||||
<div id="navbar-header" class="navbar-header" [ngClass]="selectedNavBarHeaderClass"
|
||||
(mouseenter)="mouseEnter($event)" (mouseleave)="mouseLeave($event)">
|
||||
<div
|
||||
id="navbar-header"
|
||||
class="navbar-header"
|
||||
[ngClass]="selectedNavBarHeaderClass"
|
||||
(mouseenter)="mouseEnter($event)"
|
||||
(mouseleave)="mouseLeave($event)"
|
||||
style="background-color: #fbfbfb !important"
|
||||
>
|
||||
<ul class="nav navbar-nav flex-row">
|
||||
<!-- Remove position relative in responsive -->
|
||||
<li class="nav-item mobile-menu d-lg-none mr-auto"><a class="nav-link nav-menu-main menu-toggle hidden-xs11"
|
||||
(click)="toggleNavigation($event)">
|
||||
<i class="feather ft-menu font-large-1"></i></a></li>
|
||||
<li class="nav-item mr-auto"><a [routerLink]="['/dashboard/sales']" class="navbar-brand"
|
||||
routerLink="/dashboard/sales"><img class="brand-logo" alt="modern admin logo"
|
||||
[src]="_themeSettingsConfig.brand.logo.value">
|
||||
<h3 class="brand-text">{{_themeSettingsConfig.brand.brand_name}}</h3>
|
||||
</a></li>
|
||||
<li class="nav-item d-none d-md-block nav-toggle">
|
||||
<a [routerLink]="" class="nav-link modern-nav-toggle pr-0" data-toggle="collapse"
|
||||
(click)="toggleFixMenu($event)">
|
||||
<i class="feather toggle-icon font-medium-3 white"
|
||||
[ngClass]="{'ft-toggle-left': _themeSettingsConfig.menu === 'collapse','ft-toggle-right': _themeSettingsConfig.menu === 'expand'}"></i>
|
||||
<li class="nav-item mobile-menu d-lg-none mr-auto">
|
||||
<a
|
||||
class="nav-link nav-menu-main menu-toggle hidden-xs11"
|
||||
(click)="toggleNavigation($event)"
|
||||
>
|
||||
<i class="feather ft-menu font-large-1"></i
|
||||
></a>
|
||||
</li>
|
||||
<li class="nav-item mr-auto">
|
||||
<a
|
||||
[routerLink]="['/monitoring']"
|
||||
class="navbar-brand"
|
||||
routerLink="/monitoring"
|
||||
>
|
||||
<img
|
||||
class="brand-logo"
|
||||
alt="modern admin logo"
|
||||
src="../../../../assets/images/logo/smart2.png"
|
||||
/>
|
||||
<!-- <h3 class="brand-text" style="color: #ffffff;">{{_themeSettingsConfig.brand.brand_name}}</h3> -->
|
||||
<div
|
||||
class="brand-text-wrapper"
|
||||
style="
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
>
|
||||
<h3 class="brand-text" style="color: #242222; margin: 0">
|
||||
Smart Building
|
||||
</h3>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item d-lg-none"><a class="nav-link open-navbar-container" data-toggle="collapse"
|
||||
data-target="#navbar-mobile" (click)="toggleNavbar($event)"><i class="la la-ellipsis-v"></i></a></li>
|
||||
<li class="nav-item d-none d-md-block nav-toggle">
|
||||
<a
|
||||
[routerLink]=""
|
||||
class="nav-link modern-nav-toggle pr-0"
|
||||
data-toggle="collapse"
|
||||
|
||||
(click)="toggleFixMenu($event)"
|
||||
>
|
||||
<i
|
||||
class="feather toggle-icon font-medium-3 white"
|
||||
[ngClass]="{
|
||||
'ft-toggle-left': _themeSettingsConfig.menu === 'collapse',
|
||||
'ft-toggle-right': _themeSettingsConfig.menu === 'expand'
|
||||
}"
|
||||
></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item d-lg-none">
|
||||
<a
|
||||
class="nav-link open-navbar-container"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbar-mobile"
|
||||
(click)="toggleNavbar($event)"
|
||||
><i class="la la-ellipsis-v"></i
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- New-->
|
||||
<div class="navbar-container content" [hidden]="isMobile && !showNavbar">
|
||||
<div class="collapse navbar-collapse" id="navbar-mobile">
|
||||
<ul class="nav navbar-nav mr-auto float-left">
|
||||
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand"
|
||||
<!-- <li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand"
|
||||
(click)="toggleFullScreen()" *ngIf="maximize === 'on'"><i class="ficon feather ft-maximize"></i></a></li>
|
||||
<li class="nav-item nav-search"><a [routerLink]="" class="nav-link nav-link-search" (click)="clickSearch()"
|
||||
*ngIf="search === 'on'"><i class="ficon feather ft-search"></i></a>
|
||||
<div class="search-input" [ngClass]="{'open': isHeaderSearchOpen}">
|
||||
<input class="input" type="text" placeholder="Explore Modern...">
|
||||
</div>
|
||||
</li>
|
||||
</li> -->
|
||||
</ul>
|
||||
<ul class="nav navbar-nav float-right">
|
||||
<li class="dropdown-language nav-item" ngbDropdown *ngIf="internationalization === 'on'">
|
||||
<!-- <li class="dropdown-language nav-item" ngbDropdown *ngIf="internationalization === 'on'">
|
||||
<a [routerLink]="" class="dropdown-toggle nav-link" ngbDropdownToggle id="dropdown-flag">
|
||||
<i class="flag-icon flag-icon-gb"></i><span class="selected-language"></span>
|
||||
</a>
|
||||
|
@ -56,84 +108,152 @@
|
|||
<i class="flag-icon flag-icon-de"></i> German
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf="notification === 'on'">
|
||||
<a class="nav-link nav-link-label" ngbDropdownToggle>
|
||||
<i class="ficon feather ft-bell"></i>
|
||||
</li> -->
|
||||
<li
|
||||
class="dropdown-notification nav-item dropdown"
|
||||
ngbDropdown
|
||||
*ngIf="notification === 'on'"
|
||||
>
|
||||
<!-- <a class="nav-link nav-link-label" ngbDropdownToggle>
|
||||
<i class="ficon feather ft-bell" style="color: #bef264"></i>
|
||||
<span class="badge badge-pill badge-danger badge-up badge-glow">5</span>
|
||||
</a> -->
|
||||
<a class="nav-link nav-link-label">
|
||||
<i class="ficon la la-bell" style="color: #242424"></i>
|
||||
<!-- <span class="badge badge-pill badge-danger badge-up badge-glow">5</span> -->
|
||||
</a>
|
||||
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
|
||||
<li class="dropdown-menu-header">
|
||||
<h6 class="dropdown-header m-0"><span class="grey darken-2">Notifications</span></h6><span
|
||||
class="notification-tag badge badge-default badge-danger float-right m-0">5 New</span>
|
||||
<h6 class="dropdown-header m-0">
|
||||
<span class="grey darken-2">Notifications</span>
|
||||
</h6>
|
||||
<span
|
||||
class="notification-tag badge badge-default badge-danger float-right m-0"
|
||||
>5 New</span
|
||||
>
|
||||
</li>
|
||||
<li class="scrollable-container media-list w-100 ps-container ps-theme-dark ps-active-y" fxFlex="auto" [perfectScrollbar]="config">
|
||||
<li
|
||||
class="scrollable-container media-list w-100 ps-container ps-theme-dark ps-active-y"
|
||||
fxFlex="auto"
|
||||
[perfectScrollbar]="config"
|
||||
>
|
||||
<a href="javascript:void(0)">
|
||||
<div class="media">
|
||||
<div class="media-left align-self-center"><i
|
||||
class="feather ft-plus-square icon-bg-circle bg-cyan"></i>
|
||||
<div class="media-left align-self-center">
|
||||
<i
|
||||
class="feather ft-plus-square icon-bg-circle bg-cyan"
|
||||
></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h6 class="media-heading">You have new order!</h6>
|
||||
<p class="notification-text font-small-3 text-muted">Lorem ipsum dolor sit amet, consectetuer
|
||||
elit.</p><small>
|
||||
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">30 minutes
|
||||
ago</time></small>
|
||||
<p class="notification-text font-small-3 text-muted">
|
||||
Lorem ipsum dolor sit amet, consectetuer elit.
|
||||
</p>
|
||||
<small>
|
||||
<time
|
||||
class="media-meta text-muted"
|
||||
datetime="2015-06-11T18:29:20+08:00"
|
||||
>30 minutes ago</time
|
||||
></small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0)">
|
||||
<div class="media">
|
||||
<div class="media-left align-self-center"><i
|
||||
class="feather ft-download-cloud icon-bg-circle bg-red bg-darken-1"></i></div>
|
||||
<div class="media-left align-self-center">
|
||||
<i
|
||||
class="feather ft-download-cloud icon-bg-circle bg-red bg-darken-1"
|
||||
></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h6 class="media-heading red darken-1">99% Server load</h6>
|
||||
<p class="notification-text font-small-3 text-muted">Aliquam tincidunt mauris eu risus.</p><small>
|
||||
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Five hour
|
||||
ago</time></small>
|
||||
<h6 class="media-heading red darken-1">
|
||||
99% Server load
|
||||
</h6>
|
||||
<p class="notification-text font-small-3 text-muted">
|
||||
Aliquam tincidunt mauris eu risus.
|
||||
</p>
|
||||
<small>
|
||||
<time
|
||||
class="media-meta text-muted"
|
||||
datetime="2015-06-11T18:29:20+08:00"
|
||||
>Five hour ago</time
|
||||
></small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0)">
|
||||
<div class="media">
|
||||
<div class="media-left align-self-center"><i
|
||||
class="feather ft-alert-triangle icon-bg-circle bg-yellow bg-darken-3"></i></div>
|
||||
<div class="media-left align-self-center">
|
||||
<i
|
||||
class="feather ft-alert-triangle icon-bg-circle bg-yellow bg-darken-3"
|
||||
></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h6 class="media-heading yellow darken-3">Warning notifixation</h6>
|
||||
<p class="notification-text font-small-3 text-muted">Vestibulum auctor dapibus neque.</p><small>
|
||||
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Today</time></small>
|
||||
<h6 class="media-heading yellow darken-3">
|
||||
Warning notifixation
|
||||
</h6>
|
||||
<p class="notification-text font-small-3 text-muted">
|
||||
Vestibulum auctor dapibus neque.
|
||||
</p>
|
||||
<small>
|
||||
<time
|
||||
class="media-meta text-muted"
|
||||
datetime="2015-06-11T18:29:20+08:00"
|
||||
>Today</time
|
||||
></small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0)">
|
||||
<div class="media">
|
||||
<div class="media-left align-self-center"><i
|
||||
class="feather ft-check-circle icon-bg-circle bg-cyan"></i>
|
||||
<div class="media-left align-self-center">
|
||||
<i
|
||||
class="feather ft-check-circle icon-bg-circle bg-cyan"
|
||||
></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h6 class="media-heading">Complete the task</h6><small>
|
||||
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Last
|
||||
week</time></small>
|
||||
<h6 class="media-heading">Complete the task</h6>
|
||||
<small>
|
||||
<time
|
||||
class="media-meta text-muted"
|
||||
datetime="2015-06-11T18:29:20+08:00"
|
||||
>Last week</time
|
||||
></small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0)">
|
||||
<div class="media">
|
||||
<div class="media-left align-self-center"><i class="feather ft-file icon-bg-circle bg-teal"></i>
|
||||
<div class="media-left align-self-center">
|
||||
<i class="feather ft-file icon-bg-circle bg-teal"></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h6 class="media-heading">Generate monthly report</h6><small>
|
||||
<time class="media-meta text-muted" datetime="2015-06-11T18:29:20+08:00">Last
|
||||
month</time></small>
|
||||
<h6 class="media-heading">Generate monthly report</h6>
|
||||
<small>
|
||||
<time
|
||||
class="media-meta text-muted"
|
||||
datetime="2015-06-11T18:29:20+08:00"
|
||||
>Last month</time
|
||||
></small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
|
||||
href="javascript:void(0)">Read all notifications</a></li>
|
||||
<li class="dropdown-menu-footer">
|
||||
<a
|
||||
class="dropdown-item text-muted text-center"
|
||||
href="javascript:void(0)"
|
||||
>Read all notifications</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown-notification nav-item" ngbDropdown>
|
||||
<!-- <li class="dropdown-notification nav-item" ngbDropdown>
|
||||
<a class="nav-link nav-link-label" ngbDropdownToggle *ngIf="email === 'on'"><i
|
||||
class="ficon feather ft-mail"></i></a>
|
||||
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
|
||||
|
@ -194,28 +314,47 @@
|
|||
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
|
||||
href="javascript:void(0)">Read all messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</li> -->
|
||||
|
||||
<li class="dropdown-user nav-item" ngbDropdown>
|
||||
<a class="nav-link dropdown-user-link" ngbDropdownToggle>
|
||||
<span *ngIf="currentUser.displayName"
|
||||
class="mr-1 user-name text-bold-700">{{currentUser.displayName}}</span>
|
||||
<span *ngIf="!currentUser.displayName" class="mr-1 user-name text-bold-700">John Doe</span>
|
||||
<span
|
||||
*ngIf="currentUser.displayName"
|
||||
class="mr-1 user-name text-bold-700"
|
||||
style="color: #242222"
|
||||
>{{ currentUser.displayName }}</span
|
||||
>
|
||||
<span
|
||||
*ngIf="!currentUser.displayName"
|
||||
class="mr-1 user-name text-bold-700"
|
||||
>John Doe</span
|
||||
>
|
||||
<span class="avatar avatar-online">
|
||||
<img *ngIf="currentUser.photoURL" src="{{currentUser.photoURL}}" alt="avatar">
|
||||
<img *ngIf="!currentUser.photoURL" src="../../../assets/images/portrait/small/avatar-s-19.png"
|
||||
alt="avatar">
|
||||
<img src="{{ urlImage }}" alt="avatar" />
|
||||
<i></i>
|
||||
</span>
|
||||
</a>
|
||||
<div ngbDropdownMenu class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownProfileMenu">
|
||||
<a class="dropdown-item" [routerLink]="['/user/user-profile']"><i class="feather ft-user"></i> Edit
|
||||
Profile </a>
|
||||
<a class="dropdown-item" [routerLink]="['/email']"><i class="feather ft-mail"></i> My Inbox </a>
|
||||
<a class="dropdown-item" [routerLink]="['/todos']"><i class="feather ft-check-square"></i> Task </a>
|
||||
<a class="dropdown-item" [routerLink]="['/chats']"><i class="feather ft-message-square"></i> Chats </a>
|
||||
<div
|
||||
ngbDropdownMenu
|
||||
class="dropdown-menu dropdown-menu-right"
|
||||
aria-labelledby="dropdownProfileMenu"
|
||||
>
|
||||
<a class="dropdown-item" [routerLink]="'/user-profil'"
|
||||
><i class="feather ft-user"></i> Edit Profile
|
||||
</a>
|
||||
<!-- <a class="dropdown-item"
|
||||
><i class="feather ft-mail"></i> My Inbox
|
||||
</a>
|
||||
<a class="dropdown-item"
|
||||
><i class="feather ft-check-square"></i> Task
|
||||
</a>
|
||||
<a class="dropdown-item"
|
||||
><i class="feather ft-message-square"></i> Chats
|
||||
</a> -->
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" [routerLink]="" (click)="logout()"><i class="feather ft-power"></i> Logout</a>
|
||||
<a class="dropdown-item" [routerLink]="" (click)="logout()"
|
||||
><i class="feather ft-power"></i> Logout</a
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -9,6 +9,7 @@ import { AuthService } from 'src/app/_services/auth.service';
|
|||
import { Router } from '@angular/router';
|
||||
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
|
||||
import { AppConstants } from 'src/app/_helpers/app.constants';
|
||||
import { LoginService } from 'src/app/content/hemat-app/service/login.service';
|
||||
|
||||
const docElmWithBrowsersFullScreenFunctions = document.documentElement as HTMLElement & {
|
||||
mozRequestFullScreen(): Promise<void>;
|
||||
|
@ -30,6 +31,8 @@ export class VerticalComponent implements OnInit, AfterViewInit {
|
|||
|
||||
insideTm: any;
|
||||
outsideTm: any;
|
||||
urlImage: string = 'https://www.w3schools.com/howto/img_avatar.png';
|
||||
dataAccount: any;
|
||||
private _unsubscribeAll: Subject<any>;
|
||||
private _unsubscribeAllMenu: Subject<any>;
|
||||
public _themeSettingsConfig: any;
|
||||
|
@ -57,7 +60,8 @@ export class VerticalComponent implements OnInit, AfterViewInit {
|
|||
private _menuSettingsService: MenuSettingsService,
|
||||
public authService: AuthService,
|
||||
private router: Router,
|
||||
private elementRef: ElementRef
|
||||
private elementRef: ElementRef,
|
||||
private authServiceLogin: LoginService,
|
||||
) {
|
||||
this._unsubscribeAll = new Subject();
|
||||
this._unsubscribeAllMenu = new Subject();
|
||||
|
@ -82,6 +86,13 @@ export class VerticalComponent implements OnInit, AfterViewInit {
|
|||
if (localStorage.getItem('currentUser')) {
|
||||
this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
}
|
||||
|
||||
if (localStorage.getItem('account_info')) {
|
||||
this.dataAccount = JSON.parse(localStorage.getItem('account_info'));
|
||||
this.dataProfil(this.dataAccount.sub);
|
||||
}
|
||||
|
||||
|
||||
// Subscribe to config changes
|
||||
this._themeSettingsService.config
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
|
@ -101,6 +112,14 @@ export class VerticalComponent implements OnInit, AfterViewInit {
|
|||
this.email = this._themeSettingsConfig.headerIcons.email;
|
||||
}
|
||||
|
||||
dataProfil(userId){
|
||||
this.authServiceLogin.getDataProfil(userId).subscribe(data => {
|
||||
if (data.data.image_path !== "https://kapi.absys.ninja/hemat/image/null") {
|
||||
this.urlImage = data.data.image_path
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.refreshView();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
.menu-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-item.active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 5px;
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.active-link::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background-color: green;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
<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">
|
||||
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"
|
||||
[perfectScrollbar]="config">
|
||||
<ul class="navigation navigation-main" id="main-menu-navigation" data-menu="menu-navigation">
|
||||
[perfectScrollbar]="config" >
|
||||
<ul class="navigation navigation-main" id="main-menu-navigation" data-menu="menu-navigation" style="background-color: #fbfbfb !important;">
|
||||
<!-- Menu -->
|
||||
{{child?child.title:''}}
|
||||
<li *ngFor="let child of _menuSettingsConfig.vertical_menu.items" class="" [ngClass]="{
|
||||
|
@ -13,22 +13,24 @@
|
|||
'active': child.isSelected && !child.submenu,
|
||||
'menu-collapsed-open': child.isSelected && child.submenu,
|
||||
'hover': child.hover
|
||||
}">
|
||||
}" >
|
||||
<!-- Section -->
|
||||
<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"
|
||||
data-original-title="Support"></i>
|
||||
data-original-title="Support" style="color: #242222;"></i>
|
||||
|
||||
<!-- Root Menu -->
|
||||
<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)">
|
||||
<i class="la" [ngClass]="child.icon"></i>
|
||||
<span class="menu-title" data-i18n="">{{child.title}}</span>
|
||||
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)"
|
||||
style="background-color: #fbfbfb !important;">
|
||||
<i class="la" [ngClass]="child.icon" style="color: #242222;"></i>
|
||||
<span class="menu-title" data-i18n="" style="color: #242222;">{{child.title}}</span>
|
||||
<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}}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a *ngIf="child.title && !child.submenu && !child.excludeInVertical && child.isExternalLink"
|
||||
[href]="child.page" target="_blank" (click)="toggleMenu($event, child)">
|
||||
<i class="la" [ngClass]="child.icon"></i>
|
||||
|
@ -51,20 +53,23 @@
|
|||
|
||||
<!-- Submenu -->
|
||||
<a *ngIf="child.title && child.submenu && !child.excludeInVertical"
|
||||
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)">
|
||||
<i class="la" [ngClass]="child.icon"></i>
|
||||
<span class="menu-title" data-i18n="">{{child.title}}</span>
|
||||
routerLink="{{child.page !== 'null'?child.page:router.url}}" (click)="toggleMenu($event, child)" style="background-color: #fbfbfb !important;">
|
||||
<i class="la" [ngClass]="child.icon" style="color: #242222;"></i>
|
||||
<span class="menu-title" data-i18n="" style="color: #242222;">{{child.title}}</span>
|
||||
<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}}
|
||||
</span>
|
||||
</a>
|
||||
<ul *ngIf="child.submenu" class="menu-content" [@popOverState]="child.isOpen">
|
||||
<ul *ngIf="child.submenu" class="menu-content" [@popOverState]="child.isOpen" style="background-color: #fbfbfb !important;">
|
||||
<!-- Submenu of Submenu -->
|
||||
<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}">
|
||||
<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>
|
||||
<a class="menu-item" *ngIf="!subchild.submenu && !subchild.excludeInVertical"
|
||||
(click)="toggleMenu($event, subchild, true)"
|
||||
routerLink="{{subchild.page !== 'null'?subchild.page:router.url}}"
|
||||
[ngClass]="{'active': subchild.isSelected}"
|
||||
style="background-color: #fbfbfb !important; color: #242222;">{{subchild.title}}</a>
|
||||
<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>
|
||||
<ul *ngIf="subchild.submenu && !subchild.excludeInVertical" class="menu-content">
|
||||
|
|
|
@ -384,6 +384,7 @@ export class VerticalnavComponent implements OnInit {
|
|||
} else if ( child.page === '/chats' && this.loggedInUser.email !== 'john@pixinvent.com') {
|
||||
this.router.navigate(['/chats']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
<div (window:resize)="onResize($event)"></div>
|
||||
<app-navigation></app-navigation>
|
||||
<router-outlet></router-outlet>
|
||||
<div class="sidenav-overlay d-none" id="sidenav-overlay" (click)="rightbar($event)"></div>
|
||||
<div
|
||||
class="sidenav-overlay d-none"
|
||||
id="sidenav-overlay"
|
||||
(click)="rightbar($event)"
|
||||
></div>
|
||||
<app-footer></app-footer>
|
||||
<div *ngIf ="customizer === 'on'">
|
||||
<app-customizer *ngIf="layout === 'vertical'"></app-customizer>
|
||||
<app-horizontal-customizer *ngIf="layout === 'horizontal'"></app-horizontal-customizer>
|
||||
</div>
|
||||
<div *ngIf ="buybutton === 'on'">
|
||||
<div class="buy-now" >
|
||||
<!-- <div *ngIf="customizer === 'on'">
|
||||
<app-customizer *ngIf="layout === 'vertical'"></app-customizer>
|
||||
<app-horizontal-customizer
|
||||
*ngIf="layout === 'horizontal'"
|
||||
></app-horizontal-customizer>
|
||||
</div> -->
|
||||
<!-- <div *ngIf="buybutton === 'on'">
|
||||
<div class="buy-now" >
|
||||
<a href="https://1.envato.market/modern_admin_angular" target="_blank" class="btn bg-gradient-directional-purple round white btn-purple btn-glow px-2">Buy Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,5 +29,5 @@ export const ThemeSettingsConfig = {
|
|||
// value:'http://evolvision.com/wp-content/uploads/2018/01/envelope4-green.png'
|
||||
},
|
||||
},
|
||||
defaultTitleSuffix: 'Modern Admin - Angular 11+ Bootstrap 5 Admin Dashboard Template'
|
||||
defaultTitleSuffix: ''
|
||||
};
|
||||
|
|
|
@ -107,11 +107,17 @@ export class AuthService {
|
|||
doLogout() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (firebase.auth().currentUser) {
|
||||
console.log('masuk atas');
|
||||
localStorage.removeItem('currentUser');
|
||||
localStorage.removeItem('account_info');
|
||||
localStorage.removeItem('access_token');
|
||||
localStorage.removeItem('remember');
|
||||
this.afAuth.signOut();
|
||||
resolve();
|
||||
} else {
|
||||
console.log('masuk bawah');
|
||||
localStorage.removeItem('account_info');
|
||||
localStorage.removeItem('access_token');
|
||||
localStorage.removeItem('currentUser');
|
||||
resolve();
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ export class TableApiService {
|
|||
}
|
||||
|
||||
private extractData(res: Response) {
|
||||
console.log(res);
|
||||
|
||||
const body = res;
|
||||
return body || {};
|
||||
}
|
||||
|
|
|
@ -1,37 +1,280 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import * as FileSaver from 'file-saver';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { Injectable } from "@angular/core";
|
||||
import * as FileSaver from "file-saver";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
const EXCEL_TYPE =
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
|
||||
const EXCEL_EXTENSION = '.xlsx';
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8";
|
||||
const EXCEL_EXTENSION = ".xlsx";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: "root",
|
||||
})
|
||||
export class TableexcelService {
|
||||
constructor() { }
|
||||
constructor() {}
|
||||
public exportAsExcelFile(json: any[], excelFileName: string): void {
|
||||
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(json);
|
||||
console.log('worksheet', worksheet);
|
||||
console.log("worksheet", worksheet);
|
||||
const workbook: XLSX.WorkBook = {
|
||||
Sheets: { data: worksheet },
|
||||
SheetNames: ['data']
|
||||
SheetNames: ["data"],
|
||||
};
|
||||
const excelBuffer: any = XLSX.write(workbook, {
|
||||
bookType: 'xlsx',
|
||||
type: 'array'
|
||||
bookType: "xlsx",
|
||||
type: "array",
|
||||
});
|
||||
this.saveAsExcelFile(excelBuffer, excelFileName);
|
||||
}
|
||||
|
||||
private saveAsExcelFile(buffer: any, fileName: string): void {
|
||||
const data: Blob = new Blob([buffer], {
|
||||
type: EXCEL_TYPE
|
||||
type: EXCEL_TYPE,
|
||||
});
|
||||
FileSaver.saveAs(
|
||||
data,
|
||||
fileName + '_export_' + new Date().getTime() + EXCEL_EXTENSION
|
||||
fileName + "_export_" + new Date().getTime() + EXCEL_EXTENSION
|
||||
);
|
||||
}
|
||||
|
||||
public exportAsExcelFileDevice(
|
||||
json: any[],
|
||||
excelFileName: string,
|
||||
columns: string[]
|
||||
): 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);
|
||||
const columnWidths = [
|
||||
{ wch: 40 },
|
||||
{ wch: 30 },
|
||||
{ wch: 30 },
|
||||
{ wch: 10 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
];
|
||||
worksheet["!cols"] = columnWidths;
|
||||
|
||||
const header = [
|
||||
"Device",
|
||||
"Building",
|
||||
"Room",
|
||||
"Watt",
|
||||
"Category",
|
||||
"Status",
|
||||
"Type",
|
||||
"Voltage",
|
||||
];
|
||||
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);
|
||||
}
|
||||
|
||||
public exportAsExcelFileCostManage(
|
||||
json: any[],
|
||||
excelFileName: string,
|
||||
columns: string[]
|
||||
): void {
|
||||
// Filter the json data based on the columns
|
||||
const filteredJson = json.map((item) => {
|
||||
const filteredItem = {};
|
||||
columns.forEach((column) => {
|
||||
filteredItem[column] = item[column];
|
||||
});
|
||||
return filteredItem;
|
||||
});
|
||||
|
||||
// Calculate totals for estimation_cost and total_use
|
||||
const totalEstimationCost = filteredJson.reduce(
|
||||
(sum, item) => sum + (item["estimation_cost"] || 0),
|
||||
0
|
||||
);
|
||||
const totalUse = filteredJson.reduce(
|
||||
(sum, item) => sum + (item["total_use"] || 0),
|
||||
0
|
||||
);
|
||||
|
||||
// Create the worksheet
|
||||
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(filteredJson);
|
||||
const columnWidths = [
|
||||
{ wch: 40 },
|
||||
{ wch: 30 },
|
||||
{ wch: 20 },
|
||||
{ wch: 30 },
|
||||
{ wch: 30 },
|
||||
{ wch: 30 },
|
||||
];
|
||||
worksheet["!cols"] = columnWidths;
|
||||
|
||||
// Add header
|
||||
const header = [
|
||||
"Building",
|
||||
"Room",
|
||||
"Category",
|
||||
"Total Use",
|
||||
"Estimation Cost",
|
||||
"Date",
|
||||
];
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [header]);
|
||||
|
||||
// Add totals row
|
||||
const totalsRow = [
|
||||
"Totals",
|
||||
"",
|
||||
"",
|
||||
`Total: ${totalUse} Kwh`,
|
||||
`Total: ${totalEstimationCost}`,
|
||||
"",
|
||||
];
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [totalsRow], { origin: -1 });
|
||||
|
||||
// Create the workbook
|
||||
const workbook: XLSX.WorkBook = {
|
||||
Sheets: { data: worksheet },
|
||||
SheetNames: ["data"],
|
||||
};
|
||||
|
||||
// Write the workbook and save it
|
||||
const excelBuffer: any = XLSX.write(workbook, {
|
||||
bookType: "xlsx",
|
||||
type: "array",
|
||||
});
|
||||
this.saveAsExcelFile(excelBuffer, excelFileName);
|
||||
}
|
||||
|
||||
public exportAsExcelFileManageDetail(
|
||||
json: any[],
|
||||
excelFileName: string,
|
||||
columns: string[]
|
||||
): 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);
|
||||
const columnWidths = [
|
||||
{ wch: 30 },
|
||||
{ wch: 40 },
|
||||
{ wch: 30 },
|
||||
{ wch: 30 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
{ wch: 20 },
|
||||
];
|
||||
worksheet["!cols"] = columnWidths;
|
||||
|
||||
const header = [
|
||||
"Periode",
|
||||
"Device",
|
||||
"Room",
|
||||
"Category",
|
||||
"Estimation Cost",
|
||||
"Total Kwh",
|
||||
"Watt",
|
||||
"Duration",
|
||||
"Price Kwh",
|
||||
];
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ export class AppComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
if (this.title && this.router.url !== '/') {
|
||||
this.titleService.setTitle(this.title + ' - ' + this._themeSettingsConfig.defaultTitleSuffix);
|
||||
this.titleService.setTitle(this.title);
|
||||
// this.titleService.setTitle(this.title + ' - ' + this._themeSettingsConfig.defaultTitleSuffix);
|
||||
} else {
|
||||
if ((this.router.url === '/' || this.router.url === '/login' || this.router.url === '/register') &&
|
||||
!localStorage.getItem('remember')) {
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
HammerGestureConfig
|
||||
} from '@angular/platform-browser';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
||||
import {
|
||||
NgbModule,
|
||||
NgbCarouselConfig,
|
||||
|
@ -67,7 +67,8 @@ import { FullLayoutComponent } from './_layout/full-layout/full-layout.component
|
|||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { UserService } from './_api/user/user.service';
|
||||
import { PrivacyPolicyComponent } from './login/privacy-policy/privacy-policy.component';
|
||||
import { TermsConditionComponent } from './login/terms-condition/terms-condition.component';;
|
||||
import { TermsConditionComponent } from './login/terms-condition/terms-condition.component';
|
||||
import { HttpErrorInterceptorService } from './interceptors/http-error-interceptor.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -93,7 +94,7 @@ import { TermsConditionComponent } from './login/terms-condition/terms-condition
|
|||
LoadingBarRouterModule,
|
||||
BlockUIModule.forRoot({
|
||||
template: BlockTemplateComponent
|
||||
})
|
||||
}),
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
|
@ -117,7 +118,7 @@ import { TermsConditionComponent } from './login/terms-condition/terms-condition
|
|||
BlockTemplateComponent,
|
||||
FullLayoutComponent,
|
||||
PrivacyPolicyComponent,
|
||||
TermsConditionComponent,
|
||||
TermsConditionComponent
|
||||
],
|
||||
providers: [
|
||||
AuthGuard,
|
||||
|
@ -136,6 +137,7 @@ import { TermsConditionComponent } from './login/terms-condition/terms-condition
|
|||
},
|
||||
NgbCarouselConfig,
|
||||
NgbModalConfig,
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptorService, multi: true }
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
exports: [RouterModule]
|
||||
|
|
|
@ -48,6 +48,38 @@ const appRoutes: Routes = [
|
|||
children: [
|
||||
{ path: 'logout', component: LoginComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'changelog', component: ChangelogComponent, canActivate: [AuthGuard] },
|
||||
{
|
||||
path: 'monitoring', loadChildren: () => import('../app/content/hemat-app/monitoring/monitoring.module').then(m => m.MonitoringModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'calculator', loadChildren: () => import('../app/content/hemat-app/calculator/calculator.module').then(m => m.CalculatorModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'list-monitoring', loadChildren: () => import('../app/content/hemat-app/list-monitoring/list-monitoring.module').then(m => m.ListMonitoringModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'device', loadChildren: () => import('../app/content/hemat-app/device/device.module').then(m => m.DeviceModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'cost-management', loadChildren: () => import('../app/content/hemat-app/cost-management/cost-management.module').then(m => m.CostManagementModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'user-access', loadChildren: () => import('../app/content/hemat-app/user-access/user-access.module').then(m => m.UserAccessModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'master', loadChildren: () => import('../app/content/hemat-app/master/master.module').then(m => m.MasterModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'user-profil', loadChildren: () => import('../app/content/hemat-app/user-profile/user-profile.module').then(m => m.UserProfileModule)
|
||||
, canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'dashboard', loadChildren: () => import('../app/content/dashboard/dashboard.module').then(m => m.DashboardModule)
|
||||
, canActivate: [AuthGuard]
|
||||
|
|
|
@ -1,196 +1,241 @@
|
|||
<div class="app-content content">
|
||||
<div class="content-overlay"></div>
|
||||
<div class="content-wrapper">
|
||||
<div class="content-header row">
|
||||
</div>
|
||||
<div class="content-body"><!-- Hospital Info cards -->
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-user-md font-large-2 success"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Doctors Available</h5>
|
||||
<h3 class="text-bold-600">122</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-stethoscope font-large-2 warning"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Visiting Doctors</h5>
|
||||
<h3 class="text-bold-600">34</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-calendar-check-o font-large-2 info"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Today's Inquiry</h5>
|
||||
<h3 class="text-bold-600">3.5K</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-bed font-large-2 danger"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Rooms Available</h5>
|
||||
<h3 class="text-bold-600">179</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Hospital Info cards Ends -->
|
||||
|
||||
<!-- Appointment Bar Line Chart -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<section id="chartjs-bar-charts">
|
||||
<div class="content-overlay"></div>
|
||||
<div class="content-wrapper">
|
||||
<div class="content-header row"></div>
|
||||
<div class="content-body">
|
||||
<!-- Hospital Info cards -->
|
||||
<div class="row">
|
||||
<div class="col-12" *blockUI="'barCharts'; message: 'Loading'">
|
||||
<m-card [options]="options" (reloadFunction)="reloadBarCharts($event)">
|
||||
<ng-container mCardHeaderTitle>
|
||||
Appointment
|
||||
</ng-container>
|
||||
<ng-container mCardBody>
|
||||
<div class="z">
|
||||
<canvas class="barchart" height="328" baseChart [datasets]="barChartData" [labels]="barChartLabels"
|
||||
[options]="barChartOptions" [legend]="barChartLegend"
|
||||
[chartType]="barChartType"></canvas>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-user-md font-large-2 success"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Doctors Available</h5>
|
||||
<h3 class="text-bold-600">122</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</m-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-stethoscope font-large-2 warning"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Visiting Doctors</h5>
|
||||
<h3 class="text-bold-600">34</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-calendar-check-o font-large-2 info"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Today's Inquiry</h5>
|
||||
<h3 class="text-bold-600">3.5K</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-6 col-md-6 col-12">
|
||||
<div class="card pull-up">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<i class="la la-bed font-large-2 danger"></i>
|
||||
</div>
|
||||
<div class="media-body text-right">
|
||||
<h5 class="text-muted text-bold-500">Rooms Available</h5>
|
||||
<h3 class="text-bold-600">179</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Appointment Bar Line Chart Ends -->
|
||||
<!-- Hospital Info cards Ends -->
|
||||
|
||||
<!-- Appointment Table -->
|
||||
<div class="row" matchHeight="card">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Doctors Available</h4>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="table-responsive">
|
||||
<table id="recent-orders" class="table table-hover table-xl mb-0">
|
||||
<tbody>
|
||||
<tr *ngFor = "let doctor of doctors ">
|
||||
<td class="text-truncate p-1 border-top-0">
|
||||
<div class="avatar avatar-md">
|
||||
<img class="media-object rounded-circle" [src]= doctor.image
|
||||
alt="Avatar">
|
||||
<!-- Appointment Bar Line Chart -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<section id="chartjs-bar-charts">
|
||||
<div class="row">
|
||||
<div class="col-12" *blockUI="'barCharts'; message: 'Loading'">
|
||||
<m-card
|
||||
[options]="options"
|
||||
(reloadFunction)="reloadBarCharts($event)"
|
||||
>
|
||||
<ng-container mCardHeaderTitle> Appointment </ng-container>
|
||||
<ng-container mCardBody>
|
||||
<div class="z">
|
||||
<canvas
|
||||
class="barchart"
|
||||
height="328"
|
||||
baseChart
|
||||
[datasets]="barChartData"
|
||||
[labels]="barChartLabels"
|
||||
[options]="barChartOptions"
|
||||
[legend]="barChartLegend"
|
||||
[chartType]="barChartType"
|
||||
></canvas>
|
||||
</div>
|
||||
</ng-container>
|
||||
</m-card>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-truncate pl-0 border-top-0">
|
||||
<div class="name">{{doctor.name}}</div>
|
||||
<div class="designation text-light font-small-2">Dentist</div>
|
||||
</td>
|
||||
<td class="text-right border-top-0">
|
||||
<a href="hospital-book-appointment.html" class="btn btn-sm btn-outline-success">Book Appointment</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Appointment Bar Line Chart Ends -->
|
||||
|
||||
<!-- Appointment Table -->
|
||||
<div class="row" matchHeight="card">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Doctors Available</h4>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="table-responsive">
|
||||
<table
|
||||
id="recent-orders"
|
||||
class="table table-hover table-xl mb-0"
|
||||
>
|
||||
<tbody>
|
||||
<tr *ngFor="let doctor of doctors">
|
||||
<td class="text-truncate p-1 border-top-0">
|
||||
<div class="avatar avatar-md">
|
||||
<img
|
||||
class="media-object rounded-circle"
|
||||
[src]="doctor.image"
|
||||
alt="Avatar"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-truncate pl-0 border-top-0">
|
||||
<div class="name">{{ doctor.name }}</div>
|
||||
<div class="designation text-light font-small-2">
|
||||
Dentist
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right border-top-0">
|
||||
<a
|
||||
href="hospital-book-appointment.html"
|
||||
class="btn btn-sm btn-outline-success"
|
||||
>Book Appointment</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="recent-appointments" class="col-12 col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Recent Appointments</h4>
|
||||
<a class="heading-elements-toggle"
|
||||
><i class="la la-ellipsis-v font-medium-3"></i
|
||||
></a>
|
||||
<div class="heading-elements">
|
||||
<ul class="list-inline mb-0">
|
||||
<li>
|
||||
<a
|
||||
class="btn btn-sm btn-danger box-shadow-2 round btn-min-width pull-right"
|
||||
href="hospital-book-appointment.html"
|
||||
target="_blank"
|
||||
>View all</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content mt-1">
|
||||
<div class="table-responsive">
|
||||
<table
|
||||
id="recent-orders-doctors"
|
||||
class="table table-hover table-xl mb-0"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-top-0">Doctor</th>
|
||||
<th class="border-top-0">Patients</th>
|
||||
<th class="border-top-0">Specialities</th>
|
||||
<th class="border-top-0">Timings</th>
|
||||
<th class="border-top-0">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="pull-up" *ngFor="let doctor of doctorList">
|
||||
<td class="text-truncate">{{ doctor.name }}</td>
|
||||
<td class="text-truncate p-1">
|
||||
<ul class="list-unstyled users-list m-0">
|
||||
<li
|
||||
data-toggle="tooltip"
|
||||
data-popup="tooltip-custom"
|
||||
data-original-title="Kimberly Simmons"
|
||||
class="avatar avatar-sm pull-up"
|
||||
*ngFor="let imageUrl of doctor.image"
|
||||
>
|
||||
<img
|
||||
class="media-object rounded-circle"
|
||||
[src]="imageUrl"
|
||||
alt="Avatar"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li class="avatar avatar-sm">
|
||||
<span class="badge badge-info">{{
|
||||
doctor.bagde
|
||||
}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-{{ doctor.type }} round"
|
||||
>
|
||||
{{ doctor.designation }}
|
||||
</button>
|
||||
</td>
|
||||
<td class="text-truncate">{{ doctor.time }}</td>
|
||||
<td class="text-truncate">{{ doctor.amount }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Appointment Table Ends -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="recent-appointments" class="col-12 col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Recent Appointments</h4>
|
||||
<a class="heading-elements-toggle"><i class="la la-ellipsis-v font-medium-3"></i></a>
|
||||
<div class="heading-elements">
|
||||
<ul class="list-inline mb-0">
|
||||
<li><a class="btn btn-sm btn-danger box-shadow-2 round btn-min-width pull-right" href="hospital-book-appointment.html"
|
||||
target="_blank">View all</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content mt-1">
|
||||
<div class="table-responsive">
|
||||
<table id="recent-orders-doctors" class="table table-hover table-xl mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-top-0">Doctor</th>
|
||||
<th class="border-top-0">Patients</th>
|
||||
<th class="border-top-0">Specialities</th>
|
||||
<th class="border-top-0">Timings</th>
|
||||
<th class="border-top-0">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="pull-up" *ngFor="let doctor of doctorList">
|
||||
<td class="text-truncate">{{doctor.name}}</td>
|
||||
<td class="text-truncate p-1">
|
||||
<ul class="list-unstyled users-list m-0">
|
||||
<li data-toggle="tooltip" data-popup="tooltip-custom" data-original-title="Kimberly Simmons" class="avatar avatar-sm pull-up" *ngFor="let imageUrl of doctor.image">
|
||||
<img class="media-object rounded-circle" [src]="imageUrl" alt="Avatar">
|
||||
|
||||
</li>
|
||||
|
||||
<li class="avatar avatar-sm">
|
||||
<span class="badge badge-info">{{doctor.bagde}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-outline-{{doctor.type}} round">{{doctor.designation}}</button>
|
||||
</td>
|
||||
<td class="text-truncate">{{doctor.time}}</td>
|
||||
<td class="text-truncate">{{doctor.amount}}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Appointment Table Ends -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Content-->
|
||||
<!-- END: Content-->
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
}
|
||||
|
||||
:host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut {
|
||||
stroke: #ff4961;
|
||||
stroke: #7949ff;
|
||||
stroke-width: 5.5px !important;
|
||||
}
|
||||
:host ::ng-deep .donut-chart2 {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</fieldset>
|
||||
<div class="row py-2">
|
||||
<div class="col-12 col-sm-6 col-md-6 mb-1">
|
||||
<a [routerLink]="['/dashboard/sales']" class="btn btn-primary btn-block"><i class="feather ft-home"></i>
|
||||
<a [routerLink]="['/monitoring']" class="btn btn-primary btn-block"><i class="feather ft-home"></i>
|
||||
Home</a>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6 mb-1">
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<div class="card border-grey border-lighten-3 px-1 py-1 box-shadow-3 m-0">
|
||||
<div class="card-body">
|
||||
<span class="card-title text-center">
|
||||
<img src="../../../../../assets/images/logo/logo-dark-lg.png" class="img-fluid mx-auto d-block pt-2"
|
||||
<img src="../../../../../assets/images/logo/smart.png" class="img-fluid mx-auto d-block pt-2"
|
||||
width="250" alt="logo">
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div class="col-12 d-flex align-items-center justify-content-center">
|
||||
<div class="col-lg-6 col-10">
|
||||
<img class="img-fluid mx-auto d-block pb-3 pt-4 width-65-per"
|
||||
src="../../../../../assets/images/logo/logo-dark-lg.png" alt="Modern Search">
|
||||
src="../../../../../assets/images/logo/smart.png" alt="Modern Search">
|
||||
<fieldset class="form-group position-relative">
|
||||
<input type="text" class="form-control form-control-xl input-xl" id="iconLeft1"
|
||||
placeholder="Explore Modern ...">
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<app-coming-soon></app-coming-soon>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CalculationComponent } from './calculation.component';
|
||||
|
||||
describe('CalculationComponent', () => {
|
||||
let component: CalculationComponent;
|
||||
let fixture: ComponentFixture<CalculationComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ CalculationComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CalculationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-calculation',
|
||||
templateUrl: './calculation.component.html',
|
||||
styleUrls: ['./calculation.component.css']
|
||||
})
|
||||
export class CalculationComponent {
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<p>calculator works!</p>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CalculatorComponent } from './calculator.component';
|
||||
|
||||
describe('CalculatorComponent', () => {
|
||||
let component: CalculatorComponent;
|
||||
let fixture: ComponentFixture<CalculatorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ CalculatorComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CalculatorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-calculator',
|
||||
templateUrl: './calculator.component.html',
|
||||
styleUrls: ['./calculator.component.css']
|
||||
})
|
||||
export class CalculatorComponent {
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CalculationComponent } from './calculation/calculation.component';
|
||||
import { ReductionComponent } from './reduction/reduction.component';
|
||||
import { CardModule } from '../../partials/general/card/card.module';
|
||||
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ClipboardModule } from 'ngx-clipboard';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ComingSoonComponent } from '../coming-soon/coming-soon.component';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CalculationComponent,
|
||||
ReductionComponent,
|
||||
ComingSoonComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
BreadcrumbModule,
|
||||
NgSelectModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
ClipboardModule,
|
||||
PerfectScrollbarModule,
|
||||
NgxDatatableModule,
|
||||
BlockUIModule.forRoot({
|
||||
template: BlockTemplateComponent
|
||||
}),
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: 'calculation',
|
||||
component: CalculationComponent
|
||||
},
|
||||
{
|
||||
path: 'reduction',
|
||||
component: ReductionComponent
|
||||
},
|
||||
])
|
||||
]
|
||||
})
|
||||
export class CalculatorModule { }
|
|
@ -0,0 +1 @@
|
|||
<app-coming-soon></app-coming-soon>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ReductionComponent } from './reduction.component';
|
||||
|
||||
describe('ReductionComponent', () => {
|
||||
let component: ReductionComponent;
|
||||
let fixture: ComponentFixture<ReductionComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ReductionComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ReductionComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-reduction',
|
||||
templateUrl: './reduction.component.html',
|
||||
styleUrls: ['./reduction.component.css']
|
||||
})
|
||||
export class ReductionComponent {
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
.bg-maintenance-image {
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.centered-card {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.box-shadow-2 {
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.box-shadow-3 {
|
||||
box-shadow: 0 3px 20px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
padding: 20px;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<div class="app-content content bg-maintenance-image">
|
||||
<div class="content-wrapper">
|
||||
<div class="content-body">
|
||||
<section class="flexbox-container">
|
||||
<div class="centered-card">
|
||||
<div class="card box-shadow-3">
|
||||
<div class="card-body">
|
||||
<span class="card-title text-center">
|
||||
<img
|
||||
src="assets/images/logo/smart.png"
|
||||
class="img-fluid mx-auto d-block pt-2"
|
||||
width="250"
|
||||
alt="logo"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<h3 style="font-weight: 600; color: #000000">Coming Soon</h3>
|
||||
<p style="color: #000000">
|
||||
We're working hard to bring you this page. <br />
|
||||
Please check back later.
|
||||
</p>
|
||||
<div class="mt-2">
|
||||
<i class="la la-cog spinner font-large-2"></i>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ComingSoonComponent } from './coming-soon.component';
|
||||
|
||||
describe('ComingSoonComponent', () => {
|
||||
let component: ComingSoonComponent;
|
||||
let fixture: ComponentFixture<ComingSoonComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ComingSoonComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ComingSoonComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-coming-soon',
|
||||
templateUrl: './coming-soon.component.html',
|
||||
styleUrls: ['./coming-soon.component.css']
|
||||
})
|
||||
export class ComingSoonComponent {
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
:host ::ng-deep .ng-select .ng-select-container {
|
||||
/* color: #ffffff !important; */
|
||||
/* background-color: #252525 !important; */
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<ng-select
|
||||
[items]="icons"
|
||||
bindLabel="name"
|
||||
(change)="onSelect($event)"
|
||||
[(ngModel)]="selectedIcon"
|
||||
bindValue="icon"
|
||||
placeholder="Select an icon"
|
||||
>
|
||||
<ng-template ng-option-tmp let-item="item">
|
||||
<i [ngClass]="item.icon"></i> {{ item.name }}
|
||||
</ng-template>
|
||||
</ng-select>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SelectIconComponent } from './select-icon.component';
|
||||
|
||||
describe('SelectIconComponent', () => {
|
||||
let component: SelectIconComponent;
|
||||
let fixture: ComponentFixture<SelectIconComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ SelectIconComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SelectIconComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { MasterService } from "../../service/master-api.service";
|
||||
interface Icon {
|
||||
name: string;
|
||||
icon: string;
|
||||
}
|
||||
@Component({
|
||||
selector: "app-select-icon",
|
||||
templateUrl: "./select-icon.component.html",
|
||||
styleUrls: ["./select-icon.component.css"],
|
||||
})
|
||||
export class SelectIconComponent {
|
||||
// @Output() iconSelected: EventEmitter<string> = new EventEmitter<string>();
|
||||
@Output() iconSelected = new EventEmitter<string>();
|
||||
@Input() selectedIcon = undefined;
|
||||
icons: any[] = [];
|
||||
constructor(private masterService: MasterService) {}
|
||||
ngOnInit(): void {
|
||||
this.masterService.getIconData().subscribe((res) => {
|
||||
this.icons = res.rows;
|
||||
});
|
||||
if (!this.selectedIcon) {
|
||||
this.selectedIcon = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onSelect(icon: Icon): void {
|
||||
if (icon) {
|
||||
this.iconSelected.emit(icon.icon);
|
||||
} else {
|
||||
this.iconSelected.emit(undefined);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { SelectIconComponent } from "./select-icon.component";
|
||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { NgSelectModule } from "@ng-select/ng-select";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
|
||||
@NgModule({
|
||||
declarations: [SelectIconComponent],
|
||||
imports: [CommonModule, NgbModule, NgSelectModule, FormsModule],
|
||||
exports: [
|
||||
SelectIconComponent
|
||||
]
|
||||
})
|
||||
export class SelectIconModule {}
|
|
@ -0,0 +1,443 @@
|
|||
: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: #37A647;
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,411 @@
|
|||
<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>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-6">
|
||||
<div class="card" style="background-color: #DDE1E6 !important">
|
||||
<div
|
||||
class="card-header"
|
||||
style="background-color: #DDE1E6 !important"
|
||||
>
|
||||
<h4
|
||||
class="card-title text-center text-custom-label"
|
||||
>
|
||||
Comparison of Previous Month Costs
|
||||
</h4>
|
||||
<hr
|
||||
style="
|
||||
border-top: 4px solid #242222;
|
||||
border-color: #242222 !important;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div
|
||||
echarts
|
||||
[options]="chartOption"
|
||||
class="echart-container"
|
||||
style="height: 150% !important"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-6">
|
||||
<div class="card" style="background-color: #DDE1E6 !important">
|
||||
<div
|
||||
class="card-header"
|
||||
style="background-color: #DDE1E6 !important"
|
||||
>
|
||||
<h4
|
||||
class="card-title text-center text-custom-label"
|
||||
>
|
||||
Comparison of Actual Costs and Estimated Costs
|
||||
</h4>
|
||||
<hr
|
||||
style="
|
||||
border-top: 4px solid #242222;
|
||||
border-color: #242222 !important;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div
|
||||
echarts
|
||||
[options]="chartOption2"
|
||||
class="echart-container"
|
||||
style="height: 150% !important"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="configuration">
|
||||
<div class="card" style="background-color: #FBFBFB !important">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-6 col-sm-3 col-md-3 col-lg-3 col-xl-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
[items]="dataBuildingList"
|
||||
[searchable]="true"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Building"
|
||||
[(ngModel)]="buildingSelected"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-3 col-md-3 col-lg-3 col-xl-3">
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="month"
|
||||
class="form-control"
|
||||
[(ngModel)]="dateSelected"
|
||||
id="month12"
|
||||
(focus)="focusElement('month12')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-3 col-md-3 col-lg-3 col-xl-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
[items]="dataMasterCategori"
|
||||
[searchable]="true"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Category"
|
||||
[(ngModel)]="categorySelected"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-3 col-md-3 col-lg-3 col-xl-3">
|
||||
<div class="d-flex">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success"
|
||||
(click)="doFilter()"
|
||||
style="
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-3">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Kwh"
|
||||
[(ngModel)]="kwhTerm"
|
||||
disabled
|
||||
/>
|
||||
<div
|
||||
class="input-group-append"
|
||||
style="background-color: #FBFBFB !important"
|
||||
>
|
||||
<span
|
||||
class="input-group-text"
|
||||
style="
|
||||
background-color: #FBFBFB !important;
|
||||
color: #242222;
|
||||
height: 40px !important;
|
||||
"
|
||||
>Kwh</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-3">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Cost"
|
||||
mask="separator"
|
||||
thousandSeparator="."
|
||||
[(ngModel)]="costTerm"
|
||||
disabled
|
||||
/>
|
||||
<div
|
||||
class="input-group-append"
|
||||
style="background-color: #FBFBFB !important"
|
||||
>
|
||||
<span
|
||||
class="input-group-text"
|
||||
style="
|
||||
background-color: #FBFBFB !important;
|
||||
color: #242222;
|
||||
height: 40px !important;
|
||||
"
|
||||
>IDR</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-6">
|
||||
<div class="d-flex justify-content-end">
|
||||
<button
|
||||
class="btn btn-secondary mr-2"
|
||||
style="
|
||||
width: 100%;
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
(click)="export()"
|
||||
[disabled]="spinnerExportActive"
|
||||
>
|
||||
<i
|
||||
class="la la-spinner spinner"
|
||||
*ngIf="spinnerExportActive"
|
||||
></i>
|
||||
<i class="ri-export-line" *ngIf="!spinnerExportActive"></i
|
||||
>
|
||||
<span>Export</span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary mr-2"
|
||||
style="
|
||||
width: 100%;
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
(click)="syncData()"
|
||||
[disabled]="spinnerActive"
|
||||
>
|
||||
<i
|
||||
class="la la-spinner spinner"
|
||||
*ngIf="spinnerActive"
|
||||
></i>
|
||||
<i class="la la-spinner" *ngIf="!spinnerActive"></i>
|
||||
<span>Syncing Data</span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
style="
|
||||
width: 100%;
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
(click)="addFieldValue()"
|
||||
>
|
||||
<i class="feather ft-plus"></i>
|
||||
<span>Add Actual Cost</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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 class="style-custom-label">
|
||||
{{ rowIndex + 1 }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="building"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Building</span>
|
||||
</ng-template>
|
||||
<ng-template let-value="value" ngx-datatable-cell-template>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="categoryName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Category</span>
|
||||
</ng-template>
|
||||
<ng-template let-value="value" ngx-datatable-cell-template>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="roomName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Room</span>
|
||||
</ng-template>
|
||||
<ng-template let-value="value" ngx-datatable-cell-template>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="estimationCost"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label"
|
||||
>Estimation Cost</span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template let-value="value" ngx-datatable-cell-template>
|
||||
<p class="style-custom-label">
|
||||
{{
|
||||
value.toLocaleString("id-ID", {
|
||||
style: "currency",
|
||||
currency: "IDR"
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="totalUse"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Total Kwh</span>
|
||||
</ng-template>
|
||||
<ng-template let-value="value" ngx-datatable-cell-template>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
kWh
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<!-- <ngx-datatable-column
|
||||
name="endDate"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Tanggal</span>
|
||||
</ng-template>
|
||||
<ng-template let-value="value" ngx-datatable-cell-template>
|
||||
<p class="style-custom-label">
|
||||
{{ value | date : "MM/yyyy" }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column> -->
|
||||
<ngx-datatable-column
|
||||
name="status_id"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Status</span>
|
||||
</ng-template>
|
||||
<ng-template ngx-datatable-cell-template let-value="value">
|
||||
<p class="style-custom-label">
|
||||
{{ value === 2 ? "Aktif" : "Tidak Aktif" }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="Actions"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="150"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Actions</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-rowIndex="rowIndex"
|
||||
let-row="row"
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm btn-warning mr-1"
|
||||
style="
|
||||
background-color: #DDE1E6 !important;
|
||||
border-color: #37A647 !important;
|
||||
"
|
||||
(click)="viewRow(row)"
|
||||
>
|
||||
<i
|
||||
class="ficon ri-export-line"
|
||||
style="color: #37A647 !important"
|
||||
></i>
|
||||
</button>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CostManagementComponent } from './cost-management.component';
|
||||
|
||||
describe('CostManagementComponent', () => {
|
||||
let component: CostManagementComponent;
|
||||
let fixture: ComponentFixture<CostManagementComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ CostManagementComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CostManagementComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,473 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { BuildingService } from "../service/monitoring-api.service";
|
||||
import { CostManagementService } from "../service/cost-management.service";
|
||||
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { ModalAddActualComponent } from "./modal-add-actual/modal-add-actual.component";
|
||||
import "chartist-plugin-tooltips";
|
||||
import { ModalExportComponent } from "./modal-export/modal-export.component";
|
||||
import { TableexcelService } from "src/app/_services/tableexcel.service";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { LoginService } from "../service/login.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-cost-management",
|
||||
templateUrl: "./cost-management.component.html",
|
||||
styleUrls: ["./cost-management.component.css"],
|
||||
})
|
||||
export class CostManagementComponent implements OnInit {
|
||||
public breadcrumb: any;
|
||||
data: any;
|
||||
filteredRows: any[];
|
||||
data_cost: any;
|
||||
searchTerm: string = "";
|
||||
kwhTerm: string = "";
|
||||
costTerm: string = "";
|
||||
rows: any = [];
|
||||
dataMasterCategori: any;
|
||||
dataBuildingList: any;
|
||||
public focucedElement = "";
|
||||
|
||||
spinnerActive = false;
|
||||
spinnerActiveActual = false;
|
||||
spinnerFilterActive = false;
|
||||
barChart: any;
|
||||
|
||||
dateSelected: any;
|
||||
buildingSelected: any;
|
||||
categorySelected: any;
|
||||
dataCompPrev: any;
|
||||
dataCompAct: any;
|
||||
storedData: any;
|
||||
|
||||
chartOption: any;
|
||||
chartOption2: any;
|
||||
|
||||
spinnerExportActive = false;
|
||||
|
||||
constructor(
|
||||
private monitoringApiService: BuildingService,
|
||||
private costService: CostManagementService,
|
||||
private modalService: NgbModal,
|
||||
private tableexcelService: TableexcelService,
|
||||
private toastr: ToastrService,
|
||||
private authService: LoginService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.breadcrumb = {
|
||||
mainlabel: "Cost Management",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Cost Management",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
this.storedData = JSON.parse(localStorage.getItem("currentUser"));
|
||||
this.buildingSelected = this.storedData.buildingId;
|
||||
const currentDate = new Date();
|
||||
this.dateSelected = currentDate.toISOString().slice(0, 7);
|
||||
|
||||
this.fetchData(
|
||||
this.storedData.buildingId,
|
||||
this.dateSelected,
|
||||
this.categorySelected
|
||||
);
|
||||
this.dataListMaster();
|
||||
this.dataListBuilding();
|
||||
|
||||
this.dataCompPrevMonthCost(this.storedData.buildingId);
|
||||
this.dataCompActEstCost(this.storedData.buildingId);
|
||||
}
|
||||
|
||||
fetchData(id, period, category) {
|
||||
this.costService
|
||||
.getCostManagement(id, period, category)
|
||||
.subscribe((response) => {
|
||||
this.data = response.results.data;
|
||||
this.filteredRows = this.data;
|
||||
let kwhData = parseFloat(response.results.kwh);
|
||||
this.kwhTerm = kwhData.toFixed(1);
|
||||
|
||||
this.costTerm = response.results.cost;
|
||||
|
||||
this.data_cost = this.filteredRows.map((item) => ({
|
||||
building: item.name,
|
||||
roomName: item.room_name,
|
||||
categoryName: item.category_name,
|
||||
estimationCost: item.estimation_cost,
|
||||
totalUse: item.total_use.toFixed(1),
|
||||
endDate: this.convertToUTC7(item.end_date),
|
||||
// endDate: item.end_date,
|
||||
statusId: item.status_id,
|
||||
categoryId: item.category_id,
|
||||
roomId: item.room_id,
|
||||
}));
|
||||
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();
|
||||
}
|
||||
|
||||
dataListMaster() {
|
||||
this.monitoringApiService.getMasterListData().subscribe((data) => {
|
||||
const dataCategory = data.data.find(
|
||||
(item) => item.name === "master_category"
|
||||
).headerDetailParam;
|
||||
this.dataMasterCategori = dataCategory.filter(
|
||||
(item) => item.statusName.toLowerCase() === "aktif"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
dataListBuilding() {
|
||||
this.monitoringApiService.getBuildingList().subscribe((data) => {
|
||||
this.dataBuildingList = data.data.filter(
|
||||
(item) => item.statusName.toLowerCase() === "aktif"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
dataCompPrevMonthCost(buildingId) {
|
||||
this.costService.getCompPrevMonthCost(buildingId).subscribe((data) => {
|
||||
this.dataCompPrev = data.data;
|
||||
this.chartOption = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
},
|
||||
formatter: function (params) {
|
||||
var tar = params[1];
|
||||
return tar.name + "<br/>" + tar.seriesName + " : " + tar.value;
|
||||
},
|
||||
},
|
||||
|
||||
grid: {
|
||||
left: "25%",
|
||||
right: "25%",
|
||||
top: "20%",
|
||||
bottom: "20%",
|
||||
},
|
||||
color: ["#37A647"],
|
||||
xAxis: {
|
||||
type: "category",
|
||||
splitLine: { show: false },
|
||||
data: [this.dataCompPrev[0].name, this.dataCompPrev[1].name],
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#37A647",
|
||||
width: 7,
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
|
||||
series: [
|
||||
// {
|
||||
// name: "Placeholder",
|
||||
// type: "bar",
|
||||
// stack: "Total",
|
||||
// itemStyle: {
|
||||
// borderColor: "transparent",
|
||||
// color: "transparent",
|
||||
// },
|
||||
// emphasis: {
|
||||
// itemStyle: {
|
||||
// borderColor: "transparent",
|
||||
// color: "transparent",
|
||||
// },
|
||||
// },
|
||||
// data: [1000, 1000],
|
||||
// },
|
||||
{
|
||||
name: "Cost",
|
||||
type: "bar",
|
||||
stack: "Total",
|
||||
label: {
|
||||
show: true,
|
||||
position: "top",
|
||||
color: "#242222",
|
||||
formatter: function (params) {
|
||||
return `Rp. ${params.value.toLocaleString()}`;
|
||||
},
|
||||
},
|
||||
// barWidth: "50%",
|
||||
data: [this.dataCompPrev[0].rupiah, this.dataCompPrev[1].rupiah],
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
dataCompActEstCost(buildingId) {
|
||||
this.costService.getCompActEstCost(buildingId).subscribe((data) => {
|
||||
this.dataCompAct = data.data[0];
|
||||
this.chartOption2 = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
},
|
||||
formatter: function (params) {
|
||||
var tar = params[1];
|
||||
return tar.name + "<br/>" + tar.seriesName + " : " + tar.value;
|
||||
},
|
||||
},
|
||||
|
||||
grid: {
|
||||
left: "25%",
|
||||
right: "25%",
|
||||
top: "20%",
|
||||
bottom: "20%",
|
||||
},
|
||||
color: ["#37A647"],
|
||||
xAxis: {
|
||||
type: "category",
|
||||
splitLine: { show: false },
|
||||
data: ["Estimation Cost", "Actual Cost"],
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#37A647",
|
||||
width: 7,
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
|
||||
series: [
|
||||
// {
|
||||
// name: "Placeholder",
|
||||
// type: "bar",
|
||||
// stack: "Total",
|
||||
// itemStyle: {
|
||||
// borderColor: "transparent",
|
||||
// color: "transparent",
|
||||
// },
|
||||
// emphasis: {
|
||||
// itemStyle: {
|
||||
// borderColor: "transparent",
|
||||
// color: "transparent",
|
||||
// },
|
||||
// },
|
||||
// data: [2500, 2500],
|
||||
// },
|
||||
{
|
||||
name: "Cost",
|
||||
type: "bar",
|
||||
stack: "Total",
|
||||
label: {
|
||||
show: true,
|
||||
position: "top",
|
||||
color: "#242222",
|
||||
formatter: function (params) {
|
||||
return `Rp. ${params.value.toLocaleString()}`;
|
||||
},
|
||||
},
|
||||
// barWidth: "50%",
|
||||
data: [this.dataCompAct.est_cost, this.dataCompAct.real_cost],
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
syncData() {
|
||||
const dataDate = {
|
||||
buildingId: this.buildingSelected,
|
||||
periode: this.dateSelected,
|
||||
};
|
||||
this.spinnerActive = true;
|
||||
this.costService.getSyncCost(dataDate).subscribe((data) => {
|
||||
this.dataCompPrevMonthCost(this.storedData.buildingId);
|
||||
this.dataCompActEstCost(this.storedData.buildingId);
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.spinnerActive = false;
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.dateSelected,
|
||||
this.categorySelected
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
actualData() {
|
||||
this.spinnerActiveActual = true;
|
||||
this.costService
|
||||
.getRealCostByBuildingId(4, this.dateSelected)
|
||||
.subscribe((data) => {
|
||||
// console.log(data.data[0]);
|
||||
// this.costTerm = data.data[0].est_cost
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.spinnerActiveActual = false;
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.dateSelected,
|
||||
this.categorySelected
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
doFilter() {
|
||||
if (this.dateSelected) {
|
||||
this.spinnerFilterActive = true;
|
||||
setTimeout(() => {
|
||||
this.spinnerFilterActive = false;
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.dateSelected,
|
||||
this.categorySelected
|
||||
);
|
||||
}, 3000);
|
||||
} else {
|
||||
this.toastr.error("Warning", "Format date tidak valid.", {
|
||||
timeOut: 5000,
|
||||
closeButton: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addFieldValue() {
|
||||
const modalRef = this.modalService.open(ModalAddActualComponent, {
|
||||
size: "sm",
|
||||
centered: true,
|
||||
});
|
||||
modalRef.componentInstance.buildingId = this.buildingSelected;
|
||||
modalRef.componentInstance.periode = this.dateSelected;
|
||||
|
||||
modalRef.result.then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.rows.push(result);
|
||||
this.rows = [...this.rows];
|
||||
this.dataCompActEstCost(this.buildingSelected);
|
||||
}
|
||||
},
|
||||
(reason) => {
|
||||
console.log(`Dismissed: ${reason}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
focusElement(focucedElement: any) {
|
||||
this.focucedElement = focucedElement;
|
||||
}
|
||||
|
||||
filterRows() {
|
||||
if (!this.searchTerm) {
|
||||
this.filteredRows = [...this.data.rows];
|
||||
} else {
|
||||
this.filteredRows = this.data.rows.filter((row) =>
|
||||
this.rowContainsSearchTerm(row)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rowContainsSearchTerm(row: any): boolean {
|
||||
const searchTermLC = this.searchTerm.toLowerCase();
|
||||
return Object.values(row).some(
|
||||
(value) =>
|
||||
value !== null && value.toString().toLowerCase().includes(searchTermLC)
|
||||
);
|
||||
}
|
||||
|
||||
viewRow(row) {
|
||||
const modalRef = this.modalService.open(ModalExportComponent, {
|
||||
size: "xl",
|
||||
centered: true,
|
||||
});
|
||||
modalRef.componentInstance.buildingId = this.buildingSelected;
|
||||
modalRef.componentInstance.dataRow = row;
|
||||
|
||||
modalRef.result.then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.rows.push(result);
|
||||
this.rows = [...this.rows];
|
||||
}
|
||||
},
|
||||
(reason) => {
|
||||
console.log(`Dismissed: ${reason}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export() {
|
||||
this.spinnerExportActive = true;
|
||||
setTimeout(() => {
|
||||
const columnsToExport = [
|
||||
"building",
|
||||
"roomName",
|
||||
"categoryName",
|
||||
"totalUse",
|
||||
"estimationCost",
|
||||
"endDate",
|
||||
];
|
||||
this.tableexcelService.exportAsExcelFileCostManage(
|
||||
this.data_cost,
|
||||
"Smart_building_cost_management",
|
||||
columnsToExport
|
||||
);
|
||||
this.spinnerExportActive = false;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule, DatePipe } from '@angular/common';
|
||||
import { CostManagementComponent } from './cost-management.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
|
||||
import { CardModule } from '../../partials/general/card/card.module';
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ClipboardModule } from 'ngx-clipboard';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgChartsModule } from 'ng2-charts';
|
||||
import { ChartistModule } from 'ng-chartist';
|
||||
import { MatchHeightModule } from '../../partials/general/match-height/match-height.module';
|
||||
import { ModalAddActualComponent } from './modal-add-actual/modal-add-actual.component';
|
||||
import { NgxMaskModule, IConfig } from 'ngx-mask';
|
||||
import { ModalExportComponent } from './modal-export/modal-export.component'
|
||||
import { NgxEchartsModule } from 'ngx-echarts';
|
||||
export const options: Partial<null|IConfig> | (() => Partial<IConfig>) = null;
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CostManagementComponent,
|
||||
ModalAddActualComponent,
|
||||
ModalExportComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
BreadcrumbModule,
|
||||
NgSelectModule,
|
||||
FormsModule,
|
||||
NgbModule,
|
||||
ReactiveFormsModule,
|
||||
ClipboardModule,
|
||||
PerfectScrollbarModule,
|
||||
NgxDatatableModule,
|
||||
NgChartsModule,
|
||||
ChartistModule,
|
||||
MatchHeightModule,
|
||||
NgxEchartsModule.forRoot({
|
||||
echarts: () => import('echarts')
|
||||
}),
|
||||
NgxMaskModule.forRoot(),
|
||||
BlockUIModule.forRoot({
|
||||
template: BlockTemplateComponent
|
||||
}),
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: CostManagementComponent
|
||||
}
|
||||
])
|
||||
],
|
||||
providers: [
|
||||
DatePipe // Add DatePipe to providers
|
||||
],
|
||||
})
|
||||
export class CostManagementModule { }
|
|
@ -0,0 +1,56 @@
|
|||
/* modal-add-edit.component.css */
|
||||
::ng-deep .modal-backdrop.show {
|
||||
z-index: auto !important;
|
||||
}
|
||||
|
||||
::ng-deep .input-group-append .btn {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
flex-grow: 0;
|
||||
border-left: 1px solid #ced4da;
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group {
|
||||
display: flex;
|
||||
flex-wrap: nowrap; /* Prevents wrapping of the items */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::ng-deep .form-control {
|
||||
flex-grow: 1; /* Ensures select takes up available space */
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group select,
|
||||
::ng-deep .input-group .input-group-append .btn {
|
||||
padding-right: 5px; /* Adjust padding if necessary */
|
||||
}
|
||||
|
||||
::ng-deep .input-group .form-control {
|
||||
margin-right: 2px; /* Adjust margin to make space */
|
||||
}
|
||||
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<div class="modal-body" style="background-color: #FBFBFB !important">
|
||||
<h4 style="color: #242222">Input the actual cost of your expenses</h4>
|
||||
<p style="color: #242222">Building : {{ buildingName }}</p>
|
||||
<p style="color: #242222">Periode : {{ formattedDate }}</p>
|
||||
<form [formGroup]="myForm">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div
|
||||
class="input-group-prepend"
|
||||
style="background-color: #FBFBFB !important"
|
||||
>
|
||||
<span
|
||||
class="input-group-text"
|
||||
id="basic-addon1"
|
||||
style="
|
||||
background-color: #FBFBFB !important;
|
||||
color: #242222;
|
||||
height: calc(1.5em + 0.75rem + 2px) !important;
|
||||
"
|
||||
>Rp</span
|
||||
>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="real_cost"
|
||||
aria-describedby="basic-addon1"
|
||||
formControlName="real_cost"
|
||||
placeholder="..............."
|
||||
mask="separator"
|
||||
thousandSeparator="."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer justify-content-between" style="background-color: #FBFBFB !important; border-style: none !important;">
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
style="
|
||||
color: #242222;
|
||||
width: 25%;
|
||||
background-color: #FBFBFB !important;
|
||||
border-color: #FBFBFB !important;
|
||||
border-radius: 10px;
|
||||
"
|
||||
(click)="activeModal.dismiss('Cross click')"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
style="
|
||||
color: #242222 !important;
|
||||
width: 25%;
|
||||
background-color: #DDE1E6 !important;
|
||||
border-color: #DDE1E6 !important;
|
||||
border-radius: 10px;
|
||||
"
|
||||
(click)="addRow()"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ModalAddActualComponent } from './modal-add-actual.component';
|
||||
|
||||
describe('ModalAddActualComponent', () => {
|
||||
let component: ModalAddActualComponent;
|
||||
let fixture: ComponentFixture<ModalAddActualComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ModalAddActualComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ModalAddActualComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,100 @@
|
|||
import { Component, Input } from "@angular/core";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { CostManagementService } from "../../service/cost-management.service";
|
||||
import { LoginService } from "../../service/login.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-modal-add-actual",
|
||||
templateUrl: "./modal-add-actual.component.html",
|
||||
styleUrls: ["./modal-add-actual.component.css"],
|
||||
})
|
||||
export class ModalAddActualComponent {
|
||||
@Input() buildingId: number;
|
||||
@Input() periode: any;
|
||||
|
||||
myForm: FormGroup;
|
||||
dateCurrent: any;
|
||||
dataCost: any;
|
||||
formattedDate: any;
|
||||
formattedDate2: any;
|
||||
buildingName: any;
|
||||
|
||||
constructor(
|
||||
public activeModal: NgbActiveModal,
|
||||
private fb: FormBuilder,
|
||||
private costService: CostManagementService,
|
||||
private authService: LoginService
|
||||
) {
|
||||
this.createForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
const currentDate = new Date();
|
||||
this.dateCurrent = currentDate.toISOString().slice(0, 7);
|
||||
this.dateFormat();
|
||||
this.getBuildingById();
|
||||
this.datalistcost();
|
||||
}
|
||||
|
||||
dateFormat() {
|
||||
let year = this.periode.slice(0, 4);
|
||||
let month = this.periode.slice(5, 7);
|
||||
let monthNames = [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Maret",
|
||||
"April",
|
||||
"Mei",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Agustus",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Desember",
|
||||
];
|
||||
let monthName = monthNames[parseInt(month) - 1];
|
||||
this.formattedDate = `${monthName} ${year}`;
|
||||
this.formattedDate2 = `${year}-${month}`;
|
||||
|
||||
|
||||
}
|
||||
|
||||
createForm() {
|
||||
this.myForm = this.fb.group({
|
||||
real_cost: ["", Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
getBuildingById() {
|
||||
this.costService.getBUildingById(this.buildingId).subscribe((data) => {
|
||||
this.buildingName = data.data.name;
|
||||
});
|
||||
}
|
||||
|
||||
datalistcost() {
|
||||
this.costService
|
||||
.getRealCostByBuildingId(this.buildingId, this.formattedDate2)
|
||||
.subscribe((data) => {
|
||||
this.dataCost = data.data[0];
|
||||
this.myForm.patchValue({
|
||||
real_cost: data.data[0].real_cost ? data.data[0].real_cost : 0,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addRow() {
|
||||
if (this.myForm.valid) {
|
||||
this.costService
|
||||
.putRealCost(this.myForm.value, this.dataCost.id)
|
||||
.subscribe((data) => {
|
||||
console.log(data);
|
||||
|
||||
this.activeModal.close(this.myForm.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
<div class="modal-body" style="background-color: #FBFBFB !important">
|
||||
<h4 style="color: #242222; margin-bottom: 20px !important">
|
||||
Comparison of Water and Electricity Costs > {{ dataRow.building }}
|
||||
</h4>
|
||||
<p style="color: #242222">Room : {{ dataRow?.roomName }}</p>
|
||||
<p style="color: #242222">Category : {{ dataRow?.categoryName }}</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="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="roomName" [flexGrow]="1" [minWidth]="90">
|
||||
<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="categoryName" [flexGrow]="1" [minWidth]="90">
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span style="color: #242222 !important">Category</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="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-column name="totalKwh" [flexGrow]="1" [minWidth]="90">
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span style="color: #242222 !important">Total 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="watt" [flexGrow]="1" [minWidth]="90">
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span style="color: #242222 !important">Watt</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.toLocaleString("id-ID", {
|
||||
style: "currency",
|
||||
currency: "IDR"
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="modal-footer justify-content-between"
|
||||
style="background-color: #FBFBFB !important; border-style: none !important"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
style="
|
||||
color: #242222;
|
||||
width: 25%;
|
||||
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: #242222 !important;
|
||||
width: 25%;
|
||||
background-color: #DDE1E6 !important;
|
||||
border-color: #DDE1E6 !important;
|
||||
border-radius: 10px;
|
||||
"
|
||||
[disabled]="spinnerExportActive"
|
||||
(click)="export()"
|
||||
>
|
||||
<i class="la la-spinner spinner" *ngIf="spinnerExportActive"></i>
|
||||
Export
|
||||
</button>
|
||||
</div>
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,103 @@
|
|||
import { Component, Input } from "@angular/core";
|
||||
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { DeviceService } from "../../service/device.service";
|
||||
import { CostManagementService } from "../../service/cost-management.service";
|
||||
import { TableexcelService } from "src/app/_services/tableexcel.service";
|
||||
import { LoginService } from "../../service/login.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-modal-export",
|
||||
templateUrl: "./modal-export.component.html",
|
||||
styleUrls: ["./modal-export.component.css"],
|
||||
})
|
||||
export class ModalExportComponent {
|
||||
@Input() buildingId: number;
|
||||
@Input() dataRow: any;
|
||||
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 costService: CostManagementService,
|
||||
private tableexcelService: TableexcelService,
|
||||
private authService: LoginService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
const dateRow = this.convertToUTC7(this.dataRow.endDate)
|
||||
this.formattedEndDate = dateRow.slice(0, 7);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
console.log(this.dataRow);
|
||||
this.fetchData(
|
||||
this.dataRow.categoryId,
|
||||
this.dataRow.roomId,
|
||||
this.formattedEndDate
|
||||
);
|
||||
}
|
||||
|
||||
fetchData(category, room, period) {
|
||||
this.costService
|
||||
.getCostDetail(category, room, period)
|
||||
.subscribe((response) => {
|
||||
this.dataExport = response.data;
|
||||
console.log(this.dataExport);
|
||||
this.data_cost = response.data.map((item) => ({
|
||||
deviceName: item.device_name,
|
||||
roomName: item.room_name,
|
||||
categoryName: item.category_name,
|
||||
estimationCost: item.estimation_cost,
|
||||
totalKwh: item.total_kwh,
|
||||
watt: item.watt,
|
||||
duration: item.duration,
|
||||
priceKwh: item.price_kwh,
|
||||
// periode: item.periode,
|
||||
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(() => {
|
||||
const columnsToExport = [
|
||||
"periode",
|
||||
"deviceName",
|
||||
"roomName",
|
||||
"categoryName",
|
||||
"estimationCost",
|
||||
"totalKwh",
|
||||
"watt",
|
||||
"duration",
|
||||
"priceKwh",
|
||||
];
|
||||
this.tableexcelService.exportAsExcelFileManageDetail(
|
||||
this.data_cost,
|
||||
"export_detail_cost_management",
|
||||
columnsToExport
|
||||
);
|
||||
this.spinnerExportActive = false;
|
||||
this.activeModal.close("Export completed");
|
||||
}, 3000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
.form-control.is-invalid {
|
||||
border-color: #CACFE7;
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
.div.basicInfoCard {
|
||||
height: 700px;
|
||||
}
|
||||
|
||||
:host ::ng-deep .block-ui-wrapper {
|
||||
background: rgba(255, 249, 249, 0.5) !important;
|
||||
}
|
||||
:host ::ng-deep .block-ui-wrapper {
|
||||
background: rgba(255, 249, 249, 0.5) !important;
|
||||
}
|
||||
:host ::ng-deep .btn-light:not(:disabled):not(.disabled):active {
|
||||
color: unset !important;
|
||||
background-color: unset !important;
|
||||
border-color: #d3d9df !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .btn-light:hover:not(.disabled):active {
|
||||
background-color: #e2e6ea !important;
|
||||
border-color: #dae0e5 !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .btn-light {
|
||||
color: unset !important;
|
||||
background-color: unset !important;
|
||||
border-color: unset !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .bg-primary {
|
||||
background-color: #007bff !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .text-white {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .custom-day {
|
||||
text-align: center;
|
||||
padding: .185rem .25rem;
|
||||
display: inline-block;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
:host ::ng-deep .custom-day:active {
|
||||
color: #6d7183 !important;
|
||||
background-color: #fff !important;
|
||||
border-block-color: rgb(2, 117, 216) !important;
|
||||
|
||||
}
|
||||
|
||||
.bg-light {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .hidden {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.ngb-dp-weekday {
|
||||
color: #17a2b8;
|
||||
}
|
||||
|
||||
.ngb-dp-week-number,
|
||||
.ngb-dp-weekday {
|
||||
line-height: 2rem;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.ngb-datepicker-month-view {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 80%;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.ngb-dp-day {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.ngb-dp-month {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.btn-light:hover {
|
||||
color: #212529 !important;
|
||||
background-color: #e2e6ea !important;
|
||||
border-color: #dae0e5 !important;
|
||||
}
|
||||
|
||||
.ngb-datepicker-month-view {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
:host ::ng-deep .ngb-dp-header {
|
||||
background-color: var(--light) !important;
|
||||
}
|
||||
|
||||
:host ::ng-deep .ngb-dp-weekdays {
|
||||
background-color: var(--light);
|
||||
}
|
||||
|
||||
:host ::ng-deep .ngb-dp-month-name {
|
||||
background-color: var(--light);
|
||||
}
|
||||
|
||||
.ngb-dp-header {
|
||||
border-bottom: 0;
|
||||
border-radius: .25rem .25rem 0 0;
|
||||
padding-top: .25rem;
|
||||
}
|
||||
|
||||
.ngb-dp-day,
|
||||
.ngb-dp-week-number,
|
||||
.ngb-dp-weekday {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.custom-day {
|
||||
text-align: center;
|
||||
padding: 0.185rem 0.25rem;
|
||||
display: inline-block;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.custom-day.focused {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.custom-day.range,
|
||||
.custom-day:hover {
|
||||
background-color: rgb(2, 117, 216);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.custom-day.faded {
|
||||
background-color: rgba(2, 117, 216, 0.5);
|
||||
}
|
||||
|
||||
:host ::ng-deep .block-ui-wrapper {
|
||||
background: rgba(255, 249, 249, 0.5) !important;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
<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-12" *blockUI="'projectInfo'; message: 'Loading'">
|
||||
<div class="card" style="background-color: #fbfbfb !important">
|
||||
<div class="card-content">
|
||||
<div
|
||||
class="card-header"
|
||||
style="background-color: #fbfbfb !important"
|
||||
>
|
||||
<h2 style="color: #242222">
|
||||
{{
|
||||
isEditMode()
|
||||
? "Edit Device"
|
||||
: isViewMode()
|
||||
? "View Device"
|
||||
: "Add New Device"
|
||||
}}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form
|
||||
[formGroup]="projectInfo"
|
||||
(ngSubmit)="onProjectInfoSubmit()"
|
||||
>
|
||||
<div class="form-body">
|
||||
<h4 class="form-section" style="color: #242222">
|
||||
<i class="feather ft-user" style="color: #242222"></i>
|
||||
General Information
|
||||
</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="name" style="color: #242222"
|
||||
>Device Name *</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
class="form-control"
|
||||
formControlName="name"
|
||||
placeholder="Device Name"
|
||||
maxlength="50"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.name.errors
|
||||
}"
|
||||
/>
|
||||
<small
|
||||
class="form-text text-muted danger"
|
||||
*ngIf="submitted && f.name.errors"
|
||||
class="invalid-feedback"
|
||||
>
|
||||
<div *ngIf="f.name.errors.required">
|
||||
Device Name is required
|
||||
</div>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="categoryId" style="color: #242222"
|
||||
>Category *</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<select
|
||||
id="categoryId"
|
||||
class="form-control custom-select"
|
||||
formControlName="categoryId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.categoryId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataMasterCategori"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="
|
||||
projectInfo.get('categoryId').invalid &&
|
||||
projectInfo.get('categoryId').touched
|
||||
"
|
||||
class="text-danger"
|
||||
>
|
||||
<small class="text-danger"
|
||||
>Category is required.</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="voltageId" style="color: #242222"
|
||||
>Voltage *</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<select
|
||||
id="voltageId"
|
||||
class="form-control custom-select"
|
||||
formControlName="voltageId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.voltageId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataMasterVoltage"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="
|
||||
projectInfo.get('voltageId').invalid &&
|
||||
projectInfo.get('voltageId').touched
|
||||
"
|
||||
class="text-danger"
|
||||
>
|
||||
<small class="text-danger"
|
||||
>Voltage is required.</small
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="typeId" style="color: #242222"
|
||||
>Type *</label
|
||||
>
|
||||
<select
|
||||
id="typeId"
|
||||
class="form-control custom-select"
|
||||
formControlName="typeId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.typeId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataMasterType"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
<small
|
||||
class="form-text text-muted danger"
|
||||
*ngIf="submitted && f.typeId.errors"
|
||||
class="invalid-feedback"
|
||||
>
|
||||
<div *ngIf="f.typeId.errors.required">
|
||||
Type is required
|
||||
</div>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="durationId" style="color: #242222"
|
||||
>Duration Use *</label
|
||||
>
|
||||
<select
|
||||
id="durationId"
|
||||
class="form-control custom-select"
|
||||
formControlName="durationId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.durationId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataMasterDuration"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
<small
|
||||
class="form-text text-muted danger"
|
||||
*ngIf="submitted && f.durationId.errors"
|
||||
class="invalid-feedback"
|
||||
>
|
||||
<div *ngIf="f.durationId.errors.required">
|
||||
Duration is required
|
||||
</div>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="roomBuildingId" style="color: #242222"
|
||||
>Location Room *</label
|
||||
>
|
||||
<select
|
||||
id="roomBuildingId"
|
||||
class="form-control custom-select"
|
||||
formControlName="roomBuildingId"
|
||||
[ngClass]="{
|
||||
'is-invalid':
|
||||
submitted && f.roomBuildingId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataBuildingRoomList"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
<small
|
||||
class="form-text text-muted danger"
|
||||
*ngIf="submitted && f.roomBuildingId.errors"
|
||||
class="invalid-feedback"
|
||||
>
|
||||
<div *ngIf="f.roomBuildingId.errors.required">
|
||||
location room is required
|
||||
</div>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="watt" style="color: #242222"
|
||||
>Watt *</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="watt"
|
||||
class="form-control"
|
||||
formControlName="watt"
|
||||
maxlength="10"
|
||||
placeholder="Watt"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.watt.errors
|
||||
}"
|
||||
/>
|
||||
<div
|
||||
*ngIf="
|
||||
projectInfo.get('watt').invalid &&
|
||||
projectInfo.get('watt').touched
|
||||
"
|
||||
class="text-danger"
|
||||
>
|
||||
<small class="text-danger">Please enter a valid Watt.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning mr-1"
|
||||
style="
|
||||
color: #242222 !important;
|
||||
background-color: #fbfbfb !important;
|
||||
border-color: #fbfbfb !important;
|
||||
"
|
||||
(click)="cancel()"
|
||||
>
|
||||
<i *ngIf="mode === 'edit'" class="feather ft-x"></i>
|
||||
<i *ngIf="mode === 'view'" class="la la-arrow-left"></i>
|
||||
{{ mode === "edit" ? "Cancel" : "Back" }}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
style="
|
||||
color: #ffffff !important;
|
||||
background-color: #37a647 !important;
|
||||
"
|
||||
(click)="saveEdit()"
|
||||
*ngIf="mode === 'edit'"
|
||||
>
|
||||
<i class="la la-check"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AddEditDeviceComponent } from './add-edit-device.component';
|
||||
|
||||
describe('AddEditDeviceComponent', () => {
|
||||
let component: AddEditDeviceComponent;
|
||||
let fixture: ComponentFixture<AddEditDeviceComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ AddEditDeviceComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AddEditDeviceComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,308 @@
|
|||
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormBuilder, FormGroup, 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 Swal from "sweetalert2";
|
||||
|
||||
@Component({
|
||||
selector: "app-add-edit-device",
|
||||
templateUrl: "./add-edit-device.component.html",
|
||||
styleUrls: ["./add-edit-device.component.css"],
|
||||
})
|
||||
export class AddEditDeviceComponent implements OnInit {
|
||||
@ViewChild("f", { read: true }) userProfileForm: NgForm;
|
||||
dataMasterCategori: any;
|
||||
dataMasterVoltage: any;
|
||||
dataMasterType: any;
|
||||
dataMasterDuration: any;
|
||||
dataMasterStatus: any;
|
||||
dataBuildingRoomList: any;
|
||||
deviceId: any;
|
||||
|
||||
model: any = {};
|
||||
dataDevice: any;
|
||||
mode: string;
|
||||
|
||||
@BlockUI("projectInfo") blockUIProjectInfo: NgBlockUI;
|
||||
|
||||
public breadcrumb: any;
|
||||
|
||||
projectInfo: FormGroup;
|
||||
|
||||
submitted = false;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private monitoringApiService: BuildingService,
|
||||
private authService: LoginService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.route.params.subscribe((params) => {
|
||||
const id = params["id"];
|
||||
this.deviceId = id;
|
||||
if (id) {
|
||||
this.loadDevice(id);
|
||||
this.dataListMaster();
|
||||
this.dataListRoomBuilding();
|
||||
}
|
||||
});
|
||||
this.setBreadcrumb();
|
||||
this.route.data.subscribe((data) => {
|
||||
this.mode = data.mode;
|
||||
});
|
||||
|
||||
this.projectInfo = this.formBuilder.group({
|
||||
name: ["", Validators.required],
|
||||
categoryId: ["", Validators.required],
|
||||
voltageId: ["", Validators.required],
|
||||
typeId: ["", Validators.required],
|
||||
durationId: ["", Validators.required],
|
||||
roomBuildingId: ["", Validators.required],
|
||||
watt: ["", [Validators.required, Validators.maxLength(15), Validators.pattern(/^[0-9]{1,7}$/)]],
|
||||
});
|
||||
}
|
||||
|
||||
loadDevice(deviceId: string) {
|
||||
this.monitoringApiService.getDeviceById(deviceId).subscribe((data) => {
|
||||
this.dataDevice = data;
|
||||
console.log(this.dataDevice);
|
||||
|
||||
this.formGetDevice(data);
|
||||
});
|
||||
}
|
||||
|
||||
dataListMaster() {
|
||||
this.monitoringApiService.getMasterListData().subscribe((data) => {
|
||||
const dataCategory = data.data.find(
|
||||
(item) => item.name === "master_category"
|
||||
).headerDetailParam;
|
||||
this.dataMasterCategori = dataCategory.filter(
|
||||
(item) =>
|
||||
item.statusName.toLowerCase() === "aktif" ||
|
||||
item.status.toLowerCase() === "71"
|
||||
);
|
||||
|
||||
const dataVoltage = data.data.find(
|
||||
(item) => item.name === "master_voltage"
|
||||
).headerDetailParam;
|
||||
this.dataMasterVoltage = dataVoltage.filter(
|
||||
(item) =>
|
||||
item.statusName.toLowerCase() === "aktif" ||
|
||||
item.status.toLowerCase() === "71"
|
||||
);
|
||||
|
||||
const dataType = data.data.find(
|
||||
(item) => item.name === "master_type"
|
||||
).headerDetailParam;
|
||||
this.dataMasterType = dataType.filter(
|
||||
(item) =>
|
||||
item.statusName.toLowerCase() === "aktif" ||
|
||||
item.status.toLowerCase() === "71"
|
||||
);
|
||||
|
||||
const dataDuration = data.data.find(
|
||||
(item) => item.name === "master_duration"
|
||||
).headerDetailParam;
|
||||
this.dataMasterDuration = dataDuration.filter(
|
||||
(item) =>
|
||||
item.statusName.toLowerCase() === "aktif" ||
|
||||
item.status.toLowerCase() === "71"
|
||||
);
|
||||
|
||||
const dataStatus = data.data.find(
|
||||
(item) => item.name === "master_status"
|
||||
).headerDetailParam;
|
||||
this.dataMasterStatus = dataStatus.filter(
|
||||
(item) =>
|
||||
item.statusName.toLowerCase() === "aktif" ||
|
||||
item.status.toLowerCase() === "71"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
dataListRoomBuilding() {
|
||||
this.monitoringApiService.getBuildingRoomList().subscribe((data) => {
|
||||
const newArray = data.results.data.map((item) => ({
|
||||
id: item.id,
|
||||
name: `${item.buildingEntity.name} (${item.roomEntity.name})`,
|
||||
}));
|
||||
this.dataBuildingRoomList = newArray;
|
||||
});
|
||||
}
|
||||
|
||||
formGetDevice(data) {
|
||||
this.projectInfo.patchValue({
|
||||
name: data.data.name,
|
||||
categoryId: data.data.categoryId,
|
||||
voltageId: data.data.voltageId,
|
||||
typeId: data.data.typeId,
|
||||
durationId: data.data.durationId,
|
||||
roomBuildingId: data.data.roomBuildingId,
|
||||
watt: data.data.watt,
|
||||
});
|
||||
if (this.mode === "view") {
|
||||
this.formDisable();
|
||||
}
|
||||
if (this.projectInfo.get("roomBuildingId").value) {
|
||||
this.projectInfo.get("roomBuildingId").disable();
|
||||
}
|
||||
}
|
||||
|
||||
formDisable() {
|
||||
this.projectInfo.get("name").disable();
|
||||
this.projectInfo.get("categoryId").disable();
|
||||
this.projectInfo.get("voltageId").disable();
|
||||
this.projectInfo.get("typeId").disable();
|
||||
this.projectInfo.get("durationId").disable();
|
||||
this.projectInfo.get("roomBuildingId").disable();
|
||||
this.projectInfo.get("watt").disable();
|
||||
}
|
||||
|
||||
setBreadcrumb() {
|
||||
if (this.isAddMode()) {
|
||||
this.breadcrumb = {
|
||||
mainlabel: "Device",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Add new device",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else if (this.isEditMode()) {
|
||||
this.breadcrumb = {
|
||||
mainlabel: "Device",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Edit new device",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else if (this.isViewMode()) {
|
||||
this.breadcrumb = {
|
||||
mainlabel: "Device",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "View new device",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
isEditMode() {
|
||||
return this.mode === "edit";
|
||||
}
|
||||
|
||||
isViewMode() {
|
||||
return this.mode === "view";
|
||||
}
|
||||
|
||||
isAddMode() {
|
||||
return this.mode === "add";
|
||||
}
|
||||
|
||||
get f() {
|
||||
return this.projectInfo.controls;
|
||||
}
|
||||
|
||||
onProjectInfoSubmit() {
|
||||
this.submitted = true;
|
||||
if (this.projectInfo.invalid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
keyPress(event: any) {
|
||||
const pattern = /[0-9\+\-\ ]/;
|
||||
const inputChar = String.fromCharCode(event.charCode);
|
||||
if (event.keyCode !== 8 && !pattern.test(inputChar)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
saveEdit() {
|
||||
if (this.projectInfo.valid) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.router.navigate(["/device"]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
::ng-deep .modal-backdrop.show {
|
||||
z-index: auto !important;
|
||||
}
|
|
@ -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">×</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>
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
: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-color: #252525 !important;
|
||||
padding: 8px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #BEF264;
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
<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="configuration">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div
|
||||
class="card"
|
||||
style="
|
||||
background-color: #fbfbfb !important;
|
||||
box-shadow: none !important;
|
||||
"
|
||||
>
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
class="select-custom"
|
||||
[items]="dataBuildingList"
|
||||
[searchable]="true"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Building"
|
||||
[(ngModel)]="buildingSelected"
|
||||
style="width: 100% !important"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
class="select-custom"
|
||||
[items]="dataMasterCategori"
|
||||
[searchable]="true"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Category"
|
||||
[(ngModel)]="categorySelected"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
class="select-custom"
|
||||
[items]="dataMasterStatus"
|
||||
[searchable]="true"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Status"
|
||||
[(ngModel)]="statusSelected"
|
||||
>
|
||||
</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: #ffffff !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 btn-outline-success ml-2"
|
||||
(click)="doCancelFilter()"
|
||||
style="
|
||||
background-color: #fbfbfb !important;
|
||||
border-color: #6b6b6b !important;
|
||||
color: #6b6b6b;
|
||||
border-radius: 12px;
|
||||
"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="configuration">
|
||||
<div class="row">
|
||||
<div class="col-12" *ngIf="filteredRows?.length === 0">
|
||||
<div
|
||||
class="card"
|
||||
style="
|
||||
background-color: #fbfbfb !important;
|
||||
box-shadow: none !important;
|
||||
"
|
||||
>
|
||||
<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="card"
|
||||
style="background-color: #dde1e6; position: relative"
|
||||
>
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="align-self-center">
|
||||
<div
|
||||
style="
|
||||
background-color: #37a647;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="{{
|
||||
item.category_icon
|
||||
}} font-large-1 blue-grey d-block"
|
||||
style="color: #ffffff !important"
|
||||
></i>
|
||||
</div>
|
||||
<div style="margin-top: 10px">
|
||||
<span class="text-custom-name">{{ item.name }}</span>
|
||||
<br />
|
||||
<span class="text-custom-category">{{
|
||||
item.category_name
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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;
|
||||
"
|
||||
>
|
||||
⋮
|
||||
</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
|
||||
style="border-color: #bef264 !important"
|
||||
class="switchery"
|
||||
switchColor="black"
|
||||
color="rgb(55, 166, 71)"
|
||||
size="small"
|
||||
[checked]="item.status_id === 2"
|
||||
(change)="switchChanged($event, item)"
|
||||
></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DeviceControlComponent } from './device-control.component';
|
||||
|
||||
describe('DeviceControlComponent', () => {
|
||||
let component: DeviceControlComponent;
|
||||
let fixture: ComponentFixture<DeviceControlComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DeviceControlComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DeviceControlComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,213 @@
|
|||
import { Component, HostListener } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { BuildingService } from "../../service/monitoring-api.service";
|
||||
import { DeviceService } from "../../service/device.service";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { LoginService } from "../../service/login.service";
|
||||
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { ControlSchedulerComponent } from "../control-scheduler/control-scheduler.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-device-control",
|
||||
templateUrl: "./device-control.component.html",
|
||||
styleUrls: ["./device-control.component.css"],
|
||||
})
|
||||
export class DeviceControlComponent {
|
||||
data: any;
|
||||
|
||||
filteredRows: any[];
|
||||
filteredDeviceRows: any[];
|
||||
searchTerm: string = "";
|
||||
buildingSelected: any;
|
||||
statusSelected: any;
|
||||
categorySelected: any;
|
||||
dataMasterCategori: any;
|
||||
dataBuildingList: any;
|
||||
dataMasterStatus: any;
|
||||
storedData: any;
|
||||
spinnerFilterActive = false;
|
||||
switchState: boolean;
|
||||
public breadcrumb: any;
|
||||
spinnerActive: boolean = false;
|
||||
singlebasicSelected: any;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private deviceService: DeviceService,
|
||||
private monitoringApiService: BuildingService,
|
||||
private toastr: ToastrService,
|
||||
private authService: LoginService,
|
||||
private modalService: NgbModal,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.breadcrumb = {
|
||||
mainlabel: "Device",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
link: "/dashboard/sales",
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
this.storedData = JSON.parse(localStorage.getItem("currentUser"));
|
||||
this.buildingSelected = this.storedData.buildingId;
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
this.dataListMaster();
|
||||
this.dataListBuilding();
|
||||
}
|
||||
|
||||
fetchData(buildingSelected, categorySelected, statusSelected) {
|
||||
this.deviceService
|
||||
.getDeviceData(buildingSelected, categorySelected, statusSelected)
|
||||
.subscribe((res) => {
|
||||
this.data = res;
|
||||
this.filteredRows = this.data.results.data;
|
||||
this.filteredDeviceRows = this.filterDevices(this.filteredRows);
|
||||
});
|
||||
}
|
||||
|
||||
filterDevices(devices: any[]): any[] {
|
||||
return devices.filter((device) =>
|
||||
device.mapping.some(
|
||||
(map) => map.code.startsWith("switch") && map.type === "Boolean"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
dataListMaster() {
|
||||
this.monitoringApiService.getMasterListData().subscribe((data) => {
|
||||
const dataCategory = data.data.find(
|
||||
(item) => item.name === "master_category"
|
||||
).headerDetailParam;
|
||||
const dataStatus = data.data.find(
|
||||
(item) => item.name === "master_status"
|
||||
).headerDetailParam;
|
||||
this.dataMasterCategori = dataCategory.filter(
|
||||
(item) => item.statusName.toLowerCase() === "aktif"
|
||||
);
|
||||
this.dataMasterStatus = dataStatus.filter((item) => item.statusName.toLowerCase() === "aktif");
|
||||
});
|
||||
}
|
||||
|
||||
dataListBuilding() {
|
||||
this.monitoringApiService.getBuildingList().subscribe((data) => {
|
||||
this.dataBuildingList = data.data.filter((item) => item.statusName.toLowerCase() === "aktif");
|
||||
});
|
||||
}
|
||||
|
||||
doFilter() {
|
||||
if (!this.buildingSelected) {
|
||||
this.toastr.error("Warning", "Filter Building tidak boleh kosong.", {
|
||||
timeOut: 5000,
|
||||
closeButton: true,
|
||||
});
|
||||
} else {
|
||||
this.spinnerFilterActive = true;
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
setTimeout(() => {
|
||||
this.spinnerFilterActive = false;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
doCancelFilter() {
|
||||
this.storedData = JSON.parse(localStorage.getItem("currentUser"));
|
||||
this.buildingSelected = this.storedData.buildingId;
|
||||
this.categorySelected = undefined;
|
||||
this.statusSelected = undefined;
|
||||
this.fetchData(this.buildingSelected, 0, 0);
|
||||
}
|
||||
|
||||
filterRows() {
|
||||
if (!this.searchTerm) {
|
||||
this.filteredRows = [...this.data.results.data];
|
||||
} else {
|
||||
this.filteredRows = this.data.results.data.filter((row) =>
|
||||
this.rowContainsSearchTerm(row)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rowContainsSearchTerm(row: any): boolean {
|
||||
const searchTermLC = this.searchTerm.toLowerCase();
|
||||
return Object.values(row).some(
|
||||
(value) =>
|
||||
value !== null && value.toString().toLowerCase().includes(searchTermLC)
|
||||
);
|
||||
}
|
||||
|
||||
switchChanged(ev, data) {
|
||||
const requestData = {
|
||||
id: data.id,
|
||||
code: data.mapping[0].code,
|
||||
value: ev,
|
||||
command_type: "on_off",
|
||||
};
|
||||
this.deviceService.deviceSwitch(requestData).subscribe((res) => {
|
||||
console.log(res);
|
||||
});
|
||||
}
|
||||
|
||||
toggleMenu(itemId) {
|
||||
this.filteredDeviceRows.forEach(item => {
|
||||
if (item.id === itemId) {
|
||||
item.menuOpen = !item.menuOpen;
|
||||
} else {
|
||||
item.menuOpen = false; // Close other menus
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
: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: #37A647;
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,516 @@
|
|||
<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="configuration">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="card" style="background-color: #DDE1E6 !important; box-shadow: none !important;">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h6 class="text-custom-label">
|
||||
Total Device
|
||||
</h6>
|
||||
<h3 class="text-custom-data">
|
||||
{{ summaryTotal?.length }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<div
|
||||
style="
|
||||
background-color: #37A647;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="ri-device-line primary font-large-1 float-right"
|
||||
style="color: #ffffff !important"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="card" style="background-color: #DDE1E6 !important; box-shadow: none !important;">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h6 class="text-custom-label">
|
||||
Total Device Active
|
||||
</h6>
|
||||
<h3 class="text-custom-data">{{ totalOn }}</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<div
|
||||
style="
|
||||
background-color: #37A647;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="feather ft-wifi primary font-large-1 float-right"
|
||||
style="color: #ffffff !important"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="card" style="background-color: #DDE1E6 !important; box-shadow: none !important;">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h6 class="text-custom-label">
|
||||
Total Device Non-Active
|
||||
</h6>
|
||||
<h3 class="text-custom-data">{{ totalOff }}</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<div
|
||||
style="
|
||||
background-color: #37A647;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="feather ft-wifi-off primary font-large-1 float-right"
|
||||
style="color: #ffffff !important"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="configuration">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card" style="background-color: #FBFBFB !important; box-shadow: none;">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="row mb-2">
|
||||
<div class="col-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
class="select-custom"
|
||||
[items]="dataBuildingList"
|
||||
[searchable]="true"
|
||||
[disabled]="newDeviceActive"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Building"
|
||||
[(ngModel)]="buildingSelected"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
class="select-custom"
|
||||
[items]="dataMasterCategori"
|
||||
[searchable]="true"
|
||||
[disabled]="newDeviceActive"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Category"
|
||||
[(ngModel)]="categorySelected"
|
||||
>
|
||||
</ng-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="form-group">
|
||||
<ng-select
|
||||
class="select-custom"
|
||||
[items]="dataMasterStatus"
|
||||
[searchable]="true"
|
||||
[disabled]="newDeviceActive"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
placeholder="Select Status"
|
||||
[(ngModel)]="statusSelected"
|
||||
>
|
||||
</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 || newDeviceActive"
|
||||
>
|
||||
<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"
|
||||
(click)="doCancelFilter()"
|
||||
style="
|
||||
background-color: #FBFBFB !important;
|
||||
border-color: #242222 !important;
|
||||
color: #242222;
|
||||
border-radius: 12px;
|
||||
"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-6 col-md-3 mb-2">
|
||||
<button
|
||||
class="btn btn-secondary btn-block"
|
||||
[disabled]="spinnerActive"
|
||||
(click)="addDevice()"
|
||||
style="
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="la la-spinner spinner"
|
||||
*ngIf="spinnerActive"
|
||||
></i>
|
||||
<i class="feather ft-plus" *ngIf="!spinnerActive"></i>
|
||||
|
||||
<span style="font-weight: 600">Synchronization</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-6 col-md-3 mb-2">
|
||||
<button
|
||||
class="btn btn-secondary btn-block"
|
||||
[disabled]="spinnerExportActive"
|
||||
(click)="exportDevice()"
|
||||
style="
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="la la-spinner spinner"
|
||||
*ngIf="spinnerExportActive"
|
||||
></i>
|
||||
<i
|
||||
class="ri-export-fill"
|
||||
*ngIf="!spinnerExportActive"
|
||||
></i>
|
||||
|
||||
<span style="font-weight: 600">Export</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-6 col-md-3 mb-2">
|
||||
<button
|
||||
class="btn btn-secondary btn-block"
|
||||
*ngIf="!newDeviceActive"
|
||||
[disabled]="spinnerNewDeviceActive"
|
||||
(click)="newDevice()"
|
||||
style="
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="la la-spinner spinner"
|
||||
*ngIf="spinnerNewDeviceActive"
|
||||
></i>
|
||||
<i
|
||||
class="ri-sticky-note-add-fill"
|
||||
*ngIf="!spinnerNewDeviceActive"
|
||||
></i>
|
||||
|
||||
<span style="font-weight: 600">New Device</span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary btn-block"
|
||||
*ngIf="newDeviceActive"
|
||||
[disabled]="spinnerNewDeviceActive"
|
||||
(click)="allDevice()"
|
||||
style="
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="la la-spinner spinner"
|
||||
*ngIf="spinnerNewDeviceActive"
|
||||
></i>
|
||||
<i
|
||||
class="ri-arrow-left-circle-line"
|
||||
*ngIf="!spinnerNewDeviceActive"
|
||||
></i>
|
||||
|
||||
<span style="font-weight: 600">All Device</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-dashboard">
|
||||
<ngx-datatable
|
||||
class="bootstrap table-bordered"
|
||||
[limit]="5"
|
||||
[rows]="data_device"
|
||||
[columnMode]="'force'"
|
||||
[headerHeight]="50"
|
||||
[footerHeight]="50"
|
||||
[rowHeight]="50"
|
||||
fxFlex="auto"
|
||||
[scrollbarH]="true"
|
||||
>
|
||||
<ngx-datatable-column
|
||||
name="#"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="10"
|
||||
>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-rowIndex="rowIndex"
|
||||
>
|
||||
{{ rowIndex + 1 }}
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="icon"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="20"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Image</span>
|
||||
</ng-template>
|
||||
<ng-template ngx-datatable-cell-template let-row="row">
|
||||
<span class="avatar avatar-sm rounded-circle">
|
||||
<img [src]="row.icon" /><i></i
|
||||
></span>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="Name"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="150"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label"
|
||||
>Device Name</span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
let-value="value"
|
||||
ngx-datatable-cell-template
|
||||
>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="buildingName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label"
|
||||
>Building</span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
let-value="value"
|
||||
ngx-datatable-cell-template
|
||||
>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="categoryName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label"
|
||||
>Category</span
|
||||
>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<p class="style-custom-label">
|
||||
{{ value }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="watt"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Watt</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<p class="style-custom-label">{{ value }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="typeName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Type</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<p class="style-custom-label">
|
||||
{{ value }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column
|
||||
name="voltageName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Voltage</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<p class="style-custom-label">
|
||||
{{ value }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<!-- <ngx-datatable-column
|
||||
name="statusName"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span style="color: #ffffff !important">Status</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<p style="color: #ffffff !important">
|
||||
{{ value }}
|
||||
</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column> -->
|
||||
<ngx-datatable-column
|
||||
name="Actions"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="150"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Actions</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-rowIndex="rowIndex"
|
||||
let-row="row"
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm btn-info mr-1"
|
||||
style="
|
||||
background-color: #DDE1E6 !important;
|
||||
border-color: #37A647 !important;
|
||||
"
|
||||
(click)="viewRow(row)"
|
||||
>
|
||||
<i
|
||||
class="ficon feather ft-eye"
|
||||
style="color: #37A647 !important"
|
||||
></i>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-warning mr-1"
|
||||
style="
|
||||
background-color: #DDE1E6 !important;
|
||||
border-color: #37A647 !important;
|
||||
"
|
||||
(click)="editRow(row)"
|
||||
>
|
||||
<i
|
||||
class="ficon feather ft-edit"
|
||||
style="color: #37A647 !important"
|
||||
></i>
|
||||
</button>
|
||||
<!-- <button
|
||||
class="btn btn-sm btn-danger"
|
||||
(click)="deleteRow(row)"
|
||||
>
|
||||
<i class="ficon feather ft-trash-2"></i>
|
||||
</button> -->
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DeviceComponent } from './device.component';
|
||||
|
||||
describe('DeviceComponent', () => {
|
||||
let component: DeviceComponent;
|
||||
let fixture: ComponentFixture<DeviceComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DeviceComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DeviceComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,303 @@
|
|||
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { TableApiService } from "src/app/_services/table-api.service";
|
||||
import { ModalAddEditComponent } from "./modal-add-edit/modal-add-edit.component";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { BuildingService } from "../service/monitoring-api.service";
|
||||
import { DeviceService } from "../service/device.service";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import * as FileSaver from "file-saver";
|
||||
import * as XLSX from "xlsx";
|
||||
import { TableexcelService } from "src/app/_services/tableexcel.service";
|
||||
import { LoginService } from "../service/login.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-device",
|
||||
templateUrl: "./device.component.html",
|
||||
styleUrls: ["./device.component.css"],
|
||||
})
|
||||
export class DeviceComponent implements OnInit {
|
||||
data: any;
|
||||
totalOn: any;
|
||||
totalOff: any;
|
||||
filteredRows: any[];
|
||||
summaryTotal: any[];
|
||||
searchTerm: string = "";
|
||||
buildingSelected: any;
|
||||
statusSelected: any;
|
||||
categorySelected: any;
|
||||
dataMasterCategori: any;
|
||||
dataBuildingList: any;
|
||||
dataMasterStatus: any;
|
||||
data_device: any;
|
||||
spinnerFilterActive = false;
|
||||
storedData: any;
|
||||
|
||||
rows: any = [];
|
||||
public breadcrumb: any;
|
||||
spinnerActive: boolean = false;
|
||||
spinnerExportActive: boolean = false;
|
||||
spinnerNewDeviceActive: boolean = false;
|
||||
newDeviceActive: boolean = false;
|
||||
|
||||
singlebasicSelected: any;
|
||||
|
||||
constructor(
|
||||
private modalService: NgbModal,
|
||||
private router: Router,
|
||||
private monitoringApiService: BuildingService,
|
||||
private deviceService: DeviceService,
|
||||
private toastr: ToastrService,
|
||||
private tableexcelService: TableexcelService,
|
||||
private authService: LoginService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.breadcrumb = {
|
||||
mainlabel: "Device",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
link: "/dashboard/sales",
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
this.storedData = JSON.parse(localStorage.getItem("currentUser"));
|
||||
this.buildingSelected = this.storedData.buildingId;
|
||||
|
||||
if (this.newDeviceActive === true) {
|
||||
}
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
this.summaryDevice(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
this.dataListMaster();
|
||||
this.dataListBuilding();
|
||||
}
|
||||
|
||||
fetchData(buildingSelected, categorySelected, statusSelected) {
|
||||
this.newDeviceActive = false;
|
||||
this.buildingSelected = buildingSelected;
|
||||
this.deviceService
|
||||
.getDeviceData(buildingSelected, categorySelected, statusSelected)
|
||||
.subscribe((res) => {
|
||||
this.data = res;
|
||||
this.filteredRows = this.data.results.data;
|
||||
this.data_device = this.filteredRows.map((item) => ({
|
||||
buildingName: item.building_name,
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
icon: item.icon,
|
||||
watt: item.watt,
|
||||
categoryName: item.category_name,
|
||||
typeName: item.type_name,
|
||||
voltageName: item.voltage_name,
|
||||
statusName: item.status_name,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
summaryDevice(buildingSelected, categorySelected, statusSelected) {
|
||||
this.deviceService
|
||||
.getDeviceData(buildingSelected, categorySelected, statusSelected)
|
||||
.subscribe((res) => {
|
||||
this.summaryTotal = res.results.data;
|
||||
this.totalOn = res.results.data.filter(
|
||||
(row) => row.status_id === 2
|
||||
).length;
|
||||
this.totalOff = res.results.data.filter(
|
||||
(row) => row.status_id === 3
|
||||
).length;
|
||||
});
|
||||
}
|
||||
|
||||
newDevice() {
|
||||
this.spinnerNewDeviceActive = true;
|
||||
this.newDeviceActive = true;
|
||||
this.deviceService.getDeviceData(0, 0, 0).subscribe((res) => {
|
||||
this.data = res;
|
||||
this.filteredRows = this.data.results.data;
|
||||
this.spinnerNewDeviceActive = false;
|
||||
this.data_device = this.filteredRows.map((item) => ({
|
||||
buildingName: item.building_name,
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
icon: item.icon,
|
||||
watt: item.watt,
|
||||
categoryName: item.category_name,
|
||||
typeName: item.type_name,
|
||||
voltageName: item.voltage_name,
|
||||
statusName: item.status_name,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
allDevice() {
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
}
|
||||
|
||||
dataListMaster() {
|
||||
this.monitoringApiService.getMasterListData().subscribe((data) => {
|
||||
const dataCategory = data.data.find(
|
||||
(item) => item.name === "master_category"
|
||||
).headerDetailParam;
|
||||
const dataStatus = data.data.find(
|
||||
(item) => item.name === "master_status"
|
||||
).headerDetailParam;
|
||||
this.dataMasterCategori = dataCategory.filter(
|
||||
(item) => item.statusName.toLowerCase() === "aktif"
|
||||
);
|
||||
this.dataMasterStatus = dataStatus.filter((item) => item.statusName.toLowerCase() === "aktif");
|
||||
});
|
||||
}
|
||||
|
||||
dataListBuilding() {
|
||||
this.monitoringApiService.getBuildingList().subscribe((data) => {
|
||||
this.dataBuildingList = data.data.filter((item) => item.statusName.toLowerCase() === "aktif");
|
||||
});
|
||||
}
|
||||
|
||||
doFilter() {
|
||||
if (!this.buildingSelected) {
|
||||
this.toastr.error("Warning", "Filter Building tidak boleh kosong.", {
|
||||
timeOut: 5000,
|
||||
closeButton: true,
|
||||
});
|
||||
} else {
|
||||
this.spinnerFilterActive = true;
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
setTimeout(() => {
|
||||
this.spinnerFilterActive = false;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
doCancelFilter() {
|
||||
this.storedData = JSON.parse(localStorage.getItem("currentUser"));
|
||||
this.buildingSelected = this.storedData.buildingId;
|
||||
this.categorySelected = undefined;
|
||||
this.statusSelected = undefined;
|
||||
this.fetchData(this.buildingSelected, 0, 0);
|
||||
}
|
||||
|
||||
filterRows() {
|
||||
if (!this.searchTerm) {
|
||||
this.filteredRows = [...this.data.results.data];
|
||||
} else {
|
||||
this.filteredRows = this.data.results.data.filter((row) =>
|
||||
this.rowContainsSearchTerm(row)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rowContainsSearchTerm(row: any): boolean {
|
||||
const searchTermLC = this.searchTerm.toLowerCase();
|
||||
return Object.values(row).some(
|
||||
(value) =>
|
||||
value !== null && value.toString().toLowerCase().includes(searchTermLC)
|
||||
);
|
||||
}
|
||||
|
||||
addFieldValue() {
|
||||
const modalRef = this.modalService.open(ModalAddEditComponent, {
|
||||
size: "lg",
|
||||
});
|
||||
modalRef.componentInstance.newAttribute = {
|
||||
id: null,
|
||||
name: "",
|
||||
position: "",
|
||||
office: "",
|
||||
age: "",
|
||||
salary: "",
|
||||
startdate: "",
|
||||
};
|
||||
|
||||
modalRef.result.then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.rows.push(result);
|
||||
this.rows = [...this.rows];
|
||||
}
|
||||
},
|
||||
(reason) => {
|
||||
console.log(`Dismissed: ${reason}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
viewRow(row) {
|
||||
this.router.navigate(["/device/view", row.id]);
|
||||
}
|
||||
|
||||
editRow(row) {
|
||||
this.router.navigate(["/device/edit", row.id]);
|
||||
}
|
||||
|
||||
deleteRow(row) {
|
||||
console.log("Delete row:", row);
|
||||
}
|
||||
|
||||
addDevice(): void {
|
||||
// Aktifkan spinner
|
||||
this.spinnerActive = true;
|
||||
this.deviceService.getSyncDeviceData().subscribe((res) => {
|
||||
console.log(res);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.spinnerActive = false;
|
||||
this.toastr.success("Success", "Sync Completed.", {
|
||||
timeOut: 2000,
|
||||
closeButton: true,
|
||||
});
|
||||
this.fetchData(
|
||||
this.buildingSelected,
|
||||
this.categorySelected,
|
||||
this.statusSelected
|
||||
);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
exportDevice() {
|
||||
this.spinnerExportActive = true;
|
||||
setTimeout(() => {
|
||||
const columnsToExport = [
|
||||
"name",
|
||||
"building_name",
|
||||
"room_name",
|
||||
"watt",
|
||||
"category_name",
|
||||
"status_name",
|
||||
"type_name",
|
||||
"voltage_name",
|
||||
];
|
||||
this.tableexcelService.exportAsExcelFileDevice(
|
||||
this.filteredRows,
|
||||
"Smart_building_list_device",
|
||||
columnsToExport
|
||||
);
|
||||
this.spinnerExportActive = false;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DeviceComponent } from './device.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ClipboardModule } from 'ngx-clipboard';
|
||||
import { CardModule } from '../../partials/general/card/card.module';
|
||||
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { BlockTemplateComponent } from '../../../_layout/blockui/block-template.component';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
import { AddEditDeviceComponent } from './add-edit-device/add-edit-device.component';
|
||||
import { ModalAddEditComponent } from './modal-add-edit/modal-add-edit.component';
|
||||
import { DeviceControlComponent } from './device-control/device-control.component';
|
||||
import { UiSwitchModule } from 'ngx-ui-switch';
|
||||
import { ControlSchedulerComponent } from './control-scheduler/control-scheduler.component';
|
||||
import { SchedulerListComponent } from './scheduler-list/scheduler-list.component';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
DeviceComponent,
|
||||
AddEditDeviceComponent,
|
||||
ModalAddEditComponent,
|
||||
DeviceControlComponent,
|
||||
ControlSchedulerComponent,
|
||||
SchedulerListComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
BreadcrumbModule,
|
||||
NgSelectModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
ClipboardModule,
|
||||
PerfectScrollbarModule,
|
||||
UiSwitchModule,
|
||||
NgxDatatableModule,
|
||||
BlockUIModule.forRoot({
|
||||
template: BlockTemplateComponent
|
||||
}),
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: DeviceComponent
|
||||
},
|
||||
{
|
||||
path: 'control-device',
|
||||
component: DeviceControlComponent,
|
||||
},
|
||||
{
|
||||
path: 'add-row',
|
||||
component: AddEditDeviceComponent,
|
||||
data: { mode: 'add' }
|
||||
},
|
||||
{
|
||||
path: 'edit/:id',
|
||||
component: AddEditDeviceComponent,
|
||||
data: { mode: 'edit' }
|
||||
},
|
||||
{
|
||||
path: 'view/:id',
|
||||
component: AddEditDeviceComponent,
|
||||
data: { mode: 'view' }
|
||||
},
|
||||
{
|
||||
path: 'scheduler/:id',
|
||||
component: SchedulerListComponent,
|
||||
data: { mode: 'scheduler' }
|
||||
}
|
||||
]),
|
||||
|
||||
|
||||
]
|
||||
})
|
||||
export class DeviceModule { }
|
|
@ -0,0 +1,55 @@
|
|||
/* modal-add-edit.component.css */
|
||||
::ng-deep .modal-backdrop.show {
|
||||
z-index: auto !important;
|
||||
}
|
||||
|
||||
::ng-deep .input-group-append .btn {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
flex-grow: 0;
|
||||
border-left: 1px solid #ced4da;
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group {
|
||||
display: flex;
|
||||
flex-wrap: nowrap; /* Prevents wrapping of the items */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::ng-deep .form-control {
|
||||
flex-grow: 1; /* Ensures select takes up available space */
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group select,
|
||||
::ng-deep .input-group .input-group-append .btn {
|
||||
padding-right: 5px; /* Adjust padding if necessary */
|
||||
}
|
||||
|
||||
::ng-deep .input-group .form-control {
|
||||
margin-right: 2px; /* Adjust margin to make space */
|
||||
}
|
||||
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<div class="modal-header">
|
||||
<h4 class="modal-title">Add New Row</h4>
|
||||
<button type="button" class="close" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form [formGroup]="myForm">
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" class="form-control" id="name" formControlName="name">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="position">Position:</label>
|
||||
<input type="text" class="form-control" id="position" formControlName="position">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="age">Age:</label>
|
||||
<input type="number" class="form-control" id="age" formControlName="age">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="department">Department:</label>
|
||||
<div class="input-group">
|
||||
<select class="form-control" formControlName="department">
|
||||
<option>IT</option>
|
||||
<option>HR</option>
|
||||
<option>Finance</option>
|
||||
</select>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="button" (click)="addDepartment()">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" (click)="activeModal.dismiss('Cross click')">Close</button>
|
||||
<button type="button" class="btn btn-primary" (click)="addRow()">Save Changes</button>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ModalAddEditComponent } from './modal-add-edit.component';
|
||||
|
||||
describe('ModalAddEditComponent', () => {
|
||||
let component: ModalAddEditComponent;
|
||||
let fixture: ComponentFixture<ModalAddEditComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ModalAddEditComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ModalAddEditComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
import { Component, Input } from "@angular/core";
|
||||
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: "app-modal-add-edit",
|
||||
templateUrl: "./modal-add-edit.component.html",
|
||||
styleUrls: ["./modal-add-edit.component.css"],
|
||||
})
|
||||
export class ModalAddEditComponent {
|
||||
@Input() newAttribute: any = {};
|
||||
myForm: FormGroup;
|
||||
|
||||
constructor(public activeModal: NgbActiveModal, private fb: FormBuilder) {
|
||||
this.createForm();
|
||||
}
|
||||
|
||||
createForm() {
|
||||
this.myForm = this.fb.group({
|
||||
name: ['', Validators.required],
|
||||
position: ['', Validators.required],
|
||||
age: [null, [Validators.required, Validators.min(18)]],
|
||||
department: ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
addRow() {
|
||||
if (this.myForm.valid) {
|
||||
this.activeModal.close(this.myForm.value);
|
||||
}
|
||||
}
|
||||
|
||||
addDepartment() {
|
||||
// Example function to simulate adding a department
|
||||
let newDept = prompt("Enter new department name:");
|
||||
if (newDept) {
|
||||
// Normally you would add to a database or a service
|
||||
alert(`Department ${newDept} added! (simulated)`);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
<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-12" *blockUI="'projectInfo'; message: 'Loading'">
|
||||
<div class="card" style="background-color: #fbfbfb !important">
|
||||
<div class="card-content">
|
||||
<div
|
||||
class="card-header"
|
||||
style="background-color: #fbfbfb !important"
|
||||
>
|
||||
<h2 style="color: #242222">
|
||||
{{
|
||||
isEditMode()
|
||||
? "Edit List Monitoring"
|
||||
: isViewMode()
|
||||
? "View List Monitoring"
|
||||
: "Add New List Monitoring"
|
||||
}}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form
|
||||
[formGroup]="projectInfo"
|
||||
(ngSubmit)="onProjectInfoSubmit()"
|
||||
>
|
||||
<div class="form-body">
|
||||
<!-- <h4 class="form-section" style="color: #242222">
|
||||
<i class="feather ft-user" style="color: #242222"></i>
|
||||
General Information
|
||||
</h4> -->
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="buildingId" style="color: #242222"
|
||||
>Building *</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<select
|
||||
id="buildingId"
|
||||
class="form-control"
|
||||
formControlName="buildingId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.buildingId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataBuildingList"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</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>
|
||||
<div class="form-group">
|
||||
<label for="floorId" style="color: #242222"
|
||||
>Floor *</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<select
|
||||
id="floorId"
|
||||
class="form-control"
|
||||
formControlName="floorId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.floorId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataFloorList"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group" *ngIf="mode === 'add'">
|
||||
<div class="" formArrayName="userArray">
|
||||
<div
|
||||
class=""
|
||||
*ngFor="
|
||||
let userForm of userFormGroup.controls;
|
||||
let i = index
|
||||
"
|
||||
>
|
||||
<div [formGroupName]="i" class="">
|
||||
<div class="input-group mb-1">
|
||||
<select
|
||||
id="roomId{{i}}"
|
||||
class="form-control"
|
||||
formControlName="roomId"
|
||||
(change)="validateDouble($event, i)"
|
||||
[ngClass]="{
|
||||
'is-invalid':
|
||||
submitted && f.roomId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let list of dataRoomList; trackBy: trackByFn"
|
||||
[value]="list.id"
|
||||
>
|
||||
{{ list.name }}
|
||||
</option>
|
||||
</select>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
style="
|
||||
color: #ffffff !important;
|
||||
border-color: #a64f37 !important;
|
||||
background-color: #a64f37 !important;
|
||||
"
|
||||
(click)="removePhone(i)"
|
||||
>
|
||||
<i class="feather ft-x"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
[disabled]="disableButton"
|
||||
style="
|
||||
color: #ffffff !important;
|
||||
border-color: #37a647 !important;
|
||||
background-color: #37a647 !important;
|
||||
"
|
||||
(click)="addPhone()"
|
||||
>
|
||||
<i class="feather ft-plus"></i> Add Room
|
||||
</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 class="form-group" *ngIf="mode !== 'add'">
|
||||
<label for="roomId">Room *</label>
|
||||
<div class="input-group">
|
||||
<select
|
||||
id="roomId"
|
||||
class="form-control"
|
||||
formControlName="roomId"
|
||||
[ngClass]="{
|
||||
'is-invalid': submitted && f.roomId.errors
|
||||
}"
|
||||
>
|
||||
<option
|
||||
*ngFor="let data of dataRoomList"
|
||||
[value]="data.id"
|
||||
>
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<small
|
||||
class="form-text text-muted danger"
|
||||
*ngIf="submitted && f.roomId.errors"
|
||||
class="invalid-feedback"
|
||||
>
|
||||
<div *ngIf="f.roomId.errors.required">
|
||||
Status is required
|
||||
</div>
|
||||
</small>
|
||||
</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 class="form-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning mr-1"
|
||||
style="
|
||||
color: #242222 !important;
|
||||
border-color: #242222 !important;
|
||||
background-color: #fbfbfb !important;
|
||||
"
|
||||
(click)="cancel()"
|
||||
>
|
||||
<i class="feather ft-x"></i> Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
[disabled]="disableButtonSave"
|
||||
style="
|
||||
color: #ffffff !important;
|
||||
border-color: #37a647 !important;
|
||||
background-color: #37a647 !important;
|
||||
"
|
||||
(click)="save()"
|
||||
>
|
||||
<i class="la la-check"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AddEditListComponent } from './add-edit-list.component';
|
||||
|
||||
describe('AddEditListComponent', () => {
|
||||
let component: AddEditListComponent;
|
||||
let fixture: ComponentFixture<AddEditListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ AddEditListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AddEditListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,465 @@
|
|||
import { Component, ViewChild } from "@angular/core";
|
||||
import {
|
||||
FormArray,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
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({
|
||||
selector: "app-add-edit-list",
|
||||
templateUrl: "./add-edit-list.component.html",
|
||||
styleUrls: ["./add-edit-list.component.css"],
|
||||
})
|
||||
export class AddEditListComponent {
|
||||
// @ViewChild("f", { read: true }) userProfileForm: NgForm;
|
||||
|
||||
model: any = {};
|
||||
mode: string;
|
||||
public breadcrumb: any;
|
||||
projectInfo: FormGroup;
|
||||
submitted = false;
|
||||
|
||||
dataBuildingList: any;
|
||||
dataRoomList: any;
|
||||
dataRoomListSementara: any;
|
||||
dataFloorList: any;
|
||||
dataMasterStatus: any;
|
||||
roombuildingId: any;
|
||||
dataRoomBuilding: any;
|
||||
disableButton: boolean = true;
|
||||
disableButtonSave: boolean = true;
|
||||
lewatModal: boolean = false;
|
||||
// userProfileForm: FormGroup;
|
||||
public userList: FormArray;
|
||||
|
||||
@BlockUI("projectInfo") blockUIProjectInfo: NgBlockUI;
|
||||
get userFormGroup() {
|
||||
return this.projectInfo.get("userArray") as FormArray;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private monitoringApiService: BuildingService,
|
||||
private authService: LoginService,
|
||||
private toastr: ToastrService,
|
||||
private modalService: NgbModal
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.route.data.subscribe((data) => {
|
||||
this.mode = data.mode;
|
||||
});
|
||||
this.route.params.subscribe((params) => {
|
||||
const id = params["id"];
|
||||
this.roombuildingId = id;
|
||||
if (id) {
|
||||
this.loadRoomBuilding(id);
|
||||
}
|
||||
});
|
||||
this.setBreadcrumb();
|
||||
|
||||
|
||||
this.projectInfo = this.formBuilder.group({
|
||||
buildingId: ["", Validators.required],
|
||||
roomId: [""],
|
||||
statusId: ["", Validators.required],
|
||||
floorId: ["", Validators.required],
|
||||
userArray: this.formBuilder.array([this.createRoom()]),
|
||||
});
|
||||
this.userList = this.projectInfo.get("userArray") as FormArray;
|
||||
|
||||
this.dataListBuilding();
|
||||
this.dataListRoom();
|
||||
this.dataListMaster();
|
||||
this.dataListFloor();
|
||||
}
|
||||
|
||||
createRoom(): FormGroup {
|
||||
return this.formBuilder.group({
|
||||
roomId: ["", Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
addPhone() {
|
||||
this.userList.push(this.createRoom());
|
||||
this.disableButton = true;
|
||||
this.disableButtonSave = true;
|
||||
}
|
||||
|
||||
removePhone(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() {
|
||||
if (this.isAddMode()) {
|
||||
this.breadcrumb = {
|
||||
mainlabel: "List Monitoring",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "List Monitoring",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Add New List Monitoring",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else if (this.isEditMode()) {
|
||||
this.breadcrumb = {
|
||||
mainlabel: "List Monitoring",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "List Monitoring",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "Edit New List Monitoring",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
loadRoomBuilding(deviceId: string) {
|
||||
this.monitoringApiService
|
||||
.getRoomBuildingById(deviceId)
|
||||
.subscribe((data) => {
|
||||
this.dataRoomBuilding = data;
|
||||
this.formGetDevice(data);
|
||||
});
|
||||
}
|
||||
|
||||
formGetDevice(data) {
|
||||
this.projectInfo.patchValue({
|
||||
buildingId: data.data.buildingId,
|
||||
roomId: data.data.roomId,
|
||||
floorId: data.data.floorId,
|
||||
statusId: data.data.statusId,
|
||||
});
|
||||
|
||||
if (this.mode === "view") {
|
||||
this.formDisable();
|
||||
}
|
||||
}
|
||||
|
||||
formDisable() {
|
||||
this.projectInfo.get("buildingId").disable();
|
||||
this.projectInfo.get("roomId").disable();
|
||||
this.projectInfo.get("statusId").disable();
|
||||
}
|
||||
|
||||
isEditMode() {
|
||||
return this.mode === "edit";
|
||||
}
|
||||
|
||||
isViewMode() {
|
||||
return this.mode === "view";
|
||||
}
|
||||
|
||||
isAddMode() {
|
||||
return this.mode === "add";
|
||||
}
|
||||
|
||||
get f() {
|
||||
return this.projectInfo.controls;
|
||||
}
|
||||
|
||||
onProjectInfoSubmit() {
|
||||
this.submitted = true;
|
||||
if (this.projectInfo.invalid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
keyPress(event: any) {
|
||||
const pattern = /[0-9\+\-\ ]/;
|
||||
const inputChar = String.fromCharCode(event.charCode);
|
||||
if (event.keyCode !== 8 && !pattern.test(inputChar)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
dataListBuilding() {
|
||||
this.monitoringApiService.getBuildingList().subscribe((data) => {
|
||||
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() {
|
||||
this.monitoringApiService.getListRoomDataUnmap().subscribe((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() {
|
||||
this.monitoringApiService.getMasterListData().subscribe((data) => {
|
||||
const dataStatus = data.data.find(
|
||||
(item) => item.name === "master_status"
|
||||
).headerDetailParam;
|
||||
this.dataMasterStatus = dataStatus.filter(
|
||||
(item) =>
|
||||
item.statusName.toLowerCase() === "aktif" ||
|
||||
item.status.toLowerCase() === "71"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.mode === "add") {
|
||||
if (this.projectInfo.invalid) {
|
||||
this.markFormGroupTouched(this.projectInfo)
|
||||
return;
|
||||
}
|
||||
const formData = this.projectInfo.value;
|
||||
const transformedData = {
|
||||
buildingId: formData.buildingId,
|
||||
roomId: formData.userArray.map((room) => room.roomId),
|
||||
statusId: formData.statusId,
|
||||
floorId: formData.floorId,
|
||||
};
|
||||
this.monitoringApiService
|
||||
.postBatchBuilding(transformedData)
|
||||
.subscribe((res) => {
|
||||
this.router.navigate(["/list-monitoring"]);
|
||||
});
|
||||
} else {
|
||||
delete this.projectInfo.value.userArray;
|
||||
this.monitoringApiService
|
||||
.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() {
|
||||
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}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
: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: #37A647;
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
<div class="app-content content" style="background-color: #FBFBFB !important">
|
||||
<div class="content-wrapper" style="height: 900px !important;">
|
||||
<div class="content-header row mb-1">
|
||||
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
|
||||
</div>
|
||||
<div class="content-body">
|
||||
<section id="configuration">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card" style="background-color: #FBFBFB !important">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-6">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Search..."
|
||||
[(ngModel)]="searchTerm"
|
||||
(input)="filterRows()"
|
||||
(touchstart)="onTouchStart($event)"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6 text-right">
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
[routerLink]="['/list-monitoring/add-row']"
|
||||
style="
|
||||
background-color: #37A647 !important;
|
||||
border-color: #37A647 !important;
|
||||
color: #ffffff !important;
|
||||
"
|
||||
>
|
||||
<i class="feather ft-plus" style="color: #ffffff"></i
|
||||
>
|
||||
<span style="font-weight: 600">Add new data</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-dashboard">
|
||||
<ngx-datatable
|
||||
class="bootstrap table-bordered"
|
||||
[limit]="10"
|
||||
[rows]="filteredRows"
|
||||
[columnMode]="'force'"
|
||||
[headerHeight]="50"
|
||||
[footerHeight]="50"
|
||||
[rowHeight]="50"
|
||||
fxFlex="auto"
|
||||
[scrollbarH]="true"
|
||||
>
|
||||
<ngx-datatable-column
|
||||
name="#"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="10"
|
||||
>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-rowIndex="rowIndex"
|
||||
>
|
||||
<p class="style-custom-label">{{ rowIndex + 1 }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
|
||||
<ngx-datatable-column
|
||||
name="buildingEntity"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Building</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
let-value="value"
|
||||
ngx-datatable-cell-template
|
||||
>
|
||||
<p class="style-custom-label">{{ value.name }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
|
||||
<ngx-datatable-column
|
||||
name="roomEntity"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Room</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<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>
|
||||
</ngx-datatable-column>
|
||||
|
||||
<ngx-datatable-column
|
||||
name="statusEntity"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="90"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Status</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-value="value"
|
||||
>
|
||||
<p class="style-custom-label">{{ value.name }}</p>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
|
||||
<ngx-datatable-column
|
||||
name="Actions"
|
||||
[flexGrow]="1"
|
||||
[minWidth]="150"
|
||||
>
|
||||
<ng-template ngx-datatable-header-template>
|
||||
<span class="style-custom-label">Actions</span>
|
||||
</ng-template>
|
||||
<ng-template
|
||||
ngx-datatable-cell-template
|
||||
let-rowIndex="rowIndex"
|
||||
let-row="row"
|
||||
>
|
||||
<!-- <button
|
||||
class="btn btn-sm btn-warning mr-1"
|
||||
style="background-color: #FBFBFB !important; border-color: #37A647 !important;"
|
||||
(click)="editRow(row)"
|
||||
>
|
||||
<i class="ficon feather ft-edit" style="color: #37A647 !important;"></i>
|
||||
</button> -->
|
||||
<button
|
||||
class="btn btn-sm btn-danger"
|
||||
style="
|
||||
color: #37a647 !important;
|
||||
border-color: #DDE1E6 !important;
|
||||
background-color: #DDE1E6 !important;
|
||||
"
|
||||
(click)="deleteRow(row)"
|
||||
>
|
||||
<i class="ficon feather ft-trash-2" style="color: #37A647 !important;"></i>
|
||||
</button>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ListMonitoringComponent } from './list-monitoring.component';
|
||||
|
||||
describe('ListMonitoringComponent', () => {
|
||||
let component: ListMonitoringComponent;
|
||||
let fixture: ComponentFixture<ListMonitoringComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ListMonitoringComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ListMonitoringComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
import { Component } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { TableApiService } from "src/app/_services/table-api.service";
|
||||
import { BuildingService } from "../service/monitoring-api.service";
|
||||
import Swal from "sweetalert2";
|
||||
import { LoginService } from "../service/login.service";
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
|
||||
@Component({
|
||||
selector: "app-list-monitoring",
|
||||
templateUrl: "./list-monitoring.component.html",
|
||||
styleUrls: ["./list-monitoring.component.css"],
|
||||
})
|
||||
export class ListMonitoringComponent {
|
||||
public breadcrumb: any;
|
||||
data: any;
|
||||
filteredRows: any[];
|
||||
searchTerm: string = "";
|
||||
rows: any = [];
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private monitoringApiService: BuildingService,
|
||||
private authService: LoginService,
|
||||
private toastr: ToastrService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.breadcrumb = {
|
||||
mainlabel: "List Monitoring",
|
||||
links: [
|
||||
{
|
||||
name: "Home",
|
||||
isLink: false,
|
||||
},
|
||||
{
|
||||
name: "List Monitoring",
|
||||
isLink: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
fetchData() {
|
||||
this.monitoringApiService.getBuildingRoomList().subscribe((res) => {
|
||||
this.data = res;
|
||||
// this.filteredRows = this.data.results.data;
|
||||
this.filteredRows = this.data.results.data.sort((a, b) => b.id - a.id);
|
||||
});
|
||||
}
|
||||
|
||||
filterRows() {
|
||||
if (!this.searchTerm) {
|
||||
this.filteredRows = [...this.data.results.data];
|
||||
} else {
|
||||
const searchTermLC = this.searchTerm.toLowerCase();
|
||||
this.filteredRows = this.data.results.data.filter((row) =>
|
||||
this.rowContainsSearchTerm(row, searchTermLC)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rowContainsSearchTerm(row: any, searchTermLC: string): boolean {
|
||||
return (
|
||||
row.buildingEntity.name.toLowerCase().includes(searchTermLC) ||
|
||||
row.roomEntity.name.toLowerCase().includes(searchTermLC) ||
|
||||
row.statusEntity.name.toLowerCase().includes(searchTermLC) ||
|
||||
row.floorEntity?.name.toLowerCase().includes(searchTermLC)
|
||||
);
|
||||
}
|
||||
|
||||
viewRow(row) {
|
||||
this.router.navigate(["/list-monitoring/view", row.id]);
|
||||
}
|
||||
|
||||
editRow(row) {
|
||||
this.router.navigate(["/list-monitoring/edit", row.id]);
|
||||
}
|
||||
|
||||
deleteRow(row) {
|
||||
const confirmDelete = confirm("Are you sure you want to delete this item?");
|
||||
if (confirmDelete) {
|
||||
this.monitoringApiService.deleteRoomBuilding(row.id).subscribe(
|
||||
(res) => {
|
||||
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,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onTouchStart(event: Event) {
|
||||
event.preventDefault(); // Add this if necessary
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ClipboardModule } from 'ngx-clipboard';
|
||||
import { CardModule } from '../../partials/general/card/card.module';
|
||||
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { BlockTemplateComponent } from '../../../_layout/blockui/block-template.component';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
import { ListMonitoringComponent } from './list-monitoring.component';
|
||||
import { AddEditListComponent } from './add-edit-list/add-edit-list.component';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ListMonitoringComponent,
|
||||
AddEditListComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardModule,
|
||||
BreadcrumbModule,
|
||||
NgSelectModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
ClipboardModule,
|
||||
PerfectScrollbarModule,
|
||||
NgxDatatableModule,
|
||||
BlockUIModule.forRoot({
|
||||
template: BlockTemplateComponent
|
||||
}),
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: ListMonitoringComponent
|
||||
},
|
||||
{
|
||||
path: 'add-row',
|
||||
component: AddEditListComponent,
|
||||
data: { mode: 'add' }
|
||||
},
|
||||
{
|
||||
path: 'edit/:id',
|
||||
component: AddEditListComponent,
|
||||
data: { mode: 'edit' }
|
||||
},
|
||||
{
|
||||
path: 'view/:id',
|
||||
component: AddEditListComponent,
|
||||
data: { mode: 'view' }
|
||||
}
|
||||
])
|
||||
]
|
||||
})
|
||||
export class ListMonitoringModule { }
|
|
@ -0,0 +1,54 @@
|
|||
/* modal-add-edit.component.css */
|
||||
::ng-deep .modal-backdrop.show {
|
||||
z-index: auto !important;
|
||||
}
|
||||
/*
|
||||
::ng-deep .input-group-append .btn {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
flex-grow: 0;
|
||||
border-left: 1px solid #ced4da;
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::ng-deep .form-control {
|
||||
flex-grow: 1;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group select,
|
||||
::ng-deep .input-group .input-group-append .btn {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
::ng-deep .input-group .form-control {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
} */
|
|
@ -0,0 +1,79 @@
|
|||
<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">×</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-6">
|
||||
<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-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">
|
||||
<label for="icon" style="color: #242222">Icon:</label>
|
||||
<app-select-icon [selectedIcon]="selectedIcon" (iconSelected)="onIconSelected($event)"></app-select-icon>
|
||||
<div *ngIf="myForm.get('icon').touched && myForm.get('icon').invalid" class="text-danger">
|
||||
Icon is required.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="status" style="color: #242222">Status:</label>
|
||||
<select
|
||||
id="projectinput5"
|
||||
class="form-control custom-select"
|
||||
formControlName="status"
|
||||
>
|
||||
<option *ngFor="let data of dataMasterStatus" [value]="data.id">
|
||||
{{ data.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div *ngIf="myForm.get('status').touched && myForm.get('status').invalid" class="text-danger">
|
||||
Status 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)="addRow()"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AddEditMasterComponent } from './add-edit-master.component';
|
||||
|
||||
describe('AddEditMasterComponent', () => {
|
||||
let component: AddEditMasterComponent;
|
||||
let fixture: ComponentFixture<AddEditMasterComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ AddEditMasterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AddEditMasterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,127 @@
|
|||
import { Component, Input, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { BuildingService } from "../../service/monitoring-api.service";
|
||||
import { LoginService } from "../../service/login.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-add-edit-master",
|
||||
templateUrl: "./add-edit-master.component.html",
|
||||
styleUrls: ["./add-edit-master.component.css"],
|
||||
})
|
||||
export class AddEditMasterComponent implements OnInit {
|
||||
@Input() headerId: number;
|
||||
@Input() dataRow: any;
|
||||
@Input() mode: any;
|
||||
@Input() category: boolean = false;
|
||||
@Input() floor: boolean = false;
|
||||
myForm: FormGroup;
|
||||
dataMasterStatus: any;
|
||||
selectedIcon: string = '';
|
||||
labelModal: string = '';
|
||||
|
||||
constructor(
|
||||
public activeModal: NgbActiveModal,
|
||||
private fb: FormBuilder,
|
||||
private monitoringApiService: BuildingService,
|
||||
private authService: LoginService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.startTokenCheck();
|
||||
this.authService.startTrackingActivity();
|
||||
this.createForm();
|
||||
this.dataListMaster();
|
||||
if (this.mode === "add") {
|
||||
this.labelModal = "Add Row"
|
||||
} else {
|
||||
this.labelModal = "Edit Row"
|
||||
}
|
||||
|
||||
if (this.dataRow) {
|
||||
this.editForm();
|
||||
}
|
||||
}
|
||||
|
||||
createForm() {
|
||||
const formControls = {
|
||||
name: ["", Validators.required],
|
||||
status: ["", Validators.required],
|
||||
headerId: this.headerId
|
||||
};
|
||||
|
||||
if (this.category) {
|
||||
formControls['icon'] = [undefined, Validators.required];
|
||||
}
|
||||
|
||||
if (this.floor) {
|
||||
formControls['code'] = ['', Validators.required];
|
||||
}
|
||||
|
||||
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() {
|
||||
const formControls = {
|
||||
id: this.dataRow.id,
|
||||
name: [this.dataRow.name, Validators.required],
|
||||
status: [this.dataRow.status, Validators.required],
|
||||
headerId: this.dataRow.header_id,
|
||||
};
|
||||
|
||||
if (this.category) {
|
||||
formControls['icon'] = [this.dataRow.icon || undefined , Validators.required];
|
||||
this.selectedIcon = this.dataRow.icon || undefined;
|
||||
}
|
||||
|
||||
if (this.floor) {
|
||||
formControls['code'] = [this.dataRow.code || '' , Validators.required];
|
||||
}
|
||||
this.myForm = this.fb.group(formControls);
|
||||
}
|
||||
|
||||
dataListMaster() {
|
||||
this.monitoringApiService.getMasterListData().subscribe((data) => {
|
||||
const dataCategory = data.data.find(
|
||||
(item) => item.name === "master_status"
|
||||
).headerDetailParam;
|
||||
this.dataMasterStatus = dataCategory.filter(item => item.statusName.toLowerCase() === "aktif" || item.status.toLowerCase() === "71" || item.status.toLowerCase() === "71");
|
||||
});
|
||||
}
|
||||
|
||||
addRow() {
|
||||
if (this.myForm.valid) {
|
||||
this.activeModal.close(this.myForm.value);
|
||||
} else {
|
||||
this.markFormGroupTouched(this.myForm)
|
||||
}
|
||||
}
|
||||
|
||||
markFormGroupTouched(formGroup: FormGroup) {
|
||||
(Object as any).values(formGroup.controls).forEach((control) => {
|
||||
control.markAsTouched();
|
||||
if (control.controls) {
|
||||
this.markFormGroupTouched(control);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addDepartment() {
|
||||
let newDept = prompt("Enter new department name:");
|
||||
if (newDept) {
|
||||
alert(`Department ${newDept} added! (simulated)`);
|
||||
}
|
||||
}
|
||||
|
||||
onIconSelected(icon: string): void {
|
||||
this.selectedIcon = icon;
|
||||
this.myForm.get('icon').setValue(icon); // Set nilai icon ke dalam form
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* modal-add-edit.component.css */
|
||||
::ng-deep .modal-backdrop.show {
|
||||
z-index: auto !important;
|
||||
}
|
||||
|
||||
::ng-deep .input-group-append .btn {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
flex-grow: 0;
|
||||
border-left: 1px solid #ced4da;
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group {
|
||||
display: flex;
|
||||
flex-wrap: nowrap; /* Prevents wrapping of the items */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::ng-deep .form-control {
|
||||
flex-grow: 1; /* Ensures select takes up available space */
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
::ng-deep .input-group select,
|
||||
::ng-deep .input-group .input-group-append .btn {
|
||||
padding-right: 5px; /* Adjust padding if necessary */
|
||||
}
|
||||
|
||||
::ng-deep .input-group .form-control {
|
||||
margin-right: 2px; /* Adjust margin to make space */
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 0.25rem;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
::ng-deep .no-arrow::-webkit-inner-spin-button,
|
||||
.no-arrow::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
::ng-deep .no-arrow {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
/* Add this CSS to style invalid form controls */
|
||||
.is-invalid {
|
||||
border-color: #dc3545;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #dc3545;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue