diff --git a/.ai/mcp/mcp.json b/.ai/mcp/mcp.json
index e69de29..bb3f251 100644
--- a/.ai/mcp/mcp.json
+++ b/.ai/mcp/mcp.json
@@ -0,0 +1,12 @@
+{
+ "mcpServers": {
+ "angular-cli": {
+ "command": "npx",
+ "args": [
+ "-y",
+ "@angular/cli",
+ "mcp"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.phpactor.json b/.phpactor.json
new file mode 100644
index 0000000..4933b4b
--- /dev/null
+++ b/.phpactor.json
@@ -0,0 +1,3 @@
+{
+ "indexer.exclude_patterns": ["/node_modules/**/*", "/backend/**/*"]
+}
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index f6736f3..3e3354b 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -19,4 +19,9 @@ export const routes: Routes = [
canActivate: [authGuard, roleGuard],
data: { roles: ["admin", "broker"] },
},
+ {
+ path: "checkout",
+ loadChildren: () =>
+ import("./features/checkout/checkout.routes").then((routes) => routes.checkoutRoutes),
+ },
];
diff --git a/src/app/core/guards/auth-guard.ts b/src/app/core/guards/auth-guard.ts
index 8b3e945..5eeaf9c 100644
--- a/src/app/core/guards/auth-guard.ts
+++ b/src/app/core/guards/auth-guard.ts
@@ -1,6 +1,6 @@
import { CanActivateFn, Router } from "@angular/router";
import { inject } from "@angular/core";
-import { AuthService } from "../../features/auth/services/auth-service";
+import { AuthService } from "@core/services/auth-service";
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
diff --git a/src/app/core/guards/role-guard.ts b/src/app/core/guards/role-guard.ts
index dfd7a3c..48d4074 100644
--- a/src/app/core/guards/role-guard.ts
+++ b/src/app/core/guards/role-guard.ts
@@ -1,6 +1,6 @@
import { CanActivateFn } from "@angular/router";
import { inject } from "@angular/core";
-import { AuthService } from "../../features/auth/services/auth-service";
+import { AuthService } from "@core/services/auth-service";
export const roleGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
diff --git a/src/app/core/layouts/header/header.html b/src/app/core/layouts/header/header.html
index 70f585c..ea798f2 100644
--- a/src/app/core/layouts/header/header.html
+++ b/src/app/core/layouts/header/header.html
@@ -20,14 +20,14 @@
+
+
+ Proceed to checkout
+
}
diff --git a/src/app/shared/components/cart/cart.ts b/src/app/shared/components/cart/cart.ts
index 121b0ef..6319fd3 100644
--- a/src/app/shared/components/cart/cart.ts
+++ b/src/app/shared/components/cart/cart.ts
@@ -1,13 +1,14 @@
import { Component, computed, inject, Input, signal } from "@angular/core";
import { CartItemModel, CartItemRequest, CartModel } from "@app/core/models/cart.model";
import { CartItem } from "../cart-item/cart-item";
-import { AuthService, AuthState } from "@app/features/auth/services/auth-service";
+import { AuthService, AuthState } from "@core/services/auth-service";
import { CartService } from "@app/core/services/cart-service";
import { finalize, tap } from "rxjs";
+import { RouterLink } from "@angular/router";
@Component({
selector: "app-cart",
- imports: [CartItem],
+ imports: [CartItem, RouterLink],
templateUrl: "./cart.html",
styleUrl: "./cart.css",
})
diff --git a/src/app/shared/components/go-back/go-back.css b/src/app/shared/components/go-back/go-back.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/shared/components/go-back/go-back.html b/src/app/shared/components/go-back/go-back.html
new file mode 100644
index 0000000..c21331c
--- /dev/null
+++ b/src/app/shared/components/go-back/go-back.html
@@ -0,0 +1,4 @@
+
+
+ {{ text }}
+
diff --git a/src/app/shared/components/go-back/go-back.spec.ts b/src/app/shared/components/go-back/go-back.spec.ts
new file mode 100644
index 0000000..8b2a9b0
--- /dev/null
+++ b/src/app/shared/components/go-back/go-back.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+
+import { GoBack } from "./go-back";
+
+describe("GoBack", () => {
+ let component: GoBack;
+ let fixture: ComponentFixture
;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [GoBack],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(GoBack);
+ component = fixture.componentInstance;
+ await fixture.whenStable();
+ });
+
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/components/go-back/go-back.ts b/src/app/shared/components/go-back/go-back.ts
new file mode 100644
index 0000000..b690ada
--- /dev/null
+++ b/src/app/shared/components/go-back/go-back.ts
@@ -0,0 +1,15 @@
+import { Component, Input } from "@angular/core";
+import { RouterLink } from "@angular/router";
+import { LucideAngularModule, MoveLeft } from "lucide-angular";
+
+@Component({
+ selector: "app-go-back",
+ imports: [RouterLink, LucideAngularModule],
+ templateUrl: "./go-back.html",
+ styleUrl: "./go-back.css",
+})
+export class GoBack {
+ @Input() route: string = "#";
+ @Input() text: string = "";
+ MoveLeftIcon = MoveLeft;
+}
diff --git a/src/app/shared/components/stepper/stepper.css b/src/app/shared/components/stepper/stepper.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/shared/components/stepper/stepper.html b/src/app/shared/components/stepper/stepper.html
new file mode 100644
index 0000000..91b4b16
--- /dev/null
+++ b/src/app/shared/components/stepper/stepper.html
@@ -0,0 +1,29 @@
+
+ @for (step of steps; track step) {
+ -
+
+
+ currentStep"
+ [img]="$index <= currentStep ? CheckIcon : CirecleIcon"
+ class="w-4"
+ />
+
+
+
+ @if (!$last) {
+
= currentStep"
+ class="border w-20"
+ />
+ }
+
+ {{ step.label }}
+
+ }
+
diff --git a/src/app/shared/components/stepper/stepper.spec.ts b/src/app/shared/components/stepper/stepper.spec.ts
new file mode 100644
index 0000000..53af7c4
--- /dev/null
+++ b/src/app/shared/components/stepper/stepper.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+
+import { Stepper } from "./stepper";
+
+describe("Stepper", () => {
+ let component: Stepper;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [Stepper],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(Stepper);
+ component = fixture.componentInstance;
+ await fixture.whenStable();
+ });
+
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/components/stepper/stepper.ts b/src/app/shared/components/stepper/stepper.ts
new file mode 100644
index 0000000..af56031
--- /dev/null
+++ b/src/app/shared/components/stepper/stepper.ts
@@ -0,0 +1,20 @@
+import { Component, Input } from "@angular/core";
+import { Check, Circle, LucideAngularModule } from "lucide-angular";
+
+export type Steps = {
+ label: string;
+};
+
+@Component({
+ selector: "app-stepper",
+ imports: [LucideAngularModule],
+ templateUrl: "./stepper.html",
+ styleUrl: "./stepper.css",
+})
+export class Stepper {
+ @Input() currentStep: number = 0;
+ @Input() steps: Steps[] = [];
+
+ CheckIcon = Check;
+ CirecleIcon = Circle;
+}
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(" "));
+ }
+}
diff --git a/src/styles.css b/src/styles.css
index 0f9fd15..09b81b8 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -13,7 +13,7 @@
}
body {
- @apply bg-gray-100 antialiased m-0;
+ @apply bg-gray-50 antialiased m-0;
}
.wrapper {
@@ -33,11 +33,11 @@ body {
}
.btn-primary {
- @apply text-blue-100 bg-blue-600 border border-b-3 border-blue-900 hover:bg-blue-700;
+ @apply text-blue-100 bg-blue-600 border-b border-b-3 border-blue-900 hover:bg-blue-700;
}
.card {
- @apply bg-gray-50 rounded-xl border border-gray-300 hover:border-gray-400 p-4 hover:shadow-xl transition-all duration-300 ease-in-out;
+ @apply bg-white rounded-xl border-2 border-gray-200 p-4;
}
.fieldset {