From c89483a2855e42df8994b3fc1d7e88e81c292825 Mon Sep 17 00:00:00 2001 From: Angel Echavarria Date: Sun, 28 Jan 2018 16:17:14 -0600 Subject: [PATCH 1/3] added database models for campists --- .../models/basal-insulin.interface.ts | 4 ++ .../core/services/models/campist.interface.ts | 21 +++++++++ .../core/services/models/campist.service.ts | 45 +++++++++++++++++++ src/app/core/services/models/food.types.ts | 19 ++++++++ .../services/models/insulin-intervals.enum.ts | 6 +++ .../models/insulin-scheme.interface.ts | 13 ++++++ src/app/core/services/models/team.enum.ts | 7 +++ 7 files changed, 115 insertions(+) create mode 100644 src/app/core/services/models/basal-insulin.interface.ts create mode 100644 src/app/core/services/models/campist.interface.ts create mode 100644 src/app/core/services/models/campist.service.ts create mode 100644 src/app/core/services/models/food.types.ts create mode 100644 src/app/core/services/models/insulin-intervals.enum.ts create mode 100644 src/app/core/services/models/insulin-scheme.interface.ts create mode 100644 src/app/core/services/models/team.enum.ts diff --git a/src/app/core/services/models/basal-insulin.interface.ts b/src/app/core/services/models/basal-insulin.interface.ts new file mode 100644 index 0000000..f3f1d13 --- /dev/null +++ b/src/app/core/services/models/basal-insulin.interface.ts @@ -0,0 +1,4 @@ +export interface BasalInsulin { + dosage: number; + timestamp: Date; +} diff --git a/src/app/core/services/models/campist.interface.ts b/src/app/core/services/models/campist.interface.ts new file mode 100644 index 0000000..e008924 --- /dev/null +++ b/src/app/core/services/models/campist.interface.ts @@ -0,0 +1,21 @@ +import { Team } from './team.enum'; +import { + InsulinSchemeIntervals, + InsulinSchemeRatio +} from './insulin-scheme.interface'; +import { BasalInsulin } from './basal-insulin.interface'; +import { FoodTable } from './food.types'; + +export interface Campist { + id: string; + names: string; + lastNames: string; + age: number; + team: Team; + allergies: string; + medications: string; + insulinSchemeIntervals: InsulinSchemeIntervals; + insulinSchemeRatio: InsulinSchemeRatio; + basalInsulin: Array; + foodTable: Array; +} diff --git a/src/app/core/services/models/campist.service.ts b/src/app/core/services/models/campist.service.ts new file mode 100644 index 0000000..0296cb0 --- /dev/null +++ b/src/app/core/services/models/campist.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { + AngularFirestore, + AngularFirestoreCollection, + AngularFirestoreDocument +} from 'angularfire2/firestore'; + +import { Observable } from 'rxjs/Observable'; + +import { Campist } from './campist.interface'; + +@Injectable() +export class CampistService { + campistsCollection: AngularFirestoreCollection; + campists: Observable; + + constructor(public afs: AngularFirestore) { + this.campistsCollection = this.afs.collection('campists'); + this.campists = this.campistsCollection.snapshotChanges().map(changes => { + return changes.map(a => { + const data = a.payload.doc.data() as Campist; + data.id = a.payload.doc.id; + return data; + }); + }); + } + + getCampists() { + return this.campists; + } + + addCampist(campist: Campist) { + this.campistsCollection.add(campist); + } + + deleteCampist(campist: Campist) { + const campistDoc = this.afs.doc(`campists/${campist.id}`); + campistDoc.delete(); + } + + updateCampist(campist: Campist) { + const campistDoc = this.afs.doc(`campists/${campist.id}`); + campistDoc.update(campist); + } +} diff --git a/src/app/core/services/models/food.types.ts b/src/app/core/services/models/food.types.ts new file mode 100644 index 0000000..c8db05f --- /dev/null +++ b/src/app/core/services/models/food.types.ts @@ -0,0 +1,19 @@ +export enum FoodTime { + Breakfast = 'Desayuno', + MorningSnack = 'Merienda Mañana', + Lunch = 'Almuerzo', + AfternoonSnack = 'Merienda Tarde', + Dinner = 'Cena' +} + +export enum FoodType { + carbs= 'Carbohidratos', + proteins= 'Proteínas', + fruits= 'Frutas', + dairy= 'Leche' +} + +export interface FoodTable { + foodTime: FoodTime; + foodType: FoodType; +} diff --git a/src/app/core/services/models/insulin-intervals.enum.ts b/src/app/core/services/models/insulin-intervals.enum.ts new file mode 100644 index 0000000..8eaae1e --- /dev/null +++ b/src/app/core/services/models/insulin-intervals.enum.ts @@ -0,0 +1,6 @@ +export enum InsulinIntervals { + lessThan80 = '<80', + from81To160 = '81-160', + from161To250 = '161-250', + biggerThan250 = '>250' +} diff --git a/src/app/core/services/models/insulin-scheme.interface.ts b/src/app/core/services/models/insulin-scheme.interface.ts new file mode 100644 index 0000000..2e834e2 --- /dev/null +++ b/src/app/core/services/models/insulin-scheme.interface.ts @@ -0,0 +1,13 @@ +import { InsulinIntervals } from './insulin-intervals.enum'; +import { FoodTime } from './food.types'; + +export interface InsulinSchemeIntervals { + foodTime: FoodTime; + scheme: InsulinIntervals; + quantity: number; +} + +export interface InsulinSchemeRatio { + minimium: number; + maximium: number; +} diff --git a/src/app/core/services/models/team.enum.ts b/src/app/core/services/models/team.enum.ts new file mode 100644 index 0000000..04f8a74 --- /dev/null +++ b/src/app/core/services/models/team.enum.ts @@ -0,0 +1,7 @@ +export enum Team { + morado, + verde, + azul, + amarillo, + rojo +} From 26833e83ab9fe1d83c897cbed0c868e33f41cc58 Mon Sep 17 00:00:00 2001 From: Angel Echavarria Date: Sun, 28 Jan 2018 19:56:43 -0600 Subject: [PATCH 2/3] testings with campist service --- src/app/app.module.ts | 4 ++-- src/app/app.routing.ts | 2 +- src/app/core/core.module.ts | 19 +------------------ src/app/core/index.ts | 13 ------------- src/app/core/services/index.ts | 4 +--- 5 files changed, 5 insertions(+), 37 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a1b923c..0f53af2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,6 +15,7 @@ import { AngularFirestoreModule } from 'angularfire2/firestore'; import { AngularFireAuthModule } from 'angularfire2/auth'; import { NgcFloatButtonModule } from 'ngc-float-button'; +import { CoreModule } from './core/index'; @NgModule({ declarations: [AppComponent, NotfoundComponent], @@ -27,8 +28,7 @@ import { NgcFloatButtonModule } from 'ngc-float-button'; NgcFloatButtonModule, AngularFireModule.initializeApp(environment.firebase), AngularFirestoreModule.enablePersistence(), - // AuthModule, - // CoreModule, + CoreModule, AppRoutingModule ], providers: [], diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts index 1a78ec4..11181d8 100644 --- a/src/app/app.routing.ts +++ b/src/app/app.routing.ts @@ -1,7 +1,7 @@ // Platform imports import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { RouterModule, Routes } from '@angular/router'; +import { RouterModule } from '@angular/router'; // @Components import { NotfoundComponent } from './notfound/notfound.component'; diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 591b855..7749362 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -1,23 +1,6 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports import { NgModule } from '@angular/core'; -// Services Imports -import { SessionService, NotificationService, DialogService } from './services'; -import { AuthGuard } from './guards/auth.guard'; - -// Modules Imports -import { SharedModule } from '../shared'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODULE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - @NgModule({ - imports: [SharedModule], - providers: [SessionService, NotificationService, DialogService, AuthGuard] + providers: [] }) export class CoreModule {} diff --git a/src/app/core/index.ts b/src/app/core/index.ts index 8c709e1..df05cf1 100644 --- a/src/app/core/index.ts +++ b/src/app/core/index.ts @@ -1,18 +1,5 @@ // Exports module. export * from './core.module'; -// Export guards -export * from './guards/auth.guard'; - -// Enums Exports -export * from './enums'; - -// Export interfaces -export * from './interfaces'; - -// Export public constants -export * from './constants/routes-access.constant'; -export * from './constants/routes-role-requirements.constant'; - // Export public models export * from './services'; diff --git a/src/app/core/services/index.ts b/src/app/core/services/index.ts index ed61eb6..81ef16f 100644 --- a/src/app/core/services/index.ts +++ b/src/app/core/services/index.ts @@ -1,3 +1 @@ -export { SessionService } from './session/session.service'; -export { NotificationService } from './notification/notification.service'; -export { DialogService } from './dialog/dialog.service'; +export { CampistService } from './models/campist.service'; From 39a4956c45ce6b673c0141ae9c7388698f3bb44c Mon Sep 17 00:00:00 2001 From: Angel Echavarria Date: Sun, 28 Jan 2018 19:57:07 -0600 Subject: [PATCH 3/3] removed unused files #5 --- .../core/constants/routes-access.constant.ts | 16 - .../routes-role-requirements.constant.ts | 26 -- src/app/core/enums/index.ts | 1 - src/app/core/enums/notification-type.enum.ts | 6 - src/app/core/guards/auth.guard.ts | 132 ------- src/app/core/interfaces/dialog.interface.ts | 20 - src/app/core/interfaces/index.ts | 2 - .../core/interfaces/notification.interface.ts | 14 - .../core/services/dialog/dialog.service.ts | 56 --- .../notification/notification.service.spec.ts | 160 -------- .../notification/notification.service.ts | 69 ---- .../services/session/session.interface.ts | 13 - .../services/session/session.service.spec.ts | 231 ------------ .../core/services/session/session.service.ts | 120 ------ .../custom-select.component.html | 31 -- .../custom-select.component.scss | 115 ------ .../custom-select/custom-select.component.ts | 205 ---------- .../custom-select/custom-select.constants.ts | 14 - .../components/dialog/dialog.component.html | 13 - .../components/dialog/dialog.component.scss | 100 ----- .../components/dialog/dialog.component.ts | 114 ------ .../components/dialog/dialog.constants.ts | 14 - src/app/shared/components/index.ts | 4 - .../notification-toaster.component.html | 3 - .../notification-toaster.component.scss | 59 --- .../notification-toaster.component.ts | 156 -------- .../notification.constants.ts | 35 -- .../tag-list-select.component.html | 31 -- .../tag-list-select.component.scss | 160 -------- .../tag-list-select.component.ts | 350 ------------------ .../tag-list-select.constants.ts | 15 - .../shared/directives/autoheight.directive.ts | 46 --- src/app/shared/directives/index.ts | 2 - .../shared/directives/scrollto.directive.ts | 83 ----- src/app/shared/index.ts | 37 -- src/app/shared/interfaces/area.interface.ts | 17 - .../shared/interfaces/category.interface.ts | 16 - src/app/shared/interfaces/index.ts | 6 - .../shared/interfaces/question.interface.ts | 11 - .../interfaces/request-type.interface.ts | 20 - .../tag-list-select-item.interface.ts | 4 - src/app/shared/interfaces/user.interface.ts | 22 -- src/app/shared/models/area.model.ts | 65 ---- src/app/shared/models/category.model.ts | 41 -- src/app/shared/models/index.ts | 5 - src/app/shared/models/question.model.ts | 26 -- src/app/shared/models/request-type.model.ts | 41 -- src/app/shared/models/user.model.ts | 41 -- .../pipes/custom-date/custom-date.pipe.ts | 66 ---- .../date-i18n-dictionary.constants.ts | 24 -- src/app/shared/pipes/index.ts | 2 - .../pipes/truncate/truncate.pipe.spec.ts | 0 .../shared/pipes/truncate/truncate.pipe.ts | 30 -- .../shared/services/area/area.service.spec.ts | 0 src/app/shared/services/area/area.service.ts | 104 ------ .../services/category/category.service.ts | 34 -- .../shared/services/file/file.service.spec.ts | 0 src/app/shared/services/file/file.service.ts | 36 -- src/app/shared/services/index.ts | 7 - .../local-storage.service.spec.ts | 215 ----------- .../local-storage/local-storage.service.ts | 67 ---- .../request-type/request-type.service.ts | 80 ---- .../sac-api/api-request-options.interface.ts | 11 - .../services/sac-api/sac-api.service.spec.ts | 347 ----------------- .../services/sac-api/sac-api.service.ts | 218 ----------- .../shared/services/user/user.service.spec.ts | 197 ---------- src/app/shared/services/user/user.service.ts | 49 --- src/app/shared/shared.constants.ts | 55 --- src/app/shared/shared.module.ts | 66 ---- 69 files changed, 4376 deletions(-) delete mode 100644 src/app/core/constants/routes-access.constant.ts delete mode 100644 src/app/core/constants/routes-role-requirements.constant.ts delete mode 100644 src/app/core/enums/index.ts delete mode 100644 src/app/core/enums/notification-type.enum.ts delete mode 100644 src/app/core/guards/auth.guard.ts delete mode 100644 src/app/core/interfaces/dialog.interface.ts delete mode 100644 src/app/core/interfaces/index.ts delete mode 100644 src/app/core/interfaces/notification.interface.ts delete mode 100644 src/app/core/services/dialog/dialog.service.ts delete mode 100644 src/app/core/services/notification/notification.service.spec.ts delete mode 100644 src/app/core/services/notification/notification.service.ts delete mode 100644 src/app/core/services/session/session.interface.ts delete mode 100644 src/app/core/services/session/session.service.spec.ts delete mode 100644 src/app/core/services/session/session.service.ts delete mode 100644 src/app/shared/components/custom-select/custom-select.component.html delete mode 100644 src/app/shared/components/custom-select/custom-select.component.scss delete mode 100644 src/app/shared/components/custom-select/custom-select.component.ts delete mode 100644 src/app/shared/components/custom-select/custom-select.constants.ts delete mode 100644 src/app/shared/components/dialog/dialog.component.html delete mode 100644 src/app/shared/components/dialog/dialog.component.scss delete mode 100644 src/app/shared/components/dialog/dialog.component.ts delete mode 100644 src/app/shared/components/dialog/dialog.constants.ts delete mode 100644 src/app/shared/components/index.ts delete mode 100644 src/app/shared/components/notification-toaster/notification-toaster.component.html delete mode 100644 src/app/shared/components/notification-toaster/notification-toaster.component.scss delete mode 100644 src/app/shared/components/notification-toaster/notification-toaster.component.ts delete mode 100644 src/app/shared/components/notification-toaster/notification.constants.ts delete mode 100644 src/app/shared/components/tag-list-select/tag-list-select.component.html delete mode 100644 src/app/shared/components/tag-list-select/tag-list-select.component.scss delete mode 100644 src/app/shared/components/tag-list-select/tag-list-select.component.ts delete mode 100644 src/app/shared/components/tag-list-select/tag-list-select.constants.ts delete mode 100644 src/app/shared/directives/autoheight.directive.ts delete mode 100644 src/app/shared/directives/index.ts delete mode 100644 src/app/shared/directives/scrollto.directive.ts delete mode 100644 src/app/shared/index.ts delete mode 100644 src/app/shared/interfaces/area.interface.ts delete mode 100644 src/app/shared/interfaces/category.interface.ts delete mode 100644 src/app/shared/interfaces/index.ts delete mode 100644 src/app/shared/interfaces/question.interface.ts delete mode 100644 src/app/shared/interfaces/request-type.interface.ts delete mode 100644 src/app/shared/interfaces/tag-list-select-item.interface.ts delete mode 100644 src/app/shared/interfaces/user.interface.ts delete mode 100644 src/app/shared/models/area.model.ts delete mode 100644 src/app/shared/models/category.model.ts delete mode 100644 src/app/shared/models/index.ts delete mode 100644 src/app/shared/models/question.model.ts delete mode 100644 src/app/shared/models/request-type.model.ts delete mode 100644 src/app/shared/models/user.model.ts delete mode 100644 src/app/shared/pipes/custom-date/custom-date.pipe.ts delete mode 100644 src/app/shared/pipes/custom-date/date-i18n-dictionary.constants.ts delete mode 100644 src/app/shared/pipes/index.ts delete mode 100644 src/app/shared/pipes/truncate/truncate.pipe.spec.ts delete mode 100644 src/app/shared/pipes/truncate/truncate.pipe.ts delete mode 100644 src/app/shared/services/area/area.service.spec.ts delete mode 100644 src/app/shared/services/area/area.service.ts delete mode 100644 src/app/shared/services/category/category.service.ts delete mode 100644 src/app/shared/services/file/file.service.spec.ts delete mode 100644 src/app/shared/services/file/file.service.ts delete mode 100644 src/app/shared/services/index.ts delete mode 100644 src/app/shared/services/local-storage/local-storage.service.spec.ts delete mode 100644 src/app/shared/services/local-storage/local-storage.service.ts delete mode 100644 src/app/shared/services/request-type/request-type.service.ts delete mode 100644 src/app/shared/services/sac-api/api-request-options.interface.ts delete mode 100644 src/app/shared/services/sac-api/sac-api.service.spec.ts delete mode 100644 src/app/shared/services/sac-api/sac-api.service.ts delete mode 100644 src/app/shared/services/user/user.service.spec.ts delete mode 100644 src/app/shared/services/user/user.service.ts delete mode 100644 src/app/shared/shared.constants.ts delete mode 100644 src/app/shared/shared.module.ts diff --git a/src/app/core/constants/routes-access.constant.ts b/src/app/core/constants/routes-access.constant.ts deleted file mode 100644 index a964a5e..0000000 --- a/src/app/core/constants/routes-access.constant.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -interface RoutesAccess { - PUBLIC: string[]; - AUTH_REQ: string[]; -} - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export const ROUTES_ACCESS: RoutesAccess = { - PUBLIC: ['login'], - AUTH_REQ: ['requests', 'admin'] -}; diff --git a/src/app/core/constants/routes-role-requirements.constant.ts b/src/app/core/constants/routes-role-requirements.constant.ts deleted file mode 100644 index 5a3738a..0000000 --- a/src/app/core/constants/routes-role-requirements.constant.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -import { USER_ROLES } from '../../shared/shared.constants'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -interface RoleRequirement { - ROUTE: string; - REQUIRED_ROLES: string[]; -} -interface RouteRoleRequirement { - ADMIN: RoleRequirement; - REQUESTS: RoleRequirement; -} - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export const ROUTES_ROLE_REQUIREMENTS: RouteRoleRequirement = { - ADMIN: { ROUTE: 'admin', REQUIRED_ROLES: ['Administrator'] }, - REQUESTS: { ROUTE: 'requests', REQUIRED_ROLES: ['Specialist'] } -}; diff --git a/src/app/core/enums/index.ts b/src/app/core/enums/index.ts deleted file mode 100644 index e5c5163..0000000 --- a/src/app/core/enums/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { NotificationType } from './notification-type.enum'; diff --git a/src/app/core/enums/notification-type.enum.ts b/src/app/core/enums/notification-type.enum.ts deleted file mode 100644 index 6364a77..0000000 --- a/src/app/core/enums/notification-type.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum NotificationType { - Success, - Info, - Warning, - Error -} diff --git a/src/app/core/guards/auth.guard.ts b/src/app/core/guards/auth.guard.ts deleted file mode 100644 index 3165bd6..0000000 --- a/src/app/core/guards/auth.guard.ts +++ /dev/null @@ -1,132 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -// Framework imports -import { Injectable } from '@angular/core'; -import { - CanActivate, - ActivatedRouteSnapshot, - RouterStateSnapshot, - Router -} from '@angular/router'; - -// Service Imports -import { SessionService } from '../services'; - -// Constants Imports -import { USER_ROLES } from '../../shared/shared.constants'; -import { User } from '../../shared/models'; -import { ROUTES_ACCESS } from '../constants/routes-access.constant'; -import { ROUTES_ROLE_REQUIREMENTS } from '../constants/routes-role-requirements.constant'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• GUARD DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class AuthGuard implements CanActivate { - /** ––– - * –– Constructor - */ - constructor(private sessionService: SessionService, private router: Router) {} - - /** ––– - * –– Helper methods - */ - - isIncludedRoute(searchedRoutes: string[], routes: ActivatedRouteSnapshot[]) { - return routes.some( - (activatedRoute: ActivatedRouteSnapshot) => - !!activatedRoute.url.length && - searchedRoutes.includes(activatedRoute.url[0].path) - ); - } - - isRouteValidUser(routeRequirements: string[], sessionUser: User) { - return routeRequirements.every(requirement => - sessionUser.hasRole(requirement) - ); - } - - /** ––– - * –– Lifecycle Hooks - */ - canActivate(nextState: ActivatedRouteSnapshot) { - const session = this.sessionService.getCurrent(), - isLoggedUser = session !== null; - - if ( - !isLoggedUser && - this.isIncludedRoute(ROUTES_ACCESS.AUTH_REQ, nextState.pathFromRoot) - ) { - this.router.navigate(['/login']); - } - - if ( - isLoggedUser && - this.isIncludedRoute(ROUTES_ACCESS.PUBLIC, nextState.pathFromRoot) - ) { - if (session.user.hasRole(USER_ROLES.SPECIALIST.LABEL)) { - this.router.navigate(['/requests']); - } else if (session.user.hasRole(USER_ROLES.ADMINISTRATOR.LABEL)) { - this.router.navigate(['/admin']); - } else { - this.sessionService.destroySession(); - } - } - - if ( - isLoggedUser && - this.isIncludedRoute(ROUTES_ACCESS.AUTH_REQ, nextState.pathFromRoot) - ) { - // Checks for user role requirements. - // Request validations. - if ( - this.isIncludedRoute( - [ROUTES_ROLE_REQUIREMENTS.REQUESTS.ROUTE], - nextState.pathFromRoot - ) && - !this.isRouteValidUser( - ROUTES_ROLE_REQUIREMENTS.REQUESTS.REQUIRED_ROLES, - session.user - ) - ) { - if ( - this.isRouteValidUser( - ROUTES_ROLE_REQUIREMENTS.ADMIN.REQUIRED_ROLES, - session.user - ) - ) { - this.router.navigate(['/admin']); - } else { - this.sessionService.destroySession(); - this.router.navigate(['/']); - } - } - - if ( - this.isIncludedRoute( - [ROUTES_ROLE_REQUIREMENTS.ADMIN.ROUTE], - nextState.pathFromRoot - ) && - !this.isRouteValidUser( - ROUTES_ROLE_REQUIREMENTS.ADMIN.REQUIRED_ROLES, - session.user - ) - ) { - if ( - this.isRouteValidUser( - ROUTES_ROLE_REQUIREMENTS.REQUESTS.REQUIRED_ROLES, - session.user - ) - ) { - this.router.navigate(['/requests']); - } else { - this.sessionService.destroySession(); - this.router.navigate(['/']); - } - } - } - - return true; - } -} diff --git a/src/app/core/interfaces/dialog.interface.ts b/src/app/core/interfaces/dialog.interface.ts deleted file mode 100644 index c617d28..0000000 --- a/src/app/core/interfaces/dialog.interface.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Subject } from 'rxjs/Subject'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface DialogConfig { - title: string; - message: string; - cancelAction: string; - applyAction: string; -} - -export interface DialogMessage { - config: DialogConfig; - response: Subject; -} diff --git a/src/app/core/interfaces/index.ts b/src/app/core/interfaces/index.ts deleted file mode 100644 index 05e9155..0000000 --- a/src/app/core/interfaces/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Notification } from './notification.interface'; -export { DialogMessage, DialogConfig } from './dialog.interface'; diff --git a/src/app/core/interfaces/notification.interface.ts b/src/app/core/interfaces/notification.interface.ts deleted file mode 100644 index 1145a2a..0000000 --- a/src/app/core/interfaces/notification.interface.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -import { NotificationType } from '../enums'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface Notification { - message: string; - type: NotificationType; -} diff --git a/src/app/core/services/dialog/dialog.service.ts b/src/app/core/services/dialog/dialog.service.ts deleted file mode 100644 index 5abe7ef..0000000 --- a/src/app/core/services/dialog/dialog.service.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports. -import { Injectable } from '@angular/core'; - -// Rxjs Imports -import { Observable } from 'rxjs/Observable'; -import { Subscription } from 'rxjs/Subscription'; -import { Observer, PartialObserver } from 'rxjs/Observer'; -import { Subject } from 'rxjs/Subject'; - -// App Imports -import { DialogMessage, DialogConfig } from '../../interfaces'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class DialogService { - /** ––– - * –– Variables - */ - - private dialogSource: Subject; - - /** ––– - * –– Constructor - */ - constructor() { - this.dialogSource = new Subject(); - } - - /** ––– - * –– Public Methods - */ - - subscribe( - observerOrNext?: (value: DialogMessage) => void, - error?: (value: any) => void, - complete?: () => void - ): Subscription { - return this.dialogSource.subscribe(observerOrNext, error, complete); - } - - unsubscribe(subscription: Subscription) { - subscription.unsubscribe(); - } - - displayDialog(config: DialogConfig): Observable { - const response = new Subject(); - this.dialogSource.next({ config, response }); - return response; - } -} diff --git a/src/app/core/services/notification/notification.service.spec.ts b/src/app/core/services/notification/notification.service.spec.ts deleted file mode 100644 index 3c87c4f..0000000 --- a/src/app/core/services/notification/notification.service.spec.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Testing Imports -import { TestBed, async, fakeAsync, inject, tick } from '@angular/core/testing'; - -// Rxjs Imports -import { Subscription } from 'rxjs/Subscription'; - -// App Imports -import { NotificationService } from './notification.service'; -import { Notification } from '../../interfaces'; -import { NotificationType } from '../../enums'; - -describe('CoreModule | NotificationService', () => { - /** - * –– Global Variables - */ - let notificationSubscription: Subscription; - - /** - * –– Global Functions - */ - beforeEach(() => { - // configures our module. - TestBed.configureTestingModule({ - providers: [NotificationService] - }); - }); - - afterEach(() => { - if (notificationSubscription) { - notificationSubscription.unsubscribe(); - } - }); - - /** - * –– Specs definitions - */ - it( - 'should subscribe to notification source', - async( - inject( - [NotificationService], - (notificationService: NotificationService) => { - notificationSubscription = notificationService.subscribe(); - - expect(notificationSubscription).toBeDefined(); - expect(notificationSubscription instanceof Subscription).toBeTruthy(); - } - ) - ) - ); - - it( - 'should unsubscribe to notification source', - async( - inject( - [NotificationService], - (notificationService: NotificationService) => { - notificationSubscription = notificationService.subscribe(); - expect(notificationSubscription.closed).toBeFalsy(); - - notificationService.unsubscribe(notificationSubscription); - expect(notificationSubscription.closed).toBeTruthy(); - - notificationSubscription = null; - } - ) - ) - ); - - it( - 'should push notifications', - fakeAsync( - inject( - [NotificationService], - (notificationService: NotificationService) => { - const successMessage = 'Se ha enviado la respuesta correctamente', - errorMessage = 'Sin conexión a internet', - infoMessage = 'Nuevas consultas disponibles'; - let receivedNotification, notificationResponse; - - notificationSubscription = notificationService.subscribe( - (notification: Notification) => - (receivedNotification = notification), - error => { - console.error(error); - fail(); - } - ); - - notificationResponse = notificationService.pushNotification( - successMessage - ); - - tick(200); - expect(receivedNotification).toEqual(notificationResponse); - expect(receivedNotification.message).toEqual(successMessage); - expect(receivedNotification.type).toEqual(NotificationType.Success); - - notificationResponse = notificationService.pushNotification( - successMessage, - NotificationType.Success - ); - - tick(200); - expect(receivedNotification).toEqual(notificationResponse); - expect(receivedNotification.message).toEqual(successMessage); - expect(receivedNotification.type).toEqual(NotificationType.Success); - - notificationResponse = notificationService.pushNotification( - errorMessage, - NotificationType.Error - ); - - tick(200); - expect(receivedNotification).toEqual(notificationResponse); - expect(receivedNotification.message).toEqual(errorMessage); - expect(receivedNotification.type).toEqual(NotificationType.Error); - - notificationResponse = notificationService.pushNotification( - infoMessage, - NotificationType.Info - ); - - tick(200); - expect(receivedNotification).toEqual(notificationResponse); - expect(receivedNotification.message).toEqual(infoMessage); - expect(receivedNotification.type).toEqual(NotificationType.Info); - } - ) - ) - ); - - it( - 'should not send notifications', - async( - inject( - [NotificationService], - (notificationService: NotificationService) => { - const wrongMessage = ''; - let notificationResponse; - - notificationResponse = notificationService.pushNotification( - wrongMessage - ); - expect(notificationResponse).toBeNull(); - - notificationResponse = notificationService.pushNotification( - wrongMessage, - NotificationType.Error - ); - expect(notificationResponse).toBeNull(); - } - ) - ) - ); -}); diff --git a/src/app/core/services/notification/notification.service.ts b/src/app/core/services/notification/notification.service.ts deleted file mode 100644 index 7227f09..0000000 --- a/src/app/core/services/notification/notification.service.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports. -import { Injectable } from '@angular/core'; - -// Rxjs Imports -import { Observable } from 'rxjs/Observable'; -import { Subscription } from 'rxjs/Subscription'; -import { PartialObserver } from 'rxjs/Observer'; -import { Subject } from 'rxjs/Subject'; - -// App Imports -import { Notification } from '../../interfaces'; -import { NotificationType } from '../../enums'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class NotificationService { - /** ––– - * –– Variables - */ - - private notificationSource: Subject; - - /** ––– - * –– Constructor - */ - constructor() { - this.notificationSource = new Subject(); - } - - /** ––– - * –– Public Methods - */ - - subscribe( - observerOrNext?: (value: Notification) => void, - error?: (value: any) => void, - complete?: () => void - ): Subscription { - return this.notificationSource.subscribe(observerOrNext, error, complete); - } - - unsubscribe(subscription: Subscription) { - subscription.unsubscribe(); - } - - pushNotification( - notificationMessage: string, - notificationType: NotificationType = NotificationType.Success - ) { - if (!notificationMessage || typeof notificationMessage !== 'string') { - return null; - } - - const notification = { - message: notificationMessage, - type: notificationType - }; - - this.notificationSource.next(notification); - - return notification; - } -} diff --git a/src/app/core/services/session/session.interface.ts b/src/app/core/services/session/session.interface.ts deleted file mode 100644 index cda6f7c..0000000 --- a/src/app/core/services/session/session.interface.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -import { User } from '../../../shared/models'; -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface Session { - user: User; - token: string; -} diff --git a/src/app/core/services/session/session.service.spec.ts b/src/app/core/services/session/session.service.spec.ts deleted file mode 100644 index a800e59..0000000 --- a/src/app/core/services/session/session.service.spec.ts +++ /dev/null @@ -1,231 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { - HttpModule, - Http, - ConnectionBackend, - BaseRequestOptions, - Response, - ResponseOptions -} from '@angular/http'; - -// Platform Testing Imports -import { TestBed, async, fakeAsync, inject, tick } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { MockBackend } from '@angular/http/testing'; - -// App Imports -import { SharedModule } from '../../../'; - -import { Session } from './session.interface'; - -import { SessionService } from './session.service'; -import { SACAPIService, LocalStorageService } from '../../../shared/services'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SUITE DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -describe('CoreModule | SessionService', () => { - /** - * –– Global Variables - */ - let backendSubscription, - sessionSubscription, - loginBody = - '{ "id": 1, "username": "szamora", "name": "Sofia", "lastname": "Zamora", "roles": ["Administrator"], "token": "example" }'; - - /** - * –– Global Functions - */ - beforeEach( - async(() => { - // configures our module. - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes([ - { path: 'login', component: MockLoginComponent }, - { path: 'requests', component: MockRequestComponent } - ]) - ], - declarations: [MockLoginComponent, MockRequestComponent], - providers: [ - SessionService, - MockBackend, - BaseRequestOptions, - SACAPIService, - LocalStorageService, - // Setup our mocked backend. - { - provide: Http, - useFactory: ( - backend: ConnectionBackend, - options: BaseRequestOptions - ) => new Http(backend, options), - deps: [MockBackend, BaseRequestOptions] - } - ] - }); - }) - ); - - afterEach(() => { - let result; - if (sessionSubscription) { - result = sessionSubscription.unsubscribe - ? sessionSubscription.unsubscribe() - : sessionSubscription.dispose(); - } - if (backendSubscription) { - result = backendSubscription.unsubscribe - ? backendSubscription.unsubscribe() - : backendSubscription.dispose(); - } - - localStorage.clear(); - }); - - /** - * –– Specs definitions - */ - it( - 'should successfully login a user', - async( - inject( - [SessionService, MockBackend], - (sessionService: SessionService, backend: MockBackend) => { - // Creates backend response. - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: loginBody, - status: 200 - }); - connection.mockRespond(new Response(response)); - }); - - sessionSubscription = sessionService - .createSession('username', 'password') - .subscribe( - (session: Session) => { - expect(session.user.name).toEqual('Sofia'); - expect(session.user.lastname).toEqual('Zamora'); - expect(session.user.username).toEqual('szamora'); - expect(session.user.roles).toContain('Administrator'); - expect(session.token).toEqual( - 'example' - ); - }, - error => { - fail('SessionService should create a session successfully'); - } - ); - } - ) - ) - ); - - it( - 'should handle unsuccessful login', - async( - inject( - [SessionService, MockBackend], - (sessionService: SessionService, backend: MockBackend) => { - // Creates backend response. - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: '{ "message": "USER NOT FOUND" }', - status: 404 - }); - connection.mockError(new Response(response)); - }); - - sessionSubscription = sessionService - .createSession('username', 'password') - .subscribe( - (session: Session) => - fail('SessionService should handle fal login request'), - error => expect(error.code).toBe(404) - ); - } - ) - ) - ); - - it( - 'should retrieve current session', - fakeAsync( - inject( - [SessionService, MockBackend], - (sessionService: SessionService, backend: MockBackend) => { - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: loginBody, - status: 200 - }); - connection.mockRespond(new Response(response)); - }); - - sessionSubscription = sessionService - .createSession('username', 'password') - .subscribe(); - - tick(500); - const session = sessionService.getCurrent(); - - expect(session).toBeTruthy(); - expect(session.user.name).toEqual('Sofia'); - expect(session.user.lastname).toEqual('Zamora'); - expect(session.user.username).toEqual('szamora'); - expect(session.user.roles).toContain('Administrator'); - expect(session.token).toEqual( - 'example' - ); - } - ) - ) - ); - - it( - 'should return null when there is no current session', - async( - inject([SessionService], (sessionService: SessionService) => { - const session = sessionService.getCurrent(); - expect(session).toBeNull(); - }) - ) - ); - - it( - 'should remove current session', - fakeAsync( - inject( - [SessionService, MockBackend], - (sessionService: SessionService, backend: MockBackend) => { - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: loginBody, - status: 200 - }); - connection.mockRespond(new Response(response)); - }); - - sessionSubscription = sessionService - .createSession('username', 'password') - .subscribe(); - - tick(500); - let session = sessionService.getCurrent(); - expect(session).toBeTruthy(); - - sessionService.destroySession(); - - session = sessionService.getCurrent(); - expect(session).toBeNull(); - } - ) - ) - ); -}); diff --git a/src/app/core/services/session/session.service.ts b/src/app/core/services/session/session.service.ts deleted file mode 100644 index 070894e..0000000 --- a/src/app/core/services/session/session.service.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; - -// App Imports -import { SACAPIService } from '../../../shared/services/sac-api/sac-api.service'; -import { LocalStorageService } from '../../../shared/services/local-storage/local-storage.service'; - -import { User } from '../../../shared/models'; -import { Session } from './session.interface'; - -// Rxjs Imports -import { Observable } from 'rxjs/Observable'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class SessionService { - /** ––– - * –– Constants - */ - private STORAGE_KEY = 'QZYMAQRMK'; - - /** ––– - * –– Variables - */ - private sessionBackup: Session; - private session: Session; - - /** ––– - * –– Constructor - */ - constructor( - private router: Router, - private sacapiService: SACAPIService, - private localStorageService: LocalStorageService - ) {} - - /** ––– - * Helper Methods - */ - - private createLocalReference(responseObject: any): Session { - const user: User = - responseObject.user instanceof User - ? responseObject.user - : new User(responseObject), - session = { user, token: responseObject.token }; - - // Stores created session in localStorage. - const storeResult = this.localStorageService.storeValue( - this.STORAGE_KEY, - session - ); - - if (!storeResult) { - console.error('Session was not stored'); - } - - return session; - } - - /** ––– - * –– Public Methods - */ - - createSession(username: string, password: string) { - return this.sacapiService - .post('/user', { username, password }) - .map(response => { - this.session = this.createLocalReference(response); - this.sessionBackup = this.session; - return this.session; - }); - } - - getCurrent() { - // If session is not defined look at localSotrage value. - if (!this.session) { - this.session = this.localStorageService.getValue( - this.STORAGE_KEY - ); - if (this.session) { - this.session.user = new User(this.session.user); - this.sessionBackup = this.session; - } - } - - return this.session; - } - - destroySession() { - // First remove stored value. - const removeResult = this.localStorageService.removeValue(this.STORAGE_KEY); - - if (this.session) { - this.session = undefined; - } - } - - restoreSession() { - this.session = this.createLocalReference(this.sessionBackup); - } - - checkAuthenticatedInterceptor() { - const sessionService = this; - return function(error) { - if (error.code === 401) { - sessionService.destroySession(); - sessionService.router.navigate(['login']); - } - return Observable.throw(error); - }; - } -} diff --git a/src/app/shared/components/custom-select/custom-select.component.html b/src/app/shared/components/custom-select/custom-select.component.html deleted file mode 100644 index 92202ac..0000000 --- a/src/app/shared/components/custom-select/custom-select.component.html +++ /dev/null @@ -1,31 +0,0 @@ -
-
-
- - - {{selectedItem.value}} - -
- -
- -
\ No newline at end of file diff --git a/src/app/shared/components/custom-select/custom-select.component.scss b/src/app/shared/components/custom-select/custom-select.component.scss deleted file mode 100644 index 50847cb..0000000 --- a/src/app/shared/components/custom-select/custom-select.component.scss +++ /dev/null @@ -1,115 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SAC client RequestList styling •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ -@import "../../../../style/sac.base"; - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ - -// Colors -$border-color: #000000; -$dropdown-background-color: #FFFFFF; -$item-over-color: #F1F3F5; - -$content-header-color: #AAADB0; -$item-border-color: #E3E7EA; -$selected-item-color: #03B576; - -// List padding -$content-padding: .425em; - -// Transitions -$soft-bezier: cubic-bezier(0.25, 0.8, 0.25, 1); - -/* ––––––––––––––––– GENERAL ––––––––––––––––– */ - -.custom-select { - position: relative; - width: 100%; -} -/* ––––––––––––––––– HEADER ––––––––––––––––– */ - -.custom-select > header { - display: flex; - align-items: center; - justify-content: space-between; - - padding: $content-padding $content-padding * 1.33 $content-padding $content-padding * 2; - - border-radius: 3px; - border: 1px solid $border-color; - cursor: pointer; - - .header-content { - width: 95%; - - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - i { - font-size: .9em; - } -} - -/* ––––––––––––––––– DROPDOWN ––––––––––––––––– */ - -.dropdown-container { - position: absolute; - top: 0; - left: 0; - - overflow-y: auto; - max-height: 300px; - width: 100%; - - box-shadow: 0 8px 12px rgba(0,0,0,.13); - transform-origin: center top; - - background-color: $dropdown-background-color; - - & > header { - padding: .25em 0; - - .header-label { - padding: $content-padding * 1.35 $content-padding * 2.5; - color: $content-header-color; - font-size: .935em; - font-weight: 300; - } - - &.fixed { - border-bottom: 1px solid $item-border-color; - } - } - - .items-container { - padding: .25em 0 .25em; - } -} - -/* ––––––––––––––––– DROPDOWN ITEM ––––––––––––––––– */ - -.item { - - padding: $content-padding * 1.5 $content-padding * 2.5; - - transition: background-color 1s $soft-bezier; - will-change: background-color; - - &:hover { - background-color: $item-over-color; - cursor: pointer; - } - - &.selected { - color: $selected-item-color; - } -} - -.empty-message { - padding: .4em .4em 1em; - text-align: center; -} \ No newline at end of file diff --git a/src/app/shared/components/custom-select/custom-select.component.ts b/src/app/shared/components/custom-select/custom-select.component.ts deleted file mode 100644 index 9b7d145..0000000 --- a/src/app/shared/components/custom-select/custom-select.component.ts +++ /dev/null @@ -1,205 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform imports -import { - Component, - OnInit, - Input, - Output, - EventEmitter, - Renderer, - state, - style, - transition, - animate, - trigger -} from '@angular/core'; - -import { CUSTOM_SELECT } from './custom-select.constants'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• COMPONENT DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Component({ - moduleId: module.id, - selector: 'custom-select', - templateUrl: 'custom-select.component.html', - styleUrls: ['custom-select.component.scss'], - animations: [ - trigger('openState', [ - state( - CUSTOM_SELECT.STATE.OPEN, - style({ - opacity: 1, - 'pointer-events': 'all', - transform: 'scaleY(1)' - }) - ), - state( - CUSTOM_SELECT.STATE.CLOSE, - style({ - opacity: 0, - 'pointer-events': 'none', - transform: 'scaleY(0)' - }) - ), - transition( - `${CUSTOM_SELECT.STATE.CLOSE} <=> ${CUSTOM_SELECT.STATE.OPEN}`, - animate('.25s cubic-bezier(0.25, 0.8, 0.25, 1)') - ) - ]) - ] -}) -export class CustomSelectComponent implements OnInit { - /** ––– - * –– Variables - */ - - private _datasource: any[]; - private _fixedIndex: number; - private _fixedId: number; - private _selectedId: number | number[]; - private _selectedIndex: number; - private disposeGlobalListener; - - public multipleSelection: boolean; - public dropdownState: string; - - /** ––– - * –– Getters / Setters - */ - public; - get fixedItem() { - return this._fixedIndex !== null && this._datasource[this._fixedIndex]; - } - get dynamicItems() { - return this._fixedIndex !== null - ? Array.prototype.concat.apply( - this._datasource.slice(0, this._fixedIndex), - this._datasource.slice(this._fixedIndex + 1) - ) - : this._datasource; - } - - set selectedItem(item: any) { - this.multipleSelection = false; - this._selectedIndex = null; - - if (item) { - this._datasource.forEach((sourceItem, index) => { - sourceItem.selected = sourceItem[this.itemId] === item[this.itemId]; - if (sourceItem.selected) { - this._selectedIndex = index; - } - }); - } else { - this._datasource.forEach(item => (item.selected = false)); - } - } - get selectedItem() { - return ( - this._selectedIndex !== null && this._datasource[this._selectedIndex] - ); - } - - @Input() itemId = 'id'; - - @Input() - set data(datasource: any[]) { - this._datasource = datasource || []; - - // Recalculates defined selections. - if (!this._selectedIndex && this._selectedId) { - this.selectedId = this._selectedId; - } - this.fixedId = this._fixedId; - } - get data() { - return this._datasource; - } - - @Input() - set fixedId(newFixedId: number) { - this._fixedIndex = null; - this._fixedId = newFixedId; - - this._datasource.some((item, index) => { - const matchedValue = newFixedId === item[this.itemId]; - - if (matchedValue) { - this._fixedIndex = index; - } - return matchedValue; - }); - } - - @Input() - set selectedId(id: number | number[]) { - this._selectedId = id; - this.multipleSelection = id instanceof Array; - this._selectedIndex = null; - - if (this.multipleSelection) { - this.data.forEach(item => (item.selected = false)); - } else { - this.data.forEach((item, index) => { - item.selected = item[this.itemId] === id; - if (item.selected) { - this._selectedIndex = index; - } - }); - } - } - - @Output() - change: EventEmitter<{ - selectedIndex: number; - selectedItem: any; - }> = new EventEmitter<{ selectedIndex: number; selectedItem: any }>(); - - /** ––– - * –– Constructor - */ - constructor(private renderer: Renderer) {} - - /** ––– - * –– Lifecycle hooks - */ - ngOnInit() { - this.dropdownState = CUSTOM_SELECT.STATE.CLOSE; - } - - /** ––– - * –– Helper functions - */ - - /** ––– - * –– Public functions - */ - - toggleDropdown($event) { - if (this.dropdownState === CUSTOM_SELECT.STATE.CLOSE) { - $event.stopPropagation(); - this.disposeGlobalListener = this.renderer.listenGlobal( - 'body', - 'click', - $event => this.toggleDropdown($event) - ); - - this.dropdownState = CUSTOM_SELECT.STATE.OPEN; - } else { - this.disposeGlobalListener(); - this.dropdownState = CUSTOM_SELECT.STATE.CLOSE; - } - } - - selectItem(item) { - this.selectedItem = item; - this.change.emit({ - selectedIndex: this._selectedIndex, - selectedItem: this.selectedItem - }); - } -} diff --git a/src/app/shared/components/custom-select/custom-select.constants.ts b/src/app/shared/components/custom-select/custom-select.constants.ts deleted file mode 100644 index 083ae36..0000000 --- a/src/app/shared/components/custom-select/custom-select.constants.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export const CUSTOM_SELECT = { - STATE: { - OPEN: 'open', - CLOSE: 'close' - } -}; diff --git a/src/app/shared/components/dialog/dialog.component.html b/src/app/shared/components/dialog/dialog.component.html deleted file mode 100644 index 6ba70ca..0000000 --- a/src/app/shared/components/dialog/dialog.component.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
- {{ dialogConfig?.title }} - -
-
- {{ dialogConfig?.message }} -
-
- - -
-
\ No newline at end of file diff --git a/src/app/shared/components/dialog/dialog.component.scss b/src/app/shared/components/dialog/dialog.component.scss deleted file mode 100644 index e17c3a7..0000000 --- a/src/app/shared/components/dialog/dialog.component.scss +++ /dev/null @@ -1,100 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• Dialog styling •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -/* ––––––––––––––––– IMPORTS ––––––––––––––––– */ -@import "../../../../style/sac.base"; - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ - -// Colors -$error-color: #D50000; -$header-color: #215280; -$light-font: #FFFFFF; -$content-color: #727475; -$overlay-color: rgba(0, 0, 0, .46); - -/* ––––––––––––––––– GENERAL ––––––––––––––––– */ - -:host { - position: fixed; - - display: flex; - align-items: center; - justify-content: center; - - z-index: 2; - - width: 100%; - height: 100%; - - background-color: $overlay-color; - -} - -/* ––––––––––––––––– DIALOG ––––––––––––––––– */ - -.container { - width: 40%; - - border-radius: 4px; - - background-color: $light-font; - - & > header { - display: flex; - justify-content: space-between; - align-items: center; - - padding: .7em .7em .55em; - - font-size: 1.33em; - font-weight: 300; - color: $light-font; - background-color: $header-color; - - i { - cursor: pointer; - font-size: .75em; - } - } - - & > footer { - padding: .8em 1em; - - text-align: right; - - button { - padding: .5em .75em; - min-width: 120px; - - cursor: pointer; - border-radius: 3px; - text-align: center; - - &[type="submit"] { - color: $light-font; - background-color: $error-color; - } - } - } -} - -.content { - padding: .9em 1em 1.2em; - - color: $content-color; - -} - -/* ––––––––––––––––– MEDIA QUERIES ––––––––––––––––– */ - -@media screen { - @media (min-width: $lg-devices){ - .container { width: 35%; } - } - - @media (min-width: $xl-devices){ - .container { width: 30%; } - } -} \ No newline at end of file diff --git a/src/app/shared/components/dialog/dialog.component.ts b/src/app/shared/components/dialog/dialog.component.ts deleted file mode 100644 index eba4935..0000000 --- a/src/app/shared/components/dialog/dialog.component.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform imports -import { - Component, - OnInit, - HostBinding, - trigger, - state, - style, - transition, - animate -} from '@angular/core'; - -// App Imports -import { DialogService } from '../../../core/services'; -import { DialogMessage, DialogConfig } from '../../../core/interfaces'; - -import { DIALOG } from './dialog.constants'; - -// Rxjs Imports -import { Subject } from 'rxjs/Subject'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• COMPONENT DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Component({ - moduleId: module.id, - selector: 'dialog-popup', - templateUrl: 'dialog.component.html', - styleUrls: ['dialog.component.scss'], - host: { - '[@displayState]': 'getDisplayState()' - }, - animations: [ - trigger('displayState', [ - state( - DIALOG.STATE.DISPLAYED, - style({ - opacity: 1, - pointerEvents: 'all' - }) - ), - state( - DIALOG.STATE.HIDDEN, - style({ - opacity: 0, - pointerEvents: 'none' - }) - ), - transition( - `${DIALOG.STATE.HIDDEN} => ${DIALOG.STATE.DISPLAYED}`, - animate('.5s cubic-bezier(0.25, 0.8, 0.25, 1)') - ), - transition( - `${DIALOG.STATE.DISPLAYED} => ${DIALOG.STATE.HIDDEN}`, - animate('.2s cubic-bezier(0.25, 0.8, 0.25, 1)') - ) - ]) - ] -}) -export class DialogComponent implements OnInit { - /** ––– - * –– Variables - */ - private dialogResponse: Subject; - public dialogState: string; - public dialogConfig: DialogConfig; - - /** ––– - * –– Constructor - */ - constructor(private dialogService: DialogService) {} - - ngOnInit() { - this.dialogState = DIALOG.STATE.HIDDEN; - - // Subscribe to DialogService. - this.dialogService.subscribe(dialogMessage => { - if (!this.dialogResponse || this.dialogResponse.isStopped) { - this.dialogConfig = dialogMessage.config; - this.dialogState = DIALOG.STATE.DISPLAYED; - - // Set response observer. - this.dialogResponse = dialogMessage.response; - } - }); - } - - private sendResponse(value: boolean) { - if (this.dialogResponse && !this.dialogResponse.closed) { - this.dialogResponse.next(value); - this.dialogResponse.complete(); - this.dialogState = DIALOG.STATE.HIDDEN; - } - } - - private getDisplayState() { - return this.dialogState; - } - - /** ––– - * –– Public Methods - */ - dismiss() { - this.sendResponse(false); - } - - confirm() { - this.sendResponse(true); - } -} diff --git a/src/app/shared/components/dialog/dialog.constants.ts b/src/app/shared/components/dialog/dialog.constants.ts deleted file mode 100644 index 79d616a..0000000 --- a/src/app/shared/components/dialog/dialog.constants.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export const DIALOG = { - STATE: { - DISPLAYED: 'displayed', - HIDDEN: 'hidden' - } -}; diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts deleted file mode 100644 index 23d890f..0000000 --- a/src/app/shared/components/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { CustomSelectComponent } from './custom-select/custom-select.component'; -export { NotificationToasterComponent } from './notification-toaster/notification-toaster.component'; -export { DialogComponent } from './dialog/dialog.component'; -export { TagListSelectComponent } from './tag-list-select/tag-list-select.component'; diff --git a/src/app/shared/components/notification-toaster/notification-toaster.component.html b/src/app/shared/components/notification-toaster/notification-toaster.component.html deleted file mode 100644 index e8ff25c..0000000 --- a/src/app/shared/components/notification-toaster/notification-toaster.component.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

{{ notificationMessage | truncate:70 }}

-
\ No newline at end of file diff --git a/src/app/shared/components/notification-toaster/notification-toaster.component.scss b/src/app/shared/components/notification-toaster/notification-toaster.component.scss deleted file mode 100644 index 8484bc9..0000000 --- a/src/app/shared/components/notification-toaster/notification-toaster.component.scss +++ /dev/null @@ -1,59 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• Notification toaster styling •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ -// @import "../../../style/sac.base"; - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ - -// Colors -$success-color: #03C882; -$error-color: #D50000; -$light-font: #FFFFFF; - -// Margins -$border-margin: 16px; - -/* ––––––––––––––––– GENERAL ––––––––––––––––– */ - -:host { - position: relative; -} - -/* ––––––––––––––––– NOTIFICATION ––––––––––––––––– */ - -.notification { - position: absolute; - bottom: $border-margin; - left: $border-margin; - - width: 315px; - height: 68px; - - padding: 1em; - box-shadow: 0px 11px 17px 0 rgba(0, 0, 0, 0.22); - - font-size: 1.075em; - font-weight: 300; - - p { - display: flex; - - i { - display: inline-block; - padding-top: .05em; - margin-right: .6em; - } - } - - &.success { - color: $light-font; - background-color: $success-color; - } - - &.error { - color: $light-font; - background-color: $error-color; - } -} \ No newline at end of file diff --git a/src/app/shared/components/notification-toaster/notification-toaster.component.ts b/src/app/shared/components/notification-toaster/notification-toaster.component.ts deleted file mode 100644 index 341577b..0000000 --- a/src/app/shared/components/notification-toaster/notification-toaster.component.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform imports -import { - Component, - OnInit, - trigger, - state, - style, - transition, - animate -} from '@angular/core'; - -// App Imports -import { NotificationService } from '../../../core/services'; -import { Notification } from '../../../core/interfaces'; -import { NotificationType } from '../../../core/enums'; - -import { NOTIFICATION } from './notification.constants'; - -// Rxjs Imports -import { Observable } from 'rxjs/Observable'; -import { Subscription } from 'rxjs/Subscription'; -import 'rxjs/add/observable/interval'; -import 'rxjs/add/operator/take'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• COMPONENT DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Component({ - moduleId: module.id, - selector: 'notification-toaster', - templateUrl: 'notification-toaster.component.html', - styleUrls: ['notification-toaster.component.scss'], - animations: [ - trigger('displayState', [ - state( - NOTIFICATION.STATE.INACTIVE, - style({ - transform: 'translateY(150%)' - }) - ), - state( - NOTIFICATION.STATE.ACTIVE, - style({ - transform: 'translateY(0)' - }) - ), - transition( - `${NOTIFICATION.STATE.INACTIVE} => ${NOTIFICATION.STATE.ACTIVE}`, - animate('.35s cubic-bezier(0.25, 0.8, 0.25, 1)') - ), - transition( - `${NOTIFICATION.STATE.ACTIVE} => ${NOTIFICATION.STATE.INACTIVE}`, - animate('.23s cubic-bezier(0.25, 0.8, 0.25, 1)') - ) - ]) - ] -}) -export class NotificationToasterComponent implements OnInit { - /** ––– - * –– Variables - */ - private notificationSubscription: Subscription; - private intervalChecker$: Observable; - private notificationStack: Notification[]; - private timerSubscription: Subscription; - - public notificationMessage: string; - public notificationState: string; - public notificationIcon: string; - public notificationType: string; - - public; - set notification(notification: Notification) { - // If not interval set, fires it, otherwise stack it. - if (!this.timerSubscription) { - this.setNotificationValues(notification); - this.notificationState = NOTIFICATION.STATE.ACTIVE; - - this.timerSubscription = this.intervalChecker$.subscribe( - (second: number) => { - if ( - second === NOTIFICATION.TIME_HOOKS.FINISHED || - (second >= NOTIFICATION.TIME_HOOKS.DISPOSABLE && - this.notificationStack.length) - ) { - this.notificationState = NOTIFICATION.STATE.INACTIVE; - this.disposeTimerSubscription(); - } - }, - error => { - this.notificationState = NOTIFICATION.STATE.INACTIVE; - } - ); - } else { - this.notificationStack.push(notification); - } - } - - /** ––– - * –– Constructor - */ - constructor(private notificationService: NotificationService) { - this.intervalChecker$ = Observable.interval(1000); - } - - /** ––– - * –– Helper methods - */ - private disposeTimerSubscription() { - this.timerSubscription.unsubscribe(); - this.timerSubscription = null; - this.fireNextNotification(); - } - - private fireNextNotification() { - setTimeout(() => { - if (this.notificationStack.length) { - this.notification = this.notificationStack.shift(); - } - }, NOTIFICATION.SWITCH_DELAY); - } - - private setNotificationValues(notification: Notification) { - const styleObject = NOTIFICATION.STYLES_MAP.get(notification.type); - this.notificationMessage = notification.message; - this.notificationIcon = styleObject.icon; - this.notificationType = styleObject.class; - } - - /** ––– - * –– Lifecycle hooks - */ - ngOnInit() { - this.notificationStack = []; - this.notificationState = NOTIFICATION.STATE.INACTIVE; - - this.notificationSubscription = this.notificationService.subscribe( - (notification: Notification) => { - this.notification = notification; - }, - error => { - console.group('Error during observing for notifications'); - console.error(error); - console.groupEnd(); - } - ); - } - - /** ––– - * –– Public methods - */ -} diff --git a/src/app/shared/components/notification-toaster/notification.constants.ts b/src/app/shared/components/notification-toaster/notification.constants.ts deleted file mode 100644 index e1a7696..0000000 --- a/src/app/shared/components/notification-toaster/notification.constants.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -import { NotificationType } from '../../../core/enums'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -const notificationClass = new Map< - NotificationType, - { icon: string; class: string } ->(); -notificationClass.set(NotificationType.Success, { - icon: 'icon-check', - class: 'success' -}); -notificationClass.set(NotificationType.Error, { - icon: 'icon-warning', - class: 'error' -}); - -export const NOTIFICATION = { - STATE: { - INACTIVE: 'off', - ACTIVE: 'on' - }, - STYLES_MAP: notificationClass, - TIME_HOOKS: { - DISPOSABLE: 1, - FINISHED: 4 - }, - SWITCH_DELAY: 500 -}; diff --git a/src/app/shared/components/tag-list-select/tag-list-select.component.html b/src/app/shared/components/tag-list-select/tag-list-select.component.html deleted file mode 100644 index 1c23aab..0000000 --- a/src/app/shared/components/tag-list-select/tag-list-select.component.html +++ /dev/null @@ -1,31 +0,0 @@ -
- - - - -
-
- -
-
- {{ selectedItem.label }} -
-
-
diff --git a/src/app/shared/components/tag-list-select/tag-list-select.component.scss b/src/app/shared/components/tag-list-select/tag-list-select.component.scss deleted file mode 100644 index 6de2128..0000000 --- a/src/app/shared/components/tag-list-select/tag-list-select.component.scss +++ /dev/null @@ -1,160 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SAC client RequestList styling •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ -// @import "../../../../style/sac.base"; - -/* ––––––––––––––––– VARIABLES ––––––––––––––––– */ - -// Colors -$soft-border-color: #979797; -$dropdown-background-color: #FFFFFF; -$item-over-color: #F1F3F5; -$soft-font-color: #727475; -$content-header-color: #AAADB0; - -$input-color: #000000; -$input-back-color: #FFFFFF; -$input-border-color: #CCCCCC; -$placeholder-color: #9F9F9F; - -// List padding -$content-padding: .425em; -$select-width: 70%; - -// Transitions -$soft-bezier: cubic-bezier(0.25, 0.8, 0.25, 1); - -/* ––––––––––––––––– GENERAL ––––––––––––––––– */ - -/* ––––––––––––––––– BLOCK_LABELS ––––––––––––––––– */ - -.search-block /deep/ [search-label], .selected-block /deep/ [selected-label] { - display: block; - - margin-bottom: .325em; - - font-size: 1.075em; - color: $soft-font-color; -} - -/* ––––––––––––––––– SEARCH SECTION ––––––––––––––––– */ - -.search-block { - position: relative; - margin-bottom: .75em; -} - -input { - width: 100%; - - padding: 0 .8em; - border-radius: 5px; - border: 1px solid $input-border-color; - line-height: 2.7; - - color: $input-color; - background-color: $input-back-color; - - &::-webkit-input-placeholder { - color: $placeholder-color; - font-weight: 300; - font-style: italic; - } - - &:-moz-placeholder { - color: $placeholder-color; - font-weight: 300; - font-style: italic; - } - - &::-moz-placeholder { - color: $placeholder-color; - font-weight: 300; - font-style: italic; - } - - &:-ms-input-placeholder { - color: $placeholder-color; - font-weight: 300; - font-style: italic; - } -} - -/* ––––––––––––––––– DROPDOWN ––––––––––––––––– */ - -.dropdown { - position: absolute; - top: 102.5%; - left: 0; - - z-index: 2; - overflow-y: auto; - max-height: 300px; - width: $select-width; - - box-shadow: 0 8px 12px rgba(0,0,0,.13); - transform-origin: center top; - - background-color: $dropdown-background-color; - - & > header { - padding: $content-padding * 1.35 $content-padding * 2.5; - color: $content-header-color; - font-size: .935em; - font-weight: 300; - } -} - -/* ––––––––––––––––– DROPDOWN ITEM ––––––––––––––––– */ - -.dropdown-item { - - padding: $content-padding * 1.5 $content-padding * 2.5; - cursor: pointer; - - transition: background-color .26s $soft-bezier; - will-change: background-color; - - &.highlighted { - background-color: $item-over-color; - } -} - -/* ––––––––––––––––– SELECTED ITEMS ––––––––––––––––– */ - -.selected-items { - width: 100%; -} - -.selected-item { - display: inline-flex; - align-items: center; - - padding: .4em .7em; - margin-right: 5px; - margin-bottom: 3px; - - border-radius: 3px; - border: 1px solid $soft-border-color; - - .selected-item__label { - flex-shrink: 0; - font-size: 1.075em; - color: $soft-font-color; - - } - - .remove-section { - width: 30px; - text-align: right; - cursor: pointer; - font-size: .93em; - } -} - -.empty-hints { - padding: .4em .4em 1em; - text-align: center; -} \ No newline at end of file diff --git a/src/app/shared/components/tag-list-select/tag-list-select.component.ts b/src/app/shared/components/tag-list-select/tag-list-select.component.ts deleted file mode 100644 index 7975061..0000000 --- a/src/app/shared/components/tag-list-select/tag-list-select.component.ts +++ /dev/null @@ -1,350 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { - Component, - Input, - ViewChild, - ElementRef, - forwardRef, - Renderer, - trigger, - transition, - state, - animate, - style -} from '@angular/core'; -import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; - -// App Imports -import { TAG_LIST_SELECT } from './tag-list-select.constants'; -import { TagListSelectItem } from '../../interfaces'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -const TAG_LIST_SELECT_VALUE_ACCESSOR = { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => TagListSelectComponent), - multi: true -}; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• COMPONENT DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -@Component({ - moduleId: module.id, - selector: 'tag-list-select', - templateUrl: 'tag-list-select.component.html', - styleUrls: ['tag-list-select.component.scss'], - providers: [TAG_LIST_SELECT_VALUE_ACCESSOR], - animations: [ - trigger('openState', [ - state( - TAG_LIST_SELECT.STATE.OPEN, - style({ - opacity: 1, - 'pointer-events': 'all', - transform: 'scaleY(1)' - }) - ), - state( - TAG_LIST_SELECT.STATE.CLOSE, - style({ - opacity: 0, - 'pointer-events': 'none', - transform: 'scaleY(0)' - }) - ), - transition( - `${TAG_LIST_SELECT.STATE.CLOSE} <=> ${TAG_LIST_SELECT.STATE.OPEN}`, - animate('.25s cubic-bezier(0.25, 0.8, 0.25, 1)') - ) - ]) - ] -}) -export class TagListSelectComponent implements ControlValueAccessor { - /** ––– - * –– Variables - */ - private selectedItems: any[]; - private selectedIndeces: number[]; - private datasource: TagListSelectItem[]; - private isDataReady: boolean; - private touched: boolean; - private showHints: boolean; - private datasourceIndeces: { [key: string]: number[] }; - private filteredIndeces: number[]; - private highlightedIndex: number; - private storedCriteria: string; - private disposeGlobalListener: Function; - - private onChangeHandler: (selectedItems: any[]) => any; - private onTouchedHandler: () => any; - - public dropdownState: string; - public searchCriteria: string; - - /** ––– - * –– Inputs / Outputs - */ - - @ViewChild('dropdown') dropdownContainer: ElementRef; - - @Input() fixedItems: number[] = []; - @Input() placeholder = 'Seleccionar'; - @Input() - - /** ––– - * –– Getters / Setters - */ - set data(datasource: TagListSelectItem[]) { - this.isDataReady = datasource instanceof Array && !!datasource.length; - - this.datasource = datasource; - - // Makes items chuncks for improving search performance. - this.datasource.forEach((item, index) => { - const initialKeys = item.label - .toLowerCase() - .split(' ') - .map(nameWord => nameWord[0] || '') - .filter( - (initialWord, wordIndex, array) => - initialWord && array.indexOf(initialWord) === wordIndex - ); - - initialKeys.forEach(initialKey => { - const keyRecord = this.datasourceIndeces[initialKey]; - - if (!keyRecord) { - this.datasourceIndeces[initialKey] = [index]; - } else { - keyRecord.push(index); - } - }); - }); - - this.updateView(); - } - - get selectedValues() { - return this.selectedIndeces.map(index => this.datasource[index]); - } - - get availableValues() { - return this.showHints - ? this.filteredIndeces - .filter( - filteredIndex => this.selectedIndeces.indexOf(filteredIndex) < 0 - ) - .map(filteredIndex => this.datasource[filteredIndex]) - .filter(item => item.label.toLowerCase().match(this.storedCriteria)) - : []; - } - - /** ––– - * –– Constructor - */ - - constructor(private renderer: Renderer) { - this.selectedItems = []; - this.filteredIndeces = []; - this.selectedIndeces = []; - this.onChangeHandler = () => {}; - this.onTouchedHandler = () => {}; - this.dropdownState = TAG_LIST_SELECT.STATE.CLOSE; - this.datasourceIndeces = {}; - } - - /** ––– - * –– Helpers - */ - - private updateHighlightedIndex(isUp: boolean) { - const hintsLength = this.availableValues.length; - - if (isUp && this.highlightedIndex > 0) { - this.highlightedIndex--; - this.updateDropdownScroll(); - } else if (!isUp && this.highlightedIndex < hintsLength - 1) { - this.highlightedIndex++; - this.updateDropdownScroll(); - } - } - - private updateDropdownScroll() { - const highlightedItem = this.dropdownContainer.nativeElement.children[ - this.highlightedIndex + 1 - ], - scrollViewRange = { - start: this.dropdownContainer.nativeElement.scrollTop, - end: - this.dropdownContainer.nativeElement.scrollTop + - this.dropdownContainer.nativeElement.offsetHeight - - TAG_LIST_SELECT.SCROLL.MARGIN - }; - - if (highlightedItem.offsetTop > scrollViewRange.end) { - this.dropdownContainer.nativeElement.scrollTop = Math.min( - this.dropdownContainer.nativeElement.scrollHeight - - this.dropdownContainer.nativeElement.offsetHeight, - scrollViewRange.start + TAG_LIST_SELECT.SCROLL.CHUNK - ); - } else if (highlightedItem.offsetTop < scrollViewRange.start) { - this.dropdownContainer.nativeElement.scrollTop = Math.max( - 0, - scrollViewRange.start - TAG_LIST_SELECT.SCROLL.CHUNK - ); - } - } - - private updateView() { - // Process selectedItems until data is set. - if (this.isDataReady && this.selectedItems.length) { - let foundCount = 0, - foundSelectedItems = []; - - this.selectedIndeces = []; - - this.datasource.some((sourceItem, index) => { - if (this.selectedItems.indexOf(sourceItem.id) !== -1) { - this.selectedIndeces.push(index); - foundSelectedItems.push(sourceItem.id); - foundCount++; - } - return foundCount === this.selectedItems.length; - }); - - if (this.selectedItems.length !== foundSelectedItems.length) { - this.selectedItems = foundSelectedItems; - this.onChangeHandler(this.selectedItems); - } - } - } - - private updateModel() { - // Evaluates control and emit a value change. - this.selectedItems = this.selectedIndeces.map( - index => this.datasource[index].id - ); - - this.onChangeHandler(this.selectedItems); - } - - /** ––– - * –– ControlValueAccessor methods - */ - - writeValue(modelValue) { - if (modelValue instanceof Array) { - this.selectedItems = modelValue; - - this.updateView(); - } - } - - registerOnChange(changeHandler: (selectedItems: any[]) => any) { - this.onChangeHandler = changeHandler; - } - - registerOnTouched(touchedHandler: () => any) { - this.onTouchedHandler = touchedHandler; - } - - /** ––– - * –– Public methods - */ - - addItem(item: TagListSelectItem) { - this.selectedIndeces.push(this.datasource.indexOf(item)); - - this.updateModel(); - - this.storedCriteria = ''; - this.searchCriteria = ''; - this.updateCriteriaHints(this.searchCriteria); - } - - keyboardHandler(event) { - if (this.showHints && this.availableValues.length) { - switch (event.keyCode) { - case 13: - this.addItem(this.availableValues[this.highlightedIndex]); - break; - case 38: - case 40: - this.updateHighlightedIndex(event.keyCode < 40); - break; - } - } - } - - removeItem(selectedItemIndex: number) { - this.selectedIndeces.splice(selectedItemIndex, 1); - - this.updateModel(); - - this.onTouchedHandler(); - } - - updateCriteriaHints(searchCriteria) { - searchCriteria = searchCriteria.toLowerCase(); - - if (searchCriteria.length >= 1) { - if ( - !this.showHints || - (this.showHints && searchCriteria[0] !== this.storedCriteria[0]) - ) { - this.filteredIndeces = this.datasourceIndeces[searchCriteria[0]]; - this.dropdownState = TAG_LIST_SELECT.STATE.OPEN; - this.showHints = true; - } - } else { - this.closeSelection(); - } - - this.highlightedIndex = 0; - this.storedCriteria = searchCriteria; - } - - setHighlightedIndex(itemIndex) { - this.highlightedIndex = itemIndex; - } - - isHighlightedIndex(itemIndex) { - return this.highlightedIndex === itemIndex; - } - - isFixedItem(item: TagListSelectItem) { - return this.fixedItems.indexOf(item.id) !== -1; - } - - stopPropagation($event) { - $event.stopPropagation(); - } - - onInputFocus() { - if (this.storedCriteria) { - this.showHints = true; - this.dropdownState = TAG_LIST_SELECT.STATE.OPEN; - } - this.disposeGlobalListener = this.renderer.listenGlobal( - 'body', - 'click', - () => this.closeSelection() - ); - - this.onTouchedHandler(); - } - - closeSelection() { - this.showHints = false; - this.disposeGlobalListener(); - this.dropdownState = TAG_LIST_SELECT.STATE.CLOSE; - } -} diff --git a/src/app/shared/components/tag-list-select/tag-list-select.constants.ts b/src/app/shared/components/tag-list-select/tag-list-select.constants.ts deleted file mode 100644 index 6d57832..0000000 --- a/src/app/shared/components/tag-list-select/tag-list-select.constants.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export const TAG_LIST_SELECT = { - STATE: { - OPEN: 'open', - CLOSE: 'close' - }, - - SCROLL: { - CHUNK: 70, - MARGIN: 30 - } -}; diff --git a/src/app/shared/directives/autoheight.directive.ts b/src/app/shared/directives/autoheight.directive.ts deleted file mode 100644 index 1b52b72..0000000 --- a/src/app/shared/directives/autoheight.directive.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { - ElementRef, - HostListener, - Directive, - AfterContentChecked -} from '@angular/core'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• DIRECTIVE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Directive({ - selector: 'textarea[autoheight]' -}) -export class AutoHeightDirective implements AfterContentChecked { - /** ––– - * –– Listeners - */ - @HostListener('input', ['$event.target']) - onInput(textArea: HTMLTextAreaElement): void { - this.adjust(); - } - - /** ––– - * –– Constructor - */ - constructor(public element: ElementRef) {} - - /** ––– - * –– Lifecyle hooks - */ - ngAfterContentChecked(): void { - this.adjust(); - } - - /** ––– - * –– Public Methods - */ - adjust(): void { - this.element.nativeElement.style.height = 'auto'; - this.element.nativeElement.style.height = - this.element.nativeElement.scrollHeight + 'px'; - } -} diff --git a/src/app/shared/directives/index.ts b/src/app/shared/directives/index.ts deleted file mode 100644 index 5251602..0000000 --- a/src/app/shared/directives/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { AutoHeightDirective } from './autoheight.directive'; -export { ScrollToDirective } from './scrollto.directive'; diff --git a/src/app/shared/directives/scrollto.directive.ts b/src/app/shared/directives/scrollto.directive.ts deleted file mode 100644 index 16b70ea..0000000 --- a/src/app/shared/directives/scrollto.directive.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { - ElementRef, - Directive, - Input, - Renderer, - ContentChild, - AfterContentInit -} from '@angular/core'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• DIRECTIVE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Directive({ - selector: '[scrollTo]' -}) -export class ScrollToDirective { - /** ––– - * –– Inputs/Outputs - */ - @Input() scrollTo: string; - @Input() - set applyScroll(value: any) { - if (value !== undefined) { - this.scrollToChild(); - } - } - - /** ––– - * –– Constructor - */ - constructor(private element: ElementRef) {} - - /** ––– - * –– Helper Methods - */ - - scrollAnimation(scrollDuration, scrollTo, scrollableElement) { - let scrollCount = 0, - baseScrollTop = scrollableElement.scrollTop, - maxScroll = - scrollableElement.scrollHeight - scrollableElement.clientHeight, - oldTimestamp = performance.now(); - - function step(newTimestamp) { - scrollCount += Math.PI / (scrollDuration / (newTimestamp - oldTimestamp)); - - if (scrollCount >= Math.PI) { - scrollableElement.scrollTop = scrollTo; - } - if (scrollableElement.scrollTop >= maxScroll) { - return; - } - - scrollableElement.scrollTop = - baseScrollTop + Math.round(scrollTo - scrollTo * Math.cos(scrollCount)); - oldTimestamp = newTimestamp; - - window.requestAnimationFrame(step); - } - - window.requestAnimationFrame(step); - } - scrollToChild(): void { - let scrollableElement = this.element.nativeElement, - targetElement = scrollableElement.querySelector(this.scrollTo), - offsetDifference = 0; - - if (targetElement) { - const scrollableTopOffset = scrollableElement.offsetTop, - targetTopOffset = targetElement.offsetTop; - - offsetDifference = Math.abs(targetTopOffset - scrollableTopOffset); - } - this.scrollAnimation( - 460, - offsetDifference - scrollableElement.scrollTop, - scrollableElement - ); - } -} diff --git a/src/app/shared/index.ts b/src/app/shared/index.ts deleted file mode 100644 index 76d349b..0000000 --- a/src/app/shared/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• EXPORTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Module exports -export * from './shared.module'; - -// Components exports -export { - CustomSelectComponent, - NotificationToasterComponent, - DialogComponent, - TagListSelectComponent -} from './components'; - -// Directives exports -export { AutoHeightDirective, ScrollToDirective } from './directives'; - -// Pipes exports -export { TruncatePipe, CustomDatePipe } from './pipes'; - -// Services exports -export { - SACAPIService, - LocalStorageService, - CategoryService, - RequestTypeService, - UserService, - FileService, - AreaService -} from './services'; - -// Constants exports -export { USER_ROLES } from './shared.constants'; - -// Models exports -export * from './models'; diff --git a/src/app/shared/interfaces/area.interface.ts b/src/app/shared/interfaces/area.interface.ts deleted file mode 100644 index 4e2d6ed..0000000 --- a/src/app/shared/interfaces/area.interface.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Category } from './'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface Area { - id: number; - label: string; - active: boolean; - removable: boolean; - - categories: Category[]; -} diff --git a/src/app/shared/interfaces/category.interface.ts b/src/app/shared/interfaces/category.interface.ts deleted file mode 100644 index 4243bf1..0000000 --- a/src/app/shared/interfaces/category.interface.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { RequestType } from './'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface Category { - id: number; - label: string; - removable: boolean; - specialists: { id: number; removable: boolean }[]; - requestTypes: RequestType[]; -} diff --git a/src/app/shared/interfaces/index.ts b/src/app/shared/interfaces/index.ts deleted file mode 100644 index df71b7c..0000000 --- a/src/app/shared/interfaces/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { Area } from './area.interface'; -export { User } from './user.interface'; -export { Category } from './category.interface'; -export { RequestType } from './request-type.interface'; -export { Question, QuestionType } from './question.interface'; -export { TagListSelectItem } from './tag-list-select-item.interface'; diff --git a/src/app/shared/interfaces/question.interface.ts b/src/app/shared/interfaces/question.interface.ts deleted file mode 100644 index 9fd80f3..0000000 --- a/src/app/shared/interfaces/question.interface.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -export type QuestionType = 'text' | 'number' | 'bool'; - -export interface Question { - id: number; - text: string; - type: QuestionType; - active: boolean; -} diff --git a/src/app/shared/interfaces/request-type.interface.ts b/src/app/shared/interfaces/request-type.interface.ts deleted file mode 100644 index 3d1dd44..0000000 --- a/src/app/shared/interfaces/request-type.interface.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -import { Question } from './'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface RequestType { - id: number; - label: string; - removable: boolean; - isQuery: boolean; - questions: Question[]; - message: string; - responseTime: number; - categoryId: number; -} diff --git a/src/app/shared/interfaces/tag-list-select-item.interface.ts b/src/app/shared/interfaces/tag-list-select-item.interface.ts deleted file mode 100644 index 1a3877c..0000000 --- a/src/app/shared/interfaces/tag-list-select-item.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface TagListSelectItem { - id: any; - label: string; -} diff --git a/src/app/shared/interfaces/user.interface.ts b/src/app/shared/interfaces/user.interface.ts deleted file mode 100644 index 2272cc7..0000000 --- a/src/app/shared/interfaces/user.interface.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Area } from './'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface User { - id: number; - name: string; - lastname: string; - username: string; - roles: string[]; - categories: number[]; - areas: Area[]; - - getFullName(): string; - getSelectedArea(): Area; - hasRole(requestedRole: string): boolean; -} diff --git a/src/app/shared/models/area.model.ts b/src/app/shared/models/area.model.ts deleted file mode 100644 index ace1eeb..0000000 --- a/src/app/shared/models/area.model.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Area as IArea } from '../interfaces'; -import { Category } from './category.model'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODEL IMPLEMENTATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export class Area implements IArea { - private sortedCategories: { - added: Category[]; - updated: Category[]; - deleted: Category[]; - }; - - public id: number; - public label: string; - public removable: boolean; - public active: boolean; - public categories: Category[]; - - public expanded: boolean; - public removed: boolean; - - constructor(dataObject?: any) { - this.id = (dataObject && dataObject.id) || null; - this.label = (dataObject && dataObject.label) || ''; - this.active = - dataObject === undefined - ? true - : dataObject.active === null || dataObject.active; - this.removable = - dataObject === undefined - ? true - : dataObject.removable === undefined || dataObject.removable; - this.categories = - (dataObject && - dataObject.categories.map(category => new Category(category))) || - []; - - this.expanded = false; - this.removed = false; - this.sortedCategories = { added: [], updated: [], deleted: [] }; - } - - setRemoved() { - this.removed = true; - } - toggleContent() { - this.expanded = !this.expanded; - } - - getSortedCategories() { - return this.sortedCategories; - } - setSortedCategories(sortedCategories: { - added: Category[]; - updated: Category[]; - deleted: Category[]; - }) { - this.sortedCategories = sortedCategories; - } -} diff --git a/src/app/shared/models/category.model.ts b/src/app/shared/models/category.model.ts deleted file mode 100644 index 8c6758e..0000000 --- a/src/app/shared/models/category.model.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Category as ICategory, RequestType } from '../interfaces'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODEL IMPLEMENTATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export class Category implements ICategory { - private sortedSpecialists: { added: number[]; deleted: number[] }; - public id: number; - public label: string; - public removable: boolean; - public specialists: { id: number; removable: boolean }[]; - public requestTypes: RequestType[]; - - public removed: boolean; - - constructor(dataObject?: any) { - this.id = (dataObject && dataObject.id) || null; - this.label = (dataObject && dataObject.label) || ''; - this.removable = - dataObject === undefined - ? true - : dataObject.removable === undefined || dataObject.removable; - this.requestTypes = - (dataObject && dataObject.requestTypes) || []; - this.specialists = (dataObject && dataObject.specialists) || []; - - this.removed = false; - this.sortedSpecialists = { added: [], deleted: [] }; - } - - setRemoved() { - this.removed = true; - } - getSortedSpecialists() { - return this.sortedSpecialists; - } -} diff --git a/src/app/shared/models/index.ts b/src/app/shared/models/index.ts deleted file mode 100644 index 580225f..0000000 --- a/src/app/shared/models/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { User } from './user.model'; -export { Area } from './area.model'; -export { Category } from './category.model'; -export { RequestType } from './request-type.model'; -export { Question } from './question.model'; diff --git a/src/app/shared/models/question.model.ts b/src/app/shared/models/question.model.ts deleted file mode 100644 index 0846a13..0000000 --- a/src/app/shared/models/question.model.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Question as IQuestion, QuestionType } from '../interfaces'; -import { QUESTION_TYPES } from '../shared.constants'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODEL IMPLEMENTATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export class Question implements IQuestion { - public id: number; - public text: string; - public type: QuestionType; - public active: boolean; - - constructor(dataObject?: any) { - this.id = (dataObject && dataObject.id) || null; - this.text = (dataObject && dataObject.text) || ''; - this.type = (dataObject && dataObject.type) || QUESTION_TYPES.TEXT; - this.active = - dataObject === undefined - ? true - : dataObject.active === null || dataObject.active; - } -} diff --git a/src/app/shared/models/request-type.model.ts b/src/app/shared/models/request-type.model.ts deleted file mode 100644 index 75d740e..0000000 --- a/src/app/shared/models/request-type.model.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { RequestType as IRequestType } from '../interfaces'; -import { Question } from './question.model'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODEL IMPLEMENTATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export class RequestType implements IRequestType { - public id: number; - public label: string; - public removable: boolean; - public isQuery: boolean; - public categoryId: number; - public questions: Question[]; - - public message: string; - public responseTime: number; - - constructor(dataObject?: any) { - this.id = (dataObject && dataObject.id) || null; - this.label = (dataObject && dataObject.label) || ''; - this.isQuery = (dataObject && dataObject.isQuery) || false; - this.categoryId = (dataObject && dataObject.categoryId) || null; - this.removable = - dataObject === undefined - ? true - : dataObject.removable === undefined || dataObject.removable; - - this.questions = - (dataObject && - dataObject.questions && - dataObject.questions.map(question => new Question(question))) || - []; - - this.message = (dataObject && dataObject.message) || ''; - this.responseTime = (dataObject && dataObject.responseTime) || 0; - } -} diff --git a/src/app/shared/models/user.model.ts b/src/app/shared/models/user.model.ts deleted file mode 100644 index ee83875..0000000 --- a/src/app/shared/models/user.model.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { User as IUser, Area } from '../interfaces'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODEL IMPLEMENTATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export class User implements IUser { - private _selectedArea: number; - public id: number; - public name: string; - public lastname: string; - public username: string; - public roles: string[]; - public areas: Area[]; - public categories: number[]; - - constructor(dataObject: any) { - this.id = dataObject.id || null; - this.name = dataObject.name || ''; - this.lastname = dataObject.lastname || ''; - this.username = dataObject.username || ''; - this.roles = dataObject.roles instanceof Array ? dataObject.roles : []; - this.areas = dataObject.areas || []; - this.categories = (dataObject && dataObject.categories) || []; - - this._selectedArea = this.areas.length ? 0 : null; - } - - getFullName() { - return `${this.name} ${this.lastname}`; - } - getSelectedArea() { - return this.areas.length ? this.areas[this._selectedArea] : null; - } - hasRole(requestedRole: string) { - return this.roles.indexOf(requestedRole) !== -1; - } -} diff --git a/src/app/shared/pipes/custom-date/custom-date.pipe.ts b/src/app/shared/pipes/custom-date/custom-date.pipe.ts deleted file mode 100644 index de72e26..0000000 --- a/src/app/shared/pipes/custom-date/custom-date.pipe.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -// Platform Imports -import { Pipe, PipeTransform } from '@angular/core'; - -// App Imports -import { DATE_I18N_DICTIONARY } from './date-i18n-dictionary.constants'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• PIPE DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Pipe({ name: 'customDate' }) -export class CustomDatePipe implements PipeTransform { - /** ––– - * –– Helper functions - */ - private isDefined(value) { - return value !== undefined && value !== null; - } - - private formatTimeValue(value: number) { - const stringValue = value.toString(); - return this.isDefined(value) - ? '00'.substr(0, 2 - stringValue.length) + stringValue - : ''; - } - - /** ––– - * –– Transform Implementation - */ - transform( - date: Date | string, - withTime: boolean = false, - fullTimeFormat: boolean = false - ) { - if (date !== undefined && date !== null) { - let dateValue = date instanceof Date ? date : new Date(date); - dateValue = new Date( - dateValue.getTime() + dateValue.getTimezoneOffset() * 60000 - ); - - // Validates current date. - if (!isNaN(dateValue.valueOf())) { - let formattedDate = `${dateValue.getDate()} ${DATE_I18N_DICTIONARY.ES_CR.MONTHS.get( - dateValue.getMonth() - )} ${dateValue.getFullYear()}`; - - if (withTime) { - const hours = dateValue.getHours(), - isMorning = hours < 12, - dateHours = - !fullTimeFormat && (!isMorning || hours === 0) - ? hours ? hours % 12 : 12 - : hours; - - formattedDate += ` | ${dateHours}:${this.formatTimeValue( - dateValue.getMinutes() - )} ${isMorning ? 'am' : 'pm'}`; - } - return formattedDate; - } - } - return ''; - } -} diff --git a/src/app/shared/pipes/custom-date/date-i18n-dictionary.constants.ts b/src/app/shared/pipes/custom-date/date-i18n-dictionary.constants.ts deleted file mode 100644 index e05e39f..0000000 --- a/src/app/shared/pipes/custom-date/date-i18n-dictionary.constants.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -const monthsMap = new Map(); - -monthsMap.set(0, 'enero'); -monthsMap.set(1, 'febrero'); -monthsMap.set(2, 'marzo'); -monthsMap.set(3, 'abril'); -monthsMap.set(4, 'mayo'); -monthsMap.set(5, 'junio'); -monthsMap.set(6, 'julio'); -monthsMap.set(7, 'agosto'); -monthsMap.set(8, 'septiembre'); -monthsMap.set(9, 'octubre'); -monthsMap.set(10, 'noviembre'); -monthsMap.set(11, 'diciembre'); - -export const DATE_I18N_DICTIONARY = { - ES_CR: { - MONTHS: monthsMap - } -}; diff --git a/src/app/shared/pipes/index.ts b/src/app/shared/pipes/index.ts deleted file mode 100644 index 0ebb4e6..0000000 --- a/src/app/shared/pipes/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { TruncatePipe } from './truncate/truncate.pipe'; -export { CustomDatePipe } from './custom-date/custom-date.pipe'; diff --git a/src/app/shared/pipes/truncate/truncate.pipe.spec.ts b/src/app/shared/pipes/truncate/truncate.pipe.spec.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/shared/pipes/truncate/truncate.pipe.ts b/src/app/shared/pipes/truncate/truncate.pipe.ts deleted file mode 100644 index 9180d86..0000000 --- a/src/app/shared/pipes/truncate/truncate.pipe.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -import { Pipe, PipeTransform } from '@angular/core'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• PIPE DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Pipe({ name: 'truncate' }) -export class TruncatePipe implements PipeTransform { - /** ––– - * –– Variables - */ - public ellipsis = '…'; - - /** ––– - * –– Transform Implementation - */ - transform(value: any, length: number = 50) { - if (value !== undefined && value !== null) { - let stringValue = value.toString(); - - if (stringValue.length > length) { - stringValue = `${stringValue.substr(0, length)}${this.ellipsis}`; - } - return stringValue; - } - return ''; - } -} diff --git a/src/app/shared/services/area/area.service.spec.ts b/src/app/shared/services/area/area.service.spec.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/shared/services/area/area.service.ts b/src/app/shared/services/area/area.service.ts deleted file mode 100644 index 3551917..0000000 --- a/src/app/shared/services/area/area.service.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Injectable } from '@angular/core'; - -// Rxjs imports -import { Observable } from 'rxjs/Observable'; - -// App Imports -import { SACAPIService } from '../sac-api/sac-api.service'; -import { SessionService } from '../../../core/services'; -import { Area } from '../../../shared/models'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class AreaService { - constructor( - private sacapiService: SACAPIService, - private sessionService: SessionService - ) {} - - /** ––– - * –– Public Methods - */ - - getAreas() { - const session = this.sessionService.getCurrent(); - return this.sacapiService - .get(`/area`, { customHeaders: { Authorization: session.token } }) - .map(areas => areas.map(area => new Area(area))) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - createAreas(areasCollection) { - const session = this.sessionService.getCurrent(), - data = areasCollection.map(area => ({ - label: area.label, - active: area.active, - categories: area.categories.map(category => ({ - label: category.label, - specialists: category.getSortedSpecialists().added - })) - })); - - return this.sacapiService - .post( - `/area`, - { areas: data }, - { customHeaders: { Authorization: session.token } } - ) - .map(areas => areas.map(area => new Area(area))) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - updateAreas(areasCollection: Area[]) { - const session = this.sessionService.getCurrent(), - data = areasCollection.map(area => { - const sortedCategories = area.getSortedCategories(), - added = sortedCategories.added.map(category => ({ - label: category.label, - specialists: category.getSortedSpecialists().added - })), - updated = sortedCategories.updated.map(category => ({ - id: category.id, - label: category.label, - specialists: category.getSortedSpecialists() - })), - deleted = sortedCategories.deleted.map(category => category.id); - - return { - id: area.id, - label: area.label, - active: area.active, - categories: { added, updated, deleted } - }; - }); - - return this.sacapiService - .put( - `/area`, - { areas: data }, - { customHeaders: { Authorization: session.token } } - ) - .map(areas => areas.map(area => new Area(area))) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - removeAreas(areasCollection) { - const session = this.sessionService.getCurrent(), - data = areasCollection.map(area => area.id); - - return this.sacapiService - .delete( - `/area`, - { areas: data }, - { customHeaders: { Authorization: session.token } } - ) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } -} diff --git a/src/app/shared/services/category/category.service.ts b/src/app/shared/services/category/category.service.ts deleted file mode 100644 index 5f1a190..0000000 --- a/src/app/shared/services/category/category.service.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Injectable } from '@angular/core'; - -// App Imports -import { SACAPIService } from '../sac-api/sac-api.service'; -import { SessionService } from '../../../core/services'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class CategoryService { - constructor( - private sacapiService: SACAPIService, - private sessionService: SessionService - ) {} - - /** ––– - * –– Public Methods - */ - - getCategories() { - const session = this.sessionService.getCurrent(); - return this.sacapiService - .get(`/area/${session.user.getSelectedArea().id}/categories`, { - customHeaders: { Authorization: session.token } - }) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } -} diff --git a/src/app/shared/services/file/file.service.spec.ts b/src/app/shared/services/file/file.service.spec.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/shared/services/file/file.service.ts b/src/app/shared/services/file/file.service.ts deleted file mode 100644 index 897720b..0000000 --- a/src/app/shared/services/file/file.service.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports. -import { Injectable } from '@angular/core'; - -// Rxjs Imports -import { Observable } from 'rxjs/Observable'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class FileService { - /** ––– - * –– Constructor - */ - constructor() {} - - /** ––– - * –– Helper Methods - */ - - /** ––– - * –– Public Methods - */ - - createBlob(data: any[], type: string) { - return new Blob(data, { type }); - } - - saveFile(file: Blob | File, filename?: string) { - // saveAs(file, filename); - } -} diff --git a/src/app/shared/services/index.ts b/src/app/shared/services/index.ts deleted file mode 100644 index d8bbd49..0000000 --- a/src/app/shared/services/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { SACAPIService } from './sac-api/sac-api.service'; -export { LocalStorageService } from './local-storage/local-storage.service'; -export { CategoryService } from './category/category.service'; -export { RequestTypeService } from './request-type/request-type.service'; -export { UserService } from './user/user.service'; -export { FileService } from './file/file.service'; -export { AreaService } from './area/area.service'; diff --git a/src/app/shared/services/local-storage/local-storage.service.spec.ts b/src/app/shared/services/local-storage/local-storage.service.spec.ts deleted file mode 100644 index c1627d4..0000000 --- a/src/app/shared/services/local-storage/local-storage.service.spec.ts +++ /dev/null @@ -1,215 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Testing Imports -import { TestBed, async, fakeAsync, inject } from '@angular/core/testing'; - -// App Imports -import { LocalStorageService } from '../'; - -describe('SharedModule | LocalStorageService', () => { - /** - * –– Global Variables - */ - const DEFAULT_PRIMITIVE_KEY = 'defaultPrimitiveValue', - DEFAULT_PRIMITIVE_VALUE = '496949645', - DEFAULT_OBJECT_KEY = 'defaultObjectValue', - DEFAULT_OBJECT_VALUE = { property: '456', property2: 456, property3: true }, - UNEXISTING_KEY = 'defaultUnexistingKey'; - - /** - * –– Global Functions - */ - beforeEach(() => { - // configures our module. - TestBed.configureTestingModule({ - providers: [LocalStorageService] - }); - - // Sets some default values into LocalStorage. - // !! This may be change when other client storage API get included as options. - localStorage.setItem( - DEFAULT_PRIMITIVE_KEY, - JSON.stringify(DEFAULT_PRIMITIVE_VALUE) - ); - localStorage.setItem( - DEFAULT_OBJECT_KEY, - JSON.stringify(DEFAULT_OBJECT_VALUE) - ); - }); - - afterEach(() => { - localStorage.removeItem(DEFAULT_PRIMITIVE_KEY); - localStorage.removeItem(DEFAULT_OBJECT_KEY); - }); - - /** - * –– Specs definitions - */ - it( - 'should get stored values', - async( - inject( - [LocalStorageService], - (localSotrageService: LocalStorageService) => { - let storedValue = localSotrageService.getValue(DEFAULT_PRIMITIVE_KEY); - - expect(storedValue).toBeDefined(); - expect(storedValue).toEqual(DEFAULT_PRIMITIVE_VALUE); - - storedValue = localSotrageService.getValue(DEFAULT_OBJECT_KEY); - - expect(storedValue).toBeDefined(); - expect(storedValue).toEqual(DEFAULT_OBJECT_VALUE); - } - ) - ) - ); - - it( - 'should return null for unexisting keys', - async( - inject( - [LocalStorageService], - (localSotrageService: LocalStorageService) => { - const unexistingValue = localSotrageService.getValue(UNEXISTING_KEY); - expect(unexistingValue).toBeNull(); - - const emptyKeyValue = localSotrageService.getValue(''); - expect(emptyKeyValue).toBeNull(); - } - ) - ) - ); - - it( - 'should store values into localStorage', - async( - inject( - [LocalStorageService], - (localSotrageService: LocalStorageService) => { - let object = { user: 'Sofia', id: 5837538 }, - key = 'objectTestingKey'; - - let result = localSotrageService.storeValue(key, object); - - expect(result).toBe(true); - expect(localStorage.getItem(key)).toEqual(JSON.stringify(object)); - - const array = [ - 'Administrator', - 'Collaborator', - 'Assistant', - 45, - undefined, - null, - true - ]; - key = 'arrayTestingKey'; - - result = localSotrageService.storeValue(key, array); - - expect(result).toBe(true); - expect(localStorage.getItem(key)).toEqual(JSON.stringify(array)); - - const number = 395932958293523; - key = 'numberTestingKey'; - - result = localSotrageService.storeValue(key, number); - - expect(result).toBe(true); - expect(localStorage.getItem(key)).toEqual(JSON.stringify(number)); - - const string = 'My beautiful string'; - key = 'stringTestingKey'; - - result = localSotrageService.storeValue(key, string); - - expect(result).toBe(true); - expect(localStorage.getItem(key)).toEqual(JSON.stringify(string)); - - const boolean = false; - key = 'booleanTestingKey'; - - result = localSotrageService.storeValue(key, boolean); - - expect(result).toBe(true); - expect(localStorage.getItem(key)).toEqual(JSON.stringify(boolean)); - } - ) - ) - ); - - it( - 'should not store values into localStorage', - async( - inject( - [LocalStorageService], - (localSotrageService: LocalStorageService) => { - let object = { user: 'Sofia', id: 5837538 }, - key = '', - result = localSotrageService.storeValue(key, object); - - expect(result).toBe(false); - - key = undefined; - result = localSotrageService.storeValue(key, object); - - expect(result).toBe(false); - - key = null; - result = localSotrageService.storeValue(key, object); - - expect(result).toBe(false); - } - ) - ) - ); - - it( - 'should remove stored values', - async( - inject( - [LocalStorageService], - (localSotrageService: LocalStorageService) => { - let removedValue = localSotrageService.removeValue( - DEFAULT_PRIMITIVE_KEY - ); - expect(removedValue).toEqual(DEFAULT_PRIMITIVE_VALUE); - - removedValue = localSotrageService.removeValue(DEFAULT_PRIMITIVE_KEY); - expect(removedValue).toBe(true); - - removedValue = localSotrageService.removeValue(DEFAULT_OBJECT_KEY); - expect(removedValue).toEqual(DEFAULT_OBJECT_VALUE); - - removedValue = localSotrageService.removeValue(UNEXISTING_KEY); - expect(removedValue).toBe(true); - } - ) - ) - ); - - it( - 'should not remove stored values', - async( - inject( - [LocalStorageService], - (localSotrageService: LocalStorageService) => { - let key = '', - result = localSotrageService.removeValue(key); - expect(result).toBe(false); - - key = undefined; - result = localSotrageService.removeValue(key); - expect(result).toBe(false); - - key = null; - result = localSotrageService.removeValue(key); - expect(result).toBe(false); - } - ) - ) - ); -}); diff --git a/src/app/shared/services/local-storage/local-storage.service.ts b/src/app/shared/services/local-storage/local-storage.service.ts deleted file mode 100644 index b2ca57e..0000000 --- a/src/app/shared/services/local-storage/local-storage.service.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Injectable } from '@angular/core'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class LocalStorageService { - /** ––– - * –– Constants - */ - - /** ––– - * –– Variables - */ - - /** ––– - * –– Constructor - */ - constructor() {} - - /** ––– - * Helper Methods - */ - - /** ––– - * –– Public Methods - */ - - getValue(key: string) { - if (!key || key === null) { - return null; - } - const storedValue = localStorage.getItem(key); - return JSON.parse(storedValue); - } - - storeValue(key: string, value: any) { - if (!key || key === null) { - return false; - } - - const serializedValue = JSON.stringify(value); - - localStorage.setItem(key, serializedValue); - - return true; - } - - removeValue(key: string) { - if (!key || key === null) { - return false; - } - const value = localStorage.getItem(key); - - if (value === null) { - return true; - } - localStorage.removeItem(key); - - return JSON.parse(value); - } -} diff --git a/src/app/shared/services/request-type/request-type.service.ts b/src/app/shared/services/request-type/request-type.service.ts deleted file mode 100644 index 38a77c9..0000000 --- a/src/app/shared/services/request-type/request-type.service.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Injectable } from '@angular/core'; - -// App Imports -import { SACAPIService } from '../sac-api/sac-api.service'; -import { SessionService } from '../../../core/services'; -import { RequestType } from '../../models'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class RequestTypeService { - constructor( - private sacapiService: SACAPIService, - private sessionService: SessionService - ) {} - - private createHeaders() { - const session = this.sessionService.getCurrent(); - return { customHeaders: { Authorization: session.token } }; - } - /** ––– - * –– Public Methods - */ - - getRequestTypes() { - const session = this.sessionService.getCurrent(); - return this.sacapiService - .get( - `/area/${session.user.getSelectedArea().id}/requesttypes`, - this.createHeaders() - ) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - getRequestType(requestTypeId) { - const session = this.sessionService.getCurrent(); - return this.sacapiService - .get(`/requesttypes/${requestTypeId}`, this.createHeaders()) - .map(response => new RequestType(response)) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - createRequestType(requestTypeModel, categoryIndex) { - const session = this.sessionService.getCurrent(); - - requestTypeModel.categoryId = categoryIndex; - - return this.sacapiService - .post(`/requesttypes`, requestTypeModel, this.createHeaders()) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - updateRequestType(requestTypeId, requestTypeModel) { - const session = this.sessionService.getCurrent(); - requestTypeModel.questions.deleted = requestTypeModel.questions.deleted.map( - deletedQuestion => deletedQuestion.id - ); - - return this.sacapiService - .put( - `/requesttypes/${requestTypeId}`, - requestTypeModel, - this.createHeaders() - ) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - deleteRequestType(requestTypeId) { - const session = this.sessionService.getCurrent(); - return this.sacapiService - .delete(`/requesttypes/${requestTypeId}`, {}, this.createHeaders()) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } -} diff --git a/src/app/shared/services/sac-api/api-request-options.interface.ts b/src/app/shared/services/sac-api/api-request-options.interface.ts deleted file mode 100644 index 0a8268b..0000000 --- a/src/app/shared/services/sac-api/api-request-options.interface.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• INTERFACE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export interface APIRequestOptions { - authorization?: string; - formData?: boolean; - blobResponse?: boolean; - customHeaders?: { [key: string]: string }; - params?: { [key: string]: any }; -} diff --git a/src/app/shared/services/sac-api/sac-api.service.spec.ts b/src/app/shared/services/sac-api/sac-api.service.spec.ts deleted file mode 100644 index 86a2398..0000000 --- a/src/app/shared/services/sac-api/sac-api.service.spec.ts +++ /dev/null @@ -1,347 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { - HttpModule, - Http, - ConnectionBackend, - BaseRequestOptions, - Response, - ResponseOptions, - RequestMethod -} from '@angular/http'; - -// Platform Testing Imports -import { TestBed, async, inject } from '@angular/core/testing'; -import { MockBackend } from '@angular/http/testing'; - -// App Imports -import { SACAPIService } from './sac-api.service'; -import { APIRequestOptions } from './api-request-options.interface'; -import environment from '../../../../environments/environment'; - -describe('SharedModule | SACAPIService', () => { - /** - * –– Global Variables - */ - let serviceSubscription, backendSubscription; - - /** - * –– Global Functions - */ - beforeEach(() => { - // configures our module. - TestBed.configureTestingModule({ - imports: [HttpModule], - providers: [ - SACAPIService, - MockBackend, - BaseRequestOptions, - // Setup our mocked backend. - { - provide: Http, - useFactory: ( - backend: ConnectionBackend, - options: BaseRequestOptions - ) => new Http(backend, options), - deps: [MockBackend, BaseRequestOptions] - } - ] - }); - }); - - afterEach(() => { - let result; - if (serviceSubscription) { - result = serviceSubscription.unsubscribe - ? serviceSubscription.unsubscribe() - : serviceSubscription.dispose(); - } - if (backendSubscription) { - result = backendSubscription.unsubscribe - ? backendSubscription.unsubscribe() - : backendSubscription.dispose(); - } - }); - - /** - * –– Specs definitions - */ - it( - 'should make a successful request', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: '{"response": true, "message": "OK" }', - status: 200 - }); - connection.mockRespond(new Response(response)); - }); - - serviceSubscription = sacapiService.get('/session').subscribe( - (response: { response: any; message: string }) => { - expect(response).toBeDefined(); - expect(response.response).toEqual(true); - expect(response.message).toEqual('OK'); - }, - error => { - fail('SACAPIService should push a valid response.'); - } - ); - } - ) - ) - ); - - it( - 'should catch server errors', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session'; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.url).toEqual(environment.API_URL + path); - const response = new ResponseOptions({ - body: '"NOT FOUND"', - status: 404 - }); - connection.mockError(new Response(response)); - }); - - serviceSubscription = sacapiService.get(path).subscribe( - response => { - fail('SACAPIService should catch and handle invalid values.'); - }, - error => { - expect(error).toBeDefined(); - expect(error.code).toBe(404); - expect(error.data).toEqual('NOT FOUND'); - } - ); - } - ) - ) - ); - - it( - 'should catch local errors', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session'; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.url).toEqual(environment.API_URL + path); - const response = new ResponseOptions({ - body: '{ invalidKey: "Valid Value" }', - status: 200 - }); - connection.mockRespond(new Response(response)); - }); - - serviceSubscription = sacapiService.get(path).subscribe( - response => { - fail('SACAPIService should handle unexpected errors.'); - }, - error => { - expect(error).toBeDefined(); - expect(error.code).toBe(500); - expect(error.data.message).toEqual('Unexpected local error'); - } - ); - } - ) - ) - ); - - it( - 'should add default headers to requests', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session'; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.headers.get('Content-Type')).toEqual( - 'application/json' - ); - }); - - serviceSubscription = sacapiService.get(path); - } - ) - ) - ); - - it( - 'should make a GET request', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session'; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.url).toEqual(environment.API_URL + path); - expect(connection.request.method).toEqual(RequestMethod.Get); - }); - - serviceSubscription = sacapiService.get(path); - } - ) - ) - ); - - it( - 'should apply query string parameters', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session', - options = { - params: { id: 4953, name: 'Gabriel & Sofia' } - }; - - backendSubscription = backend.connections.subscribe(connection => { - const queryString = Object.keys(options.params) - .map( - paramKey => - `${encodeURIComponent(paramKey)}=${encodeURIComponent( - options.params[paramKey] - )}` - ) - .join('&'); - - expect(connection.request.url).toEqual( - `${environment.API_URL}${path}?${queryString}` - ); - }); - - serviceSubscription = sacapiService.get(path, options); - } - ) - ) - ); - - it( - 'should not apply query string parameters', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session', - options = {}; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.url).toEqual( - `${environment.API_URL}${path}` - ); - }); - - serviceSubscription = sacapiService.get(path, options); - serviceSubscription.unsubscribe(); - - options.params = {}; - serviceSubscription = sacapiService.get(path, options); - - serviceSubscription.unsubscribe(); - - options.params = { id: 49945 }; - serviceSubscription = sacapiService.post(path, {}, options); - } - ) - ) - ); - - it( - 'should make a POST request', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session', - data = { username: 'fakename', password: 'Vwi4idfjd?GJ' }, - options = { authorization: 'FKNJNJeivinjncjuv*&^fjvjfvbfhvbhf' }; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.url).toEqual(environment.API_URL + path); - expect(connection.request.method).toEqual(RequestMethod.Post); - expect(connection.request._body).toEqual(JSON.stringify(data)); - }); - - serviceSubscription = sacapiService.post(path, data, options); - } - ) - ) - ); - - it( - 'should apply Authorization header to requests', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session', - data = {}, - options = { authorization: 'FKNJNJeivinjncjuv*&^fjvjfvbfhvbhf' }; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.headers.get('Authorization')).toEqual( - 'FKNJNJeivinjncjuv*&^fjvjfvbfhvbhf' - ); - }); - - serviceSubscription = sacapiService.get(path, options); - serviceSubscription.unsubscribe(); - serviceSubscription = sacapiService.post(path, data, options); - } - ) - ) - ); - - it( - 'should not apply Authorization header to requests', - async( - inject( - [SACAPIService, MockBackend], - (sacapiService: SACAPIService, backend: MockBackend) => { - // Creates backend response. - const path = '/session', - data = { username: 'fakename', password: 'Vwi4idfjd?GJ' }, - options = {}; - - backendSubscription = backend.connections.subscribe(connection => { - expect(connection.request.headers.get('Authorization')).toBeNull(); - }); - - serviceSubscription = sacapiService.get(path); - serviceSubscription.unsubscribe(); - serviceSubscription = sacapiService.post(path, data, options); - serviceSubscription.unsubscribe(); - - options.authorization = null; - serviceSubscription = sacapiService.post(path, data, options); - } - ) - ) - ); -}); diff --git a/src/app/shared/services/sac-api/sac-api.service.ts b/src/app/shared/services/sac-api/sac-api.service.ts deleted file mode 100644 index a0c37fc..0000000 --- a/src/app/shared/services/sac-api/sac-api.service.ts +++ /dev/null @@ -1,218 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports. -import { Injectable } from '@angular/core'; -import { - Http, - Response, - ResponseOptions, - ResponseContentType, - Headers, - RequestOptions, - URLSearchParams -} from '@angular/http'; - -// Rxjs Imports -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/observable/of'; -import 'rxjs/add/observable/throw'; - -import 'rxjs/add/operator/mergeMap'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/map'; - -// Environment Imports -import { environment } from '../../../../environments/environment'; - -// App Imports -import { APIRequestOptions } from './api-request-options.interface'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class SACAPIService { - /** ––– - * –– Constructor - */ - constructor(private http: Http) {} - - /** ––– - * –– Helper Methods - */ - private parseErrorHandler(error) { - const errorObject = error.status - ? { code: error.status, data: error.json() } - : { - code: 500, - data: { message: 'Unexpected local error', error: error } - }; - - return Observable.throw(errorObject); - } - - private defineRequestHeaders(options: APIRequestOptions) { - const headers = { - Accept: 'application/json', - 'Content-Type': 'application/json' - }; - - if (options) { - if (options.customHeaders && typeof options.customHeaders === 'object') { - Object.assign(headers, options.customHeaders); - } - if (options.formData) { - headers['Accept'] = '*/*'; - delete headers['Content-Type']; - } - } - - return new Headers(headers); - } - - private createQueryString(paramsObject) { - const queryString = new URLSearchParams(); - - // Iterates over paramsOject properties. - Object.keys(paramsObject).forEach((paramKey: string) => - queryString.append(paramKey, paramsObject[paramKey]) - ); - - return queryString; - } - - private makeRootRequest( - path: string, - method: string, - data: any, - options: APIRequestOptions - ) { - return Observable.create(observer => { - const xhr: XMLHttpRequest = new XMLHttpRequest(), - headers = this.defineRequestHeaders(options); - - // Set event handlers. - xhr.onreadystatechange = () => { - if (xhr.readyState === 4) { - const responseOptions = new ResponseOptions({ - body: xhr.response, - status: xhr.status - }); - - if (xhr.status >= 200 && xhr.status < 300) { - observer.next(new Response(responseOptions)); - observer.complete(); - } else { - observer.error(new Response(responseOptions)); - } - } - }; - - // Make request. - xhr.open(method, `${environment.API_URL}${path}`, true); - - // Set headers. - headers.forEach( - (values, key) => - values.length > 1 - ? xhr.setRequestHeader(key, values.join(';')) - : xhr.setRequestHeader(key, values[0]) - ); - - // Send request. - xhr.send(data); - }); - } - - /** ––– - * –– Public Methods - */ - - get(path: string, options?: APIRequestOptions) { - const headers = this.defineRequestHeaders(options), - requestOptions = new RequestOptions({ headers }); - - if (options && options.blobResponse) { - requestOptions.responseType = ResponseContentType.Blob; - } - - if (options && options.params && Object.keys(options.params).length) { - const queryString = this.createQueryString(options.params); - requestOptions.search = queryString; - } - - return this.http - .get(`${environment.API_URL}${path}`, requestOptions) - .map(response => { - switch (response.headers.get('Content-Type')) { - case 'application/octet-stream': - case 'application/zip': - return response.blob(); - default: - return response.json(); - } - }) - .catch(this.parseErrorHandler); - } - - post(path: string, data: any, options?: APIRequestOptions) { - // Parse request body data - const requestBody = JSON.stringify(data), - headers = this.defineRequestHeaders(options), - requestOptions = new RequestOptions({ headers }); - - return this.http - .post(`${environment.API_URL}${path}`, requestBody, requestOptions) - .map(response => response.json()) - .catch(this.parseErrorHandler); - } - - patch(path: string, data: any, options?: APIRequestOptions) { - // Parse request body data - const requestBody = JSON.stringify(data), - headers = this.defineRequestHeaders(options), - requestOptions = new RequestOptions({ headers }); - - return this.http - .patch(`${environment.API_URL}${path}`, requestBody, requestOptions) - .map(response => response.json()) - .catch(this.parseErrorHandler); - } - - put(path: string, data: any, options?: APIRequestOptions) { - // Parse request body data - let httpObservable: Observable; - - if (data instanceof FormData) { - httpObservable = this.makeRootRequest(path, 'PUT', data, options); - } else { - const requestBody = JSON.stringify(data), - headers = this.defineRequestHeaders(options), - requestOptions = new RequestOptions({ headers }); - - httpObservable = this.http.put( - `${environment.API_URL}${path}`, - requestBody, - requestOptions - ); - } - - return httpObservable - .map(response => response.json()) - .catch(this.parseErrorHandler); - } - - delete(path: string, data: any, options?: APIRequestOptions) { - // Parse request body data - const requestBody = JSON.stringify(data), - headers = this.defineRequestHeaders(options), - requestOptions = new RequestOptions({ headers, body: requestBody }); - - return this.http - .delete(`${environment.API_URL}${path}`, requestOptions) - .map(response => response.json()) - .catch(this.parseErrorHandler); - } -} diff --git a/src/app/shared/services/user/user.service.spec.ts b/src/app/shared/services/user/user.service.spec.ts deleted file mode 100644 index b217810..0000000 --- a/src/app/shared/services/user/user.service.spec.ts +++ /dev/null @@ -1,197 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Router } from '@angular/router'; -import { - HttpModule, - Http, - ConnectionBackend, - BaseRequestOptions, - Response, - ResponseOptions -} from '@angular/http'; - -// Platform Testing Imports -import { TestBed, async, fakeAsync, inject, tick } from '@angular/core/testing'; -import { MockBackend } from '@angular/http/testing'; -import { RouterTestingModule } from '@angular/router/testing'; - -// App Testing Imports -import { MockLoggedSessionService } from '../../../../test/services.helper'; -import { - MockLoginComponent, - MockRequestComponent -} from '../../../../test/components.helper'; - -// App Imports -import { SharedModule } from '../../../'; - -import { User } from '../../models'; -import { AppComponent } from '../../../../sac.component'; -import { UserService } from './user.service'; -import { SessionService } from '../../../core/services'; -import { SACAPIService, LocalStorageService } from '../../../shared/services'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SUITE DECLARATION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -describe('SharedModule | UserService', () => { - /** - * –– Global Variables - */ - let backendSubscription, userSubscription; - - /** - * –– Global Functions - */ - beforeEach(() => { - // configures our module. - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes([ - { path: 'login', component: MockLoginComponent }, - { path: 'requests', component: MockRequestComponent }, - { path: '', pathMatch: 'full', redirectTo: 'requests' } - ]) - ], - declarations: [AppComponent, MockLoginComponent, MockRequestComponent], - providers: [ - LocalStorageService, - - UserService, - MockBackend, - BaseRequestOptions, - SACAPIService, - { - provide: SessionService, - useClass: MockLoggedSessionService - }, - // Setup our mocked backend. - { - provide: Http, - useFactory: ( - backend: ConnectionBackend, - options: BaseRequestOptions - ) => new Http(backend, options), - deps: [MockBackend, BaseRequestOptions] - } - ] - }); - - const fixture = TestBed.createComponent(AppComponent); - }); - - afterEach(() => { - let result; - if (userSubscription) { - result = userSubscription.unsubscribe - ? userSubscription.unsubscribe() - : userSubscription.dispose(); - } - if (backendSubscription) { - result = backendSubscription.unsubscribe - ? backendSubscription.unsubscribe() - : backendSubscription.dispose(); - } - }); - - /** - * –– Specs definitions - */ - it( - 'should successfully retrieve users', - async( - inject( - [UserService, MockBackend], - (userService: UserService, backend: MockBackend) => { - const usersBody = - '[{ "id": 1, "name": "Larry", "lastname": "Cobb" }, { "id": 2, "name": "Herman", "lastname": "Summers" }, { "id": 3, "name": "Bryan", "lastname": "Campbell" }, { "id": 4, "name": "Gene", "lastname": "Nguyen" }, {"id": 5, "name": "Polly", "lastname": "Taylor"}]'; - // Creates backend response. - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: usersBody, - status: 200 - }); - connection.mockRespond(new Response(response)); - }); - - userSubscription = userService.getUsers().subscribe( - (users: User[]) => { - expect(users.length).toEqual(5); - expect(users[2].id).toEqual(3); - expect(users[1].getFullName()).toEqual('Herman Summers'); - expect(users[4].id).toEqual(5); - expect(users[4].getFullName()).toEqual('Polly Taylor'); - }, - error => fail('UserService should retrieve users successfully') - ); - } - ) - ) - ); - - it( - 'should redirect session with unauthenticated response', - fakeAsync( - inject( - [UserService, MockBackend, Router], - (userService: UserService, backend: MockBackend, router: Router) => { - router.navigate(['requests']); - tick(200); - - // Creates backend response. - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: '"UNAUTHENTICATED"', - status: 401 - }); - connection.mockError(new Response(response)); - }); - - userSubscription = userService.getUsers().subscribe( - () => { - fail('UserService should delegate errors'); - }, - error => { - expect(error.code).toEqual(401); - expect(error.data).toEqual('UNAUTHENTICATED'); - } - ); - - tick(400); - expect(router.url).toEqual('/login'); - } - ) - ) - ); - - it( - 'should delegate error messages', - async( - inject( - [UserService, MockBackend], - (userService: UserService, backend: MockBackend) => { - // Creates backend response. - backendSubscription = backend.connections.subscribe(connection => { - const response = new ResponseOptions({ - body: '"NOT FOUND"', - status: 404 - }); - connection.mockError(new Response(response)); - }); - - userSubscription = userService.getUsers().subscribe( - () => fail('UserService should delegate errors'), - error => { - expect(error.code).toEqual(404); - expect(error.data).toEqual('NOT FOUND'); - } - ); - } - ) - ) - ); -}); diff --git a/src/app/shared/services/user/user.service.ts b/src/app/shared/services/user/user.service.ts deleted file mode 100644 index 3154944..0000000 --- a/src/app/shared/services/user/user.service.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { Injectable } from '@angular/core'; - -// App Imports -import { SACAPIService } from '../sac-api/sac-api.service'; -import { SessionService } from '../../../core/services'; -import { User } from '../../models'; -import { USER_ROLES } from '../../shared.constants'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• SERVICE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -@Injectable() -export class UserService { - constructor( - private sacapiService: SACAPIService, - private sessionService: SessionService - ) {} - - /** ––– - * –– Public Methods - */ - - getUsers() { - const session = this.sessionService.getCurrent(); - - return this.sacapiService - .get( - `/areas/${session.user.getSelectedArea().id}/users/roles/${ - USER_ROLES.SPECIALIST.ID - }`, - { customHeaders: { Authorization: session.token } } - ) - .map(users => users.map(user => new User(user))) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } - - getAllUsers() { - const session = this.sessionService.getCurrent(); - - return this.sacapiService - .get('/users', { customHeaders: { Authorization: session.token } }) - .catch(this.sessionService.checkAuthenticatedInterceptor()); - } -} diff --git a/src/app/shared/shared.constants.ts b/src/app/shared/shared.constants.ts deleted file mode 100644 index c77ffc3..0000000 --- a/src/app/shared/shared.constants.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• CONSTANTS DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -export const USER_ROLES = { - ADMINISTRATOR: { - ID: 1, - LABEL: 'Administrator' - }, - SPECIALIST: { - ID: 2, - LABEL: 'Specialist' - }, - COLLABORATOR: { - ID: 3, - LABEL: 'Collaborator' - } -}; - -export const ATTACHMENTS_TYPES = { - REQUEST: 'request', - RESPONSE: 'response' -}; - -export const QUESTION_TYPES = { - NUMBER: 'number', - TEXT: 'text', - BOOLEAN: 'bool' -}; - -export const QUESTION_BOOLEAN = { - TRUE: 'True', - FALSE: 'False' -}; - -export const ERROR_MESSAGES = { - UNAVAILABLE_CATEGORIES: - 'No pudimos obtener las categorías. Inténtelo mas tarde', - UNAVAILABLE_REQUEST_TYPES: - 'No pudimos obtener las subcategorías. Inténtelo mas tarde.', - UNAVAILABLE_REQUESTS: - 'No pudimos obtener las gestiones. Pasa de nuevo más tarde.', - UNAVAILABLE_USERS: 'No pudimos obtener usuarios. Inténtalo más tarde.', - - ASSIGN_ERROR: 'No fue posible asignar las gestiones. Inténtelo de nuevo.', - RESOLUTION_ERROR: 'No pudimos responder la gestión. Inténtelo de nuevo.', - DOWNLOAD_ERROR: - 'No pudimos descargar los archivos adjuntos. Inténtelo de nuevo.' -}; - -export const SUCCESS_MESSAGES = { - ASSIGNED_REQUESTS: 'Gestiones asignadas exitosamente.', - RESOLUTION_SUCCESS: 'Respuesta registrada exitosamente.', - DOWNLOAD_SUCCESS: 'Archivos descargados exitosamente.' -}; diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts deleted file mode 100644 index e0521fc..0000000 --- a/src/app/shared/shared.module.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• IMPORTS •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -// Platform Imports -import { NgModule } from '@angular/core'; -import { HttpModule } from '@angular/http'; -import { FormsModule } from '@angular/forms'; -import { CommonModule } from '@angular/common'; - -// Services Imports -import { - SACAPIService, - LocalStorageService, - CategoryService, - RequestTypeService, - UserService, - FileService, - AreaService -} from './services'; -import { AutoHeightDirective, ScrollToDirective } from './directives'; -import { TruncatePipe, CustomDatePipe } from './pipes'; -import { - CustomSelectComponent, - NotificationToasterComponent, - DialogComponent, - TagListSelectComponent -} from './components'; - -/* ••••••••••••••••••••••••••••••••••••••••••• */ -/* •• MODULE DEFINITION •• */ -/* ••••••••••••••••••••••••••••••••••••••••••• */ - -@NgModule({ - imports: [HttpModule, CommonModule, FormsModule], - declarations: [ - TruncatePipe, - CustomDatePipe, - CustomSelectComponent, - NotificationToasterComponent, - DialogComponent, - TagListSelectComponent, - AutoHeightDirective, - ScrollToDirective - ], - exports: [ - TruncatePipe, - CustomDatePipe, - CustomSelectComponent, - NotificationToasterComponent, - DialogComponent, - TagListSelectComponent, - AutoHeightDirective, - ScrollToDirective - ], - providers: [ - SACAPIService, - LocalStorageService, - CategoryService, - RequestTypeService, - UserService, - FileService, - AreaService - ] -}) -export class SharedModule {}