Commit 86614ff9 authored by hcordova's avatar hcordova

feat: added flight agency frontend

parents
Pipeline #392 failed with stages
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
14.17.3
\ No newline at end of file
FROM nginx:1.17-alpine
LABEL maintainer "mortiz@bytesw.com"
RUN apk --no-cache add curl
RUN curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst && \
chmod +x envsubst && \
mv envsubst /usr/local/bin
EXPOSE 80
COPY ./nginx.config /etc/nginx/nginx.template
CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/nginx.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]
COPY dist/bytebot-html /usr/share/nginx/html
pipeline {
environment {
imagename = "bytesw/bytebot-html"
url = "http://192.168.27.148:5000"
tag_name = "192.168.27.148:5000"
credentials = "admin-docker-hub"
dockerImage = ''
PACKAGE_VERSION = '2.5.0'
}
agent any
parameters {
string(defaultValue: 'no', description: 'Ejecuta los procesos docker', name: 'include_docker')
}
stages {
stage('Install') {
steps {
echo "Branch is ${env.BRANCH_NAME}..."
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'PACKAGE_VERSION=$(node -p -e "require(\'./package.json\').version")'
sh 'npm config ls'
sh 'npm install'
sh 'npm i -D typescript@3.4.3'
}
}
}
stage('Test') {
parallel {
stage('Static code analysis') {
steps {
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'npm run-script lint'
}
}
}
}
}
stage('Build') {
steps {
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'ng build'
}
}
}
stage('Build Docker Image') {
when {
expression { params.include_docker == 'yes' }
}
steps {
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'PACKAGE_VERSION=$(node -p -e "require(\'./package.json\').version")'
}
script {
dockerImage = docker.build imagename
}
}
}
stage('Deploy Image') {
when {
expression { params.include_docker == 'yes' }
}
steps{
script {
docker.withRegistry(url, credentials ) {
dockerImage.push("$PACKAGE_VERSION")
dockerImage.push('latest')
}
}
}
}
stage('Remove Unused docker image') {
when {
expression { params.include_docker == 'yes' }
}
steps{
sh "docker rmi $tag_name/$imagename:$PACKAGE_VERSION"
sh "docker rmi $tag_name/$imagename:latest"
}
}
}
post {
always {
echo 'Confirmación de ejecución!'
emailext body: "${currentBuild.currentResult}: Job ${env.JOB_NAME} build ${env.BUILD_NUMBER}\n More info at: ${env.BUILD_URL}",
recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']],
subject: "Jenkins Build ${currentBuild.currentResult}: Job ${env.JOB_NAME}",
to: '$DEFAULT_RECIPIENTS'
}
}
}
# ByteBot
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.24.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"bytebot-html": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "projects/bytebot-html",
"sourceRoot": "projects/bytebot-html/src",
"prefix": "byte",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/bytebot-html",
"index": "projects/bytebot-html/src/index.html",
"main": "projects/bytebot-html/src/main.ts",
"polyfills": "projects/bytebot-html/src/polyfills.ts",
"tsConfig": "projects/bytebot-html/tsconfig.app.json",
"aot": false,
"assets": [
"projects/bytebot-html/src/favicon.ico",
"projects/bytebot-html/src/assets"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"./node_modules/material-icons/iconfont/material-icons.css",
"projects/bytebot-html/src/styles.scss",
"node_modules/font-awesome/scss/font-awesome.scss",
"node_modules/ngx-toastr/toastr.css",
"node_modules/ngx-bootstrap/datepicker/bs-datepicker.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"vendor/metismenu/metisMenu.js",
"node_modules/popper.js/dist/umd/popper.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/jquery-slimscroll/jquery.slimscroll.min.js",
"node_modules/marked/marked.min.js",
"node_modules/ace-builds/src-min/ace.js",
"node_modules/ace-builds/src-min/mode-markdown.js",
"node_modules/ace-builds/src-min/theme-eclipse.js",
"node_modules/ace-builds/src-min/mode-java.js",
"node_modules/peity/jquery.peity.min.js",
"node_modules/pace-js/pace.min.js",
"vendor/inspinia/inspinia.js"
]
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "projects/bytebot-html/src/environments/environment.ts",
"with": "projects/bytebot-html/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "bytebot-html:build"
},
"configurations": {
"production": {
"browserTarget": "bytebot-html:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "bytebot-html:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/bytebot-html/src/test.ts",
"polyfills": "projects/bytebot-html/src/polyfills.ts",
"tsConfig": "projects/bytebot-html/tsconfig.spec.json",
"karmaConfig": "projects/bytebot-html/karma.conf.js",
"assets": [
"projects/bytebot-html/src/favicon.ico",
"projects/bytebot-html/src/assets"
],
"styles": [
"projects/bytebot-html/src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/bytebot-html/tsconfig.app.json",
"projects/bytebot-html/tsconfig.spec.json",
"projects/bytebot-html/e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/bytebot-html/e2e/protractor.conf.js",
"devServerTarget": "bytebot-html:serve"
},
"configurations": {
"production": {
"devServerTarget": "bytebot-html:serve:production"
}
}
}
}
}
},
"defaultProject": "bytebot-html"
}
\ No newline at end of file
server {
listen ${PORT:-80};
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $$uri /index.html;
}
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; frame-ancestors 'none'; connect-src 'self' https://*.okta.com https://*.herokuapp.com";
add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
add_header Feature-Policy "accelerometer 'none'; camera 'none'; microphone 'none'";
}
\ No newline at end of file
This diff is collapsed.
{
"name": "bytebot-projects",
"version": "1.0.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@agm/core": "^1.1.0",
"@angular-material-components/datetime-picker": "^2.0.4",
"@angular/animations": "^8.2.14",
"@angular/cdk": "^8.2.3",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/material": "^8.2.3",
"@angular/material-moment-adapter": "^9.2.0",
"@angular/platform-browser": "^8.2.14",
"@angular/platform-browser-dynamic": "^8.2.14",
"@angular/router": "~8.2.14",
"@babel/compat-data": "^7.8.0",
"@ng-bootstrap/ng-bootstrap": "^5.1.5",
"@ng-select/ng-select": "^3.7.3",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^4.0.0",
"@swimlane/ngx-datatable": "^16.0.3",
"@swimlane/ngx-graph": "^6.2.0",
"@types/jquery": "^3.3.34",
"@xdf/commons": "^1.0.4",
"@xdf/gallery": "^1.0.18",
"@xdf/graph": "file:libs/xdf-graph-0.0.1.tgz",
"@xdf/layouts": "^1.0.3",
"@xdf/security": "^1.0.0",
"@xdf/settings": "^1.0.6",
"ace-builds": "^1.4.8",
"angular-gauge-chart": "^0.7.2",
"angular-highcharts": "^9.0.2",
"angular-marked": "^1.2.2",
"bootstrap": "^4.4.1",
"chart.js": "^2.9.3",
"dagre": "^0.8.5",
"date-fns": "^2.11.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"highcharts": "^8.0.4",
"jquery": "^3.4.1",
"jquery-slimscroll": "^1.3.8",
"material-design-icons": "^3.0.1",
"material-icons": "^0.3.1",
"metismenu": "^3.0.6",
"moment": "^2.22.1",
"moment-timezone": "^0.5.31",
"net": "^1.0.2",
"ng-circle-progress": "^1.5.1",
"ng-json-view": "^3.0.0",
"ng2-ace-editor": "^0.3.9",
"ng2-charts": "^2.3.0",
"ng2-data-table": "^1.4.0",
"ngx-bootstrap": "^4.3.0",
"ngx-color": "^4.1.1",
"ngx-echarts": "^4.2.2",
"ngx-material-file-input": "2.0.0",
"ngx-moment": "^3.5.0",
"ngx-scrollbar": "7.1.0",
"ngx-slick-carousel": "^0.5.1",
"ngx-toastr": "^10.0.4",
"ngx-translate-multi-http-loader": "^3.0.0",
"ngx-tribute": "^1.5.1",
"nomnoml": "^0.6.2",
"pace-js": "^1.0.2",
"peity": "^3.3.0",
"popper": "^1.0.1",
"popper.js": "^1.16.1",
"rxjs": "~6.4.0",
"stompjs": "^2.3.3",
"tributejs": "^5.1.3",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.803.29",
"@angular/cli": "~8.3.24",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.5.3"
}
}
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
browserName: 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('bytebot-html app is running!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('app-root .content span')).getText() as Promise<string>;
}
}
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage/bytebot-html'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomLayoutComponent, NotFoundComponent } from '@xdf/layouts';
import { AuthGuard, LoginComponent } from '@xdf/security';
import { BytebotLayoutComponent } from './modules/bytebot-layout/bytebot-layout/bytebot-layout.component';
import { HomeComponent } from './views/home/home.component';
const routes: Routes = [
// Remover para SSO
{ path: 'login', component: LoginComponent },
// Main redirect
{ path: '', redirectTo: 'home', pathMatch: 'full', canActivate: [AuthGuard] },
{
path: '', component: CustomLayoutComponent,
children: [
{ path: 'home', component: HomeComponent, data: { breadcrumb: 'Home' } },
{
path: 'security', data: { breadcrumb: 'Seguridad' }, canLoad: [AuthGuard],
loadChildren: () => import('./modules/security/security.module').then(m => m.SecurityModule)
},
{
path: 'settings', data: { breadcrumb: 'Ajustes Generales' }, canLoad: [AuthGuard],
loadChildren: () => import('./modules/settings/settings.module').then(m => m.SettingsModule)
},
{
path: 'agent', data:{ breadcrumb: 'Agentes'}, canLoad: [AuthGuard],
loadChildren: () => import('./modules/agent/agent.module').then(m => m.AgentModule)
},
{
path: 'supervisor', data: { breadcrumb: 'Supervisor' }, canLoad: [AuthGuard],
loadChildren: () => import('./modules/supervisor/supervisor.module').then(m => m.SupervisorModule)
},
{
path: 'passenger', data: { breadcrumb: 'Pasajeros' }, canLoad: [AuthGuard],
loadChildren: () => import('./modules/passenger/passenger.module').then(m => m.PassengerModule)
}
],
canActivate: [AuthGuard]
},
{ path: 'notpermitted', component: NotFoundComponent},
// Handle all other routes
{ path: '**', component: NotFoundComponent}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
onSameUrlNavigation: 'ignore'
})],
exports: [ RouterModule ]
})
export class AppRoutingModule { }
<router-outlet></router-outlet>
\ No newline at end of file
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'bytebot-html'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('bytebot-html');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('bytebot-html app is running!');
});
});
import { Component } from '@angular/core';
@Component({
selector: 'byte-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'bytebot-html';
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { CommonModule, HashLocationStrategy, LocationStrategy, registerLocaleData } from '@angular/common';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core';
// XDF
import { XdfLayoutsModule, SettingsService, ByteSettingsService, SettingsFakeBackendInterceptor } from '@xdf/layouts';
import { XdfSecurityModule, ByteAuthenticationService, AuthGuard, OAuthGuard, OAuthAuthenticationService } from '@xdf/security';
import { ResourceAuthGuard, AuthenticationFakeBackendInterceptor, ProgramsFakeBackendInterceptor } from '@xdf/security';
import { XdfCommonsModule, NotificationService, ToastNotificationService, AuthenticationService } from '@xdf/commons';
import { INITSERVICE_OPTIONS, InitCommonsService, ErrorsHandler } from '@xdf/commons';
// Components
import { AppComponent } from './app.component';
import { HomeComponent } from './views/home/home.component';
import { ToastrModule } from 'ngx-toastr';
import localeEs from '@angular/common/locales/es-PE';
import localeEn from '@angular/common/locales/en';
import { MAT_DATE_LOCALE, MatButtonModule, MatDialogModule, MatPaginatorIntl, DateAdapter } from '@angular/material';
import { MAT_DATE_FORMATS, MatIconModule } from '@angular/material';
import { XdfGalleryModule, CustomMatPaginatorIntl, DATERANGEPICKER_LOCALE, DaterangepickerLocaleService } from '@xdf/gallery';
import { ConflictErrorDialogService, HttpErrorHandleInterceptor } from '@xdf/gallery';
import { BytebotSettingsService } from './services/bytebot-settings-service';
import { MultiTranslateHttpLoader } from 'ngx-translate-multi-http-loader';
import {
MAT_MOMENT_DATE_FORMATS,
MomentDateAdapter,
MAT_MOMENT_DATE_ADAPTER_OPTIONS,
} from '@angular/material-moment-adapter';
import { CustomProgramsFakeBackendInterceptor } from './interceptors/custom-programs-fake-backend.interceptor';
import { OperativeDashboardFakeBackendInterceptor } from './interceptors/operative-dashboard-fake-backend.interceptor';
import { SupervisorModule } from './modules/supervisor/supervisor.module';
import { RouterModule } from '@angular/router';
const INITIAL_LANGUAGE = 'es';
registerLocaleData(localeEs, 'es');
registerLocaleData(localeEn, 'en');
export function createTranslateLoader(http: HttpClient) {
return new MultiTranslateHttpLoader(http,
[
{ prefix: './assets/i18n/', suffix: '.json' },
{ prefix: './assets/i18n/menu/', suffix: '.json' },
{ prefix: './assets/i18n/layouts/', suffix: '.json' },
{ prefix: './assets/i18n/gallery/', suffix: '.json' },
{ prefix: './assets/i18n/security/', suffix: '.json' },
{ prefix: './assets/i18n/settings/', suffix: '.json' }
]);
}
@NgModule({
declarations: [
AppComponent,
HomeComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
CommonModule,
HttpClientModule,
RouterModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
ToastrModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
}
}),
XdfCommonsModule.forRoot({
language: INITIAL_LANGUAGE
}),
XdfLayoutsModule,
XdfSecurityModule,
XdfGalleryModule,
MatDialogModule,
MatButtonModule,
MatIconModule,
SupervisorModule
],
providers: [
{ provide: MAT_DATE_LOCALE, useValue: INITIAL_LANGUAGE },
{
provide: DateAdapter,
useClass: MomentDateAdapter,
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS]
},
{ provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl, deps: [TranslateService] },
{ provide: DATERANGEPICKER_LOCALE, useValue: INITIAL_LANGUAGE },
{ provide: DaterangepickerLocaleService, useClass: DaterangepickerLocaleService },
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: NotificationService, useClass: ToastNotificationService },
{ provide: SettingsService, useClass: ByteSettingsService },
ConflictErrorDialogService,
{ provide: HTTP_INTERCEPTORS, useClass: HttpErrorHandleInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: ErrorsHandler, multi: true},
{ provide: ResourceAuthGuard, useClass: ResourceAuthGuard },
// descomentar estas lineas para OAUTH
// { provide: AuthGuard, useClass: OAuthGuard },
//{ provide: AuthenticationService, useClass: OAuthAuthenticationService },
//{ provide: APP_INITIALIZER, useFactory: loginLoaderFactory, deps: [AuthenticationService], multi: true },
// Para probar mantenimientos
// comentar estas lineas para OAUTH
{ provide: AuthGuard, useClass: AuthGuard},
{ provide: AuthenticationService, useClass: ByteAuthenticationService },
{ provide: HTTP_INTERCEPTORS, useClass: AuthenticationFakeBackendInterceptor, multi: true},
{ provide: HTTP_INTERCEPTORS, useClass: SettingsFakeBackendInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: CustomProgramsFakeBackendInterceptor, multi: true },
//{ provide: HTTP_INTERCEPTORS, useClass: AgentFakeBackendInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: OperativeDashboardFakeBackendInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: SupervisorFakeBackend, multi: true},
// { provide: HTTP_INTERCEPTORS, useClass: PassengerFakeBackendInterceptor, multi: true},
// { provide: HTTP_INTERCEPTORS, useClass: PassengerReservationFakeBackendInterceptor, multi: true},
//{ provide: HTTP_INTERCEPTORS, useClass: FlightFakeBackendInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: AgentReservationFakeBackendInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: ReservationFakeBackendInterceptor, multi: true },
{ provide: APP_INITIALIZER, useFactory: init_app, deps: [InitCommonsService, TranslateService], multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
export function init_app(appLoaderService: InitCommonsService) {
return () => appLoaderService.initializeApp();
}
// required for AOT compilation
// export function HttpLoaderFactory(http: HttpClient) {
// return new TranslateHttpLoader(http);
// }
// Para OAUTH
export function loginLoaderFactory(provider: OAuthAuthenticationService) {
return () => provider.login(null, null).toPromise();
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/agent';
const tableData: Array<any> = [
{
id: 1,
name: 'John',
lastname: 'Doe',
details: 'Activo',
},
{
id: 2,
name: 'Jane',
lastname: 'Doe',
details: 'Activo',
},
{
id: 3,
name: 'Juan',
lastname: 'Perez',
details: 'Activo',
},
{
id: 4,
name: 'Pedro',
lastname: 'Perez',
details: 'Activo',
}
];
@Injectable()
export class AgentFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
return ok({});
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
return by(url)
case url.indexOf(basePath + '/') !== -1 && method === 'DELETE':
return deleteById(url);
case url.indexOf(basePath + '/create') !== -1 && method === 'POST':
return save(body);
case url.indexOf(basePath + '/edit') !== -1 && method === 'PUT':
return edit(body, url);
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function edit(data: any, url: string) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
data.id = id;
tableData[index] = data;
return ok(data);
}
function save(data: any) {
const id = tableData.length + 1;
data.id = id;
tableData.push(data);
return ok(data);
}
function deleteById(url) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
tableData.splice(index, 1);
return ok();
}
function by(url: string) {
const id = parseInt(url.split('/').pop());
const by = tableData.find(x => x.id === id);
return ok(by);
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/agent-reservation';
const tableData: Array<any> = [
{
id: 1,
passenger: "Victoria Abad Torrez",
ticketType: "Economy",
travelClass: "Economy",
status: "RESERVATED",
},
{
id: 2,
passenger: "Paola Abad Torrez",
ticketType: "Economy",
travelClass: "Economy",
status: "PAID",
},
{
id: 3,
passenger: "Juan Perez",
ticketType: "Economy",
travelClass: "Economy",
status: "CANCELLED",
}
];
@Injectable()
export class AgentReservationFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
return ok({});
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
return by(url)
case url.indexOf(basePath + '/') !== -1 && method === 'DELETE':
return deleteById(url);
case url.indexOf(basePath + '/create') !== -1 && method === 'POST':
return save(body);
case url.indexOf(basePath + '/edit') !== -1 && method === 'PUT':
return edit(body, url);
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function edit(data: any, url: string) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
data.id = id;
tableData[index] = data;
return ok(data);
}
function save(data: any) {
const id = tableData.length + 1;
data.id = id;
tableData.push(data);
return ok(data);
}
function deleteById(url) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
tableData.splice(index, 1);
return ok();
}
function by(url: string) {
const id = parseInt(url.split('/').pop());
const by = tableData.find(x => x.id === id);
return ok(by);
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import {
HttpRequest,
HttpResponse,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError, of, EMPTY } from 'rxjs';
import { Injectable } from '@angular/core';
import { catchError, tap, map } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { NotificationService, NotificationType, AuthenticationService } from '@xdf/commons';
import { Router } from '@angular/router';
import { ConflictErrorDialogService } from '@xdf/gallery';
@Injectable()
export class CustomErrorHandlerInterceptor implements HttpInterceptor {
constructor(
private router: Router,
private translate: TranslateService,
private authenticationService: AuthenticationService,
private notificationService: NotificationService,
private conflictErrorDialogService: ConflictErrorDialogService) {
}
intercept(
req: HttpRequest<any>, next: HttpHandler): Observable<any> {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
switch (error.status) {
case 401:
const message = this.translate.instant('message.error.unauthorized');
this.notificationService.showMessage(message, this.translate.instant('title.error'), NotificationType.error);
break;
case 404:
const messageError = error.error ? error.error : error.message;
this.notificationService.showMessage(messageError, this.translate.instant('title.error'), NotificationType.error);
break;
case 409:
const messageDuplicate = this.translate.instant('message.error.duplicated');
this.notificationService.showMessage(messageDuplicate, this.translate.instant('title.error'), NotificationType.error);
break;
case 419: // validar cual es el código correcto
this.conflictErrorDialogService.loadComponent(
null,
'title.error.conflict',
'message.error.conflict',
error.error);
break;
default:
if (error.status === 0) {
this.authenticationService.login(null, null).subscribe(
data => {
window.location.href = './';
});
} else {
let messageDefault = '';
if (error.error) {
if (error.error.params) {
const params = [];
error.error.params.forEach(element => {
params.push(this.translate.instant(element));
});
messageDefault = this.translate.instant(error.error.message, params);
} else {
if (error.error.message) {
messageDefault = this.translate.instant(error.error.message);
} else {
messageDefault = this.translate.instant(error.error);
}
}
} else {
messageDefault = this.translate.instant(error.message);
}
this.notificationService.showMessage(messageDefault, this.translate.instant('title.error'), NotificationType.error);
}
}
return throwError(error);
})
);
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import * as source from '../../assets/fake-data/programs-data.json';
import * as controlsSource from '../../assets/fake-data/controls-data.json';
const basePath = '/service/security/programs';
const basePathCotnrols = '/service/security/controls';
@Injectable()
export class CustomProgramsFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
const data = (source as any).default;
const dataControls = (controlsSource as any).default;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(50))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.match('.*' + basePath) && method === 'GET':
return getList();
case url.match('.*' + basePathCotnrols + '.*') && method === 'GET':
return getControls();
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function getList() {
return ok(data);
}
function getControls() {
return ok(dataControls);
}
// helper functions
function ok(bodyContent?) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/flights';
const tableData: Array<any> = [
{
id: 1,
airportOrigin: 'MEX',
airportDestination: 'CUN',
departureDate: '2021-05-01T00:00:00.000Z',
arrivalDate: '2021-06-01T00:00:00.000Z',
airline: 'AM',
aircraft: 'B737',
scales: [
{
id: 1,
airportOrigin: 'MEX',
airportDestination: 'CUN',
departureDate: '2021-05-01T00:00:00.000Z',
arrivalDate: '2021-06-01T00:00:00.000Z',
}
],
costs: [
{
id: 1,
departureDate: '2021-05-01T00:00:00.000Z',
arrivalDate: '2021-06-01T00:00:00.000Z',
price: 1000
}
]
},
{
id: 2,
airportOrigin: 'MEX',
airportDestination: 'CUN',
departureDate: '2021-05-01T00:00:00.000Z',
arrivalDate: '2021-06-01T00:00:00.000Z',
airline: 'AM',
aircraft: 'B737',
scales: [
{
id: 1,
airportOrigin: 'MEX',
airportDestination: 'CUN',
departureDate: '2021-05-01T00:00:00.000Z',
arrivalDate: '2021-06-01T00:00:00.000Z',
}
],
costs: [
{
id: 1,
departureDate: '2021-05-01T00:00:00.000Z',
arrivalDate: '2021-06-01T00:00:00.000Z',
price: 1000
}
]
}
];
@Injectable()
export class FlightFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
return ok({});
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
return by(url)
case url.indexOf(basePath + '/') !== -1 && method === 'DELETE':
return deleteById(url);
case url.indexOf(basePath + '/create') !== -1 && method === 'POST':
return save(body);
case url.indexOf(basePath + '/edit') !== -1 && method === 'PUT':
return edit(body, url);
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function edit(data: any, url: string) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
data.id = id;
tableData[index] = data;
return ok(data);
}
function save(data: any) {
const id = tableData.length + 1;
data.id = id;
tableData.push(data);
return ok(data);
}
function deleteById(url) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
tableData.splice(index, 1);
return ok();
}
function by(url: string) {
const id = parseInt(url.split('/').pop());
const by = tableData.find(x => x.id === id);
return ok(by);
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import * as source from '../../assets/fake-data/operative-dashboard-data.json';
const basePath = '/test';
@Injectable()
export class OperativeDashboardFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
const data = (source as any).default;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(50))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.match('.*' + basePath) && method === 'POST':
return getData();
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function getData() {
return ok(data);
}
// helper functions
function ok(bodyContent?) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/passengers';
const tableData: Array<any> = [
{
id: 1,
name: 'John',
lastname: 'Doe',
phone: '123456789',
country: 'USA',
city: 'New York',
address: 'Calle 123',
email: 'johndoe@email.com'
},
{
id: 2,
name: 'Jane',
lastname: 'Doe',
phone: '123456789',
country: 'Spain',
city: 'Madrid',
address: 'Calle 123',
email: 'janedoe@email.com'
},
{
id: 3,
name: 'Juan',
lastname: 'Perez',
phone: '123456789',
country: 'China',
city: 'Beijing',
address: 'Calle 123',
email: 'juanperez@gmail.com'
},
{
id: 4,
name: 'Pedro',
lastname: 'Perez',
phone: '123456789',
country: 'New Zealand',
city: 'Auckland',
address: 'Calle 123',
email: 'pedroperez@gmail.com'
}
];
@Injectable()
export class PassengerFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
console.log(body);
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
console.log('here2');
return ok({});
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
console.log('here3');
return by(url)
case url.indexOf(basePath + '/') !== -1 && method === 'DELETE':
console.log('here4');
return deleteById(url);
case url.indexOf(basePath + '/create') !== -1 && method === 'POST':
console.log('here5');
return save(body);
case url.indexOf(basePath + '/edit') !== -1 && method === 'PUT':
console.log('here6');
return edit(body, url);
default:
return next.handle(request);
}
}
function edit(data: any, url: string) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
data.id = id;
tableData[index] = data;
return ok(data);
}
function save(data: any) {
const id = tableData.length + 1;
data.id = id;
tableData.push(data);
return ok(data);
}
function deleteById(url) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
tableData.splice(index, 1);
return ok();
}
function by(url: string) {
const id = parseInt(url.split('/').pop());
const by = tableData.find(x => x.id === id);
return ok(by);
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/passenger-reservation';
const tableData: Array<any> = [
{
id: 1,
airportOrigin: 'Aeropuerto Internacional de la Ciudad de México',
airportDestination: 'Aeropuerto Internacional John F. Kennedy',
departureDate: '2023-01-01',
arrivalDate: '2023-01-01',
status: 'RESERVATED',
cost: '1000 USD'
},
{
id: 2,
airportOrigin: 'Aeropuerto Internacional Jorge Chávez',
airportDestination: 'Aeropuerto Internacional Heathrow',
departureDate: '2023-02-01',
arrivalDate: '2023-02-01',
status: 'CANCELLED',
cost: '2000 USD'
},
{
id: 3,
airportOrigin: 'Aeropuerto Internacional de la Ciudad de México',
airportDestination: 'Aeropuerto Internacional Madrid-Barajas',
departureDate: '2023-03-01',
arrivalDate: '2023-03-01',
status: 'PAID',
cost: '3000 USD'
}
];
@Injectable()
export class PassengerReservationFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
return ok({});
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
return by(url)
case url.indexOf(basePath + '/') !== -1 && method === 'DELETE':
return deleteById(url);
case url.indexOf(basePath + '/create') !== -1 && method === 'POST':
return save(body);
case url.indexOf(basePath + '/edit') !== -1 && method === 'PUT':
return edit(body, url);
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function edit(data: any, url: string) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
data.id = id;
tableData[index] = data;
return ok(data);
}
function save(data: any) {
const id = tableData.length + 1;
data.id = id;
tableData.push(data);
return ok(data);
}
function deleteById(url) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
tableData.splice(index, 1);
return ok();
}
function by(url: string) {
const id = parseInt(url.split('/').pop());
const by = tableData.find(x => x.id === id);
return ok(by);
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/reservations';
const tableData: Array<any> = [
{
id: 1,
passenger: "Victoria Abad Torrez",
ticketType: "Economy",
travelClass: "Economy",
status: "RESERVATED",
},
{
id: 2,
passenger: "Paola Abad Torrez",
ticketType: "Economy",
travelClass: "Economy",
status: "PAID",
},
{
id: 3,
passenger: "Juan Perez",
ticketType: "Economy",
travelClass: "Economy",
status: "CANCELLED",
}
];
@Injectable()
export class ReservationFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
return ok({});
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
return by(url)
case url.indexOf(basePath + '/') !== -1 && method === 'DELETE':
return deleteById(url);
case url.indexOf(basePath + '/create') !== -1 && method === 'POST':
return save(body);
case url.indexOf(basePath + '/edit') !== -1 && method === 'PUT':
return edit(body, url);
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function edit(data: any, url: string) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
data.id = id;
tableData[index] = data;
return ok(data);
}
function save(data: any) {
const id = tableData.length + 1;
data.id = id;
tableData.push(data);
return ok(data);
}
function deleteById(url) {
const id = parseInt(url.split('/').pop());
const index = tableData.findIndex(x => x.id === id);
tableData.splice(index, 1);
return ok();
}
function by(url: string) {
const id = parseInt(url.split('/').pop());
const by = tableData.find(x => x.id === id);
return ok(by);
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http";
import { Injectable } from '@angular/core';
import { DIRECTION } from "@xdf/commons";
import { Observable, of, throwError } from "rxjs";
import { delay, dematerialize, materialize, mergeMap } from "rxjs/operators";
const basePath = '/service/supervisor';
const tableData: Array<any> = [
{
id: 361,
name: 'John',
lastname: 'Doe'
},
{
id: 362,
name: 'Jane',
lastname: 'Doe'
},
{
id: 363,
name: 'Juan',
lastname: 'Perez'
},
{
id: 364,
name: 'Pedro',
lastname: 'Perez'
}
];
@Injectable()
export class SupervisorFakeBackend implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith(basePath + '/page') && method === 'POST':
return pagination(body);
case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
return ok({});
/* case url.indexOf(basePath + '/countries') !== -1 && method === 'GET':
return ok(countries);
case url.indexOf(basePath + '/channels') !== -1 && method === 'GET':
return ok(channels);
case url.indexOf(basePath + '/file-upload') !== -1 && method === 'POST':
return ok(fileOK);
case url.indexOf(basePath + '/') !== -1 && method === 'GET':
return ok(fakeAgentData); */
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields && dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
console.log(dataRecibida);
console.log(pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
\ No newline at end of file
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard, ResourceAuthGuard } from '@xdf/security';
import { CrudDetailComponent, CrudGridComponent, DirtyGuard, TemplateResolver } from '@xdf/gallery';
import { PassengerDetailComponent } from './view/passenger-detail/passenger-detail.component';
import { ReservationsComponent } from './view/reservations/reservations.component';
const routes: Routes = [
{
path: 'passengers',
canActivate: [AuthGuard, ResourceAuthGuard],
component: CrudGridComponent,
resolve: { template: TemplateResolver},
data: {
program: 'passenger_list',
breadcrumb: 'Pasajeros'
}
},
{
path: 'passengers/detail/:mode',
canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { record: TemplateResolver},
component: PassengerDetailComponent,
data: {
innerTemplate: 'none',
program: 'passenger_detail',
breadcrumb: 'Pasajeros'
}
},
{
path: 'reservations',
canActivate: [AuthGuard, ResourceAuthGuard],
component: CrudGridComponent,
resolve: { template: TemplateResolver},
data: {
innerTemplate: 'none',
program: 'reservations_agent_list',
breadcrumb: 'Reservaciones'
}
},
{
path: 'reservations/detail/:mode',
canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { record: TemplateResolver},
component: ReservationsComponent,
data: {
innerTemplate: 'none',
program: 'reservations_agent_detail',
breadcrumb: 'Reservaciones'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AgentRoutingModule { }
import { NgModule } from '@angular/core';
import { AgentRoutingModule } from './agent-routing.module';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { XdfCommonsModule } from '@xdf/commons';
import { XdfSettingsModule } from '@xdf/settings';
import { XdfGalleryModule } from '@xdf/gallery';
import { MatButtonModule, MatIconModule, MatMenuModule, MatPaginatorModule, MatProgressSpinnerModule, MatSortModule, MatStepperModule, MatTableModule } from '@angular/material';
import { PassengerDetailComponent } from './view/passenger-detail/passenger-detail.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { ReservationsComponent } from './view/reservations/reservations.component';
import { StepPersonalInformationComponent } from './components/step-personal-information/step-personal-information.component';
import { StepFlightSelectionComponent } from './components/step-flight-selection/step-flight-selection.component';
import { StepSummaryReservationComponent } from './components/step-summary-reservation/step-summary-reservation.component';
@NgModule({
declarations: [
PassengerDetailComponent,
ReservationsComponent,
StepPersonalInformationComponent,
StepFlightSelectionComponent,
StepSummaryReservationComponent
],
imports: [
CommonModule,
RouterModule,
AgentRoutingModule,
MatTableModule,
MatMenuModule,
MatIconModule,
MatButtonModule,
MatPaginatorModule,
MatProgressSpinnerModule,
MatSortModule,
MatStepperModule,
FormsModule,
ReactiveFormsModule,
XdfGalleryModule,
XdfSettingsModule,
TranslateModule
]
})
export class AgentModule { }
<div class="flightStep">
<div class="custom_container">
<div class="custom_container-header">
<span>Selección de vuelo</span>
</div>
<div class="custom_container-content">
<div class="group_panel">
<span class="group_panel-label">Buscador</span>
<div class="group_panel_content">
<form [formGroup]="flightSelectionFormGroup" (onSubmit)="onSearch()" class="row">
<div class="col-6">
<xdf-select name="origin" label="agent-form.origin.placeholder" [required]="true"
placeholder="agent-form.origin.placeholder" [values]="airports"
[options]="{maxLenght: 120, showLength: true}" [formGroup]="flightSelectionFormGroup" [disabled]="getDisabledCondicion()">
</xdf-select>
</div>
<div class="col-6">
<xdf-select name="destination" label="agent-form.destination.placeholder" [required]="true"
placeholder="agent-form.destination.placeholder" [values]="airports"
[options]="{maxLenght: 120, showLength: true}" [formGroup]="flightSelectionFormGroup" [disabled]="getDisabledCondicion()">
</xdf-select>
</div>
<div class="col-12">
<xdf-datepicker name="departureDate" label="agent-form.departureDate" [required]="true"
placeholder="agent-form.departureDate.placeholder"
[options]="{maxLenght: 120, showLength: true}" [formGroup]="flightSelectionFormGroup">
</xdf-datepicker>
</div>
<div class="col-12 d-flex justify-content-end">
<button (click)="onSearch()" [disabled]="flightSelectionFormGroup.invalid || getDisabledCondicion()" type="submit" class="btn btn-primary">Filtrar</button>
</div>
</form>
</div>
</div>
<div class="grid-container mat-elevation-z3 mt-2">
<div class="grid-ibox-content">
<div class="spinner-container" *ngIf="dataSource?.loading$ | async">
<mat-spinner diameter="40"></mat-spinner>
</div>
<table class="crud-table table table-striped table-hover" mat-table
[dataSource]="dataSource" matSort [matSortActive]="sortColumn"
[matSortDirection]="sortDirection" matSortDisableClear multiTemplateDataRows>
<ng-container *ngFor="let template of columnTemplateArray" matColumnDef="{{template.name}}">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ template.title | translate }} </th>
<td mat-cell *matCellDef="let item"> {{ item[template['name']] }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let item">
<button [disabled]="flightSelected === item.id || mode === 'view'" (click)="onSelect(item)" class="btn btn-outline-secondary">
<i class="fa fa-solid fa-plus"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
</div>
<hr>
<div class="d-flex justify-content-between">
<button matStepperPrevious class="btn btn-outline-secondary">
<i class="fa fa-thin fa-chevron-left mr-1"></i>
<span>Anterior</span>
</button>
<button [disabled]="!flightSelected" matStepperNext class="btn btn-outline-secondary">
<span>Siguiente</span>
<i class="fa fa-thin fa-chevron-right ml-1"></i>
</button>
</div>
</div>
$my-gray-dark: #bfc0c2;
.custom_container {
border: 1px solid $my-gray-dark;
}
.custom_container-header {
padding: 10px 20px;
background-color: $my-gray-dark;
color: white;
}
.custom_container-content {
padding: 20px;
}
.group_panel {
border: 1px solid $my-gray-dark;
position: relative;
}
.group_panel-label {
position: absolute;
top: -15px;
left: 20px;
background-color: white;
padding: 5px 10px;
}
.group_panel_content {
padding: 20px 30px;
}
\ No newline at end of file
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatStepper } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
import { ColumnTemplate } from '@xdf/gallery';
import { AirportService } from '../../service/airport.service';
import { FlightSearchService } from '../../../supervisor/service/flight-search.service';
import { DatePipe } from '@angular/common';
import { ReservationService } from '../../service/reservation.service';
const columnTemplateArray = [
{
name: 'id',
sortable: false,
title: 'flight_id',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'number',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'airline',
sortable: true,
title: 'flight_airline',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'aircraft',
sortable: true,
title: 'flight_aircraft',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'flightType',
sortable: true,
title: 'flight_travelClass',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'departureDate',
sortable: true,
title: 'flight_departureDate',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'arrivalDate',
sortable: true,
title: 'flight_arrivalDate',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'amount',
sortable: true,
title: 'flight_price',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
}
];
@Component({
selector: 'byte-step-flight-selection',
templateUrl: './step-flight-selection.component.html',
styleUrls: ['./step-flight-selection.component.scss']
})
export class StepFlightSelectionComponent implements OnInit {
airports: any[] = [];
columnTemplateArray: ColumnTemplate[];
dataSource: any[] = [];
displayedColumns = new Array<string>();
filterTags = [];
sortDirection: string = 'asc';
flightSelected: number;
@Input()
public airportOrigin: number;
@Input()
public airportDestination: number;
@Input()
public departureDate: string;
public id: number;
public flightSelectionFormGroup = new FormGroup({});
constructor(private formBuilder: FormBuilder,
private activatedRoute: ActivatedRoute,
private reservationService: ReservationService,
private airportService: AirportService,
private activateRoute: ActivatedRoute,
private flightSearchService: FlightSearchService) { }
@Input()
searchResults: any[] = [];
@Input()
public stepper: MatStepper;
@Output()
public onFlightSelected: EventEmitter<number> = new EventEmitter();
public mode: string;
ngOnInit() {
this.columnTemplateArray = columnTemplateArray;
this.columnTemplateArray.forEach(column => {
this.displayedColumns.push(column.name);
});
this.airportService.getAll()
.subscribe(data => this.airports = data);
this.activateRoute.params.subscribe(params => this.mode = params.mode);
this.displayedColumns.push("actions");
this.buildForm();
this.updateData();
}
searchFLight(data: any) {
this.flightSearchService.searchFlights(data.airportOrigin, data.airportDestination, data.travelDate)
.subscribe(result => {
this.searchResults = result;
this.dataSource = [...result];
});
}
getDisabledCondicion() {
return this.mode !== 'new';
}
buildForm(): void {
this.flightSelectionFormGroup = new FormGroup({
origin: new FormControl({ value: '', disabled: this.getDisabledCondicion()}, [Validators.required]),
destination: new FormControl({ value: '', disabled: this.getDisabledCondicion()}, [Validators.required]),
departureDate: new FormControl({ value: '', disabled: this.getDisabledCondicion()}, [Validators.required])
});
}
updateData() {
if (this.mode !== 'new') {
this.activateRoute.queryParams.subscribe(params => {
this.id = params['id'];
});
this.reservationService.getById(this.id)
.subscribe(reservation => {
this.flightSelectionFormGroup.get('origin').setValue(reservation.airportOriginId);
this.flightSelectionFormGroup.get('destination').setValue(reservation.airportDestinationId);
this.flightSelectionFormGroup.get('departureDate').setValue(reservation.departureDate);
this.flightSelected = reservation.flightId;
this.dataSource = [...reservation.flightSearchBean];
});
}
}
onSearch() {
if (this.flightSelectionFormGroup.valid) {
const searchFlight = {
airportOrigin: this.flightSelectionFormGroup.get('origin').value,
airportDestination: this.flightSelectionFormGroup.get('destination').value,
travelDate: new DatePipe('en-US').transform(this.flightSelectionFormGroup.get('departureDate').value, "yyyy-MM-dd'T'HH:mm:ss")
}
this.searchFLight(searchFlight);
}
}
onSelect(item: any) {
this.flightSelected = item.id;
this.onFlightSelected.emit(item);
}
onNext() {
if (this.flightSelected) {
this.stepper.next();
}
}
}
<form [formGroup]="formGroup" (ngSubmit)="onSave()" class="baseInfoStep">
<div class="custom_container">
<div class="custom_container-header">
<span>Información base</span>
</div>
<div class="custom_container-content">
<div class="row">
<div class="col-12">
<xdf-select name="passenger" label="agent-form.passenger.placeholder" [required]="true"
placeholder="agent-form.passenger.placeholder" [values]="passengers" [formGroup]="formGroup"
[options]="{maxLenght: 120, showLength: true}" [disabled]="getDisableConditions()">
</xdf-select>
</div>
<div class="col-6">
<xdf-select name="ticketType" label="agent-form.ticketType.placeholder" [required]="true"
placeholder="agent-form.ticketType.placeholder" [values]="ticketTypes" [formGroup]="formGroup"
[options]="{maxLenght: 120, showLength: true}" [disabled]="getDisableConditions()">
</xdf-select>
</div>
<div class="col-6">
<xdf-select name="travelClass" label="agent-form.travelClass.placeholder"[required]="true"
placeholder="agent-form.travelClass.placeholder" [values]="travelClasses" [formGroup]="formGroup"
[options]="{maxLenght: 120, showLength: true}" [disabled]="getDisableConditions()">
</xdf-select>
</div>
</div>
</div>
</div>
<hr>
<div class="d-flex justify-content-end">
<button [disabled]="formGroup.invalid" type="submit" class="btn btn-outline-secondary">
<span>Siguiente</span>
<i class="fa fa-thin fa-chevron-right ml-1"></i>
</button>
</div>
</form>
$my-gray-dark: #bfc0c2;
.custom_container {
border: 1px solid $my-gray-dark;
}
.custom_container-header {
padding: 10px 20px;
background-color: $my-gray-dark;
color: white;
}
.custom_container-content {
padding: 20px;
}
\ No newline at end of file
import { AfterContentChecked, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { MatStepper } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'byte-step-personal-information',
templateUrl: './step-personal-information.component.html',
styleUrls: ['./step-personal-information.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StepPersonalInformationComponent implements OnInit, AfterContentChecked {
@Input()
public stepper: MatStepper;
@Input()
public passengers: any[] = [];
@Input()
public ticketTypes: any[] = [];
@Input()
public travelClasses: any[] = [];
public mode: string = 'view';
constructor(private activatedRouter: ActivatedRoute, private changeDetectorRef: ChangeDetectorRef) { }
ngAfterContentChecked(): void {
this.changeDetectorRef.detectChanges();
}
getDisableConditions() {
return this.mode !== 'new';
}
@Input()
public formGroup: FormGroup = new FormGroup({
passenger: new FormControl(),
ticketType: new FormControl(),
travelClass: new FormControl()
});
ngOnInit() {
this.activatedRouter.params
.subscribe(params => {
this.mode = params['mode'];
});
}
onSave() {
if (this.formGroup.valid || this.getDisableConditions()) {
this.stepper.next();
}
}
}
<div class="summaryStep">
<div class="custom_container">
<div class="custom_container-header">
<span>Resumen</span>
</div>
<div class="custom_container-content">
<div class="legend">
<span class="group-title">Información base</span>
</div>
<div class="dictionaries">
<div class="dictionary">
<span class="dictionaty__key">Pasajero</span>
<span class="dictionary_value">{{ passenger }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Tipo de ticket</span>
<span class="dictionary_value">{{ ticketType }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Clase de vuelo</span>
<span class="dictionary_value">{{ travelClass }}</span>
</div>
</div>
<div class="legend">
<span class="group-title">Selección de vuelo</span>
</div>
<div class="dictionaries">
<div class="dictionary">
<span class="dictionaty__key">Origen</span>
<span class="dictionary_value">{{ flight?.airportOrigin }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Destino</span>
<span class="dictionary_value">{{ flight?.airportDestination }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Fecha de salida</span>
<span class="dictionary_value">{{ flight?.departureDate }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Fecha de llegada</span>
<span class="dictionary_value">{{ flight?.arrivalDate }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Aerolinea</span>
<span class="dictionary_value">{{ flight?.airline }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Tipo de vuelo</span>
<span class="dictionary_value">{{ flight?.flightType }}</span>
</div>
<div class="dictionary">
<span class="dictionaty__key">Costo total</span>
<span class="dictionary_value">{{ flight?.amount }}</span>
</div>
</div>
<div class="legend">
<span class="group-title">Detalle de vuelo</span>
</div>
<table class="table" mat-table [dataSource]="flight?.scales">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>Id</th>
<td mat-cell *matCellDef="let element" >{{ element?.id }}</td>
</ng-container>
<ng-container matColumnDef="airportOriginName">
<th mat-header-cell *matHeaderCellDef>Aeropuerto Origen</th>
<td mat-cell *matCellDef="let element">{{ element?.airportOriginName }}</td>
</ng-container>
<ng-container matColumnDef="airportDestinationName">
<th mat-header-cell *matHeaderCellDef>Aeropuerto Destino</th>
<td mat-cell *matCellDef="let element">{{ element?.airportDestinationName }}</td>
</ng-container>
<ng-container matColumnDef="departureDate">
<th mat-header-cell *matHeaderCellDef>Fecha de partida</th>
<td mat-cell *matCellDef="let element">{{ element?.departureDate }}</td>
</ng-container>
<ng-container matColumnDef="arrivalDate">
<th mat-header-cell *matHeaderCellDef>Fecha de llegada</th>
<td mat-cell *matCellDef="let element">{{ element?.arrivalDate }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
<hr>
<div class="d-flex justify-content-between">
<button matStepperPrevious class="btn btn-outline-secondary">
<i class="fa fa-thin fa-chevron-left mr-1"></i>
<span>Anterior</span>
</button>
<button (click)="onEmitSave()" [disabled]="getDisabledConditions()" matStepperNext class="btn btn-primary">
<span>Guardar</span>
<i class="fa fa-thin fa-chevron-right ml-1"></i>
</button>
</div>
</div>
$my-gray-dark: #bfc0c2;
.custom_container {
border: 1px solid $my-gray-dark;
}
.custom_container-header {
padding: 10px 20px;
background-color: $my-gray-dark;
color: white;
}
.custom_container-content {
padding: 20px;
}
.dictionaries {
margin-bottom: 10px;
}
.dictionary {
display: grid;
grid-template-columns: 200px 200px;
column-gap: 30px;
}
.dictionaty__key {
display: flex;
justify-content: end;
}
\ No newline at end of file
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'byte-step-summary-reservation',
templateUrl: './step-summary-reservation.component.html',
styleUrls: ['./step-summary-reservation.component.scss']
})
export class StepSummaryReservationComponent implements OnInit {
public displayedColumns: string[] = ['id', 'airportOriginName', 'airportDestinationName', 'departureDate', 'arrivalDate'];
@Input()
public flight: any;
@Input()
public passenger: any;
@Input()
public travelClass: string;
@Input()
public ticketType: string;
@Output()
public onSave: EventEmitter<void> = new EventEmitter();
public mode: string;
getDisabledConditions(): boolean {
return this.mode !== 'new';
}
constructor(private activatedRoute: ActivatedRoute) { }
ngOnInit(): void {
this.activatedRoute.params.subscribe(params => this.mode = params.mode);
}
get flightType(): string | null {
return this.flight ? this.flight.length > 1 ? 'Con escalas' : 'Directo' : null;
}
onEmitSave(): void {
this.onSave.emit();
}
}
export const TICKET_TYPES: any[] = [
{
label: 'Negocios',
value: 'BUSINESS'
},
{
label: 'Economica',
value: 'ECONOMIC'
},
{
label: "Primera clase",
value: 'FIRST-CLASS'
}
];
export const TRAVEL_CLASSES: any[] = [
{
label: 'Negocios',
value: 'BUSINESS'
},
{
label: 'Economica',
value: 'ECONOMIC'
},
{
label: 'Primera clase',
value: 'FIRST-CLASS'
}
];
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { PassengerService } from '../service/passenger.service';
@Injectable({ providedIn: 'root' })
export class PassengerResolver implements Resolve<any> {
constructor(private passengerService: PassengerService) {}
resolve(route: ActivatedRouteSnapshot): Observable<any> | Promise<any> | any {
return this.passengerService.getResultList();
}
}
\ No newline at end of file
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AirportService {
constructor(private http: HttpClient) { }
getAll() {
return this.http.get<any[]>('http://localhost:9077/AVB/service/airports');
}
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DynaDataService } from '@xdf/gallery';
import { Observable } from 'rxjs';
@Injectable({providedIn: 'root'})
export class PassengerService extends DynaDataService {
constructor(private httpClient: HttpClient) {
super(httpClient);
}
edit(data: any, id: any): Observable<object> {
this.serviceURL = '/service/passengers/edit';
return super.update(id, data);
}
create(data: any): Observable<object> {
this.serviceURL = '/service/passengers/create';
return super.create(data);
}
getResultList() {
this.serviceURL = '/service/passengers';
return super.getResultList(this.serviceURL);
}
getResult(id: any): Observable<object> {
this.serviceURL = '/service/passengers';
return super.getResult(id);
}
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { DynaDataService } from '@xdf/gallery';
import { Observable } from 'rxjs';
@Injectable({providedIn: 'root'})
export class ReservationService extends DynaDataService {
constructor(private httpClient: HttpClient) {
super(httpClient);
}
edit(data: any, id: any): Observable<object> {
this.serviceURL = '/service/reservations/edit';
return super.update(id, data);
}
create(data: any): Observable<object> {
this.serviceURL = '/service/reservations/create';
return super.create(data);
}
getResultList(serviceURL?: string) {
this.serviceURL = '/service/reservations';
return super.getResultList(serviceURL);
}
getResult(id: any): Observable<object> {
this.serviceURL = '/service/reservations';
return super.getResult(id);
}
getById(id: any): Observable<any> {
this.serviceURL = '/service/reservations';
return this.httpClient.get<any>(`${this.serviceURL}/${id}`);
}
}
<form [formGroup]="form" name="form" autocomplete="off" novalidate (ngSubmit)="onSubmit()">
<div class="mail-box-header detail-header">
<xdf-form-header [icon]="icon" title_="passenger_list_title" [recordIdentifier]="record?.id"
titleDesc="passenger_list_description" [mode]="mode" [resourceAuth]="resourceAuth"
[editing]="mode === 'edit'" [displaying]="mode === 'view'" (optionEvent)="optionEvent($event)">
</xdf-form-header>
</div>
<div class="mail-box-content">
<div class="row">
<div class="px-5 pt-4 col-12">
<div class="legend">
<span class="group-title">Información Personal</span>
</div>
<div class="form-content">
<div class="group-content">
<div class="row">
<div class="form-group col-12">
<xdf-input name="name" label="passenger-form.name" type="text" [required]="true"
placeholder="passenger-form.name.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<div class="form-group col-12 col-lg-6">
<xdf-input name="lastname" label="passenger-form.lastname" type="text" [required]="true"
placeholder="passenger-form.lastname.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<div class="form-group col-12 col-lg-6">
<xdf-input name="phone" label="passenger-form.phone" type="text" [required]="true"
placeholder="passenger-form.phone.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<div class="form-group col-6">
<xdf-input name="country" label="passenger-form.country" type="text" [required]="true"
placeholder="passenger-form.country.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<div class="form-group col-6">
<xdf-input name="city" label="passenger-form.city" type="text" [required]="true"
placeholder="passenger-form.city.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<div class="form-group col-12">
<xdf-input name="address" label="passenger-form.address" type="text" [required]="true"
placeholder="passenger-form.address.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
</div>
</div>
</div>
<div class="legend">
<span class="group-title">Credenciales</span>
</div>
<div class="form-content">
<div class="group-content">
<div class="row">
<div class="form-group col-12">
<xdf-input name="email" label="passenger-form.email" type="text" [required]="true"
placeholder="passenger-form.email.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<div class="form-group col-12">
<xdf-password name="password" label="passenger-form.password" type="text" [required]="true"
placeholder="passenger-form.password.placeholder" [formGroup]="form"
[options]="{maxLenght: 120, showLength: true}">
</xdf-password>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12" *ngIf="mode !== 'view'">
<div class="form-status-bar border-top d-flex justify-content-end pt-2">
<button [disabled]="form.invalid" type="submit" mat-stroked-button class="btn btn-primary">
<i class="fa fa-save" aria-hidden="true"></i>
<span class="ml-1">Guardar</span>
</button>
</div>
</div>
</div>
</div>
</form>
import { AfterViewChecked, ChangeDetectorRef, Component, OnInit, ViewContainerRef } from '@angular/core';
import { FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { InitCommonsService, NotificationService, NotificationType } from '@xdf/commons';
import { AuditDialogService, ConfirmationDialogService, DynaDataService, IFormView, ValidatorUtils } from '@xdf/gallery';
import { NavigationService } from '@xdf/layouts';
import { param } from 'jquery';
import { element } from 'protractor';
import { PassengerService } from '../../service/passenger.service';
@Component({
selector: 'byte-passenger-detail',
templateUrl: './passenger-detail.component.html',
styleUrls: ['./passenger-detail.component.scss']
})
export class PassengerDetailComponent extends IFormView implements OnInit, AfterViewChecked {
disabledFields = [
'id', 'name', 'lastname', 'phone', 'country', 'city', 'address', 'email'
];
constructor(
protected vcRef: ViewContainerRef,
protected route: ActivatedRoute,
protected router: Router,
protected dynaDataService: DynaDataService,
protected translate: TranslateService,
protected notificationService: NotificationService,
protected auditDialogService: AuditDialogService,
protected confirmationDialogService: ConfirmationDialogService,
protected navigationService: NavigationService,
protected init: InitCommonsService,
protected validatorUtils: ValidatorUtils,
private readonly changeDetectorRef: ChangeDetectorRef,
private activatedRouter: ActivatedRoute,
private passengerService: PassengerService
) {
super(vcRef, route, router, dynaDataService, translate, notificationService, auditDialogService, confirmationDialogService, init);
}
ngOnInit() {
super.ngOnInit();
this.serviceURL = "./service/passengers";
this.icon = '<i class="fa fa-users fa-1_5x"></i>';
this.id = parseInt(this.route.snapshot.queryParamMap.get('id'));
this.dynaDataService.serviceURL = this.serviceURL;
this.passengerService.serviceURL = this.serviceURL;
this.updateForm(this.id, this.mode);
}
ngAfterViewChecked(): void {
this.changeDetectorRef.detectChanges();
}
protected getFields(): FormGroup {
let form;
if (this.mode !== "new" && this.record) {
form = new FormGroup({
name: this.createFormControl("name", true, true),
lastname: this.createFormControl("lastname", true, true),
phone: this.createFormControl("phone", true, true),
country: this.createFormControl("country", true, true),
city: this.createFormControl("city", true, true),
address: this.createFormControl("address", true, true),
email: this.createFormControl("email", true, true),
password: this.createFormControl("password", true, true),
});
} else {
form = new FormGroup({
name: this.createFormControl("name", false, true),
lastname: this.createFormControl("lastname", false, true),
phone: this.createFormControl("phone", false, true),
country: this.createFormControl("country", false, true),
city: this.createFormControl("city", false, true),
address: this.createFormControl("address", false, true),
email: this.createFormControl("email", false, true),
password: this.createFormControl("password", false, true),
});
}
return form;
}
private createFormControl(name: string, existRecord?: boolean, required?: boolean, defaultValue?: string, validators?: Array<ValidationErrors>): FormControl {
if (!defaultValue) defaultValue = '';
let validatorList = [];
if (validators) validatorList = validators;
if (required) validatorList.push(Validators.required);
let valueaux = existRecord ? this.record[name] : '';
valueaux = this.mode === 'view' && name === 'password' ? '********' : valueaux;
return new FormControl({ value: valueaux, disabled: this.disabledCondition(name) }, validatorList);
}
private disabledCondition(controlName?): boolean {
const disabled = this.mode === 'view' || (this.disabledFields.includes(controlName) && this.mode === 'edit');
return disabled;
}
onSubmit() {
this.processing = true;
if (this.mode === 'new') {
let data = this.form.value;
this.passengerService.create(data).subscribe(response => {
this.processing = false;
const title = this.translate.instant('title.information');
const message = this.translate.instant('message.create.succesful');
this.notificationService.showMessage(message, title, NotificationType.success);
this.record = new Object();
this.router.navigate(['/agent/passengers']);
this.form.reset();
this.processing = false;
}, error => {
this.processing = false;
});
} else {
let updatePassword = { password: this.form.value.password };
this.passengerService.edit(updatePassword, this.id).subscribe(response => {
this.processing = false;
const title = this.translate.instant('title.information');
const message = this.translate.instant('message.edit.succesful');
this.notificationService.showMessage(message, title, NotificationType.success);
this.record = new Object();
this.router.navigate(['/agent/passengers']);
this.form.reset();
this.processing = false;
});
}
}
updateForm(id, mode) {
this.mode = mode;
this.id = id;
if (this.id) {
this.dynaDataService.getResult(this.id).subscribe(
data => {
this.record = data;
this.form = this.getFields();
}
);
} else {
this.record = new Object();
this.form = this.getFields();
}
}
}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="mail-box-header detail-header">
<xdf-form-header [icon]="icon" title_="reservations_agent_list_title" [recordIdentifier]="record?.id"
titleDesc="reservations_agent_list_description" [mode]="mode" [resourceAuth]="resourceAuth"
[editing]="mode === 'edit'" [displaying]="mode === 'view'" (optionEvent)="optionEvent($event)">
</xdf-form-header>
</div>
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-content">
<mat-horizontal-stepper labelPosition="bottom" [linear]="true" #stepper>
<mat-step [stepControl]="personalInformationFormGroup" label="step1" state="info">
<ng-template matStepLabel>
<span class="font-bold">Informacion base</span>
<div class="font-size-description">
Información general de la reserva
</div>
</ng-template>
<byte-step-personal-information
[passengers]="passengers"
[travelClasses]="travelClasses"
[ticketTypes]="ticketTypes"
[stepper]="stepper"
[formGroup]="personalInformationFormGroup">
</byte-step-personal-information>
</mat-step>
<mat-step [stepControl]="flightSelectedForm" label="step2" state="flight">
<ng-template matStepLabel>
<span class="font-bold">Selección de vuelo</span>
<div class="font-size-description">
Información del vuelo
</div>
</ng-template>
<byte-step-flight-selection
[searchResults]="[reservation?.flightSearchBean]"
[airportOrigin]="reservation?.airportOriginId"
[airportDestination]="reservation?.airportDestinationId"
[departureDate]="reservation?.departureDate"
(onFlightSelected)="onFlightSelected($event)">
</byte-step-flight-selection>
</mat-step>
<mat-step label="step3" state="summary">
<ng-template matStepLabel>
<span class="font-bold">Resumen</span>
<div class="font-size-description">
Valida la configuración
</div>
</ng-template>
<byte-step-summary-reservation
[flight]="flightSelected"
[passenger]="passengerName"
[travelClass]="travelClassName"
[ticketType]="ticketTypeName"
(onSave)="onSaveReservation()">
</byte-step-summary-reservation>
</mat-step>
<ng-template matStepperIcon="info">
<mat-icon>call_end</mat-icon>
</ng-template>
<ng-template matStepperIcon="flight">
<mat-icon>forum</mat-icon>
</ng-template>
<ng-template matStepperIcon="summary">
<mat-icon>user</mat-icon>
</ng-template>
</mat-horizontal-stepper>
</div>
</div>
</div>
</div>
$my-gray-dark: #bfc0c2;
.custom_container {
border: 1px solid $my-gray-dark;
}
.custom_container-header {
padding: 10px 20px;
background-color: $my-gray-dark;
color: white;
}
.custom_container-content {
padding: 20px;
}
\ No newline at end of file
import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper';
import { AfterViewChecked, ChangeDetectorRef, Component, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatStepper } from '@angular/material';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { InitCommonsService, NotificationService, NotificationType } from '@xdf/commons';
import { AuditDialogService, ConfirmationDialogService, DynaDataService, IFormView, ValidatorUtils } from '@xdf/gallery';
import { NavigationService } from '@xdf/layouts';
import { ReservationService } from '../../service/reservation.service';
import { PassengerService } from '../../service/passenger.service';
import { TICKET_TYPES } from '../../interfaces/ticketType.interface';
import { TRAVEL_CLASSES } from '../../interfaces/travelClass.interface';
@Component({
selector: 'byte-reservations',
templateUrl: './reservations.component.html',
styleUrls: ['./reservations.component.scss'],
providers: [
{
provide: STEPPER_GLOBAL_OPTIONS,
useValue: { showError: true }
}
]
})
export class ReservationsComponent extends IFormView implements OnInit {
protected getFields(): FormGroup {
throw new Error('Method not implemented.');
}
@ViewChild('stepper', { static: true }) stepper: MatStepper;
passengers: any[] = [];
ticketTypes: any[] = TICKET_TYPES;
travelClasses: any[] = TRAVEL_CLASSES;
isLinear: boolean = false;
personalInformationFormGroup: FormGroup;
flightSelectedForm = this._formBuilder.group({
flightId: ['', Validators.required]
});
public flightSelected: any;
constructor(
protected vcRef: ViewContainerRef,
protected route: ActivatedRoute,
protected router: Router,
protected dynaDataService: DynaDataService,
protected translate: TranslateService,
protected notificationService: NotificationService,
protected auditDialogService: AuditDialogService,
protected confirmationDialogService: ConfirmationDialogService,
protected navigationService: NavigationService,
protected init: InitCommonsService,
protected validatorUtils: ValidatorUtils,
private readonly changeDetectorRef: ChangeDetectorRef,
private activatedRouter: ActivatedRoute,
private _formBuilder: FormBuilder,
private reservationService: ReservationService,
private passengerService: PassengerService
) {
super(vcRef, route, router, dynaDataService, translate, notificationService, auditDialogService, confirmationDialogService, init);
}
ngOnInit() {
this.icon = "<i class=\"fa fa-book fa-1_5x\"></i>";
this.activatedRouter.params.subscribe(params => this.mode = params['mode']);
this.ticketTypes = TICKET_TYPES;
this.travelClasses = TRAVEL_CLASSES;
this.getAllPassengers();
this.getRecords();
this.buildForm();
}
getRecords(): void {
if (this.mode !== 'new') {
this.route.queryParams.subscribe(params => {
this.id = params['id'];
});
this.reservationService.getById(this.id)
.subscribe(reservation => {
this.flightSelectedForm.controls['flightId'].setValue(reservation.flightId);
this.personalInformationFormGroup.controls['passenger'].setValue(reservation.passengerId);
this.personalInformationFormGroup.controls['ticketType'].setValue(reservation.ticketType);
this.personalInformationFormGroup.controls['travelClass'].setValue(reservation.travelClass);
this.flightSelected = reservation.flightSearchBean;
});
}
}
buildForm(): void {
this.personalInformationFormGroup = this._formBuilder.group({
passenger: new FormControl({value: null, disabled: this.mode === 'view' || this.mode === 'edit'}, [Validators.required]),
ticketType: new FormControl({value: null, disabled: this.mode === 'view' || this.mode === 'edit'}, [Validators.required]),
travelClass: new FormControl({value: null, disabled: this.mode === 'view' || this.mode === 'edit'}, [Validators.required])
});
}
getAllPassengers(): void {
this.passengerService.getResultList()
.subscribe(passengers => this.passengers = passengers);
}
get passengerName() {
const passenger = this.passengers.find(passenger => passenger.value === this.personalInformationFormGroup.get('passenger').value);
return passenger ? passenger.label : '';
}
get ticketTypeName() { return this.personalInformationFormGroup.get('ticketType').value; }
get travelClassName() { return this.personalInformationFormGroup.get('travelClass').value; }
optionEvent(option: any) {
this.router.navigate(["/agent/reservations"]);
}
onFlightSelected(flight: any) {
this.flightSelectedForm.controls['flightId'].setValue(flight.id);
this.flightSelected = flight;
}
onSaveReservation() {
const reservation = {
agentId: 6,
passengerId: this.personalInformationFormGroup.get('passenger').value,
ticketType: this.personalInformationFormGroup.get('ticketType').value,
travelClass: this.personalInformationFormGroup.get('travelClass').value,
flightId: this.flightSelectedForm.get('flightId').value,
departureDate: this.flightSelected.departureDate
}
this.reservationService.create(reservation)
.subscribe(response => {
this.notificationService.showMessage('Reservación creada exitosamente', 'Satisfactorio', NotificationType.success);
this.router.navigate(["/agent/reservations"]);
}, error => {
this.notificationService.showMessage('Error al crear la reservación', 'Error', NotificationType.error);
})
}
}
/*
* Inspinia js helpers:
*
* correctHeight() - fix the height of main wrapper
* detectBody() - detect windows size
* smoothlyMenu() - add smooth fade in/out on navigation show/ide
*
*/
// import * as jQuery_ from 'jquery';
// const jQuery = jQuery_;
declare var jQuery: any;
export function correctHeight() {
const pageWrapper = jQuery('#page-wrapper');
const navbarHeight = jQuery('nav.navbar-default').height();
const wrapperHeight = pageWrapper.height();
if (navbarHeight > wrapperHeight) {
pageWrapper.css('min-height', navbarHeight + 'px');
}
if (navbarHeight <= wrapperHeight) {
if (navbarHeight < jQuery(window).height()) {
pageWrapper.css('min-height', jQuery(window).height() + 'px');
} else {
pageWrapper.css('min-height', navbarHeight + 'px');
}
}
if (jQuery('body').hasClass('fixed-nav')) {
if (navbarHeight > wrapperHeight) {
pageWrapper.css('min-height', navbarHeight + 'px');
} else {
pageWrapper.css('min-height', jQuery(window).height() - 60 + 'px');
}
}
}
export function detectBody() {
if (jQuery(document).width() < 769) {
jQuery('body').addClass('body-small');
} else {
jQuery('body').removeClass('body-small');
}
}
export function smoothlyMenu() {
if (!jQuery('body').hasClass('mini-navbar') || jQuery('body').hasClass('body-small')) {
// Hide menu in order to smoothly turn on when maximize menu
jQuery('#side-menu').hide();
// For smoothly turn on menu
setTimeout(
() => {
jQuery('#side-menu').fadeIn(400);
}, 200);
} else if (jQuery('body').hasClass('fixed-sidebar')) {
jQuery('#side-menu').hide();
setTimeout(
() => {
jQuery('#side-menu').fadeIn(400);
}, 100);
} else {
// Remove all inline style from jquery fadeIn function to reset menu state
jQuery('#side-menu').removeAttr('style');
}
}
export function fixHeight() {
const heightWithoutNavbar = jQuery('body > #wrapper').height() - 62;
jQuery('.sidebar-panel').css('min-height', heightWithoutNavbar + 'px');
const navbarheight = jQuery('nav.navbar-default').height();
const wrapperHeight = jQuery('#page-wrapper').height();
if (navbarheight > wrapperHeight) {
jQuery('#page-wrapper').css('min-height', navbarheight + 'px');
}
if (navbarheight < wrapperHeight) {
jQuery('#page-wrapper').css('min-height', jQuery(window).height() + 'px');
}
if (jQuery('body').hasClass('fixed-nav')) {
if (navbarheight > wrapperHeight) {
jQuery('#page-wrapper').css('min-height', navbarheight + 'px');
} else {
jQuery('#page-wrapper').css('min-height', jQuery(window).height() - 60 + 'px');
}
}
}
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule } from '@xdf/gallery';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { XdfSettingsModule } from '@xdf/settings';
import { BytebotLayoutComponent } from './bytebot-layout/bytebot-layout.component';
import { LayoutModule } from '@angular/cdk/layout';
@NgModule({
declarations: [
BytebotLayoutComponent
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
LayoutModule
],
entryComponents: [
],
exports: [
BytebotLayoutComponent
]
,
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard }
]
})
export class BytebotLayoutModule { }
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BytebotLayoutComponent } from './bytebot-layout.component';
describe('BytebotLayoutComponent', () => {
let component: BytebotLayoutComponent;
let fixture: ComponentFixture<BytebotLayoutComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BytebotLayoutComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BytebotLayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, HostListener, OnInit } from '@angular/core';
import { detectBody } from '../app.helpers';
@Component({
selector: 'byte-bytebot-layout',
templateUrl: './bytebot-layout.component.html',
styleUrls: ['./bytebot-layout.component.scss']
})
export class BytebotLayoutComponent implements OnInit {
constructor(// protected toogleService: ToogleService
) { }
ngOnInit() {
detectBody();
}
@HostListener('window:resize')
public onResize() {
detectBody();
}
gotoTop() {
console.log('custom-layout');
}
onToggle() {
console.log('test');
// this.toogleService.onToggle(true);
}
}
<form (ngSubmit)="onCancel()">
<div class="d-flex align-items-center">
<i class="bi bi-exclamation-triangle-fill icon"></i>
<h1 mat-dialog-title class="mb-0 ml-2">Cancelar reserva</h1>
</div>
<div class="my-4" mat-dialog-content>
<div class="d-flex justify-content-center">
¿Esta seguro que desea cancelar la reserva?
</div>
<hr>
</div>
<div mat-dialog-actions class="d-flex">
<button type="button" mat-button (click)="onNoClick()" class="btn-cancel mr-2">No</button>
<button type="submit" mat-button class="btn-ok" cdkFocusInitial>Si</button>
</div>
</form>
.btn-ok,
.btn-cancel {
width: 60px;
padding: 8px;
color: black;
border-radius: 4px;
border: none;
font-size: 14px;
}
.btn-ok {
background-color: transparent;
}
.btn-cancel {
background-color: #c7c7c7;
}
.icon {
font-size: 28px;
color: red;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DialogReservationCancelComponent } from './dialog-reservation-cancel.component';
describe('DialogReservationCancelComponent', () => {
let component: DialogReservationCancelComponent;
let fixture: ComponentFixture<DialogReservationCancelComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DialogReservationCancelComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DialogReservationCancelComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector: 'byte-dialog-reservation-cancel',
templateUrl: './dialog-reservation-cancel.component.html',
styleUrls: ['./dialog-reservation-cancel.component.scss']
})
export class DialogReservationCancelComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<DialogReservationCancelComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {}
ngOnInit(): void {}
onNoClick() {
this.dialogRef.close(false);
}
onCancel() {
this.dialogRef.close(true);
}
}
<form [formGroup]="payForm" (ngSubmit)="onPay()">
<div class="d-flex">
<img width="100" src="../../../../../assets/images/logo.png" class="img-thumbnail">
<h1 mat-dialog-title class="mb-0 ml-2">Realizar pago</h1>
</div>
<div mat-dialog-content>
<hr>
<div>
<xdf-input name="creditCardNumber" label="pay-form.creditCardNumber" [required]="true"
placeholder="pay-form.creditCardNumber.placeholder" type="number" [formGroup]="payForm"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
<div class="row">
<xdf-datepicker class="col-6" name="expiration" label="pay-form.expiration" [required]="true"
placeholder="pay-form.expiration.placeholder" [formGroup]="payForm"
[options]="{maxLenght: 120, showLength: true}">
</xdf-datepicker>
<xdf-input class="col-6" name="cvv" label="pay-form.cvv" [required]="true"
placeholder="pay-form.cvv.placeholder" type="number" [formGroup]="payForm"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<xdf-input name="owner" label="pay-form.owner" [required]="true"
placeholder="pay-form.owner.placeholder" type="text" [formGroup]="payForm"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<hr>
</div>
<div mat-dialog-actions class="d-flex justify-content-between">
<button type="button" mat-button (click)="onNoClick()" class="btn btn-outline-secondary">Cancelar</button>
<button type="submit" mat-button [disabled]="payForm.invalid" class="btn btn-primary" cdkFocusInitial>Pagar: {{ data.pay.amount }} USD</button>
</div>
</form>
import { Component, Inject, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { DialogFlightCostComponent } from '../../../supervisor/components/dialog-flight-cost/dialog-flight-cost.component';
@Component({
templateUrl: './dialog-reservation-pay.component.html',
styleUrls: ['./dialog-reservation-pay.component.scss']
})
export class DialogReservationPayComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<DialogFlightCostComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {}
payForm: FormGroup = new FormGroup({
creditCardNumber: new FormControl('', [Validators.required, Validators.minLength(16), Validators.maxLength(16)]),
expiration: new FormControl('', [Validators.required, Validators.minLength(5), Validators.maxLength(5)]),
cvv: new FormControl('', [Validators.required, Validators.minLength(3), Validators.maxLength(3)]),
owner: new FormControl('', [Validators.required, Validators.minLength(3), Validators.maxLength(50)]),
});
ngOnInit(): void {
}
onNoClick() {
this.data.status = false;
this.dialogRef.close({ status: false });
}
onPay() {
const pay = {
creditCardNumber: this.payForm.value.creditCardNumber,
expiration: this.payForm.value.expiration,
cvv: this.payForm.value.cvv,
owner: this.payForm.value.owner
}
this.data.status = true;
this.data.pay.status = "PAID";
this.dialogRef.close({status: true, pay: pay});
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard, ResourceAuthGuard } from '@xdf/security';
import { ReservationsComponent } from './view/reservations/reservations.component';
const routes: Routes = [
{
path: 'my-reservations',
component: ReservationsComponent,
canActivate: [AuthGuard, ResourceAuthGuard],
data: {
innerTemplate: 'none',
program: 'reservations_passenger_list',
breadcrumb: 'Reservaciones'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PassengerRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatIconModule, MatMenuModule, MatPaginatorModule, MatProgressSpinnerModule, MatSortModule, MatTableModule } from '@angular/material';
import { XdfGalleryModule } from '@xdf/gallery';
import { XdfSettingsModule } from '@xdf/settings';
import { RouterModule } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { ReservationsComponent } from './view/reservations/reservations.component';
import { PassengerRoutingModule } from './passenger-routing.module';
import { DialogReservationPayComponent } from './components/dialog-reservation-pay/dialog-reservation-pay.component';
import { DialogReservationCancelComponent } from './components/dialog-reservation-cancel/dialog-reservation-cancel.component';
@NgModule({
declarations: [ReservationsComponent, DialogReservationPayComponent, DialogReservationCancelComponent],
imports: [
CommonModule,
RouterModule,
PassengerRoutingModule,
MatTableModule,
MatMenuModule,
MatIconModule,
MatIconModule,
MatProgressSpinnerModule,
MatSortModule,
MatPaginatorModule,
FormsModule,
ReactiveFormsModule,
XdfGalleryModule,
XdfSettingsModule,
TranslateModule
],
entryComponents: [
DialogReservationPayComponent,
DialogReservationCancelComponent
]
})
export class PassengerModule { }
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DynaDataService } from '@xdf/gallery';
import { Observable } from 'rxjs';
@Injectable({providedIn: 'root'})
export class PassengerReservationService extends DynaDataService {
constructor(private httpClient: HttpClient) {
super(httpClient);
}
edit(data: any, id: any): Observable<any> {
this.serviceURL = '/service/reservations/edit';
return super.update(id, data);
}
}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<div class="">
<i class="fa fa-book fa-1_5x"></i>
<h5 class="ml-2 title">Mis reservas</h5>
</div>
<span class="subtitle">Este mantenimiento te permite visualizar tus reservas</span>
</div>
<div class="ibox-content">
<div class="content">
<div class="grid-ibox-content">
<div class="filter-panel mat-elevation-z3">
<xdf-ngx-tags-input name="name" class="input-lg" [fields]="fieldFilters"
(filterEvent)="onFilter($event)"></xdf-ngx-tags-input>
</div>
<div class="mat-elevation-z3">
<table class="crud-table table table-striped table-hover mt-2 mb-0" mat-table
[dataSource]="dataSource" matSort [matSortActive]="sortColumn"
[matSortDirection]="sortDirection" matSortDisableClear multiTemplateDataRows>
<ng-container *ngFor="let template of columnTemplateArray" matColumnDef="{{template.name}}">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{ template.title | translate }} </th>
<td mat-cell *matCellDef="let item">
<span [ngClass]="getReservationStatusClass(item[template['name']])">{{ item[template['name']] | translate }}</span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td class="text-center mat-cell cdk-column-actions mat-column-actions ng-star-inserted"
mat-cell="" role="gridcell" *matCellDef="let item">
<div class="d-flex">
<button (click)="onPayProcess(item)" [disabled]="item.status !== 'RESERVED'" class="btn btn-pay mr-0">
<i class="fa fa-regular fa-credit-card"></i>
<span class="ml-1">Pagar</span>
</button>
<button (click)="onCancelProcess(item)" [disabled]="item.status !== 'RESERVED'" class="btn btn-pay">
<i class="fa fa-solid fa-ban"></i>
<span class="ml-1">Cancelar</span>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<div class="grid-container d-flex justify-content-between align-items-center">
<div class="status-button-bar pull-left">
<button class="btn ml-2 btn-refresh" type="button" mat-icon-button
(click)="onRefresh()">
<i class="fa fa-refresh"></i>
</button>
</div>
<mat-paginator [length]="pagination?.totalItems" [pageSize]="pagination?.itemsPerPage"
[pageSizeOptions]="[5, 10, 15]" [pageIndex]="pagination?.currentPage">
</mat-paginator>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
$my-gray-dark: #676a6c;
$my-gray-light: #bfc0c2;
.title {
font-size: 16px;
font-weight: bold;
}
.subtitle {
font-weight: normal;
font-size: 12px;
}
th, td {
color: $my-gray-dark;
font-size: 12px;
}
.btn-pay {
height: 24px;
font-size: 10px;
width: auto;
background-color: white;
border: 1px solid $my-gray-light;
color: #343a40;
border-radius: 4px;
padding: 0 10px;
display: flex;
align-items: center;
}
.btn-refresh {
border-radius: 50%;
box-shadow: none;
}
.btn-refresh:active {
background-color: #e8e7e7;
}
import { DialogReservationCancelComponent } from './../../components/dialog-reservation-cancel/dialog-reservation-cancel.component';
import { ChangeDetectorRef, Component, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { PassengerReservationService } from '../../services/passenger-reservation.service';
import { ColumnTemplate, ConfirmationDialogService, DynaDataSource, FieldFilter, extractRSQL } from '@xdf/gallery';
import { TagFilter } from '@xdf/gallery/lib/views/gallery/ngx-tags-input/model/tag-filter';
import { AuthenticationService, NotificationService, NotificationType, Pagination, SortField } from '@xdf/commons';
import { tap } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import { AgentService } from '../../../supervisor/service/agent.service';
import { TranslateService } from '@ngx-translate/core';
import { MatDialog, MatPaginator, MatSort } from '@angular/material';
import { DialogReservationPayComponent } from '../../components/dialog-reservation-pay/dialog-reservation-pay.component';
const columnTemplateArray = [
{
name: 'id',
sortable: true,
title: 'reservation_id',
visible: true,
filtable: true,
style: { width: '75px' },
type: 'number',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'airportOrigin',
sortable: true,
title: 'reservation_airportOrigin',
visible: true,
filtable: true,
style: { width: '120px' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'airportDestination',
sortable: true,
title: 'reservation_airportDestination',
visible: true,
filtable: true,
style: { width: '120xp' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'departureDate',
sortable: true,
title: 'reservation_departureDate',
visible: true,
filtable: true,
style: { width: '120px' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'status',
sortable: true,
title: 'reservation_status',
visible: true,
filtable: true,
style: { width: '120px' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'amount',
sortable: true,
title: 'reservation_price',
visible: true,
filtable: true,
style: { width: '120px' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
}
];
const fieldFilters = [];
@Component({
selector: 'byte-reservations',
templateUrl: './reservations.component.html',
styleUrls: ['./reservations.component.scss']
})
export class ReservationsComponent implements OnInit {
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
@ViewChild(MatSort, { static: false }) sort: MatSort;
sortColumn: string;
sortDirection: string;
statusQuickFilter: string;
pagingSize = 10;
programIdentifier = 'agent';
columnTemplateArray: ColumnTemplate[];
dataSource: DynaDataSource;
displayedColumns = new Array<string>();
fieldFilters: Array<FieldFilter> = fieldFilters;
filterTags = [];
pagination: Pagination;
public resourceAuth: any;
constructor(
private route: ActivatedRoute,
private reservationService: PassengerReservationService,
private notificationService: NotificationService,
protected confirmationDialogService: ConfirmationDialogService,
protected vcRef: ViewContainerRef,
public matDialog: MatDialog
) { }
ngAfterViewInit(): void {
this.sort.sortChange.subscribe(() => {
if (!this.sort.disabled && this.sort.active) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection = this.sort.direction;
sortField.field = this.sortColumn = this.sort.active;
this.pagination.sortFields.push(sortField);
}
this.paginator.pageIndex = 0;
this.dataSource.load(this.pagination);
});
this.paginator.page
.pipe(
tap(() => {
this.pagination.currentPage = this.paginator.pageIndex;
this.pagination.itemsPerPage = this.paginator.pageSize;
this.dataSource.load(this.pagination);
})
)
.subscribe();
}
ngOnInit() {
this.sortColumn = 'id';
this.sortDirection = 'asc';
const authList = this.route.snapshot.paramMap['authorization'];
if (authList) {
this.resourceAuth = new Object();
authList.forEach(option => {
this.resourceAuth[option] = true;
});
}
this.columnTemplateArray = columnTemplateArray;
this.reservationService.serviceURL = '/service/reservations';
this.dataSource = new DynaDataSource(this.reservationService);
const previousState = JSON.parse(localStorage.getItem(this.programIdentifier + '-state'));
if (previousState) {
const PAG = 'pagination';
const FILTERS = 'filtersTags';
this.pagination = previousState[PAG];
this.filterTags = previousState[FILTERS];
localStorage.removeItem(this.programIdentifier + '-state');
} else {
// Paginación
this.pagination = new Pagination();
this.pagination.currentPage = 0;
this.pagination.itemsPerPage = this.pagingSize;
this.pagination.filterExpression = 'id != 0';
// Ordenación por defecto
if (this.sortColumn && this.sortDirection) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection;
sortField.field = this.sortColumn;
this.pagination.sortFields.push(sortField);
}
}
// calculando la columnas a pintar
this.columnTemplateArray.forEach(column => {
this.displayedColumns.push(column.name);
});
this.displayedColumns.push('actions');
this.dataSource.load(this.pagination);
}
getReservationStatusClass(status: string) {
switch (status) {
case 'RESERVED':
return 'badge badge-pill badge-info py-2 px-1 rounded';
case 'PAID':
return 'badge badge-pill badge-success py-2 px-1 rounded';
case 'CANCELED':
return 'badge badge-pill badge-danger py-2 px-1 rounded';
default:
return '';
}
}
onFilter(tags: Array<TagFilter>) {
this.filterTags = tags;
this.pagination.currentPage = 0;
// let tagsTemp = tags.slice();
const tagsTemp = tags.map(a => Object.assign({}, a));
for (let i = 0; i < tagsTemp.length; i++) {
if (tagsTemp[i].column !== 'id') {
tagsTemp[i].value = tags[i].value;
}
}
this.pagination.filterExpression = extractRSQL(tagsTemp);
if (this.pagination.filterExpression === null || this.pagination.filterExpression === undefined) {
this.pagination.filterExpression = 'id != 0';
}
this.dataSource.load(this.pagination);
}
onRefresh() {
this.dataSource.load(this.pagination);
}
onPayProcess(pay) {
const ref = this.matDialog.open(DialogReservationPayComponent, {
width: '600px',
data: {
status: false,
pay: pay
}
});
ref.afterClosed().subscribe(result => {
if (result && result.status) {
const data = { status: 'PAID' };
this.reservationService.edit(data, pay.id)
.subscribe(response => {
this.notificationService.showMessage('Pago realizado con éxito', 'Información', NotificationType.success);
})
}
});
}
onCancelProcess(pay) {
const ref = this.matDialog.open(DialogReservationCancelComponent, {
width: '400px',
});
ref.afterClosed().subscribe(result => {
if (result) {
const data = { status: 'CANCELED' };
this.reservationService.edit(data, pay.id)
.subscribe(response => {
this.notificationService.showMessage('Se cancelo la reserva con exito!', 'Información', NotificationType.success);
})
}
});
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '@xdf/security';
import { TemplateResolver, CrudDetailComponent, DirtyGuard, GridViewComponent, CrudGridComponent, RecordResolver } from '@xdf/gallery';
import { ResourceAuthGuard } from '@xdf/security';
import { UserRoleFormComponent, AccessDetailResolver } from '@xdf/settings';
const routes: Routes = [
{
path: 'user-role', component: GridViewComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
program: 'user_role',
breadcrumb: 'breadcrumb.user.role'
}
},
{
path: 'user-role/detail/:mode', component: UserRoleFormComponent, canActivate: [AuthGuard, ResourceAuthGuard],
canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver, accessList: AccessDetailResolver },
data: {
program: 'user_role',
breadcrumb: 'breadcrumb.user.role.detail'
}
},
{
path: 'user', component: CrudGridComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
innerTemplate: 'none',
program: 'user',
breadcrumb: 'breadcrumb.user'
}
},
{
path: 'user/detail/:mode', component: CrudDetailComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver },
data: {
program: 'user',
breadcrumb: 'breadcrumb.user.detail'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SecurityRoutingModule { }
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule } from '@xdf/gallery';
import { SecurityRoutingModule } from './security-routing.module';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { XdfSettingsModule } from '@xdf/settings';
@NgModule({
declarations: [
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
XdfGalleryModule,
XdfSettingsModule,
SecurityRoutingModule
],
entryComponents: [
],
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard }
]
})
export class SecurityModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '@xdf/security';
import { DirtyGuard, TemplateResolver, CrudGridComponent, EditableDataTableTemplateResolver } from '@xdf/gallery';
import { CrudDetailComponent, FormViewComponent, ListResolver, RecordResolver } from '@xdf/gallery';
import { ResourceAuthGuard } from '@xdf/security';
import { ApplicationFormComponent, ValposFormComponent } from '@xdf/settings';
import { TabsLayoutComponent, TabsTemplateResolver } from '@xdf/layouts';
const routes: Routes = [
{
path: 'system-settings', component: TabsLayoutComponent,
resolve: { template: TabsTemplateResolver },
data: {
templateName: 'system-settings',
},
children: [
{ path: 'information', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
option: 'information',
program: 'system_settings_information',
breadcrumb: 'breadcrumb.settings.information'
}
},
{ path: 'information/:mode', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { ecord: ListResolver },
data: {
withoutGrid: true,
option: 'information',
program: 'system_settings_information',
breadcrumb: 'breadcrumb.settings.information'
}
},
{ path: 'password', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
option: 'password',
program: 'system_settings_password',
breadcrumb: 'breadcrumb.settings.password'
}
},
{ path: 'password/:mode', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
withoutGrid: true,
option: 'password',
program: 'system_settings_password',
breadcrumb: 'breadcrumb.settings.password'
}
},
{ path: 'userpolicy', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
option: 'userpolicy',
program: 'system_settings_userpolicy',
breadcrumb: 'breadcrumb.settings.userpolicy'
}
},
{ path: 'userpolicy/:mode', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
withoutGrid: true,
option: 'userpolicy',
program: 'system_settings_userpolicy',
breadcrumb: 'breadcrumb.settings.userpolicy'
}
}
]
},
{
path: 'application', component: CrudGridComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
program: 'application',
breadcrumb: 'breadcrumb.application'
}
},
{
path: 'application/detail/:mode', component: ApplicationFormComponent,
canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver },
data: {
program: 'application',
breadcrumb: 'breadcrumb.application.detail'
}
},
{
path: 'valpos', component: CrudGridComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
program: 'valpos',
breadcrumb: 'breadcrumb.valpos'
}
},
{
path: 'valpos/detail/:mode', component: ValposFormComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver, editableTableTemplate: EditableDataTableTemplateResolver },
data: {
program: 'valpos',
breadcrumb: 'breadcrumb.valpos.detail',
editableTableTemplate: 'valpos-detail'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SettingsRoutingModule { }
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule, EditableDataTableTemplateResolver } from '@xdf/gallery';
import { SettingsRoutingModule } from './settings-routing.module';
import { TranslateModule } from '@ngx-translate/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule, MatSelectModule, MatTooltipModule, MatButtonModule } from '@angular/material';
import { XdfSettingsModule } from '@xdf/settings';
import { XdfLayoutsModule } from '@xdf/layouts';
@NgModule({
declarations: [
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
SettingsRoutingModule,
MatFormFieldModule,
MatSelectModule,
MatTooltipModule,
XdfGalleryModule,
XdfSettingsModule,
XdfLayoutsModule,
MatButtonModule
],
entryComponents: [
],
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard },
EditableDataTableTemplateResolver
]
})
export class SettingsModule { }
<form (ngSubmit)="onSave()">
<div class="d-flex">
<i class="fa fa-solid fa-triangle-exclamation text-error"></i>
<h1 mat-dialog-title class="mb-0 ml-2">Eliminar</h1>
</div>
<div mat-dialog-content>
<hr>
<div>
<p>¿Está seguro que desea eliminar este registro?</p>
</div>
<hr>
</div>
<div mat-dialog-actions class="d-flex justify-content-between">
<button type="button" mat-button (click)="onNoClick()" class="btn btn-outline-secondary">Cancelar</button>
<button type="submit" mat-button class="btn btn-primary" cdkFocusInitial>Aceptar</button>
</div>
</form>
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { DialogFlightCostComponent } from '../dialog-flight-cost/dialog-flight-cost.component';
@Component({
selector: 'byte-dialog-delete',
templateUrl: './dialog-delete.component.html',
styleUrls: ['./dialog-delete.component.scss']
})
export class DialogDeleteComponent {
constructor(public dialogRef: MatDialogRef<DialogFlightCostComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) { }
onNoClick() {
this.dialogRef.close(false);
}
onSave() {
this.dialogRef.close(true);
}
}
<form [formGroup]="costForm" (ngSubmit)="onSave()">
<div class="d-flex">
<img width="100" src="../../../../../assets/images/logo.png" class="img-thumbnail">
<h1 mat-dialog-title class="mb-0 ml-2">Configurar costo</h1>
</div>
<div mat-dialog-content>
<hr>
<div>
<xdf-datepicker name="departureDate" label="flight-form.departureDate" [required]="true"
placeholder="flight-form.departureDate.placeholder" [formGroup]="costForm"
[options]="{maxLenght: 120, showLength: true}" [minDate]="data.minDate" [maxDate]="data.maxDate">
</xdf-datepicker>
<xdf-datepicker name="arrivalDate" label="flight-form.arrivalDate" [required]="true"
placeholder="flight-form.arrivalDate.placeholder" [formGroup]="costForm"
[options]="{maxLenght: 120, showLength: true}" [minDate]="data.minDate" [maxDate]="data.maxDate">
</xdf-datepicker>
<xdf-input name="price" label="flight-form.price" [required]="true"
placeholder="flight-form.price.placeholder" type="number" [formGroup]="costForm"
[options]="{maxLenght: 120, showLength: true}">
</xdf-input>
</div>
<hr>
</div>
<div mat-dialog-actions class="d-flex justify-content-between">
<button type="button" mat-button (click)="onNoClick()" class="btn btn-outline-secondary">Cancelar</button>
<button type="submit" mat-button [disabled]="costForm.invalid" class="btn btn-primary" cdkFocusInitial>Aceptar</button>
</div>
</form>
import { DatePipe } from '@angular/common';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector: 'byte-dialog-flight-cost',
templateUrl: './dialog-flight-cost.component.html',
styleUrls: ['./dialog-flight-cost.component.scss']
})
export class DialogFlightCostComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<DialogFlightCostComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {}
costForm: FormGroup = new FormGroup({
departureDate: new FormControl(null, [Validators.required]),
arrivalDate: new FormControl(null, [Validators.required]),
price: new FormControl(null, [Validators.required])
});
ngOnInit(): void {
}
onNoClick() {
this.data.status = false;
this.dialogRef.close({ status: false });
}
onSave() {
const cost = {
departureDate: new DatePipe('en-US').transform(this.costForm.get('departureDate').value, "yyyy-MM-dd'T'HH:mm:ss"),
arrivalDate: new DatePipe('en-US').transform(this.costForm.get('arrivalDate').value, "yyyy-MM-dd'T'HH:mm:ss"),
amount: this.costForm.value.price,
isNew: true
}
this.dialogRef.close({status: true, cost: cost});
}
}
<form [formGroup]="scaleForm" (ngSubmit)="onSave()">
<div class="d-flex">
<img width="100" src="../../../../../assets/images/logo.png" class="img-thumbnail">
<h1 mat-dialog-title class="mb-0 ml-2">Configurar escala</h1>
</div>
<div mat-dialog-content>
<hr>
<div>
<xdf-select name="airportOrigin" label="flight-form.airportOrigin.placeholder" [required]="true"
placeholder="flight-form.airportOrigin.placeholder" [values]="data.airports" [formGroup]="scaleForm"
[options]="{maxLenght: 120, showLenght: true}">
</xdf-select>
<xdf-select name="airportDestination" label="flight-form.airportDestination.placeholder" [required]="true"
placeholder="flight-form.airportDestination.placeholder" [values]="data.airports" [formGroup]="scaleForm"
[options]="{maxLenght: 120, showLenght: true}">
</xdf-select>
<xdf-datepicker name="departureDate" label="flight-form.departureDate" [required]="true"
placeholder="flight-form.departureDate.placeholder" [formGroup]="scaleForm"
[options]="{maxLenght: 120, showLength: true}">
</xdf-datepicker>
<xdf-datepicker name="arrivalDate" label="flight-form.arrivalDate" [required]="true"
placeholder="flight-form.arrivalDate.placeholder" [formGroup]="scaleForm"
[options]="{maxLenght: 120, showLength: true}" [minDate]="scaleForm.get('departureDate').value">
</xdf-datepicker>
</div>
<hr>
</div>
<div mat-dialog-actions class="d-flex justify-content-between">
<button type="button" mat-button (click)="onNoClick()" class="btn btn-outline-secondary">Cancelar</button>
<button type="submit" mat-button class="btn btn-primary" cdkFocusInitial>Aceptar</button>
</div>
</form>
import { DatePipe } from '@angular/common';
import { Component, Inject, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector: 'byte-dialog-flight-scale',
templateUrl: './dialog-flight-scale.component.html',
styleUrls: ['./dialog-flight-scale.component.scss']
})
export class DialogFlightScaleComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<DialogFlightScaleComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {}
scaleForm: FormGroup = new FormGroup({
airportOrigin: new FormControl(null, [Validators.required]),
airportDestination: new FormControl(null, [Validators.required]),
departureDate: new FormControl(null, [Validators.required]),
arrivalDate: new FormControl(null, [Validators.required])
});
ngOnInit(): void {
}
onNoClick() {
this.data.status = false;
this.dialogRef.close({ status: false });
}
onSave() {
const scale = {
airportOriginId: this.scaleForm.value.airportOrigin,
airportDestinationId: this.scaleForm.value.airportDestination,
departureDate: new DatePipe('en-US').transform(this.scaleForm.get('departureDate').value, "yyyy-MM-dd'T'HH:mm:ss"),
arrivalDate: new DatePipe('en-US').transform(this.scaleForm.get('arrivalDate').value, "yyyy-MM-dd'T'HH:mm:ss")
}
console.log(scale);
this.dialogRef.close({status: true, scale: scale});
}
}
<div class="grid-ibox-content d-flex">
<div class="flex-fill mr-2">
<div class="filter-panel mat-elevation-z3">
<xdf-ngx-tags-input name="name" class="input-lg" [fields]="fieldFilters">
</xdf-ngx-tags-input>
</div>
<br />
<div class="grid-container mat-elevation-z3">
<div class="grid-ibox-content">
<table class="crud-table table table-striped table-hover" mat-table
[dataSource]="costs">
<ng-container *ngFor="let template of columnTemplateArray" matColumnDef="{{template.name}}">
<th mat-header-cell *matHeaderCellDef> {{ template.title | translate }} </th>
<td mat-cell *matCellDef="let item"> {{ item[template['name']] }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let item">
<div class="d-flex justify-content-end">
<button type="button" (click)="onDelete(item)" [disabled]="mode === 'view' || !item.isNew" class="btn btn-autline-secondary btn-small">
<span><i class="fa fa-trash"></i></span>
<span class="ml-1">Eliminar</span>
</button>
<button type="button" (click)="onEdit(item)" [disabled]="mode === 'view' || !item.isNew" class="btn btn-autline-secondary btn-small ml-0">
<span><i class="fa fa-pencil"></i></span>
<span class="ml-1">Editar</span>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
<div class="toolbar-option flex-auto">
<button type="button" (click)="onAdd()" [disabled]="mode === 'view'" color="default" mat-mini-fab="" class="mat-mini-fab">
<span><i class="fa fa-plus"></i></span>
</button>
</div>
</div>
$my-gray-dark: #6c757d;
td, th {
color: $my-gray-dark;
font-size: 12px;
}
.btn {
font-size: 10px;
color: #6c757d;
height: 24px;
display: flex;
align-items: center;
background-color: white;
border: 1px solid $my-gray-dark;
}
\ No newline at end of file
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewContainerRef } from '@angular/core';
import { MatDialog, MatStepper } from '@angular/material';
import { AuditDialogService, ColumnTemplate, ConfirmationDialogService, DynaDataService, DynaDataSource, FieldFilter, IFormView, ValidatorUtils } from '@xdf/gallery';
import { DialogFlightCostComponent } from '../dialog-flight-cost/dialog-flight-cost.component';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { InitCommonsService, NotificationService } from '@xdf/commons';
import { NavigationService } from '@xdf/layouts';
import { FormGroup } from '@angular/forms';
const fieldFilters = [
new FieldFilter('agent_code', 'id', 'id', 'number', undefined),
new FieldFilter('agent_name', 'name', 'name', 'string', undefined),
new FieldFilter('agent_status', 'status', 'status', 'valpos', (
{ DP: 'label.deployed', PS: 'label.sync-pending' }
) as any),
];
const columnTemplateArray = [
{
name: 'id',
sortable: false,
title: 'cost_id',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'number',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'departureDate',
sortable: true,
title: 'cost_departureDate',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'arrivalDate',
sortable: true,
title: 'cost_arrivalDate',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'amount',
sortable: true,
title: 'cost_price',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'number',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
}
];
@Component({
selector: 'byte-panel-cost-config',
templateUrl: './panel-cost-config.component.html',
styleUrls: ['./panel-cost-config.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PanelCostConfigComponent implements OnInit {
columnTemplateArray: ColumnTemplate[];
displayedColumns = new Array<string>();
fieldFilters: Array<FieldFilter> = fieldFilters;
filterTags = [];
mode: string;
@Input()
public costs: any[] = [];
@Input()
public minDate: any;
@Input()
public maxDate: any;
@Output()
public onAddCost: EventEmitter<any> = new EventEmitter();
constructor(public dialog: MatDialog, public changeDetectorRef: ChangeDetectorRef, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.columnTemplateArray = columnTemplateArray;
this.columnTemplateArray.forEach(column => {
this.displayedColumns.push(column.name);
});
this.activatedRoute.params.subscribe(params => {
this.mode = params.mode;
});
this.displayedColumns.push('actions');
}
ngAfterViewChecked(): void {
this.changeDetectorRef.detectChanges();
}
foundMaxId(): number {
let maxId = 0;
this.costs.forEach(cost => {
if (cost.id > maxId) {
maxId = cost.id;
}
});
return maxId;
}
onDelete(): void {
console.log('onDelete');
}
onEdit(): void {
console.log('onEdit');
}
onAdd() {
const dialogRef = this.dialog.open(DialogFlightCostComponent, {
width: '600px',
data: { minDate: this.minDate, maxDate: this.maxDate }
});
dialogRef.afterClosed().subscribe(result => {
if (result.status) {
this.onAddCost.emit({...result.cost, id: this.foundMaxId() + 1});
}
})
}
}
<div class="grid-ibox-content d-flex">
<div class="flex-fill mr-2">
<div class="filter-panel mat-elevation-z3">
<xdf-ngx-tags-input name="name" class="input-lg" [fields]="fieldFilters"
(filterEvent)="onFilter($event)"></xdf-ngx-tags-input>
</div>
<br />
<div class="grid-container mat-elevation-z3">
<div class="grid-ibox-content">
<table class="crud-table table table-striped table-hover" mat-table
[dataSource]="scales">
<ng-container *ngFor="let template of columnTemplateArray" matColumnDef="{{template.name}}">
<th mat-header-cell *matHeaderCellDef> {{ template.title | translate }} </th>
<td mat-cell *matCellDef="let item"> {{ item[template.name] }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let item">
<div class="d-flex justify-content-end">
<button type="button" (click)="onDelete(item)" [disabled]="true" class="btn btn-autline-secondary btn-small">
<span><i class="fa fa-trash"></i></span>
<span class="ml-1">Eliminar</span>
</button>
<button type="button" (click)="onEdit(item)" [disabled]="true" class="btn btn-autline-secondary btn-small ml-0">
<span><i class="fa fa-pencil"></i></span>
<span class="ml-1">Editar</span>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
<div class="toolbar-option flex-auto">
<button type="button" (click)="onAddScale()" [disabled]="mode !== 'new'" color="default" mat-mini-fab="" class="mat-mini-fab">
<span><i class="fa fa-plus"></i></span>
</button>
</div>
</div>
$my-gray-dark: #6c757d;
td, th {
color: $my-gray-dark;
font-size: 12px;
}
.btn {
font-size: 10px;
color: #6c757d;
height: 24px;
display: flex;
align-items: center;
background-color: white;
border: 1px solid $my-gray-dark;
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment