diff options
| author | Dayana31 <[email protected]> | 2022-04-21 17:27:08 -0500 |
|---|---|---|
| committer | Dayana31 <[email protected]> | 2022-04-21 17:27:08 -0500 |
| commit | 67c50667678dd0ce4709b29a854f6a47093a1ac5 (patch) | |
| tree | b6f9f39092ad54bf6b815984d32b37d7c7ca67ab /front/odiparpack/app/components/Gallery | |
| parent | 91140b24f0d49a9f89a080ee063e9eb023a4b73a (diff) | |
| parent | e13e630cd6e4fc0b1ff92098a28a770794c7bb9a (diff) | |
| download | DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.tar.gz DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.tar.bz2 DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.zip | |
Merge branch 'gabshr' into dayana
Diffstat (limited to 'front/odiparpack/app/components/Gallery')
5 files changed, 596 insertions, 0 deletions
diff --git a/front/odiparpack/app/components/Gallery/PhotoGallery.js b/front/odiparpack/app/components/Gallery/PhotoGallery.js new file mode 100644 index 0000000..3877bba --- /dev/null +++ b/front/odiparpack/app/components/Gallery/PhotoGallery.js @@ -0,0 +1,83 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import 'ba-styles/vendors/image-lightbox/image-lightbox.css'; +import { Typography, ButtonBase } from '@material-ui/core'; +import ImageLightbox from '../ImageLightbox/ImageLightbox'; +import styles from './photo-jss'; + + +class PhotoGallery extends React.Component { + constructor(props) { + super(props); + + this.state = { + photoIndex: 0, + isOpen: false, + }; + } + + openPopup = (photoIndex) => { + this.setState({ isOpen: true, photoIndex }); + } + + render() { + const { photoIndex, isOpen } = this.state; + const { classes, imgData } = this.props; + return ( + <div> + {isOpen && ( + <ImageLightbox + mainSrc={imgData[photoIndex].img} + nextSrc={imgData[(photoIndex + 1) % imgData.length].img} + prevSrc={imgData[(photoIndex + (imgData.length - 1)) % imgData.length].img} + onCloseRequest={() => this.setState({ isOpen: false })} + onMovePrevRequest={() => this.setState({ + photoIndex: (photoIndex + (imgData.length - 1)) % imgData.length, + }) + } + onMoveNextRequest={() => this.setState({ + photoIndex: (photoIndex + 1) % imgData.length, + }) + } + /> + )} + <div className={classes.masonry}> + { + imgData.map((thumb, index) => ( + <figure className={classes.item} key={index.toString()}> + <ButtonBase + focusRipple + className={classes.image} + focusVisibleClassName={classes.focusVisible} + onClick={() => this.openPopup(index)} + > + <img src={thumb.img} alt={thumb.title} /> + <span className={classes.imageBackdrop} /> + <span className={classes.imageButton}> + <Typography + component="span" + variant="subtitle1" + color="inherit" + className={classes.imageTitle} + > + {thumb.title} + <span className={classes.imageMarked} /> + </Typography> + </span> + </ButtonBase> + </figure> + )) + } + </div> + </div> + ); + } +} + +PhotoGallery.propTypes = { + classes: PropTypes.object.isRequired, + imgData: PropTypes.array.isRequired +}; + +export default withStyles(styles)(PhotoGallery); diff --git a/front/odiparpack/app/components/Gallery/ProductDetail.js b/front/odiparpack/app/components/Gallery/ProductDetail.js new file mode 100644 index 0000000..f05852f --- /dev/null +++ b/front/odiparpack/app/components/Gallery/ProductDetail.js @@ -0,0 +1,195 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import Slider from 'react-slick'; +import CloseIcon from '@material-ui/icons/Close'; +import AddShoppingCart from '@material-ui/icons/AddShoppingCart'; +import imgData from 'ba-api/imgData'; +import Type from 'ba-styles/Typography.scss'; +import 'ba-styles/vendors/slick-carousel/slick-carousel.css'; +import 'ba-styles/vendors/slick-carousel/slick.css'; +import 'ba-styles/vendors/slick-carousel/slick-theme.css'; +import { + Typography, + Grid, + Dialog, + AppBar, + Toolbar, + IconButton, + Slide, + Button, + Chip, + TextField, +} from '@material-ui/core'; +import Rating from '../Rating/Rating'; +import styles from './product-jss'; + +const getThumb = imgData.map(a => a.thumb); + +const Transition = React.forwardRef(function Transition(props, ref) { // eslint-disable-line + return <Slide direction="up" ref={ref} {...props} />; +}); + +class ProductDetail extends React.Component { + state = { + qty: 1, + } + + handleQtyChange = event => { + this.setState({ qty: event.target.value }); + } + + submitToCart = itemAttr => { + this.props.handleAddToCart(itemAttr); + this.props.close(); + } + + render() { + const { + classes, + open, + close, + detailContent, + productIndex + } = this.props; + + const { qty } = this.state; + + const itemAttr = (item) => { + if (item !== undefined) { + return { + id: detailContent.getIn([productIndex, 'id']), + name: detailContent.getIn([productIndex, 'name']), + thumbnail: detailContent.getIn([productIndex, 'thumbnail']), + price: detailContent.getIn([productIndex, 'price']), + quantity: qty + }; + } + return false; + }; + + const settings = { + customPaging: (i) => ( + <a> + <img src={getThumb[i]} alt="thumb" /> + </a> + ), + infinite: true, + dots: true, + slidesToShow: 1, + slidesToScroll: 1, + }; + + return ( + <Dialog + fullScreen + open={open} + onClose={close} + TransitionComponent={Transition} + > + <AppBar className={classes.appBar}> + <Toolbar> + <Typography variant="h6" color="inherit" className={classes.flex}> + {detailContent.getIn([productIndex, 'name'])} + </Typography> + <IconButton color="inherit" onClick={() => close()} aria-label="Close"> + <CloseIcon /> + </IconButton> + </Toolbar> + </AppBar> + <div className={classes.detailContainer}> + <Grid container className={classes.root} spacing={3}> + <Grid item md={5} sm={12} xs={12}> + <div className="container thumb-nav"> + <Slider {...settings}> + {imgData.map((item, index) => { + if (index >= 5) { + return false; + } + return ( + <div key={index.toString()} className={classes.item}> + <img src={item.img} alt={item.title} /> + </div> + ); + })} + </Slider> + </div> + </Grid> + <Grid item md={7} sm={12} xs={12}> + <section className={classes.detailWrap}> + <Typography noWrap gutterBottom variant="h5" className={classes.title} component="h2"> + {detailContent.getIn([productIndex, 'name'])} + </Typography> + <div className={classes.price}> + <Typography variant="h5"> + <span> +$ + {detailContent.getIn([productIndex, 'price'])} + </span> + </Typography> + {detailContent.getIn([productIndex, 'discount']) !== '' && ( + <Fragment> + <Typography variant="caption" component="h5"> + <span className={Type.lineThrought}> +$ + {detailContent.getIn([productIndex, 'prevPrice'])} + </span> + </Typography> + <Chip label={'Discount ' + detailContent.getIn([productIndex, 'discount'])} className={classes.chipDiscount} /> + </Fragment> + )} + {detailContent.getIn([productIndex, 'soldout']) && ( + <Chip label="Sold Out" className={classes.chipSold} /> + )} + </div> + <div className={classes.ratting}> + <Rating value={detailContent.getIn([productIndex, 'ratting'])} max={5} readOnly /> + </div> + <Typography component="p" className={classes.desc}> + {detailContent.getIn([productIndex, 'desc'])} + </Typography> + {!detailContent.getIn([productIndex, 'soldout']) && ( + <div className={classes.btnArea}> + <Typography variant="subtitle1"> + Quantity : + </Typography> + <TextField + type="number" + InputLabelProps={{ + shrink: true, + }} + margin="none" + value={qty} + className={classes.quantity} + onChange={this.handleQtyChange} + /> + <Button variant="contained" onClick={() => this.submitToCart(itemAttr(detailContent))} color="secondary"> + <AddShoppingCart /> + {' '} +Add to cart + </Button> + </div> + )} + </section> + </Grid> + </Grid> + </div> + </Dialog> + ); + } +} + +ProductDetail.propTypes = { + classes: PropTypes.object.isRequired, + open: PropTypes.bool.isRequired, + close: PropTypes.func.isRequired, + handleAddToCart: PropTypes.func.isRequired, + detailContent: PropTypes.object.isRequired, + productIndex: PropTypes.number, +}; + +ProductDetail.defaultProps = { + productIndex: undefined +}; + +export default withStyles(styles)(ProductDetail); diff --git a/front/odiparpack/app/components/Gallery/ProductGallery.js b/front/odiparpack/app/components/Gallery/ProductGallery.js new file mode 100644 index 0000000..94f6c1e --- /dev/null +++ b/front/odiparpack/app/components/Gallery/ProductGallery.js @@ -0,0 +1,152 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import ViewList from '@material-ui/icons/ViewList'; +import GridOn from '@material-ui/icons/GridOn'; +import { Grid, Typography, Button } from '@material-ui/core'; +import ProductCard from '../CardPaper/ProductCard'; +import ProductDetail from './ProductDetail'; + + +const styles = theme => ({ + result: { + margin: theme.spacing(1) + }, + option: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 10 + }, + button: { + fontSize: 12, + '& svg': { + marginRight: 10 + } + }, + appBar: { + position: 'relative', + }, + flex: { + flex: 1, + }, +}); + +class ProductGallery extends React.Component { + state = { + listView: false, + open: false, + } + + handleDetailOpen = (product) => { + this.setState({ open: true }); + this.props.showDetail(product); + }; + + handleClose = () => { + this.setState({ open: false }); + }; + + handleSwitchView = () => { + this.setState({ + listView: !this.state.listView + }); + } + + render() { + const { classes } = this.props; + const { listView, open } = this.state; + const { + dataProduct, + handleAddToCart, + productIndex, + keyword, + } = this.props; + + const getTotalResult = dataArray => { + let totalResult = 0; + for (let i = 0; i < dataArray.size; i += 1) { + if (dataArray.getIn([i, 'name']) === undefined) { + return false; + } + if (dataArray.getIn([i, 'name']).toLowerCase().indexOf(keyword) !== -1) { + totalResult += 1; + } + } + return totalResult; + }; + + return ( + <div> + <ProductDetail + open={open} + close={this.handleClose} + detailContent={dataProduct} + productIndex={productIndex} + handleAddToCart={handleAddToCart} + /> + <section className={classes.option}> + <Typography variant="caption" className={classes.result}> + {getTotalResult(dataProduct)} + {' '} +Results + </Typography> + <Button onClick={this.handleSwitchView} className={classes.button} size="small"> + {listView ? <GridOn /> : <ViewList />} + {listView ? 'Grid View' : 'List View'} + </Button> + </section> + <Grid + container + alignItems="flex-start" + justify="flex-start" + direction="row" + spacing={3} + > + { + dataProduct.map((product, index) => { + if (product.get('name').toLowerCase().indexOf(keyword) === -1) { + return false; + } + const itemAttr = { + id: product.get('id'), + name: product.get('name'), + thumbnail: product.get('thumbnail'), + price: product.get('price'), + quantity: 1 + }; + return ( + <Grid item md={listView ? 12 : 4} sm={listView ? 12 : 6} xs={12} key={index.toString()}> + <ProductCard + list={listView} + name={product.get('name')} + thumbnail={product.get('thumbnail')} + desc={product.get('desc')} + ratting={product.get('ratting')} + price={product.get('price')} + prevPrice={product.get('prevPrice')} + discount={product.get('discount')} + soldout={product.get('soldout')} + detailOpen={() => this.handleDetailOpen(product)} + addToCart={() => handleAddToCart(itemAttr)} + /> + </Grid> + ); + }) + } + </Grid> + </div> + ); + } +} + +ProductGallery.propTypes = { + classes: PropTypes.object.isRequired, + dataProduct: PropTypes.object.isRequired, + handleAddToCart: PropTypes.func.isRequired, + showDetail: PropTypes.func.isRequired, + productIndex: PropTypes.number.isRequired, + keyword: PropTypes.string.isRequired, +}; + +export default withStyles(styles)(ProductGallery); diff --git a/front/odiparpack/app/components/Gallery/photo-jss.js b/front/odiparpack/app/components/Gallery/photo-jss.js new file mode 100644 index 0000000..61a6961 --- /dev/null +++ b/front/odiparpack/app/components/Gallery/photo-jss.js @@ -0,0 +1,79 @@ +const styles = theme => ({ + masonry: { /* Masonry container */ + [theme.breakpoints.up('sm')]: { + columnCount: 2, + }, + [theme.breakpoints.up('md')]: { + columnCount: 3, + }, + columnGap: '1em', + columnFill: 'initial', + marginTop: 20 + }, + item: { + display: 'inline-table', + margin: `0 0 ${theme.spacing(2)}px`, + width: '100%', + boxShadow: theme.shadows[4], + overflow: 'hidden', + borderRadius: 2, + transition: 'box-shadow .3s', + '&:hover': { + cursor: 'pointer', + boxShadow: theme.shadows[7], + }, + '& img': { + marginBottom: -7 + } + }, + image: { + position: 'relative', + [theme.breakpoints.down('xs')]: { + width: '100% !important', // Overrides inline-style + }, + '&:hover, &$focusVisible': { + zIndex: 1, + '& $imageBackdrop': { + opacity: 0.15, + }, + }, + }, + focusVisible: {}, + imageButton: { + position: 'absolute', + left: 0, + right: 0, + top: 0, + bottom: 0, + display: 'flex', + alignItems: 'flex-end', + justifyContent: 'center', + color: theme.palette.common.white, + paddingBottom: 10 + }, + imageBackdrop: { + position: 'absolute', + left: 0, + right: 0, + top: 0, + bottom: 0, + backgroundColor: theme.palette.common.black, + opacity: 0, + transition: theme.transitions.create('opacity'), + }, + imageTitle: { + position: 'relative', + padding: `${theme.spacing(2)}px ${theme.spacing(4)}px ${theme.spacing(1) + 6}px`, + }, + imageMarked: { + height: 3, + width: 18, + backgroundColor: theme.palette.common.white, + position: 'absolute', + bottom: -2, + left: 'calc(50% - 9px)', + transition: theme.transitions.create('opacity'), + }, +}); + +export default styles; diff --git a/front/odiparpack/app/components/Gallery/product-jss.js b/front/odiparpack/app/components/Gallery/product-jss.js new file mode 100644 index 0000000..230ebf0 --- /dev/null +++ b/front/odiparpack/app/components/Gallery/product-jss.js @@ -0,0 +1,87 @@ +import { blueGrey as dark } from '@material-ui/core/colors'; +const styles = theme => ({ + root: { + flexGrow: 1, + }, + rootSlider: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' + }, + item: { + textAlign: 'center', + '& img': { + margin: '10px auto' + } + }, + appBar: { + position: 'relative', + }, + flex: { + flex: 1, + }, + detailContainer: { + margin: '-16px auto 0', + maxWidth: '100%', + [theme.breakpoints.up('lg')]: { + maxWidth: 1080, + }, + [theme.breakpoints.up('md')]: { + maxWidth: 960, + paddingTop: 40, + marginTop: 0 + }, + [theme.breakpoints.down('sm')]: { + overflowX: 'hidden', + } + }, + chipDiscount: { + background: theme.palette.primary.light, + color: theme.palette.primary.dark, + marginBottom: 10, + }, + chipSold: { + background: dark[500], + color: theme.palette.getContrastText(dark[500]), + marginBottom: 10, + }, + detailWrap: { + padding: 30 + }, + title: { + marginBottom: 30 + }, + price: { + display: 'flex', + alignItems: 'center', + marginTop: 30, + padding: '8px 12px', + '& > *': { + marginRight: 10 + } + }, + ratting: { + borderBottom: `1px solid ${theme.palette.grey[400]}`, + marginBottom: 20, + }, + btnArea: { + display: 'flex', + alignItems: 'center', + marginTop: 20, + background: theme.palette.grey[100], + padding: '10px 20px' + }, + quantity: { + width: 40, + marginRight: 40, + marginLeft: 10, + '& input': { + textAlign: 'right' + } + }, + desc: { + padding: '10px 0' + } +}); + +export default styles; |
