Akinon Release Notes (05/12/2025) are now live! Click here to learn what's new.
LogoLogo
API Reference
  • Home
  • Quick Start
  • Tutorials
  • Technical Guides
  • Release Notes
  • Glossary
  • Welcome to Akinon Tutorials
  • ACC
    • How to Manage Projects and Services?
    • How to Use Demo Projects with ARC?
    • How to Move Apps into ACC?
    • How To Configure Database Connection in ACC?
    • How to Configure Your ACC Application with akinon.json and Procfile?
    • How to Create, Manage, Build, and Deploy Applications in ACC?
    • How to Install Applications from the App Store in ACC?
    • How to Add and Manage Domains in ACC?
    • How to Generate and Add Public Keys in ACC?
    • How to Monitor Application Resources in ACC?
    • How to Manage Users and Roles in ACC?
    • How to Integrate a BI Tool with Your Project in ACC?
  • Omnitron
    • Products & Catalogs
      • How to Add and Bulk Update Products in Omnitron?
      • How to Create Product Attributes and Attribute Sets in Omnitron?
      • How to Manage Catalogs in Omnitron?
      • How to Create and Update Price Lists in Omnitron?
      • How to Create and Update Stock Lists in Omnitron?
      • How to Create and Manage Collections in Omnitron?
    • Orders
      • How to Manage Orders in Omnitron?
      • How to Manage Cancellation and Return Requests in Omnitron?
    • Sales Channels
      • How to Manage Products in Omnitron?
      • How to Manage Registered Users Based on Sales Channel?
      • How to Create and Update Customer Groups in Omnitron?
      • Marketing
        • How to Create and Manage Campaigns in Omnitron
        • How to Create and Manage Coupons in Omnitron?
        • How to Create and Manage Bulk Coupons in Omnitron?
        • How to Create and Manage Discount Codes in Omnitron?
        • How to Configure SEO Settings in Omnitron?
        • How to Configure URL Redirects and Settings in Omnitron?​
        • How to Manage Promotions in Omnitron?
      • Content Management
        • How to Manage Widgets in Omnitron?
        • How to Manage Widget Schema in Omnitron?
        • How to Manage Flat Pages in Omnitron?
        • How to Manage Custom/Campaign Pages in Omnitron?
        • How to Manage Navigations/Menus in Omnitron?
        • How to Manage Mailing Templates in Omnitron?
      • Store Management
        • How to Manage Stores in Omnitron?
        • How to Manage Instore Store Employees in Omnitron?
        • How to Manage Instore Store from Omnitron?
        • How to Manage Store Delivery Points in Omnitron?
        • How to Manage Slots and Retail Store Groups?
      • Payment Management
        • How to Manage POS Integrations in Omnitron?
        • How to Manage Banks in Omnitron?
        • How to Manage Card Types in Omnitron?
        • How to Manage Card Settings in Omnitron?
        • How to Manage Checkout Providers in Omnitron?
        • How to Manage Payment Options in Omnitron?
      • Category Management
        • How to Automatically Assign Category Mapping Rules in Omnitron?
      • Sales Channel Settings
        • How to Configure Marketplace Attribute Mapping in Omnitron?
        • How to Manage Marketplace Mapping in Omnitron?
        • How to Manage Marketplace Operations?
        • How to Manage Address Mapping in Omnitron?
        • How to Manage Social Accounts in Omnitron?
        • How to Manage Loyalty Integration Settings?
        • How to Manage Store Stock Settings?
        • How to Manage Product List Filter Settings?
        • How to Manage Instore Settings in Omnitron?
        • How to Manage General Sorting Settings?
        • How to Manage Shipping Options in Omnitron?
        • How to Manage Delivery Options in Omnitron?
        • How to Manage Easy Return Shipping Options in Omnitron?
    • Integration
      • How to Manage Pending Products in Omnitron?
      • How to Manage City/District Mapping Error Logs in Omnitron?
    • Reports
      • How to Create and Download Reports in Omnitron?
    • Settings
      • How to Add and Configure a New Sales Channel in Omnitron?
      • How to Add and Configure a Shipping Company in Omnitron?
      • How to Create and Manage Sorting Algorithms in Omnitron?
      • How to Create and Manage Users in Omnitron?
      • How to Manage Reasons for Cancellation and Return in Omnitron?
      • How to Manage Authority Groups in Omnitron?
      • How to Manage Advanced Permission Policies and Items?
      • How to Log in to Omnitron Using OAuth2 (SSO)?
  • OMS
    • How to Set Up and Manage Locations in OMS?
    • How to Set Up Basic Configurations in OMS?
    • How to Manage Application Settings in OMS?
    • How to Add and Edit Stock Locations in OMS?
    • How to Create or Edit Distribution Scenarios in OMS?
    • How to Create or Edit Transfer Scenarios in OMS ?
    • How to Perform a Product Search in OMS?
    • How to Add or Edit a Product Stock Integration Engine in OMS?
    • How to Add or Edit Shipping Details in OMS?
    • How to Add or Edit a Webhook in OMS?
    • How to Add or Edit a State Transition in OMS?
    • How to Add or Edit a Packaging Refusal Reason in OMS?
    • How to Pull Orders from Omnitron to OMS?
    • How to Add or Edit Translatable Models in OMS?
    • How to Manage Scheduled Operations in OMS?
    • Working Logic of Scenarios
  • Instore
    • How to Install the Instore Service on an ACC Project?
    • How to Create Customer Account?
    • How to Manage Store & Staff?
    • How to Manage Instore Settings?
    • How to Create Instore Settings Via Omnitron Panel?
    • How to Customize Instore Widgets?
    • How to Configure Payment Methods in Instore?
    • Instore User Manual
      • Selling Through Instore
      • Order Refund/Cancellation Processes
      • Click & Collect Order Management (For Brands without an OMS)
      • Package Orders
      • Transfer Orders
      • Customer Profile
      • Settings
  • Integrator
    • How to Update S3 Bucket?
    • How to Manage Users in Integrator?
    • How to Create and Manage Integration Flow?
    • How to Monitor Integration Logs in Integrator?
    • How to Use the Flow Testing Screen in Integrator?
    • How to Use Alarm Services in Integrator?
    • How to Monitor Flow Performance in Integrator?
    • How to Create a Version Service in Integrator?
    • Flows
      • Login Flow
      • Product Flow
      • Stock Flow
      • Full Stock Flow
      • Price Flow
      • Full Price Flow
      • Order Flow
      • Order Status Flow
      • Order Cancel Flow
      • OMS Stock Flow
      • Whippy Stock Flow
      • Generic Proxy Flow
      • Image S3 Flow
      • Video S3 Flow
      • JOLT Mapping
      • Scripting in Flows
  • Project Zero
    • How to Configure Mini Basket?
    • How to Optimize Menu Performance?
    • How to Implement the Quickly Add to Cart Feature?
    • How to Implement Product Image Slider?
    • How to Create and Integrate a Custom Payment Option View in Checkout?
  • Marketplace Dashboard
    • How to Monitor Integration Logs in the Marketplace Dashboard?
    • How to Monitor Integration Reports in Marketplace Dashboard?
    • How to Create Alarms and Notifications in Marketplace Dashboard?
  • Akifast
    • Akifast Admin Dashboard
    • Akifast Merchant Dashboard
  • Seller Center
    • Seller
      • Settings
        • How to Manage Users in Seller Center?
        • How to Generate and Revoke Access Tokens in Seller Center?
        • How to Manage Delivery Settings in Seller Center?
      • Products
        • How to Use Offer Actions in Seller Center?
        • How to Add Single Product in Seller Center?
        • How to Add Product Offers Using Bulk Actions in Seller Center?
        • How to Manage Offers via Marketplace Catalog?
        • How to Create Revison Requests?
        • How to Use Bulk Actions in Seller Center?
        • Inventory Management
          • How to Manage Stock List in Seller Center?
          • How to Manage Price List in Seller Center?
      • Orders
        • How to Manage Orders in Seller Center?
        • How to Manage Packages in Seller Center?
        • How to Manage Cancellation & Returns in Seller Center?
      • Finance
        • Account Management
        • How to Manage Reconciliations in Seller Center?
      • Store Management
      • Messages
      • Support
    • Marketplace Owner
      • Settings
        • How to Manage Users in Seller Center?
        • How to Manage Delivery Settings in Seller Center?
        • How to Manage Offer Reject Reasons in Seller Center?
        • How to Manage Attribute Set & Category Mapping?
      • Products
        • How to Manage Offers via Marketplace Catalog?
        • How to Use Offer Actions in Seller Center?
      • Orders
        • How to Manage Orders in Seller Center?
        • How to Manage Packages in Seller Center?
        • How to Cancel or Return an Order in Seller Center?
      • Finance
        • How to Manage Reconciliations?
        • Seller Management
      • Support
      • Messages
  • Whippy Ware
    • Whippy Ware
  • Dynamic Price
    • Dynamic Price
  • How to Use Offer Reject Reasons?
