diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ca926ac --- /dev/null +++ b/.dockerignore @@ -0,0 +1,66 @@ +# Dependencias +node_modules +npm-debug.log +yarn-debug.log +yarn-error.log + +# Archivos de compilación +/dist +/tmp +/out-tsc +/bazel-out + +# Archivos de IDE y editores +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace +.vscode/* + +# Archivos del sistema +.DS_Store +Thumbs.db + +# Archivos de entorno (excepto los de ejemplo) +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Archivos de Docker (para evitar recursión) +Dockerfile +Dockerfile.* +docker-compose.yml +docker-compose.*.yml + +# Archivos Git +.git +.gitignore + +# Archivos de test y coverage +/coverage +/tests +*.spec.ts + +# Archivos de configuración +.angular/cache +.sass-cache/ +connect.lock +libpeerconnection.log +testem.log +/typings + +# Archivos de build temporales +.build +.buildinfo +.cache + +# Otros archivos innecesarios +README.md +CHANGELOG.md +*.md +LICENSE \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2aa7e3b..fb2685d 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ testem.log Thumbs.db .sonarlint .vscode -.scannerwork \ No newline at end of file +.scannerwork +package-lock.json \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..7147036 --- /dev/null +++ b/.htaccess @@ -0,0 +1,67 @@ +# Habilitar compresión GZIP + + # Comprimir HTML, CSS, JavaScript, Text, XML y fonts + AddOutputFilterByType DEFLATE application/javascript + AddOutputFilterByType DEFLATE application/rss+xml + AddOutputFilterByType DEFLATE application/vnd.ms-fontobject + AddOutputFilterByType DEFLATE application/x-font + AddOutputFilterByType DEFLATE application/x-font-opentype + AddOutputFilterByType DEFLATE application/x-font-otf + AddOutputFilterByType DEFLATE application/x-font-truetype + AddOutputFilterByType DEFLATE application/x-font-ttf + AddOutputFilterByType DEFLATE application/x-javascript + AddOutputFilterByType DEFLATE application/xhtml+xml + AddOutputFilterByType DEFLATE application/xml + AddOutputFilterByType DEFLATE font/opentype + AddOutputFilterByType DEFLATE font/otf + AddOutputFilterByType DEFLATE font/ttf + AddOutputFilterByType DEFLATE image/svg+xml + AddOutputFilterByType DEFLATE image/x-icon + AddOutputFilterByType DEFLATE text/css + AddOutputFilterByType DEFLATE text/html + AddOutputFilterByType DEFLATE text/javascript + AddOutputFilterByType DEFLATE text/plain + AddOutputFilterByType DEFLATE text/xml + + # Eliminar bugs de navegadores antiguos + BrowserMatch ^Mozilla/4 gzip-only-text/html + BrowserMatch ^Mozilla/4\.0[678] no-gzip + BrowserMatch \bMSIE !no-gzip !gzip-only-text/html + + # No comprimir imágenes (ya están comprimidas) + SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp)$ no-gzip + + +# Habilitar caché de navegador + + ExpiresActive On + + # Imágenes + ExpiresByType image/jpeg "access plus 1 year" + ExpiresByType image/gif "access plus 1 year" + ExpiresByType image/png "access plus 1 year" + ExpiresByType image/webp "access plus 1 year" + ExpiresByType image/svg+xml "access plus 1 year" + ExpiresByType image/x-icon "access plus 1 year" + + # Video + ExpiresByType video/mp4 "access plus 1 year" + ExpiresByType video/mpeg "access plus 1 year" + + # CSS, JavaScript + ExpiresByType text/css "access plus 1 month" + ExpiresByType text/javascript "access plus 1 month" + ExpiresByType application/javascript "access plus 1 month" + + # Otros + ExpiresByType application/pdf "access plus 1 month" + ExpiresByType application/x-shockwave-flash "access plus 1 month" + + +# Reglas de SPA para Angular +RewriteEngine On +RewriteBase / +RewriteRule ^index\.html$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.html [L] \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f71eca5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +FROM node:20.19.1-alpine AS build + +# Establecer directorio de trabajo +WORKDIR /app + +# Copiar archivos de dependencias e instalar +COPY package*.json ./ +RUN npm install + +# Copiar el resto de archivos de la aplicación +COPY . . + +# Compilar la aplicación +RUN npm run build:prod + +# Segunda etapa: Nginx +FROM nginx:latest + +# Copiar la configuración de Nginx +COPY nginx.conf /etc/nginx/nginx.conf + +# Copiar archivos compilados desde la etapa anterior +COPY --from=build /app/dist/cronogramas-primeng/browser /usr/share/nginx/html + +# Exponer puerto +EXPOSE 80 + +# Comando para iniciar Nginx (usa el predeterminado de la imagen) \ No newline at end of file diff --git a/angular.json b/angular.json index 3bc0b7a..67a8205 100644 --- a/angular.json +++ b/angular.json @@ -29,13 +29,30 @@ { "glob": "**/*", "input": "public" + }, + { + "glob": ".htaccess", + "input": ".", + "output": "/" } ], "styles": [ "src/styles.scss", - "node_modules/animate.css/animate.min.css", - "node_modules/primeflex/primeflex.css", - "node_modules/primeicons/primeicons.css" + { + "input": "node_modules/animate.css/animate.min.css", + "bundleName": "animate", + "inject": true + }, + { + "input": "node_modules/primeflex/primeflex.css", + "bundleName": "primeflex", + "inject": true + }, + { + "input": "node_modules/primeicons/primeicons.css", + "bundleName": "primeicons", + "inject": true + } ], "scripts": [], "allowedCommonJsDependencies": [ @@ -45,7 +62,11 @@ }, "configurations": { "production": { - "outputHashing": "all" + "outputHashing": "all", + "optimization": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true }, "development": { "optimization": false, @@ -83,6 +104,11 @@ { "glob": "**/*", "input": "public" + }, + { + "glob": ".htaccess", + "input": ".", + "output": "/" } ], "styles": [ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..791043d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + web: + build: + context: . + dockerfile: Dockerfile + ports: + - "80:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + restart: unless-stopped \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..bd3cc2b --- /dev/null +++ b/nginx.conf @@ -0,0 +1,27 @@ +# the events block is required +events{} + +http { + # include the default mime.types to map file extensions to MIME types + include /etc/nginx/mime.types; + + server { + # set the root directory for the server (we need to copy our + # application files here) + root /usr/share/nginx/html; + + # set the default index file for the server (Angular generates the + # index.html file for us and it will be in the above directory) + index index.html; + + # specify the configuration for the '/' location + location / { + # try to serve the requested URI. if that fails then try to + # serve the URI with a trailing slash. if that fails, then + # serve the index.html file; this is needed in order to serve + # Angular routes--e.g.,'localhost:8080/customer' will serve + # the index.html file + try_files $uri $uri/ /index.html; + } + } +} diff --git a/package.json b/package.json index bbb7b8c..17cb376 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "ng": "ng", "start": "ng serve", "build": "ng build", + "build:prod": "ng build --configuration production", "watch": "ng build --watch --configuration development", "test": "ng test" }, diff --git a/public/img/footer-logo.webp b/public/img/footer-logo.webp new file mode 100644 index 0000000..0b3df45 Binary files /dev/null and b/public/img/footer-logo.webp differ diff --git a/public/img/header2.webp b/public/img/header2.webp new file mode 100644 index 0000000..4328642 Binary files /dev/null and b/public/img/header2.webp differ diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 975748c..6d4c25f 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,5 +1,5 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; -import { provideRouter, RouteReuseStrategy } from '@angular/router'; +import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router'; import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http'; import { routes } from './app.routes'; @@ -7,12 +7,14 @@ import { provideAnimations } from '@angular/platform-browser/animations'; import { providePrimeNG } from 'primeng/config'; import Aura from '@primeng/themes/aura'; import { authInterceptor } from './interceptors/auth.interceptor'; -import { CustomRouteReuseStrategy } from './utils/custom-route-reuse-strategy'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), - provideRouter(routes), + provideRouter( + routes, + withPreloading(PreloadAllModules) + ), provideAnimations(), provideHttpClient(withFetch(), withInterceptors([authInterceptor])), providePrimeNG({ @@ -22,12 +24,6 @@ export const appConfig: ApplicationConfig = { darkModeSelector: false || 'none' } } - }), - // Añadir estrategia de reuso de rutas personalizada para forzar - // recreación de componentes en cada navegación - { - provide: RouteReuseStrategy, - useClass: CustomRouteReuseStrategy - } + }) ] }; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 6c617c1..04c92d5 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,12 +1,6 @@ -import { Routes } from '@angular/router'; +import { Routes, PreloadAllModules } from '@angular/router'; import { LoginComponent } from './pages/login/login.component'; import { LayoutComponent } from './components/layout/layout.component'; -import { HomeComponent } from './pages/home/home.component'; -import { ConcesionesComponent } from './pages/concesiones/concesiones.component'; -import { ActualizacionPdComponent } from './pages/actualizacion-pd/actualizacion-pd.component'; -import { AjustePdComponent } from './pages/ajuste-pd/ajuste-pd.component'; -import { ResumenComponent } from './pages/resumen/resumen.component'; -import { UnidadInformacionComponent } from './pages/unidad-informacion/unidad-informacion.component'; import { authGuard } from './guards/auth.guard'; import { NotFoundComponent } from './pages/not-found/not-found.component'; @@ -18,13 +12,41 @@ export const routes: Routes = [ canActivate: [authGuard], children: [ { path: '', redirectTo: 'inicio', pathMatch: 'full' }, - { path: 'inicio', component: HomeComponent, data: { title: 'Inicio' } }, - { path: 'unidad-concesiones', component: ConcesionesComponent, data: { title: 'Unidad de Concesiones' } }, - { path: 'ct-actualizacion', component: ActualizacionPdComponent, data: { title: 'Cronograma temporal por actualización de PD' } }, - { path: 'ct-ajuste', component: AjustePdComponent, data: { title: 'Cronograma temporal por ajuste de PD' } }, - { path: 'resumen', component: ResumenComponent, data: { title: 'Resumen' } }, - { path: 'unidad-informacion', component: UnidadInformacionComponent, data: { title: 'Unidad de Información' } }, - { path: '404', component: NotFoundComponent , data: { title: 'Error 404' } }, + { + path: 'inicio', + loadComponent: () => import('./pages/home/home.component').then(m => m.HomeComponent), + data: { title: 'Inicio' } + }, + { + path: 'unidad-concesiones', + loadComponent: () => import('./pages/concesiones/concesiones.component').then(m => m.ConcesionesComponent), + data: { title: 'Unidad de Concesiones' } + }, + { + path: 'ct-actualizacion', + loadComponent: () => import('./pages/actualizacion-pd/actualizacion-pd.component').then(m => m.ActualizacionPdComponent), + data: { title: 'Cronograma temporal por actualización de PD' } + }, + { + path: 'ct-ajuste', + loadComponent: () => import('./pages/ajuste-pd/ajuste-pd.component').then(m => m.AjustePdComponent), + data: { title: 'Cronograma temporal por ajuste de PD' } + }, + { + path: 'resumen', + loadComponent: () => import('./pages/resumen/resumen.component').then(m => m.ResumenComponent), + data: { title: 'Resumen' } + }, + { + path: 'unidad-informacion', + loadComponent: () => import('./pages/unidad-informacion/unidad-informacion.component').then(m => m.UnidadInformacionComponent), + data: { title: 'Unidad de Información' } + }, + { + path: '404', + component: NotFoundComponent, + data: { title: 'Error 404' } + }, ] }, { path: '**', redirectTo: '404' } diff --git a/src/app/components/footer/footer.component.html b/src/app/components/footer/footer.component.html index 92f5541..e7f39f3 100644 --- a/src/app/components/footer/footer.component.html +++ b/src/app/components/footer/footer.component.html @@ -2,14 +2,13 @@