generated from deco-sites/storefront
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: BuyTogether section implemented
- Loading branch information
1 parent
156936d
commit 2e285b3
Showing
12 changed files
with
339 additions
and
35 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import Button from "$store/components/ui/Button.tsx"; | ||
import { sendEvent } from "$store/sdk/analytics.tsx"; | ||
import { useUI } from "$store/sdk/useUI.ts"; | ||
import { AddToCartParams } from "apps/commerce/types.ts"; | ||
import { useState } from "preact/hooks"; | ||
|
||
export interface Props { | ||
/** @description: sku name */ | ||
eventParams: AddToCartParams; | ||
onAddItem: () => Promise<void>; | ||
} | ||
|
||
const useAddToCart = ({ eventParams, onAddItem }: Props) => { | ||
const [loading, setLoading] = useState(false); | ||
const { displayCart } = useUI(); | ||
|
||
const onClick = async (e: MouseEvent) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
|
||
try { | ||
setLoading(true); | ||
|
||
await onAddItem(); | ||
|
||
sendEvent({ | ||
name: "add_to_cart", | ||
params: eventParams, | ||
}); | ||
|
||
displayCart.value = true; | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
return { onClick, loading, "data-deco": "add-to-cart" }; | ||
}; | ||
|
||
export default function AddToCartButton(props: Props) { | ||
const btnProps = useAddToCart(props); | ||
|
||
return ( | ||
<Button | ||
{...btnProps} | ||
class="max-w-[250px] h-[60px] rounded bg-green hover:bg-green/90 border border-green drop-shadow transition-all duration-150 text-white-normal font-bold text-lg leading-5" | ||
> | ||
Comprar Junto | ||
</Button> | ||
); | ||
} |
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,18 @@ | ||
import { useCart } from "apps/vtex/hooks/useCart.ts"; | ||
import Button, { Props as BtnProps } from "./common.tsx"; | ||
|
||
export interface Props extends Omit<BtnProps, "onAddItem"> { | ||
products: Array<{ seller: string; id: string; quantity: number }>; | ||
} | ||
|
||
function AddToCartButton({ products, eventParams }: Props) { | ||
const { addItems } = useCart(); | ||
const onAddItem = () => | ||
addItems({ | ||
orderItems: products, | ||
}); | ||
|
||
return <Button onAddItem={onAddItem} eventParams={eventParams} />; | ||
} | ||
|
||
export default AddToCartButton; |
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,110 @@ | ||
import { useMemo } from "preact/hooks"; | ||
import Icon from "deco-sites/maconequiio/components/ui/Icon.tsx"; | ||
import Card from "./Card.tsx"; | ||
import AddToCartButtonVTEX from "$store/islands/AddToCartButton/BuyTogether/vtex.tsx"; | ||
|
||
import { useOffer } from "$store/sdk/useOffer.ts"; | ||
import { formatPrice } from "deco-sites/maconequiio/sdk/format.ts"; | ||
|
||
import type { Product } from "apps/commerce/types.ts"; | ||
|
||
export interface Props { | ||
products: Product[] | null; | ||
} | ||
|
||
export default function BuyTogether({ products }: Props) { | ||
if (!products || products.length === 0) return null; | ||
|
||
const othersProducts = useMemo( | ||
() => products.filter((_, index) => index !== 0), | ||
[products], | ||
); | ||
|
||
if (!othersProducts || othersProducts.length === 0) return null; | ||
|
||
const productsOffers = useMemo( | ||
() => products.map((item) => item.offers?.lowPrice ?? 0), | ||
[products], | ||
); | ||
const totalPrice = useMemo( | ||
() => productsOffers.reduce((acc, price) => acc + price, 0), | ||
[productsOffers], | ||
); | ||
|
||
const cartProducts = useMemo(() => | ||
products.map((product) => { | ||
const { seller = "1" } = useOffer(product.offers); | ||
return { | ||
id: product.productID, | ||
seller, | ||
quantity: 1, | ||
}; | ||
}), [products]); | ||
|
||
const eventParams = useMemo(() => | ||
products.map((item) => ({ | ||
item_id: item.productID, | ||
item_name: item.isVariantOf?.name || item.name, | ||
quantity: 1, | ||
})), [products]); | ||
|
||
return ( | ||
<div class="flex items-center justify-center my-12 py-6 px-4 xl:px-0 bg-white-ice"> | ||
<div class="flex items-center gap-7 xl:max-w-full xl:mx-auto"> | ||
<div class="flex flex-col gap-2.5"> | ||
<h2 class="text-black-neutral font-bold text-xl leading-6"> | ||
Você está vendo | ||
</h2> | ||
<Card product={products[0]} /> | ||
</div> | ||
<Icon | ||
id="PlusNew" | ||
width={24} | ||
height={23} | ||
strokeWidth={2} | ||
class="text-green" | ||
/> | ||
<div class="flex flex-col gap-2.5"> | ||
<h2 class="text-black-neutral font-bold text-xl leading-6"> | ||
Compre junto | ||
</h2> | ||
<div class="flex items-center justify-between gap-7"> | ||
{othersProducts.map((product, index) => ( | ||
<> | ||
<Card product={product} hasViewProductLink={true} /> | ||
{index !== othersProducts.length - 1 && ( | ||
<Icon | ||
id="PlusNew" | ||
width={24} | ||
height={23} | ||
strokeWidth={2} | ||
class="text-green" | ||
/> | ||
)} | ||
</> | ||
))} | ||
<Icon | ||
id="Equals" | ||
width={20} | ||
height={17} | ||
strokeWidth={2} | ||
class="text-green" | ||
/> | ||
</div> | ||
</div> | ||
<div class="flex flex-col gap-4 items-center justify-center text-center"> | ||
<div class="flex flex-col gap-0"> | ||
<h2 class="text-lg text-black-neutral">Compre estes produtos</h2> | ||
<span class="text-lg text-black-neutral font-bold"> | ||
por {formatPrice(totalPrice)} | ||
</span> | ||
</div> | ||
<AddToCartButtonVTEX | ||
products={cartProducts} | ||
eventParams={{ items: eventParams }} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
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,88 @@ | ||
import Image from "apps/website/components/Image.tsx"; | ||
|
||
import { useOffer } from "$store/sdk/useOffer.ts"; | ||
import { relative } from "$store/sdk/url.ts"; | ||
import { formatPrice } from "$store/sdk/format.ts"; | ||
|
||
import type { Product } from "apps/commerce/types.ts"; | ||
|
||
export interface Props { | ||
product: Product; | ||
hasViewProductLink?: boolean; | ||
} | ||
|
||
const WIDTH = 183; | ||
const HEIGHT = 183; | ||
|
||
export default function BuyTogetherCard( | ||
{ product, hasViewProductLink = false }: Props, | ||
) { | ||
const { url, name, image: images, offers } = product; | ||
const [front] = images ?? []; | ||
const { listPrice, price } = useOffer(offers); | ||
|
||
const discount = Math.round( | ||
(((listPrice ?? 0) - (price ?? 0)) / (listPrice ?? 0)) * 100, | ||
); | ||
|
||
return ( | ||
<div class="flex flex-col rounded w-[218px] h-[344px] bg-white-normal border border-[#BEBEBE] p-3"> | ||
<figure | ||
class="relative" | ||
style={{ aspectRatio: `${WIDTH} / ${HEIGHT}` }} | ||
> | ||
<div class="absolute top-2 z-10 flex items-center left-1/2"> | ||
<div class=""></div> | ||
</div> | ||
|
||
{/* Product Images */} | ||
<div class="grid grid-cols-1 grid-rows-1 w-full"> | ||
<Image | ||
src={front.url!} | ||
alt={front.alternateName} | ||
width={WIDTH} | ||
height={HEIGHT} | ||
class="col-span-full row-span-full rounded w-full" | ||
sizes="(max-width: 640px) 50vw, 20vw" | ||
loading="lazy" | ||
decoding="async" | ||
/> | ||
</div> | ||
</figure> | ||
|
||
<div class="flex flex-col gap-1 pt-3 border-t border-t-white-base h-full justify-between"> | ||
<h2 | ||
class="line-clamp-3 text-sm text-black-neutral uppercase font-medium leading-4" | ||
dangerouslySetInnerHTML={{ __html: name ?? "" }} | ||
/> | ||
|
||
{hasViewProductLink && ( | ||
<a | ||
href={url && relative(url)} | ||
class="underline text-red text-sm font-medium" | ||
> | ||
{"Ver produto >"} | ||
</a> | ||
)} | ||
|
||
<div class="flex w-full items-center justify-between gap-2"> | ||
<div class="flex flex-col gap-0.5"> | ||
<div class="line-through text-gray-base text-xs leading-3"> | ||
de: {formatPrice(listPrice, offers?.priceCurrency)} | ||
</div> | ||
|
||
<div class="text-black-neutral text-sm font-bold leading-4"> | ||
por: {formatPrice(price, offers?.priceCurrency)} | ||
</div> | ||
</div> | ||
|
||
{discount > 0 && ( | ||
<div class="flex items-center justify-center text-xs leading-3 font-bold bg-red-light text-white-normal w-10 h-8 p-0.5 rounded-tl-2xl rounded-br-2xl"> | ||
-{discount}% | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
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
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,8 @@ | ||
import Component from "$store/components/product/BuyTogether/AddToCartButton/vtex.tsx"; | ||
import type { Props } from "$store/components/product/BuyTogether/AddToCartButton/vtex.tsx"; | ||
|
||
function Island(props: Props) { | ||
return <Component {...props} />; | ||
} | ||
|
||
export default Island; |
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.