Powered by GitBook

© 2025 Akinon. All rights reserved.

On this page
  • Technical Requirements and Prerequisites​
  • Implementation Steps​
  • 1. Adding the Button to Product Item​
  • 2. Creating Components for Variants​
  • 3. Creating Variant Modal Component​
  • 4. Creating Basket Drawer Component​

Was this helpful?

  1. Project Zero

How to Implement the Quickly Add to Cart Feature?

PreviousHow to Optimize Menu Performance?NextHow to Implement Product Image Slider?

Last updated 16 days ago

Was this helpful?

This feature allows users to quickly add products to their basket from the listing pages. A button is displayed on the bottom-right corner of each product, enabling users to view product variants without navigating to the detailed product page. Variants can then be selected and added to the cart directly. This functionality aims to streamline the shopping process, save time, and improve conversion rates and reduce drop-offs caused by lengthy navigation processes.

Technical Requirements and Prerequisites​

  • Compatibility: The feature is supported in @akinon/next versions between 1.43.0-rc.14 and 1.72.0.

Implementation Steps​

1. Adding the Button to Product Item​

To display the "Quickly Add to Cart" button on product items, add the following code block to the desired location in src/views/product-item/index.tsx:

Ensure that item.attribute_key values for variantsFilter and variantsSizes correspond to the attribute keys used for color and size in your project.

