/* eslint-disable @next/next/no-img-element */ import type { FunctionComponent } from 'react' import React, { useMemo } from 'react' import { Badge, Button, QuantitySelector, Skeleton } from '../..' import Icon from '../../atoms/Icon' import Price, { type PriceFormatter } from '../../atoms/Price' import { useFadeEffect, useSKUMatrix, useUI } from '../../hooks' import { Table, TableBody, TableCell, TableHead, TableRow, } from '../../molecules/Table' import SlideOver, { SlideOverHeader, type SlideOverProps } from '../SlideOver' interface VariationProductColumn { name: string additionalColumns: Array<{ label: string; value: string }> availability: { label: string stockDisplaySettings: 'showStockQuantity' | 'showAvailability' } price: string quantitySelector: string } const ImageComponentFallback: SKUMatrixSidebarProps['ImageComponent'] = ({ src, alt, ...otherProps }) => {alt} // TODO: Moves this component to the `@faststore/core` package. We decided that it doesn't make sense to have this component in the library since it's vey specific to the SKU Matrix feature. export interface SKUMatrixSidebarProps extends Omit { /** * Title for the SKUMatrixSidebar component. */ title?: string /** * Represents the variations products to building the table. */ columns: VariationProductColumn /** * Properties related to the 'add to cart' button */ buyProps: { 'data-testid': string 'data-sku': string 'data-seller': string onClick(e: React.MouseEvent): void } /** * Formatter function that transforms the raw price value and render the result. */ formatter?: PriceFormatter /** * Check if some result is still loading before render the result. */ loading?: boolean /** * Function that returns a React component that will be used to render images. */ ImageComponent: FunctionComponent<{ src: string alt: string width?: number height?: number }> /** * Labels related to the 'invalid quantity' toast. */ invalidQuantityToastLabels?: { title?: string message?: string } } function SKUMatrixSidebar({ title, direction = 'rightSide', size = 'partial', children, columns, loading, formatter, ImageComponent = ImageComponentFallback, buyProps: { onClick: buyButtonOnClick, ...buyProps }, overlayProps, invalidQuantityToastLabels, ...otherProps }: SKUMatrixSidebarProps) { const { isOpen, setIsOpen, setAllVariantProducts, allVariantProducts, onChangeQuantityItem, } = useSKUMatrix() const { pushToast } = useUI() const { fade } = useFadeEffect() const cartDetails = useMemo(() => { return allVariantProducts.reduce( (acc, product) => ({ amount: acc.amount + product.selectedCount, subtotal: acc.subtotal + product.selectedCount * product.price, }), { amount: 0, subtotal: 0 } ) }, [allVariantProducts]) function resetQuantityItems() { setAllVariantProducts((prev) => prev.map((item) => ({ ...item, selectedCount: 0 })) ) } function onClose() { resetQuantityItems() setIsOpen(false) } function handleAddToCart(e: React.MouseEvent) { buyButtonOnClick(e) onClose() } const totalColumnsSkeletonLength = Object.keys(columns).filter((v) => v !== 'additionalColumns').length + (columns.additionalColumns?.length ?? 0) return (

{title}

{children} {columns.name} {columns.additionalColumns?.map(({ label, value }) => ( {label} ))} {columns.availability.label} {columns.price} {columns.quantitySelector} {loading ? ( <> {Array.from({ length: 5 }).map((_, index) => { return ( {Array.from({ length: totalColumnsSkeletonLength, }).map((_, index) => { return ( ) })} ) })} ) : ( <> {allVariantProducts.map((variantProduct) => ( {variantProduct.name} {columns.additionalColumns?.map(({ value }) => ( {variantProduct.specifications[value.toLowerCase()]} ))} {columns.availability.stockDisplaySettings === 'showAvailability' && ( {variantProduct.availability === 'outOfStock' ? 'Out of stock' : 'Available'} )} {columns.availability.stockDisplaySettings === 'showStockQuantity' && variantProduct.inventory}
onChangeQuantityItem(variantProduct.id, value) } onValidateBlur={( min: number, maxValue: number, quantity: number ) => { pushToast({ title: invalidQuantityToastLabels?.title, message: invalidQuantityToastLabels?.message ?.replace('%{min}', min.toString()) ?.replace('%{max}', maxValue.toString()) ?.replace('%{quantity}', quantity.toString()) || '', status: 'INFO', icon: ( ), }) }} />
))} )}
) } export default SKUMatrixSidebar