diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 544936e..0a1ed18 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -16,7 +16,7 @@ const routes: Routes = [
// 'login'
// 'register'
- { path: '**', pathMatch: 'full', redirectTo: '/dashboard' },
+ { path: '', pathMatch: 'full', redirectTo: '/dashboard' },
{ path: '**', component: NopagefoundComponent },
];
diff --git a/src/app/components/components.module.ts b/src/app/components/components.module.ts
index 650f382..9a994ca 100644
--- a/src/app/components/components.module.ts
+++ b/src/app/components/components.module.ts
@@ -7,10 +7,11 @@ import { ChartsModule } from 'ng2-charts';
import { IncrementadorComponent } from './incrementador/incrementador.component';
import { DonutComponent } from './donut/donut.component';
+import { ModalImageComponent } from './modal-image/modal-image.component';
@NgModule({
- declarations: [IncrementadorComponent, DonutComponent],
- exports: [IncrementadorComponent, DonutComponent],
+ declarations: [IncrementadorComponent, DonutComponent, ModalImageComponent],
+ exports: [IncrementadorComponent, DonutComponent, ModalImageComponent],
imports: [CommonModule, FormsModule, ChartsModule],
})
export class ComponentsModule {}
diff --git a/src/app/components/modal-image/modal-image.component.html b/src/app/components/modal-image/modal-image.component.html
new file mode 100644
index 0000000..d138b9f
--- /dev/null
+++ b/src/app/components/modal-image/modal-image.component.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
Seleccione una imagen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/components/modal-image/modal-image.component.ts b/src/app/components/modal-image/modal-image.component.ts
new file mode 100644
index 0000000..cdb2499
--- /dev/null
+++ b/src/app/components/modal-image/modal-image.component.ts
@@ -0,0 +1,54 @@
+import { Component, OnInit } from '@angular/core';
+import { FileUploadService } from 'src/app/services/file-upload.service';
+import { ModalImageService } from 'src/app/services/modal-image.service';
+import Swal from 'sweetalert2';
+
+@Component({
+ selector: 'app-modal-image',
+ templateUrl: './modal-image.component.html',
+ styles: [],
+})
+export class ModalImageComponent implements OnInit {
+ imageToUpload: File;
+ imageUrl: string | ArrayBuffer;
+
+ constructor(
+ public modalService: ModalImageService,
+ private fileService: FileUploadService
+ ) {}
+
+ ngOnInit(): void {}
+
+ closeModal() {
+ this.modalService.closeModal();
+ }
+
+ changeImage(file: File) {
+ this.imageToUpload = file;
+
+ if (!file) return;
+
+ const reader = new FileReader();
+ const url64 = reader.readAsDataURL(file);
+ reader.onload = () => {
+ this.imageUrl = reader.result;
+ this.modalService.img = reader.result;
+ };
+ // console.log(file);
+ }
+
+ updateImage() {
+ const id = this.modalService.id;
+ const type = this.modalService.type;
+ this.fileService
+ .updateImage(this.imageToUpload, type, id)
+ .then((img) => {
+ Swal.fire('Guardado', 'Se cambió la imagen de perfíl', 'success');
+ this.modalService.newImg.emit(img);
+ this.closeModal();
+ })
+ .catch((err) => {
+ Swal.fire('Error', 'No se pudo actulizar la imagen', 'error');
+ });
+ }
+}
diff --git a/src/app/interfaces/repsonse-interface.ts b/src/app/interfaces/repsonse-interface.ts
index 26ed2a3..f024fd4 100644
--- a/src/app/interfaces/repsonse-interface.ts
+++ b/src/app/interfaces/repsonse-interface.ts
@@ -1 +1,32 @@
+import { Doctor } from '../models/doctor.model';
+import { Hospital } from '../models/hospital.model';
+import { User } from '../models/user.model';
+
export interface updateUserResponse {}
+
+export interface getUsersResponse {
+ ok: boolean;
+ users: User[];
+ uid: string;
+ total: number;
+}
+
+export interface UserByTermResponse {
+ ok: boolean;
+ results: User[];
+}
+
+export interface HospByTermResponse {
+ ok: boolean;
+ results: Hospital[];
+}
+
+export interface DocByTermResponse {
+ ok: boolean;
+ results: Doctor[];
+}
+
+export interface searchByTermResponse {
+ ok: boolean;
+ results: [];
+}
diff --git a/src/app/models/doctor.model.ts b/src/app/models/doctor.model.ts
new file mode 100644
index 0000000..4bee595
--- /dev/null
+++ b/src/app/models/doctor.model.ts
@@ -0,0 +1,3 @@
+export class Doctor {
+ constructor(public name: string) {}
+}
diff --git a/src/app/models/hospital.model.ts b/src/app/models/hospital.model.ts
new file mode 100644
index 0000000..8ad4eb5
--- /dev/null
+++ b/src/app/models/hospital.model.ts
@@ -0,0 +1,3 @@
+export class Hospital {
+ constructor(public name: string) {}
+}
diff --git a/src/app/pages/maintenance/initialTemplate.txt b/src/app/pages/maintenance/initialTemplate.txt
new file mode 100644
index 0000000..da9623f
--- /dev/null
+++ b/src/app/pages/maintenance/initialTemplate.txt
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
Cargando...
+
+
Espere un momento.
+
+
+
+
+
+
+
+
+
+
Usuarios
+
Usuarios de la aplicación.
+
+
+
+
+ Imagen
+ Email
+ Nombre
+ Rol
+ Autenticación
+ Acciones
+
+
+
+
+ Lunar probe project
+ Lunar probe project
+ Lunar probe project
+ Lunar probe project
+ Lunar probe project
+
+
+
+
+
+
+
+
+
+ Anterior
+ Siguiente
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/maintenance/users/users.component.html b/src/app/pages/maintenance/users/users.component.html
new file mode 100644
index 0000000..bfdc314
--- /dev/null
+++ b/src/app/pages/maintenance/users/users.component.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
Cargando...
+
+
Espere un momento.
+
+
+
+
+
+
+
+
+
+
Usuarios
+
Se encontraron {{totalUsers}} usuarios de la aplicación.
+
+
+
+
+ Imagen
+ Email
+ Nombre
+ Rol
+ Autenticación
+ Acciones
+
+
+
+
+
+
+
+
+
+ {{user.email}}
+ {{user.name}}
+
+ Admin
+ User
+
+
+ oogle
+ Email
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Anterior
+
{{(page +1)}}/{{totalPages}}
+
Siguiente
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/maintenance/users/users.component.ts b/src/app/pages/maintenance/users/users.component.ts
new file mode 100644
index 0000000..a1136e5
--- /dev/null
+++ b/src/app/pages/maintenance/users/users.component.ts
@@ -0,0 +1,148 @@
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import Swal from 'sweetalert2';
+
+import {
+ DocByTermResponse,
+ HospByTermResponse,
+ UserByTermResponse,
+} from 'src/app/interfaces/repsonse-interface';
+import { User } from 'src/app/models/user.model';
+
+import { SearchService } from 'src/app/services/search.service';
+import { UserService } from 'src/app/services/user.service';
+import { ModalImageService } from 'src/app/services/modal-image.service';
+import { delay } from 'rxjs/operators';
+import { Subscription } from 'rxjs';
+
+@Component({
+ selector: 'app-users',
+ templateUrl: './users.component.html',
+ styles: [],
+})
+export class UsersComponent implements OnInit, OnDestroy {
+ users: User[] = [];
+ totalUsers = 0;
+ page = 0;
+ isLoading = false;
+ imgSubs: Subscription;
+
+ constructor(
+ private searchService: SearchService,
+ private userService: UserService,
+ private modalService: ModalImageService
+ ) {}
+
+ ngOnDestroy(): void {
+ this.imgSubs.unsubscribe();
+ }
+
+ ngOnInit(): void {
+ this.getUsers();
+ this.imgSubs = this.modalService.newImg
+ .pipe(delay(200))
+ .subscribe((img) => this.getUsers());
+ }
+
+ // TODO: Refactorizar
+ get totalPages() {
+ return Math.ceil(this.totalUsers / 5);
+ }
+
+ changePage(value: number) {
+ this.page += value;
+ if (this.page < 0) {
+ this.page = 0;
+ return;
+ } else if (this.page * 5 >= this.totalUsers) {
+ this.page -= value;
+ return;
+ }
+ this.getUsers();
+ }
+
+ getUsers() {
+ this.isLoading = true;
+ this.userService.getUsers(this.page * 5).subscribe(({ total, users }) => {
+ // console.log(resp);
+ this.users = users;
+ this.totalUsers = total;
+ this.isLoading = false;
+ });
+ }
+
+ getUserByName(name) {
+ if (name == '') {
+ this.getUsers();
+ return;
+ }
+
+ this.isLoading = true;
+ this.searchService.searchByTerm(name, 'users').subscribe((resp: User[]) => {
+ // console.log(resp);
+ this.users = resp;
+ this.totalUsers = this.users.length;
+ this.isLoading = false;
+ });
+ }
+
+ deleteUser(user: User) {
+ if (user.uid === this.userService.uid) {
+ return Swal.fire('Error', 'No puede borrar su propio usuario', 'error');
+ }
+ console.log(user);
+ Swal.fire({
+ title: 'Eliminar Usuario',
+ text: `Desea eliminar al usuario ${user.name}?`,
+ icon: 'question',
+ showCancelButton: true,
+ confirmButtonColor: '#3085d6',
+ cancelButtonColor: '#d33',
+ confirmButtonText: 'Si, Eliminar',
+ }).then((result) => {
+ if (result.isConfirmed) {
+ this.userService.deleteUser(user).subscribe((resp) => {
+ this.getUsers();
+ Swal.fire(
+ 'Eliminado!',
+ '${user.name} fue eliminado de los usuarios.',
+ 'success'
+ );
+ });
+ }
+ });
+ }
+
+ editUser(user: User) {}
+
+ changeRole(user: User) {
+ // console.log(user);
+ this.userService.changeUserRole(user).subscribe((resp) => {});
+ }
+
+ openModal(user: User) {
+ this.modalService.openModal('users', user.uid, user.img);
+ }
+
+ // Mi implementacion vieja con 2 funciones
+ // nextPage() {
+ // if ((this.page + 1) * 5 > this.totalUsers) return;
+ // this.page++;
+ // console.log(this.page);
+ // this.getUsers(this.page * 5);
+ // }
+ // prevPage() {
+ // if (this.page == 0) return;
+ // this.page--;
+ // this.getUsers(this.page * 5);
+ // }
+
+ // Implementacion del profesor, el tenia una prop de la clase llamada this.from
+ // changePage(value: number) {
+ // this.from = value;
+ // if (this.from < 0) {
+ // this.form= 0
+ // } else if (this.from > this.totalUsers) {
+ // this.from -= value
+ // }
+ // }
+}
diff --git a/src/app/pages/pages.component.html b/src/app/pages/pages.component.html
index 4cc7d66..7122865 100644
--- a/src/app/pages/pages.component.html
+++ b/src/app/pages/pages.component.html
@@ -20,14 +20,16 @@
-->
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/pages.module.ts b/src/app/pages/pages.module.ts
index 8c06f42..5eea876 100644
--- a/src/app/pages/pages.module.ts
+++ b/src/app/pages/pages.module.ts
@@ -17,6 +17,7 @@ import { AccountSettingsComponent } from './account-settings/account-settings.co
import { PromisesComponent } from './promises/promises.component';
import { RxjsComponent } from './rxjs/rxjs.component';
import { ProfileComponent } from './profile/profile.component';
+import { UsersComponent } from './maintenance/users/users.component';
@NgModule({
declarations: [
@@ -28,6 +29,7 @@ import { ProfileComponent } from './profile/profile.component';
PromisesComponent,
RxjsComponent,
ProfileComponent,
+ UsersComponent,
],
exports: [
DashboardComponent,
diff --git a/src/app/pages/pages.routing.ts b/src/app/pages/pages.routing.ts
index 450be9b..64801df 100644
--- a/src/app/pages/pages.routing.ts
+++ b/src/app/pages/pages.routing.ts
@@ -12,6 +12,8 @@ import { PromisesComponent } from './promises/promises.component';
import { RxjsComponent } from './rxjs/rxjs.component';
import { ProfileComponent } from './profile/profile.component';
+import { UsersComponent } from './maintenance/users/users.component';
+
const routes: Routes = [
{
path: 'dashboard',
@@ -45,6 +47,13 @@ const routes: Routes = [
data: { title: 'Pormesas' },
},
{ path: 'rxjs', component: RxjsComponent, data: { title: 'RXJS' } },
+
+ // Mantenimientos
+ {
+ path: 'users',
+ component: UsersComponent,
+ data: { title: 'Usuarios de App' },
+ },
],
},
];
diff --git a/src/app/services/file-upload.service.ts b/src/app/services/file-upload.service.ts
index 3e2d580..ba26c63 100644
--- a/src/app/services/file-upload.service.ts
+++ b/src/app/services/file-upload.service.ts
@@ -10,7 +10,7 @@ export class FileUploadService {
async updateImage(
file: File,
- type: 'users' | 'doctors' | 'hospitals',
+ type: 'users' | 'hospitals' | 'doctors',
id: string
) {
try {
diff --git a/src/app/services/modal-image.service.ts b/src/app/services/modal-image.service.ts
new file mode 100644
index 0000000..bfed754
--- /dev/null
+++ b/src/app/services/modal-image.service.ts
@@ -0,0 +1,46 @@
+import { EventEmitter, Injectable } from '@angular/core';
+import { environment } from 'src/environments/environment';
+
+const base_url = environment.base_url;
+
+@Injectable({
+ providedIn: 'root',
+})
+export class ModalImageService {
+ private _hideModal = true;
+ type: 'users' | 'hospitals' | 'doctors';
+ id: string;
+ img: string | ArrayBuffer;
+ newImg = new EventEmitter();
+
+ constructor() {}
+
+ get hideModal() {
+ // console.log('hidemodal');
+ return this._hideModal;
+ }
+
+ openModal(
+ type: 'users' | 'hospitals' | 'doctors',
+ id: string,
+ img: string = 'no-img'
+ ) {
+ this._hideModal = false;
+ this.type = type;
+ this.id = id;
+ this.img = img;
+
+ if (img.includes('https')) {
+ // console.log('url img:', this.img);
+ this.img = img;
+ } else if (img) {
+ // console.log('url img:', this.img);
+ this.img = `${base_url}/upload/${type}/${img}`;
+ }
+ this.img = `${base_url}/upload/users/no-image`;
+ }
+
+ closeModal() {
+ this._hideModal = true;
+ }
+}
diff --git a/src/app/services/search.service.ts b/src/app/services/search.service.ts
new file mode 100644
index 0000000..8f2fe92
--- /dev/null
+++ b/src/app/services/search.service.ts
@@ -0,0 +1,80 @@
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { environment } from 'src/environments/environment';
+
+import {
+ DocByTermResponse,
+ HospByTermResponse,
+ searchByTermResponse,
+ UserByTermResponse,
+} from '../interfaces/repsonse-interface';
+import { User } from '../models/user.model';
+
+const base_url = environment.base_url;
+
+@Injectable({
+ providedIn: 'root',
+})
+export class SearchService {
+ constructor(private http: HttpClient) {}
+
+ get token(): string {
+ return localStorage.getItem('token') || '';
+ }
+
+ get headers() {
+ return { headers: { 'x-token': this.token } };
+ }
+
+ tranformInUsers(users: User[]) {
+ return users.map(
+ (user) =>
+ new User(
+ user.name,
+ user.email,
+ '',
+ user.img,
+ user.google,
+ user.role,
+ user.uid
+ )
+ );
+ }
+
+ searchByTerm(
+ term: string = '',
+ type: 'users' | 'hospitals' | 'doctors'
+ ): Observable {
+ const url = `${base_url}/search/collection/${type}/${term}`;
+ return this.http
+ .get(
+ url,
+ this.headers
+ )
+ .pipe(
+ map((resp) => {
+ if (type === 'users') {
+ return this.tranformInUsers(resp.results as User[]);
+ } else if (type === 'hospitals') {
+ return resp;
+ } else if (type === 'doctors') {
+ return resp;
+ }
+ })
+ );
+ }
+
+ searchByTermProfe(
+ term: string = '',
+ type: 'users' | 'hospitals' | 'doctors'
+ ) {
+ const url = `${base_url}/search/collection/${type}/${term}`;
+ return this.http.get(url, this.headers).pipe(
+ map((resp) => {
+ resp.results;
+ })
+ );
+ }
+}
diff --git a/src/app/services/sidebar.service.ts b/src/app/services/sidebar.service.ts
index 399af87..40a075f 100644
--- a/src/app/services/sidebar.service.ts
+++ b/src/app/services/sidebar.service.ts
@@ -17,6 +17,16 @@ export class SidebarService {
{ title: 'Rxjs', url: 'rxjs' },
],
},
+
+ {
+ title: 'Mantenimiento',
+ icon: 'mdi mdi-tooltip-edit',
+ submenu: [
+ { title: 'Usuarios', url: 'users' },
+ { title: 'Hospitales', url: 'hospitals' },
+ { title: 'Medicos', url: 'doctors' },
+ ],
+ },
];
constructor() {}
diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts
index 45fe86e..7d3a9d1 100644
--- a/src/app/services/user.service.ts
+++ b/src/app/services/user.service.ts
@@ -1,17 +1,18 @@
import { HttpClient } from '@angular/common/http';
import { Injectable, NgZone } from '@angular/core';
+import { Router } from '@angular/router';
+
import { catchError, map, tap } from 'rxjs/operators';
+import { Observable, of } from 'rxjs';
import { environment } from 'src/environments/environment';
-import { Observable, of } from 'rxjs';
-import { Router } from '@angular/router';
-
import {
LoginForm,
ProfileForm,
RegisterForm,
} from '../interfaces/forms.interface';
+import { getUsersResponse } from '../interfaces/repsonse-interface';
import { User } from '../models/user.model';
const base_url = environment.base_url;
@@ -40,6 +41,10 @@ export class UserService {
return this.user.uid || '';
}
+ get headers() {
+ return { headers: { 'x-token': this.token } };
+ }
+
googleInit() {
return new Promise((resolve) => {
gapi.load('auth2', () => {
@@ -73,23 +78,6 @@ export class UserService {
})
);
}
-
- createUser(formData: RegisterForm) {
- return this.http.post(`${base_url}/users`, formData).pipe(
- tap((res: any) => {
- localStorage.setItem('token', res.token);
- })
- );
- }
-
- // updateUser(formData: {name:string,email:string})
- updateUser(formData: ProfileForm) {
- formData = { ...formData, role: this.user.role };
- return this.http.put(`${base_url}/users/${this.uid}`, formData, {
- headers: { 'x-token': this.token },
- });
- }
-
// TODO: Crear y aplicar interfaces para las respuestas de las peticiones
login(formData: LoginForm) {
try {
@@ -118,4 +106,54 @@ export class UserService {
this.ngZone.run(() => this.router.navigate(['/login']));
});
}
+
+ createUser(formData: RegisterForm) {
+ return this.http.post(`${base_url}/users`, formData).pipe(
+ tap((res: any) => {
+ localStorage.setItem('token', res.token);
+ })
+ );
+ }
+
+ // updateUser(formData: {name:string,email:string})
+ updateUser(formData: ProfileForm) {
+ formData = { ...formData, role: this.user.role };
+ return this.http.put(
+ `${base_url}/users/${this.uid}`,
+ formData,
+ this.headers
+ );
+ }
+
+ changeUserRole(user: User) {
+ // console.log(user);
+
+ return this.http.put(`${base_url}/users/${user.uid}`, user, this.headers);
+ }
+
+ getUsers(from: number = 0) {
+ const url = `${base_url}/users?from=${from}`;
+ return this.http.get(url, this.headers).pipe(
+ map((resp) => {
+ resp.users = resp.users.map(
+ (user) =>
+ new User(
+ user.name,
+ user.email,
+ '',
+ user.img,
+ user.google,
+ user.role,
+ user.uid
+ )
+ );
+ return resp;
+ })
+ );
+ }
+
+ deleteUser(user: User) {
+ const url = `${base_url}/users/${user.uid}`;
+ return this.http.delete(url, this.headers);
+ }
}
diff --git a/src/app/shared/sidebar/sidebar.component.html b/src/app/shared/sidebar/sidebar.component.html
index b6ba9ef..1cc3fc1 100644
--- a/src/app/shared/sidebar/sidebar.component.html
+++ b/src/app/shared/sidebar/sidebar.component.html
@@ -23,7 +23,7 @@
-
+
diff --git a/src/styles.css b/src/styles.css
index 42e44ce..72d16d1 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -40,3 +40,36 @@
.mailbox .message-center a .mail-contnet {
margin-left: 10px;
}
+
+.w100 {
+ width: 100px;
+}
+.w140 {
+ width: 140px;
+}
+
+table div.user-img {
+ width: 50px;
+ height: 50px;
+ overflow: hidden;
+ position: relative;
+ display: inline-block;
+ border-radius: 100%;
+}
+table div.user-img .img-profile {
+ width: 100%;
+}
+
+#fondo-modal-image {
+ background-color: rgba(0, 0, 0, 0.356);
+ left: 0px;
+ height: 100%;
+ position: fixed;
+ top: 0px;
+ width: 100%;
+ z-index: 999;
+}
+
+.hide {
+ display: none;
+}