const [openVariantModal, setOpenVariantModal] = useState(false);
  const [openSizeVariantDesktop, setOpenSizeVariantDesktop] = useState(false);
  const [openColorVariantDesktop, setOpenColorVariantDesktop] = useState(false);
  const [variantType, setVariantType] = useState('');
  const [isBasketDrawerOpen, setIsBasketDrawerOpen] = useState(false);
  const variants = product?.extra_data?.variants;
  const image_url_one = product?.productimage_set[0]?.image;
  const product_brand =
    product?.attributes_kwargs?.integration_alt_marka?.label;
  const basket_offers_label = product?.basket_offers[0]?.label?.toLowerCase();
  const basket_offers_price =
    product?.basket_offers[0]?.listing_kwargs?.discounted_total_price;
  const variantsFilter = variants?.filter(
    (item) =>
      item.attribute_key === 'mp_color' ||
      item.attribute_key === 'integration_color' ||
      item.attribute_key === 'integration_renk'
  );

  const variantsSizes = variants?.filter(
    (item) =>
      item.attribute_key === 'mp_size' ||
      item.attribute_key === 'integration_beden'
  );

  const selectableColors =
    variantsFilter &&
    variantsFilter[0]?.options?.filter((item) => item.is_selectable);

  const selectableSizes =
    variantsSizes &&
    variantsSizes[0]?.options?.filter((item) => item.is_selectable);

  useEffect(() => {
    setProductNameText(product_name);
  }, [product_name]);

  useEffect(() => {
    setProducPriceText(price);
  }, [price]);

  const [productNameText, setProductNameText] = useState(product_name);
  const [producPriceText, setProducPriceText] = useState(price);
  const [productVariantUrl, setProducVariantUrl] = useState(absolute_url);
  const [productImage, setProductImage] = useState(image_url_one);
  const [swiper, setSwiper] = useState(null);
  const [multiImages, setMultiImages] = useState(null);
  const [selectedPk, setSelectedPk] = useState<number>(product.pk);

  useEffect(() => {
    setProducVariantUrl(productVariantUrl);
  }, [productVariantUrl]);

  const handleBasketDrawer = useCallback(
    (pk: number) => {
      setSelectedPk(pk);
      setIsBasketDrawerOpen(true);
    },
    [setIsBasketDrawerOpen]
  );

