Sfoglia il codice sorgente

Added basic structure to the project

Oscar José Nuñez Chávez 6 anni fa
parent
commit
0f76017d8c
100 ha cambiato i file con 3507 aggiunte e 609 eliminazioni
  1. 29 4
      angular.json
  2. 271 105
      package-lock.json
  3. 29 0
      package.json
  4. 41 6
      src/app/app-routing.module.ts
  5. 0 486
      src/app/app.component.html
  6. 55 8
      src/app/app.module.ts
  7. 20 0
      src/app/components/arbitrations/arbitrations.component.html
  8. 0 0
      src/app/components/arbitrations/arbitrations.component.scss
  9. 25 0
      src/app/components/arbitrations/arbitrations.component.spec.ts
  10. 14 0
      src/app/components/arbitrations/arbitrations.component.ts
  11. 115 0
      src/app/components/confirm-account/confirm-account.component.html
  12. 113 0
      src/app/components/confirm-account/confirm-account.component.scss
  13. 25 0
      src/app/components/confirm-account/confirm-account.component.spec.ts
  14. 139 0
      src/app/components/confirm-account/confirm-account.component.ts
  15. 7 0
      src/app/components/dashboard/dashboard.component.html
  16. 28 0
      src/app/components/dashboard/dashboard.component.scss
  17. 25 0
      src/app/components/dashboard/dashboard.component.spec.ts
  18. 29 0
      src/app/components/dashboard/dashboard.component.ts
  19. 31 0
      src/app/components/investment-proposals/investment-proposals.component.html
  20. 0 0
      src/app/components/investment-proposals/investment-proposals.component.scss
  21. 25 0
      src/app/components/investment-proposals/investment-proposals.component.spec.ts
  22. 20 0
      src/app/components/investment-proposals/investment-proposals.component.ts
  23. 31 0
      src/app/components/investments/investments.component.html
  24. 0 0
      src/app/components/investments/investments.component.scss
  25. 25 0
      src/app/components/investments/investments.component.spec.ts
  26. 14 0
      src/app/components/investments/investments.component.ts
  27. 45 0
      src/app/components/login/login.component.html
  28. 134 0
      src/app/components/login/login.component.scss
  29. 25 0
      src/app/components/login/login.component.spec.ts
  30. 153 0
      src/app/components/login/login.component.ts
  31. 20 0
      src/app/components/performances/performances.component.html
  32. 0 0
      src/app/components/performances/performances.component.scss
  33. 25 0
      src/app/components/performances/performances.component.spec.ts
  34. 14 0
      src/app/components/performances/performances.component.ts
  35. 38 0
      src/app/components/plugins/plugins.module.ts
  36. 54 0
      src/app/components/plugins/validator/validator.component.ts
  37. 19 0
      src/app/components/profile/profile.component.html
  38. 6 0
      src/app/components/profile/profile.component.scss
  39. 25 0
      src/app/components/profile/profile.component.spec.ts
  40. 23 0
      src/app/components/profile/profile.component.ts
  41. 9 0
      src/app/components/shared/footer/footer.component.html
  42. 0 0
      src/app/components/shared/footer/footer.component.scss
  43. 25 0
      src/app/components/shared/footer/footer.component.spec.ts
  44. 15 0
      src/app/components/shared/footer/footer.component.ts
  45. 47 0
      src/app/components/shared/navbar/navbar.component.html
  46. 0 0
      src/app/components/shared/navbar/navbar.component.scss
  47. 25 0
      src/app/components/shared/navbar/navbar.component.spec.ts
  48. 186 0
      src/app/components/shared/navbar/navbar.component.ts
  49. 25 0
      src/app/components/shared/shared.module.ts
  50. 78 0
      src/app/components/shared/sidebar/sidebar.component.html
  51. 9 0
      src/app/components/shared/sidebar/sidebar.component.scss
  52. 25 0
      src/app/components/shared/sidebar/sidebar.component.spec.ts
  53. 97 0
      src/app/components/shared/sidebar/sidebar.component.ts
  54. 22 0
      src/app/components/terms/terms.component.html
  55. 4 0
      src/app/components/terms/terms.component.scss
  56. 25 0
      src/app/components/terms/terms.component.spec.ts
  57. 15 0
      src/app/components/terms/terms.component.ts
  58. 171 0
      src/app/components/users/new-user/new-user.component.html
  59. 3 0
      src/app/components/users/new-user/new-user.component.scss
  60. 25 0
      src/app/components/users/new-user/new-user.component.spec.ts
  61. 95 0
      src/app/components/users/new-user/new-user.component.ts
  62. 80 0
      src/app/components/users/users.component.html
  63. 0 0
      src/app/components/users/users.component.scss
  64. 25 0
      src/app/components/users/users.component.spec.ts
  65. 76 0
      src/app/components/users/users.component.ts
  66. 55 0
      src/app/layouts/admin/admin.component.html
  67. 0 0
      src/app/layouts/admin/admin.component.scss
  68. 25 0
      src/app/layouts/admin/admin.component.spec.ts
  69. 161 0
      src/app/layouts/admin/admin.component.ts
  70. 73 0
      src/app/layouts/admin/admin.module.ts
  71. 88 0
      src/app/layouts/admin/admin.routing.ts
  72. 3 0
      src/app/models/index.ts
  73. 4 0
      src/app/models/role.ts
  74. 4 0
      src/app/models/token.ts
  75. 18 0
      src/app/models/user.ts
  76. 28 0
      src/app/services/auth.guard.ts
  77. 113 0
      src/app/services/auth2.service.ts
  78. 13 0
      src/app/services/services.module.ts
  79. 84 0
      src/app/services/token.interceptor.ts
  80. 64 0
      src/app/services/user.service.ts
  81. BIN
      src/assets/img/cover.jpeg
  82. BIN
      src/assets/img/dawn.jpg
  83. BIN
      src/assets/img/desktop-pc-icon.png
  84. BIN
      src/assets/img/favicon.png
  85. BIN
      src/assets/img/html.png
  86. BIN
      src/assets/img/inverlec_logo.png
  87. BIN
      src/assets/img/login-bg.png
  88. BIN
      src/assets/img/logo-inverlec.png
  89. BIN
      src/assets/img/logo-inverlec2.png
  90. BIN
      src/assets/img/logo.png
  91. BIN
      src/assets/img/logo_inverlec_inv_m.png
  92. BIN
      src/assets/img/logo_inverlec_inv_p.png
  93. BIN
      src/assets/img/marker-icon.png
  94. BIN
      src/assets/img/me-logo.png
  95. BIN
      src/assets/img/sidebar-1.jpg
  96. BIN
      src/assets/img/sidebar-2.jpg
  97. BIN
      src/assets/img/sidebar-3.jpg
  98. BIN
      src/assets/img/sidebar-4.jpg
  99. BIN
      src/assets/img/tv-icon.png
  100. BIN
      src/assets/img/waves-alt.png

+ 29 - 4
angular.json

@@ -28,9 +28,21 @@
               "src/assets"
             ],
             "styles": [
-              "src/styles.scss"
+              "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
+              "node_modules/perfect-scrollbar/css/perfect-scrollbar.css",
+              "src/assets/scss/material-dashboard.scss",
+              "src/styles.scss",
+              "node_modules/bootstrap-select/dist/css/bootstrap-select.css"
             ],
-            "scripts": []
+            "scripts": [
+              "node_modules/jquery/dist/jquery.js",
+              "node_modules/popper.js/dist/umd/popper.js",
+              "node_modules/arrive/src/arrive.js",
+              "node_modules/moment/moment.js",
+              "node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js",
+              "node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js",
+              "node_modules/bootstrap-select/dist/js/bootstrap-select.min.js"
+            ]
           },
           "configurations": {
             "production": {
@@ -93,9 +105,22 @@
               "src/assets"
             ],
             "styles": [
-              "src/styles.scss"
+              "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
+              "node_modules/font-awesome/scss/font-awesome.scss",
+              "node_modules/perfect-scrollbar/css/perfect-scrollbar.css",
+              "src/assets/scss/material-dashboard.scss",
+              "src/styles.scss",
+              "node_modules/bootstrap-select/dist/css/bootstrap-select.css"
             ],
-            "scripts": []
+            "scripts": [
+              "node_modules/jquery/dist/jquery.js",
+              "node_modules/popper.js/dist/umd/popper.js",
+              "node_modules/arrive/src/arrive.js",
+              "node_modules/moment/moment.js",
+              "node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js",
+              "node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js",
+              "node_modules/bootstrap-select/dist/js/bootstrap-select.min.js"
+            ]
           }
         },
         "lint": {

File diff suppressed because it is too large
+ 271 - 105
package-lock.json


+ 29 - 0
package.json

@@ -11,15 +11,43 @@
   },
   "private": true,
   "dependencies": {
+    "@angular-material-extensions/password-strength": "^4.0.1",
     "@angular/animations": "~8.2.14",
+    "@angular/cdk": "^8.2.3",
     "@angular/common": "~8.2.14",
     "@angular/compiler": "~8.2.14",
     "@angular/core": "~8.2.14",
     "@angular/forms": "~8.2.14",
+    "@angular/material": "^8.2.3",
     "@angular/platform-browser": "~8.2.14",
     "@angular/platform-browser-dynamic": "~8.2.14",
     "@angular/router": "~8.2.14",
+    "@fortawesome/angular-fontawesome": "^0.5.0",
+    "@fortawesome/fontawesome-free": "^5.12.0",
+    "@fortawesome/fontawesome-svg-core": "^1.2.26",
+    "@types/crypto-js": "^3.1.43",
+    "angular-bootstrap-md": "^8.8.1",
+    "angular-datatables": "^8.0.0",
+    "angular-mydatepicker": "^0.3.4",
+    "arrive": "^2.4.1",
+    "bootstrap": "^4.4.1",
+    "bootstrap-material-design": "4.1.2",
+    "bootstrap-select": "^1.13.12",
+    "chart.js": "^2.9.3",
+    "classlist.js": "^1.1.20150312",
+    "crypto-js": "^3.1.9-1",
+    "hammerjs": "^2.0.8",
+    "jquery": "^3.4.1",
+    "mat-table-exporter": "^1.2.2",
+    "moment": "^2.24.0",
+    "ngx-animating-datepicker": "^1.2.1",
+    "ngx-bootstrap": "^5.1.1",
+    "ngx-daterangepicker": "^1.1.1",
+    "perfect-scrollbar": "^1.4.0",
+    "popper.js": "^1.15.0",
+    "print-js": "^1.0.63",
     "rxjs": "~6.4.0",
+    "sweetalert2": "^9.5.4",
     "tslib": "^1.10.0",
     "zone.js": "~0.9.1"
   },
