diff --git a/src/pages/shop.js b/src/pages/shop.js index ad2e3e6..d785a58 100644 --- a/src/pages/shop.js +++ b/src/pages/shop.js @@ -1,269 +1,41 @@ import React, { useState, useEffect } from "react"; -import styled from "styled-components"; import Layout from "../layouts"; import { useTranslation } from "react-i18next"; import BG from "../components/bg"; import SEO from "../components/seo"; import "../i18n"; -const PopupProducts = styled.div` - background: white; - padding: 2rem; - border-radius: 16px; - width: 100%; - overflow-y: auto; - text-align: center; - color: black; - - @media (max-width: 640px) { - padding: 0px; - } -`; - -const Popup = styled.div` - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background: white; - padding: 2rem; - border-radius: 16px; - // box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25); - width: 100%; - max-width: 1400px; - max-height: 65vh; - overflow-y: auto; - text-align: center; - color: black; - @media (max-width: 640px) { - padding: 0px; - } -`; - -const Input = styled.input` - width: 100%; - padding: 12px 14px; - margin: 0.3rem 0; - border: 2px solid #ddd; - border-radius: 10px; - font-size: 1rem; - outline: none; - transition: all 0.25s ease; - - &:focus { - border-color: #3498db; - box-shadow: 0 0 8px rgba(52, 152, 219, 0.4); - transform: scale(1.02); - } -`; - -const Button = styled.button` - margin: 1rem auto 0; - width: 200px; - border: none; - border-radius: 10px; - font-size: 1rem; - background: linear-gradient(135deg, rgb(23, 130, 253), rgb(97, 171, 255)); - color: white; - - font-weight: bold; - cursor: pointer; - transition: all 0.3s ease; - display: block; - - &:hover { - transform: translateY(-2px) scale(1.02); - box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); - } - - &:disabled { - background: #aaa; - cursor: not-allowed; - transform: none; - box-shadow: none; - } -`; - -const Spinner = styled.div` - margin: 1rem auto; - border: 4px solid #eee; - border-top: 4px solid #3498db; - border-radius: 50%; - width: 32px; - height: 32px; - animation: spin 1s linear infinite; - - @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } - } -`; - -const ErrorMsg = styled.p` - color: red; - margin: 0.2rem 0; - font-size: 0.9rem; - animation: fadeIn 0.3s ease; - - @keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } - } -`; - -const Table = styled.table` - width: 100%; - border-collapse: collapse; - margin-top: 1rem; -`; - -const Th = styled.th` - background: #3498db; - color: white; - padding: 10px; - - &:first-child { - padding-left: 16px; - } -`; - -const Td = styled.td` - overflow: hidden; - white-space: preserve nowrap; - border: 1px solid #ddd; - padding: 8px; - text-align: left; - - &:first-child { - padding-left: 16px; - } -`; - -const ProductsColumn = styled.div` - flex: 3; - overflow-y: auto; -`; - -const OrderColumn = styled.div` - flex: 3; - overflow-y: auto; -`; - -const CategoriesColumn = styled.div` - padding-top: 20px; - flex: 1; - // border-left: 1px solid #ddd; - // padding-left: 1rem; - max-height: 70vh; - overflow-y: auto; - text-align: left; -`; - -const CartPopup = styled.div` - color: black; - position: fixed; - top: 0; - right: 0; - width: 600px; - max-width: 90%; - height: 100vh; - background: white; - // border-left: 2px solid #ddd; - padding: 2rem; - overflow-y: auto; - box-shadow: -8px 0 30px rgba(0, 0, 0, 0.2); - animation: slideIn 0.3s ease; - z-index: 1000; - - @keyframes slideIn { - from { - transform: translateX(100%); - } - to { - transform: translateX(0%); - } - } -`; - -const ProductGrid = styled.div` - display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - gap: 1rem; - margin-top: 1rem; -`; - -const ProductCard = styled.div` - background: #fff; - border: 2px solid ${(props) => (props.selected ? "#2ecc71" : "white")}; - border-radius: 12px; - padding: 1rem; - text-align: center; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06); - transition: transform 0.2s, border-color 0.2s; - - &:hover { - cursor: pointer; - } -`; - -const ProductPrice = styled.div` - font-weight: bold; - margin: 0.25rem 0; - color: #2ecc71; -`; - -const ProductImage = styled.img` - width: 100%; - height: 200px; - object-fit: cover; - border-radius: 10px; -`; - -const ProductTitle = styled.h4` - font-size: 1rem; - margin: 0.5rem 0; -`; - -const ProductDescription = styled.p` - font-size: 0.9rem; - color: #666; - min-height: 3em; -`; - -const ProductCheckbox = styled.input` - margin-top: 0.5rem; - transform: scale(1.3); - cursor: pointer; -`; +import LoginPopup from "../shop/LoginPopup"; +import CartPopup from "../shop/CartPopup"; +import ProductsPopup from "../shop/ProductsPopup"; +import OrdersPopup from "../shop/OrdersPopup"; +import { Button, Popup } from "../shop/styled"; const Shop = (props) => { const { t, i18n } = useTranslation(); const lang = i18n.language; + const [email, setEmail] = useState("anna@posdemo.pl"); const [password, setPassword] = useState("test1234"); const [loggedInEmail, setLoggedInEmail] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [validationError, setValidationError] = useState(""); + const [showOrders, setShowOrders] = useState(false); const [orders, setOrders] = useState([]); const [ordersLoading, setOrdersLoading] = useState(false); const [ordersError, setOrdersError] = useState(""); + const [localProducts, setLocalProducts] = useState([]); const [productsLoading, setProductsLoading] = useState(false); const [productsError, setProductsError] = useState(""); const [showProducts, setShowProducts] = useState(false); const [selectedCategories, setSelectedCategories] = useState([]); const categories = [...new Set(localProducts.map((p) => p.category))]; + const [timeLeft, setTimeLeft] = useState(null); + const [cart, setCart] = useState([]); const [showCart, setShowCart] = useState(false); const [placingOrder, setPlacingOrder] = useState(false); @@ -275,115 +47,26 @@ const Shop = (props) => { if (expiry) { const now = Date.now(); const diff = Math.floor((expiry - now) / 1000); - if (diff > 0) { - setTimeLeft(diff); - } else { - handleLogout(); - } + if (diff > 0) setTimeLeft(diff); + else handleLogout(); } }, []); useEffect(() => { if (timeLeft === null) return; - if (timeLeft <= 0) { handleLogout(); return; } - - const timerId = setInterval(() => { - setTimeLeft((prev) => prev - 1); - }, 1000); - + const timerId = setInterval(() => setTimeLeft((prev) => prev - 1), 1000); return () => clearInterval(timerId); }, [timeLeft]); useEffect(() => { const storedEmail = localStorage.getItem("email"); - if (storedEmail) { - setLoggedInEmail(storedEmail); - } + if (storedEmail) setLoggedInEmail(storedEmail); }, []); - const placeOrder = async () => { - if (cart.length === 0) return; - - setPlacingOrder(true); - setOrderError(""); - setOrderSuccess(false); - - const token = localStorage.getItem("token"); - - const orderData = { - customer: loggedInEmail, - total: totalPrice, - items: cart.map((item) => ({ - product_id: item.id, - quantity: item.quantity, - })), - }; - - try { - const res = await fetch( - "https://pos-backend-kso1.onrender.com/api/orders", - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify(orderData), - } - ); - - if (!res.ok) { - const errorData = await res.json(); - throw new Error(errorData.message || "Błąd składania zamówienia"); - } - - setOrderSuccess(true); - setCart([]); - } catch (err) { - setOrderError(err.message); - } finally { - setPlacingOrder(false); - } - }; - - const updateQuantity = (productId, newQuantity) => { - if (newQuantity < 1) return; - - setCart((prev) => - prev.map((item) => - item.id === productId ? { ...item, quantity: newQuantity } : item - ) - ); - }; - - const toggleProductInCart = (product) => { - setCart((prev) => { - const exists = prev.find((p) => p.id === product.id); - if (exists) { - return prev.filter((p) => p.id !== product.id); - } else { - return [...prev, { ...product, quantity: 1 }]; - } - }); - }; - - const filteredProducts = - selectedCategories.length === 0 - ? localProducts - : localProducts.filter((p) => selectedCategories.includes(p.category)); - - const toggleCategory = (category) => { - setSelectedCategories((prev) => - prev.includes(category) - ? prev.filter((c) => c !== category) - : [...prev, category] - ); - }; - const validateForm = () => { if (!email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) { setValidationError("Podaj poprawny adres email"); @@ -397,45 +80,12 @@ const Shop = (props) => { return true; }; - const fetchLocalProducts = async () => { - setProductsLoading(true); - setProductsError(""); - const token = localStorage.getItem("token"); - - try { - const res = await fetch( - "https://pos-backend-kso1.onrender.com/api/products/local", - { - headers: { Authorization: `Bearer ${token}` }, - } - ); - - if (!res.ok) throw new Error("Błąd pobierania produktów"); - - const data = await res.json(); - setLocalProducts(data); - } catch (err) { - setProductsError(err.message); - } finally { - setProductsLoading(false); - } - }; - - const openProductsPopup = () => { - setShowProducts(true); - fetchLocalProducts(); - }; - - const closeProductsPopup = () => { - setShowProducts(false); - setShowOrders(false); - }; - const handleLogin = async () => { if (!validateForm()) return; setLoading(true); setError(""); + try { const res = await fetch( "https://pos-backend-kso1.onrender.com/api/auth/login", @@ -445,22 +95,17 @@ const Shop = (props) => { body: JSON.stringify({ email, password }), } ); - if (!res.ok) { const errData = await res.json(); throw new Error(errData.message || "Błąd logowania"); } - const data = await res.json(); localStorage.setItem("token", data.token); localStorage.setItem("email", email); - - const expiryTimestamp = Date.now() + 60 * 60 * 1000; - localStorage.setItem("tokenExpiry", expiryTimestamp); + localStorage.setItem("tokenExpiry", Date.now() + 60 * 60 * 1000); setLoggedInEmail(email); setTimeLeft(60 * 60); - openProductsPopup(); } catch (err) { setError(err.message); @@ -483,29 +128,118 @@ const Shop = (props) => { setTimeLeft(null); }; - const formatTime = (seconds) => { - const m = Math.floor(seconds / 60) - .toString() - .padStart(2, "0"); - const s = (seconds % 60).toString().padStart(2, "0"); - return `${m}:${s}`; + const fetchLocalProducts = async () => { + setProductsLoading(true); + setProductsError(""); + const token = localStorage.getItem("token"); + + try { + const res = await fetch( + "https://pos-backend-kso1.onrender.com/api/products/local", + { headers: { Authorization: `Bearer ${token}` } } + ); + if (!res.ok) throw new Error("Błąd pobierania produktów"); + const data = await res.json(); + setLocalProducts(data); + } catch (err) { + setProductsError(err.message); + } finally { + setProductsLoading(false); + } }; - const fetchOrders = async () => { - setOrdersLoading(true); - setOrdersError(""); + const openProductsPopup = () => { + setShowProducts(true); + fetchLocalProducts(); + }; + + const closeProductsPopup = () => setShowProducts(false); + + const toggleCategory = (category) => { + setSelectedCategories((prev) => + prev.includes(category) + ? prev.filter((c) => c !== category) + : [...prev, category] + ); + }; + + const filteredProducts = + selectedCategories.length === 0 + ? localProducts + : localProducts.filter((p) => selectedCategories.includes(p.category)); + + const toggleProductInCart = (product) => { + setCart((prev) => { + const exists = prev.find((p) => p.id === product.id); + if (exists) return prev.filter((p) => p.id !== product.id); + return [...prev, { ...product, quantity: 1 }]; + }); + }; + + const updateQuantity = (productId, newQuantity) => { + if (newQuantity < 1) return; + setCart((prev) => + prev.map((item) => + item.id === productId ? { ...item, quantity: newQuantity } : item + ) + ); + }; + + const placeOrder = async () => { + if (cart.length === 0) return; + setPlacingOrder(true); + setOrderError(""); + setOrderSuccess(false); + const token = localStorage.getItem("token"); + const orderData = { + customer: loggedInEmail, + total: cart.reduce( + (sum, item) => sum + item.quantity * parseFloat(item.price || 0), + 0 + ), + items: cart.map((item) => ({ + product_id: item.id, + quantity: item.quantity, + })), + }; try { const res = await fetch( "https://pos-backend-kso1.onrender.com/api/orders", { - headers: { Authorization: `Bearer ${token}` }, + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(orderData), } ); + if (!res.ok) { + const errorData = await res.json(); + throw new Error(errorData.message || "Błąd składania zamówienia"); + } + setOrderSuccess(true); + setCart([]); + } catch (err) { + setOrderError(err.message); + } finally { + setPlacingOrder(false); + } + }; - if (!res.ok) throw new Error("Błąd pobierania zamówień"); + const fetchOrders = async () => { + setOrdersLoading(true); + setOrdersError(""); + const token = localStorage.getItem("token"); + try { + const res = await fetch( + "https://pos-backend-kso1.onrender.com/api/orders", + { headers: { Authorization: `Bearer ${token}` } } + ); + if (!res.ok) throw new Error("Błąd pobierania zamówień"); const data = await res.json(); setOrders(data); } catch (err) { @@ -522,166 +256,72 @@ const Shop = (props) => { const closeOrdersPopup = () => setShowOrders(false); - const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0); - const totalPrice = cart.reduce( - (sum, item) => sum + item.quantity * parseFloat(item.price || 0), - 0 - ); + const formatTime = (seconds) => { + const m = Math.floor(seconds / 60) + .toString() + .padStart(2, "0"); + const s = (seconds % 60).toString().padStart(2, "0"); + return `${m}:${s}`; + }; return ( -
- {loggedInEmail && ( -
- - -
- )} -
- {!loggedInEmail && ( - -

Logowanie

- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - - {loading && } - {validationError && {validationError}} - {error && {error}} -
- )} - {showCart && ( - -

Koszyk

+ - {orderSuccess && ( -

- Zamówienie złożone pomyślnie! -

- )} - {cart.length === 0 ? ( -

Brak produktów w koszyku

- ) : ( - <> - - - - - - - - - - {cart.map((item) => ( - - - - - - - ))} - -
ProductCenaIlość
{item.title.slice(0, 24)}{item.price} zł - - updateQuantity(item.id, parseInt(e.target.value)) - } - style={{ - width: "60px", - padding: "4px", - fontSize: "1rem", - }} - /> - - -
-
- Liczba produktów:{" "} - {totalItems} -
- Razem:{" "} - {totalPrice?.toFixed(2)} zł -
-
- - {placingOrder && } - {orderError && {orderError}} -
- - )} -
+ )} + + {!loggedInEmail && ( + + )} + + {showCart && ( + + )} + {loggedInEmail && !showOrders && !showProducts && (

@@ -697,116 +337,29 @@ const Shop = (props) => { )} + {showProducts && ( - - -

Produkty

- - {productsLoading && } - {productsError && {productsError}} - {!productsLoading && !productsError && ( - <> - - {filteredProducts.map((product) => ( - toggleProductInCart(product)} - selected={ - cart.find((item) => item.id === product.id) !== - undefined - } - > - - {product.title} - {product.price} zł - {/* - {product.description} - */} - - ))} - - - )} - - {!productsLoading && ( - -

Kategorie

- {categories.map((category) => ( -
- -
- ))} -
- )} - + )} + {showOrders && ( - - -

Zamówienia

- - {ordersLoading && } - {ordersError && {ordersError}} - {!ordersLoading && !ordersError && ( - - - - - - - - - - - - {orders.map((order) => ( - - - - - - - - ))} - -
IDCustomerTotalCreated AtItems
{order.id}{order.customer}{parseFloat(order.total).toFixed(2)} zł{new Date(order.created_at).toLocaleString()} - {order.items && order.items.length > 0 ? ( - order.items.map((item, i) => ( - - {item.product_name} x {item.quantity} ( - {item.product_price} zł) - - )) - ) : ( - Brak produktów - )} -
- )} -
-
+ )}
); diff --git a/src/shop/CartPopup.jsx b/src/shop/CartPopup.jsx new file mode 100644 index 0000000..488b13b --- /dev/null +++ b/src/shop/CartPopup.jsx @@ -0,0 +1,88 @@ +import React from "react"; +import { CartPopup as CartPopupWrapper, Table, Th, Td, Button, Spinner, ErrorMsg } from "./styled"; + +const CartPopup = ({ + cart, + setShowCart, + updateQuantity, + toggleProductInCart, + placeOrder, + placingOrder, + orderSuccess, + orderError, +}) => { + const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0); + const totalPrice = cart.reduce( + (sum, item) => sum + item.quantity * parseFloat(item.price || 0), + 0 + ); + + return ( + +

Koszyk

+ + + {orderSuccess && ( +

+ Zamówienie złożone pomyślnie! +

+ )} + + {cart.length === 0 ? ( +

Brak produktów w koszyku

+ ) : ( + <> + + + + + + + + + + {cart.map((item) => ( + + + + + + + ))} + +
ProductCenaIlość
{item.title.slice(0, 24)}{item.price} zł + updateQuantity(item.id, parseInt(e.target.value))} + style={{ width: "60px", padding: "4px", fontSize: "1rem" }} + /> + + +
+ +
+ Liczba produktów: {totalItems} +
+ Razem: {totalPrice?.toFixed(2)} zł +
+ +
+ + {placingOrder && } + {orderError && {orderError}} +
+ + )} +
+ ); +}; + +export default CartPopup; diff --git a/src/shop/LoginPopup.jsx b/src/shop/LoginPopup.jsx new file mode 100644 index 0000000..24da5bb --- /dev/null +++ b/src/shop/LoginPopup.jsx @@ -0,0 +1,39 @@ +import React from "react"; +import { Input, Button, Popup, Spinner, ErrorMsg } from "./styled"; + +const LoginPopup = ({ + email, + setEmail, + password, + setPassword, + handleLogin, + loading, + error, + validationError, +}) => { + return ( + +

Logowanie

+ setEmail(e.target.value)} + /> + setPassword(e.target.value)} + /> + + {loading && } + {validationError && {validationError}} + {error && {error}} +
+ ); +}; + +export default LoginPopup; diff --git a/src/shop/OrdersPopup.jsx b/src/shop/OrdersPopup.jsx new file mode 100644 index 0000000..9de22e5 --- /dev/null +++ b/src/shop/OrdersPopup.jsx @@ -0,0 +1,59 @@ +import React from "react"; +import { PopupProducts, OrderColumn, Table, Th, Td, Button, Spinner, ErrorMsg } from "./styled"; + +const OrdersPopup = ({ + orders, + ordersLoading, + ordersError, + closeOrdersPopup, +}) => { + return ( + + +

Zamówienia

+ + + {ordersLoading && } + {ordersError && {ordersError}} + {!ordersLoading && !ordersError && ( + + + + + + + + + + + + {orders.map((order) => ( + + + + + + + + ))} + +
IDCustomerTotalCreated AtItems
{order.id}{order.customer}{parseFloat(order.total).toFixed(2)} zł{new Date(order.created_at).toLocaleString()} + {order.items && order.items.length > 0 ? ( + order.items.map((item, i) => ( + + {item.product_name} x {item.quantity} ({item.product_price} zł) + + )) + ) : ( + Brak produktów + )} +
+ )} +
+
+ ); +}; + +export default OrdersPopup; diff --git a/src/shop/ProductCard.jsx b/src/shop/ProductCard.jsx new file mode 100644 index 0000000..4b40062 --- /dev/null +++ b/src/shop/ProductCard.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import { + ProductCardWrapper, + ProductImage, + ProductTitle, + ProductPrice, +} from "./styled"; + +const ProductCard = ({ product, selected, onClick }) => { + return ( + + + {product.title} + {product.price} zł + + ); +}; + +export default ProductCard; diff --git a/src/shop/ProductsPopup.jsx b/src/shop/ProductsPopup.jsx new file mode 100644 index 0000000..9c4aa5e --- /dev/null +++ b/src/shop/ProductsPopup.jsx @@ -0,0 +1,67 @@ +import React from "react"; +import { + PopupProducts, + ProductsColumn, + CategoriesColumn, + Button, +} from "./styled"; +import ProductCard from "./ProductCard"; + +const ProductsPopup = ({ + products, + filteredProducts, + categories, + selectedCategories, + toggleCategory, + cart, + toggleProductInCart, + productsLoading, + productsError, + closeProductsPopup, +}) => { + return ( + + +

Produkty

+ + + {productsLoading &&

Ładowanie...

} + {productsError &&

{productsError}

} + {!productsLoading && !productsError && ( +
+ {filteredProducts.map((product) => ( + item.id === product.id) !== undefined} + onClick={() => toggleProductInCart(product)} + /> + ))} +
+ )} +
+ + {!productsLoading && ( + +

Kategorie

+ {categories.map((category) => ( +
+ +
+ ))} +
+ )} +
+ ); +}; + +export default ProductsPopup; diff --git a/src/shop/styled.js b/src/shop/styled.js new file mode 100644 index 0000000..ea57787 --- /dev/null +++ b/src/shop/styled.js @@ -0,0 +1,215 @@ +import styled from "styled-components"; + +export const Popup = styled.div` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: white; + padding: 2rem; + border-radius: 16px; + width: 100%; + max-width: 1400px; + max-height: 65vh; + overflow-y: auto; + text-align: center; + color: black; + @media (max-width: 640px) { + padding: 0px; + } +`; + +export const PopupProducts = styled.div` + background: white; + padding: 2rem; + border-radius: 16px; + width: 100%; + overflow-y: auto; + text-align: center; + color: black; + @media (max-width: 640px) { + padding: 0px; + } +`; + +export const Input = styled.input` + width: 100%; + padding: 12px 14px; + margin: 0.3rem 0; + border: 2px solid #ddd; + border-radius: 10px; + font-size: 1rem; + outline: none; + transition: all 0.25s ease; + &:focus { + border-color: #3498db; + box-shadow: 0 0 8px rgba(52, 152, 219, 0.4); + transform: scale(1.02); + } +`; + +export const Button = styled.button` + margin: 1rem auto 0; + width: 200px; + border: none; + border-radius: 10px; + font-size: 1rem; + background: linear-gradient(135deg, rgb(23, 130, 253), rgb(97, 171, 255)); + color: white; + font-weight: bold; + cursor: pointer; + transition: all 0.3s ease; + display: block; + &:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + &:disabled { + background: #aaa; + cursor: not-allowed; + transform: none; + box-shadow: none; + } +`; + +export const Spinner = styled.div` + margin: 1rem auto; + border: 4px solid #eee; + border-top: 4px solid #3498db; + border-radius: 50%; + width: 32px; + height: 32px; + animation: spin 1s linear infinite; + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } +`; + +export const ErrorMsg = styled.p` + color: red; + margin: 0.2rem 0; + font-size: 0.9rem; + animation: fadeIn 0.3s ease; + @keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } +`; + +export const Table = styled.table` + width: 100%; + border-collapse: collapse; + margin-top: 1rem; +`; + +export const Th = styled.th` + background: #3498db; + color: white; + padding: 10px; + &:first-child { + padding-left: 16px; + } +`; + +export const Td = styled.td` + overflow: hidden; + white-space: nowrap; + border: 1px solid #ddd; + padding: 8px; + text-align: left; + &:first-child { + padding-left: 16px; + } +`; + +export const CartPopup = styled.div` + color: black; + position: fixed; + top: 0; + right: 0; + width: 600px; + max-width: 90%; + height: 100vh; + background: white; + padding: 2rem; + overflow-y: auto; + box-shadow: -8px 0 30px rgba(0, 0, 0, 0.2); + animation: slideIn 0.3s ease; + z-index: 1000; + @keyframes slideIn { + from { + transform: translateX(100%); + } + to { + transform: translateX(0%); + } + } +`; + +export const ProductGrid = styled.div` + display: grid; + grid-template-columns: repeat(auto-fill, 220px); + gap: 1rem; + justify-content: center; + margin-top: 1rem; +`; + +export const ProductCardWrapper = styled.div` + width: 220px; + background: #fff; + border: 2px solid ${(props) => (props.selected ? "#2ecc71" : "white")}; + border-radius: 12px; + padding: 1rem; + text-align: center; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06); + transition: transform 0.2s, border-color 0.2s; + + &:hover { + cursor: pointer; + } +`; + +export const ProductPrice = styled.div` + font-weight: bold; + margin: 0.25rem 0; + color: #2ecc71; +`; + +export const ProductImage = styled.img` + width: 100%; + height: 200px; + object-fit: cover; + border-radius: 10px; +`; + +export const ProductTitle = styled.h4` + font-size: 1rem; + margin: 0.5rem 0; +`; + +export const ProductsColumn = styled.div` + flex: 3; + overflow-y: auto; +`; + +export const OrderColumn = styled.div` + flex: 3; + overflow-y: auto; +`; + +export const CategoriesColumn = styled.div` + padding-top: 20px; + flex: 1; + max-height: 70vh; + overflow-y: auto; + text-align: left; +`;