<ShowVariants
       variantsColors={variantsFilter}
       variantsSizes={variantsSizes}
       setVariantType={setVariantType}
       setOpenVariantModal={setOpenVariantModal}
       setOpenColorVariantDesktop={setOpenColorVariantDesktop}
       setOpenSizeVariantDesktop={setOpenSizeVariantDesktop}
       openSizeVariantDesktop={openSizeVariantDesktop}
       openColorVariantDesktop={openColorVariantDesktop}
       variantsFilter={variantsFilter}
       setProductNameText={setProductNameText}
       setProducPriceText={setProducPriceText}
       setProductImage={setProductImage}
       setProducVariantUrl={setProducVariantUrl}
       setMultiImages={setMultiImages}
       swiper={swiper}
       absolute_url={productVariantUrl}
       productPk={product?.pk}
       setIsBasketDrawerOpen={handleBasketDrawer}
       selectedProduct={product}
     />

     {openSizeVariantDesktop && (
       <Suspense fallback={<LoaderSpinner />}>
         <div className="bg-gray-100 p-2">
           <div className="mb-3 text-base xl:text-lg font-bold leading-snug text-secondary">
             <span>Quickly Add to Cart</span>
           </div>
           <VariantModal
             key={product?.pk}
             item={product}
             index={index + 1}
             type={'size'}
             setIsBasketDrawerOpen={handleBasketDrawer}
           />
         </div>
       </Suspense>
     )}

     {!openSizeVariantDesktop && (
       <div className="h-full">
         <Link
           href={productVariantUrl}
           data-testid={`${product.pk}-${index}`}
           className="flex flex-col mb-3 2xl:mb-[1.125rem]"
           key={`${product.pk}-${index}`}
         >
           <span
             className={clsx(
               'text-xs text-secondary font-bold leading-snug xl:!leading-6',
               '2xl:text-lg 2xl:tracking-tight'
             )}
           >
             {product_brand}
           </span>
           <span
             key={`${product.pk}-${index}`}
             className="text-xs font-medium leading-snug text-secondary-100 2xl:text-sm 2xl:leading-5 min-h-[50px] md:min-h-10"
           >
             {productNameText}
           </span>
         </Link>
         {/* <div>
           {retail_price && retail_price > price ? (
             <DiscountPrice
               price={product_min_quantity ? (+product_min_quantity * +producPriceText) : producPriceText}
               retailPrice={product_min_quantity ? (+product_min_quantity * +retail_price) : retail_price}
               priceColor={
                 basket_offers_price ? 'text-secondary' : 'text-primary'
               }
             />
           ) : (
             <Price
               value={product_min_quantity ? (+product_min_quantity * +producPriceText).toString() : producPriceText}
               data-testid="product-price"
               className="text-secondary text-sm font-bold leading-snug tracking-tight 2xl:text-lg"
             />
           )}
         </div> */}
       </div>
     )}

     {variants && (
       <Modal
         portalId={`size_${product.pk}`}
         title={`Farklı ${
           variantType === 'size' ? 'Beden' : 'Renk'
         } Seçenekleri  (${
           variantType === 'size'
             ? selectableSizes?.length
             : selectableColors?.length
         })`}
         open={openVariantModal}
         setOpen={setOpenVariantModal}
         showCloseButton
         className="w-full bottom-0 top-auto transform-none left-0 px-0 pb-5 md:hidden"
         // titleClass="text-secondary md:text-lg font-semibold leading-snug py-3 px-4 border-b-0"
       >
         <Suspense fallback={<LoaderSpinner />}>
           <div>
             <VariantModal
               key={product?.pk}
               item={product}
               index={index + 1}
               type={variantType}
               setIsBasketDrawerOpen={handleBasketDrawer}
             />
           </div>
         </Suspense>
       </Modal>
     )}

     {product.pk && (
       <DrawerBasket
         offerLabel={basket_offers_label}
         offerPrice={basket_offers_price}
         open={isBasketDrawerOpen}
         productPk={selectedPk}
         setOpen={setIsBasketDrawerOpen}
       />
     )}

2. Creating Components for Variants​

Color Variants Component​

A variants folder should be created within the src/views/product-item directory, and a color-variant.tsx file with the following code should be added inside it.

This component ensures that color variants are displayed on the listing page if available:

import { Image } from '@akinon/next/components/image';
import { Link, Price } from '@theme/components';

interface ProductItem {
 is_selectable: boolean;
 product: {
   absolute_url: string;
   productimage_set: { image: string };
   name: string;
   price: number;
 };
}