@@ -39,6 +67,7 @@
     "karma-coverage-istanbul-reporter": "~2.0.1",
     "karma-jasmine": "~2.0.1",
     "karma-jasmine-html-reporter": "^1.4.0",
+    "prettier": "^1.19.1",
     "protractor": "~5.4.0",
     "ts-node": "~7.0.0",
     "tslint": "~5.15.0",

+ 41 - 6
src/app/app-routing.module.ts

@@ -1,11 +1,46 @@
-import { NgModule } from '@angular/core';
-import { Routes, RouterModule } from '@angular/router';
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { BrowserModule } from "@angular/platform-browser";
+import { Routes, RouterModule } from "@angular/router";
+import { AdminModule } from "./layouts/admin/admin.module";
 
+import { AdminComponent } from "./layouts/admin/admin.component";
+import { LoginComponent } from "./components/login/login.component";
+import { AuthGuard } from "./services/auth.guard";
+import { Role } from "./models/role";
+import { ConfirmAccountComponent } from "./components/confirm-account/confirm-account.component";
 
-const routes: Routes = [];
+const routes: Routes = [
+  {
+    path: "",
+    redirectTo: "dashboard",
+    pathMatch: "full"
+  },
+  {
+    path: "",
+    component: AdminComponent,
+    canActivate: [AuthGuard],
+    children: [
+      {
+        path: "",
+        loadChildren: "./layouts/admin/admin.module#AdminModule" //() => AdminModule
+      }
+    ]
+  },
+  { path: "login", component: LoginComponent },
+  { path: "confirm-account", component: ConfirmAccountComponent },
+  { path: "**", redirectTo: "" }
+];
 
 @NgModule({
-  imports: [RouterModule.forRoot(routes)],
-  exports: [RouterModule]
+  imports: [
+    CommonModule,
+    BrowserModule,
+    RouterModule.forRoot(routes, {
+      useHash: true,
+      onSameUrlNavigation: "reload"
+    })
+  ],
+  exports: []
 })
-export class AppRoutingModule { }
+export class AppRoutingModule {}

File diff suppressed because it is too large
+ 0 - 486
src/app/app.component.html


+ 55 - 8
src/app/app.module.ts

@@ -1,18 +1,65 @@
-import { BrowserModule } from '@angular/platform-browser';
-import { NgModule } from '@angular/core';
+import { BrowserModule } from "@angular/platform-browser";
+import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
+import { NgModule } from "@angular/core";
+import { AppRoutingModule } from "./app-routing.module";
+import { AppComponent } from "./app.component";
+import { FormsModule, ReactiveFormsModule } from "@angular/forms";
+import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
+import { registerLocaleData, DatePipe } from "@angular/common";
+import { RouterModule } from "@angular/router";
+import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
 
-import { AppRoutingModule } from './app-routing.module';
-import { AppComponent } from './app.component';
+// Internationalization i18n
+import localeEs from "@angular/common/locales/es";
+import localeEsExtra from "@angular/common/locales/extra/es";
+registerLocaleData(localeEs, "es-Es", localeEsExtra);
+
+// used to create fake backend
+//import { fakeBackendProvider } from './helpers';
+//import { JwtInterceptor, ErrorInterceptor } from './helpers';
+
+import { SharedModule } from "./components/shared/shared.module";
+
+import { AdminComponent } from "./layouts/admin/admin.component";
+import { AngularMyDatePickerModule } from "angular-mydatepicker";
+
+import { PluginsModule } from "./components/plugins/plugins.module";
+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({
   declarations: [
-    AppComponent
+    AppComponent,
+    AdminComponent,
+    LoginComponent,
+    ConfirmAccountComponent
   ],
   imports: [
     BrowserModule,
-    AppRoutingModule
+    BrowserAnimationsModule,
+    FormsModule,
+    ReactiveFormsModule,
+    HttpClientModule,
+    SharedModule,
+    RouterModule,
+    AppRoutingModule,
+    PluginsModule,
+    AngularMyDatePickerModule,
+    FontAwesomeModule,
+    MatPasswordStrengthModule.forRoot()
+  ],
+  providers: [
+    { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true },
+    [DatePipe]
+
+    //{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
+    //AuthenticationService,
+    // provider used to create fake backend
+    //fakeBackendProvider
   ],
-  providers: [],
   bootstrap: [AppComponent]
 })
-export class AppModule { }
+export class AppModule {}

+ 20 - 0
src/app/components/arbitrations/arbitrations.component.html

@@ -0,0 +1,20 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">Arbitrajes</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 0 - 0
src/app/components/arbitrations/arbitrations.component.scss


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

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

+ 14 - 0
src/app/components/arbitrations/arbitrations.component.ts

@@ -0,0 +1,14 @@
+import { Component, OnInit } from "@angular/core";
+
+@Component({
+  selector: "app-arbitrations",
+  templateUrl: "./arbitrations.component.html",
+  styleUrls: ["./arbitrations.component.scss"]
+})
+export class ArbitrationsComponent implements OnInit {
+  title: string = "Arbitrajes";
+
+  constructor() {}
+
+  ngOnInit() {}
+}

+ 115 - 0
src/app/components/confirm-account/confirm-account.component.html

@@ -0,0 +1,115 @@
+<div id="wrapper">
+  <div class="vertical-align-wrap">
+    <div class="vertical-align-middle auth-main">
+      <div class="auth-box">
+        <div class="top">
+          <img alt="Inverlec" src="./assets/img/inverlec_logo.png">
+        </div>
+
+        <div class="card">
+          <div class="header">
+            <h1 class="lead">Confirmación de cuenta</h1>
+          </div>
+          <div class="body" *ngIf="validToken">
+            <form [formGroup]="activateForm" (ngSubmit)="activateAccount()">
+
+              <div class="form-group">
+                <label for="email">Correo electrónico</label>
+                <input type="text" class="form-control"
+                formControlName="email" required email readonly />
+              </div>
+
+              <div class="form-group">
+                <label for="name">Nombre</label>
+                <input type="text" class="form-control"
+                formControlName="first_name" [ngClass]="{ 'is-invalid': submitted && f.first_name.errors }"/>
+                <div *ngIf="submitted && f.first_name.errors" class="invalid-feedback">
+                  <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>
+              </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>
+
+              <div class="form-group">
+                <label for="confirm_password">Confirmar contraseña</label>
+                <input type="password" class="form-control"
+                formControlName="confirm_password" [ngClass]="{ 'is-invalid': submitted && f.confirm_password.errors }"/>
+                <div *ngIf="submitted && f.confirm_password.errors" class="invalid-feedback">
+                  <div *ngIf="f.confirm_password.errors.required">Campo requerido</div>
+                  <div *ngIf="f.confirm_password.errors.mustMatch">Las contraseñas deben coincidir</div>
+                </div>
+              </div>
+    
+              <br>
+
+              <div class="div-center">
+                <button class="btn btn-primary" type="submit"> 
+                  Confirmar cuenta
+                </button>
+              </div>
+
+            </form>
+          </div>
+
+          <div class="body" *ngIf="invalidToken">
+            <div class="tokenError">
+              <h3>
+                {{errorMessage}}
+              </h3>
+
+              <div *ngIf="userActivated">
+                <a class="btn btn-primary" [routerLink]="['/login']">
+                  Ir a inicio de sesion
+                </a>
+              </div>
+
+            </div>
+          </div>
+
+          <div class="body" *ngIf="successActivation">
+            <div class="tokenSuccess">
+              <h3>
+                {{activateMessage}}
+              </h3>
+
+              <a class="btn btn-primary" [routerLink]="['/login']">
+                Ir a inicio de sesion
+              </a>
+
+            </div>
+          </div>
+
+
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

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

@@ -0,0 +1,113 @@
+.hint-wrapper {
+  background: #eee;
+  border: 1px solid #aaa;
+  padding: 5px;
+  margin-bottom: 5px;
+}
+
+.vertical-align-wrap {
+  //position: absolute;
+  width: 100%;
+  height: 100%;
+  //display: table;
+}
+
+.vertical-align-middle {
+  //display: table-cell;
+  vertical-align: middle;
+}
+
+.auth-box {
+  width: 800px;
+  height: auto;
+  margin: 20px auto;
+
+  .top {
+    margin: 0 auto;
+    text-align: center;
+  }
+
+  .card {
+    padding: 25px;
+
+    .lead {
+      text-align: center;
+      font-size: 1.5rem;
+      color: #223d7d;
+    }
+  }
+
+  .div-center {
+    text-align: center;
+    margin: 0 auto;
+  }
+}
+
+.auth-main::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 200px;
+  height: 100%;
+  z-index: -1;
+  background: #223d7d; //#f0f0f0;
+}
+
+.auth-main:after {
+  content: '';
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  z-index: -2;
+  //background: #223d7d;
+  //background: url(../../assets/images/auth_bg.jpg) no-repeat top left fixed;
+}
+
+.card {
+  background: #fff;
+  transition: .5s;
+  border: 0;
+  margin-bottom: 30px;
+  border-radius: .55rem;
+  position: relative;
+  width: 100%;
+  box-shadow: 0 1px 2px 0 rgba(0,0,0,0.1);
+}
+
+.tokenError,
+.tokenSuccess {
+  padding: 40px 20px;
+  text-align: center;
+  margin-bottom: 20px;
+  font-weight: bold;
+}
+
+.tokenError {
+  color: #f44336;
+}
+
+.tokenSuccess {
+  color: #4caf50;
+}
+
+h3 {
+  font-size: 1.6rem;
+  margin-bottom: 30px;
+}
+
+@media screen and (max-width: 640px) {
+  .auth-box {
+      width: 90%;
+  }
+}
+
+@media screen and (max-width: 992px) {
+  .auth-box {
+      width: 80%;
+      margin: 0 auto;
+  }
+}
+

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

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

+ 139 - 0
src/app/components/confirm-account/confirm-account.component.ts

