-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
…enh facets system (#60) * [email protected], [email protected], [email protected] Cmmc: FacetValueDesc is now nested enh: AddToCartWidget: hover and sizing enh: radio selector now (optionally) shows quantities impl: SelectCategoryItemCard SelectCategoryItemCard; widget / card / panel naming Category has optional parentTitle renamed several key components according to new "widget" / "card" / "panel" system impl and moved BuyItem<Button|Card|Pupop> to here (from client project) Final styling and layout for buy popup minor tree cleanup changed mobx-utils to peerDep minor changes to service function names
- Loading branch information
1 parent
4c57bc5
commit 6ccc6c8
Showing
63 changed files
with
821 additions
and
452 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 0 additions & 13 deletions
13
packages/commerce/blocks/components/commerce-cat-and-item-block.tsx
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
'use client' | ||
import React, {type PropsWithChildren} from 'react' | ||
|
||
import { type ButtonVariants, type ButtonSizes, Button } from '@hanzo/ui/primitives' | ||
|
||
import BuyItemPopup from './buy-item-popup' | ||
|
||
const BuyItemButton: React.FC<PropsWithChildren & { | ||
skuPath: string | ||
variant? : ButtonVariants | ||
size?: ButtonSizes | ||
/* rounded?: ButtonRounded // wait for version bump*/ | ||
className?: string | ||
popupClx?: string | ||
}> = ({ | ||
skuPath, | ||
variant, | ||
size, | ||
children, | ||
className='', | ||
popupClx='' | ||
}) => ( | ||
<BuyItemPopup skuPath={skuPath} popupClx={popupClx}> | ||
<Button size={size} variant={variant} className={className}>{children}</Button> | ||
</BuyItemPopup> | ||
) | ||
|
||
export default BuyItemButton |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
'use client' | ||
import React, { useRef, useEffect } from 'react' | ||
import { autorun } from 'mobx' | ||
import { observer } from 'mobx-react-lite' | ||
|
||
import { cn } from '@hanzo/ui/util' | ||
|
||
import type { FacetsValue } from '../../types' | ||
import { useCommerce } from '../../service/context' | ||
import { getFacetValuesMutator } from '../../util' | ||
import FacetValuesWidget from '../facet-values-widget' | ||
import SelectCategoryItemCard from './select-category-item-card' | ||
|
||
|
||
const BuyItemCard: React.FC<{ | ||
skuPath: string | ||
className?: string | ||
}> = observer(({ | ||
skuPath, | ||
className='' | ||
}) => { | ||
|
||
const cmmc = useCommerce() | ||
const levelRef = useRef<number>(-1) | ||
|
||
const cat = cmmc.getCategory(skuPath) | ||
const facets = cat ? undefined : cmmc.getFacetValuesAtSkuPath(skuPath) | ||
|
||
useEffect(() => { | ||
|
||
if (facets) { | ||
const toks = skuPath.split('-') | ||
const levelSpecified = toks.length - 1 | ||
const fsv: FacetsValue = {} | ||
for (let level = 1; level <= levelSpecified; level++ ) { | ||
fsv[level] = [toks[level]] | ||
} | ||
fsv[levelSpecified + 1] = [facets[0].value] | ||
levelRef.current = levelSpecified | ||
cmmc.setFacets(fsv) | ||
} | ||
return autorun(() => { | ||
const cats = cmmc.specifiedCategories | ||
// Original cat was legit | ||
if (cat && (cats.length === 0 || cats[0].id !== cat.id)) { | ||
if (!cmmc.currentItem || cmmc.currentItem.categoryId !== cat.id) { | ||
cmmc.setCurrentItem(cat.products[0].sku) | ||
} | ||
} | ||
else if (cats.length > 0) { | ||
if (!cmmc.currentItem || cmmc.currentItem.categoryId !== cats[0].id) { | ||
cmmc.setCurrentItem(cats[0].products[0].sku) | ||
} | ||
} | ||
}) | ||
}, [cat, facets]) | ||
|
||
return ( | ||
<div className={className} > | ||
{facets && levelRef.current > 0 && ( | ||
<FacetValuesWidget | ||
className={cn('grid gap-0 ' + `grid-cols-${facets.length}` + ' self-start ', 'border-b mb-2 -mr-2 -ml-2')} | ||
isMobile={false} | ||
mutator={getFacetValuesMutator(levelRef.current + 1, cmmc)} | ||
itemClx='flex-col h-auto gap-0 pb-1 pt-3 px-3' | ||
buttonClx='h-auto !rounded-bl-none !rounded-br-none !rounded-tl-lg !rounded-tr-lg ' | ||
facetValues={facets} | ||
/> | ||
)} | ||
{cmmc.specifiedCategories[0] && ( | ||
<SelectCategoryItemCard | ||
noTitle | ||
category={cmmc.specifiedCategories[0]} | ||
selectedItemRef={cmmc /* ...conveniently. :) */ } | ||
selectSku={cmmc.setCurrentItem.bind(cmmc)} | ||
/> | ||
)} | ||
</div > | ||
) | ||
}) | ||
|
||
export default BuyItemCard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use client' | ||
import React, {type PropsWithChildren} from 'react' | ||
|
||
import { X } from 'lucide-react' | ||
|
||
import { | ||
Popover, | ||
PopoverContent, | ||
PopoverTrigger, | ||
PopoverClose | ||
} from "@hanzo/ui/primitives" | ||
|
||
import { cn } from '@hanzo/ui/util' | ||
|
||
import BuyItemCard from './buy-item-card' | ||
|
||
const BuyItemPopup: React.FC<PropsWithChildren & { | ||
skuPath: string | ||
popupClx?: string | ||
cardClx?: string | ||
}> = ({ | ||
skuPath, | ||
children, | ||
popupClx='', | ||
cardClx='', | ||
}) => ( | ||
<Popover> | ||
<PopoverTrigger asChild> | ||
{children} | ||
</PopoverTrigger> | ||
<PopoverContent className={cn('relative flex flex-col p-0 px-4 pb-4 pt-2', popupClx)}> | ||
<PopoverClose className='absolute z-20 right-2 top-2 self-end hover:bg-level-3 text-muted hover:text-accent p-1 rounded-full'><X className='w-5 h-5'/></PopoverClose> | ||
<BuyItemCard skuPath={skuPath} className={cn("w-full relative ", cardClx)}/> | ||
</PopoverContent> | ||
</Popover> | ||
) | ||
|
||
export default BuyItemPopup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
packages/commerce/components/buy-item/select-category-item-card.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
'use client' | ||
import React from 'react' | ||
import { observer } from 'mobx-react-lite' | ||
|
||
import { cn } from '@hanzo/ui/util' | ||
import { Skeleton } from '@hanzo/ui/primitives' | ||
|
||
import type { ItemSelector, LineItem } from '../../types' | ||
|
||
import AddToCartWidget from '../add-to-cart-widget' | ||
import CategoryItemRadioSelector from '../category-item-radio-selector' | ||
import CategoryItemIOSWheelSelector from '../category-item-ios-wheel-selector' | ||
import { formatPrice } from '../../util' | ||
|
||
const SelectCategoryItemCard: React.FC<React.HTMLAttributes<HTMLDivElement> & ItemSelector & { | ||
isLoading?: boolean | ||
mobile?: boolean | ||
noTitle?: boolean | ||
}> = /* NOT observer */({ | ||
category, | ||
selectedItemRef: selItemRef, | ||
selectSku, | ||
className, | ||
isLoading = false, | ||
mobile = false, | ||
noTitle = false, | ||
...props | ||
}) => { | ||
|
||
const soleOption = category.products.length === 1 | ||
|
||
const SelectProductComp: React.FC<{ className?: string }> = ({ className = '' }) => { | ||
|
||
if (soleOption) { | ||
const item = category.products[0] as LineItem | ||
return ( | ||
<p >{item.titleAsOption + ', ' + formatPrice(item.price) + (item.quantity > 0 ? `(${item.quantity})` : '')}</p> | ||
) | ||
} | ||
const mobilePicker = (mobile && category.products.length > 6) | ||
|
||
return ( | ||
<div /* id='CV_AVAIL_AMOUNTS' */ className={cn( | ||
'sm:w-pr-80 sm:mx-auto md:w-full flex flex-col justify-start items-center', | ||
className | ||
)}> | ||
{!noTitle && (<div className={'h-[1px] bg-muted-3 ' + (mobilePicker ? 'w-pr-55' : 'w-pr-60') } /> )} | ||
{mobilePicker ? ( | ||
<CategoryItemIOSWheelSelector | ||
category={category} | ||
selectedItemRef={selItemRef} | ||
selectSku={selectSku} | ||
height={180} | ||
itemHeight={30} | ||
outerClx='mb-4' | ||
/> | ||
) : ( | ||
<CategoryItemRadioSelector | ||
category={category} | ||
selectedItemRef={selItemRef} | ||
selectSku={selectSku} | ||
groupClx='mt-2' | ||
itemClx='flex flex-row gap-2.5 items-center' | ||
/> | ||
)} | ||
</div> | ||
) | ||
} | ||
|
||
const AddToCartComp: React.FC<{ className?: string }> = observer(({ className = '' }) => ( | ||
// TODO disable if nothing selected | ||
(selItemRef.item && !isLoading) && ( | ||
<AddToCartWidget size='default' item={selItemRef.item} className={cn('lg:min-w-[160px] lg:mx-auto', className)}/> | ||
) | ||
)) | ||
|
||
const TitleArea: React.FC<{ className?: string }> = observer(({ className = '' }) => ( | ||
|
||
isLoading ? (<Skeleton className={'h-8 w-full ' + className} />) : ( | ||
|
||
<div className={cn('text-center flex flex-col justify-start items-center', className)}> | ||
<p className='font-nav text-center'>{category.title}</p> | ||
</div> | ||
|
||
))) | ||
|
||
return mobile ? ( | ||
<div /* id='CV_OUTER' */ | ||
className={cn( | ||
'w-full h-[calc(100svh-96px)] max-h-[700px] flex flex-col justify-between ' + | ||
'items-stretch gap-[4vh] mt-[2vh] pb-[6vh]', | ||
className | ||
)} | ||
{...props} | ||
> | ||
{!noTitle && (<TitleArea className='grow pt-3 mb-0' />)} | ||
<SelectProductComp className='mb-[3vh]' /> | ||
<AddToCartComp className='w-pr-70 mx-auto' /> | ||
</div> | ||
) : ( | ||
<div className={cn('', className)} {...props}> | ||
{!noTitle && (<TitleArea className='' />)} | ||
<div className='flex flex-col justify-start items-center gap-4'> | ||
<SelectProductComp /> | ||
<AddToCartComp className='' /> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default SelectCategoryItemCard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.