interface Props {
 variant: ProductItem[];
 index: number;
}

export const ColorVariant = (props: Props) => {
 const { variant, index } = props;
 const default_image = '/default-no-image.png'
 return (
   <div
     key={index}
     className="flex flex-row items-start justify-start gap-x-2 overflow-scroll pl-4"
   >
     {variant
       ?.filter((option) => option.is_selectable)
       ?.map((productItem, itemIndex) => (
         <Link
           key={itemIndex}
           href={productItem.product.absolute_url}
           className="w-[3.75rem] min-w-[3.75rem] h-auto p-0 bg-white border-none flex flex-col gap-y-1"
         >
           <Image
             loading="lazy"
             src={productItem.product.productimage_set[0].image || default_image}
             alt={productItem.product.name}
             title={productItem.product.name}
             aspectRatio={1}
             width={60}
             height={60}
             crop="center"
             className="flex"
             style={{
               imageRendering : "-webkit-optimize-contrast",
             }}
           />

           <Price
             value={productItem.product.price}
             data-testid="product-price"
             className="text-secondary text-xs font-medium leading-snug"
           />
         </Link>
       ))}
   </div>
 );
};

Show Variants Component​

A variants folder should be created within the src/views/product-item directory, and a show-variant.tsx file with the following code should be added inside it.

This component handles the display of size and color variants:

import { Image } from '@akinon/next/components/image';
import { Product } from '@akinon/next/types';
import { Button, Icon, Link } from '@theme/components';
import { useAddProductToBasket } from '@theme/hooks';
import { pushAddToCart } from '@theme/utils/gtm';

interface ColorImage {
 is_selectable: boolean;
 product: Product;
}

const ShowVariants = ({
 variantsSizes,
 variantsColors,
 setVariantType,
 setOpenVariantModal,
 setOpenSizeVariantDesktop,
 openSizeVariantDesktop,
 openColorVariantDesktop,
 variantsFilter,
 setProductNameText,
 setProducPriceText,
 setProductImage,
 setMultiImages,
 swiper,
 absolute_url,
 productPk,
 setIsBasketDrawerOpen,
 setProducVariantUrl,
 selectedProduct
}) => {
 const [addProductToBasket] = useAddProductToBasket();

 const sizeClickHandler = (isMobile: boolean = false) => {
   const selectableSizes =
     variantsSizes &&
     variantsSizes[0]?.options.filter((option) => option.is_selectable);

   if (!selectableSizes) {
     addProductToBasket({
       product: productPk,
       quantity: 1,
       attributes: {},
       shouldOpenMiniBasket: false
     }).then(() => {
       setIsBasketDrawerOpen(productPk);
       pushAddToCart(selectedProduct);
     });
     return;
   }

   setVariantType('size');
   if (isMobile) {
     setOpenVariantModal(true);
     return;
   }
   setOpenSizeVariantDesktop(!openSizeVariantDesktop);
 };

 const selectableColorsLength =
   variantsFilter &&
   variantsFilter[0]?.options?.filter((item) => item.is_selectable)?.length;

 const default_image = '/default-no-image.png';
 return (
   <>
     {variantsColors && variantsColors[0]?.options?.length > 1 && (
       <Button
         onClick={() => {
           setVariantType('color');
           setOpenVariantModal(true);
         }}
         className="absolute bottom-3 left-4 z-10 p-1 bg-white flex flex-row items-center gap-x-1 border-none h-auto md:hidden"
       >
         <Image
           loading="lazy"
           src="/colors.png"
           alt="colors"
           aspectRatio={1}
           width={28.5}
           height={17}
           style={{
             imageRendering: '-webkit-optimize-contrast'
           }}
         />
         <span className="text-xs font-medium leading-snug text-secondary">
           {selectableColorsLength}
         </span>
       </Button>
     )}

     <Button
       onClick={() => sizeClickHandler(true)}
       className="absolute bottom-3 right-4 z-10 p-1.5 bg-secondary flex flex-row items-center gap-x-1 rounded-full border-none h-auto xl:p-2 hover:bg-secondary md:hidden"
     >
       <Icon
         name={'add'}
         className="text-white text-xs !leading-none xl:text-base"
       />
     </Button>

     <div className="hidden md:flex absolute bottom-[1rem] md:bottom-2 h-4 z-10 right-4">
       <Button
         onClick={() => sizeClickHandler()}
         className="bg-secondary flex flex-row items-center gap-x-1 rounded-full border-none h-auto ml-auto p-2 hover:bg-secondary hover:!text-secondary"
       >
         <Icon
           name={'add'}
           className="text-xs text-inherit !leading-none xl:text-base"
         />
       </Button>
     </div>

     {openColorVariantDesktop && variantsFilter?.length && (
       <div className="absolute bottom-0 z-10 w-full bg-white flex flex-row items-center justify-start gap-x-1 p-3">
         {variantsFilter &&
           variantsFilter[0]?.options
             ?.filter((option: ColorImage) => option.is_selectable)
             ?.map(
               (colorImage: ColorImage, colorImageIndex: number) =>
                 colorImageIndex < 4 && (
                   <Image
                     key={colorImageIndex}
                     loading="lazy"
                     src={
                       colorImage.product.productimage_set[0].image ||
                       default_image
                     }
                     alt={colorImage.product.name}
                     title={colorImage.product.name}
                     aspectRatio={1}
                     width={48}
                     height={48}
                     crop="center"
                     className="flex cursor-pointer"
                     style={{
                       imageRendering: '-webkit-optimize-contrast'
                     }}
                     onClick={() => {
                       setProductNameText(colorImage.product.name);
                       setProducPriceText(colorImage.product.price);
                       setProductImage(
                         colorImage.product.productimage_set[0].image ||
                           default_image
                       );
                       setProducVariantUrl(colorImage.product.absolute_url);
                       setMultiImages(colorImage.product.productimage_set);
                       swiper?.slideTo(0);
                     }}
                   />
                 )
             )}

         {variantsFilter && variantsFilter[0]?.options?.length >= 5 && (
           <Link href={absolute_url} className="flex">
             <div className="flex flex-row items-center justify-center gap-x-1 w-[4.25rem]">
               <span className="text-xs font-medium leading-6 text-secondary underline underline-offset-4">
                 +4
               </span>
               <Icon name="chevron-right" size={13} />
             </div>
           </Link>
         )}
       </div>
     )}
   </>
 );
};