@@ -0,0 +1,139 @@
+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, PasswordStrengthValidator } from '../plugins/validator/validator.component';
+
+
+@Component({
+  selector: 'app-confirm-account',
+  templateUrl: './confirm-account.component.html',
+  styleUrls: ['./confirm-account.component.scss']
+})
+export class ConfirmAccountComponent implements OnInit {
+  token:string;
+  validToken:boolean;
+  activateForm: FormGroup;
+  errorMessage: string;
+  userActivated: boolean;
+  successActivation: boolean;
+  activateMessage: string;
+  invalidToken: boolean;
+  submitted: boolean = false;
+  showDetails: boolean;
+
+  constructor(private formBuilder: FormBuilder, private route: ActivatedRoute, private userService: UserService) {
+    this.route.queryParams.subscribe(params => {
+      this.token = params['token'];
+    });
+  }
+
+  ngOnInit() {
+    if (this.token !== null){
+      
+      this.userService.validateUserToken(
+        {
+          token: this.token
+        }
+      ).subscribe(res => {
+        
+        let userData = res["data"].user;
+
+        this.validToken = true;
+        this.activateForm = this.formBuilder.group({
+          // Load information
+          email: [(userData.email)],
+          first_name: [(userData.first_name),Validators.required],
+          last_name: [(userData.last_name),Validators.required],
+          password: ['',[Validators.required, Validators.minLength(8), PasswordStrengthValidator]],
+          confirm_password: ['',Validators.required]
+        },{
+          
+            validator: ValidatorComponent('password', 'confirm_password')
+        });
+      }, (err) => {
+       
+        this.userActivated = true;
+        this.invalidToken = true;
+        this.errorMessage = err.message;
+      });
+    
+    }
+    else {
+      this.invalidToken = true;
+      this.errorMessage = "No existe el token";
+    }
+  }
+
+  get f() { return this.activateForm.controls; }
+
+
+  activateAccount(){
+
+    this.submitted = true;
+
+    // stop here if form is invalid
+    if (this.activateForm.invalid) {
+      return;
+    }
+
+    this.userService.activateUser(
+      {
+        email: this.f.email.value,
+        first_name: this.f.first_name.value,
+        last_name: this.f.last_name.value,
+        password: this.f.password.value,
+        confirm_password: this.f.confirm_password.value,
+      }
+    ).subscribe(res => {
+      this.successActivation = true;
+      this.validToken = false;
+      this.activateMessage = "Usuario registrado con exito";
+
+    }, (err) => {
+      this.validToken = false;
+      this.errorMessage = err.message;
+    });
+    //
+
+  }
+
+}
+
+
+/*
+
+Swal.fire({
+      allowOutsideClick: false,
+      type: 'info',
+      text: 'Espere por favor...'
+    });
+    Swal.showLoading();
+
+    this.authService.login(
+      {
+        email: this.f.email.value,
+        password: this.f.password.value
+      }
+    )
+    .subscribe(success => {
+      if (success) {
+        window.location.href="#/dashboard";
+      }
+      else {
+        Swal.fire({
+          type: 'error',
+          title: 'No se pudo auntenticar',
+          text: "Email o contraseña incorrecta"
+        })  
+      }
+    },(err) => {
+      Swal.fire({
+        type: 'error',
+        title: 'Error en el servidor',
+        text: "No su pudo obtener la informacion"
+      });
+    });
+
+    */

+ 7 - 0
src/app/components/dashboard/dashboard.component.html

@@ -0,0 +1,7 @@
+<h2 class="floating-title">{{title}}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    Content
+  </div>
+</div>

+ 28 - 0
src/app/components/dashboard/dashboard.component.scss

@@ -0,0 +1,28 @@
+agm-map {
+  height: 300px;
+}
+
+.card-img-holder {
+  margin-bottom: 10px;
+}
+
+.hidden-element {
+  display: none;
+}
+
+.detail-box {
+  border: none;
+  border-radius: 0;
+  box-shadow: none;
+}
+
+.plant-detail {
+  h3 {
+    margin-top: 0;
+  }
+  button {
+    position: absolute;
+    bottom: 15px;
+  }
+}
+

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

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

+ 29 - 0
src/app/components/dashboard/dashboard.component.ts

@@ -0,0 +1,29 @@
+import { ActivatedRoute, Router } from '@angular/router';
+import { Component, OnInit, Input, Output, EventEmitter, OnDestroy, NgZone, ViewChild } from '@angular/core';
+import {MatPaginator} from '@angular/material/paginator';
+import {MatSort} from '@angular/material/sort';
+import {MatTableDataSource} from '@angular/material/table';
+
+import { of as observableOf, Observable, throwError, from } from 'rxjs';
+
+import * as moment from 'moment';
+import Swal from 'sweetalert2';
+
+
+@Component({
+  selector: 'app-dashboard',
+  templateUrl: './dashboard.component.html',
+  styleUrls: ['./dashboard.component.scss']
+})
+export class DashboardComponent implements OnInit {
+
+  title = "Dashboard";
+
+
+  constructor() {  }
+
+  ngOnInit(): void {
+    Swal.close()
+  }
+
+}

+ 31 - 0
src/app/components/investment-proposals/investment-proposals.component.html

@@ -0,0 +1,31 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">Propuestas de inversión</li>
+            </ol>
+          </nav>
+
+          <a class="btn btn-primary" href="#">
+            Nuevo registro
+          </a>
+        </div>
+      </div>
+
+      <div class="col-12">
+        <div class="align-container">
+          <h4><b>Listado de propuestas de inversiones</b></h4>
+        </div>
+      </div>
+      <br />
+    </div>
+  </div>
+</div>

+ 0 - 0
src/app/components/investment-proposals/investment-proposals.component.scss


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

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

+ 20 - 0
src/app/components/investment-proposals/investment-proposals.component.ts

@@ -0,0 +1,20 @@
+import { Component, ViewChild, OnInit } from "@angular/core";
+import { MatPaginator } from "@angular/material/paginator";
+import { MatSort } from "@angular/material/sort";
+import { MatTableDataSource } from "@angular/material/table";
+import Swal from "sweetalert2";
+import { Router } from "@angular/router";
+import { AuthService } from "@app/services/auth2.service";
+
+@Component({
+  selector: "app-investment-proposals",
+  templateUrl: "./investment-proposals.component.html",
+  styleUrls: ["./investment-proposals.component.scss"]
+})
+export class InvestmentProposalsComponent implements OnInit {
+  title: string = "Propuestas de inversión";
+
+  constructor(private router: Router, private authService: AuthService) {}
+
+  ngOnInit() {}
+}

+ 31 - 0
src/app/components/investments/investments.component.html

@@ -0,0 +1,31 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">Inversiones</li>
+            </ol>
+          </nav>
+
+          <a class="btn btn-primary" href="#">
+            Nuevo registro
+          </a>
+        </div>
+      </div>
+
+      <div class="col-12">
+        <div class="align-container">
+          <h4><b>Listado de inversiones</b></h4>
+        </div>
+      </div>
+      <br />
+    </div>
+  </div>
+</div>

+ 0 - 0
src/app/components/investments/investments.component.scss


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

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

+ 14 - 0
src/app/components/investments/investments.component.ts

@@ -0,0 +1,14 @@
+import { Component, OnInit } from "@angular/core";
+
+@Component({
+  selector: "app-investments",
+  templateUrl: "./investments.component.html",
+  styleUrls: ["./investments.component.scss"]
+})
+export class InvestmentsComponent implements OnInit {
+  title: string = "Inversiones";
+
+  constructor() {}
+
+  ngOnInit() {}
+}

+ 45 - 0
src/app/components/login/login.component.html

@@ -0,0 +1,45 @@
+<div id="wrapper">
+  <div class="vertical-align-wrap">
+    <div class="vertical-align-middle auth-main">
+      <div class="auth-box">
+        
+        <div class="card">
+          <div class="top d-block d-lg-none">
+            <img alt="Inverlec" src="./assets/img/inverlec_logo.png">
+          </div>
+
+          <div class="header">
+            <p class="lead">Iniciar sesión con tu cuenta</p>
+          </div>
+          <div class="body">
+            <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" [ngClass]="{ 'is-invalid': submitted && f.email.errors }" email/>
+                <div *ngIf="submitted && f.email.errors" class="invalid-feedback">
+                  <div>Ingresar un correo válido</div>
+                </div>
+  
+              </div>
+              <div class="form-group">
+                <label for="password">Contraseña</label>
+                <input type="password" name="password"  class="form-control"
+                formControlName="password" minlength="5"  [ngClass]="{ 'is-invalid': submitted && f.password.errors }"/>
+                <div *ngIf="submitted && f.password.errors" class="invalid-feedback">
+                  <div *ngIf="f.password.errors.required">Ingresar contraseña</div>
+                </div>
+  
+              </div>
+  
+              <button class="btn btn-primary" type="submit"> 
+                Iniciar sesión
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 134 - 0
src/app/components/login/login.component.scss

