From ba1c59b04ceb5bfc939fb305cb7523e2fbe9c8e8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Mar 2026 14:17:52 +0000
Subject: [PATCH 1/3] Initial plan
From cca853261b5c5e8818d06c52e2f3f6ee73363e7e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Mar 2026 14:29:00 +0000
Subject: [PATCH 2/3] Implement shopping cart with persistent storage and
checkout integration
Co-authored-by: webmaxru <1560278+webmaxru@users.noreply.github.com>
---
frontend/src/App.tsx | 7 +-
frontend/src/components/Navigation.tsx | 27 +++
frontend/src/components/entity/Cart.tsx | 210 ++++++++++++++++++
.../components/entity/product/Products.tsx | 21 +-
frontend/src/context/CartContext.tsx | 90 ++++++++
5 files changed, 348 insertions(+), 7 deletions(-)
create mode 100644 frontend/src/components/entity/Cart.tsx
create mode 100644 frontend/src/context/CartContext.tsx
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 29b9f53..bf0bcca 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -4,9 +4,11 @@ import Welcome from './components/Welcome';
import About from './components/About';
import Footer from './components/Footer';
import Products from './components/entity/product/Products';
+import Cart from './components/entity/Cart';
import Login from './components/Login';
import { AuthProvider } from './context/AuthContext';
import { ThemeProvider } from './context/ThemeContext';
+import { CartProvider } from './context/CartContext';
import AdminProducts from './components/admin/AdminProducts';
import { useTheme } from './context/ThemeContext';
@@ -25,6 +27,7 @@ function ThemedApp() {
} />
} />
} />
+ } />
} />
} />
@@ -39,7 +42,9 @@ function App() {
return (
-
+
+
+
);
diff --git a/frontend/src/components/Navigation.tsx b/frontend/src/components/Navigation.tsx
index 5f35e12..f38acf3 100644
--- a/frontend/src/components/Navigation.tsx
+++ b/frontend/src/components/Navigation.tsx
@@ -1,11 +1,13 @@
import { Link } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { useTheme } from '../context/ThemeContext';
+import { useCart } from '../context/CartContext';
import { useState } from 'react';
export default function Navigation() {
const { isLoggedIn, isAdmin, logout } = useAuth();
const { darkMode, toggleTheme } = useTheme();
+ const { totalItems } = useCart();
const [adminMenuOpen, setAdminMenuOpen] = useState(false);
return (
@@ -85,6 +87,31 @@ export default function Navigation() {
+
+
+ {totalItems > 0 && (
+
+ {totalItems}
+
+ )}
+
handleAddToCart(product.productId)}
+ onClick={() => handleAddToCart(product)}
className={`px-4 py-2 rounded-lg transition-colors ${
quantities[product.productId]
? 'bg-primary hover:bg-accent text-white'
diff --git a/frontend/src/context/CartContext.tsx b/frontend/src/context/CartContext.tsx
new file mode 100644
index 0000000..44c0424
--- /dev/null
+++ b/frontend/src/context/CartContext.tsx
@@ -0,0 +1,90 @@
+import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
+
+export interface CartItem {
+ productId: number;
+ name: string;
+ price: number;
+ quantity: number;
+ discount?: number;
+}
+
+export function effectivePrice(item: Pick): number {
+ return item.discount ? item.price * (1 - item.discount) : item.price;
+}
+
+interface CartContextType {
+ items: CartItem[];
+ addToCart: (item: Omit, quantity: number) => void;
+ updateQuantity: (productId: number, quantity: number) => void;
+ removeFromCart: (productId: number) => void;
+ clearCart: () => void;
+ totalItems: number;
+ totalPrice: number;
+}
+
+const CartContext = createContext(null);
+
+const CART_STORAGE_KEY = 'octocat_cart';
+
+export function CartProvider({ children }: { children: ReactNode }) {
+ const [items, setItems] = useState(() => {
+ try {
+ const saved = localStorage.getItem(CART_STORAGE_KEY);
+ return saved ? (JSON.parse(saved) as CartItem[]) : [];
+ } catch {
+ return [];
+ }
+ });
+
+ useEffect(() => {
+ localStorage.setItem(CART_STORAGE_KEY, JSON.stringify(items));
+ }, [items]);
+
+ const addToCart = (item: Omit, quantity: number) => {
+ setItems((prev) => {
+ const existing = prev.find((i) => i.productId === item.productId);
+ if (existing) {
+ return prev.map((i) =>
+ i.productId === item.productId ? { ...i, quantity: i.quantity + quantity } : i,
+ );
+ }
+ return [...prev, { ...item, quantity }];
+ });
+ };
+
+ const updateQuantity = (productId: number, quantity: number) => {
+ setItems((prev) =>
+ quantity <= 0
+ ? prev.filter((i) => i.productId !== productId)
+ : prev.map((i) => (i.productId === productId ? { ...i, quantity } : i)),
+ );
+ };
+
+ const removeFromCart = (productId: number) => {
+ setItems((prev) => prev.filter((i) => i.productId !== productId));
+ };
+
+ const clearCart = () => setItems([]);
+
+ const totalItems = items.reduce((sum, i) => sum + i.quantity, 0);
+ const totalPrice = items.reduce((sum, i) => {
+ return sum + effectivePrice(i) * i.quantity;
+ }, 0);
+
+ return (
+
+ {children}
+
+ );
+}
+
+// eslint-disable-next-line react-refresh/only-export-components
+export function useCart() {
+ const context = useContext(CartContext);
+ if (!context) {
+ throw new Error('useCart must be used within a CartProvider');
+ }
+ return context;
+}
From 07173b58a6032cb9969c8fe10d4aa108cc800768 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Mar 2026 15:03:15 +0000
Subject: [PATCH 3/3] Co-authored-by: webmaxru
<1560278+webmaxru@users.noreply.github.com>
---
api/nohup.out | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 api/nohup.out
diff --git a/api/nohup.out b/api/nohup.out
new file mode 100644
index 0000000..67db272
--- /dev/null
+++ b/api/nohup.out
@@ -0,0 +1,13 @@
+Configured CORS origins: [
+ 'http://localhost:5137',
+ 'http://localhost:3001',
+ /^https:\/\/.*\.app\.github\.dev$/
+]
+π Initializing database...
+π Initializing database...
+π Starting database migration...
+β
No pending migrations. Database is up to date.
+β
Database initialization complete!
+β
Database initialized successfully
+Server is running on port 3000
+API documentation is available at http://localhost:3000/api-docs