فهرست منبع

Modified asset chart viewer, added validations, assets endpoints, added terms & conditions page

Oscar José Nuñez Chávez 6 سال پیش
والد
کامیت
fa25f5343a
28فایلهای تغییر یافته به همراه708 افزوده شده و 214 حذف شده
  1. 20 10
      package-lock.json
  2. 1 0
      package.json
  3. 3 1
      src/app/app.module.ts
  4. 66 38
      src/app/components/assets/assets.component.html
  5. 36 6
      src/app/components/assets/assets.component.scss
  6. 94 39
      src/app/components/assets/assets.component.ts
  7. 19 8
      src/app/components/confirm-account/confirm-account.component.html
  8. 7 0
      src/app/components/confirm-account/confirm-account.component.scss
  9. 8 6
      src/app/components/confirm-account/confirm-account.component.ts
  10. 25 40
      src/app/components/dashboard/dashboard.component.ts
  11. 12 30
      src/app/components/organizations/edit-organization/edit-organization.component.ts
  12. 0 5
      src/app/components/organizations/new-organization/new-organization.component.ts
  13. 80 1
      src/app/components/plants/edit-plant/edit-plant.component.html
  14. 71 1
      src/app/components/plants/edit-plant/edit-plant.component.ts
  15. 45 7
      src/app/components/plants/new-plant/new-plant.component.html
  16. 59 2
      src/app/components/plants/new-plant/new-plant.component.ts
  17. 45 5
      src/app/components/plugins/validator/validator.component.ts
  18. 9 1
      src/app/components/shared/footer/footer.component.html
  19. 22 0
      src/app/components/terms/terms.component.html
  20. 4 0
      src/app/components/terms/terms.component.scss
  21. 25 0
      src/app/components/terms/terms.component.spec.ts
  22. 15 0
      src/app/components/terms/terms.component.ts
  23. 3 2
      src/app/layouts/admin/admin.component.html
  24. 6 7
      src/app/layouts/admin/admin.module.ts
  25. 5 0
      src/app/layouts/admin/admin.routing.ts
  26. 26 4
      src/app/services/plants.service.ts
  27. 1 0
      src/environments/environment.ts
  28. 1 1
      src/index.html

+ 20 - 10
package-lock.json

@@ -180,6 +180,11 @@
         }
       }
     },