@@ -0,0 +1,134 @@
+.vertical-align-wrap {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  display: table;
+}
+
+.vertical-align-middle {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+.auth-box {
+  width: 400px;
+  height: auto;
+  margin-left: 130px;
+
+  .card {
+    padding: 25px;
+  }
+}
+
+.auth-main::before {
+  content: "";
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 600px;
+  height: 100%;
+  z-index: -1;
+  background: url("/assets/img/test1.png") no-repeat left top;
+  background-color: #223d7d;
+  background-size: cover;
+  background-position: 10%;
+}
+
+.auth-main:after {
+  content: "";
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 80%;
+  height: 100%;
+  z-index: -2;
+  background: url("/assets/img/inverlec_logo.png") no-repeat 70% center;
+  background-color: #fff;
+  //background: url(../../assets/images/auth_bg.jpg) no-repeat top left fixed;
+}
+
+.logo-box {
+  width: 400px;
+  float: right;
+  margin-right: 150px;
+}
+
+.card {
+  background: #fff;
+  transition: 0.5s;
+  border: 0;
+  margin-bottom: 30px;
+  border-radius: 0.55rem;
+  position: relative;
+  width: 100%;
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
+}
+
+@media screen and (max-width: 1200px) {
+  .auth-main:after {
+    background: url("/assets/img/inverlec_logo.png") no-repeat 85% center;
+    background-color: #fff;
+  }
+}
+
+@media screen and (max-width: 1024px) {
+  .auth-box {
+    width: 80%;
+    margin: 0 auto;
+  }
+
+  .auth-main:before {
+    width: 100%;
+    background-image: url("/assets/img/login-bg.png");
+  }
+
+  .top {
+    margin: 0 auto 20px;
+    text-align: center;
+    img {
+      width: 100%;
+      max-width: 350px;
+    }
+  }
+}
+
+@media screen and (max-width: 768px) {
+  .auth-main:before,
+  .auth-main:after {
+    background-color: #223d7d;
+  }
+
+  .top {
+    margin: 0 auto 20px;
+    text-align: center;
+    img {
+      width: 100%;
+      max-width: 350px;
+    }
+  }
+}
+
+@media screen and (max-width: 640px) {
+  .auth-box {
+    width: 90%;
+    border: 0;
+
+    .card {
+      box-shadow: none;
+    }
+  }
+  .auth-main:before,
+  .auth-main:after {
+    background-image: none;
+    background-color: #fff;
+  }
+
+  .top {
+    margin: 0 auto 20px;
+    text-align: center;
+    img {
+      width: 100%;
+      max-width: 300px;
+    }
+  }
+}

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

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

+ 153 - 0
src/app/components/login/login.component.ts

@@ -0,0 +1,153 @@
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { AuthService } from '@app/services/auth2.service';
+import Swal from 'sweetalert2';
+
+@Component({
+  selector: 'app-login',
+  templateUrl: './login.component.html',
+  styleUrls: ['./login.component.scss']
+})
+export class LoginComponent implements OnInit {
+
+  loginForm: FormGroup;
+  submitted:boolean = false;
+
+  constructor(private authService: AuthService, private formBuilder: FormBuilder, private router: Router) { }
+
+  ngOnInit() {
+    this.loginForm = this.formBuilder.group({
+      email: ['', [Validators.required, Validators.email]],
+      password: ['', Validators.required]
+    });
+  }
+
+  get f() { return this.loginForm.controls; }
+
+  login() {
+    this.submitted = true;
+
+    // stop here if form is invalid
+    if (this.loginForm.invalid) {
+      return;
+    }
+
+    Swal.fire({
+      
+    });
+    Swal.showLoading();
+
+    this.authService.login(
+      {
+        email: this.f.email.value,
+        password: this.f.password.value
+      }
+    )
+    .subscribe(success => {
+      if (success) {
+        window.location.href="#/dashboard";
+      }
+      else {
+        Swal.fire({
+      
+        })  
+      }
+    },(err) => {
+      Swal.fire({
+      
+      });
+    });
+  }
+
+}
+
+/* import { Component, OnInit } from '@angular/core';
+import { Location } from '@angular/common';
+
+import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
+import { NgForm } from '@angular/forms';
+
+import { User } from '../../models/user';
+import { AuthService } from '../../services/auth.service';
+
+import Swal from 'sweetalert2';
+
+@Component({
+  selector: 'app-login',
+  templateUrl: './login.component.html',
+  styleUrls: ['./login.component.scss']
+})
+export class LoginComponent implements OnInit {
+
+  user: User = new User();
+  recordarme = false;
+  returnUrl: string;
+  error_message: string;
+
+  constructor( private auth: AuthService,
+               private router: Router,
+               private route: ActivatedRoute,
+               private location: Location ) {
+
+              this.router.routeReuseStrategy.shouldReuseRoute = function(){
+                return false;
+              }
+
+              this.router.events.subscribe((evt) => {
+                if (evt instanceof NavigationEnd) {
+                  // trick the Router into believing it's last link wasn't previously loaded
+                  this.router.navigated = false;
+                  // if you need to scroll back to top, here is the right place
+                  window.scrollTo(0, 0);
+                }
+              });
+            }
+
+  ngOnInit() {
+    this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
+    if ( localStorage.getItem('email') ) {
+      this.user.email = localStorage.getItem('email');
+      //this.recordarme = true;
+    }
+  }
+
+  login( form: NgForm ) {
+    if (  form.invalid ) { return; }
+
+    Swal.fire({
+      allowOutsideClick: false,
+      type: 'info',
+      text: 'Espere por favor...'
+    });
+    Swal.showLoading();
+
+    this.auth.login( this.user )
+      .subscribe( resp => {
+
+        Swal.close();
+
+        localStorage.setItem('email', this.user.email);
+
+        //this.router.navigate([this.returnUrl]);
+        window.location.href="";
+      }, (err) => {
+        if(err.error.error.message == "INVALID_EMAIL"){
+          this.error_message = "Correo electrónico inválido";
+        }
+        else if(err.error.error.message == "INVALID_PASSWORD"){
+          this.error_message = "Contraseña incorrecta";
+        }
+        else {
+          this.error_message = "Ha ocurrido un error";
+        }
+        Swal.fire({
+          type: 'error',
+          title: 'Error al autenticar',
+          text: this.error_message
+        });
+      });
+  }
+
+}
+*/

+ 20 - 0
src/app/components/performances/performances.component.html

@@ -0,0 +1,20 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">Rendimientos</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 0 - 0
src/app/components/performances/performances.component.scss


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

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

+ 14 - 0
src/app/components/performances/performances.component.ts

@@ -0,0 +1,14 @@
+import { Component, OnInit } from "@angular/core";
+
+@Component({
+  selector: "app-performances",
+  templateUrl: "./performances.component.html",
+  styleUrls: ["./performances.component.scss"]
+})
+export class PerformancesComponent implements OnInit {
+  title: string = "Rendimientos";
+
+  constructor() {}
+
+  ngOnInit() {}
+}

+ 38 - 0
src/app/components/plugins/plugins.module.ts

@@ -0,0 +1,38 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import {
+  MatButtonModule,
+  MatInputModule,
+  MatRippleModule,
+  MatFormFieldModule,
+  MatTooltipModule,
+  MatSelectModule,
+  MatExpansionModule,
+  MatTableModule,
+  MatPaginatorModule,
+  MatProgressSpinnerModule,
+  MatSortModule
+} from '@angular/material';
+import { } from '@angular/material/table';
+
+@NgModule({
+  declarations: [
+  ],
+  imports: [
+    CommonModule,
+    MatButtonModule,
+    MatRippleModule,
+    MatFormFieldModule,
+    MatInputModule,
+    MatSelectModule,
+    MatTooltipModule,
+    MatExpansionModule,
+    MatTableModule,
+    MatPaginatorModule,
+    MatProgressSpinnerModule,
+    MatSortModule,
+  ],
+  exports: [
+  ]
+})
+export class PluginsModule { }

+ 54 - 0
src/app/components/plugins/validator/validator.component.ts

@@ -0,0 +1,54 @@
+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) {
+    return (formGroup: FormGroup) => {
+        const control = formGroup.controls[controlName];
+        const matchingControl = formGroup.controls[matchingControlName];
+
+        if (matchingControl.errors && !matchingControl.errors.mustMatch) {
+          // 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 });
+        } {
+          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;
+
+}

+ 19 - 0
src/app/components/profile/profile.component.html

@@ -0,0 +1,19 @@
+<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">
+        <div class="card dark-yellow-skin bg-gradient-danger card-img-holder text-white profile">
+          <div class="card-body">
+            <img alt="circle-image" class="card-img-absolute" src="assets/img/waves-opt.png">
+            <h4 class="font-weight-normal mb-3">Administrador</h4>
+            <h2 class="mb-3">{{email}}</h2>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 6 - 0
src/app/components/profile/profile.component.scss

@@ -0,0 +1,6 @@
+
+.profile {
+  background: url("/assets/img/dawn.jpg") 0 320px;
+}
+
+

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

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

+ 23 - 0
src/app/components/profile/profile.component.ts

@@ -0,0 +1,23 @@
+import { Component, OnInit } from '@angular/core';
+import { Title } from '@angular/platform-browser';
+
+@Component({
+  selector: 'app-profile',
+  templateUrl: './profile.component.html',
+  styleUrls: ['./profile.component.scss']
+})
+export class ProfileComponent implements OnInit {
+
+  title = "Perfil del usuario";
+
+  constructor(private titleService: Title) { }
+
+  email:string;
+
+  ngOnInit() {
+    this.titleService.setTitle(this.title);
+    this.email = localStorage.getItem("email");
+
+  }
+
+}

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

@@ -0,0 +1,9 @@
+<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>

+ 0 - 0
src/app/components/shared/footer/footer.component.scss


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

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

+ 15 - 0
src/app/components/shared/footer/footer.component.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-footer',
+  templateUrl: './footer.component.html',
+  styleUrls: ['./footer.component.scss']
+})
+export class FooterComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 47 - 0
src/app/components/shared/navbar/navbar.component.html

@@ -0,0 +1,47 @@
+<nav class="navbar navbar-expand-lg navbar-transparent  navbar-absolute fixed-top">
+  <div class="container-fluid">
+    <div class="navbar-wrapper">
+      <a class="navbar-brand d-none d-lg-block" title="Logout" (click)="menuToggle()">
+
+        <i class="material-icons text_align-center visible-on-sidebar-regular">more_vert</i>
+        <i class="material-icons design_bullet-list-67 visible-on-sidebar-mini">view_list</i>
+      </a>
+      <!--<a class="navbar-brand">{{getTitle()}}</a>-->
+    </div>
+    <button mat-raised-button class="navbar-toggler" type="button" (click)="sidebarToggle()">
+      <span class="sr-only">Toggle navigation</span>
+      <span class="navbar-toggler-icon icon-bar"></span>
+      <span class="navbar-toggler-icon icon-bar"></span>
+      <span class="navbar-toggler-icon icon-bar"></span>
+    </button>
+    <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">
+            <i class="material-icons">dashboard</i>
+            <p>
+              <span class="d-lg-none d-md-block">Stats</span>
+            </p>
+          </a>
+        </li>
+        <!--
+        <li class="nav-item">
+          <a class="nav-link" title="Account" href="#/profile">
+            <i class="material-icons">person</i>
+            <p>
+              <span class="d-lg-none d-md-block">Account</span>
+            </p>
+          </a>
+        </li>-->
+        <li class="nav-item">
+          <a class="nav-link" title="Cerrar sesión" (click)="logout()" href="javascript:void(0)">
+            <i class="material-icons">exit_to_app</i>
+            <p>
+              <span class="d-lg-none d-md-block">Logout</span>
+            </p>
+          </a>
+        </li>
+      </ul>
+    </div>
+  </div>
+</nav>

+ 0 - 0
src/app/components/shared/navbar/navbar.component.scss


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

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

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

