Created
August 18, 2021 16:38
-
-
Save IgorDePaula/548e78c83d0c7b3e38750b4951bb83b8 to your computer and use it in GitHub Desktop.
ProductPage.js
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
import React from 'react' | |
import {Fragment, useState, useEffect} from 'react' | |
import {Dialog, Disclosure, Popover, RadioGroup, Tab, Transition} from '@headlessui/react' | |
import {MenuIcon, SearchIcon, ShieldCheckIcon, ShoppingBagIcon, XIcon} from '@heroicons/react/outline' | |
import {CheckIcon, ChevronDownIcon, PlusSmIcon, QuestionMarkCircleIcon, StarIcon} from '@heroicons/react/solid' | |
import MainLayout from "../src/Layouts/Main"; | |
import {useTranslation} from "react-i18next"; | |
import {API} from 'aws-amplify' | |
import {listColors, listSizes, listCategories} from "../src/graphql/queries"; | |
const navigation = { | |
categories: [ | |
{ | |
id: 'women', | |
name: 'Women', | |
featured: [ | |
{ | |
name: 'New Arrivals', | |
href: '#', | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/mega-menu-category-01.jpg', | |
imageAlt: 'Models sitting back to back, wearing Basic Tee in black and bone.', | |
}, | |
{ | |
name: 'Basic Tees', | |
href: '#', | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/mega-menu-category-02.jpg', | |
imageAlt: 'Close up of Basic Tee fall bundle with off-white, ochre, olive, and black tees.', | |
}, | |
], | |
sections: [ | |
{ | |
id: 'clothing', | |
name: 'Clothing', | |
items: [ | |
{name: 'Tops', href: '#'}, | |
{name: 'Dresses', href: '#'}, | |
{name: 'Pants', href: '#'}, | |
{name: 'Denim', href: '#'}, | |
{name: 'Sweaters', href: '#'}, | |
{name: 'T-Shirts', href: '#'}, | |
{name: 'Jackets', href: '#'}, | |
{name: 'Activewear', href: '#'}, | |
{name: 'Browse All', href: '#'}, | |
], | |
}, | |
{ | |
id: 'accessories', | |
name: 'Accessories', | |
items: [ | |
{name: 'Watches', href: '#'}, | |
{name: 'Wallets', href: '#'}, | |
{name: 'Bags', href: '#'}, | |
{name: 'Sunglasses', href: '#'}, | |
{name: 'Hats', href: '#'}, | |
{name: 'Belts', href: '#'}, | |
], | |
}, | |
{ | |
id: 'brands', | |
name: 'Brands', | |
items: [ | |
{name: 'Full Nelson', href: '#'}, | |
{name: 'My Way', href: '#'}, | |
{name: 'Re-Arranged', href: '#'}, | |
{name: 'Counterfeit', href: '#'}, | |
{name: 'Significant Other', href: '#'}, | |
], | |
}, | |
], | |
}, | |
{ | |
id: 'men', | |
name: 'Men', | |
featured: [ | |
{ | |
name: 'New Arrivals', | |
href: '#', | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-04-detail-product-shot-01.jpg', | |
imageAlt: 'Drawstring top with elastic loop closure and textured interior padding.', | |
}, | |
{ | |
name: 'Artwork Tees', | |
href: '#', | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/category-page-02-image-card-06.jpg', | |
imageAlt: | |
'Three shirts in gray, white, and blue arranged on table with same line drawing of hands and shapes overlapping on front of shirt.', | |
}, | |
], | |
sections: [ | |
{ | |
id: 'clothing', | |
name: 'Clothing', | |
items: [ | |
{name: 'Tops', href: '#'}, | |
{name: 'Pants', href: '#'}, | |
{name: 'Sweaters', href: '#'}, | |
{name: 'T-Shirts', href: '#'}, | |
{name: 'Jackets', href: '#'}, | |
{name: 'Activewear', href: '#'}, | |
{name: 'Browse All', href: '#'}, | |
], | |
}, | |
{ | |
id: 'accessories', | |
name: 'Accessories', | |
items: [ | |
{name: 'Watches', href: '#'}, | |
{name: 'Wallets', href: '#'}, | |
{name: 'Bags', href: '#'}, | |
{name: 'Sunglasses', href: '#'}, | |
{name: 'Hats', href: '#'}, | |
{name: 'Belts', href: '#'}, | |
], | |
}, | |
{ | |
id: 'brands', | |
name: 'Brands', | |
items: [ | |
{name: 'Re-Arranged', href: '#'}, | |
{name: 'Counterfeit', href: '#'}, | |
{name: 'Full Nelson', href: '#'}, | |
{name: 'My Way', href: '#'}, | |
], | |
}, | |
], | |
}, | |
], | |
pages: [ | |
{name: 'Company', href: '#'}, | |
{name: 'Stores', href: '#'}, | |
], | |
} | |
const filters = [ | |
{ | |
id: 'category', | |
name: 'Category', | |
options: [ | |
{value: 'new-arrivals', label: 'All New Arrivals'}, | |
{value: 'tees', label: 'Tees'}, | |
{value: 'crewnecks', label: 'Crewnecks'}, | |
{value: 'sweatshirts', label: 'Sweatshirts'}, | |
{value: 'pants-shorts', label: 'Pants & Shorts'}, | |
], | |
}, | |
{ | |
id: 'sizes', | |
name: 'Sizes', | |
options: [ | |
{value: 'xs', label: 'XS'}, | |
{value: 's', label: 'S'}, | |
{value: 'm', label: 'M'}, | |
{value: 'l', label: 'L'}, | |
{value: 'xl', label: 'XL'}, | |
{value: '2xl', label: '2XL'}, | |
], | |
}, | |
] | |
const userNavigation = [ | |
{name: 'Sign in', href: '#'}, | |
{name: 'Create account', href: '#'}, | |
] | |
const product = { | |
name: 'Everyday Ruck Snack', | |
href: '#', | |
price: '220', | |
description: | |
"Don't compromise on snack-carrying capacity with this lightweight and spacious bag. The drawstring top keeps all your favorite chips, crisps, fries, biscuits, crackers, and cookies secure.", | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-04-featured-product-shot.jpg', | |
imageAlt: 'Light green canvas bag with black straps, handle, front zipper pouch, and drawstring top.', | |
breadcrumbs: [ | |
{id: 1, name: 'Travel', href: '#'}, | |
{id: 2, name: 'Bags', href: '#'}, | |
], | |
sizes: [ | |
{name: '18L', description: 'Perfect for a reasonable amount of snacks.'}, | |
{name: '20L', description: 'Enough room for a serious amount of snacks.'}, | |
], | |
} | |
const policies = [ | |
{ | |
name: 'Free delivery all year long', | |
description: | |
'Name another place that offers year long free delivery? We’ll be waiting. Order now and you’ll get delivery absolutely free.', | |
imageSrc: 'https://tailwindui.com/img/ecommerce/icons/icon-delivery-light.svg', | |
}, | |
{ | |
name: '24/7 Customer Support', | |
description: | |
'Or so we want you to believe. In reality our chat widget is powered by a naive series of if/else statements that churn out canned responses. Guaranteed to irritate.', | |
imageSrc: 'https://tailwindui.com/img/ecommerce/icons/icon-chat-light.svg', | |
}, | |
{ | |
name: 'Fast Shopping Cart', | |
description: | |
"Look at the cart in that icon, there's never been a faster cart. What does this mean for the actual checkout experience? I don't know.", | |
imageSrc: 'https://tailwindui.com/img/ecommerce/icons/icon-fast-checkout-light.svg', | |
}, | |
{ | |
name: 'Gift Cards', | |
description: | |
"We sell these hoping that you will buy them for your friends and they will never actually use it. Free money for us, it's great.", | |
imageSrc: 'https://tailwindui.com/img/ecommerce/icons/icon-gift-card-light.svg', | |
}, | |
] | |
const reviews = { | |
average: 4, | |
totalCount: 1624, | |
counts: [ | |
{rating: 5, count: 1019}, | |
{rating: 4, count: 162}, | |
{rating: 3, count: 97}, | |
{rating: 2, count: 199}, | |
{rating: 1, count: 147}, | |
], | |
featured: [ | |
{ | |
id: 1, | |
rating: 5, | |
content: ` | |
<p>This is the bag of my dreams. I took it on my last vacation and was able to fit an absurd amount of snacks for the many long and hungry flights.</p> | |
`, | |
author: 'Emily Selman', | |
avatarSrc: | |
'https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80', | |
}, | |
// More reviews... | |
], | |
} | |
const footerNavigation = { | |
products: [ | |
{name: 'Bags', href: '#'}, | |
{name: 'Tees', href: '#'}, | |
{name: 'Objects', href: '#'}, | |
{name: 'Home Goods', href: '#'}, | |
{name: 'Accessories', href: '#'}, | |
], | |
company: [ | |
{name: 'Who we are', href: '#'}, | |
{name: 'Sustainability', href: '#'}, | |
{name: 'Press', href: '#'}, | |
{name: 'Careers', href: '#'}, | |
{name: 'Terms & Conditions', href: '#'}, | |
{name: 'Privacy', href: '#'}, | |
], | |
customerService: [ | |
{name: 'Contact', href: '#'}, | |
{name: 'Shipping', href: '#'}, | |
{name: 'Returns', href: '#'}, | |
{name: 'Warranty', href: '#'}, | |
{name: 'Secure Payments', href: '#'}, | |
{name: 'FAQ', href: '#'}, | |
{name: 'Find a store', href: '#'}, | |
], | |
} | |
function classNames(...classes) { | |
return classes.filter(Boolean).join(' ') | |
} | |
const products = [ | |
{ | |
id: 1, | |
name: 'cobredon macio casal azul extra grande', | |
color: 'White and black', | |
href: '#', | |
rating: 5, | |
reviewCount: 38, | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-03-related-product-01.jpg', | |
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.', | |
price: '140', | |
}, { | |
id: 2, | |
name: 'Zip Tote Basket', | |
color: 'White and black', | |
href: '#', | |
rating: 5, | |
reviewCount: 38, | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-03-related-product-01.jpg', | |
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.', | |
price: '140', | |
}, { | |
id: 3, | |
name: 'Zip Tote Basket', | |
color: 'White and black', | |
href: '#', | |
rating: 5, | |
reviewCount: 38, | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-03-related-product-01.jpg', | |
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.', | |
price: '140', | |
}, { | |
id: 4, | |
name: 'Zip Tote Basket', | |
color: 'White and black', | |
href: '#', | |
rating: 5, | |
reviewCount: 38, | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-03-related-product-01.jpg', | |
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.', | |
price: '140', | |
}, { | |
id: 5, | |
name: 'Zip Tote Basket', | |
color: 'White and black', | |
href: '#', | |
rating: 5, | |
reviewCount: 38, | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-03-related-product-01.jpg', | |
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.', | |
price: '140', | |
}, { | |
id: 6, | |
name: 'Zip Tote Basket', | |
color: 'White and black', | |
href: '#', | |
rating: 5, | |
reviewCount: 38, | |
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-03-related-product-01.jpg', | |
imageAlt: 'Front of zip tote bag with white canvas, black canvas straps and handle, and black zipper pulls.', | |
price: '140', | |
}, | |
// More products... | |
] | |
export default function ProductPage({props}) { | |
console.log('props',props) | |
const [open, setOpen] = useState(false) | |
const [colors, setColors] = useState([]) | |
const [category, setCategory] = useState([]) | |
const [size, setSize] = useState([]) | |
const [selectedSize, setSelectedSize] = useState(product.sizes[0]) | |
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) | |
const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false) | |
useEffect(async () => { | |
const colors = await API.graphql({ | |
query: listColors | |
}) | |
setColors(colors.data.listColors.items.map(item => { | |
return {value: item.color, label: item.color} | |
})) | |
const sizes = await API.graphql({ | |
query: listSizes | |
}) | |
setSize(sizes.data.listSizes.items.map(item => { | |
return {value: item.name, label: item.name} | |
})) | |
const categorys = await API.graphql({ | |
query: listCategories | |
}) | |
setCategory(categorys.data.listCategories.items.map(item => { | |
return {value: item.name, label: item.name} | |
})) | |
}, []) | |
const {t} = useTranslation('common') | |
return ( | |
<div className="max-w-2xl mx-auto px-4 lg:max-w-7xl lg:px-8 bg-white"> | |
<div className="border-b border-gray-200 pt-24 pb-10"> | |
<h1 className="text-4xl font-extrabold tracking-tight text-gray-900">New Arrivals</h1> | |
<p className="mt-4 text-base text-gray-500"> | |
Checkout out the latest release of Basic Tees, new and improved with four openings! | |
</p> | |
</div> | |
<Transition.Root show={mobileFiltersOpen} as={Fragment}> | |
<Dialog as="div" className="fixed inset-0 flex z-40 lg:hidden" onClose={setMobileFiltersOpen}> | |
<Transition.Child | |
as={Fragment} | |
enter="transition-opacity ease-linear duration-300" | |
enterFrom="opacity-0" | |
enterTo="opacity-100" | |
leave="transition-opacity ease-linear duration-300" | |
leaveFrom="opacity-100" | |
leaveTo="opacity-0" | |
> | |
<Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-25"/> | |
</Transition.Child> | |
<Transition.Child | |
as={Fragment} | |
enter="transition ease-in-out duration-300 transform" | |
enterFrom="translate-x-full" | |
enterTo="translate-x-0" | |
leave="transition ease-in-out duration-300 transform" | |
leaveFrom="translate-x-0" | |
leaveTo="translate-x-full" | |
> | |
<div | |
className="ml-auto relative max-w-xs w-full h-full bg-white shadow-xl py-4 pb-6 flex flex-col overflow-y-auto"> | |
<div className="px-4 flex items-center justify-between"> | |
<h2 className="text-lg font-medium text-gray-900">Filters</h2> | |
<button | |
type="button" | |
className="-mr-2 w-10 h-10 p-2 flex items-center justify-center text-gray-400 hover:text-gray-500" | |
onClick={() => setMobileFiltersOpen(false)} | |
> | |
<span className="sr-only">Close menu</span> | |
<XIcon className="h-6 w-6" aria-hidden="true"/> | |
</button> | |
</div> | |
{/* Filters */} | |
<form className="mt-4"> | |
{colors.map((section) => ( | |
<Disclosure as="div" key={'Cores'} | |
className="border-t border-gray-200 pt-4 pb-4"> | |
{({open}) => ( | |
<fieldset> | |
<legend className="w-full px-2"> | |
<Disclosure.Button | |
className="w-full p-2 flex items-center justify-between text-gray-400 hover:text-gray-500"> | |
<span | |
className="text-sm font-medium text-gray-900">{section.name}</span> | |
<span className="ml-6 h-7 flex items-center"> | |
<ChevronDownIcon | |
className={classNames(open ? '-rotate-180' : 'rotate-0', 'h-5 w-5 transform')} | |
aria-hidden="true" | |
/> | |
</span> | |
</Disclosure.Button> | |
</legend> | |
<Disclosure.Panel className="pt-4 pb-2 px-4"> | |
<div className="space-y-6"> | |
{section.options.map((option, optionIdx) => ( | |
<div key={option.value} className="flex items-center"> | |
<input | |
id={`${section.id}-${optionIdx}-mobile`} | |
name={`${section.id}[]`} | |
defaultValue={option.value} | |
type="checkbox" | |
className="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500" | |
/> | |
<label | |
htmlFor={`${section.id}-${optionIdx}-mobile`} | |
className="ml-3 text-sm text-gray-500" | |
> | |
{option.label} | |
</label> | |
</div> | |
))} | |
</div> | |
</Disclosure.Panel> | |
</fieldset> | |
)} | |
</Disclosure> | |
))} | |
</form> | |
</div> | |
</Transition.Child> | |
</Dialog> | |
</Transition.Root> | |
<div className="pt-12 pb-24 lg:grid lg:grid-cols-3 lg:gap-x-8 xl:grid-cols-4"> | |
<aside> | |
<h2 className="sr-only">Filters</h2> | |
<button | |
type="button" | |
className="inline-flex items-center lg:hidden" | |
onClick={() => setMobileFiltersOpen(true)} | |
> | |
<span className="text-sm font-medium text-gray-700">Filters</span> | |
<PlusSmIcon className="flex-shrink-0 ml-1 h-5 w-5 text-gray-400" aria-hidden="true"/> | |
</button> | |
<div className="hidden lg:block"> | |
<form className="divide-y divide-gray-200 space-y-10"> | |
<div> | |
<fieldset> | |
<legend | |
className="block text-sm font-medium text-gray-900">{'Cores'} | |
</legend> | |
<div className="pt-6 space-y-3"> | |
{colors.map((option, optionIdx) => ( | |
<div key={option.value} className="flex items-center"> | |
<input | |
id={`${option}-${optionIdx}`} | |
name={`${option}[]`} | |
defaultValue={option.value} | |
type="checkbox" | |
className="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500" | |
/> | |
<div className={'ml-3 rounded-full w-4 h-4 border-2 border-gray-200'} | |
style={{backgroundColor: option.value}}> | |
</div> | |
</div> | |
))} | |
</div> | |
</fieldset> | |
</div> | |
<div> | |
<fieldset> | |
<legend | |
className="block text-sm font-medium text-gray-900 mt-10">{'Categorias'} | |
</legend> | |
<div className="pt-6 space-y-3"> | |
{category.map((option, optionIdx) => ( | |
<div key={option.value} className="flex items-center"> | |
<input | |
id={`${option}-${optionIdx}`} | |
name={`${option}[]`} | |
defaultValue={option.value} | |
type="checkbox" | |
className="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500" | |
/> | |
<label htmlFor={`category-${optionIdx}`} | |
className="ml-3 text-sm text-gray-600"> | |
{option.label} | |
</label> | |
</div> | |
))} | |
</div> | |
</fieldset> | |
</div> | |
<div> | |
<fieldset> | |
<legend | |
className="block text-sm font-medium text-gray-900 mt-10">{'Tamanhos'} | |
</legend> | |
<div className="pt-6 space-y-3"> | |
{size.map((option, optionIdx) => ( | |
<div key={option.value} className="flex items-center"> | |
<input | |
id={`${option}-${optionIdx}`} | |
name={`${option}[]`} | |
defaultValue={option.value} | |
type="checkbox" | |
className="h-4 w-4 border-gray-300 rounded text-indigo-600 focus:ring-indigo-500" | |
/> | |
<label htmlFor={`size-${optionIdx}`} | |
className="ml-3 text-sm text-gray-600"> | |
{option.label} | |
</label> | |
</div> | |
))} | |
</div> | |
</fieldset> | |
</div> | |
</form> | |
</div> | |
</aside> | |
<section aria-labelledby="product-heading" className="mt-6 lg:mt-0 lg:col-span-2 xl:col-span-3"> | |
<h2 id="product-heading" className="sr-only"> | |
Products | |
</h2> | |
<div | |
className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 sm:gap-x-6 sm:gap-y-10 lg:gap-x-8 xl:grid-cols-3"> | |
{products.map((product) => ( | |
<div | |
key={product.id} | |
className="group relative bg-white border border-gray-200 rounded-lg flex flex-col overflow-hidden" | |
> | |
<div | |
className="aspect-w-3 aspect-h-4 bg-gray-200 group-hover:opacity-75 sm:aspect-none sm:h-96"> | |
<img | |
src={product.imageSrc} | |
alt={product.imageAlt} | |
className="w-full h-full object-center object-cover sm:w-full sm:h-full" | |
/> | |
</div> | |
<div className="flex-1 p-4 space-y-2 flex flex-col"> | |
<h3 className="text-sm font-medium text-gray-900"> | |
<a href={product.href}> | |
<span aria-hidden="true" className="absolute inset-0"/> | |
{product.name} | |
</a> | |
</h3> | |
<p className="text-sm text-gray-500">{product.description}</p> | |
<div className="flex-1 flex flex-col justify-end"> | |
<div className="relative mt-4 flex justify-between"> | |
<div className="flex flex-col items-end"> | |
<div className="flex items-end"> | |
<p className="sr-only">{product.rating} out of 5 stars</p> | |
{[0, 1, 2, 3, 4].map((rating) => ( | |
<StarIcon | |
key={rating} | |
className={classNames( | |
product.rating > rating ? 'text-yellow-400' : 'text-gray-200', | |
'flex-shrink-0 h-5 w-5' | |
)} | |
aria-hidden="true" | |
/> | |
))} | |
</div> | |
<p className="mt-1 text-sm text-gray-500">{product.reviewCount} {t('reviews')}</p> | |
</div> | |
</div> | |
</div> | |
<div className="mt-6"> | |
<a | |
href={product.href} | |
className="relative flex bg-gray-100 border border-transparent rounded-md py-2 px-8 items-center justify-center text-sm font-medium text-gray-900 hover:bg-gray-200" | |
> | |
{t('label_add_to_bag')}<span className="sr-only">, {product.name}</span> | |
</a> | |
</div> | |
</div> | |
</div> | |
))} | |
</div> | |
</section> | |
</div> | |
</div> | |
) | |
} | |
export async function getServerSideProps(context){ | |
console.log('serverSide') | |
return { | |
props:{ | |
color:'color' | |
} | |
} | |
} | |
ProductPage.getLayout = function getLayout(page) { | |
return <MainLayout> | |
{page} | |
</MainLayout> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment