diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index bca6972..0b8cbca 100755 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -18,8 +18,6 @@ const routes: Routes = [ { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomePageModule), canActivate: [AuthGuard] }, { path: 'verify', loadChildren: () => import('./verify/verify.module').then(m => m.verifyPageModule), canActivate: [AuthoriginGuard]}, { path: 'category/:category', loadChildren: () => import('./pages/category/category.module').then(m => m.CategoryPageModule), canActivate: [AuthGuard] }, - { path: 'addcard', loadChildren: () => import('./pages/card/addcard/addcard.module').then(m => m.AddcardPageModule), canActivate: [AuthGuard] }, - { path: 'cards', loadChildren: () => import('./pages/card/cards/cards.module').then(m => m.CardsPageModule), canActivate: [AuthGuard] }, { path: 'postulations', loadChildren: () => import('./pages/postulations/postulations.module').then(m => m.PostulationsPageModule), canActivate: [AuthGuard] }, { path: 'contracts', loadChildren: () => import('./pages/contracts/contracts.module').then(m => m.ContractsPageModule), canActivate: [AuthGuard] }, { path: 'viewsuppliers/:postulation_id', loadChildren: () => import('./pages/contracts/viewsuppliers/viewsuppliers.module').then(m => m.ViewsuppliersPageModule), canActivate: [AuthGuard] }, @@ -33,6 +31,7 @@ const routes: Routes = [ { path: 'hero', loadChildren: () => import('./pages/hero/hero.module').then(m => m.HeroPageModule), canActivate: [AuthGuard] }, { path: 'comments', loadChildren: () => import('./pages/contracts/viewsuppliers/comments/comments.module').then(m => m.CommentsPageModule), canActivate: [AuthGuard] }, { path: 'faq', loadChildren: () => import('./pages/faq/faq.module').then(m => m.FaqPageModule), canActivate: [AuthGuard] }, + { path: 'team', loadChildren: () => import('./pages/team/team.module').then(m => m.TeamPageModule), canActivate: [AuthGuard] }, ]; @NgModule({ diff --git a/src/app/app.component.html b/src/app/app.component.html index f5850bd..fbc243c 100755 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -14,12 +14,6 @@ {{'menu.home' | translate}} - - - - {{'menu.cards' | translate}} - - @@ -50,6 +44,12 @@ {{'menu.hero' | translate}} + + + + {{'menu.team' | translate}} + + diff --git a/src/app/pages/contracts/contracted/contracted.page.html b/src/app/pages/contracts/contracted/contracted.page.html index 4446181..92b0a22 100755 --- a/src/app/pages/contracts/contracted/contracted.page.html +++ b/src/app/pages/contracts/contracted/contracted.page.html @@ -14,7 +14,7 @@ - + @@ -31,7 +31,11 @@ - + + + + +

{{ ccontract.category }}

{{ ccontract.en_category }}

@@ -43,8 +47,10 @@

{{'contracts.start_pin' | translate}}{{ ccontract.code }}

{{'contracts.info_pin' | translate}}

-
- {{'contracts.cancel_1.1' | translate}}
{{'contracts.cancel_1.2' | translate}}
+
+
+ {{'contracts.cancel_1.1' | translate}}
{{'contracts.cancel_1.2' | translate}}
+
diff --git a/src/app/pages/contracts/viewsuppliers/viewsuppliers.page.html b/src/app/pages/contracts/viewsuppliers/viewsuppliers.page.html index 9f22f8a..1a75987 100755 --- a/src/app/pages/contracts/viewsuppliers/viewsuppliers.page.html +++ b/src/app/pages/contracts/viewsuppliers/viewsuppliers.page.html @@ -19,6 +19,10 @@ + + + +

{{ pcontractsupplier.supplier }}

{{ pcontractssuppliers_certified[i] }}

diff --git a/src/app/pages/report-discussion/report-discussion.page.html b/src/app/pages/report-discussion/report-discussion.page.html index de4144b..bc97893 100644 --- a/src/app/pages/report-discussion/report-discussion.page.html +++ b/src/app/pages/report-discussion/report-discussion.page.html @@ -82,6 +82,8 @@ placeholder="Escribe un comentario..." rows="1" autoGrow="true" + style="--highlight-height: 0" + (keydown.enter)="$event.preventDefault(); newMessage.trim() && !sending && sendMessage()" > + + + + + + + Asignar Técnico + + + + + + + + + + + + + + + +

+ No tienes técnicos en tu equipo. Agrégalos desde la sección Técnicos en el menú. +

+ + + + + + + +

{{ tech.name }}

+

{{ tech.email }}

+
+ + Asignar + +
+
+
+
diff --git a/src/app/pages/team/team.page.html b/src/app/pages/team/team.page.html new file mode 100644 index 0000000..db79ac0 --- /dev/null +++ b/src/app/pages/team/team.page.html @@ -0,0 +1,59 @@ + + + + + + Técnicos + + + + + + + + + + Agregar técnico + + + + Agregar + + + +

Mi equipo

+ + + + + + + + + + + +

+ Aún no tienes técnicos en tu equipo. +

+ + + + + + + +

{{ tech.name }}

+

{{ tech.email }}

+
+ + + +
+
+
+
diff --git a/src/app/pages/team/team.page.ts b/src/app/pages/team/team.page.ts new file mode 100644 index 0000000..1237b4b --- /dev/null +++ b/src/app/pages/team/team.page.ts @@ -0,0 +1,124 @@ +import { Component, ChangeDetectorRef } from '@angular/core'; +import { AlertController } from '@ionic/angular'; +import { IchambaService } from 'src/app/services/ichamba.service'; +import { AlertService } from 'src/app/services/alert.service'; + +@Component({ + selector: 'app-team', + templateUrl: './team.page.html', + styleUrls: ['./team.page.scss'], + standalone: false +}) +export class TeamPage { + + technicians: any[] = []; + loading = true; + searchEmail = ''; + searching = false; + + constructor( + private ichambaService: IchambaService, + private alertService: AlertService, + private alertCtrl: AlertController, + private cdr: ChangeDetectorRef, + ) {} + + ionViewWillEnter() { + this.loadTechnicians(); + } + + loadTechnicians() { + this.loading = true; + this.ichambaService.getTeamTechnicians().subscribe({ + next: data => { + this.technicians = data; + this.loading = false; + this.cdr.detectChanges(); + }, + error: () => { + this.loading = false; + this.cdr.detectChanges(); + } + }); + } + + refresh(event: any) { + this.ichambaService.getTeamTechnicians().subscribe({ + next: data => { + this.technicians = data; + this.cdr.detectChanges(); + event.target.complete(); + }, + error: () => { + event.target.complete(); + } + }); + } + + async addTechnician() { + const email = this.searchEmail.trim(); + if (!email || this.searching) return; + this.searching = true; + this.cdr.detectChanges(); + + this.ichambaService.findUserByEmail(email).subscribe({ + next: async (user: any) => { + this.searching = false; + this.cdr.detectChanges(); + const alert = await this.alertCtrl.create({ + header: 'Confirmar', + message: ' ', + buttons: [ + { text: 'Cancelar', role: 'cancel' }, + { text: 'Agregar', handler: () => this.confirmAdd(user.id) } + ] + }); + await alert.present(); + alert.querySelector('.alert-message')!.innerHTML = `¿Estás seguro de agregar a ${user.name} a tu compañía?`; + }, + error: () => { + this.searching = false; + this.alertService.presentToast('No existe ningún usuario asignado a esa cuenta'); + this.cdr.detectChanges(); + } + }); + } + + confirmAdd(userId: any) { + this.ichambaService.addTechnicianByUserId(userId).subscribe({ + next: () => { + this.alertService.presentToast('Técnico agregado exitosamente'); + this.searchEmail = ''; + this.loadTechnicians(); + }, + error: () => { + this.alertService.presentToast('No se pudo agregar el técnico.'); + } + }); + } + + async confirmRemove(tech: any) { + const alert = await this.alertCtrl.create({ + header: 'Eliminar técnico', + message: ' ', + buttons: [ + { text: 'Cancelar', role: 'cancel' }, + { text: 'Eliminar', role: 'destructive', handler: () => this.removeTechnician(tech.id) } + ] + }); + await alert.present(); + alert.querySelector('.alert-message')!.innerHTML = `¿Estás seguro de eliminar a ${tech.name} de tu equipo?`; + } + + removeTechnician(technicianId: any) { + this.ichambaService.removeTechnician(technicianId).subscribe({ + next: () => { + this.alertService.presentToast('Técnico eliminado'); + this.loadTechnicians(); + }, + error: () => { + this.alertService.presentToast('No se pudo eliminar el técnico.'); + } + }); + } +} diff --git a/src/app/services/alert.service.ts b/src/app/services/alert.service.ts index d6afd0a..bbd59c5 100755 --- a/src/app/services/alert.service.ts +++ b/src/app/services/alert.service.ts @@ -12,7 +12,8 @@ export class AlertService { message: message, duration: 5000, position: 'bottom', - color: 'dark' + color: 'dark', + buttons: [{ icon: 'close', role: 'cancel' }] }); toast.present(); } diff --git a/src/global.scss b/src/global.scss index d70f226..734f4b8 100755 --- a/src/global.scss +++ b/src/global.scss @@ -27,6 +27,106 @@ /* Swiper styles - Swiper 11 uses bundled styles */ +/* Safe area bottom padding for edge-to-edge layout */ +ion-content.ion-padding { + --padding-bottom: env(safe-area-inset-bottom); +} + +ion-footer { + padding-bottom: env(safe-area-inset-bottom); +} + +/* Dark mode overrides para componentes que no heredan --ion-background-color */ +@media (prefers-color-scheme: dark) { + + /* Menú lateral */ + ion-menu ion-content { + --background: #1B1B1B; + } + ion-menu ion-list { + background: #1B1B1B; + } + ion-menu ion-item { + --border-color: #2d2d2d; + --color: #ffffff; + } + + /* Searchbar: .autocomplete sube especificidad a 0,1,1 para ganar a .sc-ion-searchbar-md-h (0,1,0) */ + .autocomplete ion-searchbar { + --background: #2a2a2a; + --color: #ffffff; + --icon-color: #888888; + --cancel-button-color: #888888; + --clear-button-color: #888888; + } + + /* Listboxes de autocomplete: color y borde en dark */ + ion-list ion-item { + --background: transparent; + --color: #ffffff; + --border-color: #808080; + } + + /* Dropdown: borde y sombra en dark */ + .dropdown-list { + border-color: #808080; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6); + } + .dropdown-list ion-item:hover { + --background: #252525; + } + + /* FAQ acordeones: adaptar color="light" hardcodeado al dark theme */ + ion-accordion ion-item { + --ion-color-light: var(--ion-card-background); + --ion-color-light-rgb: 40, 40, 40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255, 255, 255; + --ion-color-light-shade: #161616; + --ion-color-light-tint: #252525; + } + ion-accordion [slot="content"] { + background: var(--ion-background-color); + color: var(--ion-text-color); + } + + /* Welcome card del dashboard: sin fondo */ + .welcome-card { + --background: transparent; + box-shadow: none !important; + } + + /* Texto dentro de ion-card en dark mode */ + ion-card { + color: #ffffff; + } + ion-card ion-card-title, + ion-card ion-card-subtitle, + ion-card ion-card-header, + ion-card ion-card-content { + color: #ffffff; + } + .sc-ion-label-md-s > p { + color: var(--ion-color-step-800, #cccccc); + } +} + +/* Dropdown de autocomplete: fondo sólido adaptable al tema */ +.dropdown-list { + background: var(--ion-background-color, #ffffff); +} + +/* Separador entre ion-item y botón en tarjetas de contrato */ +.no-separator { + --border-color: transparent; + border: 0; +} + +ion-tab-button { + --padding-start: 2px; + --padding-end: 2px; +} + /* Desktop/Web responsive styles */ ion-app { max-width: 100% !important; diff --git a/src/theme/variables.scss b/src/theme/variables.scss index 1ea0090..45031cf 100755 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -11,6 +11,11 @@ } :root { + --ion-safe-area-top: env(safe-area-inset-top, 0px); + --ion-safe-area-bottom: env(safe-area-inset-bottom, 0px); + --ion-safe-area-left: env(safe-area-inset-left, 0px); + --ion-safe-area-right: env(safe-area-inset-right, 0px); + /** primary **/ --ion-color-primary: #0080ff; --ion-color-primary-rgb: 0, 128, 255; @@ -86,3 +91,40 @@ /** social networks **/ --ion-color-facebook: #3b5998; } + +@media (prefers-color-scheme: dark) { + :root { + --ion-background-color: #1B1B1B; + --ion-background-color-rgb: 27, 27, 27; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-item-background: transparent; + --ion-toolbar-background: #111111; + --ion-tab-bar-background: #111111; + --ion-card-background: #252525; + --ion-border-color: #808080; + + --ion-color-step-50: #1a1a1a; + --ion-color-step-100: #1e1e1e; + --ion-color-step-150: #252525; + --ion-color-step-200: #2b2b2b; + --ion-color-step-250: #323232; + --ion-color-step-300: #393939; + --ion-color-step-350: #3f3f3f; + --ion-color-step-400: #464646; + --ion-color-step-500: #545454; + --ion-color-step-600: #616161; + --ion-color-step-700: #6f6f6f; + --ion-color-step-800: #d1d1d1; + --ion-color-step-800: #9e9e9e; + --ion-color-step-850: #b0b0b0; + --ion-color-step-900: #c3c3c3; + --ion-color-step-950: #d6d6d6; + } + + body { + background-color: #1B1B1B; + } +}