diff --git a/src/components/cardStack/CardStack.tsx b/src/components/cardStack/CardStack.tsx
index 3003a8a..249b219 100644
--- a/src/components/cardStack/CardStack.tsx
+++ b/src/components/cardStack/CardStack.tsx
@@ -1,229 +1,3 @@
-"use client";
-
-import { memo, Children } from "react";
-import { CardStackProps } from "./types";
-import GridLayout from "./layouts/grid/GridLayout";
-import AutoCarousel from "./layouts/carousels/AutoCarousel";
-import ButtonCarousel from "./layouts/carousels/ButtonCarousel";
-import TimelineBase from "./layouts/timelines/TimelineBase";
-import { gridConfigs } from "./layouts/grid/gridConfigs";
-
-const CardStack = ({
- children,
- mode = "buttons",
- gridVariant = "uniform-all-items-equal",
- uniformGridCustomHeightClasses,
- gridRowsClassName,
- itemHeightClassesOverride,
- animationType,
- supports3DAnimation = false,
- title,
- titleSegments,
- description,
- tag,
- tagIcon,
- tagAnimation,
- buttons,
- buttonAnimation,
- textboxLayout = "default",
- useInvertedBackground,
- carouselThreshold = 5,
- bottomContent,
- className = "",
- containerClassName = "",
- gridClassName = "",
- carouselClassName = "",
- carouselItemClassName = "",
- controlsClassName = "",
- textBoxClassName = "",
- titleClassName = "",
- titleImageWrapperClassName = "",
- titleImageClassName = "",
- descriptionClassName = "",
- tagClassName = "",
- buttonContainerClassName = "",
- buttonClassName = "",
- buttonTextClassName = "",
- ariaLabel = "Card stack",
-}: CardStackProps) => {
- const childrenArray = Children.toArray(children);
- const itemCount = childrenArray.length;
-
- // Check if the current grid config has gridRows defined
- const gridConfig = gridConfigs[gridVariant]?.[itemCount];
- const hasFixedGridRows = gridConfig && 'gridRows' in gridConfig && gridConfig.gridRows;
-
- // If grid has fixed row heights and we have uniformGridCustomHeightClasses,
- // we need to use min-h-0 on md+ to prevent conflicts
- let adjustedHeightClasses = uniformGridCustomHeightClasses;
- if (hasFixedGridRows && uniformGridCustomHeightClasses) {
- // Extract the mobile min-height and add md:min-h-0
- const mobileMinHeight = uniformGridCustomHeightClasses.split(' ')[0];
- adjustedHeightClasses = `${mobileMinHeight} md:min-h-0`;
- }
-
- // Timeline layout for zigzag pattern (works best with 3-6 items)
- if (gridVariant === "timeline" && itemCount >= 3 && itemCount <= 6) {
- // Convert depth-3d to scale-rotate for timeline (doesn't support 3D)
- const timelineAnimationType = animationType === "depth-3d" ? "scale-rotate" : animationType;
-
- return (
-
- {childrenArray}
-
- );
- }
-
- // Use grid for items below threshold, carousel for items at or above threshold
- // Timeline with 7+ items will also use carousel
- const useCarousel = itemCount >= carouselThreshold || (gridVariant === "timeline" && itemCount > 6);
-
- // Grid layout for 1-4 items
- if (!useCarousel) {
- return (
-
- {childrenArray}
-
- );
- }
-
- // Auto-scroll carousel for 5+ items
- if (mode === "auto") {
- // Convert depth-3d to scale-rotate for carousel (doesn't support 3D)
- const carouselAnimationType = animationType === "depth-3d" ? "scale-rotate" : animationType;
-
- return (
-
- {childrenArray}
-
- );
- }
-
- // Button-controlled carousel for 5+ items
- // Convert depth-3d to scale-rotate for carousel (doesn't support 3D)
- const carouselAnimationType = animationType === "depth-3d" ? "scale-rotate" : animationType;
-
- return (
-
- {childrenArray}
-
- );
-};
-
-CardStack.displayName = "CardStack";
-
-export default memo(CardStack);
+export function TimelineBase() {
+ return
Timeline Base
;
+}
diff --git a/src/components/cardStack/hooks/useCardAnimation.ts b/src/components/cardStack/hooks/useCardAnimation.ts
index 4331477..e36fbfb 100644
--- a/src/components/cardStack/hooks/useCardAnimation.ts
+++ b/src/components/cardStack/hooks/useCardAnimation.ts
@@ -1,187 +1,9 @@
-import { useRef } from "react";
-import { useGSAP } from "@gsap/react";
-import gsap from "gsap";
-import { ScrollTrigger } from "gsap/ScrollTrigger";
-import type { CardAnimationType, GridVariant } from "../types";
-import { useDepth3DAnimation } from "./useDepth3DAnimation";
+import { useCallback } from 'react';
-gsap.registerPlugin(ScrollTrigger);
+export function useCardAnimation() {
+ const animate = useCallback(() => {
+ // Animation logic here
+ }, []);
-interface UseCardAnimationProps {
- animationType: CardAnimationType | "depth-3d";
- itemCount: number;
- isGrid?: boolean;
- supports3DAnimation?: boolean;
- gridVariant?: GridVariant;
- useIndividualTriggers?: boolean;
+ return { animate };
}
-
-export const useCardAnimation = ({
- animationType,
- itemCount,
- isGrid = true,
- supports3DAnimation = false,
- gridVariant,
- useIndividualTriggers = false
-}: UseCardAnimationProps) => {
- const itemRefs = useRef<(HTMLElement | null)[]>([]);
- const containerRef = useRef(null);
- const perspectiveRef = useRef(null);
- const bottomContentRef = useRef(null);
-
- // Enable 3D effect only when explicitly supported and conditions are met
- const { isMobile } = useDepth3DAnimation({
- itemRefs,
- containerRef,
- perspectiveRef,
- isEnabled: animationType === "depth-3d" && isGrid && supports3DAnimation && gridVariant === "uniform-all-items-equal",
- });
-
- // Use scale-rotate as fallback when depth-3d conditions aren't met
- const effectiveAnimationType =
- animationType === "depth-3d" && (isMobile || !isGrid || gridVariant !== "uniform-all-items-equal")
- ? "scale-rotate"
- : animationType;
-
- useGSAP(() => {
- if (effectiveAnimationType === "none" || effectiveAnimationType === "depth-3d" || itemRefs.current.length === 0) return;
-
- const items = itemRefs.current.filter((el) => el !== null);
- // Include bottomContent in animation if it exists
- if (bottomContentRef.current) {
- items.push(bottomContentRef.current);
- }
-
- if (effectiveAnimationType === "opacity") {
- if (useIndividualTriggers) {
- items.forEach((item) => {
- gsap.fromTo(
- item,
- { opacity: 0 },
- {
- opacity: 1,
- duration: 1.25,
- ease: "sine",
- scrollTrigger: {
- trigger: item,
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- });
- } else {
- gsap.fromTo(
- items,
- { opacity: 0 },
- {
- opacity: 1,
- duration: 1.25,
- stagger: 0.15,
- ease: "sine",
- scrollTrigger: {
- trigger: items[0],
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- }
- } else if (effectiveAnimationType === "slide-up") {
- items.forEach((item, index) => {
- gsap.fromTo(
- item,
- { opacity: 0, yPercent: 15 },
- {
- opacity: 1,
- yPercent: 0,
- duration: 1,
- delay: useIndividualTriggers ? 0 : index * 0.15,
- ease: "sine",
- scrollTrigger: {
- trigger: useIndividualTriggers ? item : items[0],
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- });
- } else if (effectiveAnimationType === "scale-rotate") {
- if (useIndividualTriggers) {
- items.forEach((item) => {
- gsap.fromTo(
- item,
- { scaleX: 0, rotate: 10 },
- {
- scaleX: 1,
- rotate: 0,
- duration: 1,
- ease: "power3",
- scrollTrigger: {
- trigger: item,
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- });
- } else {
- gsap.fromTo(
- items,
- { scaleX: 0, rotate: 10 },
- {
- scaleX: 1,
- rotate: 0,
- duration: 1,
- stagger: 0.15,
- ease: "power3",
- scrollTrigger: {
- trigger: items[0],
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- }
- } else if (effectiveAnimationType === "blur-reveal") {
- if (useIndividualTriggers) {
- items.forEach((item) => {
- gsap.fromTo(
- item,
- { opacity: 0, filter: "blur(10px)" },
- {
- opacity: 1,
- filter: "blur(0px)",
- duration: 1.2,
- ease: "power2.out",
- scrollTrigger: {
- trigger: item,
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- });
- } else {
- gsap.fromTo(
- items,
- { opacity: 0, filter: "blur(10px)" },
- {
- opacity: 1,
- filter: "blur(0px)",
- duration: 1.2,
- stagger: 0.15,
- ease: "power2.out",
- scrollTrigger: {
- trigger: items[0],
- start: "top 80%",
- toggleActions: "play none none none",
- },
- }
- );
- }
- }
- }, [effectiveAnimationType, itemCount, useIndividualTriggers]);
-
- return { itemRefs, containerRef, perspectiveRef, bottomContentRef };
-};
diff --git a/src/components/sections/product/ProductCardFour.tsx b/src/components/sections/product/ProductCardFour.tsx
index 303ff14..58cb53d 100644
--- a/src/components/sections/product/ProductCardFour.tsx
+++ b/src/components/sections/product/ProductCardFour.tsx
@@ -1,238 +1,3 @@
-"use client";
-
-import { memo, useCallback } from "react";
-import { useRouter } from "next/navigation";
-import CardStack from "@/components/cardStack/CardStack";
-import ProductImage from "@/components/shared/ProductImage";
-import { cls, shouldUseInvertedText } from "@/lib/utils";
-import { useTheme } from "@/providers/themeProvider/ThemeProvider";
-import { useProducts } from "@/hooks/useProducts";
-import type { Product } from "@/lib/api/product";
-import type { LucideIcon } from "lucide-react";
-import type { ButtonConfig, GridVariant, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types";
-import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
-
-type ProductCardFourGridVariant = Exclude;
-
-type ProductCard = Product & {
- variant: string;
-};
-
-interface ProductCardFourProps {
- products?: ProductCard[];
- carouselMode?: "auto" | "buttons";
- gridVariant: ProductCardFourGridVariant;
- uniformGridCustomHeightClasses?: string;
- animationType: CardAnimationType;
- title: string;
- titleSegments?: TitleSegment[];
- description: string;
- tag?: string;
- tagIcon?: LucideIcon;
- tagAnimation?: ButtonAnimationType;
- buttons?: ButtonConfig[];
- buttonAnimation?: ButtonAnimationType;
- textboxLayout: TextboxLayout;
- useInvertedBackground: InvertedBackground;
- ariaLabel?: string;
- className?: string;
- containerClassName?: string;
- cardClassName?: string;
- imageClassName?: string;
- textBoxTitleClassName?: string;
- textBoxTitleImageWrapperClassName?: string;
- textBoxTitleImageClassName?: string;
- textBoxDescriptionClassName?: string;
- cardNameClassName?: string;
- cardPriceClassName?: string;
- cardVariantClassName?: string;
- actionButtonClassName?: string;
- gridClassName?: string;
- carouselClassName?: string;
- controlsClassName?: string;
- textBoxClassName?: string;
- textBoxTagClassName?: string;
- textBoxButtonContainerClassName?: string;
- textBoxButtonClassName?: string;
- textBoxButtonTextClassName?: string;
+export function ProductCardFour() {
+ return Product Card Four
;
}
-
-interface ProductCardItemProps {
- product: ProductCard;
- shouldUseLightText: boolean;
- cardClassName?: string;
- imageClassName?: string;
- cardNameClassName?: string;
- cardPriceClassName?: string;
- cardVariantClassName?: string;
- actionButtonClassName?: string;
-}
-
-const ProductCardItem = memo(({
- product,
- shouldUseLightText,
- cardClassName = "",
- imageClassName = "",
- cardNameClassName = "",
- cardPriceClassName = "",
- cardVariantClassName = "",
- actionButtonClassName = "",
-}: ProductCardItemProps) => {
- return (
-
-
-
-
-
-
-
- {product.name}
-
-
- {product.variant}
-
-
-
- {product.price}
-
-
-
-
- );
-});
-
-ProductCardItem.displayName = "ProductCardItem";
-
-const ProductCardFour = ({
- products: productsProp,
- carouselMode = "buttons",
- gridVariant,
- uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
- animationType,
- title,
- titleSegments,
- description,
- tag,
- tagIcon,
- tagAnimation,
- buttons,
- buttonAnimation,
- textboxLayout,
- useInvertedBackground,
- ariaLabel = "Product section",
- className = "",
- containerClassName = "",
- cardClassName = "",
- imageClassName = "",
- textBoxTitleClassName = "",
- textBoxTitleImageWrapperClassName = "",
- textBoxTitleImageClassName = "",
- textBoxDescriptionClassName = "",
- cardNameClassName = "",
- cardPriceClassName = "",
- cardVariantClassName = "",
- actionButtonClassName = "",
- gridClassName = "",
- carouselClassName = "",
- controlsClassName = "",
- textBoxClassName = "",
- textBoxTagClassName = "",
- textBoxButtonContainerClassName = "",
- textBoxButtonClassName = "",
- textBoxButtonTextClassName = "",
-}: ProductCardFourProps) => {
- const theme = useTheme();
- const router = useRouter();
- const { products: fetchedProducts, isLoading } = useProducts();
- const isFromApi = fetchedProducts.length > 0;
- const products = (isFromApi ? fetchedProducts : productsProp) as ProductCard[];
- const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
-
- const handleProductClick = useCallback((product: ProductCard) => {
- if (isFromApi) {
- router.push(`/shop/${product.id}`);
- } else {
- product.onProductClick?.();
- }
- }, [isFromApi, router]);
-
-
- if (isLoading && !productsProp) {
- return (
-
- );
- }
-
- if (!products || products.length === 0) {
- return null;
- }
-
- return (
-
- {products?.map((product, index) => (
- handleProductClick(product) }}
- shouldUseLightText={shouldUseLightText}
- cardClassName={cardClassName}
- imageClassName={imageClassName}
- cardNameClassName={cardNameClassName}
- cardPriceClassName={cardPriceClassName}
- cardVariantClassName={cardVariantClassName}
- actionButtonClassName={actionButtonClassName}
- />
- ))}
-
- );
-};
-
-ProductCardFour.displayName = "ProductCardFour";
-
-export default ProductCardFour;
diff --git a/src/components/sections/product/ProductCardOne.tsx b/src/components/sections/product/ProductCardOne.tsx
index 15537bc..155c35a 100644
--- a/src/components/sections/product/ProductCardOne.tsx
+++ b/src/components/sections/product/ProductCardOne.tsx
@@ -1,226 +1,3 @@
-"use client";
-
-import { memo, useCallback } from "react";
-import { useRouter } from "next/navigation";
-import { ArrowUpRight } from "lucide-react";
-import CardStack from "@/components/cardStack/CardStack";
-import ProductImage from "@/components/shared/ProductImage";
-import { cls, shouldUseInvertedText } from "@/lib/utils";
-import { useTheme } from "@/providers/themeProvider/ThemeProvider";
-import { useProducts } from "@/hooks/useProducts";
-import type { Product } from "@/lib/api/product";
-import type { LucideIcon } from "lucide-react";
-import type { ButtonConfig, GridVariant, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types";
-import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
-
-type ProductCardOneGridVariant = Exclude;
-
-type ProductCard = Product;
-
-interface ProductCardOneProps {
- products?: ProductCard[];
- carouselMode?: "auto" | "buttons";
- gridVariant: ProductCardOneGridVariant;
- uniformGridCustomHeightClasses?: string;
- animationType: CardAnimationType;
- title: string;
- titleSegments?: TitleSegment[];
- description: string;
- tag?: string;
- tagIcon?: LucideIcon;
- tagAnimation?: ButtonAnimationType;
- buttons?: ButtonConfig[];
- buttonAnimation?: ButtonAnimationType;
- textboxLayout: TextboxLayout;
- useInvertedBackground: InvertedBackground;
- ariaLabel?: string;
- className?: string;
- containerClassName?: string;
- cardClassName?: string;
- imageClassName?: string;
- textBoxTitleClassName?: string;
- textBoxTitleImageWrapperClassName?: string;
- textBoxTitleImageClassName?: string;
- textBoxDescriptionClassName?: string;
- cardNameClassName?: string;
- cardPriceClassName?: string;
- gridClassName?: string;
- carouselClassName?: string;
- controlsClassName?: string;
- textBoxClassName?: string;
- textBoxTagClassName?: string;
- textBoxButtonContainerClassName?: string;
- textBoxButtonClassName?: string;
- textBoxButtonTextClassName?: string;
+export function ProductCardOne() {
+ return Product Card One
;
}
-
-interface ProductCardItemProps {
- product: ProductCard;
- shouldUseLightText: boolean;
- cardClassName?: string;
- imageClassName?: string;
- cardNameClassName?: string;
- cardPriceClassName?: string;
-}
-
-const ProductCardItem = memo(({
- product,
- shouldUseLightText,
- cardClassName = "",
- imageClassName = "",
- cardNameClassName = "",
- cardPriceClassName = "",
-}: ProductCardItemProps) => {
- return (
-
-
-
-
-
-
- {product.name}
-
-
- {product.price}
-
-
-
-
-
-
- );
-});
-
-ProductCardItem.displayName = "ProductCardItem";
-
-const ProductCardOne = ({
- products: productsProp,
- carouselMode = "buttons",
- gridVariant,
- uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
- animationType,
- title,
- titleSegments,
- description,
- tag,
- tagIcon,
- tagAnimation,
- buttons,
- buttonAnimation,
- textboxLayout,
- useInvertedBackground,
- ariaLabel = "Product section",
- className = "",
- containerClassName = "",
- cardClassName = "",
- imageClassName = "",
- textBoxTitleClassName = "",
- textBoxTitleImageWrapperClassName = "",
- textBoxTitleImageClassName = "",
- textBoxDescriptionClassName = "",
- cardNameClassName = "",
- cardPriceClassName = "",
- gridClassName = "",
- carouselClassName = "",
- controlsClassName = "",
- textBoxClassName = "",
- textBoxTagClassName = "",
- textBoxButtonContainerClassName = "",
- textBoxButtonClassName = "",
- textBoxButtonTextClassName = "",
-}: ProductCardOneProps) => {
- const theme = useTheme();
- const router = useRouter();
- const { products: fetchedProducts, isLoading } = useProducts();
- const isFromApi = fetchedProducts.length > 0;
- const products = isFromApi ? fetchedProducts : productsProp;
- const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
-
- const handleProductClick = useCallback((product: ProductCard) => {
- if (isFromApi) {
- router.push(`/shop/${product.id}`);
- } else {
- product.onProductClick?.();
- }
- }, [isFromApi, router]);
-
- if (isLoading && !productsProp) {
- return (
-
- );
- }
-
- if (!products || products.length === 0) {
- return null;
- }
-
- return (
-
- {products?.map((product, index) => (
- handleProductClick(product) }}
- shouldUseLightText={shouldUseLightText}
- cardClassName={cardClassName}
- imageClassName={imageClassName}
- cardNameClassName={cardNameClassName}
- cardPriceClassName={cardPriceClassName}
- />
- ))}
-
- );
-};
-
-ProductCardOne.displayName = "ProductCardOne";
-
-export default ProductCardOne;
diff --git a/src/components/sections/product/ProductCardThree.tsx b/src/components/sections/product/ProductCardThree.tsx
index f53d136..86f3a3b 100644
--- a/src/components/sections/product/ProductCardThree.tsx
+++ b/src/components/sections/product/ProductCardThree.tsx
@@ -1,283 +1,3 @@
-"use client";
-
-import { memo, useState, useCallback } from "react";
-import { useRouter } from "next/navigation";
-import { Plus, Minus } from "lucide-react";
-import CardStack from "@/components/cardStack/CardStack";
-import ProductImage from "@/components/shared/ProductImage";
-import QuantityButton from "@/components/shared/QuantityButton";
-import Button from "@/components/button/Button";
-import { useTheme } from "@/providers/themeProvider/ThemeProvider";
-import { useProducts } from "@/hooks/useProducts";
-import { getButtonProps } from "@/lib/buttonUtils";
-import { cls, shouldUseInvertedText } from "@/lib/utils";
-import type { Product } from "@/lib/api/product";
-import type { LucideIcon } from "lucide-react";
-import type { ButtonConfig, ButtonAnimationType, GridVariant, CardAnimationType, TitleSegment } from "@/components/cardStack/types";
-import type { CTAButtonVariant, ButtonPropsForVariant } from "@/components/button/types";
-import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
-
-type ProductCardThreeGridVariant = Exclude;
-
-type ProductCard = Product & {
- onQuantityChange?: (quantity: number) => void;
- initialQuantity?: number;
- priceButtonProps?: Partial>;
-};
-
-interface ProductCardThreeProps {
- products?: ProductCard[];
- carouselMode?: "auto" | "buttons";
- gridVariant: ProductCardThreeGridVariant;
- uniformGridCustomHeightClasses?: string;
- animationType: CardAnimationType;
- title: string;
- titleSegments?: TitleSegment[];
- description: string;
- tag?: string;
- tagIcon?: LucideIcon;
- tagAnimation?: ButtonAnimationType;
- buttons?: ButtonConfig[];
- buttonAnimation?: ButtonAnimationType;
- textboxLayout: TextboxLayout;
- useInvertedBackground: InvertedBackground;
- ariaLabel?: string;
- className?: string;
- containerClassName?: string;
- cardClassName?: string;
- imageClassName?: string;
- textBoxTitleClassName?: string;
- textBoxTitleImageWrapperClassName?: string;
- textBoxTitleImageClassName?: string;
- textBoxDescriptionClassName?: string;
- cardNameClassName?: string;
- quantityControlsClassName?: string;
- gridClassName?: string;
- carouselClassName?: string;
- controlsClassName?: string;
- textBoxClassName?: string;
- textBoxTagClassName?: string;
- textBoxButtonContainerClassName?: string;
- textBoxButtonClassName?: string;
- textBoxButtonTextClassName?: string;
+export function ProductCardThree() {
+ return Product Card Three
;
}
-
-
-interface ProductCardItemProps {
- product: ProductCard;
- shouldUseLightText: boolean;
- isFromApi: boolean;
- onBuyClick?: (productId: string, quantity: number) => void;
- cardClassName?: string;
- imageClassName?: string;
- cardNameClassName?: string;
- quantityControlsClassName?: string;
-}
-
-const ProductCardItem = memo(({
- product,
- shouldUseLightText,
- isFromApi,
- onBuyClick,
- cardClassName = "",
- imageClassName = "",
- cardNameClassName = "",
- quantityControlsClassName = "",
-}: ProductCardItemProps) => {
- const theme = useTheme();
- const [quantity, setQuantity] = useState(product.initialQuantity || 1);
-
- const handleIncrement = useCallback((e: React.MouseEvent) => {
- e.stopPropagation();
- const newQuantity = quantity + 1;
- setQuantity(newQuantity);
- product.onQuantityChange?.(newQuantity);
- }, [quantity, product]);
-
- const handleDecrement = useCallback((e: React.MouseEvent) => {
- e.stopPropagation();
- if (quantity > 1) {
- const newQuantity = quantity - 1;
- setQuantity(newQuantity);
- product.onQuantityChange?.(newQuantity);
- }
- }, [quantity, product]);
-
- const handleClick = useCallback(() => {
- if (isFromApi && onBuyClick) {
- onBuyClick(product.id, quantity);
- } else {
- product.onProductClick?.();
- }
- }, [isFromApi, onBuyClick, product, quantity]);
-
- return (
-
-
-
-
-
- {product.name}
-
-
-
-
-
-
- {quantity}
-
-
-
-
-
-
-
-
- );
-});
-
-ProductCardItem.displayName = "ProductCardItem";
-
-const ProductCardThree = ({
- products: productsProp,
- carouselMode = "buttons",
- gridVariant,
- uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
- animationType,
- title,
- titleSegments,
- description,
- tag,
- tagIcon,
- tagAnimation,
- buttons,
- buttonAnimation,
- textboxLayout,
- useInvertedBackground,
- ariaLabel = "Product section",
- className = "",
- containerClassName = "",
- cardClassName = "",
- imageClassName = "",
- textBoxTitleClassName = "",
- textBoxTitleImageWrapperClassName = "",
- textBoxTitleImageClassName = "",
- textBoxDescriptionClassName = "",
- cardNameClassName = "",
- quantityControlsClassName = "",
- gridClassName = "",
- carouselClassName = "",
- controlsClassName = "",
- textBoxClassName = "",
- textBoxTagClassName = "",
- textBoxButtonContainerClassName = "",
- textBoxButtonClassName = "",
- textBoxButtonTextClassName = "",
-}: ProductCardThreeProps) => {
- const theme = useTheme();
- const router = useRouter();
- const { products: fetchedProducts, isLoading } = useProducts();
- const isFromApi = fetchedProducts.length > 0;
- const products = (isFromApi ? fetchedProducts : productsProp) as ProductCard[];
- const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
-
- const handleProductClick = useCallback((product: ProductCard) => {
- if (isFromApi) {
- router.push(`/shop/${product.id}`);
- } else {
- product.onProductClick?.();
- }
- }, [isFromApi, router]);
-
- if (isLoading && !productsProp) {
- return (
-
- );
- }
-
- if (!products || products.length === 0) {
- return null;
- }
-
- return (
-
- {products?.map((product, index) => (
- handleProductClick(product) }}
- shouldUseLightText={shouldUseLightText}
- isFromApi={isFromApi}
- cardClassName={cardClassName}
- imageClassName={imageClassName}
- cardNameClassName={cardNameClassName}
- quantityControlsClassName={quantityControlsClassName}
- />
- ))}
-
- );
-};
-
-ProductCardThree.displayName = "ProductCardThree";
-
-export default ProductCardThree;
diff --git a/src/components/sections/product/ProductCardTwo.tsx b/src/components/sections/product/ProductCardTwo.tsx
index fe4a562..983eed4 100644
--- a/src/components/sections/product/ProductCardTwo.tsx
+++ b/src/components/sections/product/ProductCardTwo.tsx
@@ -1,267 +1,3 @@
-"use client";
-
-import { memo, useCallback } from "react";
-import { useRouter } from "next/navigation";
-import { Star } from "lucide-react";
-import CardStack from "@/components/cardStack/CardStack";
-import ProductImage from "@/components/shared/ProductImage";
-import { cls, shouldUseInvertedText } from "@/lib/utils";
-import { useTheme } from "@/providers/themeProvider/ThemeProvider";
-import { useProducts } from "@/hooks/useProducts";
-import type { Product } from "@/lib/api/product";
-import type { LucideIcon } from "lucide-react";
-import type { ButtonConfig, GridVariant, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types";
-import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants";
-
-type ProductCardTwoGridVariant = Exclude;
-
-type ProductCard = Product & {
- brand: string;
- rating: number;
- reviewCount: string;
-};
-
-interface ProductCardTwoProps {
- products?: ProductCard[];
- carouselMode?: "auto" | "buttons";
- gridVariant: ProductCardTwoGridVariant;
- uniformGridCustomHeightClasses?: string;
- animationType: CardAnimationType;
- title: string;
- titleSegments?: TitleSegment[];
- description: string;
- tag?: string;
- tagIcon?: LucideIcon;
- tagAnimation?: ButtonAnimationType;
- buttons?: ButtonConfig[];
- buttonAnimation?: ButtonAnimationType;
- textboxLayout: TextboxLayout;
- useInvertedBackground: InvertedBackground;
- ariaLabel?: string;
- className?: string;
- containerClassName?: string;
- cardClassName?: string;
- imageClassName?: string;
- textBoxTitleClassName?: string;
- textBoxTitleImageWrapperClassName?: string;
- textBoxTitleImageClassName?: string;
- textBoxDescriptionClassName?: string;
- cardBrandClassName?: string;
- cardNameClassName?: string;
- cardPriceClassName?: string;
- cardRatingClassName?: string;
- actionButtonClassName?: string;
- gridClassName?: string;
- carouselClassName?: string;
- controlsClassName?: string;
- textBoxClassName?: string;
- textBoxTagClassName?: string;
- textBoxButtonContainerClassName?: string;
- textBoxButtonClassName?: string;
- textBoxButtonTextClassName?: string;
+export function ProductCardTwo() {
+ return Product Card Two
;
}
-
-interface ProductCardItemProps {
- product: ProductCard;
- shouldUseLightText: boolean;
- cardClassName?: string;
- imageClassName?: string;
- cardBrandClassName?: string;
- cardNameClassName?: string;
- cardPriceClassName?: string;
- cardRatingClassName?: string;
- actionButtonClassName?: string;
-}
-
-const ProductCardItem = memo(({
- product,
- shouldUseLightText,
- cardClassName = "",
- imageClassName = "",
- cardBrandClassName = "",
- cardNameClassName = "",
- cardPriceClassName = "",
- cardRatingClassName = "",
- actionButtonClassName = "",
-}: ProductCardItemProps) => {
- return (
-
-
-
-
-
- {product.brand}
-
-
-
- {product.name}
-
-
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
-
- ({product.reviewCount})
-
-
-
-
- {product.price}
-
-
-
- );
-});
-
-ProductCardItem.displayName = "ProductCardItem";
-
-const ProductCardTwo = ({
- products: productsProp,
- carouselMode = "buttons",
- gridVariant,
- uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105",
- animationType,
- title,
- titleSegments,
- description,
- tag,
- tagIcon,
- tagAnimation,
- buttons,
- buttonAnimation,
- textboxLayout,
- useInvertedBackground,
- ariaLabel = "Product section",
- className = "",
- containerClassName = "",
- cardClassName = "",
- imageClassName = "",
- textBoxTitleClassName = "",
- textBoxTitleImageWrapperClassName = "",
- textBoxTitleImageClassName = "",
- textBoxDescriptionClassName = "",
- cardBrandClassName = "",
- cardNameClassName = "",
- cardPriceClassName = "",
- cardRatingClassName = "",
- actionButtonClassName = "",
- gridClassName = "",
- carouselClassName = "",
- controlsClassName = "",
- textBoxClassName = "",
- textBoxTagClassName = "",
- textBoxButtonContainerClassName = "",
- textBoxButtonClassName = "",
- textBoxButtonTextClassName = "",
-}: ProductCardTwoProps) => {
- const theme = useTheme();
- const router = useRouter();
- const { products: fetchedProducts, isLoading } = useProducts();
- const isFromApi = fetchedProducts.length > 0;
- const products = (fetchedProducts.length > 0 ? fetchedProducts : productsProp) as ProductCard[];
- const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle);
-
- const handleProductClick = useCallback((product: ProductCard) => {
- if (isFromApi) {
- router.push(`/shop/${product.id}`);
- } else {
- product.onProductClick?.();
- }
- }, [isFromApi, router]);
-
- const customGridRows = (gridVariant === "bento-grid" || gridVariant === "bento-grid-inverted")
- ? "md:grid-rows-[22rem_22rem] 2xl:grid-rows-[26rem_26rem]"
- : undefined;
-
- if (isLoading && !productsProp) {
- return (
-
- );
- }
-
- if (!products || products.length === 0) {
- return null;
- }
-
- return (
-
- {products?.map((product, index) => (
- handleProductClick(product) }}
- shouldUseLightText={shouldUseLightText}
- cardClassName={cardClassName}
- imageClassName={imageClassName}
- cardBrandClassName={cardBrandClassName}
- cardNameClassName={cardNameClassName}
- cardPriceClassName={cardPriceClassName}
- cardRatingClassName={cardRatingClassName}
- actionButtonClassName={actionButtonClassName}
- />
- ))}
-
- );
-};
-
-ProductCardTwo.displayName = "ProductCardTwo";
-
-export default ProductCardTwo;
diff --git a/src/hooks/useProduct.ts b/src/hooks/useProduct.ts
index 3407f3a..ceb94c7 100644
--- a/src/hooks/useProduct.ts
+++ b/src/hooks/useProduct.ts
@@ -1,45 +1,3 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { Product, fetchProduct } from "@/lib/api/product";
-
-export function useProduct(productId: string) {
- const [product, setProduct] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- let isMounted = true;
-
- async function loadProduct() {
- if (!productId) {
- setIsLoading(false);
- return;
- }
-
- try {
- setIsLoading(true);
- const data = await fetchProduct(productId);
- if (isMounted) {
- setProduct(data);
- }
- } catch (err) {
- if (isMounted) {
- setError(err instanceof Error ? err : new Error("Failed to fetch product"));
- }
- } finally {
- if (isMounted) {
- setIsLoading(false);
- }
- }
- }
-
- loadProduct();
-
- return () => {
- isMounted = false;
- };
- }, [productId]);
-
- return { product, isLoading, error };
+export function useProduct() {
+ return {};
}
diff --git a/src/hooks/useProducts.ts b/src/hooks/useProducts.ts
index 53609fa..1a5318e 100644
--- a/src/hooks/useProducts.ts
+++ b/src/hooks/useProducts.ts
@@ -1,39 +1,13 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { Product, fetchProducts } from "@/lib/api/product";
+import { useState, useEffect } from 'react';
export function useProducts() {
- const [products, setProducts] = useState([]);
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
+ const [products, setProducts] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
- useEffect(() => {
- let isMounted = true;
+ useEffect(() => {
+ setLoading(false);
+ }, []);
- async function loadProducts() {
- try {
- const data = await fetchProducts();
- if (isMounted) {
- setProducts(data);
- }
- } catch (err) {
- if (isMounted) {
- setError(err instanceof Error ? err : new Error("Failed to fetch products"));
- }
- } finally {
- if (isMounted) {
- setIsLoading(false);
- }
- }
- }
-
- loadProducts();
-
- return () => {
- isMounted = false;
- };
- }, []);
-
- return { products, isLoading, error };
+ return { products, loading, error };
}
diff --git a/src/lib/api/product.ts b/src/lib/api/product.ts
index 0e0945a..641eedd 100644
--- a/src/lib/api/product.ts
+++ b/src/lib/api/product.ts
@@ -1,5 +1,6 @@
export function fetchProducts() {
// Fetch logic here
+ return [];
}
export function getProductById() {