+
+ @if (currentStepNumber() < 3) {
@@ -29,7 +30,11 @@
Please select an address
- }
+ } @if (paymentMethodControl.invalid && paymentMethodControl.touched) {
+
+ Please select an payment checkout
+
+ } @if (currentStepNumber() === 1) {
+ } @if (currentStepNumber() === 2) {
+
+ }
+ }
diff --git a/src/app/features/checkout/checkout.routes.ts b/src/app/features/checkout/checkout.routes.ts
index 4e28c7e..35e4410 100644
--- a/src/app/features/checkout/checkout.routes.ts
+++ b/src/app/features/checkout/checkout.routes.ts
@@ -2,6 +2,7 @@ import { Routes } from "@angular/router";
import { Address } from "./address/address";
import { Checkout } from "./checkout";
import { Payment } from "@app/features/checkout/payment/payment";
+import Confirmation from "@app/features/checkout/confirmation/confirmation";
export const checkoutRoutes: Routes = [
{
@@ -16,6 +17,10 @@ export const checkoutRoutes: Routes = [
path: "payment",
component: Payment,
},
+ {
+ path: "confirmation",
+ component: Confirmation,
+ },
],
},
];
diff --git a/src/app/features/checkout/checkout.ts b/src/app/features/checkout/checkout.ts
index 872bd9a..638ca85 100644
--- a/src/app/features/checkout/checkout.ts
+++ b/src/app/features/checkout/checkout.ts
@@ -5,7 +5,7 @@ import { OrderSummery } from "@app/features/checkout/components/order-summery/or
import { GoBack } from "@shared/components/go-back/go-back";
import { AddressService } from "@app/features/checkout/services/address-service";
import { LoadingSpinner } from "@shared/components/loading-spinner/loading-spinner";
-import { OrderService } from "@app/features/checkout/services/order-service";
+import { CheckoutResponse, OrderService } from "@app/features/checkout/services/order-service";
import { CartService } from "@core/services/cart-service";
import { CartModel } from "@core/models/cart.model";
import { takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop";
@@ -23,17 +23,21 @@ export class Checkout implements OnInit {
{ label: "Cart", route: "" },
{ label: "Address", route: "/checkout/address" },
{ label: "Payment", route: "/checkout/payment" },
- { label: "Confirm", route: "/checkout/address" },
+ { label: "Confirmation", route: "/checkout/confirmation" },
];
destroyRef = inject(DestroyRef);
orderCreationLoading = signal(false);
+ proceedToPaymentLoading = signal(false);
+
private addressService = inject(AddressService);
addressIdControl = this.addressService.addressIdControl;
+
private orderService = inject(OrderService);
+ paymentMethodControl = this.orderService.paymentMethodForm;
+
private cartService = inject(CartService);
private cart: CartModel | undefined;
private router = inject(Router);
-
protected currentStepNumber = toSignal(
this.router.events.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd), // Added TS type guard
@@ -74,4 +78,32 @@ export class Checkout implements OnInit {
await this.router.navigate(["/checkout/payment"]);
});
}
+
+ protected proceedToCheckout() {
+ if (this.paymentMethodControl.invalid) {
+ this.paymentMethodControl.markAsTouched();
+ return;
+ }
+ this.proceedToPaymentLoading.set(true);
+ this.orderService
+ .checkout(this.paymentMethodControl.value!)
+ .pipe(
+ takeUntilDestroyed(this.destroyRef),
+ finalize(() => this.proceedToPaymentLoading.set(false)),
+ )
+ .subscribe((response) => this.handleCheckout(response));
+ }
+ private handleCheckout(data: CheckoutResponse): void {
+ if (data.success) {
+ if (data.method === "stripeCheckout") {
+ this.handleStripeCheckout(data);
+ }
+ }
+ }
+ private handleStripeCheckout(data: CheckoutResponse) {
+ console.log(data);
+ if (data.redirectUrl) {
+ window.location.href = data.redirectUrl;
+ }
+ }
}
diff --git a/src/app/features/checkout/components/payment-method-card/payment-method-card.css b/src/app/features/checkout/components/payment-method-card/payment-method-card.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/features/checkout/components/payment-method-card/payment-method-card.html b/src/app/features/checkout/components/payment-method-card/payment-method-card.html
new file mode 100644
index 0000000..497ba7f
--- /dev/null
+++ b/src/app/features/checkout/components/payment-method-card/payment-method-card.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/app/features/checkout/components/payment-method-card/payment-method-card.spec.ts b/src/app/features/checkout/components/payment-method-card/payment-method-card.spec.ts
new file mode 100644
index 0000000..8c4484b
--- /dev/null
+++ b/src/app/features/checkout/components/payment-method-card/payment-method-card.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+
+import { PaymentMethodCard } from "./payment-method-card";
+
+describe("PaymentMethodCard", () => {
+ let component: PaymentMethodCard;
+ let fixture: ComponentFixture
;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [PaymentMethodCard],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(PaymentMethodCard);
+ component = fixture.componentInstance;
+ await fixture.whenStable();
+ });
+
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/features/checkout/components/payment-method-card/payment-method-card.ts b/src/app/features/checkout/components/payment-method-card/payment-method-card.ts
new file mode 100644
index 0000000..0e71055
--- /dev/null
+++ b/src/app/features/checkout/components/payment-method-card/payment-method-card.ts
@@ -0,0 +1,9 @@
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-payment-method-card",
+ imports: [],
+ templateUrl: "./payment-method-card.html",
+ styleUrl: "./payment-method-card.css",
+})
+export class PaymentMethodCard {}
diff --git a/src/app/features/checkout/confirmation/confirmation.css b/src/app/features/checkout/confirmation/confirmation.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/features/checkout/confirmation/confirmation.html b/src/app/features/checkout/confirmation/confirmation.html
new file mode 100644
index 0000000..a674b5a
--- /dev/null
+++ b/src/app/features/checkout/confirmation/confirmation.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
Payment Successful
+
+ Your payment processed successfully. You will receive a confirmation email shortly.
+
+
+
+ Amount
+ Rs. 20000
+
+
+
+ Transaction ID
+ text_ch_989789y789jhhg8h8
+
+
+ Payment method
+ Stripe Checkout
+
+
+
+
+
diff --git a/src/app/features/checkout/confirmation/confirmation.spec.ts b/src/app/features/checkout/confirmation/confirmation.spec.ts
new file mode 100644
index 0000000..300fde9
--- /dev/null
+++ b/src/app/features/checkout/confirmation/confirmation.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+
+import Confirmation from "./confirmation";
+
+describe("Confirmation", () => {
+ let component: Confirmation;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [Confirmation],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(Confirmation);
+ component = fixture.componentInstance;
+ await fixture.whenStable();
+ });
+
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/features/checkout/confirmation/confirmation.ts b/src/app/features/checkout/confirmation/confirmation.ts
new file mode 100644
index 0000000..c40bc1b
--- /dev/null
+++ b/src/app/features/checkout/confirmation/confirmation.ts
@@ -0,0 +1,24 @@
+import { Component, inject } from "@angular/core";
+import { BadgeCheck, LucideAngularModule } from "lucide-angular";
+import { GoBack } from "@shared/components/go-back/go-back";
+import { ActivatedRoute } from "@angular/router";
+
+@Component({
+ selector: "app-confirmation",
+ imports: [LucideAngularModule, GoBack],
+ templateUrl: "./confirmation.html",
+ styleUrl: "./confirmation.css",
+})
+class Confirmation {
+ protected readonly BadgeCheck = BadgeCheck;
+ private route = inject(ActivatedRoute);
+ private orderId: string | null = null;
+ private sessionId: string | null = null;
+
+ ngOnInit() {
+ this.orderId = this.route.snapshot.paramMap.get("order_id");
+ this.sessionId = this.route.snapshot.paramMap.get("session_id");
+ }
+}
+
+export default Confirmation;
diff --git a/src/app/features/checkout/payment/payment.html b/src/app/features/checkout/payment/payment.html
index d9cf5ff..5e1234a 100644
--- a/src/app/features/checkout/payment/payment.html
+++ b/src/app/features/checkout/payment/payment.html
@@ -1 +1,51 @@
-payment works!
+
+
+
+
+
+
+
Pay using card via stripe checkout.
+
+
+
+
+
+
+
+
+
Additional charges may apply.
+
+
+
+
diff --git a/src/app/features/checkout/payment/payment.ts b/src/app/features/checkout/payment/payment.ts
index 6f8e9a7..3b1cde2 100644
--- a/src/app/features/checkout/payment/payment.ts
+++ b/src/app/features/checkout/payment/payment.ts
@@ -1,9 +1,28 @@
-import { Component } from "@angular/core";
+import { Component, inject, OnInit } from "@angular/core";
+import { PaymentMethodCard } from "@app/features/checkout/components/payment-method-card/payment-method-card";
+import { Coins, LucideAngularModule } from "lucide-angular";
+import { ReactiveFormsModule } from "@angular/forms";
+import { OrderService } from "@app/features/checkout/services/order-service";
+import { ActivatedRoute } from "@angular/router";
@Component({
selector: "app-payment",
- imports: [],
+ imports: [PaymentMethodCard, LucideAngularModule, ReactiveFormsModule],
templateUrl: "./payment.html",
styleUrl: "./payment.css",
})
-export class Payment {}
+export class Payment implements OnInit {
+ coinsIcon = Coins;
+ private orderService = inject(OrderService);
+ protected paymentMethodForm = this.orderService.paymentMethodForm;
+ private route = inject(ActivatedRoute);
+ private orderId: string | null = null;
+
+ ngOnInit() {
+ this.orderId = this.route.snapshot.paramMap.get("order_id");
+ }
+
+ onPaymentMethodSelected(paymentMethod: string) {
+ this.paymentMethodForm.setValue(paymentMethod);
+ }
+}
diff --git a/src/app/features/checkout/services/order-service.ts b/src/app/features/checkout/services/order-service.ts
index 0503fe6..8e8084f 100644
--- a/src/app/features/checkout/services/order-service.ts
+++ b/src/app/features/checkout/services/order-service.ts
@@ -2,22 +2,63 @@ import { inject, Injectable } from "@angular/core";
import { API_URL } from "@core/tokens/api-url-tokens";
import { HttpClient } from "@angular/common/http";
import { AuthService } from "@core/services/auth-service";
+import { FormControl, Validators } from "@angular/forms";
+import { tap } from "rxjs";
+import { SessionStorageService } from "@core/services/session-storage.service";
+export interface CheckoutResponse {
+ success: boolean;
+ amount: number;
+ currency: string;
+ method: string;
+ redirectUrl: string | null;
+ errorMessage: string | null;
+}
export interface OrderRequest {
addressId: number;
cartId: number;
}
+export interface OrderResponse {
+ orderId: number;
+ message: string;
+}
@Injectable({
providedIn: "root",
})
export class OrderService {
- http = inject(HttpClient);
- apiUrl = inject(API_URL);
+ public paymentMethodForm = new FormControl(null, Validators.required);
+ private currentOrderId: number | null = null;
+ private http = inject(HttpClient);
+ private apiUrl = inject(API_URL);
private authService = inject(AuthService);
private user = this.authService.user;
+ private sessionStorage = inject(SessionStorageService);
+
+ constructor() {
+ const cachedOrderId = this.sessionStorage.getItem("orderId");
+ if (cachedOrderId) {
+ this.currentOrderId = cachedOrderId;
+ }
+ }
createOrder(data: OrderRequest) {
- return this.http.post(`${this.apiUrl}/users/${this.user()?.id}/orders`, data);
+ return this.http
+ .post(`${this.apiUrl}/users/${this.user()?.id}/orders`, data)
+ .pipe(
+ tap((response) => {
+ this.currentOrderId = response.orderId;
+ this.sessionStorage.setItem("orderId", response.orderId);
+ }),
+ );
+ }
+
+ checkout(mode: string) {
+ return this.http.post(
+ `${this.apiUrl}/orders/${this.currentOrderId}/payments`,
+ {
+ mode: mode,
+ },
+ );
}
}
diff --git a/src/app/shared/components/go-back/go-back.html b/src/app/shared/components/go-back/go-back.html
index 4522e3f..f6819fc 100644
--- a/src/app/shared/components/go-back/go-back.html
+++ b/src/app/shared/components/go-back/go-back.html
@@ -1,4 +1,4 @@
-
+
{{ text }}
diff --git a/src/app/shared/components/stepper/stepper.html b/src/app/shared/components/stepper/stepper.html
index 2ac2146..3d06a73 100644
--- a/src/app/shared/components/stepper/stepper.html
+++ b/src/app/shared/components/stepper/stepper.html
@@ -3,14 +3,14 @@