export default ShowVariants;

Size Variants Component​

A variants folder should be created within the src/views/product-item directory, and a size-variant.tsx file with the following code should be added inside it.

This component displays size variants for products:

import { Button } from '@theme/components';
import clsx from 'clsx';
import { useAddProductToBasket } from '@theme/hooks';
import { pushAddToCart } from '@theme/utils/gtm';
import { Product } from '@akinon/next/types';

interface VariantItem {
 is_selectable: boolean;
 value: string;
 label: string;
 product: Product;
 order: string;
}

interface Props {
 variant: VariantItem[];
 index: number;
 setIsBasketDrawerOpen: (pk: number) => void;
 productMinQuantity?: number;
}

export const checkSizeHasComma = (size: string) => {
 if (!size) return;

 return size?.includes(',') ? size.replace(',', '.') : size;
};

export const SizeVariant = (props: Props) => {
 const { variant, index, setIsBasketDrawerOpen, productMinQuantity } = props;
 const [addProductToBasket, { isLoading: isAddProductToBasketLoading }] =
   useAddProductToBasket();

 const handleOnClick = (selectedProduct) => {
   addProductToBasket({
     product: selectedProduct.pk,
     quantity: productMinQuantity ?? 1,
     attributes: {},
     shouldOpenMiniBasket: false
   }).then(() => {
     setIsBasketDrawerOpen(selectedProduct.pk);
     pushAddToCart(selectedProduct);
     localStorage?.setItem(
       `GA4_index_${selectedProduct.pk}`,
       JSON.stringify(index)
     );
   });
 };

 return (
   <div
     key={index}
     className={clsx(
       'sm:grid sm:grid-cols-4 lg:flex lg:flex-row items-start justify-start lg:flex-wrap gap-x-5 gap-y-3',
       'md:gap-y-1.5 md:gap-x-1'
     )}
   >
     {variant
       .filter((option) => option.is_selectable)
       .sort((a, b) => {
         const filterableSizeA = a?.product?.attributes
           ?.filterable_size as string;
         const filterableSizeB = b?.product?.attributes
           ?.filterable_size as string;

         if (
           filterableSizeA &&
           filterableSizeB &&
           parseFloat(filterableSizeA) &&
           parseFloat(filterableSizeB)
         ) {
           const floatA = parseFloat(checkSizeHasComma(filterableSizeA));
           const floatB = parseFloat(checkSizeHasComma(filterableSizeB));

           return floatA - floatB;
         } else if (Number(a?.order) && Number(b?.order)) {
           return parseFloat(a.order) - parseFloat(b.order);
         }

         return 0;
       })
       ?.map((productItem, itemIndex) => (
         <Button
           key={itemIndex}
           type="submit"
           appearance="ghost"
           value={productItem.value}
           onClick={() => handleOnClick(productItem.product)}
           disabled={
             !productItem.product.in_stock || isAddProductToBasketLoading
           }
           className={clsx(
             'text-sm text-secondary px-0 h-auto w-[2.875rem]',
             'hover:bg-secondary hover:text-white hover:border-none hover:rounded',
             'md:w-[3.125rem]',
             !productItem.product.in_stock &&
               'hover:bg-gray-200 hover:text-gray-600'
           )}
           data-testid="list-variant-add-cart"
         >
           {productItem?.product?.attributes_kwargs?.filterable_size.label}
         </Button>
       ))}
   </div>
 );
};

3. Creating Variant Modal Component​

A variants folder should be created within the src/views/product-item directory, and a variant-modal.tsx file with the following code should be added inside it.

This modal is displayed when the "Quickly Add to Cart" button is clicked:

import { useGetProductByPkQuery } from '@akinon/next/data/client/product';
import { Product } from '@akinon/next/types';
import { ColorVariant } from './color-variant';
import { SizeVariant } from './size-variant';
import { LoaderSpinner } from '@theme/components';

interface Props {
 item: Product;
 index: number;
 type: string;
 setIsBasketDrawerOpen: (pk: number) => void;
}

export const VariantModal = (props: Props) => {
 const { item, type, index, setIsBasketDrawerOpen } = props;
 const { data, isSuccess , isLoading } = useGetProductByPkQuery(item?.pk);
 const product_min_quantity = data?.product?.attributes?.integration_min_quantity;
 let variantData = [];

 type === 'size'
   ? (variantData = data?.variants?.filter(
       (item) =>
         item.attribute_key === 'mp_size' ||
         item.attribute_key === 'integration_beden'
     ))
   : (variantData = data?.variants?.filter(
       (item) =>
         item.attribute_key === 'mp_color' ||
         item.attribute_key === 'integration_color' ||
         item.attribute_key === 'integration_renk'
     ));

     if(isLoading) {
       return <div><LoaderSpinner/></div>
     }
 return (
   isSuccess &&
   variantData &&
   variantData?.map((variant, i) => (
     <div key={i}>
       {type === 'color' && (
         <ColorVariant key={i} variant={variant.options} index={i} />
       )}
       {type === 'size' && (
         <SizeVariant
           key={i}
           variant={variant.options}
           index={index}
           setIsBasketDrawerOpen={setIsBasketDrawerOpen}
           productMinQuantity={product_min_quantity}
         />
       )}
     </div>
   ))
 );
};

4. Creating Basket Drawer Component​

Create a basket-drawer.tsx file under src/views/basket with the following code.

This component displays the cart drawer that slides out when an item is added to the cart:

import { Image } from '@akinon/next/components/image';
import { Modal, LoaderSpinner, Icon, Link } from '@theme/components';
import { useGetProductByParamsQuery } from '@akinon/next/data/client/product';
import { Price } from '@theme/components';
import { ROUTES } from '@theme/routes';
import { useMediaQuery } from '@akinon/next/hooks';
import clsx from 'clsx';

type Props = {
 open: boolean;
 setOpen: React.Dispatch<React.SetStateAction<boolean>>;
 productPk: number;
 offerLabel?: string | null;
 offerPrice?: number | null;
};

