Procházet zdrojové kódy

Merge branch 'features' of onunez/soma-frontend into development

Oscar José Nuñez Chávez před 6 roky
rodič
revize
17b64d5ac2

+ 1 - 1
e2e/tsconfig.json

@@ -10,4 +10,4 @@
       "node"
     ]
   }
-}
+}

+ 8 - 11
src/app/components/assets/assets.component.ts

@@ -37,10 +37,10 @@ export class AssetsComponent implements OnInit {
   metersKeys:any;
   metersValues:any;
   view:string;
-  energyDay:any;
-  energyWeek:any;
-  energyMonth:any;
-  energyYear:any;
+  energyDay=0;
+  energyWeek=0;
+  energyMonth=0;
+  energyYear=0;
   environment:any;
   environmentCO2:any;
   environmentHouse:any;
@@ -147,10 +147,10 @@ export class AssetsComponent implements OnInit {
       // 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;
-        this.energyWeek = this.eProduced.thisWeek.total_energy_kWh > 0 ? (this.eProduced.thisWeek.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisWeek.total_energy_kWh
-        this.energyMonth = this.eProduced.thisMonth.total_energy_kWh > 0 ? (this.eProduced.thisMonth.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisMonth.total_energy_kWh
-        this.energyYear = this.eProduced.lifeTime.total_energy_kWh > 0 ? (this.eProduced.lifeTime.total_energy_kWh/1000).toFixed(2) : this.eProduced.lifeTime.total_energy_kWh
+        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
       });
 
       this.logsService.getAssetEnviromentalStats(this.organizationId).subscribe(resp => {
@@ -472,9 +472,6 @@ export class AssetsComponent implements OnInit {
     let chart = document.getElementById("chart-wrapper");
     chart.style.display = "block";
     table.style.display = "none";
-    let foo = this.metersData; 
-    Object.values(foo)
-    console.log(Object.values(foo));
     // Select an interval according to the API permitted param
     let chartT:string;
     switch (chartType)

+ 1 - 8
src/app/components/dashboard/dashboard.component.ts

@@ -96,10 +96,6 @@ export class DashboardComponent implements OnInit {
     
     this.plantsService.getAllAssets().subscribe(res => {
       this.listAssets = res["data"]["assets"];
-
-      console.log(this.listAssets);
-      console.log("assets");
-      
       this.dataSource.data = this.listAssets;
       this.dataSource.paginator = this.paginator;
       this.dataSource.sort = this.sort;
@@ -138,12 +134,9 @@ export class DashboardComponent implements OnInit {
     ];
 
     setTimeout(() => {
-     
-
-      if (this.listAssets != undefined) {
+       if (this.listAssets != undefined) {
         this.addMarkers();
       }
-
       Swal.close();
     }, 1800);
 

+ 3 - 3
src/app/components/login/login.component.html

@@ -13,11 +13,11 @@
             <form [formGroup]="loginForm" (ngSubmit)="login()">
               <div class="form-group">
                 <label for="email">Correo electrónico</label>
-                
+
                 <input type="text" name="email" class="form-control"
-                formControlName="email" email [ngClass]="{ 'is-invalid': submitted && f.email.errors }"/>
+                formControlName="email" [ngClass]="{ 'is-invalid': submitted && f.email.errors }" email/>
                 <div *ngIf="submitted && f.email.errors" class="invalid-feedback">
-                  <div *ngIf="f.email.errors.required">Ingresar un correo válido</div>
+                  <div>Ingresar un correo válido</div>
                 </div>
   
               </div>

+ 1 - 1
src/app/components/login/login.component.ts

@@ -18,7 +18,7 @@ export class LoginComponent implements OnInit {
 
   ngOnInit() {
     this.loginForm = this.formBuilder.group({
-      email: ['', Validators.required, Validators.email],
+      email: ['', [Validators.required, Validators.email]],
       password: ['', Validators.required]
     });
   }

+ 0 - 1
src/app/components/organizations/organizations.component.ts

@@ -141,7 +141,6 @@ export class OrganizationsComponent implements OnInit {
     else {
       is_allowed = true;
     }
-    console.log(is_allowed);
     return is_allowed
   }
 

+ 0 - 1
src/app/components/plants/plants.component.ts

@@ -71,7 +71,6 @@ export class PlantsComponent implements OnInit {
     else {
       is_allowed = true;
     }
-    console.log(is_allowed);
     return is_allowed
   }
 

+ 1 - 1
src/app/components/shared/navbar/navbar.component.html

@@ -17,7 +17,7 @@
     <div class="collapse navbar-collapse justify-content-end" id="navigation">
       <ul class="navbar-nav">
         <li class="nav-item">
-          <a class="nav-link" [routerLink]="[dashboard]"  title="Dashboard">
+          <a class="nav-link" [routerLink]="['/dashboard']"  title="Dashboard">
             <i class="material-icons">dashboard</i>
             <p>
               <span class="d-lg-none d-md-block">Stats</span>

+ 10 - 0
src/app/components/shared/navbar/navbar.component.ts

@@ -7,6 +7,7 @@ import { Router, ActivatedRoute } from '@angular/router';
 //import { AuthenticationService } from 'src/app/services/authentication.service';
 import { AdminLayoutRoutes } from 'src/app/layouts/admin/admin.routing';
 import { AuthService } from '../../../services/auth2.service';
+import Swal from 'sweetalert2';
 
 @Component({
   selector: 'app-navbar',
@@ -146,8 +147,17 @@ export class NavbarComponent implements OnInit {
     };
 
     logout() {
+
+      Swal.fire({
+        allowOutsideClick: false,
+        type: 'info',
+        text: 'Espere por favor...'
+      });
+      Swal.showLoading();
+
       this.auth.logout().subscribe(success => {
         if (success) {
+          Swal.close();
           window.location.href="";
         }
       });

+ 2 - 2
src/app/components/shared/sidebar/sidebar.component.html

@@ -34,10 +34,10 @@
     </ul>
     <ul *ngIf="adminMenu" class="nav">
       <li class="nav-item">
-        <span class="nav-link">
+        <a class="nav-link" title="Administración" href="javascript:void(0)" style="cursor: unset;">
           <i class="material-icons">settings_application</i>
           <p>Administración</p>
-        </span>
+        </a>
       </li>
       <li routerLinkActive="active" *ngFor="let menuItem of adminMenuItems" class="{{menuItem.class}} nav-item">
         <a class="nav-link" [routerLink]="[menuItem.path]" *ngIf="menuItem.allowed_roles.indexOf(+role_number)>-1"> 

+ 43 - 38
src/app/components/users/new-user/new-user.component.html

@@ -23,7 +23,7 @@
 
           <div class="card">
             <div class="card-header card-header-icon card-header-rose">
-              <div class="card-icon"><i class="material-icons">map</i></div>
+              <div class="card-icon"><i class="material-icons">person_add</i></div>
               <h4 class="card-title">Nuevo Usuario - <small class="category">Complete la información básica</small></h4>
             </div>
             <div class="card-body">              
@@ -58,48 +58,48 @@
                     <br>
                     
                     <div class="form-check form-check-inline">
-                        <input class="form-check-input" type="radio" formControlName="role" id="roleRadios1" value="0" 
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
-                        <label class="form-check-label" for="roleRadios1">
-                          Invitado
-                        </label>
-                      </div>
-                      <div class="form-check form-check-inline">
-                        <input class="form-check-input" type="radio" formControlName="role" id="roleRadios2" value="1" 
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
-                        <label class="form-check-label" for="roleRadios2">
-                          Usuario
-                        </label>
-                      </div>
-                      <div class="form-check form-check-inline">
-                        <input class="form-check-input" type="radio" formControlName="role" id="roleRadios3" value="2" 
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
-                        <label class="form-check-label" for="roleRadios3">
-                          Administrador
-                        </label>
-                      </div>
-                      <div class="form-check form-check-inline">
-                        <input class="form-check-input" type="radio" formControlName="role" id="roleRadios4" value="3" 
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
-                        <label class="form-check-label" for="roleRadios4">
-                          Super Admin
-                        </label>
-                      </div>
-                      
-                    <!--<select class="form-control" formControlName="role" [ngClass]="{ 'is-invalid': submitted && f.role.errors }" >
-                      <option>Seleccione una opción</option>
-                      <option value="0">Invitado</option>
-                      <option value="1">Usuario</option>
-                      <option value="2">Administrador</option>
-                      <option value="3">Super Admin</option>
-                    </select> -->
-                    
+                      <input class="form-check-input" type="radio" formControlName="role" id="roleRadios1" value="0" 
+                      [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
+                      <label class="form-check-label" for="roleRadios1">
+                        Invitado
+                      </label>
+                    </div>
+                    <div class="form-check form-check-inline">
+                      <input class="form-check-input" type="radio" formControlName="role" id="roleRadios2" value="1" 
+                      [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
+                      <label class="form-check-label" for="roleRadios2">
+                        Usuario
+                      </label>
+                    </div>
+                    <div class="form-check form-check-inline">
+                      <input class="form-check-input" type="radio" formControlName="role" id="roleRadios3" value="2" 
+                      [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
+                      <label class="form-check-label" for="roleRadios3">
+                        Administrador
+                      </label>
+                    </div>
+                    <div class="form-check form-check-inline">
+                      <input class="form-check-input" type="radio" formControlName="role" id="roleRadios4" value="3" 
+                      [ngClass]="{ 'is-invalid': submitted && f.role.errors }">
+                      <label class="form-check-label" for="roleRadios4">
+                        Super Admin
+                      </label>
+                    </div>
+                  </div>
+
+                  <div class="form-group" *ngIf="!isLoadingOrganization; else loadingTmpl">
+                    <label>Organizaciones:</label>
+                    <div *ngFor="let item of listOrganization; let i = index" class="checkbox">
+                      <label>
+                        <input type="checkbox" [formControl]="organizationsFormGroup?.controls[item.id]" /> {{ item.name }}
+                      </label>
+                    </div>    
                   </div>
+                  
                   <br>
                   <button class="btn btn-primary">
                     Crear usuario
                   </button>
-                  <!--<div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
                 </form>
               </div>
             </div>
@@ -111,3 +111,8 @@
     </div>          
   </div>
 </div>
+
+
+<ng-template #loadingTmpl>
+  <div>Cargando...</div>
+</ng-template>

+ 3 - 0
src/app/components/users/new-user/new-user.component.scss

@@ -0,0 +1,3 @@
+.card-header-rose {
+  color: #fff;
+}

+ 86 - 33
src/app/components/users/new-user/new-user.component.ts

@@ -1,7 +1,8 @@
 import { Component, OnInit } from '@angular/core';
-import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
 import { UserService } from '@app/services/user.service';
 import Swal from 'sweetalert2';
+import { OrganizationsService } from '@app/services/organizations.service';
 
 @Component({
   selector: 'app-new-user',
@@ -12,24 +13,74 @@ export class NewUserComponent implements OnInit {
   title:string = "Nuevo usuario"; 
   userForm: FormGroup;
   submitted: boolean= false;
+  isLoadingOrganization: boolean;
+  listOrganization: any;
+  selectedHobbiesNames: [string];
 
 
-  constructor(private userService: UserService, private formBuilder: FormBuilder) {
+  constructor(private userService: UserService, private formBuilder: FormBuilder, private orgService: OrganizationsService) {
   }
 
-  ngOnInit() {
+
+  get organizationsFormArr(): FormArray {
+    return this.f && <FormArray>this.f.organizationsFormArr
+  }
+
+  get organizationsFormGroup(): FormGroup {
+    return this.f && <FormGroup>this.f.organizationsFormGroup
+  }
+
+  get organizationsFormGroupSelectedIds(): string[] {
+    let ids: string[] = [];
+    for (var key in this.organizationsFormGroup.controls) {
+      if (this.organizationsFormGroup.controls[key].value) {
+        ids.push(key);
+      }
+      else {
+        ids = ids.filter(id => id !== key);
+      }
+    }
+    return ids;
+  }
 
 
+
+  ngOnInit() {
+    this.isLoadingOrganization = true;
     this.userForm = this.formBuilder.group({
-      first_name: ['', Validators.required],
-      last_name: ['', Validators.required],
-      email: ['', Validators.required],
-      role: ['', Validators.required],
+      first_name: [''],
+      last_name: [''],
+      email: [''],
+      role: [''],
     });
+
+    this.orgService.getAllOrganizations().subscribe(ans => {
+      this.isLoadingOrganization = false;
+      this.listOrganization = ans["data"]["organizations"];
+      this.userForm.addControl("organizationsFormGroup", this.buildOrganizationFormGroup(this.listOrganization));
+
+    }, (err) => {
+      Swal.fire({
+        type: 'error',
+        title: 'Error en el servidor',
+        text: "No su pudo obtener la informacion"
+      });
+    });
+
+ 
   }
 
-  get f() { return this.userForm.controls; }
+  buildOrganizationFormGroup(organizations:any, selectedOrganizationIds: string[] = []): FormGroup {
+    let group = this.formBuilder.group({});
+    organizations.forEach(category => {
+      let isSelected = selectedOrganizationIds.some(id => id === category.id);
+      group.addControl(category.id, this.formBuilder.control(isSelected));
+    })
+    return group;
+  }
 
+  get f() { return this.userForm.controls; }
+  
   createUser() {
     this.submitted = true;
 
@@ -37,31 +88,33 @@ export class NewUserComponent implements OnInit {
     if (this.userForm.invalid) {
       return;
     }
-    
-      this.userService.createUser(
-        {
-          first_name: this.f.first_name.value,
-          last_name: this.f.last_name.value,
-          email: this.f.email.value,
-          role: +this.f.role.value,
-        }
-      )
-      .subscribe(success => {
-        if (success) {
-          Swal.fire({
-            allowOutsideClick: false,
-            type: 'success',
-            showCancelButton: false,
-            title: 'Exito',
-            confirmButtonText: 'El usuario ha sido creado'
-          }).then((result) => {
-            if (result.value) {
-              window.location.href="#/users";
-            }
-          });
-        }
-        
-      });
+  
+
+    this.userService.createUser(
+      {
+        first_name: this.f.first_name.value,
+        last_name: this.f.last_name.value,
+        email: this.f.email.value,
+        role: +this.f.role.value,
+        organizations: this.organizationsFormGroupSelectedIds
+      }
+    )
+    .subscribe(success => {
+      if (success) {
+        Swal.fire({
+          allowOutsideClick: false,
+          type: 'success',
+          showCancelButton: false,
+          title: 'Exito',
+          confirmButtonText: 'El usuario ha sido creado'
+        }).then((result) => {
+          if (result.value) {
+            window.location.href="#/users";
+          }
+        });
+      }
+      
+    }); 
   }
 
 

+ 7 - 2
src/app/services/auth2.service.ts

@@ -30,6 +30,7 @@ export class AuthService {
   }
 
   logout() {
+    // Agregar endpoint para revocar TOKEN REFRESH
     return this.http.post<any>(`${environment.productionApiUrl}/auth/logout`, {
     }).pipe(
       tap(() => this.doLogoutUser()),
@@ -55,7 +56,11 @@ export class AuthService {
       'Authorization': `Bearer ${refreshToken}`
     }).pipe(tap((tokens: Token) => {
       this.storeJwtToken(tokens["data"]["access_token"]);
-    }));
+    },
+      (error) => {
+        console.log("ERROR REFRESHING TOKEN")
+      }
+    ));
   }
 
   getJwtToken() {
@@ -88,7 +93,7 @@ export class AuthService {
     localStorage.setItem(this.REFRESH_TOKEN, tokens["data"]["user"].refresh);
   }
 
-  private removeTokens() {
+  removeTokens() {
     localStorage.removeItem(this.USER_MENU);
     localStorage.removeItem(this.JWT_TOKEN);
     localStorage.removeItem(this.REFRESH_TOKEN);

+ 17 - 4
src/app/services/token.interceptor.ts

@@ -26,9 +26,17 @@ export class TokenInterceptor implements HttpInterceptor {
     }
     
     return next.handle(request).pipe(catchError(error => {
-      if (error instanceof HttpErrorResponse && error.status === 401) {
-        return this.handle401Error(request, next);
-      } else {
+
+      // Erase storage if response code from auth refresh gives 401 or 422 error
+      if (request.url.indexOf("auth/refresh")!= -1 && error instanceof HttpErrorResponse){
+        this.authService.removeTokens();
+        window.location.href="#/login";
+      }
+
+      if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 422)) {
+        return this.handle4xxError(request, next);
+      } 
+      else {
         return throwError(error);
       }
     }));      
@@ -43,7 +51,8 @@ export class TokenInterceptor implements HttpInterceptor {
     });
   }
 
-  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
+  // Cuando el endpoint devuelva 401 debe mandarlo al login y destruir las variables del storage
+  private handle4xxError(request: HttpRequest<any>, next: HttpHandler) {
     if (!this.isRefreshing) {
       this.isRefreshing = true;
       this.refreshTokenSubject.next(null);
@@ -55,6 +64,10 @@ export class TokenInterceptor implements HttpInterceptor {
           return next.handle(this.addToken(request, token["data"]["access_token"]));
         }));
 
+
+        
+
+
     } else {
       return this.refreshTokenSubject.pipe(
         filter(token => token != null),

+ 1 - 1
src/app/services/user.service.ts

@@ -20,7 +20,7 @@ export class UserService {
   }
 
   createUser(user: { first_name :string, last_name :string, 
-    email :string, role :number }): Observable<boolean> {
+    email :string, role :number, organizations?: any }): Observable<boolean> {
       return this.http.post<any>(`${environment.productionApiUrl}/users`, user)
       .pipe(
         map(response => {