@@ -0,0 +1,186 @@
+import { Observable } from 'rxjs';
+
+import { Component, OnInit, ElementRef } from '@angular/core';
+import { ROUTES } from '../sidebar/sidebar.component';
+import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
+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',
+  templateUrl: './navbar.component.html',
+  styleUrls: ['./navbar.component.scss']
+})
+export class NavbarComponent implements OnInit {
+    private listTitles: any[];
+
+    private leTitles: any[];
+
+    location: Location;
+      mobile_menu_visible: any = 0;
+    private toggleButton: any;
+    private sidebarVisible: boolean;
+    private sidebarMini: boolean;
+    constructor(location: Location,  private element: ElementRef, private router: Router, private auth: AuthService, private route: ActivatedRoute) {
+      this.location = location;
+      this.sidebarVisible = false;
+      this.sidebarMini = false;
+    }
+
+    ngOnInit(){
+      this.listTitles = ROUTES.filter(listTitle => listTitle);
+      this.leTitles = AdminLayoutRoutes.filter(listTitle => listTitle);
+      const navbar: HTMLElement = this.element.nativeElement;
+      this.toggleButton = navbar.getElementsByClassName('navbar-toggler')[0];
+      this.router.events.subscribe((event) => {
+        this.sidebarClose();
+         var $layer: any = document.getElementsByClassName('close-layer')[0];
+         if ($layer) {
+           $layer.remove();
+           this.mobile_menu_visible = 0;
+         }
+     });
+    }
+
+    sidebarMiniOn() {
+      const toggleButton = this.toggleButton;
+      const body = document.getElementsByTagName('body')[0];
+      setTimeout(function(){
+        toggleButton.classList.add('sidebar-mini');
+      }, 500);
+      body.classList.add('sidebar-mini');
+
+      this.sidebarMini = true;
+    };
+
+    sidebarMiniOff() {
+      const body = document.getElementsByTagName('body')[0];
+      //this.toggleButton.classList.remove('');
+      this.sidebarMini = false;
+      body.classList.remove('sidebar-mini');
+    };
+
+    menuToggle(){
+      const body = document.getElementsByTagName('body')[0];
+      //body.classList.add('sidebar-mini');
+      if (this.sidebarMini === false) {
+          this.sidebarMiniOn();
+      } else {
+          this.sidebarMiniOff();
+      }
+    }
+
+    sidebarOpen() {
+      const toggleButton = this.toggleButton;
+      const body = document.getElementsByTagName('body')[0];
+      setTimeout(function(){
+        toggleButton.classList.add('toggled');
+      }, 500);
+
+      body.classList.add('nav-open');
+
+      this.sidebarVisible = true;
+    };
+    sidebarClose() {
+      const body = document.getElementsByTagName('body')[0];
+      this.toggleButton.classList.remove('toggled');
+      this.sidebarVisible = false;
+      body.classList.remove('nav-open');
+    };
+    sidebarToggle() {
+      // const toggleButton = this.toggleButton;
+      // const body = document.getElementsByTagName('body')[0];
+      var $toggle = document.getElementsByClassName('navbar-toggler')[0];
+
+      if (this.sidebarVisible === false) {
+          this.sidebarOpen();
+      } else {
+          this.sidebarClose();
+      }
+      const body = document.getElementsByTagName('body')[0];
+
+      if (this.mobile_menu_visible == 1) {
+          // $('html').removeClass('nav-open');
+          body.classList.remove('nav-open');
+          if ($layer) {
+              $layer.remove();
+          }
+          setTimeout(function() {
+              $toggle.classList.remove('toggled');
+          }, 400);
+
+          this.mobile_menu_visible = 0;
+      } else {
+        setTimeout(function() {
+            $toggle.classList.add('toggled');
+        }, 430);
+
+        var $layer = document.createElement('div');
+        $layer.setAttribute('class', 'close-layer');
+
+        if (body.querySelectorAll('.main-panel')) {
+          document.getElementsByClassName('main-panel')[0].appendChild($layer);
+        }else if (body.classList.contains('off-canvas-sidebar')) {
+          document.getElementsByClassName('wrapper-full-page')[0].appendChild($layer);
+        }
+
+        setTimeout(function() {
+            $layer.classList.add('visible');
+        }, 100);
+
+        $layer.onclick = function() { //asign a function
+          body.classList.remove('nav-open');
+          this.mobile_menu_visible = 0;
+          $layer.classList.remove('visible');
+          setTimeout(function() {
+            $layer.remove();
+            $toggle.classList.remove('toggled');
+          }, 400);
+        }.bind(this);
+
+        body.classList.add('nav-open');
+        this.mobile_menu_visible = 1;
+      }
+    };
+
+    logout() {
+
+      Swal.fire({
+      
+      });
+      Swal.showLoading();
+
+      this.auth.logout();
+
+      //this.router.navigateByUrl("login");
+    }
+
+    getTitle(){
+      var titlee = this.location.prepareExternalUrl(this.location.path());
+      var component_local = this.router.url;
+      var main_title:string;
+
+      if(titlee.charAt(0) === '#'){
+        titlee = titlee.slice( 1 );
+      }
+      var item=0
+      while( item < this.leTitles.length){
+        
+        if("/"+this.leTitles[item].path === titlee){
+          main_title = this.leTitles[item].data['title'];
+          break;
+        }
+        item++;
+      }
+      if (main_title === undefined) {
+        return 'Dashboard';
+      }
+      else {
+        return main_title;
+      }
+
+    }
+}

+ 25 - 0
src/app/components/shared/shared.module.ts

@@ -0,0 +1,25 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+
+import { FooterComponent } from './footer/footer.component';
+import { NavbarComponent } from './navbar/navbar.component';
+import { SidebarComponent } from './sidebar/sidebar.component';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    RouterModule,
+  ],
+  declarations: [
+    FooterComponent,
+    NavbarComponent,
+    SidebarComponent
+  ],
+  exports: [
+    FooterComponent,
+    NavbarComponent,
+    SidebarComponent
+  ]
+})
+export class SharedModule { }

+ 78 - 0
src/app/components/shared/sidebar/sidebar.component.html

@@ -0,0 +1,78 @@
+<div class="logo">
+  <a class="simple-text logo-mini">
+    <div class="logo-img">
+      <img src="./assets/img/logo_inverlec_inv_p.png" />
+    </div>
+  </a>
+  <a class="simple-text logo-normal" href="/">Inversiones</a>
+</div>
+
+<div class="sidebar-wrapper">
+  <div *ngIf="isMobileMenu()">
+    <!--
+    <form class="navbar-form">
+      <span class="bmd-form-group">
+        <div class="input-group no-border">
+          <input type="text" value="" class="form-control" placeholder="Search...">
+          <button mat-raised-button type="submit" class="btn btn-white btn-round btn-just-icon">
+            <i class="material-icons">search</i>
+            <div class="ripple-container"></div>
+          </button>
+        </div>
+      </span>
+    </form> -->
+  </div>
+  <ul class="nav">
+    <li
+      routerLinkActive="active"
+      *ngFor="let menuItem of menuItems"
+      class="{{ menuItem.class }} nav-item"
+    >
+      <a class="nav-link" [routerLink]="[menuItem.path]">
+        <i class="material-icons">{{ menuItem.icon }}</i>
+        <p>{{ menuItem.title }}</p>
+      </a>
+    </li>
+    <li class="nav-item" routerlinkactive="active">
+      <a class="nav-link" data-toggle="collapse" href="#tables">
+        <i class="material-icons"> grid_on </i>
+        <p>Catálogos<b class="caret"></b></p>
+      </a>
+      <div class="collapse" id="tables">
+        <ul class="nav">
+          <li class="nav-item" routerlinkactive="active">
+            <a class="nav-link" href="">
+              <span class="sidebar-mini"> C1 </span>
+              <span class="sidebar-normal"> Catalogo </span>
+            </a>
+          </li>
+          <li class="nav-item" routerlinkactive="active">
+            <a class="nav-link" href="">
+              <span class="sidebar-mini"> C2 </span>
+              <span class="sidebar-normal">Catalogo</span>
+            </a>
+          </li>
+        </ul>
+      </div>
+    </li>
+    <hr />
+  </ul>
+
+  <div *ngIf="isMobileMenu()">
+    <ul class="nav navbar-nav nav-mobile-menu-bottom">
+      <li class="nav-item">
+        <a
+          class="nav-link"
+          title="Logout"
+          (click)="logout()"
+          href="javascript:void(0)"
+        >
+          <i class="material-icons">exit_to_app</i>
+          <p>
+            <span class="d-lg-none d-md-block">Logout</span>
+          </p>
+        </a>
+      </li>
+    </ul>
+  </div>
+</div>

+ 9 - 0
src/app/components/shared/sidebar/sidebar.component.scss

@@ -0,0 +1,9 @@
+ul.nav.navbar-nav.nav-mobile-menu-bottom {
+  bottom: 0;
+  width: 100%;
+}
+
+span.nav-link{
+  margin: 10px 15px 0;
+  padding: 10px 12px;
+}

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

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

+ 97 - 0
src/app/components/shared/sidebar/sidebar.component.ts

@@ -0,0 +1,97 @@
+import { Component, OnInit } from "@angular/core";
+import { AuthService } from "../../../services/auth2.service";
+import { Router } from "@angular/router";
+import * as CryptoJS from "crypto-js";
+import Swal from "sweetalert2";
+
+declare const $: any;
+declare interface RouteInfo {
+  path: string;
+  title: string;
+  icon: string;
+  class: string;
+  allowed_roles?: any;
+}
+export const ROUTES: RouteInfo[] = [
+  {
+    path: "/dashboard",
+    title: "Dashboard",
+    icon: "dashboard",
+    class: ""
+  },
+  {
+    path: "/investment-proposals",
+    title: "Propuestas de inversión",
+    icon: "wb_incandescent",
+    class: "",
+    allowed_roles: [2, 3]
+  },
+  {
+    path: "/investments",
+    title: "Inversiones",
+    icon: "work",
+    class: "",
+    allowed_roles: [2, 3]
+  },
+  {
+    path: "/arbitrations",
+    title: "Arbitrajes",
+    icon: "flag",
+    class: "",
+    allowed_roles: [2, 3]
+  },
+  {
+    path: "/performances",
+    title: "Rendimientos",
+    icon: "playlist_add",
+    class: "",
+    allowed_roles: [2, 3]
+  },
+  {
+    path: "/users",
+    title: "Usuarios",
+    icon: "people",
+    class: "",
+    allowed_roles: [2, 3]
+  }
+];
+
+@Component({
+  selector: "app-sidebar",
+  templateUrl: "./sidebar.component.html",
+  styleUrls: ["./sidebar.component.scss"]
+})
+export class SidebarComponent implements OnInit {
+  menuItems: any[];
+  adminMenuItems: any[];
+  adminMenu: boolean = false;
+  role_number: any;
+
+  constructor(private auth: AuthService, private router: Router) {
+    var bytes = CryptoJS.AES.decrypt(
+      localStorage.getItem("USER_MENU"),
+      "soma-inverlec-2019"
+    );
+    this.role_number = bytes.toString(CryptoJS.enc.Utf8);
+  }
+
+  ngOnInit() {
+    this.menuItems = ROUTES.filter(menuItem => menuItem);
+  }
+
+  isMobileMenu() {
+    if ($(window).width() > 991) {
+      return false;
+    }
+    return true;
+  }
+
+  logout() {
+    Swal.fire({});
+    Swal.showLoading();
+
+    this.auth.logout();
+
+    //this.router.navigateByUrl("login");
+  }
+}

+ 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() {
+  }
+
+}

+ 171 - 0
src/app/components/users/new-user/new-user.component.html

