-
BTC {p?.productDisplay?.productBody?.price?.value}
diff --git a/src/components/cart/CartProductsList.tsx b/src/components/cart/CartProductsList.tsx
index 30d4c8f8..0f8a21ab 100644
--- a/src/components/cart/CartProductsList.tsx
+++ b/src/components/cart/CartProductsList.tsx
@@ -2,53 +2,64 @@ import CartItemRow from "@/components/cart/CartItemRow";
import Button from "@/components/ui/Button";
import { serviceClient } from "@/lib/api";
import { getProductPrice } from "@/lib/utils";
-import { getCartCookie } from "@/lib/utils/cart";
+import {
+ getCartProductSlugAndSizeFromKey,
+ getCookieCart,
+} from "@/lib/utils/cart";
import Link from "next/link";
export default async function CartProductsList() {
- const cart = getCartCookie();
-
- if (!cart || !cart.products) return null;
-
- const cartItems = Object.values(cart.products) as {
- // todo: add price to calculate total amount in any place in the app
- quantity: number;
- slug: string;
- size?: string;
- }[];
-
- const productsPromises = cartItems.map(async (item) => {
- const [gender, brand, name, id] = item.slug.split("/");
-
- const response = await serviceClient.GetProduct({
- gender,
- brand,
- name,
- id: parseInt(id),
- });
- const product = response.product;
-
- return {
- quantity: item.quantity,
- slug: item.slug,
- size: item.size,
- product: product,
- };
- });
-
- const products = await Promise.all(productsPromises);
-
- // TOTAL PRICE
- let totalPrice = 0;
- products.forEach((x) => (totalPrice += getProductPrice(x.product)));
+ const cartData = getCookieCart();
+
+ if (!cartData || !cartData.products) return null;
+
+ const productsPromises = Object.entries(cartData.products).map(
+ async ([productCartKey, { quanity }]) => {
+ const productSlugAndSize =
+ getCartProductSlugAndSizeFromKey(productCartKey);
+
+ if (productSlugAndSize) {
+ const { slug, size } = productSlugAndSize;
+ const item = {
+ slug,
+ size,
+ quanity,
+ };
+
+ const [gender, brand, name, id] = slug
+ ?.replaceAll("/product/", "")
+ .split("/");
+
+ try {
+ const response = await serviceClient.GetProduct({
+ gender,
+ brand,
+ name,
+ id: parseInt(id),
+ });
+
+ const product = response.product;
+
+ return {
+ ...item,
+ product: product,
+ };
+ } catch (error) {
+ console.log("failed to fetch cart product", error);
+ }
+ }
+ },
+ );
+
+ const products = (await Promise.all(productsPromises)).filter(Boolean);
return products.map((p) => (
diff --git a/src/components/cart/ProductAmountButtons.tsx b/src/components/cart/ProductAmountButtons.tsx
new file mode 100644
index 00000000..3ae2137a
--- /dev/null
+++ b/src/components/cart/ProductAmountButtons.tsx
@@ -0,0 +1,57 @@
+"use client";
+
+import Button from "@/components/ui/Button";
+import { ButtonStyle } from "@/components/ui/Button/styles";
+
+type Props = {
+ changeProductAmount: ({
+ slug,
+ size,
+ operation,
+ }: {
+ slug: string;
+ size: string;
+ operation: "increase" | "decrease";
+ }) => void;
+ removeProduct: (slug: string, size: string) => void;
+ slug: string;
+ size: string;
+};
+
+export default function ProductAmountButtons({
+ changeProductAmount,
+ removeProduct,
+ slug,
+ size,
+}: Props) {
+ // todo: check if product is in stock
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/cart/RemoveFromCartButton.tsx b/src/components/cart/RemoveFromCartButton.tsx
deleted file mode 100644
index 4695aa15..00000000
--- a/src/components/cart/RemoveFromCartButton.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-"use client";
-
-import Button from "@/components/ui/Button";
-import { ButtonStyle } from "@/components/ui/Button/styles";
-
-type Props = {
- removeItemFromCookie: (slug: string, size?: string) => Promise
;
- slug: string;
- size?: string;
-};
-
-export default function RemoveFromCart({
- removeItemFromCookie,
- slug,
- size,
-}: Props) {
- async function handleButtonClick(event: React.MouseEvent) {
- event.preventDefault();
- await removeItemFromCookie(slug, size);
- }
-
- // todo: check if product is in stock
-
- return (
-
- );
-}
diff --git a/src/components/forms/AddToCartForm/index.tsx b/src/components/forms/AddToCartForm/index.tsx
new file mode 100644
index 00000000..09248985
--- /dev/null
+++ b/src/components/forms/AddToCartForm/index.tsx
@@ -0,0 +1,61 @@
+"use client";
+
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useForm } from "react-hook-form";
+import { FormContainer } from "@/components/ui/Form/FormContainer";
+import { common_ProductSize } from "@/api/proto-http/frontend";
+import SelectField from "@/components/ui/Form/fields/SelectField";
+import { addToCartSchema, AddToCartData } from "./schema";
+import { useState } from "react";
+
+export default function AddToCartForm({
+ handleSubmit,
+ sizes,
+ slug,
+}: {
+ handleSubmit: (slug: string, size: string) => Promise;
+ slug: string;
+ sizes: common_ProductSize[];
+}) {
+ const [loading, setLoadingStatus] = useState(false);
+ const form = useForm({
+ resolver: zodResolver(addToCartSchema),
+ });
+
+ const onSubmit = async (data: AddToCartData) => {
+ if (loading) return;
+
+ setLoadingStatus(true);
+ try {
+ await handleSubmit(slug, data.size);
+ } catch (error) {
+ console.error(error);
+ } finally {
+ setLoadingStatus(false);
+ }
+ };
+
+ return (
+
+ ({
+ label: size.sizeId + "",
+ value: size.sizeId + "",
+ }))}
+ />
+
+ );
+}
diff --git a/src/components/forms/AddToCartForm/schema.ts b/src/components/forms/AddToCartForm/schema.ts
new file mode 100644
index 00000000..5a62d31a
--- /dev/null
+++ b/src/components/forms/AddToCartForm/schema.ts
@@ -0,0 +1,8 @@
+import { z } from "zod";
+
+export const addToCartSchema = z.object({
+ size: z.string(),
+ color: z.string().optional(),
+});
+
+export type AddToCartData = z.infer;
diff --git a/src/components/productPage/AddToCartButton.tsx b/src/components/productPage/AddToCartButton.tsx
deleted file mode 100644
index 577e3341..00000000
--- a/src/components/productPage/AddToCartButton.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-"use client";
-
-import Button from "@/components/ui/Button";
-import { ButtonStyle } from "@/components/ui/Button/styles";
-
-type Props = {
- addItemToCookie: (slug: string, size: string) => Promise;
- slug: string;
- size: string;
-};
-
-export default function AddToCartButton({
- addItemToCookie,
- slug,
- size,
-}: Props) {
- async function handleButtonClick(event: React.MouseEvent) {
- event.preventDefault();
- await addItemToCookie(slug, size);
- }
-
- // todo: check if product is in stock
-
- return (
-
- );
-}
diff --git a/src/components/productPage/ProductItem.tsx b/src/components/sections/ProductsGridSection/ProductItem.tsx
similarity index 100%
rename from src/components/productPage/ProductItem.tsx
rename to src/components/sections/ProductsGridSection/ProductItem.tsx
diff --git a/src/components/sections/ProductsGridSection.tsx b/src/components/sections/ProductsGridSection/index.tsx
similarity index 93%
rename from src/components/sections/ProductsGridSection.tsx
rename to src/components/sections/ProductsGridSection/index.tsx
index 494fe3b8..3bf78f09 100644
--- a/src/components/sections/ProductsGridSection.tsx
+++ b/src/components/sections/ProductsGridSection/index.tsx
@@ -1,6 +1,6 @@
import type { common_Product } from "@/api/proto-http/frontend";
// import { shouldInsertEmpty } from "@/lib/utils";
-import ProductItem from "@/components/productPage/ProductItem";
+import ProductItem from "./ProductItem";
export default function ProductsGridSection({
products,
diff --git a/src/components/ui/Form/fields/SelectField/index.tsx b/src/components/ui/Form/fields/SelectField/index.tsx
index e17d0bbb..140df098 100644
--- a/src/components/ui/Form/fields/SelectField/index.tsx
+++ b/src/components/ui/Form/fields/SelectField/index.tsx
@@ -21,6 +21,7 @@ export default function SelectField({
items,
name,
label,
+ ...props
}: Props) {
return (
(
{label}
-
+
)}
diff --git a/src/components/ui/Select/index.tsx b/src/components/ui/Select/index.tsx
index 05eccc0e..2c4b2077 100644
--- a/src/components/ui/Select/index.tsx
+++ b/src/components/ui/Select/index.tsx
@@ -13,7 +13,7 @@ export default function SelectComponent({
}) {
return (
- arrow down
+ arrow down
{items.map((item) => (
diff --git a/src/lib/utils/cart.ts b/src/lib/utils/cart.ts
index 9450229d..5c400a97 100644
--- a/src/lib/utils/cart.ts
+++ b/src/lib/utils/cart.ts
@@ -2,7 +2,22 @@ import { GRBPWR_CART } from "@/actions/cart";
import type { RequestCookie } from "next/dist/compiled/@edge-runtime/cookies";
import { cookies } from "next/headers";
-export function getCartCookie() {
+type CookieCartProductData = { quanity: number };
+type CookieCartProduct = Record;
+
+export function getCartProductKey(slug: string, size: string) {
+ return `${slug}-${size}`;
+}
+
+export function getCartProductSlugAndSizeFromKey(key: string) {
+ const [slug, size] = key.split("-");
+
+ if (!slug || !size) return null;
+
+ return { slug, size };
+}
+
+export function getCookieCart(): { products: CookieCartProduct } | null {
const cookieStore = cookies();
if (!cookieStore.has(GRBPWR_CART)) return null;
@@ -20,9 +35,92 @@ export function getCartCookie() {
return null;
}
-export function createCartId(slug: string, size?: string): string {
- if (!size) {
- return slug;
+export function createCookieCartProduct(productSlug: string, size: string) {
+ const cookieStore = cookies();
+
+ cookieStore.set(
+ GRBPWR_CART,
+ JSON.stringify({
+ products: {
+ [getCartProductKey(productSlug, size)]: {
+ quanity: 1,
+ },
+ },
+ }),
+ );
+}
+
+export function updateCookieCartProduct(
+ productSlug: string,
+ size: string,
+ quanity: number,
+) {
+ const cartData = getCookieCart();
+ const cookieStore = cookies();
+
+ const productKey = getCartProductKey(productSlug, size);
+
+ cookieStore.set(
+ GRBPWR_CART,
+ JSON.stringify({
+ ...cartData,
+ products: {
+ ...cartData?.products,
+ [productKey]: {
+ ...cartData?.products[productKey],
+ quanity,
+ },
+ },
+ }),
+ );
+}
+
+export function removeCookieCartProduct(productSlug: string, size: string) {
+ const cartData = getCookieCart();
+ const cookieStore = cookies();
+
+ cookieStore.set(
+ GRBPWR_CART,
+ JSON.stringify({
+ ...cartData,
+ products: {
+ ...cartData?.products,
+ [getCartProductKey(productSlug, size)]: undefined,
+ },
+ }),
+ );
+}
+
+export function changeCookieCartProductQuanity(
+ productSlug: string,
+ size: string,
+ operation: "increase" | "decrease",
+) {
+ const cartData = getCookieCart();
+ const cookieStore = cookies();
+
+ let operationValue = 0;
+ if (operation === "increase") {
+ operationValue = 1;
}
- return `${slug}_${size}`;
+ if (operation === "decrease") {
+ operationValue = -1;
+ }
+
+ const productKey = getCartProductKey(productSlug, size);
+ const initialQuanity = cartData?.products[productKey].quanity || 0;
+
+ cookieStore.set(
+ GRBPWR_CART,
+ JSON.stringify({
+ ...cartData,
+ products: {
+ ...cartData?.products,
+ [productKey]: {
+ ...cartData?.products[productKey],
+ quanity: initialQuanity + operationValue,
+ },
+ },
+ }),
+ );
}