import React , { useState , useEffect } from 'react'
import Head from 'next/head'
import Router from 'next/router'
import { FormController , IntegerInput , Button } from '~/components/form'
import isNum from 'validator/lib/isNumeric'
import { DateTime } from 'luxon'
import { Icon } from '@rmwc/icon'
import Modal from '~/components/modal'
import useCart , { useSetCart } from '~/hooks/useCart'
import styles from './style.module.css'
import usePrevious from '~/hooks/usePrevious'
Item . getInitialProps = async function ( { ctx : { axios , query : { slug } } } ) {
const { data : item } = await axios . get ( ` /api/items/by-slug/ ${ slug } ` )
if ( ! item ) {
const err = new Error ( "Not found" )
err . status = 404
throw err ;
}
if ( item . preorder _availability _date ) {
item . preorder _availability _date = DateTime . fromISO ( item . preorder _availability _date ) . toLocaleString ( DateTime . DATE _FULL )
}
return { item }
}
export default function Item ( { item } ) {
const cart = useCart ( )
const setCart = useSetCart ( )
// 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 [ 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 numberInStock = item . number _in _stock
const numberPreorderSlots = ( item . preorder _maximum || 0 ) - ( - Math . min ( 0 , item . number _in _stock ) )
const availabilityText =
numberInStock > 0
? ` ${ numberInStock } in stock `
: item . preorder _availability _date && numberPreorderSlots > 0
? ` ${ numberPreorderSlots } available for pre-order `
: 'Currently out of stock'
const totalAvailable = ( numberInStock > 0 ? numberInStock : numberPreorderSlots ) - numInCart
return (
< >
< Head >
< title > { item . name } | Society of Socks < / t i t l e >
< / H e a d >
< div className = { styles . pageContainer } >
< div className = { 'dark ' + styles . itemDetails } >
{ item . images && item . images . length > 0 && (
< div className = { styles . imageContainer } >
< div className = { styles . card } >
< picture >
< 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 ) } / >
< / p i c t u r e >
< / d i v >
{ item . images && item . images . length > 1 &&
< div className = { styles . imageSelector } >
{ item . images . map ( ( image , index ) => (
< picture key = { image . uuid } >
< source srcSet = { ` /api/images/ ${ image . uuid } /thumb.webp ` } type = "image/webp" / >
< img key = { image . uuid }
onClick = { ( ) => setSelected ( index ) }
className = { index === selectedIndex ? styles . selectedImage : undefined }
src = { ` /api/images/ ${ image . uuid } /thumb.png ` }
/ >
< / p i c t u r e >
) ) }
< / d i v >
}
< 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" / >
< / b u t t o n >
< 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 ) } / >
< / p i c t u r e >
) }
< / d i v >
< button onClick = { ( ) => setSelected ( index => ( index + 1 ) % item . images . length ) } >
< Icon icon = "chevron_right" / >
< / b u t t o n >
< / d i v >
< / M o d a l >
< / d i v >
) }
< div className = { styles . controls } >
< h2 > { item . name } < / h 2 >
{ item . description . split ( '\n' ) . map ( p => p . trim ( ) ) . filter ( p => p !== '' ) . map ( ( p , i ) => < p key = { i } > { p } < / p > ) }
< FormController className = { styles . form } url = { ` /api/cart/add/ ${ item . uuid } ` } afterSubmit = { ( cart ) => { setCart ( cart ) ; Router . push ( '/store/cart' ) } } >
< IntegerInput label = "Add to cart" name = "count" initialValue = "1" minimum = "1" maximum = { totalAvailable . toFixed ( 0 ) } validate = { value => isNum ( value , { no _symbols : true } ) && parseInt ( value ) <= totalAvailable } / >
{
totalAvailable > 0
? < Button type = "submit" > Add to cart < / B u t t o n >
: < Button enabled = { false } type = "submit" > Out of stock < / B u t t o n >
}
< / F o r m C o n t r o l l e r >
< div className = { styles . notes } >
< span > Price : $ { ( parseInt ( item . price _cents ) / 100 ) . toFixed ( 2 ) } each < / s p a n >
< span >
{ availabilityText }
< / s p a n >
< span > { numInCart } in < button style = { { color : "white" } } className = "buttonLink" onClick = { ( ) => Router . push ( ` /store/cart ` ) } > cart < / b u t t o n > < / s p a n >
< / d i v >
{ numberInStock < 1 && item . preorder _availability _date && numberPreorderSlots > 0 && (
< p className = "warning" >
< strong > Note : < / s t r o n g >
This is a pre - order item . If you place an order with this item in your cart , it will not ship
until at least { item . preorder _availability _date }
< / p >
) }
< / d i v >
< / d i v >
< div className = { styles . moreDetails } >
< h2 > Additional Information < / h 2 >
< p > All socks are only available in adult medium sizes ( approximately US Men 's size 10 - 13 depending on stretching) at the moment - we' re working on getting more sizes available but not quite ready for that yet . < / p >
< p > All purchases are shipped within a few days of your purchase , ( USPS first class ) . < / p >
< / d i v >
< / d i v >
< / >
)
}