+    "@angular-material-extensions/password-strength": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@angular-material-extensions/password-strength/-/password-strength-4.0.1.tgz",
+      "integrity": "sha512-+UG/9sGKtHxlwAM2eTFQDI8uXkdqFMgfKfl+ZmGvU9JV8f3oP2loCo+mfGy+a07HNo0QnLNCgP2BHzOwdgxeyw=="
+    },
     "@angular/animations": {
       "version": "8.2.3",
       "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.3.tgz",
@@ -606,14 +611,12 @@
             "minimist": {
               "version": "0.0.8",
               "bundled": true,
-              "dev": true,
-              "optional": true
+              "dev": true
             },
             "minipass": {
               "version": "2.3.5",
               "bundled": true,
               "dev": true,
-              "optional": true,
               "requires": {
                 "safe-buffer": "^5.1.2",
                 "yallist": "^3.0.0"
@@ -632,7 +635,6 @@
               "version": "0.5.1",
               "bundled": true,
               "dev": true,
-              "optional": true,
               "requires": {
                 "minimist": "0.0.8"
               }
@@ -7655,7 +7657,8 @@
             },
             "console-control-strings": {
               "version": "1.1.0",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "core-util-is": {
               "version": "1.0.2",
@@ -7758,7 +7761,8 @@
             },
             "inherits": {
               "version": "2.0.3",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "ini": {
               "version": "1.3.5",
@@ -7794,6 +7798,7 @@
             "minipass": {
               "version": "2.3.5",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "safe-buffer": "^5.1.2",
                 "yallist": "^3.0.0"
@@ -7810,6 +7815,7 @@
             "mkdirp": {
               "version": "0.5.1",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "minimist": "0.0.8"
               }
@@ -7893,6 +7899,7 @@
             "once": {
               "version": "1.4.0",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "wrappy": "1"
               }
@@ -7968,7 +7975,8 @@
             },
             "safe-buffer": {
               "version": "5.1.2",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "safer-buffer": {
               "version": "2.1.2",
@@ -7998,6 +8006,7 @@
             "string-width": {
               "version": "1.0.2",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "code-point-at": "^1.0.0",
                 "is-fullwidth-code-point": "^1.0.0",
@@ -8054,11 +8063,13 @@
             },
             "wrappy": {
               "version": "1.0.2",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "yallist": {
               "version": "3.0.3",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             }
           }
         },
@@ -12158,7 +12169,6 @@
               "version": "0.5.1",
               "bundled": true,
               "dev": true,
-              "optional": true,
               "requires": {
                 "minimist": "0.0.8"
               }

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
   "private": true,
   "dependencies": {
     "@agm/core": "^1.0.0-beta.7",
+    "@angular-material-extensions/password-strength": "^4.0.1",
     "@angular/animations": "^8.2.3",
     "@angular/cdk": "^8.1.3",
     "@angular/common": "~8.2.0",

+ 3 - 1
src/app/app.module.ts

@@ -36,6 +36,7 @@ import { LoginComponent } from './components/login/login.component';
 
 import { TokenInterceptor } from '@app/services/token.interceptor';
 import { ConfirmAccountComponent } from './components/confirm-account/confirm-account.component';
+import { MatPasswordStrengthModule } from '@angular-material-extensions/password-strength';
 
 
 @NgModule({
@@ -59,7 +60,8 @@ import { ConfirmAccountComponent } from './components/confirm-account/confirm-ac
     PluginsModule,
     NgxDatatableModule,
     MatSelectModule,
-    AngularMyDatePickerModule
+    AngularMyDatePickerModule,
+    MatPasswordStrengthModule.forRoot(),
   ],
   providers: [
     { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true },

+ 66 - 38
src/app/components/assets/assets.component.html

@@ -5,12 +5,12 @@
       <label for="sel3">Plantas</label>
     </div>
   </div>
-  <div class="row align-container" style="padding: 0 25px;">
+  <div class="row align-container" >
     <div class="col-lg-6 col-sm-4 p-1">
       <div class="row">
         <div class="col-lg-12 col-sm-12">
           <select class="custom-select" (change)="onChangeObj($event)" name="sel3">
-            <option *ngFor="let item of listAssets" [selected]="item.id===organizationId" [value]="item.id" >{{item.name}}</option>
+            <option *ngFor="let item of listAssets" [selected]="item.id===assetID" [value]="item.id" >{{item.name}}</option>
           </select>
         
         </div>
@@ -42,8 +42,20 @@
 
   </div>
 
+  <div class="row align-container" *ngIf="!metersInstalled">
+    <div class="col-12 p-1">
+      <br>
+      <div class="alert alert-danger" role="alert">
+        <h4 class="card-text">
+          <i class="fas fa-exclamation-circle"></i>
+          La planta no tiene medidores asignados
+        </h4>
+      </div>
+    </div>
+  </div>
+
   <!-- Basic stats cards -->
-  <div class="row align-container" style="padding: 0 25px;">
+  <div class="row align-container" *ngIf="metersInstalled">
 
     <div class="col-xl-3 col-lg-6 col-md-6 col-sm-6 p-1">
       <div class="widget energy-stats">
@@ -101,31 +113,57 @@
 
   <!-- Chartjs potency generation graphic -->
   <div class="row align-container">
-    <div class="col-lg-12 col-md-12 col-sm-12">
+    <div class="col-lg-12 col-md-12 col-sm-12 p-1">
       <div class="widget">
         <div class="mini-stats">
 
-          <p class="align-right">Seleccione el tipo de visualización</p>
-      
-          <div class=" action-buttons">
-            <button [ngClass]="[chartActive[0]==true ? 'btn  btn-success' : 'btn btn-dark']"  (click)="changeGraphicType('bar')"> 
-              <i class="fa fa-chart-bar"></i>
-              Barra
-            </button>
-            <button [ngClass]="[chartActive[1]==true ? 'btn  btn-success' : 'btn btn-dark']" (click)="changeGraphicType('line')"> 
-              <i class="fa fa-chart-line"></i>
-              Linea
-            </button>
-            <button [ngClass]="[chartActive[2]==true ? 'btn  btn-success' : 'btn btn-dark']" (click)="changeGraphicType('radar')"> 
-              <i class="fa fa-chart-area"></i>
-              Area
-            </button>
-            <button [ngClass]="[chartActive[3]==true ? 'btn  btn-success' : 'btn btn-dark']" (click)="changeToTable()"> 
-              <i class="fa fa-table"></i>
-              Tabla
-            </button>    
+          <div class="row" *ngIf="metersInstalled">
+            <div class="col-12">
+              <p class="align-right">Seleccione un rango y un tipo de visualización</p>
+                
+              <div class="visualization">
+                <div class=" action-buttons">
+                  <button class="btn btn-link" [class.btn-success]='isActive[0]' (click)="getMeasureRangeChart('day')">1D</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[1]' (click)="getMeasureRangeChart('week')">7D</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[2]' (click)="getMeasureRangeChart('wtd')">WTD</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[3]' (click)="getMeasureRangeChart('month')">1M</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[4]' (click)="getMeasureRangeChart('mtd')">MTD</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[5]' (click)="getMeasureRangeChart('3m')">3M</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[6]' (click)="getMeasureRangeChart('year')">YTD</button>
+                  <button class="btn btn-link" [class.btn-success]='isActive[7]' (click)="getMeasureRangeChart('total')">TOTAL</button>
+               
+                  
+                  <div class="input-box-container">
+                    <div>
+                      <p>
+                        <i class="far fa-calendar" aria-hidden="true"></i>
+                      </p>
+                      <input class="input-box form-control" placeholder="Seleccione una fecha" 
+                        angular-mydatepicker name="mydate" (click)="dp.toggleCalendar()" 
+                        [(ngModel)]="model" [options]="myDpOptions" (dateChanged)="onDateChanged($event)" 
+                        #dp="angular-mydatepicker"/>
+                    </div>
+                  </div>
+                </div>
+                <div class=" action-buttons">
+                  <button title="Barra" [ngClass]="[chartActive[0]==true ? 'btn  btn-success' : 'btn btn-dark']"  (click)="changeGraphicType('bar')"> 
+                    <i class="fa fa-chart-bar"></i>
+                  </button>
+                  <button title="Línea" [ngClass]="[chartActive[1]==true ? 'btn  btn-success' : 'btn btn-dark']" (click)="changeGraphicType('line')"> 
+                    <i class="fa fa-chart-line"></i>
+                  </button>
+                  <button title="Area" [ngClass]="[chartActive[2]==true ? 'btn  btn-success' : 'btn btn-dark']" (click)="changeGraphicType('radar')"> 
+                    <i class="fa fa-chart-area"></i>
+                  </button>
+                  <button title="Tabla" [ngClass]="[chartActive[3]==true ? 'btn  btn-success' : 'btn btn-dark']" (click)="changeToTable()"> 
+                    <i class="fa fa-table"></i>
+                  </button>
+                </div>
+              </div>
+            </div>
           </div>
 
+
           <div class="chart-container" id="chart-wrapper">
             <canvas id="canvas">{{ chart1 }}</canvas>
           </div>
@@ -165,23 +203,14 @@
                   <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
                   <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
                 </mat-table>
+
+
+
               </div>
             </ng-container>
-            <mat-paginator class="hiddenonload" [pageSizeOptions]="[5, 10, 25] " [length]="dataSource.data.length" [pageIndex]="0" [pageSize]="5"></mat-paginator>
+            <mat-paginator class="hiddenonload" [pageSizeOptions]="[5, 10, 25, dataSource.data.length] " [length]="dataSource.data.length" [pageIndex]="0" [pageSize]="5"></mat-paginator>
           </div>
 
-          <p>Seleccione un rango de visualización</p>
-
-          <button class="btn" [class.btn-success]='isActive[0]' (click)="onMeasureClickRange('day')">Día</button>
-          <button class="btn" [class.btn-success]='isActive[1]' (click)="onMeasureClickRange('week')">7 días</button>
-          <button class="btn" [class.btn-success]='isActive[2]' (click)="onMeasureClickRange('month')">30 días</button>
-          <button class="btn" [class.btn-success]='isActive[3]' (click)="onMeasureClickRange('year')">Año</button>
-          <div class="input-box-container">
-            <input class="input-box" placeholder="Click to select a date" 
-              angular-mydatepicker name="mydate" (click)="dp.toggleCalendar()" 
-              [(ngModel)]="model" [options]="myDpOptions" (dateChanged)="onDateChanged($event)" 
-              #dp="angular-mydatepicker"/>
-          </div>
         </div>
       </div>
 
@@ -189,7 +218,7 @@
   </div>
   
   <!-- Enviromental cool stats cards -->
-  <div class="row align-container">
+  <div class="row align-container" *ngIf="metersInstalled">
 
     <div class="col-xl-4 col-lg-6 col-md-6 col-sm-6 p-1">
       <div class="widget">
@@ -238,6 +267,5 @@
   </div>
 
   <br>
-  <br>
 
 </div>

+ 36 - 6
src/app/components/assets/assets.component.scss

@@ -1,16 +1,35 @@
+h4.card-text {
+  margin: 0;
+  color: #fff;
+  i {
+    color: inherit;
+  }
+}
+
 .input-box-container {
   display: inline-block;
-  margin-left: 15px;
+  margin: 0 15px;
   position: relative;
   border-collapse: separate;
+  max-width: 130px;
   
   input {
     margin: 5px 0 0;
     font-family: inherit;
-    font-size: inherit;
     line-height: inherit;
-    padding: 6px;
+    padding-left: 25px;
+    max-width: inherit;
   }
+
+  p{
+    position: absolute;
+    margin-left: 5px;
+    height: 25px;
+    display: flex;
+    align-items: center;
+    left: 5px
+  }
+
 }
 
 .savings-wrapper {
@@ -26,12 +45,23 @@
 }
 
 .action-buttons {
+  display: inline-block;
   margin-top: 10px;
   button {
-    margin-right: 7px;
+    margin-right: 5px;
+    padding: 8px 12px;
+  }
+  .btn-success {
+    background: #47a44b;
+    border-color: #39843c;
+    color: #fff;
   }
 }
 
+.visualization {
+  text-align: right;
+}
+
 table {
   width: 100%;
 }
@@ -104,7 +134,7 @@ table {
       color: #878888;
       //display: block;
       font-size: 14px;
-      line-height: 35px;
+      line-height: 25px;
       margin: 6px 0 0;
       text-transform: uppercase;
       width: auto;
@@ -176,7 +206,7 @@ table {
   display: block; 
   height:48vh; 
   @media screen and (max-width: 960px) {
-    height:38vh; 
+    height:350px; 
   }
   position: relative;
 }

+ 94 - 39
src/app/components/assets/assets.component.ts

@@ -34,7 +34,7 @@ export class AssetsComponent implements OnInit {
   title = "Plantas";
 
   // General var declarations
-  organizationId:string;
+  assetID:string;
   listAssets:any;
   eProduced:any;
   error:boolean;
@@ -51,9 +51,10 @@ export class AssetsComponent implements OnInit {
   environmentCO2:any;
   environmentHouse:any;
   environmentFuel:any;
-  isActive:[boolean,boolean,boolean,boolean]; //Activated param (chart)
+  isActive:[boolean,boolean,boolean,boolean,boolean,boolean,boolean,boolean]; //Activated param (chart)
   chartActive:[boolean,boolean,boolean,boolean]
   initialLoad: boolean = true;
+  metersInstalled:boolean = true;
 
   // For daterange
   daysLabels:any = {su: 'Dom', mo: 'Lun', tu: 'Mar', we: 'Mie', th: 'Jue', fr: 'Vie', sa: 'Sab'};
@@ -78,7 +79,8 @@ export class AssetsComponent implements OnInit {
   array1: any[];
   array2: any[];
   array3: any[];
-  dataSource = new MatTableDataSource(this.tableData2);  
+  dataSource = new MatTableDataSource(this.tableData2);
+  dataSourcePrint = new MatTableDataSource(this.tableData2);
   @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
   @ViewChild(MatSort, { static: true }) sort: MatSort;
 
@@ -107,7 +109,7 @@ export class AssetsComponent implements OnInit {
     public datepipe: DatePipe) {
       
       this.route.queryParams.subscribe(params => {
-        this.organizationId = params['id'];
+        this.assetID = params['id'];
       });
       
       Swal.fire({
@@ -134,7 +136,8 @@ export class AssetsComponent implements OnInit {
     }
 
     // Initialize default 'clicked' options for chart button options
-    this.isActive = [false, false, false, false];
+    this.isActive = [false, false, false, false, false, false, false, false];
+    
     this.chartActive = [true, false, false, false];
 
     // Get all assets (according to user's assigned organizations)
@@ -143,29 +146,26 @@ export class AssetsComponent implements OnInit {
       
       // Default values for chart 
       this.view = "month";
-      if (this.organizationId == undefined){
-        this.organizationId = this.listAssets[0].id;
-      }
       this.chart1Type = "bar";
+      
+      if (this.assetID == undefined){
+        this.assetID = this.listAssets[0].id;
+      }
 
-      // Initialize a draw chart according to the default values
-      this.onMeasureClickRange(this.view, this.initialDate);
-
-      // Api call to get the energy summary stats of all assets in the organization
-      let energy_produced = this.logsService.getEnergySummaryByAsset(this.organizationId).subscribe(resp => {
-        this.eProduced = resp["data"]["energy"];//results[1];
-        this.energyDay = this.eProduced.today.total_energy_kWh || 0;
-        this.energyWeek = this.eProduced.thisWeek.total_energy_kWh > 0 ? (this.eProduced.thisWeek.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisWeek.total_energy_kWh || 0
-        this.energyMonth = this.eProduced.thisMonth.total_energy_kWh > 0 ? (this.eProduced.thisMonth.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisMonth.total_energy_kWh || 0
-        this.energyYear = this.eProduced.lifeTime.total_energy_kWh > 0 ? (this.eProduced.lifeTime.total_energy_kWh/1000).toFixed(2) : this.eProduced.lifeTime.total_energy_kWh || 0
-      });
+      let tempAsset = this.listAssets.find(object=>object.id == this.assetID);
 
-      this.logsService.getAssetEnviromentalStats(this.organizationId).subscribe(resp => {
-        this.environment = resp["data"]["environmentals"];
-        this.environmentCO2 = this.environment.avoided_kg_of_co2.toFixed(2); 
-        this.environmentHouse = this.environment.number_of_homes.toFixed(0);
-        this.environmentFuel = this.environment.number_of_crude_barrels.toFixed(2);
-      });
+      if (tempAsset["meters_installed"].length > 0){
+        this.metersInstalled = true;
+        // Get energy produced given an asset 
+        this.getEnergyProduced(this.assetID); 
+        // Initialize a draw chart according to the default values
+        this.getMeasureRangeChart(this.view, this.initialDate, this.assetID);
+        // Get environmental data given an asset
+        this.getEnvironmentalData(this.assetID);
+      }
+      else {
+        this.metersInstalled = false;
+      }
 
 
     }, (err) => {
@@ -184,7 +184,7 @@ export class AssetsComponent implements OnInit {
  
   // Default check asset dropdown if a value is equal to an assetID
   isSelected(){
-    if(this.organizationId!=undefined){
+    if(this.assetID!=undefined){
       return true;
     }
     else{
@@ -200,8 +200,23 @@ export class AssetsComponent implements OnInit {
 
   // Trigger again the chart with the selected assetID
   onChangeObj(event:any) {
-    this.organizationId = event.target.value;
-    this.onMeasureClickRange(this.view, this.initialDate, this.organizationId);
+    this.assetID = event.target.value;
+    let tempAsset = this.listAssets.find(object=>object.id == this.assetID);
+
+    if (tempAsset["meters_installed"].length > 0){
+      this.metersInstalled = true;
+      this.getEnergyProduced(this.assetID);
+      this.getMeasureRangeChart(this.view, this.initialDate, this.assetID);
+      this.getEnvironmentalData(this.assetID);
+    }
+    else {
+      this.metersInstalled = false;
+      if (this.chart1 != undefined){
+        this.chart1.destroy();
+      }
+      this.chart1 = undefined;
+      this.chart1 = new Chart('canvas', {});
+    }
   }
   
   // Change the date range of the chart, according to the selected view (daily, weekly, ...)
@@ -211,25 +226,51 @@ export class AssetsComponent implements OnInit {
     switch (this.view)
     { 
       case "day": 
-        this.onMeasureClickRange(this.view, endDate);
+        this.getMeasureRangeChart(this.view, endDate);
         break; 
       case "week": 
-        this.onMeasureClickRange(this.view, endDate);
+        this.getMeasureRangeChart(this.view, endDate);
         break; 
       case "month": 
-        this.onMeasureClickRange(this.view, endDate);
+        this.getMeasureRangeChart(this.view, endDate);
         break; 
       case "year":
-        this.onMeasureClickRange(this.view, endDate);
+        this.getMeasureRangeChart(this.view, endDate);
         break;
       default: 
         break;
     } 
   }
 
+  getEnvironmentalData(assetID: string) {
+    this.logsService.getAssetEnviromentalStats(assetID).subscribe(resp => {
+      this.environment = resp["data"]["environmentals"];
+      this.environmentCO2 = this.environment.avoided_kg_of_co2.toFixed(2); 
+      this.environmentHouse = this.environment.number_of_homes.toFixed(0);
+      this.environmentFuel = this.environment.number_of_crude_barrels.toFixed(2);
+    });
+  }
+
+  getEnergyProduced(assetID:string){
+    // Api call to get the energy summary stats of all assets in the organization
+    let energy_produced = this.logsService.getEnergySummaryByAsset(assetID).subscribe(resp => {
+      this.eProduced = resp["data"]["energy"];//results[1];
+      this.energyDay = this.eProduced.today.total_energy_kWh || 0;
+      this.energyWeek = this.eProduced.thisWeek.total_energy_kWh > 0 ? (this.eProduced.thisWeek.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisWeek.total_energy_kWh || 0
+      this.energyMonth = this.eProduced.thisMonth.total_energy_kWh > 0 ? (this.eProduced.thisMonth.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisMonth.total_energy_kWh || 0
+      this.energyYear = this.eProduced.lifeTime.total_energy_kWh > 0 ? (this.eProduced.lifeTime.total_energy_kWh/1000).toFixed(2) : this.eProduced.lifeTime.total_energy_kWh || 0
+    }, (err) => {
+      Swal.fire({
+        type: 'error',
+        title: 'Error en el servidor',
+        text: "No su pudo obtener la informacion"
+      });
+    });
+  }
+
   // Draw a measure chart using chartjs, given some params, view, for daily, weekly, monthly or yearly measures;
   // measureDate, for a date range given a view and a paramID, for an specific assetID selected in the dropdown  
-  onMeasureClickRange(view:string, measureDate?:string, paramId?:string): void {
+  getMeasureRangeChart(view:string, measureDate?:string, paramId?:string): void {
     if(this.initialLoad == false){
       Swal.fire({
         allowOutsideClick: false,
@@ -268,25 +309,35 @@ export class AssetsComponent implements OnInit {
     let interval:string;
     switch (view)
     { 
+
       case "day": 
         interval = "1D";
-        this.isActive = [true, false, false, false];
+        this.isActive = [true, false, false, false, false, false, false, false];
         break; 
       case "week": 
         interval = "7D";
-        this.isActive = [false, true, false, false];
+        this.isActive = [false, true, false, false, false, false, false, false];
         break; 
+      case "wtd":
+        interval = "WTD"
+        this.isActive = [false, false, true, false, false, false, false, false]
       case "month":
         interval = "1M";
-        this.isActive = [false, false, true, false];
+        this.isActive = [false, false, false, true, false, false, false, false];
         break; 
-      case "mtd": //TO DO
+      case "mtd":
         interval = "MTD";
+        this.isActive = [false, false, false, false, true, false, false, false];
+      case "3m":
+        interval = "3M";
+        this.isActive = [false, false, false, false, false, true, false, false];
         break;
       case "year":
         interval = "YTD";
-        this.isActive = [false, false, false, true];
-        break;
+        this.isActive = [false, false, false, false, false, false, true, false];
+      case "total":
+        interval = "TOTAL";
+        this.isActive = [false, false, false, false, false, false, false, true];    
       default: 
     }
 
@@ -383,6 +434,9 @@ export class AssetsComponent implements OnInit {
       this.dataSource.paginator = this.paginator;
       this.dataSource.sort = this.sort;
 
+      this.dataSourcePrint.data = this.tableData2;
+
+
       this.showTable = true;
       this.chart1 = new Chart('canvas', {
         type: this.chart1Type,
@@ -466,6 +520,7 @@ export class AssetsComponent implements OnInit {
   printTable(){
     printJS(
       { printable: 'measuresTable', type: 'html', 
+        //properties: this.displayedColumns.join(","),
         header: '<h3 class="report-header">Datos de la planta </h3>',
         documentTitle: 'DENMARK - Informacion generada',
         style: '.report-header{ color: #075D9D; font-size: 24px; }' }

+ 19 - 8
src/app/components/confirm-account/confirm-account.component.html

@@ -27,23 +27,34 @@
                   <div *ngIf="f.first_name.errors.required">Campo requerido</div>
                 </div>
               </div>
-
               
               <div class="form-group">
-                  <label for="name">Apellido</label>
-                  <input type="text" class="form-control"
-                  formControlName="last_name" [ngClass]="{ 'is-invalid': submitted && f.last_name.errors }"/>
-                  <div *ngIf="submitted && f.last_name.errors" class="invalid-feedback">
-                    <div *ngIf="f.last_name.errors.required">Campo requerido</div>
-                  </div>
+                <label for="name">Apellido</label>
+                <input type="text" class="form-control"
+                formControlName="last_name" [ngClass]="{ 'is-invalid': submitted && f.last_name.errors }"/>
+                <div *ngIf="submitted && f.last_name.errors" class="invalid-feedback">
+                  <div *ngIf="f.last_name.errors.required">Campo requerido</div>
+                  
                 </div>
+              </div>
 
               <div class="form-group">
+                <div class="hint-wrapper">
+                  <small class="hint">
+                    <i class="fas fa-exclamation-circle"></i>
+                    La contraseña debe contener letras mayusculas, minusculas, al menos un número y un símbolo.
+                  </small>
+                </div>
+                
                 <label for="password">Contraseña</label>
                 <input type="password" class="form-control"
                 formControlName="password" [ngClass]="{ 'is-invalid': submitted && f.password.errors }"/>
                 <div *ngIf="submitted && f.password.errors" class="invalid-feedback">
                   <div *ngIf="f.password.errors.required">Campo requerido</div>
+                  <div *ngIf="f.password.errors.minlength">La contraseña debe contener al menos 8 caracteres</div>
+                  <div *ngIf="f.password.hasError('passwordStrength')" style="white-space: pre;">
+                    {{f.password.errors['passwordStrength']}}
+                  </div>
                 </div>
               </div>
 
@@ -56,7 +67,7 @@
                   <div *ngIf="f.confirm_password.errors.mustMatch">Las contraseñas deben coincidir</div>
                 </div>
               </div>
-
+    
               <br>
 
               <div class="div-center">

+ 7 - 0
src/app/components/confirm-account/confirm-account.component.scss

@@ -1,3 +1,10 @@
+.hint-wrapper {
+  background: #eee;
+  border: 1px solid #aaa;
+  padding: 5px;
+  margin-bottom: 5px;
+}
+
 .vertical-align-wrap {
   //position: absolute;
   width: 100%;

+ 8 - 6
src/app/components/confirm-account/confirm-account.component.ts

@@ -1,10 +1,9 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, ViewChild } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { FormGroup, FormBuilder, Validators } from '@angular/forms';
 import { UserService } from '@app/services/user.service';
 import Swal from 'sweetalert2';
-import { ValidatorComponent } from '../plugins/validator/validator.component';
-
+import { ValidatorComponent, PasswordStrengthValidator } from '../plugins/validator/validator.component';
 
 
 @Component({
@@ -22,6 +21,7 @@ export class ConfirmAccountComponent implements OnInit {
   activateMessage: string;
   invalidToken: boolean;
   submitted: boolean = false;
+  showDetails: boolean;
 
   constructor(private formBuilder: FormBuilder, private route: ActivatedRoute, private userService: UserService) {
     this.route.queryParams.subscribe(params => {
@@ -46,9 +46,10 @@ export class ConfirmAccountComponent implements OnInit {
           email: [(userData.email)],
           first_name: [(userData.first_name),Validators.required],
           last_name: [(userData.last_name),Validators.required],
-          password: ['',[Validators.required, Validators.minLength(6)]],
+          password: ['',[Validators.required, Validators.minLength(8), PasswordStrengthValidator]],
           confirm_password: ['',Validators.required]
         },{
+          
             validator: ValidatorComponent('password', 'confirm_password')
         });
       }, (err) => {
@@ -74,9 +75,10 @@ export class ConfirmAccountComponent implements OnInit {
 
     // stop here if form is invalid
     if (this.activateForm.invalid) {
+      console.log(this.activateForm);
       return;
     }
-
+    /*
     this.userService.activateUser(
       {
         email: this.f.email.value,
@@ -94,7 +96,7 @@ export class ConfirmAccountComponent implements OnInit {
       this.validToken = false;
       this.errorMessage = err.message;
     });
-
+    */
     //
 
   }

+ 25 - 40
src/app/components/dashboard/dashboard.component.ts

@@ -100,14 +100,16 @@ export class DashboardComponent implements OnInit {
       this.dataSource.data = this.listAssets;
       this.dataSource.paginator = this.paginator;
       this.dataSource.sort = this.sort;
-
       this.assetKeys = Object.keys(this.listAssets);
       for (let prop in this.assetKeys){
         this.meterKeys2 = Object.keys(this.listAssets.map(item => item["meters_installed"])[prop]);
-        for (let prop2 in this.meterKeys2){
-          this.sumarize += this.listAssets.map(item => item["meters_installed"])[prop].map(response => response["installedCapacity_kW"])[prop2];
-          //this.totalMetersInstalled = this.sumarize.toString();
-          //localStorage.setItem("installedCapacityTotal_kW", this.totalMetersInstalled);
+        if (this.meterKeys2.length > 0){
+          for (let prop2 in this.meterKeys2){
+            this.sumarize += this.listAssets.map(item => item["meters_installed"])[prop].map(response => response["installedCapacity_kW"])[prop2];
+            //this.totalMetersInstalled = this.sumarize.toString();
+            //localStorage.setItem("installedCapacityTotal_kW", this.totalMetersInstalled);
+          }
+  
         }
       }      
     }, (err) => {
@@ -152,51 +154,34 @@ export class DashboardComponent implements OnInit {
     let lat, long, address, name2;
 
     for (const plant of this.listAssets) {
-      if (localStorage.getItem("email") == "inverlec@grupomerelec.com") {
-        lat = "13.6613819";
-        long = "-89.2514334";
-        address = "Urbanización Madre Selva Calle Llama del Bosque, Edificio Avante, Local 4-5/4-6, Antiguo Cuscatlán";
-        name2 = "Inversiones MERELEC S.A de C.V";
-      }
-      else {
+      if (plant["meters_installed"].length > 0){
         lat = plant["meters_installed"][0].gpsLat;
         long = plant["meters_installed"][0].gpsLong;
         address = plant.address;
         name2 = plant.name;
-      }
-
-      const newMarker = marker(
-        [lat, long],
-        { icon: this.icon })
-        .bindPopup('<b>' + name2 + '</b><br>Dirección: ' + address)
-        .on('click', () => {
-          this.zone.run(() => {
-            this.sendPlantId(plant.id);
+      
+        const newMarker = marker(
+          [lat, long],
+          { icon: this.icon })
+          .bindPopup('<b>' + name2 + '</b><br>Dirección: ' + address)
+          .on('click', () => {
+            this.zone.run(() => {
+              this.sendPlantId(plant.id);
+            });
           });
-        });
-      this.points.push(latLng([lat, long]));
-      this.markers.push(newMarker);
+        this.points.push(latLng([lat, long]));
+        this.markers.push(newMarker);
+      }
     }
   }
 
   sendPlantId(id: string) {
     this.plantId = id;
-    if (localStorage.getItem("email") == "inverlec@grupomerelec.com") {
-      this.selectedPlant = {
-        name: "Inversiones MERELEC S.A de C.V",
-        country: "El Salvador",
-        city: "La Libertad",
-        address: "Urbanización Madre Selva Calle Llama del Bosque, Edificio Avante, Local 4-5/4-6, Antiguo Cuscatlán",
-        installedCapacity_kW: 300
-      }
-    }
-    else {
-      
-      this.selectedPlant = this.listAssets.find(e => e.id === this.plantId);
-      let keys = Object.keys(this.selectedPlant.meters_installed.map(item => item["meters_installed"]));
-      for (let prop2 in keys){
-        this.totalInstalled += this.selectedPlant.meters_installed.map(response => response["installedCapacity_kW"])[prop2];
-      }
+    this.totalInstalled = 0;
+    this.selectedPlant = this.listAssets.find(e => e.id === this.plantId);
+    let keys = Object.keys(this.selectedPlant.meters_installed.map(item => item["meters_installed"]));
+    for (let prop2 in keys){
+      this.totalInstalled += this.selectedPlant.meters_installed.map(response => response["installedCapacity_kW"])[prop2];
     }
   }
 

+ 12 - 30
src/app/components/organizations/edit-organization/edit-organization.component.ts

@@ -49,41 +49,23 @@ export class EditOrganizationComponent implements OnInit {
   }
 
   ngOnInit() {
-    /*
-    this.organizationForm = this.formBuilder.group({
-      name: [this.listOrganization.name],
-      address: [this.listOrganization.address],
-      city: [this.listOrganization.city],
-      country: [this.listOrganization.country],
-      contactName: [this.listOrganization.contactName],
-      contactNumber: [this.listOrganization.contactNumber],
-    });
-
-    this.organizationForm = this.formBuilder.group({
-      name: [""], //this.listOrganization.name
-      address: [""], //this.listOrganization.address
-      city: [""], //this.listOrganization.city
-      country: [""], //this.listOrganization.country
-      contactName: [""], //this.listOrganization.contactName
-      contactNumber: [""], //this.listOrganization.contactNumber
-    });
-    */
+  
   }
 
   get f() { return this.organizationForm.controls; }
 
   editOrganization() {
-      this.orgService.updateOrganization(this.organizationId, 
-        {
-          name: this.f.name.value,
-          address: this.f.address.value,
-          city: this.f.city.value,
-          country: this.f.country.value,
-          contactName: this.f.contactName.value,
-          contactNumber: this.f.contactNumber.value,
-          assets: [""],
-        }
-      )
+    this.orgService.updateOrganization(this.organizationId, 
+      {
+        name: this.f.name.value,
+        address: this.f.address.value,
+        city: this.f.city.value,
+        country: this.f.country.value,
+        contactName: this.f.contactName.value,
+        contactNumber: this.f.contactNumber.value,
+        assets: [""],
+      }
+    )
     .subscribe(success => {
       if (success) {
         Swal.fire({

+ 0 - 5
src/app/components/organizations/new-organization/new-organization.component.ts

@@ -17,7 +17,6 @@ export class NewOrganizationComponent implements OnInit {
 
 
   constructor(private orgService: OrganizationsService, private formBuilder: FormBuilder) {
-
   }
 
   ngOnInit() {
@@ -66,11 +65,7 @@ export class NewOrganizationComponent implements OnInit {
           }
         });
       }
-      
     });
-    
-
-
   }
 
 

+ 80 - 1
src/app/components/plants/edit-plant/edit-plant.component.html

@@ -14,9 +14,88 @@
             </ol>
           </nav>
         </div>
+      </div>
+    </div>
+    <br>
+    <div class="row justify-content-center">
+      <div class="col-8">
+        <div class="align-container">
+
+          <div class="card" *ngIf="assetExists">
+            <div class="card-header card-header-icon card-header-rose">
+              <div class="card-icon"><i class="material-icons">map</i></div>
+              <h4 class="card-title">Editar planta - <small class="category">Complete la información básica</small></h4>
+            </div>
+            <div class="card-body">              
+              <div class="align-container">
+                <form class="form-auth-small ng-untouched ng-pristine ng-valid" [formGroup]="assetForm" (ngSubmit)="editAsset()">
 
+                  <div class="form-group">
+                    <label for="name">Nombre de la planta: </label>
+                    <input type="text" formControlName="name" class="form-control" />
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="country">País: </label>
+                    <input type="text" formControlName="country" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.country.errors }" />
+                    <div *ngIf="submitted && f.country.errors" class="invalid-feedback">
+                      <div *ngIf="f.country.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="city">Ciudad: </label>
+                    <input type="text" formControlName="city" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.city.errors }" />
+                    <div *ngIf="submitted && f.city.errors" class="invalid-feedback">
+                      <div *ngIf="f.city.errors.required">Campo requerido</div>
+                    </div>
+                  </div>      
+                  
+                  <div class="form-group">
+                    <label for="address">Dirección: </label>
+                    <input type="text" formControlName="address" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.address.errors }" />
+                    <div *ngIf="submitted && f.address.errors" class="invalid-feedback">
+                      <div *ngIf="f.address.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="distribuidora">Distribuidora: </label>
+                    <select class="custom-select" formControlName="distribuidora" [ngClass]="{ 'is-invalid': submitted && f.distribuidora.errors }">
+                      <option *ngFor="let item of distributor" [value]="item" [selected]="item==listPlant.distribuidora" >{{item}}</option>
+                    </select>
+                    <div *ngIf="submitted && f.distribuidora.errors" class="invalid-feedback">
+                      <div *ngIf="f.distribuidora.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="categoria_tarifaria">Categoría tarifaria: </label>
+                    <input type="text" formControlName="categoria_tarifaria" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.categoria_tarifaria.errors }" />
+                    <div *ngIf="submitted && f.categoria_tarifaria.errors" class="invalid-feedback">
+                      <div *ngIf="f.categoria_tarifaria.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="cod_tarifa">Código de tarifa: </label>
+                    <input type="text" formControlName="cod_tarifa" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.cod_tarifa.errors }" />
+                    <div *ngIf="submitted && f.cod_tarifa.errors" class="invalid-feedback">
+                      <div *ngIf="f.cod_tarifa.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+
+                  <br>
+                  <button class="btn btn-primary">
+                    Actualizar planta
+                  </button>
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
       </div>
+    </div>
 
-    </div>          
   </div>
 </div>

+ 71 - 1
src/app/components/plants/edit-plant/edit-plant.component.ts

@@ -1,5 +1,8 @@
 import { Component, OnInit } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { PlantsService } from '@app/services/plants.service';
+import { ActivatedRoute } from '@angular/router';
+import Swal from 'sweetalert2';
 
 @Component({
   selector: 'app-edit-plant',
@@ -8,9 +11,76 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 })
 export class EditPlantComponent implements OnInit {
   title:string = "Editar planta"; 
-  constructor() { }
+
+  listPlant: any;
+  organizationExists:boolean;
+  assetForm: FormGroup;
+  assetID:any;
+  role_number: any;
+  assetExists:boolean;
+  distributor = ['CAESS', 'DEL SUR', 'AES-CLESA', 'EEO', 'DEUSEM'];
+
+  constructor(private plantsService: PlantsService, private formBuilder: FormBuilder, private route: ActivatedRoute) {
+
+    this.route.params.subscribe(params => {
+      this.assetID = params['id'];
+    });
+
+    this.plantsService.getAssetById(this.assetID).subscribe(res => {
+      this.listPlant = res["data"]["asset"];
+      this.organizationExists = true;
+
+      this.assetForm = this.formBuilder.group({
+        name: [this.listPlant.name],
+        country: [this.listPlant.country],
+        city: [this.listPlant.city],
+        address: [this.listPlant.address],
+        distribuidora: [this.listPlant.distribuidora],
+        categoria_tarifaria: [this.listPlant.categoria_tarifaria],
+        cod_tarifa: [this.listPlant.cod_tarifa],
+      });
+      this.assetExists = true;
+    }, (err) => {
+      Swal.fire({
+        type: 'error',
+        title: 'Error en el servidor',
+        text: "No su pudo obtener la informacion"
+      });
+    });
+
+  }
 
   ngOnInit() {
+  
+  }
+
+  get f() { return this.assetForm.controls; }
+
+  editAsset() {
+    this.plantsService.updatePlant(this.assetID, 
+      {
+        name: this.f.name.value,
+        country: this.f.country.value,
+        city: this.f.city.value,
+        address: this.f.address.value,
+        distribuidora: this.f.distribuidora.value,
+        categoria_tarifaria: this.f.categoria_tarifaria.value,
+        cod_tarifa: this.f.cod_tarifa.value,
+      }
+    )
+    .subscribe(success => {
+      if (success) {
+        Swal.fire({
+          allowOutsideClick: false,
+          type: 'success',
+          text: 'Informacion actualizada con exito'
+        });
+        //window.location.href="#/dashboard";
+
+      }
+      
+    });
   }
 
+
 }

+ 45 - 7
src/app/components/plants/new-plant/new-plant.component.html

@@ -28,30 +28,68 @@
             </div>
             <div class="card-body">              
               <div class="align-container">
-                <form class="form-auth-small ng-untouched ng-pristine ng-valid" >
+                <form class="form-auth-small ng-untouched ng-pristine ng-valid" [formGroup]="assetForm" (ngSubmit)="createAsset()" >
                   <div class="form-group">
                     <label for="name">Nombre de la planta: </label>
-                    <input type="text" name="name" class="form-control" required />
+                    <input type="text" formControlName="name" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" />
+                    <div *ngIf="submitted && f.name.errors" class="invalid-feedback">
+                      <div *ngIf="f.name.errors.required">Campo requerido</div>
+                    </div>
                   </div>
-
+                  
                   <div class="form-group">
                     <label for="country">País: </label>
-                    <input type="text" name="country" class="form-control" required />
+                    <input type="text" formControlName="country"class="form-control" [ngClass]="{ 'is-invalid': submitted && f.country.errors }" />
+                    <div *ngIf="submitted && f.country.errors" class="invalid-feedback">
+                      <div *ngIf="f.country.errors.required">Campo requerido</div>
+                    </div>
                   </div>
                   
                   <div class="form-group">
                     <label for="city">Ciudad: </label>
-                    <input type="text" name="city" class="form-control" required />
+                    <input type="text" formControlName="city" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.city.errors }" />
+                    <div *ngIf="submitted && f.city.errors" class="invalid-feedback">
+                      <div *ngIf="f.city.errors.required">Campo requerido</div>
+                    </div>
                   </div>      
                   
                   <div class="form-group">
                     <label for="address">Dirección: </label>
-                    <input type="text" name="address" class="form-control" required />
+                    <input type="text" formControlName="address" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.address.errors }" />
+                    <div *ngIf="submitted && f.address.errors" class="invalid-feedback">
+                      <div *ngIf="f.address.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="distribuidora">Distribuidora: </label>
+                    <select class="custom-select" formControlName="distribuidora" [ngClass]="{ 'is-invalid': submitted && f.distribuidora.errors }">
+                      <option *ngFor="let item of distributor" [value]="item" >{{item}}</option>
+                    </select>
+                    <div *ngIf="submitted && f.distribuidora.errors" class="invalid-feedback">
+                      <div *ngIf="f.distribuidora.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="categoria_tarifaria">Categoría tarifaria: </label>
+                    <input type="text" formControlName="categoria_tarifaria" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.categoria_tarifaria.errors }" />
+                    <div *ngIf="submitted && f.categoria_tarifaria.errors" class="invalid-feedback">
+                      <div *ngIf="f.categoria_tarifaria.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+                  
+                  <div class="form-group">
+                    <label for="cod_tarifa">Código de tarifa: </label>
+                    <input type="text" formControlName="cod_tarifa" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.cod_tarifa.errors }" />
+                    <div *ngIf="submitted && f.cod_tarifa.errors" class="invalid-feedback">
+                      <div *ngIf="f.cod_tarifa.errors.required">Campo requerido</div>
+                    </div>
                   </div>
 
                   <br>
                   <button class="btn btn-primary">
-                    Crear organización
+                    Crear planta
                   </button>
                   <!--<div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
                 </form>

+ 59 - 2
src/app/components/plants/new-plant/new-plant.component.ts

@@ -1,5 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { PlantsService } from '@app/services/plants.service';
+import Swal from 'sweetalert2';
 
 @Component({
   selector: 'app-new-plant',
@@ -8,10 +10,65 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 })
 export class NewPlantComponent implements OnInit {
   title:string = "Nueva planta"; 
-
-  constructor() { }
+  assetForm: FormGroup;
+  submitted: boolean = false;
+  role_number: any;
+  distributor = ['CAESS', 'DEL SUR', 'AES-CLESA', 'EEO', 'DEUSEM'];
+  
+  constructor(private plantService: PlantsService, private formBuilder: FormBuilder) { }
 
   ngOnInit() {
+    this.assetForm = this.formBuilder.group({
+      name: ['', Validators.required],
+      country: ['', Validators.required],
+      city: ['', Validators.required],
+      address: ['', Validators.required],
+      distribuidora: ['', Validators.required],
+      categoria_tarifaria: ['', Validators.required],
+      cod_tarifa: ['', Validators.required]
+    });
+  }
+
+  get f() { return this.assetForm.controls; }
+
+  createAsset() {
+    this.submitted = true;
+
+    // stop here if form is invalid
+    if (this.assetForm.invalid) {
+      return;
+    }
+    
+    console.log(this.f);
+    
+    this.plantService.createPlant(
+      {
+        name: this.f.name.value,
+        country: this.f.country.value,
+        city: this.f.city.value,
+        address: this.f.address.value,
+        distribuidora: this.f.distribuidora.value,
+        categoria_tarifaria: this.f.categoria_tarifaria.value,
+        cod_tarifa: this.f.cod_tarifa.value,
+        meters_installed: [""]
+      }
+    )
+    .subscribe(success => {
+      if (success) {
+        Swal.fire({
+          allowOutsideClick: false,
+          type: 'success',
+          showCancelButton: false,
+          title: 'Exito',
+          confirmButtonText: 'El registro ha sido guardado'
+        }).then((result) => {
+          if (result.value) {
+            window.location.href="#/plants";
+          }
+        });
+      }
+    });
   }
 
+
 }

+ 45 - 5
src/app/components/plugins/validator/validator.component.ts

@@ -1,4 +1,5 @@
 import { FormGroup } from '@angular/forms';
+import { AbstractControl, ValidationErrors } from "@angular/forms"
 
 // custom validator to check that two fields match
 export function ValidatorComponent(controlName: string, matchingControlName: string) {
@@ -7,15 +8,54 @@ export function ValidatorComponent(controlName: string, matchingControlName: str
         const matchingControl = formGroup.controls[matchingControlName];
 
         if (matchingControl.errors && !matchingControl.errors.mustMatch) {
-            // return if another validator has already found an error on the matchingControl
-            return;
+          // return if another validator has already found an error on the matchingControl
+          return;
         }
 
         // set error on matchingControl if validation fails
         if (control.value !== matchingControl.value) {
-            matchingControl.setErrors({ mustMatch: true });
-        } else {
-            matchingControl.setErrors(null);
+          matchingControl.setErrors({ mustMatch: true });
+        } {
+          matchingControl.setErrors(null);
         }
     }
 }
+
+
+
+export const PasswordStrengthValidator = function (control: AbstractControl): ValidationErrors | null {
+
+  let value: string = control.value || '';
+  let upperCaseCharacters = /[A-Z]+/g
+  let lowerCaseCharacters = /[a-z]+/g
+  let numberCharacters = /[0-9]+/g
+  let specialCharacters = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/
+
+  if (!value) {
+    return null
+  }
+
+
+  if (upperCaseCharacters.test(value) === false) {
+    return { passwordStrength: `La contraseña debe contener al menos una letra Mayúscula\n` };
+  }
+
+  if (lowerCaseCharacters.test(value) === false) {
+    return { passwordStrength: `La contraseña debe contener al menos una letra minúscula\n` };
+  }
+
+  if (numberCharacters.test(value) === false) {
+    return { passwordStrength: `La contraseña debe contener al menos un número\n` };
+  }
+
+  if (specialCharacters.test(value) === false) {
+    return { passwordStrength: `La contraseña debe contener al menos un símbolo\n` };
+  }
+
+  return null;
+
+  
+  
+
+
+}

+ 9 - 1
src/app/components/shared/footer/footer.component.html

@@ -1 +1,9 @@
-<p>footer works!</p>
+<div class="row align-container">
+  <div class="col-12">
+    <div class="card">
+      <div class="card-body">
+        <p class="card-text">&copy; 2019-2020 - INVERLEC. <a href="#/terms">Términos y condiciones.</a> </p>
+      </div>
+    </div>
+  </div>
+</div>

+ 22 - 0
src/app/components/terms/terms.component.html

@@ -0,0 +1,22 @@
+<h2 class="floating-title">{{title}}</h2>
+
+<div class="main-content">
+  
+  <div class="container-fluid">
+
+    <div class="row">
+      <div class="col-lg-12 col-md-12 col-sm-12 p-1">
+        <div class="card card-img-holder">
+          <div class="card-body">
+              The information and data above is confidential data of INVERLEC, intended for the exclusive use of its DENMARK customers and not for distribution 
+              to any third parties for any purpose whatsoever. By accessing and using such information and data, you agree to use it only for your internal analysis and other similar 
+              internal business purposes, not to transfer or disclose such information or data to any person, company or other entity, except to colleagues within your employer who 
+              have a need to know such information or data to carry out those internal business purposes, and to destroy such information and data and any copies or duplicates as soon 
+              as your use thereof for those purposes has concluded. Your foregoing agreement is subject to the terms, conditions and exceptions relating to confidentiality contained 
+              in the Terms of Use of DENMARK, to which have separately agreed.
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 4 - 0
src/app/components/terms/terms.component.scss

@@ -0,0 +1,4 @@
+.card-body {
+  line-height: 2;
+  text-align: justify;
+}

+ 25 - 0
src/app/components/terms/terms.component.spec.ts

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

+ 15 - 0
src/app/components/terms/terms.component.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-terms',
+  templateUrl: './terms.component.html',
+  styleUrls: ['./terms.component.scss']
+})
+export class TermsComponent implements OnInit {
+  title:string = "Términos y Condiciones"
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 3 - 2
src/app/layouts/admin/admin.component.html

@@ -4,8 +4,9 @@
         <div class="sidebar-background" ></div>
     </div>
     <div class="main-panel">
-        <app-navbar></app-navbar>
-        <router-outlet></router-outlet>
+      <app-navbar></app-navbar>
+      <router-outlet></router-outlet>
+      <app-footer></app-footer>
     </div>
     <!--
     <div class="fixed-plugin">

+ 6 - 7
src/app/layouts/admin/admin.module.ts

@@ -4,13 +4,10 @@ import { RouterModule } from '@angular/router';
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { LeafletModule } from "@asymmetrik/ngx-leaflet";
-
 import { ChartsModule } from 'ng2-charts';
-import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
+import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
 import { AngularMyDatePickerModule } from 'angular-mydatepicker';
 
-
-
 import { AdminLayoutRoutes } from './admin.routing';
 import { DashboardComponent } from '../../components/dashboard/dashboard.component';
 import { ProfileComponent } from '../../components/profile/profile.component';
@@ -29,7 +26,6 @@ import { NewUserComponent } from '@app/components/users/new-user/new-user.compon
 import { PluginsModule } from '../../components/plugins/plugins.module';
 
 import { MatTableExporterModule } from 'mat-table-exporter';
-
 import {
   MatButtonModule,
   MatInputModule,
@@ -44,8 +40,9 @@ import {
   MatSortModule
 
 } from '@angular/material';
-
+import { MatPasswordStrengthModule } from '@angular-material-extensions/password-strength';
 import { BreadcrumbModule, IconsModule } from 'angular-bootstrap-md'
+import { TermsComponent } from '@app/components/terms/terms.component';
 
 
 @NgModule({
@@ -70,7 +67,8 @@ import { BreadcrumbModule, IconsModule } from 'angular-bootstrap-md'
     LeafletModule,
     ChartsModule,
     NgbModule,
-    AngularMyDatePickerModule
+    AngularMyDatePickerModule,
+    MatPasswordStrengthModule
   ],
   declarations: [
     DashboardComponent,
@@ -85,6 +83,7 @@ import { BreadcrumbModule, IconsModule } from 'angular-bootstrap-md'
     NewPlantComponent,
     UsersComponent,
     NewUserComponent,
+    TermsComponent
   ]
 })
 

+ 5 - 0
src/app/layouts/admin/admin.routing.ts

@@ -14,6 +14,7 @@ import { NewPlantComponent } from '@app/components/plants/new-plant/new-plant.co
 import { UsersComponent } from '@app/components/users/users.component';
 import { NewUserComponent } from '@app/components/users/new-user/new-user.component';
 import { AuthGuard } from '@app/services/auth.guard';
+import { TermsComponent } from '@app/components/terms/terms.component';
 
 
 export const AdminLayoutRoutes: Routes = [
@@ -29,6 +30,10 @@ export const AdminLayoutRoutes: Routes = [
     component: AssetsComponent,
     data: {title: "Listado de plantas"}
   },
+  { path: 'terms', 
+    component: TermsComponent,
+    data: {title: "Términos y condiciones"}
+  },
   // General management
   { path: 'plants', 
     component: PlantsComponent,

+ 26 - 4
src/app/services/plants.service.ts

@@ -69,7 +69,6 @@ export class PlantsService extends PlantData {
     //return observableOf(this.listData.find(e => e.id === id));
   //}
 
-  
   getAssetsProducedEnergy() {
     return this.http.get(`${environment.apiUrl}/assets/energyProduced`)
     .pipe(
@@ -89,9 +88,6 @@ export class PlantsService extends PlantData {
     return observableOf(this.listData.find(e => e.id === id));
   }
 
- 
-  
-
   getOrganizationPlants(id:string)  {
     return this.http.get<any>(`${environment.apiUrl}/assets/${id}`)
     .pipe(
@@ -102,7 +98,33 @@ export class PlantsService extends PlantData {
       catchError(this.errorHandl)
     )
   }
+
+  createPlant(asset: { name :string,  country :string, 
+    city :string, address :string, distribuidora :string,
+    categoria_tarifaria: string, cod_tarifa:string, meters_installed?:any}): Observable<boolean> {
+      return this.http.post<any>(`${environment.productionApiUrl}/assets`, asset)
+      .pipe(
+        map(response => {
+          return response;
+        }),
+        catchError(this.errorHandl)
+      )  
+  }
+
+  updatePlant(id:string, asset: {  name :string,  country :string, 
+    city :string, address :string, distribuidora :string,
+    categoria_tarifaria: string, cod_tarifa:string, meters_installed?:any}): Observable<boolean> {
+      return this.http.put<any>(`${environment.productionApiUrl}/asset/${id}`, asset)
+      .pipe(
+        map(response => {
+          return response;
+        }),
+        catchError(this.errorHandl)
+      )  
+  }
   
+  
+
   errorHandl(error) {
     let errorMessage = '';
     if(error.error) {

+ 1 - 0
src/environments/environment.ts

@@ -7,6 +7,7 @@ export const environment = {
   apiUrl: 'https://api.inverlec.solar',
   //productionApiUrl: 'http://192.168.98.10:8888/api/v1',
   productionApiUrl: 'http://192.168.98.24:5000/api/v1',
+  //productionApiUrl: 'https://denmark.inverlec.solar/api/v1',
   appID: '55899b9ea53834f2736b65a3582b734b',
   gKey: '',
   config: {

+ 1 - 1
src/index.html

@@ -7,7 +7,7 @@
 
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
 
-    <title>Plant Viewer</title>
+    <title>DENMARK - Aplicación para visualizar sistemas fotovoltaicos @Inverlec</title>
 
     <meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
     <meta name="viewport" content="width=device-width" />