|
|
@ -1,16 +1,12 @@
|
|
|
|
import React, {useState, useEffect} from 'react'
|
|
|
|
import React, {useState} from 'react'
|
|
|
|
import Head from 'next/head'
|
|
|
|
import Head from 'next/head'
|
|
|
|
import Router from 'next/router'
|
|
|
|
import Router from 'next/router'
|
|
|
|
import {FormController, IntegerInput, Button} from '~/components/form'
|
|
|
|
import {FormController, IntegerInput, Button} from '~/components/form'
|
|
|
|
import isNum from 'validator/lib/isNumeric'
|
|
|
|
import isNum from 'validator/lib/isNumeric'
|
|
|
|
import {DateTime} from 'luxon'
|
|
|
|
import {DateTime} from 'luxon'
|
|
|
|
import {Icon} from '@rmwc/icon'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import Modal from '~/components/modal'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import useCart, {useSetCart} from '~/hooks/useCart'
|
|
|
|
import useCart, {useSetCart} from '~/hooks/useCart'
|
|
|
|
import styles from './style.module.css'
|
|
|
|
import styles from './style.module.css'
|
|
|
|
import usePrevious from '~/hooks/usePrevious'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Item.getInitialProps = async function({ctx: {axios, query: {slug}}}){
|
|
|
|
Item.getInitialProps = async function({ctx: {axios, query: {slug}}}){
|
|
|
|
const {data: item} = await axios.get(`/api/items/by-slug/${slug}`)
|
|
|
|
const {data: item} = await axios.get(`/api/items/by-slug/${slug}`)
|
|
|
@ -28,22 +24,13 @@ Item.getInitialProps = async function({ctx: {axios, query: {slug}}}){
|
|
|
|
return {item}
|
|
|
|
return {item}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Modal with full image size on clicking preview
|
|
|
|
export default function Item({item}){
|
|
|
|
export default function Item({item}){
|
|
|
|
const cart = useCart()
|
|
|
|
const cart = useCart()
|
|
|
|
const setCart = useSetCart()
|
|
|
|
const setCart = useSetCart()
|
|
|
|
// Pick first one with featured flag or 0
|
|
|
|
// Pick first one with featured flag or 0
|
|
|
|
const featuredIndex = item.images.reduce((p, im, i) => ((p !== undefined) ? p : (im.featured ? i : undefined)), undefined) || 0
|
|
|
|
const featuredIndex = item.images.reduce((p, im, i) => ((p !== undefined) ? p : (im.featured ? i : undefined)), undefined) || 0
|
|
|
|
const [selectedIndex, setSelected] = useState(featuredIndex);
|
|
|
|
const [selectedIndex, setSelected] = useState(featuredIndex);
|
|
|
|
const lastImage = usePrevious(selectedIndex);
|
|
|
|
|
|
|
|
const [imageModalVisible, setImageModalVisible] = useState(false);
|
|
|
|
|
|
|
|
const [imageChanged, setImageChanged] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
|
|
if (selectedIndex !== lastImage)
|
|
|
|
|
|
|
|
setImageChanged(true);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
setImageChanged(false);
|
|
|
|
|
|
|
|
}, [selectedIndex, lastImage]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const numInCart = cart?.items?.find(i => i.item.uuid === item.uuid)?.count || 0
|
|
|
|
const numInCart = cart?.items?.find(i => i.item.uuid === item.uuid)?.count || 0
|
|
|
|
|
|
|
|
|
|
|
@ -70,15 +57,15 @@ export default function Item({item}){
|
|
|
|
<div className={styles.imageContainer}>
|
|
|
|
<div className={styles.imageContainer}>
|
|
|
|
<div className={styles.card}>
|
|
|
|
<div className={styles.card}>
|
|
|
|
<picture>
|
|
|
|
<picture>
|
|
|
|
<source srcSet={`/api/images/${item.images[selectedIndex].uuid}/thumb.webp`} type="image/webp"/>
|
|
|
|
<source srcset={`/api/images/${item.images[selectedIndex].uuid}/thumb.webp`} type="image/webp"/>
|
|
|
|
<img src={`/api/images/${item.images[selectedIndex].uuid}/thumb.png`} onClick={() => setImageModalVisible(true)} />
|
|
|
|
<img src={`/api/images/${item.images[selectedIndex].uuid}/thumb.png`} />
|
|
|
|
</picture>
|
|
|
|
</picture>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{item.images && item.images.length > 1 &&
|
|
|
|
{item.images && item.images.length > 1 &&
|
|
|
|
<div className={styles.imageSelector}>
|
|
|
|
<div className={styles.imageSelector}>
|
|
|
|
{item.images.map((image, index) => (
|
|
|
|
{item.images.map((image, index) => (
|
|
|
|
<picture key={image.uuid}>
|
|
|
|
<picture>
|
|
|
|
<source srcSet={`/api/images/${image.uuid}/thumb.webp`} type="image/webp"/>
|
|
|
|
<source srcset={`/api/images/${image.uuid}/thumb.webp`} type="image/webp"/>
|
|
|
|
<img key={image.uuid}
|
|
|
|
<img key={image.uuid}
|
|
|
|
onClick={()=>setSelected(index)}
|
|
|
|
onClick={()=>setSelected(index)}
|
|
|
|
className={index === selectedIndex ? styles.selectedImage : undefined}
|
|
|
|
className={index === selectedIndex ? styles.selectedImage : undefined}
|
|
|
@ -88,24 +75,6 @@ export default function Item({item}){
|
|
|
|
))}
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
<Modal title={`${item.name} (Image ${selectedIndex + 1})`} visible={imageModalVisible} onDeactivate={() => setImageModalVisible(false)}>
|
|
|
|
|
|
|
|
<div className={styles.imageCarousel}>
|
|
|
|
|
|
|
|
<button onClick={() => setSelected(index => (index - 1 < 0) ? item.images.length - 1 : index - 1)}>
|
|
|
|
|
|
|
|
<Icon icon="chevron_left" />
|
|
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<div className={styles.fullImage}>
|
|
|
|
|
|
|
|
{!imageChanged && (
|
|
|
|
|
|
|
|
<picture>
|
|
|
|
|
|
|
|
<source srcSet={`/api/images/${item.images[selectedIndex].uuid}/large.webp`} type="image/webp"/>
|
|
|
|
|
|
|
|
<img src={`/api/images/${item.images[selectedIndex].uuid}/large.png`} onClick={() => setImageModalVisible(true)} />
|
|
|
|
|
|
|
|
</picture>
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<button onClick={() => setSelected(index => (index + 1) % item.images.length)}>
|
|
|
|
|
|
|
|
<Icon icon="chevron_right" />
|
|
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
)}
|
|
|
|
<div className={styles.controls}>
|
|
|
|
<div className={styles.controls}>
|
|
|
|