@@ -0,0 +1,171 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12">
+        <nav aria-label="breadcrumb">
+          <ol class="breadcrumb">
+            <li class="breadcrumb-item">
+              <a [routerLink]="['/']">Dashboard</a>
+            </li>
+            <li class="breadcrumb-item">
+              <a [routerLink]="['/users']">Usuarios</a>
+            </li>
+            <li class="breadcrumb-item">Nuevo Usuario</li>
+          </ol>
+        </nav>
+      </div>
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-8">
+        <div class="align-container">
+          <div class="card">
+            <div class="card-header card-header-icon card-header-rose">
+              <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">
+              <div class="align-container">
+                <form
+                  class="form-auth-small ng-untouched ng-pristine ng-valid"
+                  [formGroup]="userForm"
+                  (ngSubmit)="createUser()"
+                >
+                  <div class="form-group">
+                    <label for="first_name">Nombre: </label>
+                    <input
+                      type="text"
+                      formControlName="first_name"
+                      class="form-control"
+                      [ngClass]="{
+                        'is-invalid': submitted && f.first_name.errors
+                      }"
+                    />
+                    <div
+                      *ngIf="submitted && f.first_name.errors"
+                      class="invalid-feedback"
+                    >
+                      <div *ngIf="f.first_name.errors.required">
+                        Campo requerido
+                      </div>
+                    </div>
+                  </div>
+
+                  <div class="form-group">
+                    <label for="last_name">Apellido: </label>
+                    <input
+                      type="text"
+                      formControlName="last_name"
+                      class="form-control"
+                      [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">
+                    <label for="email">Email: </label>
+                    <input
+                      type="text"
+                      formControlName="email"
+                      class="form-control"
+                      [ngClass]="{ 'is-invalid': submitted && f.email.errors }"
+                    />
+                    <div
+                      *ngIf="submitted && f.email.errors"
+                      class="invalid-feedback"
+                    >
+                      <div *ngIf="f.email.errors.required">Campo requerido</div>
+                    </div>
+                  </div>
+
+                  <div class="form-group">
+                    <label for="role">Rol: </label>
+                    <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>
+                  </div>
+
+                  <br />
+                  <button class="btn btn-primary">
+                    Crear usuario
+                  </button>
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </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;
+}

+ 25 - 0
src/app/components/users/new-user/new-user.component.spec.ts

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

+ 95 - 0
src/app/components/users/new-user/new-user.component.ts

@@ -0,0 +1,95 @@
+import { Component, OnInit } from "@angular/core";
+import { FormGroup, FormBuilder, Validators, FormArray } from "@angular/forms";
+import { UserService } from "@app/services/user.service";
+import Swal from "sweetalert2";
+
+@Component({
+  selector: "app-new-user",
+  templateUrl: "./new-user.component.html",
+  styleUrls: ["./new-user.component.scss"]
+})
+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
+  ) {}
+
+  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: [""],
+      last_name: [""],
+      email: [""],
+      role: [""]
+    });
+  }
+
+  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;
+
+    // stop here if form is invalid
+    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({}).then(result => {
+            if (result.value) {
+              window.location.href = "#/users";
+            }
+          });
+        }
+      });
+  }
+}

+ 80 - 0
src/app/components/users/users.component.html

@@ -0,0 +1,80 @@
+<h2 class="floating-title">{{title}}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      
+      <div class="col-12 align-right">
+        <div class="align-container">
+          
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item"><a [routerLink]="['/']">Dashboard</a></li>
+              <li class="breadcrumb-item">Usuarios</li>
+            </ol>
+          </nav>
+
+          <a class="btn btn-primary" [routerLink]="['/users/new']">
+            Nuevo registro
+          </a>
+        </div>
+      </div>
+
+      <div class="col-12">
+          <div class="align-container">
+
+            <h4><b>Listado de usuarios</b></h4>
+            <div class="example-container mat-elevation-z8">
+              <div class="example-table-container">
+          
+                <table mat-table [dataSource]="dataSource" class="example-table">
+          
+                  <!-- Name Column -->
+                  <ng-container matColumnDef="email">
+                    <th mat-header-cell *matHeaderCellDef>Correo</th>
+                    <td mat-cell *matCellDef="let row">{{row.email}}</td>
+                  </ng-container>
+
+                  <!-- Country Column -->
+                  <ng-container matColumnDef="first_name">
+                    <th mat-header-cell *matHeaderCellDef>Nombre</th>
+                    <td mat-cell *matCellDef="let row">{{row.first_name}}</td>
+                  </ng-container>
+
+                  <!-- Country Column -->
+                  <ng-container matColumnDef="last_name">
+                    <th mat-header-cell *matHeaderCellDef>Apellido</th>
+                    <td mat-cell *matCellDef="let row">{{row.last_name}}</td>
+                  </ng-container>
+                  
+                  <!-- Country Column -->
+                  <ng-container matColumnDef="role">
+                    <th mat-header-cell *matHeaderCellDef>Rol</th>
+                    <td mat-cell *matCellDef="let row">{{userType(row.role)}}</td>
+                  </ng-container>
+
+                  <!--  Column 
+                  <ng-container matColumnDef="id">
+                    <th mat-header-cell *matHeaderCellDef>&nbsp;</th>
+                    <td mat-cell *matCellDef="let row">
+                      <a class="btn btn-primary btn-sm" [routerLink]="['/plant', row.id, 'edit']"  >
+                        Editar
+                      </a>
+                    </td>
+                  </ng-container>
+          -->
+          
+                  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+                </table>
+                <mat-paginator [pageSizeOptions]="[10, 15, 25]" [pageIndex]="0" [pageSize]="10"></mat-paginator>
+              </div>
+            </div>
+          </div>
+      
+      </div>
+      <br>
+      
+    </div>          
+  </div>
+</div>

+ 0 - 0
src/app/components/users/users.component.scss


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

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

+ 76 - 0
src/app/components/users/users.component.ts

@@ -0,0 +1,76 @@
+import { Component, ViewChild, OnInit } from "@angular/core";
+
+import { HttpClient } from "@angular/common/http";
+import { User } from "src/app/models/user";
+import { UserService } from "src/app/services/user.service";
+import { MatPaginator } from "@angular/material/paginator";
+import { MatSort } from "@angular/material/sort";
+import { MatTableDataSource } from "@angular/material/table";
+import Swal from "sweetalert2";
+
+@Component({
+  selector: "app-users",
+  templateUrl: "./users.component.html",
+  styleUrls: ["./users.component.scss"]
+})
+export class UsersComponent implements OnInit {
+  title: string = "Usuarios";
+
+  displayedColumns: string[] = ["email", "first_name", "last_name", "role"];
+  //displayedColumns: string[] = ['state'];
+
+  listData: User[] = [];
+  listUsers: any;
+  dataSource = new MatTableDataSource(this.listUsers);
+
+  resultsLength = 0;
+  isLoadingResults = true;
+  isRateLimitReached = false;
+
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+  role_number: any;
+
+  constructor(private userService: UserService) {
+    Swal.fire({});
+    Swal.showLoading();
+  }
+
+  ngOnInit() {
+    this.userService.getAllUsers().subscribe(
+      ans => {
+        this.listUsers = ans["data"]["users"];
+        this.dataSource.data = this.listUsers;
+        this.dataSource.paginator = this.paginator;
+        this.dataSource.sort = this.sort;
+      },
+      err => {
+        Swal.fire({});
+      }
+    );
+
+    setTimeout(() => {
+      Swal.close();
+    }, 1200);
+  }
+
+  userType(userRole: any) {
+    switch (+userRole) {
+      case 0:
+        return "Invitado";
+      case 1:
+        return "Usuario";
+      case 2:
+        return "Administrador";
+      case 3:
+        return "Super Admin";
+    }
+  }
+
+  applyFilter(filterValue: string) {
+    this.dataSource.filter = filterValue.trim().toLowerCase();
+    if (this.dataSource.paginator) {
+      this.dataSource.paginator.firstPage();
+    }
+  }
+}

+ 55 - 0
src/app/layouts/admin/admin.component.html

@@ -0,0 +1,55 @@
+<div class="wrapper">
+    <div class="sidebar" data-color="blue" data-background-color="white" >
+        <app-sidebar></app-sidebar>
+        <div class="sidebar-background" ></div>
+    </div>
+    <div class="main-panel">
+      <app-navbar></app-navbar>
+      <router-outlet></router-outlet>
+      <app-footer></app-footer>
+    </div>
+    <!--
+    <div class="fixed-plugin">
+        <div class="dropdown show-dropdown">
+            <a href="#" data-toggle="dropdown" aria-expanded="true">
+                <i class="fa fa-cog fa-2x"> </i>
+            </a>
+            <ul class="dropdown-menu" x-placement="bottom-start">
+                <li class="header-title"> Sidebar Filters</li>
+                <li class="adjustments-line">
+                    <a href="javascript:void(0)" class="switch-trigger active-color">
+                        <div class="ml-auto mr-auto">
+                            <span class="badge filter badge-white" data-color="white"></span>
+                            <span class="badge filter badge-yellow" data-color="yellow"></span>
+                            <span class="badge filter badge-blue active" data-color="blue"></span>
+                            <span class="badge filter badge-green" data-color="green"></span>
+                            <span class="badge filter badge-black" data-color="black"></span>
+                        </div>
+                        <div class="clearfix"></div>
+                    <div class="ripple-container"></div></a>
+                </li>
+                <li class="header-title">Images</li>
+                <li>
+                    <a class="img-holder switch-trigger" href="javascript:void(0)">
+                        <img src="./assets/img/sidebar-1.jpg" alt="">
+                    </a>
+                </li>
+                <li>
+                    <a class="img-holder switch-trigger" href="javascript:void(0)">
+                        <img src="./assets/img/sidebar-2.jpg" alt="">
+                    <div class="ripple-container"></div></a>
+                </li>
+                <li>
+                    <a class="img-holder switch-trigger" href="javascript:void(0)">
+                        <img src="./assets/img/sidebar-3.jpg" alt="">
+                    </a>
+                </li>
+                <li class="active">
+                    <a class="img-holder switch-trigger" href="javascript:void(0)">
+                        <img src="./assets/img/sidebar-4.jpg" alt="">
+                    </a>
+                </li>
+            </ul>
+        </div>
+    </div> -->
+</div>

+ 0 - 0
src/app/layouts/admin/admin.component.scss


+ 25 - 0
src/app/layouts/admin/admin.component.spec.ts

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

+ 161 - 0
src/app/layouts/admin/admin.component.ts

