diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3d1a308..caaadc5 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -18,11 +18,11 @@ const routes: Routes = [ path: 'pages/:userId', loadChildren: () => import('./pages/pages.module').then((m) => m.PagesModule), - canActivate : [loginGuard] + canActivate: [loginGuard], }, { path: '**', - redirectTo: '/home', + redirectTo: '', }, ]; diff --git a/src/app/app.component.ts b/src/app/app.component.ts index f215c7c..945409f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,39 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { AuthService } from './components/service/auth.service'; +import { NavigationEnd, Router } from '@angular/router'; @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] + styleUrls: ['./app.component.css'], }) -export class AppComponent { +export class AppComponent implements OnInit { title = 'Appliance Care'; + isLoggedIn = false; + + constructor(private authService: AuthService, private router: Router) {} + + ngOnInit(): void { + this.isLoggedIn = this.authService.isLoggedIn(); + + if (this.isLoggedIn) { + this.authService.redirectIfLoggedIn(); + } else { + this.router.navigate(['']); + } + + this.router.events.subscribe((event) => { + if (event instanceof NavigationEnd) { + this.isLoggedIn = this.authService.isLoggedIn(); + if (this.isLoggedIn && event.urlAfterRedirects === '/') { + this.authService.redirectIfLoggedIn(); + } + } + }); + } + + logout(): void { + this.authService.logout(); + this.isLoggedIn = false; + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7c6d99f..4b99dc2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -19,6 +19,7 @@ import { ApplianceRegistrationModule } from './pages/appliance-registration/appl import { AlertConfirmationModule } from './pages/components/alert-confirmation/alert-confirmation.module'; import { ProductModule } from './pages/product/product.module'; import { ModalProductModule } from './pages/components/modal-product/modal-product.module'; +import { PaymentModule } from './pages/payment/payment.module'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http); @@ -33,6 +34,7 @@ export function HttpLoaderFactory(http: HttpClient) { HomeModule, DashboardModule, ProductModule, + PaymentModule, ReactiveFormsModule, HttpClientModule, TranslateModule.forRoot({ diff --git a/src/app/components/guards/login.guard.ts b/src/app/components/guards/login.guard.ts index b032c1c..781607a 100644 --- a/src/app/components/guards/login.guard.ts +++ b/src/app/components/guards/login.guard.ts @@ -1,8 +1,13 @@ +import { Router } from '@angular/router'; +import { inject } from '@angular/core'; + export const loginGuard = () => { + const router = inject(Router); - if ( localStorage.getItem('token')){ - return true; - } else { - return false; - } -} + if (localStorage.getItem('token')) { + return true; + } else { + router.navigate(['auth/login']); + return false; + } +}; diff --git a/src/app/components/service/auth.service.ts b/src/app/components/service/auth.service.ts index 6663256..e3abaaa 100644 --- a/src/app/components/service/auth.service.ts +++ b/src/app/components/service/auth.service.ts @@ -1,5 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { inject, Injectable } from '@angular/core'; +import { Router } from '@angular/router'; import { map, Observable } from 'rxjs'; import { User } from 'src/app/models/user'; import { environment } from 'src/environments/environment'; @@ -12,10 +13,10 @@ export class AuthService { private apiUrlAuthRegister = `${environment.apiUrl}/register`; private apiUrlAuthLogin = `${environment.apiUrl}/login`; - constructor() {} + constructor(private router: Router) {} - register(playload: User): Observable { - return this.httpClient.post(this.apiUrlAuthRegister, playload); + register(payload: User): Observable { + return this.httpClient.post(this.apiUrlAuthRegister, payload); } login(email: string, password: string): Observable { @@ -25,6 +26,7 @@ export class AuthService { map((response) => { if (response && response.token) { localStorage.setItem('token', response.token); + localStorage.setItem('userId', response.user.id.toString()); } return response; }) @@ -33,11 +35,24 @@ export class AuthService { logout() { localStorage.removeItem('token'); - localStorage.removeItem('userName'); - localStorage.removeItem('userLastName'); + localStorage.removeItem('userId'); + this.router.navigate(['auth/login']); } isLoggedIn(): boolean { return !!localStorage.getItem('token'); } + + getUserId(): string | null { + return localStorage.getItem('userId'); + } + + redirectIfLoggedIn() { + const userId = localStorage.getItem('userId'); + if (userId) { + this.router.navigate([`/pages/${userId}/home`]); + } else { + this.router.navigate(['auth/login']); + } + } } diff --git a/src/app/constants/routes.constants.ts b/src/app/constants/routes.constants.ts index 117de20..e2aa545 100644 --- a/src/app/constants/routes.constants.ts +++ b/src/app/constants/routes.constants.ts @@ -5,6 +5,5 @@ export const RoutesConstants = { dashboard: '/pages/:userId/home', form: '/pages/:userId/form', product: '/pages/:userId/product', - root: '/', + payment: '/pages/:userId/payment/:id', }; - diff --git a/src/app/models/payment.ts b/src/app/models/payment.ts new file mode 100644 index 0000000..af219a2 --- /dev/null +++ b/src/app/models/payment.ts @@ -0,0 +1,11 @@ +export interface Payment { + user_id: number; + full_name: string; + email: string; + telephone_number: string; + card_type: string; + card_number: string; + security_code: string; + amount_payable: number; + product_id: number; +} diff --git a/src/app/pages/components/form-product/form-product.component.html b/src/app/pages/components/form-product/form-product.component.html index f5b20fa..1fc0b6e 100644 --- a/src/app/pages/components/form-product/form-product.component.html +++ b/src/app/pages/components/form-product/form-product.component.html @@ -1,23 +1,26 @@
-
-

{{ 'formProduct.CONTACT_US_TITLE' | - translate }}

-

{{ 'formProduct.CONTACT_US_DESCRIPTION' | translate }}

-
- Walnut card tray with white powder coated steel divider and 3 punchout holes. +
+

+ {{ 'formProduct.CONTACT_US_TITLE' | translate }} +

+

+ {{ 'formProduct.CONTACT_US_DESCRIPTION' | translate }} +

+
+ Walnut card tray with white powder coated steel divider and 3 punchout holes. + Top down view of walnut card tray with embedded magnets and card groove. + Side of walnut card tray with card groove and recessed card area. + Walnut card tray filled with cards and card angled in dedicated groove. - Top down view of walnut card tray with embedded magnets and card groove. - Side of walnut card tray with card groove and recessed card area. - Walnut card tray filled with cards and card angled in dedicated groove.
-
+ +

{{ @@ -25,10 +28,10 @@

{{ 'formProduct.APPLICANT_INFO_DESCRIPTION' | translate }}

- -
- +
+
-
{{ - 'formProduct.FIRST_NAME_REQUIRED' | translate }}
-
{{ - 'formProduct.FIRST_NAME_MINLENGTH' | translate }}
-
{{ - 'formProduct.FIRST_NAME_MAXLENGTH' | translate }}
+
+ {{ 'formProduct.FIRST_NAME_REQUIRED' | translate }} +
+
+ {{ 'formProduct.FIRST_NAME_MINLENGTH' | translate }} +
+
+ {{ 'formProduct.FIRST_NAME_MAXLENGTH' | translate }} +
-
- + +
+
-
{{ - 'formProduct.LAST_NAME_REQUIRED' | translate }}
-
{{ - 'formProduct.LAST_NAME_MINLENGTH' | translate }}
-
{{ - 'formProduct.LAST_NAME_MAXLENGTH' | translate }}
+
+ {{ 'formProduct.LAST_NAME_REQUIRED' | translate }} +
+
+ {{ 'formProduct.LAST_NAME_MINLENGTH' | translate }} +
+
+ {{ 'formProduct.LAST_NAME_MAXLENGTH' | translate }} +
-
- + +
+
+ required [class.border-red-500]="isFieldInvalid('email')" + placeholder="{{ 'formProduct.EMAIL_LABEL' | translate }}">
-
{{ - 'formProduct.EMAIL_REQUIRED' | translate }}
-
{{ - 'formProduct.EMAIL_INVALID' | translate }} +
+ {{ 'formProduct.EMAIL_REQUIRED' | translate }} +
+
+ {{ 'formProduct.EMAIL_INVALID' | translate }}
- -
-
-

{{ - 'formProduct.SERVICE_REQUEST_TITLE' | translate }}

-

{{ 'formProduct.SERVICE_REQUEST_DESCRIPTION' | translate }}

-
-
-
-

{{ 'formProduct.APPLIANCE_IMAGE_LABEL' | translate - }} *

-

{{ 'formProduct.APPLIANCE_IMAGE_DESCRIPTION' | translate }}

-
-
- Imagen subida - - -
-
- -
- -

{{ 'formProduct.UPLOAD_FILE_INSTRUCTIONS' | translate }}

-
-

{{ 'formProduct.FILE_FORMATS_ALLOWED' | translate }}

+
+ +
+ +
+
+
+ {{ 'formProduct.ADDRESS_REQUIRED' | translate }}
+
- -
-
{{ - 'formProduct.IMAGE_REQUIRED' | translate }}
+
+ +
+ +
+
+
+ {{ 'formProduct.STATE_REQUIRED' | translate }} +
+
-
- -
- -
-
-
{{ 'formProduct.APPLIANCE_TYPE_REQUIRED' | translate }}
-
+
+ +
+
+
+
{{ + 'formProduct.APPLIANCE_TYPE_REQUIRED' | translate }}
+
+
@@ -196,24 +195,11 @@

{{ 'formProduct.APPLIANC

- -
- -
- -
-
-
{{ - 'formProduct.ADDRESS_REQUIRED' | translate }}
-
-
- +
-
-
{{ 'formProduct.SERVICE_TYPE_REQUIRED' | translate }}
+
+
{{ + 'formProduct.SERVICE_TYPE_REQUIRED' | translate }}
+
@@ -248,22 +237,7 @@

{{ 'formProduct.APPLIANC

-
- -
- -
-
-
{{ - 'formProduct.STATE_REQUIRED' | translate }}
-
-
+
@@ -287,6 +261,54 @@

{{ 'formProduct.APPLIANC

+
+
+

{{ 'formProduct.APPLIANCE_IMAGE_LABEL' | translate + }} *

+

{{ 'formProduct.APPLIANCE_IMAGE_DESCRIPTION' | translate }}

+
+ +
+ Imagen subida + + +
+
+ +
+ +

{{ 'formProduct.UPLOAD_FILE_INSTRUCTIONS' | translate }}

+
+

{{ 'formProduct.FILE_FORMATS_ALLOWED' | translate }}

+
+
+ + +
+
{{ + 'formProduct.IMAGE_REQUIRED' | translate }}
+
+
+
+ +
@@ -305,4 +327,3 @@

{{ 'formProduct.APPLIANC
- diff --git a/src/app/pages/components/header/header.component.html b/src/app/pages/components/header/header.component.html index e9eb4b8..cf8ef5c 100644 --- a/src/app/pages/components/header/header.component.html +++ b/src/app/pages/components/header/header.component.html @@ -17,11 +17,6 @@

- @@ -70,4 +69,3 @@ - diff --git a/src/app/pages/components/menu/menu.component.ts b/src/app/pages/components/menu/menu.component.ts index 9bec36d..a979fec 100644 --- a/src/app/pages/components/menu/menu.component.ts +++ b/src/app/pages/components/menu/menu.component.ts @@ -24,6 +24,7 @@ export class MenuComponent { currentLanguage: 'en' | 'es' = 'es'; languages = LanguageConstants; userId: string | null = localStorage.getItem('userId'); + paymentId: string | undefined; constructor(private translationService: TranslationService) { this.avatar = ImageConstants.avatar; @@ -31,7 +32,7 @@ export class MenuComponent { this.userLastName = localStorage.getItem('userLastName'); } - toggleMenu() : void{ + toggleMenu(): void { this.showMenu = !this.showMenu; } @@ -50,8 +51,8 @@ export class MenuComponent { this.router.navigate(['']); } - changeLanguage(language: 'en' | 'es', event: Event) : void{ - event.preventDefault(); + changeLanguage(language: 'en' | 'es', event: Event): void { + event.preventDefault(); this.translationService.setLanguage(language); this.currentLanguage = language; this.closeMenu(); diff --git a/src/app/pages/components/modal-product/modal-product.component.html b/src/app/pages/components/modal-product/modal-product.component.html index dc02aeb..ae524d3 100644 --- a/src/app/pages/components/modal-product/modal-product.component.html +++ b/src/app/pages/components/modal-product/modal-product.component.html @@ -1,61 +1,77 @@ -
+ -
+
\ No newline at end of file diff --git a/src/app/pages/components/modal-product/modal-product.component.ts b/src/app/pages/components/modal-product/modal-product.component.ts index ab71ce4..63576f8 100644 --- a/src/app/pages/components/modal-product/modal-product.component.ts +++ b/src/app/pages/components/modal-product/modal-product.component.ts @@ -1,14 +1,16 @@ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, inject, OnInit, Output } from '@angular/core'; import { Product } from 'src/app/models/product'; import { ProductModalService } from '../../services/product-modal.service'; import { User } from 'src/app/models/user'; +import { Router } from '@angular/router'; @Component({ selector: 'app-modal-product', templateUrl: './modal-product.component.html', - styleUrls: ['./modal-product.component.css'] + styleUrls: ['./modal-product.component.css'], }) export class ModalProductComponent implements OnInit { + private readonly router: Router = inject(Router); @Output() alertClosed = new EventEmitter(); product: Product | null = null; user: User | null = null; @@ -17,13 +19,10 @@ export class ModalProductComponent implements OnInit { constructor(private productModalService: ProductModalService) {} ngOnInit(): void { - this.productModalService.currentProduct.subscribe(product => { + this.productModalService.currentProduct.subscribe((product) => { this.product = product; - }); - this.productModalService.currentUser.subscribe(user => { - this.user = user; - if (this.user && this.product) { - this.isOpenModal = true; + if (this.product) { + localStorage.setItem('currentProduct', JSON.stringify(this.product)); } }); } @@ -33,4 +32,8 @@ export class ModalProductComponent implements OnInit { this.isOpenModal = false; this.productModalService.closeModal(); } + + navigateToPayment(userId: number, productId: number): void { + this.router.navigate([`/pages/${userId}/payment/${productId}`]); + } } diff --git a/src/app/pages/home/home.component.html b/src/app/pages/home/home.component.html index 699b140..f264ad9 100644 --- a/src/app/pages/home/home.component.html +++ b/src/app/pages/home/home.component.html @@ -133,6 +133,7 @@

Ver detalles diff --git a/src/app/pages/pages-routing.module.ts b/src/app/pages/pages-routing.module.ts index c67a5d0..015b9e2 100644 --- a/src/app/pages/pages-routing.module.ts +++ b/src/app/pages/pages-routing.module.ts @@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { ApplianceRegistrationComponent } from './appliance-registration/appliance-registration.component'; import { ProductComponent } from './product/product.component'; +import { PaymentComponent } from './payment/payment.component'; const routes: Routes = [ { @@ -17,7 +18,10 @@ const routes: Routes = [ path: 'product', component: ProductComponent, }, - + { + path: 'payment/:id', + component: PaymentComponent, + }, ]; @NgModule({ diff --git a/src/app/pages/pages.module.ts b/src/app/pages/pages.module.ts index f191f0a..99c342c 100644 --- a/src/app/pages/pages.module.ts +++ b/src/app/pages/pages.module.ts @@ -5,7 +5,6 @@ import { PagesRoutingModule } from './pages-routing.module'; import { FormProductModule } from './components/form-product/form-product.module'; import { TranslateModule } from '@ngx-translate/core'; -import { ModalProductComponent } from './components/modal-product/modal-product.component'; @NgModule({ declarations: [], diff --git a/src/app/pages/payment/payment.component.css b/src/app/pages/payment/payment.component.css index e69de29..9a20654 100644 --- a/src/app/pages/payment/payment.component.css +++ b/src/app/pages/payment/payment.component.css @@ -0,0 +1,81 @@ +body { + background: linear-gradient(to right, rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)); + margin: 0; + font-family: Arial, sans-serif; +} + + +/* Contenedor de formulario y ticket */ +.flex { + display: flex; + } + + /* Formulario */ + .form-container, .ticket { + padding: 16px; + background: #fff; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + } + + /* Estilos del ticket */ + .ticket { + border: 1px solid #000; + border-radius: 4px; + padding: 16px; + width: 100%; + background-color: #fff; + font-family: 'Courier New', Courier, monospace; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); + } + + .ticket-header { + border-bottom: 2px dashed #000; + padding-bottom: 8px; + margin-bottom: 16px; + } + + .ticket-title { + font-size: 18px; + margin: 0; + text-align: center; + } + + .ticket-date { + font-size: 12px; + color: #666; + text-align: center; + } + + .ticket-body { + margin-bottom: 16px; + } + + .ticket-body p { + margin: 4px 0; + } + + .ticket-footer { + text-align: center; + font-size: 12px; + color: #666; + border-top: 2px dashed #000; + padding-top: 8px; + } + + /* Estilo del contenedor del ticket para centrar y dar margen */ +.ticket-container { + display: flex; + justify-content: center; + align-items: center; + padding: 20px; + border-radius: 12px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + background-color: #ffffff; + max-width: 400px; + margin: auto; +} + + + + diff --git a/src/app/pages/payment/payment.component.html b/src/app/pages/payment/payment.component.html index d9cf5ff..b7cd77c 100644 --- a/src/app/pages/payment/payment.component.html +++ b/src/app/pages/payment/payment.component.html @@ -1 +1,155 @@ -

payment works!

+ + +
+
+ +
+
+
+
+
+

{{ 'contact_sales' | translate }} +

+

{{ 'contact_sales_description' | translate }}

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

{{ 'service_ticket_title' | translate }}

+

{{ 'service_ticket_date' | translate }}

+
+
+

{{ 'client' | translate }}: {{ product?.user?.first_name }} + {{ product?.user?.last_name }}

+

{{ 'email_label' | translate }}: {{ product?.user?.email + }}

+

{{ 'phone' | translate }}: {{ product?.user?.phone_number + }}

+

{{ 'collection_address' | translate }}: {{ + product?.collection_address }}

+

{{ 'service_type' | translate }}: {{ product?.service_type + }}

+

{{ 'problem_details' | translate }}: {{ + product?.problem_details }}

+
+
+

{{ 'payment_ticket_title' | translate }}

+

{{ 'payment_ticket_date' | translate }}: {{ currentDate }}

+
+
+

{{ 'payment_form_full_name' | translate }}: {{ + paymentForm.get('full_name')?.value || 'N/A' }}

+

{{ 'payment_form_email' | translate }}: {{ + paymentForm.get('email')?.value || 'N/A' }}

+

{{ 'payment_form_phone' | translate }}: {{ + paymentForm.get('telephone_number')?.value || 'N/A' }}

+

{{ 'payment_form_card' | translate }}: {{ + paymentForm.get('card_number')?.value || 'N/A' }}

+

{{ 'payment_form_amount' | translate }}: {{ + paymentForm.get('amount_payable')?.value || '0.00' }}

+
+
+

{{ 'thank_you' | translate }}

+
+
+
+
+
+
+ +
+
+ diff --git a/src/app/pages/payment/payment.component.spec.ts b/src/app/pages/payment/payment.component.spec.ts deleted file mode 100644 index 3068378..0000000 --- a/src/app/pages/payment/payment.component.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PaymentComponent } from './payment.component'; - -describe('PaymentComponent', () => { - let component: PaymentComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [PaymentComponent] - }); - fixture = TestBed.createComponent(PaymentComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/pages/payment/payment.component.ts b/src/app/pages/payment/payment.component.ts index 0f3a3af..0a282a7 100644 --- a/src/app/pages/payment/payment.component.ts +++ b/src/app/pages/payment/payment.component.ts @@ -1,10 +1,106 @@ -import { Component } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { PaymentService } from '../services/payment.service'; +import { Payment } from 'src/app/models/payment'; +import { ActivatedRoute } from '@angular/router'; +import { Product } from 'src/app/models/product'; @Component({ selector: 'app-payment', templateUrl: './payment.component.html', - styleUrls: ['./payment.component.css'] + styleUrls: ['./payment.component.css'], }) export class PaymentComponent { + private readonly fb: FormBuilder = inject(FormBuilder); + paymentForm: FormGroup; + userId: number | undefined; + productId: number | undefined; + product: Product | null = null; + currentDate: string = new Date().toLocaleDateString(); + constructor( + private paymentService: PaymentService, + private route: ActivatedRoute + ) { + this.getid(); + this.paymentForm = this.buildForm(); + this.getProductFromLocalStorage(); + + this.paymentForm.valueChanges.subscribe((values) => { + this.updateTicket(); + }); + } + + private buildForm(): FormGroup { + return this.fb.group({ + user_id: [this.userId, Validators.required], + full_name: ['', [Validators.required, Validators.minLength(2)]], + email: ['', [Validators.required, Validators.email]], + telephone_number: [ + '', + [Validators.required, Validators.pattern('^[0-9]{10,15}$')], + ], + card_type: ['', Validators.required], + card_number: [ + '', + [Validators.required, Validators.pattern('^[0-9]{16}$')], + ], + security_code: [ + '', + [Validators.required, Validators.pattern('^[0-9]{3,4}$')], + ], + amount_payable: [ + '', + [Validators.required, Validators.pattern('^[0-9]+(.[0-9]{1,2})?$')], + ], + product_id: [this.productId, Validators.required], + }); + } + + private getProductFromLocalStorage(): void { + const storedProduct = localStorage.getItem('currentProduct'); + if (storedProduct) { + try { + this.product = JSON.parse(storedProduct) as Product; + } catch (error) { + console.error('Error parsing stored product:', error); + } + } + } + + private updateTicket(): void { + this.currentDate = new Date().toLocaleDateString(); + } + + getid() { + return this.route.paramMap.subscribe((params) => { + const userIdParam = params.get('userId'); + const productIdParam = params.get('id'); + + this.userId = userIdParam ? +userIdParam : undefined; + this.productId = productIdParam ? +productIdParam : undefined; + + if (!isNaN(this.userId!) && !isNaN(this.productId!)) { + this.paymentForm.patchValue({ + user_id: this.userId, + product_id: this.productId, + }); + } + }); + } + + onSubmit(): void { + if (this.paymentForm.valid) { + const paymentData: Payment = this.paymentForm.value; + this.paymentService.registerPayment(paymentData).subscribe((response) => { + if (response) { + alert('Pago registrado correctamente'); + } else { + alert('Error al registrar el pago'); + } + }); + } else { + alert('Por favor, completa todos los campos correctamente.'); + } + } } diff --git a/src/app/pages/payment/payment.module.ts b/src/app/pages/payment/payment.module.ts index e5966a0..452e2bb 100644 --- a/src/app/pages/payment/payment.module.ts +++ b/src/app/pages/payment/payment.module.ts @@ -2,13 +2,24 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { PaymentRoutingModule } from './payment-routing.module'; +import { PaymentComponent } from './payment.component'; +import { MenuModule } from '../components/menu/menu.module'; +import { FooterModule } from '../components/footer/footer.module'; +import { TranslateModule } from '@ngx-translate/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { HttpClientModule } from '@angular/common/http'; @NgModule({ - declarations: [], + declarations: [PaymentComponent], imports: [ CommonModule, - PaymentRoutingModule + PaymentRoutingModule, + MenuModule, + FooterModule, + TranslateModule, + ReactiveFormsModule, + HttpClientModule ] }) export class PaymentModule { } diff --git a/src/app/pages/product/product.component.html b/src/app/pages/product/product.component.html index 1b89905..1771846 100644 --- a/src/app/pages/product/product.component.html +++ b/src/app/pages/product/product.component.html @@ -1,6 +1,15 @@
+
+ +
@@ -108,27 +117,32 @@

    -
  • -
    +
  • +
    Appliance image
    -
    -
    -
    -

    - {{ appliance.appliance_type }} -

    -

    {{ appliance.brand }}

    -
    -

    {{ appliance.problem_details }}

    +
    +

    + {{ appliance.appliance_type }} +

    +

    {{ appliance.brand }}

    +

    {{ appliance.problem_details }}

    {{ appliance.application_date }}

    -
    - +
    + +
    @@ -151,9 +165,9 @@

    {{ 'SHOWING_RESULTS' | translate }} - {{ (currentPage - 1) * PaginationConstants.PAGE_SIZE + 1 }} + {{ (currentPage - 1) * 10 + 1 }} {{ 'TO' | translate }} - {{ currentPage * PaginationConstants.PAGE_SIZE }} + {{ currentPage * 10 }} {{ 'OF' | translate }} {{ totalItems }} {{ 'RESULTS' | translate }} @@ -161,9 +175,9 @@

    + +
    + +
    diff --git a/src/app/pages/product/product.component.ts b/src/app/pages/product/product.component.ts index b84b132..8edf32c 100644 --- a/src/app/pages/product/product.component.ts +++ b/src/app/pages/product/product.component.ts @@ -1,11 +1,14 @@ import { Component, inject } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { ApplianceServiceService } from '../services/appliance-service.service'; import { ProductConstants } from 'src/app/constants/product.constants'; import { IconsConstants } from 'src/app/constants/icons.constants'; import { TranslateService } from '@ngx-translate/core'; import { TimeConstants } from 'src/app/constants/time.constants'; import { PaginationConstants } from 'src/app/constants/pagination.constants'; +import { Product } from 'src/app/models/product'; +import { User } from 'src/app/models/user'; +import { ProductModalService } from '../services/product-modal.service'; @Component({ selector: 'app-product', @@ -28,6 +31,8 @@ export class ProductComponent { selectedType: string | null = null; private userId?: number; appliances: any[] = []; + modalProduct: boolean = false; + products: Product[] = []; currentPage: number = this.initialPage; totalPages: number = this.initialTotalPages; @@ -37,7 +42,7 @@ export class ProductComponent { timerMessage: string = ''; timerInterval: any; - constructor(private activatedRoute: ActivatedRoute) { + constructor(private activatedRoute: ActivatedRoute, private router: Router, private productModalService: ProductModalService) { this.initializeUserId(); if (this.userId !== undefined) { this.loadUserAppliances(this.currentPage); @@ -62,6 +67,25 @@ export class ProductComponent { }); } + openProductModal(appliance: Product) { + this.modalProduct = true; + this.productModalService.openModal(appliance); + } + + getUserIdFromRoute(): string { + const urlSegments = window.location.pathname.split('/'); + return urlSegments[urlSegments.indexOf('pages') + 1]; + } + + goToHome(): void { + const userId = this.getUserIdFromRoute(); + this.router.navigate([`/pages/${userId}/home`]); + } + + onAlertClosed() { + this.modalProduct = false; + } + nextPage(): void { if (this.currentPage < this.totalPages) { const nextPage = this.currentPage + 1; diff --git a/src/app/pages/services/payment.service.ts b/src/app/pages/services/payment.service.ts new file mode 100644 index 0000000..0a0dd32 --- /dev/null +++ b/src/app/pages/services/payment.service.ts @@ -0,0 +1,18 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { Payment } from 'src/app/models/payment'; +import { environment } from 'src/environments/environment'; + +@Injectable({ + providedIn: 'root', +}) +export class PaymentService { + private apiUrl = `${environment.apiUrl}/payments`; + + constructor(private http: HttpClient) {} + + registerPayment(cardDetails: Payment): Observable { + return this.http.post(this.apiUrl, cardDetails); + } +} diff --git a/src/app/pages/services/product-modal.service.ts b/src/app/pages/services/product-modal.service.ts index 3f3b9e0..374d264 100644 --- a/src/app/pages/services/product-modal.service.ts +++ b/src/app/pages/services/product-modal.service.ts @@ -14,9 +14,8 @@ export class ProductModalService { currentUser = this.userSource.asObservable(); - openModal(product: Product, user: User): void { + openModal(product: Product): void { this.productSubject.next(product); - this.userSource.next(user); } closeModal(): void { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 56741ed..4b5f6ba 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -106,7 +106,7 @@ }, "formProduct": { "CONTACT_US_TITLE": "Contact Us", - "CONTACT_US_DESCRIPTION": "We want to hear from you. Please fill out the form below, and we will get in touch as soon as possible.", + "CONTACT_US_DESCRIPTION": "Please fill out the form below, and we will get in touch as soon as possible.", "APPLICANT_INFO_TITLE": "Applicant Information", "APPLICANT_INFO_DESCRIPTION": "Please provide your personal details.", "FIRST_NAME_LABEL": "First Name", @@ -234,9 +234,49 @@ "PAY_NOW": "Pay now", "damagedApplianceImageAlt": "Image of the damaged appliance", "applianceTypeAlt": "Type of appliance", - "INVALID_APPLICATION_DATE": "Invalid application date.", + "INVALID_APPLICATION_DATE": "Invalid application date.", "INVALID_SERVICE_TYPE": "Invalid service type.", "SERVICE_COMPLETED": "The repair/maintenance is complete.", "TIMER_FORMAT": "{{days}}d {{hours}}h {{minutes}}m {{seconds}}s", - "DATE_INVALID": "Invalid application date." + "DATE_INVALID": "Invalid application date.", + "contact_sales": "Make a Payment", + "contact_sales_description": "Complete your payment details below to finalize your purchase.", + "card_number": "Card Number", + "card_number_placeholder": "Enter card number", + "card_type": "Card Type", + "card_type_placeholder": "Enter card type", + "security_code": "Security Code (CVV)", + "security_code_placeholder": "CVV", + "full_name": "Full Name", + "full_name_placeholder": "Enter your full name", + "email_placeholder": "Enter your email", + "telephone_number": "Phone Number", + "telephone_number_placeholder": "Enter your phone number", + "amount_payable": "Amount Payable", + "amount_payable_placeholder": "Enter amount", + "privacy_policy": "By selecting this, you agree to our", + "privacy_policy_link": "privacy policy", + "submit_button": "Make Payment", + "service_ticket_title": "Service Ticket - {{appliance_type}}", + "service_ticket_date": "Date: {{application_date}}", + "client": "Client", + "email_label": "Email", + "collection_address": "Collection Address", + "service_type": "Service Type", + "problem_details": "Problem Details", + "damaged_appliance_image": "Damaged Appliance Image", + "payment_ticket_title": "Payment Ticket", + "payment_ticket_date": "Date: {{currentDate}}", + "payment_form_full_name": "Full Name", + "payment_form_email": "Email", + "payment_form_phone": "Phone", + "payment_form_card": "Card", + "payment_form_amount": "Amount to Pay", + "thank_you": "Thank you for your purchase.", + "CARD_TYPE": "Tipo de tarjeta", + "SELECT_CARD_TYPE": "Seleccione el tipo de tarjeta", + "VISA": "Visa", + "MASTERCARD": "MasterCard", + "AMERICAN_EXPRESS": "American Express", + "DISCOVER": "Discover" } diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index fa0a758..9561ce5 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -106,7 +106,7 @@ }, "formProduct": { "CONTACT_US_TITLE": "Contáctenos", - "CONTACT_US_DESCRIPTION": "Queremos saber de usted. Complete el formulario a continuación y nos pondremos en contacto lo antes posible.", + "CONTACT_US_DESCRIPTION": "Complete el formulario a continuación y nos pondremos en contacto lo antes posible.", "APPLICANT_INFO_TITLE": "Información del solicitante", "APPLICANT_INFO_DESCRIPTION": "Por favor, proporciona tus datos personales.", "FIRST_NAME_LABEL": "Nombre", @@ -232,12 +232,51 @@ "email": "Correo Electrónico", "phone": "Teléfono", "address": "Dirección", - "PAY_NOW": "Pagar Ahora", + "PAY_NOW": "Pagar Ahora", "damagedApplianceImageAlt": "Imagen del electrodoméstico dañado", "applianceTypeAlt": "Tipo de electrodoméstico", - "INVALID_APPLICATION_DATE": "Fecha de aplicación no válida.", + "INVALID_APPLICATION_DATE": "Fecha de aplicación no válida.", "INVALID_SERVICE_TYPE": "Tipo de servicio no válido.", "SERVICE_COMPLETED": "La reparación/mantenimiento está completo.", "TIMER_FORMAT": "{{days}}d {{hours}}h {{minutes}}m {{seconds}}s", - "DATE_INVALID": "Fecha de aplicación no válida." + "DATE_INVALID": "Fecha de aplicación no válida.", + "contact_sales": "Realizar Pago", + "contact_sales_description": "Complete los detalles de pago a continuación para finalizar su compra.", + "card_number": "Número de tarjeta", + "card_number_placeholder": "Ingrese el número de tarjeta", + "CARD_TYPE": "Tipo de tarjeta", + "SELECT_CARD_TYPE": "Seleccione el tipo de tarjeta", + "VISA": "Visa", + "MASTERCARD": "MasterCard", + "AMERICAN_EXPRESS": "American Express", + "DISCOVER": "Discover", + "card_type_placeholder": "Ingrese el tipo de tarjeta", + "security_code": "Código de seguridad (CVV)", + "security_code_placeholder": "CVV", + "full_name": "Nombre completo", + "full_name_placeholder": "Ingrese su nombre completo", + "email_placeholder": "Ingrese su email", + "telephone_number": "Número de teléfono", + "telephone_number_placeholder": "Ingrese su número de teléfono", + "amount_payable": "Monto a pagar", + "amount_payable_placeholder": "Ingrese el monto", + "privacy_policy": "Al seleccionar esto, aceptas nuestra", + "privacy_policy_link": "política de privacidad", + "submit_button": "Realizar Pago", + "service_ticket_title": "Ticket de Servicio - {{appliance_type}}", + "service_ticket_date": "Fecha: {{application_date}}", + "client": "Cliente", + "email_label": "Email", + "collection_address": "Dirección de Recolección", + "service_type": "Tipo de Servicio", + "problem_details": "Detalles del Problema", + "damaged_appliance_image": "Imagen del Electrodoméstico Dañado", + "payment_ticket_title": "Ticket de Pago", + "payment_ticket_date": "Fecha", + "payment_form_full_name": "Nombre Completo", + "payment_form_email": "Email", + "payment_form_phone": "Teléfono", + "payment_form_card": "Tarjeta", + "payment_form_amount": "Monto a Pagar", + "thank_you": "Gracias por su compra." }