-
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.
Merge pull request #16 from deco-sites/karla-tec3
feat: search page
- Loading branch information
Showing
10 changed files
with
697 additions
and
228 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,3 @@ | ||
{ | ||
"__resolveType": "site/sections/SearchText.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,114 @@ | ||
{ | ||
"name": "CATEGORIA EXEMPLO", | ||
"path": "/example", | ||
"sections": [ | ||
{ | ||
"__resolveType": "website/sections/Rendering/Lazy.tsx", | ||
"section": { | ||
"__resolveType": "commerce/sections/Seo/SeoPLPV2.tsx", | ||
"jsonLD": { | ||
"__resolveType": "vnda/loaders/productListingPage.ts", | ||
"count": 16, | ||
"tags": [], | ||
"filterOperator": { | ||
"type_tags": "and", | ||
"property1": "and", | ||
"property2": "and", | ||
"property3": "and" | ||
}, | ||
"slug": { | ||
"__resolveType": "website/functions/requestToParam.ts", | ||
"param": "slug" | ||
} | ||
} | ||
} | ||
}, | ||
{ | ||
"__resolveType": "website/sections/Rendering/Lazy.tsx", | ||
"section": { | ||
"__resolveType": "Header" | ||
} | ||
}, | ||
{ | ||
"__resolveType": "website/sections/Rendering/Lazy.tsx", | ||
"section": { | ||
"__resolveType": "site/sections/WideBanner.tsx", | ||
"images": { | ||
"desktop": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/9d9003ed-0705-43dd-8ea5-201a4a4969ad/quem-somos-banner.png", | ||
"mobile": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/9d9003ed-0705-43dd-8ea5-201a4a4969ad/quem-somos-banner.png" | ||
}, | ||
"alt": "categoria" | ||
} | ||
}, | ||
{ | ||
"__resolveType": "website/sections/Rendering/Lazy.tsx", | ||
"section": { | ||
"__resolveType": "site/sections/Product/SearchResult.tsx", | ||
"page": { | ||
"__resolveType": "vnda/loaders/productListingPage.ts", | ||
"count": 16, | ||
"tags": [], | ||
"filterOperator": { | ||
"type_tags": "and", | ||
"property1": "and", | ||
"property2": "and", | ||
"property3": "and" | ||
}, | ||
"slug": { | ||
"__resolveType": "website/functions/requestToParam.ts", | ||
"param": "slug" | ||
} | ||
}, | ||
"layout": { | ||
"columns": { | ||
"mobile": 2, | ||
"desktop": 4 | ||
}, | ||
"variant": "aside", | ||
"pagination": "pagination" | ||
}, | ||
"startingPage": 1, | ||
"button": [ | ||
{ | ||
"image": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/49d34224-85e1-448b-80ba-24361df54712/4blocks.svg" | ||
}, | ||
{ | ||
"image": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/d070e980-9aeb-4ead-9a1f-e6e64a76b8a2/6blocks.svg" | ||
}, | ||
{ | ||
"image": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/628f2b43-2164-499b-bf9c-27eaefc78ae6/8blocks.svg" | ||
} | ||
], | ||
"buttons": [ | ||
{ | ||
"icone": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/49d34224-85e1-448b-80ba-24361df54712/4blocks.svg" | ||
}, | ||
{ | ||
"icone": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/d070e980-9aeb-4ead-9a1f-e6e64a76b8a2/6blocks.svg" | ||
}, | ||
{ | ||
"icone": "https://deco-sites-assets.s3.sa-east-1.amazonaws.com/arena-center/628f2b43-2164-499b-bf9c-27eaefc78ae6/8blocks.svg" | ||
} | ||
] | ||
} | ||
}, | ||
{ | ||
"__resolveType": "website/sections/Rendering/Lazy.tsx", | ||
"section": { | ||
"__resolveType": "site/sections/SearchText.tsx", | ||
"description": "<p><strong>Lorem Ipsum</strong> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.</p>", | ||
"title": "Lorem Ipsum" | ||
} | ||
}, | ||
{ | ||
"__resolveType": "website/sections/Rendering/Lazy.tsx", | ||
"section": { | ||
"__resolveType": "Footer" | ||
} | ||
} | ||
], | ||
"seo": { | ||
"__resolveType": "website/sections/Seo/SeoV2.tsx" | ||
}, | ||
"__resolveType": "website/pages/Page.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
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,233 @@ | ||
import type { Product } from "apps/commerce/types.ts"; | ||
import { mapProductToAnalyticsItem } from "apps/commerce/utils/productToAnalyticsItem.ts"; | ||
import Image from "apps/website/components/Image.tsx"; | ||
import { clx } from "../../sdk/clx.ts"; | ||
import { formatPrice } from "../../sdk/format.ts"; | ||
import { relative } from "../../sdk/url.ts"; | ||
import { useOffer } from "../../sdk/useOffer.ts"; | ||
import { useSendEvent } from "../../sdk/useSendEvent.ts"; | ||
import { useVariantPossibilities } from "../../sdk/useVariantPossiblities.ts"; | ||
import WishlistButton from "../wishlist/WishlistButton.tsx"; | ||
import AddToCartButton from "./AddToCartButton.tsx"; | ||
import { Ring } from "./ProductVariantSelector.tsx"; | ||
import { useId } from "../../sdk/useId.ts"; | ||
|
||
interface Props { | ||
product: Product; | ||
/** Preload card image */ | ||
preload?: boolean; | ||
|
||
/** @description used for analytics event */ | ||
itemListName?: string; | ||
|
||
/** @description index of the product card in the list */ | ||
index?: number; | ||
|
||
class?: string; | ||
} | ||
|
||
const WIDTH = 295; | ||
const HEIGHT = 378; | ||
const ASPECT_RATIO = `${WIDTH} / ${HEIGHT}`; | ||
|
||
function ProductCard({ | ||
product, | ||
preload, | ||
itemListName, | ||
index, | ||
class: _class, | ||
}: Props) { | ||
const id = useId(); | ||
|
||
const { url, image: images, offers, isVariantOf } = product; | ||
const hasVariant = isVariantOf?.hasVariant ?? []; | ||
const title = isVariantOf?.name ?? product.name; | ||
const [front, back] = images ?? []; | ||
|
||
const { listPrice, price, seller = "1", availability } = useOffer(offers); | ||
const inStock = availability === "https://schema.org/InStock"; | ||
const possibilities = useVariantPossibilities(hasVariant, product); | ||
const firstSkuVariations = Object.entries(possibilities)?.[0]; | ||
const variants = Object.entries(firstSkuVariations?.[1] ?? {}); | ||
const relativeUrl = relative(url); | ||
const percent = listPrice && price | ||
? Math.round(((listPrice - price) / listPrice) * 100) | ||
: 0; | ||
|
||
const item = mapProductToAnalyticsItem({ product, price, listPrice, index }); | ||
|
||
{/* Add click event to dataLayer */} | ||
const event = useSendEvent({ | ||
on: "click", | ||
event: { | ||
name: "select_item" as const, | ||
params: { | ||
item_list_name: itemListName, | ||
items: [item], | ||
}, | ||
}, | ||
}); | ||
|
||
//Added it to check the variant name in the SKU Selector later, so it doesn't render the SKU to "shoes size" in the Product Card | ||
const firstVariantName = firstSkuVariations?.[0]?.toLowerCase(); | ||
const shoeSizeVariant = "shoe size"; | ||
|
||
return ( | ||
<div | ||
{...event} | ||
class={clx( | ||
"card card-compact group text-sm min-w-[295px] min-h-[498px]", | ||
_class | ||
)} | ||
> | ||
<figure | ||
class={clx( | ||
"relative bg-base-100 min-w-[295px] min-h-[498px]", | ||
"rounded border border-transparent", | ||
"group-hover:border-primary" | ||
)} | ||
style={{ aspectRatio: ASPECT_RATIO }} | ||
> | ||
{/* Product Images */} | ||
<a | ||
href={relativeUrl} | ||
aria-label="view product" | ||
class={clx( | ||
"absolute top-0 left-0", | ||
"grid grid-cols-1 grid-rows-1", | ||
"w-full", | ||
!inStock && "opacity-70" | ||
)} | ||
> | ||
<Image | ||
src={front.url!} | ||
alt={front.alternateName} | ||
width={295} | ||
height={378} | ||
style={{ aspectRatio: ASPECT_RATIO }} | ||
class={clx( | ||
"object-contain", | ||
"rounded w-full", | ||
"col-span-full row-span-full" | ||
)} | ||
preload={preload} | ||
loading={preload ? "eager" : "lazy"} | ||
decoding="async" | ||
/> | ||
<Image | ||
src={back?.url ?? front.url!} | ||
alt={back?.alternateName ?? front.alternateName} | ||
width={295} | ||
height={378} | ||
style={{ aspectRatio: ASPECT_RATIO }} | ||
class={clx( | ||
"object-contain", | ||
"rounded w-full", | ||
"col-span-full row-span-full", | ||
"transition-opacity opacity-0 lg:group-hover:opacity-100" | ||
)} | ||
loading="lazy" | ||
decoding="async" | ||
/> | ||
</a> | ||
|
||
{/* Wishlist button */} | ||
{/* <div class="absolute top-0 left-0 w-full flex items-center justify-between"> | ||
<span | ||
class={clx( | ||
"text-sm/4 font-normal text-black bg-error bg-opacity-15 text-center rounded-badge px-2 py-1", | ||
inStock && "opacity-0" | ||
)} | ||
> | ||
Notify me | ||
</span> | ||
</div> */} | ||
|
||
{/* Discounts */} | ||
<span | ||
class={clx( | ||
"absolute top-2 left-2", | ||
"text-[12px] font-normal text-base-100 bg-primary text-center rounded-[4px] px-2 py-1", | ||
(percent < 1 || !inStock) && "opacity-0" | ||
)} | ||
> | ||
{percent} % off | ||
</span> | ||
|
||
{/* <div class="absolute bottom-0 right-0"> | ||
<WishlistButton item={item} variant="icon" /> | ||
</div> */} | ||
</figure> | ||
|
||
<a href={relativeUrl} class="pt-4"> | ||
<span class="font-medium text-sm">{title}</span> | ||
|
||
<div class="flex gap-2 pt-2"> | ||
{listPrice && ( | ||
<span class="line-through font-normal text-gray-600 text-[10px]"> | ||
{formatPrice(listPrice, offers?.priceCurrency)} | ||
</span> | ||
)} | ||
<span class="font-semibold text-secondary text-[12px]"> | ||
{formatPrice(price, offers?.priceCurrency)} | ||
</span> | ||
</div> | ||
</a> | ||
|
||
{/* SKU Selector */} | ||
{/* {variants.length > 1 && firstVariantName !== shoeSizeVariant && ( | ||
<ul class="flex items-center justify-start gap-2 pt-4 pb-1 pl-1 overflow-x-auto"> | ||
{variants | ||
.map(([value, link]) => [value, relative(link)] as const) | ||
.map(([value, link]) => ( | ||
<li> | ||
<a href={link} class="cursor-pointer"> | ||
<input | ||
class="hidden peer" | ||
type="radio" | ||
name={`${id}-${firstSkuVariations?.[0]}`} | ||
checked={link === relativeUrl} | ||
/> | ||
<Ring value={value} checked={link === relativeUrl} /> | ||
</a> | ||
</li> | ||
))} | ||
</ul> | ||
)} */} | ||
|
||
<div class="flex-grow" /> | ||
|
||
<div> | ||
{inStock ? ( | ||
<AddToCartButton | ||
product={product} | ||
seller={seller} | ||
item={item} | ||
class={clx( | ||
"btn", | ||
"btn-outline justify-center border-gray-300 !text-sm !font-medium px-0 no-animation w-full", | ||
"hover:!bg-primary", | ||
"hover:!text-base-100" | ||
)} | ||
/> | ||
) : ( | ||
<a | ||
href={relativeUrl} | ||
class={clx( | ||
"btn", | ||
"btn-outline justify-start border-none !text-sm !font-medium px-0 no-animation w-full h-29", | ||
"hover:!bg-transparent", | ||
"disabled:!bg-transparent disabled:!opacity-75", | ||
"btn-error hover:!text-error disabled:!text-error" | ||
)} | ||
> | ||
Fora de estoque | ||
</a> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default ProductCard; |
Oops, something went wrong.