Untitled
unknown
javascript
a year ago
7.3 kB
8
Indexable
// route.tsx
export async function loader({ params, context, request }: LoaderArgs) {
const { handle } = params;
const url = new URL(request.url);
let category: any = [];
try {
const [reqCollection, reqVideo] = await Promise.all([
fetchAPI('/api/shopify/custom-menu-metaobject', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
first: 26,
type: 'custom_menu',
handle,
language: params.language ? params.language.toUpperCase() : 'IT',
country: 'IT',
}),
}, context, request),
fetchAPI('/api/shopify/metaobjects-new', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
first: 26,
type: 'custom_menu',
language: params.language ? params.language.toUpperCase() : 'IT',
country: 'IT',
}),
}, context, request),
]);
if (reqVideo.status == 200) {
const metaobject: MetaobjectResponse = await reqVideo.json() as MetaobjectResponse;
const categoryData = metaobject.metaobjects.edges.find(
(el) => el.node.handle === handle,
);
category = categoryData?.node || [];
} else {
throw new Response(null, { status: 404, statusText: 'Not Found' });
}
if (reqCollection.status == 200) {
const check: any = await reqCollection.json();
if (check) {
const categoryWithCollections = {
...category,
fields: [
...category.fields.filter((el: any) => el.key !== 'collection'),
{ ...check?.fields?.find((item: any) => item.key === 'collection') },
],
};
category = categoryWithCollections;
}
} else {
throw new Error(`Error fetching collection: ${reqCollection.statusText}`);
}
} catch (error) {
console.error(error);
throw new Error('E101: Errore nel recuperare le informazioni.');
}
return defer({ category });
}
const ListingPage = () => {
const {category} = useLoaderData<typeof loader>();
const valuesRef = useRef<null | {
memoizedFields: MemoizedFields;
products: TProductInfo[];
hasVideo: boolean;
}>(null);
if (valuesRef.current === null) {
const getField = (key: string) => category.fields.find((e: any) => e.key === key);
const fields = {
titolo_menu: getField('titolo_menu'),
video: getField('video'),
video_mobile: getField('video_mobile'),
titolo_pagina: getField('titolo'),
titolo_lista: getField('titolo_lista'),
descrizione_pagina: getField('descrizione'),
collection: getField('collection'),
};
valuesRef.current = {
memoizedFields: fields,
products: fields.collection?.reference?.products?.nodes || [],
hasVideo: Boolean(fields.video?.reference?.sources?.[0]?.url)
};
}
const { memoizedFields, products, hasVideo } = valuesRef.current;
useSendGAEvent(EventNames.ViewItemList, {
item_list_id: memoizedFields.titolo_lista?.value ?? 'custom menu products',
items: products,
});
return (
<div className="w-full bg-background" data-element="preferiti-di-cristina-listing-page">
<div className="container-site mx-auto relative">
{memoizedFields.titolo_pagina && <PageHeaderListingPage memoizedFields={memoizedFields} hasVideo={hasVideo} category={category} />}
<ProductListListingPage products={products} titolo_lista={memoizedFields.titolo_lista} />
</div>
</div>
);
};
export default ListingPage;
// PageHeader.tsx
interface PageHeaderProps {
memoizedFields: MemoizedFields;
hasVideo: boolean;
category: { handle: string };
}
const PageHeaderListingPage: React.FC<PageHeaderProps> = React.memo(({ memoizedFields, hasVideo, category }) => (
<div className="w-full pb-10" data-element="preferiti-di-cristina-page-header">
<Breadcrumb
items={[
{
label: memoizedFields.titolo_menu?.value ?? '',
url: `/custom/${category.handle}`,
},
]}
/>
<div className="flex flex-col md:container md:mx-auto">
{memoizedFields.titolo_menu && (
<span className="md:hidden text-[14px] leading-[18px] font-bold text-rhodamine uppercase">
{memoizedFields.titolo_menu.value}
</span>
)}
<div className="flex flex-col md:flex-row items-center">
<ContentListingPage
memoizedFields={memoizedFields}
hasVideo={hasVideo}
className="order-2 md:order-1 flex-1 mb-4 md:mb-0"
/>
{hasVideo && memoizedFields.video && (
<VideoSectionListingPage
video={memoizedFields.video}
className="order-1 md:order-2 flex-1 my-3 md:my-0"
/>
)}
</div>
</div>
</div>
));
export default PageHeaderListingPage;
// Content.tsx
interface ContentProps {
memoizedFields: MemoizedFields;
hasVideo: boolean;
className?: string;
}
const ContentListingPage: React.FC<ContentProps> = React.memo(({ memoizedFields, hasVideo, className }) => (
<div
className={`flex flex-col gap-2 font-light pb-6 ${hasVideo ? 'md:max-w-[445px]' : ''} ${className}`}
data-element="preferiti-di-cristina-content"
>
{memoizedFields.titolo_menu && (
<span className="hidden md:block text-[14px] leading-[18px] font-bold text-rhodamine uppercase">
{memoizedFields.titolo_menu.value}
</span>
)}
{memoizedFields.titolo_pagina && <h3 className="bold">{memoizedFields.titolo_pagina.value}</h3>}
{memoizedFields.descrizione_pagina && (
<div
className="text-left"
dangerouslySetInnerHTML={{
__html: toHTML(memoizedFields.descrizione_pagina.value),
}}
></div>
)}
</div>
));
export default ContentListingPage;
// VideoSection.tsx
interface VideoSectionProps {
video: { reference: { sources: { url: string }[] } };
className?: string;
}
const VideoSectionListingPage: React.FC<VideoSectionProps> = React.memo(({ video, className }) => (
<div
className={`flex items-center justify-center mx-auto w-[320px] xxxs:w-[359px] md:w-[670px] ${className}`}
data-element="preferiti-di-cristina-video-section"
>
<ProductVideo
enabled={true}
video={video.reference.sources[0].url}
/>
</div>
));
export default VideoSectionListingPage;
// ProductList
interface ProductListProps {
products: TProductInfo[];
titolo_lista?: { value: string };
}
const ProductListListingPage: React.FC<ProductListProps> = React.memo(({ products, titolo_lista }) => (
<div className="container-account mx-auto" data-element="preferiti-di-cristina-product-list">
<div className="flex flex-col md:flex-row justify-between mt-6 mb-[120px]">
{products.length > 0 && (
<div>
{titolo_lista && <h4 className="mb-6">{titolo_lista.value}</h4>}
<div className="grid grid-cols-2 md:grid-cols-3 2xl:grid-cols-4 gap-4 justify-center items-center">
{products.map((product: TProductInfo) => (
<ProductCardNew key={product.id} product={product} />
))}
</div>
</div>
)}
</div>
</div>
));
export default ProductListListingPage;Editor is loading...
Leave a Comment