Skip to content

Instantly share code, notes, and snippets.

@IgorDePaula
Created August 18, 2021 16:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IgorDePaula/548e78c83d0c7b3e38750b4951bb83b8 to your computer and use it in GitHub Desktop.
Save IgorDePaula/548e78c83d0c7b3e38750b4951bb83b8 to your computer and use it in GitHub Desktop.
ProductPage.js
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