@@ -0,0 +1,161 @@
+import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
+import { Location, LocationStrategy, PathLocationStrategy, PopStateEvent } from '@angular/common';
+import { filter, map } from 'rxjs/operators';
+import { Subscription } from 'rxjs/Subscription';
+
+//import { NavbarComponent } from '../../components/navbar/navbar.component';
+import { Router, NavigationEnd, NavigationStart } from '@angular/router';
+import PerfectScrollbar from 'perfect-scrollbar';
+import * as $ from "jquery";
+
+@Component({
+  selector: 'app-admin',
+  templateUrl: './admin.component.html',
+  styleUrls: ['./admin.component.scss']
+})
+export class AdminComponent implements OnInit {
+  private _router: Subscription;
+  private lastPoppedUrl: string;
+  private yScrollStack: number[] = [];
+
+  constructor( public location: Location, private router: Router) {}
+
+  ngOnInit() {
+      const isWindows = navigator.platform.indexOf('Win') > -1 ? true : false;
+
+      if (isWindows && !document.getElementsByTagName('body')[0].classList.contains('sidebar-mini')) {
+          // if we are on windows OS we activate the perfectScrollbar function
+
+          document.getElementsByTagName('body')[0].classList.add('perfect-scrollbar-on');
+      } else {
+          document.getElementsByTagName('body')[0].classList.remove('perfect-scrollbar-off');
+      }
+      const elemMainPanel = <HTMLElement>document.querySelector('.main-panel');
+      const elemSidebar = <HTMLElement>document.querySelector('.sidebar .sidebar-wrapper');
+
+      this.location.subscribe((ev:PopStateEvent) => {
+          this.lastPoppedUrl = ev.url;
+      });
+       this.router.events.subscribe((event:any) => {
+          if (event instanceof NavigationStart) {
+             if (event.url != this.lastPoppedUrl)
+                 this.yScrollStack.push(window.scrollY);
+         } else if (event instanceof NavigationEnd) {
+             if (event.url == this.lastPoppedUrl) {
+                 this.lastPoppedUrl = undefined;
+                 window.scrollTo(0, this.yScrollStack.pop());
+             } else
+                 window.scrollTo(0, 0);
+         }
+      });
+
+      this._router = this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => {
+           elemMainPanel.scrollTop = 0;
+           elemSidebar.scrollTop = 0;
+      });
+      if (window.matchMedia(`(min-width: 960px)`).matches && !this.isMac()) {
+          let ps = new PerfectScrollbar(elemMainPanel);
+          ps = new PerfectScrollbar(elemSidebar);
+      }
+
+      const window_width = $(window).width();
+      let $sidebar = $('.sidebar');
+      let $sidebar_responsive = $('body > .navbar-collapse');
+      let $sidebar_img_container = $sidebar.find('.sidebar-background');
+
+
+      if(window_width > 767){
+          if($('.fixed-plugin .dropdown').hasClass('show-dropdown')){
+              $('.fixed-plugin .dropdown').addClass('open');
+          }
+
+      }
+
+      $('.fixed-plugin a').click(function(event){
+        // Alex if we click on switch, stop propagation of the event, so the dropdown will not be hide, otherwise we set the  section active
+          if($(this).hasClass('switch-trigger')){
+              if(event.stopPropagation){
+                  event.stopPropagation();
+              }
+              else if(window.event){
+                 window.event.cancelBubble = true;
+              }
+          }
+      });
+
+      $('.fixed-plugin .badge').click(function(){
+          let $full_page_background = $('.full-page-background');
+
+
+          $(this).siblings().removeClass('active');
+          $(this).addClass('active');
+
+          var new_color = $(this).data('color');
+
+          if($sidebar.length !== 0){
+              $sidebar.attr('data-color', new_color);
+          }
+
+          if($sidebar_responsive.length != 0){
+              $sidebar_responsive.attr('data-color',new_color);
+          }
+      });
+
+      $('.fixed-plugin .img-holder').click(function(){
+          let $full_page_background = $('.full-page-background');
+
+          $(this).parent('li').siblings().removeClass('active');
+          $(this).parent('li').addClass('active');
+
+
+          //var new_image = $(this).find("img").attr('src');
+
+          if($sidebar_img_container.length !=0 ){
+              $sidebar_img_container.fadeOut('fast', function(){
+                 //$sidebar_img_container.css('background-image','url("' + new_image + '")');
+                 $sidebar_img_container.fadeIn('fast');
+              });
+          }
+
+          if($full_page_background.length != 0){
+
+              $full_page_background.fadeOut('fast', function(){
+                 //$full_page_background.css('background-image','url("' + new_image + '")');
+                 $full_page_background.fadeIn('fast');
+              });
+          }
+
+          if($sidebar_responsive.length != 0){
+              //$sidebar_responsive.css('background-image','url("' + new_image + '")');
+          }
+      });
+  }
+  ngAfterViewInit() {
+      this.runOnRouteChange();
+  }
+  isMaps(path){
+      var titlee = this.location.prepareExternalUrl(this.location.path());
+      titlee = titlee.slice( 1 );
+      if(path == titlee){
+          return false;
+      }
+      else {
+          return true;
+      }
+  }
+  runOnRouteChange(): void {
+    if (window.matchMedia(`(min-width: 960px)`).matches && !this.isMac()) {
+      const elemMainPanel = <HTMLElement>document.querySelector('.main-panel');
+      const ps = new PerfectScrollbar(elemMainPanel);
+      ps.update();
+    }
+  }
+  isMac(): boolean {
+      let bool = false;
+      if (navigator.platform.toUpperCase().indexOf('MAC') >= 0 || navigator.platform.toUpperCase().indexOf('IPAD') >= 0) {
+          bool = true;
+      }
+      return bool;
+  }
+
+}

+ 73 - 0
src/app/layouts/admin/admin.module.ts

@@ -0,0 +1,73 @@
+import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
+import { NgModule } from "@angular/core";
+import { RouterModule } from "@angular/router";
+import { CommonModule } from "@angular/common";
+import { FormsModule, ReactiveFormsModule } from "@angular/forms";
+import { AngularMyDatePickerModule } from "angular-mydatepicker";
+
+import { AdminLayoutRoutes } from "./admin.routing";
+import { DashboardComponent } from "../../components/dashboard/dashboard.component";
+import { ProfileComponent } from "../../components/profile/profile.component";
+
+import { PluginsModule } from "../../components/plugins/plugins.module";
+
+import { MatTableExporterModule } from "mat-table-exporter";
+import {
+  MatButtonModule,
+  MatInputModule,
+  MatRippleModule,
+  MatFormFieldModule,
+  MatTooltipModule,
+  MatSelectModule,
+  MatExpansionModule,
+  MatTableModule,
+  MatPaginatorModule,
+  MatProgressSpinnerModule,
+  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";
+import { InvestmentProposalsComponent } from "@app/components/investment-proposals/investment-proposals.component";
+import { InvestmentsComponent } from "@app/components/investments/investments.component";
+import { ArbitrationsComponent } from "@app/components/arbitrations/arbitrations.component";
+import { PerformancesComponent } from "@app/components/performances/performances.component";
+
+import { UsersComponent } from "@app/components/users/users.component";
+import { NewUserComponent } from "@app/components/users/new-user/new-user.component";
+
+@NgModule({
+  imports: [
+    CommonModule,
+    RouterModule.forChild(AdminLayoutRoutes),
+    FormsModule,
+    ReactiveFormsModule,
+    MatButtonModule,
+    MatRippleModule,
+    MatFormFieldModule,
+    MatInputModule,
+    MatSelectModule,
+    MatTooltipModule,
+    MatExpansionModule,
+    MatTableModule,
+    MatPaginatorModule,
+    MatProgressSpinnerModule,
+    MatSortModule,
+    MatTableExporterModule,
+    PluginsModule,
+    AngularMyDatePickerModule,
+    MatPasswordStrengthModule
+  ],
+  declarations: [
+    DashboardComponent,
+    ProfileComponent,
+    TermsComponent,
+    InvestmentProposalsComponent,
+    InvestmentsComponent,
+    ArbitrationsComponent,
+    PerformancesComponent,
+    UsersComponent,
+    NewUserComponent
+  ]
+})
+export class AdminModule {}

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

@@ -0,0 +1,88 @@
+import { Routes } from "@angular/router";
+
+import { DashboardComponent } from "../../components/dashboard/dashboard.component";
+import { ProfileComponent } from "../../components/profile/profile.component";
+
+import { AuthGuard } from "@app/services/auth.guard";
+import { TermsComponent } from "@app/components/terms/terms.component";
+import { InvestmentsComponent } from "@app/components/investments/investments.component";
+import { InvestmentProposalsComponent } from "@app/components/investment-proposals/investment-proposals.component";
+import { ArbitrationsComponent } from "@app/components/arbitrations/arbitrations.component";
+import { PerformancesComponent } from "@app/components/performances/performances.component";
+
+import { UsersComponent } from "@app/components/users/users.component";
+import { NewUserComponent } from "@app/components/users/new-user/new-user.component";
+
+export const AdminLayoutRoutes: Routes = [
+  {
+    path: "dashboard",
+    component: DashboardComponent,
+    data: { title: "Dashboard" }
+  },
+  {
+    path: "profile",
+    component: ProfileComponent,
+    data: { title: "Perfil de usuario" }
+  },
+  {
+    path: "investment-proposals",
+    component: InvestmentProposalsComponent,
+    //canActivate: [AuthGuard],
+    data: {
+      title: "Propuestas de inversión",
+      breadcrumb: "Propuestas de inversión",
+      roles: [2, 3]
+    }
+  },
+  {
+    path: "investments",
+    component: InvestmentsComponent,
+    //canActivate: [AuthGuard],
+    data: {
+      title: "Inversiones",
+      breadcrumb: "Inversiones",
+      roles: [2, 3]
+    }
+  },
+  {
+    path: "arbitrations",
+    component: ArbitrationsComponent,
+    //canActivate: [AuthGuard],
+    data: {
+      title: "Arbitrajes",
+      breadcrumb: "Arbitrajes",
+      roles: [2, 3]
+    }
+  },
+  {
+    path: "performances",
+    component: PerformancesComponent,
+    //canActivate: [AuthGuard],
+    data: {
+      title: "Rendimientos",
+      breadcrumb: "Rendimientos",
+      roles: [2, 3]
+    }
+  },
+  {
+    path: "users",
+    component: UsersComponent,
+    //canActivate: [AuthGuard],
+    data: {
+      title: "Listado de usuarios",
+      breadcrumb: "Usuarios",
+      roles: [3]
+    }
+  },
+
+  {
+    path: "users/new",
+    component: NewUserComponent,
+    //canActivate: [AuthGuard],
+    data: {
+      title: "Nuevo usuario",
+      breadcrumb: "Nuevo usuario",
+      roles: [3]
+    }
+  }
+];

+ 3 - 0
src/app/models/index.ts

@@ -0,0 +1,3 @@
+export * from './role';
+export * from './user';
+

+ 4 - 0
src/app/models/role.ts

@@ -0,0 +1,4 @@
+export enum Role {
+    User = 'User',
+    Admin = 'Admin'
+}

+ 4 - 0
src/app/models/token.ts

@@ -0,0 +1,4 @@
+export class Token {
+  jwt: string;
+  refreshToken: string;
+}

+ 18 - 0
src/app/models/user.ts

@@ -0,0 +1,18 @@
+import { Role } from "./role";
+
+export class User {
+    email: string;
+    password: string;
+    firstName?: string;
+    lastName?: string;
+    uniqueid?: number;
+    role?: Role;
+    token?: string;
+    birthdate?: Date;
+    username?: string;
+    address?: string;
+    city?: string;
+    country?: string;
+    phone?: string;
+    gender?: string;
+}

+ 28 - 0
src/app/services/auth.guard.ts

@@ -0,0 +1,28 @@
+import { Injectable } from '@angular/core';
+import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { AuthService } from '../services/auth2.service';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class AuthGuard implements CanActivate {
+
+  constructor(private authService: AuthService, private router: Router) { }
+
+  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
+    
+    if (this.authService.isLoggedIn()) {
+      const userLevel = +this.authService.getUserLevel();
+      if (route.data.roles && route.data.roles.indexOf(userLevel) === -1) {
+        // role not authorised so redirect to home page
+        this.router.navigate(['/']);
+        return false;
+      }
+      return true
+    }
+    else {
+      this.router.navigate(['login'], { queryParams: { returnUrl: state.url }});
+      return !this.authService.isLoggedIn();
+    }
+  }
+}

+ 113 - 0
src/app/services/auth2.service.ts

@@ -0,0 +1,113 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { of, Observable, forkJoin, throwError } from 'rxjs';
+import { catchError, mapTo, tap, map, mergeMap } from 'rxjs/operators';
+import { Token } from '@app/models/token';
+import { environment } from '@environments/environment';
+import * as CryptoJS from 'crypto-js';
+import Swal from 'sweetalert2';
+
+@Injectable({
+  providedIn: 'root'
+})
+
+export class AuthService {
+
+  private readonly JWT_TOKEN = 'JWT_TOKEN';
+  private readonly REFRESH_TOKEN = 'REFRESH_TOKEN';
+  private readonly USER_MENU = 'USER_MENU';
+  private loggedUser: string;
+
+  constructor(private http: HttpClient) {}
+
+  login(user: { email: string, password: string}): Observable<boolean> {
+    return this.http.post<any>(`${environment.productionApiUrl}/auth/login`, user)
+      .pipe(
+        tap(tokens => this.doLoginUser(user.email, tokens)),
+        mapTo(true),
+        catchError(this.errorHandl)
+      );
+  }
+
+
+  logout() {
+    let refreshToken:string = this.getRefreshToken();
+    this.http.post<any>(`${environment.productionApiUrl}/auth/logout`, {})
+    .subscribe( results => {});
+    this.http.post<any>(`${environment.productionApiUrl}/auth/logout2`, {}).subscribe( results => {
+      this.doLogoutUser();
+      Swal.close();  
+      window.location.href = "";
+    });
+  }
+
+  isLoggedIn() {
+    return !!this.getJwtToken();
+  }
+
+  getUserLevel() {
+    var bytes  = CryptoJS.AES.decrypt(localStorage.getItem("USER_MENU"), 'soma-inverlec-2019');
+    var role_number = bytes.toString(CryptoJS.enc.Utf8);
+    return role_number;
+  }
+
+  refreshToken() {
+    let refreshToken:string = this.getRefreshToken();
+    return this.http.post<any>(`${environment.productionApiUrl}/auth/refresh`, {
+      'Authorization': `Bearer ${refreshToken}`
+    }).pipe(tap((tokens: Token) => {
+      this.storeJwtToken(tokens["data"]["access_token"]);
+      },
+      catchError(this.errorHandl)
+    ));
+  }
+
+  getJwtToken() {
+    return localStorage.getItem(this.JWT_TOKEN);
+  }
+
+  private doLoginUser(email: string, tokens: Token) {
+    this.loggedUser = email;
+    this.storeTokens(tokens);
+  }
+
+  private doLogoutUser() {
+    this.loggedUser = null;
+    this.removeTokens();
+  }
+
+  getRefreshToken() {
+    return localStorage.getItem(this.REFRESH_TOKEN);
+  }
+
+  private storeJwtToken(jwt: string) {
+    localStorage.setItem(this.JWT_TOKEN, jwt);
+  }
+
+  private storeTokens(tokens: Token) {
+    localStorage.clear();
+    localStorage.setItem(this.USER_MENU, CryptoJS.AES.encrypt(tokens["data"]["user"].role.toString(), 'soma-inverlec-2019').toString())
+    localStorage.setItem(this.JWT_TOKEN, tokens["data"]["user"].token); 
+    localStorage.setItem(this.REFRESH_TOKEN, tokens["data"]["user"].refresh);
+  }
+
+  removeTokens() {
+    localStorage.removeItem(this.USER_MENU);
+    localStorage.removeItem(this.JWT_TOKEN);
+    localStorage.removeItem(this.REFRESH_TOKEN);
+  }
+
+
+  errorHandl(error) {
+    let errorMessage = '';
+    if(error.error) {
+      // Get client-side error
+      errorMessage = error.error;
+    } else {
+      // Get server-side error
+      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;      
+    }
+    return throwError(errorMessage);
+  }
+
+}

+ 13 - 0
src/app/services/services.module.ts

@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule
+  ],
+  providers: [
+  ]
+})
+export class ServicesModule { }

+ 84 - 0
src/app/services/token.interceptor.ts

@@ -0,0 +1,84 @@
+import { Injectable } from '@angular/core';
+import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
+import { AuthService } from '@app/services/auth2.service';
+import { Observable, throwError, BehaviorSubject } from 'rxjs';
+import { catchError, filter, take, switchMap } from 'rxjs/operators';
+import Swal from 'sweetalert2';
+
+@Injectable()
+export class TokenInterceptor implements HttpInterceptor {
+
+  private isRefreshing = false;
+  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
+
+  constructor(public authService: AuthService) { }
+
+  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+    if (request.url.indexOf("auth/refresh")!= -1 || request.url.indexOf("auth/logout2") != -1){
+      request = this.addToken(request, this.authService.getRefreshToken());
+    }
+    else if (request.url.indexOf("openweather")!= -1 ){
+      request;
+    }
+    else {
+      if (this.authService.getJwtToken()) {
+        request = this.addToken(request, this.authService.getJwtToken());
+      }
+    }
+    
+    return next.handle(request).pipe(catchError(error => {
+      // Erase storage if response code from auth refresh gives 401 or 422 error
+      if (request.url.indexOf("auth/refresh")!= -1 && error instanceof HttpErrorResponse){
+        Swal.fire({
+         
+        });  
+        this.authService.removeTokens();
+        setTimeout(function(){
+          Swal.close();
+          window.location.href = "#/login";
+        }, 2000);
+      }
+
+      if (error instanceof HttpErrorResponse && (error.status === 401 || error.status === 422)) {
+        return this.handle4xxError(request, next);
+      } 
+      else {
+        return throwError(error);
+      }
+    }));      
+
+  }
+
+  private addToken(request: HttpRequest<any>, token: string) {
+    return request.clone({
+      setHeaders: {
+        'Authorization': `Bearer ${token}`
+      }
+    });
+  }
+
+  // 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);
+
+      return this.authService.refreshToken().pipe(
+        switchMap((token: any) => {
+          this.isRefreshing = false;
+          this.refreshTokenSubject.next(token["data"]["access_token"]);
+          return next.handle(this.addToken(request, token["data"]["access_token"]));
+        }));
+
+    } else {
+      this.isRefreshing = false;
+
+      return this.refreshTokenSubject.pipe(
+        filter(token => token != null),
+        take(2),
+        switchMap(jwt => {
+          return next.handle(this.addToken(request, jwt));
+        }));
+    }
+  }
+}

+ 64 - 0
src/app/services/user.service.ts

@@ -0,0 +1,64 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+
+import { environment } from '@environments/environment';
+import { User } from '@app/models';
+import { Observable } from 'rxjs/internal/Observable';
+import { throwError } from 'rxjs/internal/observable/throwError';
+import { map, catchError } from 'rxjs/operators';
+
+@Injectable({ providedIn: 'root' })
+export class UserService {
+  constructor(private http: HttpClient) { }
+
+  getAllUsers() {
+      return this.http.get<User[]>(`${environment.productionApiUrl}/users`);
+  }
+
+
+  createUser(user: { first_name :string, last_name :string, 
+    email :string, role :number, organizations?: any }): Observable<boolean> {
+      return this.http.post<any>(`${environment.productionApiUrl}/users`, user)
+      .pipe(
+        map(response => {
+          return response;
+        }),
+        catchError(this.errorHandl)
+      )  
+  }
+
+  validateUserToken(user: {token :string}): Observable<boolean> {
+      return this.http.post<any>(`${environment.productionApiUrl}/user/tokenvalidation`, user)
+      .pipe(
+        map(response => {
+          return response;
+        }),
+        catchError(this.errorHandl)
+      )  
+  }
+  
+  activateUser(user: { first_name :string, last_name :string, 
+    email :string, password: string, confirm_password :string }): Observable<boolean> {
+      return this.http.post<any>(`${environment.productionApiUrl}/user/activate`, user)
+      .pipe(
+        map(response => {
+          return response;
+        }),
+        catchError(this.errorHandl)
+      )  
+  }
+
+
+  errorHandl(error) {
+    let errorMessage = '';
+    if(error.error) {
+      // Get client-side error
+      errorMessage = error.error;
+    } else {
+      // Get server-side error
+      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
+    }
+    return throwError(errorMessage);
+ }
+
+}

BIN
src/assets/img/cover.jpeg


BIN
src/assets/img/dawn.jpg


BIN
src/assets/img/desktop-pc-icon.png


BIN
src/assets/img/favicon.png


BIN
src/assets/img/html.png


BIN
src/assets/img/inverlec_logo.png


BIN
src/assets/img/login-bg.png


BIN
src/assets/img/logo-inverlec.png


BIN
src/assets/img/logo-inverlec2.png


BIN
src/assets/img/logo.png


BIN
src/assets/img/logo_inverlec_inv_m.png


BIN
src/assets/img/logo_inverlec_inv_p.png


BIN
src/assets/img/marker-icon.png


BIN
src/assets/img/me-logo.png


BIN
src/assets/img/sidebar-1.jpg


BIN
src/assets/img/sidebar-2.jpg


BIN
src/assets/img/sidebar-3.jpg


BIN
src/assets/img/sidebar-4.jpg


BIN
src/assets/img/tv-icon.png


BIN
src/assets/img/waves-alt.png


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