const DrawerBasket = (props: Props) => {
 const matches = useMediaQuery('(max-height: 670px)');

 const { data, isFetching, isSuccess } = useGetProductByParamsQuery(
   {
     pk: props.productPk
   },
   {
     skip: !props.open
   }
 );

 const product_min_quantity =
   data?.product?.attributes?.integration_min_quantity;

 const title = (
   <div className="flex items-center gap-3 text-2xl text-success font-semibold tracing-[-0.48px] leading-snug">
     <Icon name="tick-circle" size={24} />
     <span>It is in the bag</span>
   </div>
 );

 return (
   <>
     <Modal
       portalId="basket-drawer"
       title={title}
       open={props.open}
       setOpen={props.setOpen}
       className={
         '!w-full  md:!w-[820px] !max-w-[510px] right-0 left-auto !transform-none md:!transform md:translate-x-0 h-[95%] md:h-screen !rounded-none overflow-auto md:!px-0'
       }
     >
       {isFetching && <LoaderSpinner />}
       {isSuccess && (
         <div className="mb-8">
           <div className="!md:pt-8 md:px-[52px]">
             <div className="flex items-center justify-between text-secondary text-sm mb-8 w-full gap-3 md:gap-5">
               <div className="w-[110px] h-[110px] md:w-[184px] md:h-[184px] md:max-w-[184px]">
                 <Image
                   alt={data.product.name}
                   src={data.product.productimage_set[0].image}
                   aspectRatio={184 / 184}
                   fill
                   sizes="768px"
                   className="w-[110px] h-[110px] md:w-[184px] md:h-[184px]"
                   style={{
                     imageRendering: '-webkit-optimize-contrast'
                   }}
                 />
               </div>
               <div className="text-xs md:text-sm">
                 <p className="font-medium mb-3">
                   <span className="font-bold">
                     {data.product.attributes_kwargs.integration_alt_marka
                       ?.label ||
                       data.product.attributes.integration_alt_marka}
                   </span>{' '}
                   {data.product.name}
                 </p>
                 <div className="flex justify-between mb-3 md:mb-4">
                   <p>
                     Renk:{' '}
                     <span className="font-bold">
                       {data.product.attributes.integration_renk_tonu}
                     </span>{' '}
                   </p>
                   <p className="hidden md:block">
                     Beden:{' '}
                     <span className="font-bold">
                       {data.product.attributes_kwargs.filterable_size?.value}
                     </span>{' '}
                   </p>
                 </div>
                 <p className="font-bold text-sm md:text-lg leading-6 tracking-tighter">
                   {parseFloat(data.product.retail_price) >
                     parseFloat(data.product.price) && (
                     <Price
                       value={parseFloat(
                         product_min_quantity
                           ? (
                               +product_min_quantity *
                               +data.product.retail_price
                             ).toString()
                           : data.product.retail_price
                       )}
                       decimalScale={2}
                       className="line-through text-base font-medium leading-6 text-secondary"
                     />
                   )}
                   <Price
                     value={
                       product_min_quantity
                         ? (
                             +product_min_quantity * +data.product.price
                           ).toString()
                         : data.product.price
                     }
                     decimalScale={2}
                     className={clsx(
                       'text-lg font-semibold leading-snug',
                       parseFloat(data.product.retail_price) >
                         parseFloat(data.product.price) && 'text-primary ml-4'
                     )}
                   />
                 </p>
                 {props.offerPrice && props.offerLabel && (
                   <div className="flex flex-col mt-1 2xl:flex-row 2xl:items-center 2xl:gap-x-1 2xl:mt-1.5">
                     <span className="text-xs text-secondary whitespace-nowrap font-medium leading-snug capitalize 2xl:leading-6">
                       {props.offerLabel}
                     </span>
                     <Price
                       value={props.offerPrice}
                       data-testid="product-price"
                       className="text-sm text-primary whitespace-nowrap font-bold leading-snug 2xl:tracking-tight"
                     />
                   </div>
                 )}
               </div>
             </div>
             <div
               style={{
                 boxShadow: matches
                   ? '0 -6px 6px 0 rgba(0, 0, 0, 0.08)'
                   : 'none'
               }}
               className="p-4 md:p-0 fixed bottom-0 left-0 w-full md:static bg-white z-10 md:!shadow-none flex justify-between items-center md:mb-24"
             >
               <button
                 onClick={() => props.setOpen(false)}
                 className="font-medium underline"
               >
                 Continue Shopping
               </button>
               <Link
                 as="a"
                 href={ROUTES.BASKET}
                 className="font-medium w-[151px] md:w-[214px] text-center"
               >
                 Go to Bag
               </Link>
             </div>
           </div>
         </div>
       )}
     </Modal>
   </>
 );
};

export default DrawerBasket;