diff --git a/src/app/features/checkout/address/address.html b/src/app/features/checkout/address/address.html index 6ae9bf5..dadbf33 100644 --- a/src/app/features/checkout/address/address.html +++ b/src/app/features/checkout/address/address.html @@ -3,10 +3,10 @@
- - - - + @for (address of addresses(); track address.id) { + + } +
diff --git a/src/app/features/checkout/address/address.ts b/src/app/features/checkout/address/address.ts index ed76393..56404fd 100644 --- a/src/app/features/checkout/address/address.ts +++ b/src/app/features/checkout/address/address.ts @@ -1,9 +1,16 @@ -import { Component, inject, OnInit } from "@angular/core"; +import { Component, inject, OnInit, signal } from "@angular/core"; import { AddressForm } from "../components/address-form/address-form"; import { GoBack } from "@app/shared/components/go-back/go-back"; import { AddressSelect } from "../components/address-select/address-select"; import { OrderSummery } from "../components/order-summery/order-summery"; -import { AddressService } from "@app/features/checkout/services/address-service"; +import { + AddressRequest, + AddressResponse, + AddressService, +} from "@app/features/checkout/services/address-service"; +import { AuthService } from "@core/services/auth-service"; +import { User } from "@core/models/user.model"; +import { switchMap } from "rxjs"; @Component({ selector: "app-address", @@ -13,6 +20,41 @@ import { AddressService } from "@app/features/checkout/services/address-service" }) export class Address implements OnInit { addressService = inject(AddressService); + authService = inject(AuthService); + private user: User | undefined; + protected addresses = signal([]); - ngOnInit() {} + ngOnInit(): void { + this.authService + .getCurrentUser() + .pipe( + switchMap((user) => { + this.user = user; + if (user?.id) { + return this.addressService.fetchAddresses(user.id); + } + return []; + }), + ) + .subscribe({ + next: (addresses) => { + this.addresses.set(addresses.data); + }, + }); + } + + createNewAddress(addressData: AddressRequest) { + this.addressService.createAddress(this.user!.id, addressData).subscribe({ + next: (address) => this.addresses.update((addresses) => [...addresses, address]), + }); + } + updateAddress(addressData: AddressResponse) { + console.log(addressData); + this.addressService.updateAddress(addressData.id, addressData).subscribe({ + next: (address) => + this.addresses.update((addresses) => + addresses.map((a) => (a.id === address.id ? address : a)), + ), + }); + } } diff --git a/src/app/features/checkout/components/address-form/address-form.html b/src/app/features/checkout/components/address-form/address-form.html index d5a240f..6ac7da9 100644 --- a/src/app/features/checkout/components/address-form/address-form.html +++ b/src/app/features/checkout/components/address-form/address-form.html @@ -1,8 +1,14 @@ -
- - +
+ + -
+
First Name @@ -17,13 +23,8 @@
Street Address - - + +
@@ -43,8 +44,12 @@
- - + +
diff --git a/src/app/features/checkout/components/address-form/address-form.ts b/src/app/features/checkout/components/address-form/address-form.ts index 12e9728..0250074 100644 --- a/src/app/features/checkout/components/address-form/address-form.ts +++ b/src/app/features/checkout/components/address-form/address-form.ts @@ -1,6 +1,7 @@ -import { Component } from "@angular/core"; +import { Component, EventEmitter, Input, Output, signal } from "@angular/core"; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; import { Error } from "@app/shared/components/error/error"; +import { AddressRequest, AddressResponse } from "@app/features/checkout/services/address-service"; @Component({ selector: "app-address-form", @@ -9,12 +10,55 @@ import { Error } from "@app/shared/components/error/error"; styleUrl: "./address-form.css", }) export class AddressForm { + @Input() set initialData(address: AddressResponse) { + if (address) { + this.addressForm.patchValue(address); + this.address.set(address); + this.isEditing.set(true); + } + } + @Output() submitAddress: EventEmitter = new EventEmitter(); + @Output() updateAddress: EventEmitter = new EventEmitter(); + @Output() editingCanceled: EventEmitter = new EventEmitter(); + + protected isEditing = signal(false); + protected address = signal(null); + addressForm = new FormGroup({ - firstName: new FormControl("", { validators: Validators.required }), - lastName: new FormControl("", { validators: Validators.required }), - streetAddress: new FormControl("", { validators: Validators.required }), + firstName: new FormControl("", { + validators: [Validators.required, Validators.pattern("^[a-zA-Z]\\S+$")], + }), + lastName: new FormControl("", { + validators: [Validators.required, Validators.pattern("^[a-zA-Z]\\S+$")], + }), + street: new FormControl("", { validators: Validators.required }), city: new FormControl("", { validators: Validators.required }), state: new FormControl("", { validators: Validators.required }), - pinCode: new FormControl("", { validators: Validators.required }), + pinCode: new FormControl("", { + validators: [Validators.required, Validators.pattern("^[0-9]{6}$")], + }), }); + + submitForm() { + if (this.addressForm.invalid) { + this.addressForm.markAllAsTouched(); + return; + } + + const emittedData = this.addressForm.getRawValue() as AddressRequest; + this.addressForm.reset(); + + if (this.isEditing()) { + const mergedData = { ...this.address(), ...emittedData }; + console.log(mergedData); + this.updateAddress.emit(mergedData as unknown as AddressResponse); + } else { + this.submitAddress.emit(emittedData); + } + } + + cancelEditing() { + this.addressForm.reset(); + this.editingCanceled.emit(); + } } diff --git a/src/app/features/checkout/components/address-select/address-select.html b/src/app/features/checkout/components/address-select/address-select.html index 1fb2a0e..da89163 100644 --- a/src/app/features/checkout/components/address-select/address-select.html +++ b/src/app/features/checkout/components/address-select/address-select.html @@ -1,10 +1,20 @@ +@if (!isEditing()) {
-

Kushal Saha

-

48 St, Park Avenue, New Towm, 700021

+

{{[address.firstName, address.lastName] | fullname}}

+

+ {{`${address.street}, ${address.city}, ${address.pinCode}`}} +

- +
+} @else{ + +} diff --git a/src/app/features/checkout/components/address-select/address-select.ts b/src/app/features/checkout/components/address-select/address-select.ts index 18a7490..64cc7ea 100644 --- a/src/app/features/checkout/components/address-select/address-select.ts +++ b/src/app/features/checkout/components/address-select/address-select.ts @@ -1,9 +1,30 @@ -import { Component } from "@angular/core"; +import { Component, EventEmitter, Input, Output, signal } from "@angular/core"; +import { AddressResponse } from "@app/features/checkout/services/address-service"; +import { FullnamePipe } from "@shared/pipes/fullname-pipe"; +import { AddressForm } from "@app/features/checkout/components/address-form/address-form"; @Component({ selector: "app-address-select", - imports: [], + imports: [FullnamePipe, AddressForm], templateUrl: "./address-select.html", styleUrl: "./address-select.css", }) -export class AddressSelect {} +export class AddressSelect { + @Input() address!: AddressResponse; + @Output() addressUpdated: EventEmitter = new EventEmitter(); + + protected isEditing = signal(false); + + editForm() { + this.isEditing.set(true); + } + + cancelEditing() { + this.isEditing.set(false); + } + + updateAddress(address: AddressResponse) { + this.isEditing.set(false); + this.addressUpdated.emit(address); + } +} diff --git a/src/app/features/checkout/services/address-service.ts b/src/app/features/checkout/services/address-service.ts index 4aacac9..db6001e 100644 --- a/src/app/features/checkout/services/address-service.ts +++ b/src/app/features/checkout/services/address-service.ts @@ -1,6 +1,20 @@ import { inject, Injectable } from "@angular/core"; import { HttpClient } from "@angular/common/http"; import { API_URL } from "@core/tokens/api-url-tokens"; +import { PaginatedResponse } from "@core/models/paginated.model"; + +export interface AddressRequest { + firstName: string; + lastName: string; + street: string; + city: string; + state: string; + pinCode: string; +} + +export interface AddressResponse extends AddressRequest { + id: number; +} @Injectable({ providedIn: "root", @@ -10,6 +24,20 @@ export class AddressService { apiUrl = inject(API_URL); fetchAddresses(userId: number) { - return this.http.get(`${this.apiUrl}/user/${userId}/addresses`); + return this.http.get>( + `${this.apiUrl}/user/${userId}/addresses`, + ); + } + + createAddress(userId: number, data: AddressRequest) { + return this.http.post(`${this.apiUrl}/user/${userId}/addresses`, data); + } + updateAddress(addressId: number, data: AddressRequest) { + return this.http.patch(`${this.apiUrl}/addresses/${addressId}`, data); + } + deleteAddress(userId: number, addressId: number) { + return this.http.delete( + `${this.apiUrl}/user/${userId}/addresses/${addressId}`, + ); } } diff --git a/src/app/shared/pipes/fullname-pipe.spec.ts b/src/app/shared/pipes/fullname-pipe.spec.ts new file mode 100644 index 0000000..8032c7e --- /dev/null +++ b/src/app/shared/pipes/fullname-pipe.spec.ts @@ -0,0 +1,8 @@ +import { FullnamePipe } from "./fullname-pipe"; + +describe("FullnamePipe", () => { + it("create an instance", () => { + const pipe = new FullnamePipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/shared/pipes/fullname-pipe.ts b/src/app/shared/pipes/fullname-pipe.ts new file mode 100644 index 0000000..ff153bd --- /dev/null +++ b/src/app/shared/pipes/fullname-pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { TitleCasePipe } from "@angular/common"; + +@Pipe({ + name: "fullname", +}) +export class FullnamePipe implements PipeTransform { + titlecase = new TitleCasePipe(); + + transform(values: string[]): unknown { + return this.titlecase.transform(values.join(" ")); + } +}