import React, { useState, useRef, useLayoutEffect } from "react"; import { connect } from "react-redux"; import { writeConfigRequest, useConfigInMainRequest, } from "secure-electron-store"; import { makeStyles, withStyles } from "@material-ui/core/styles"; import { Button, Divider, Grid, Typography, Menu, Card, CardContent, TextField, ButtonGroup, Box, } from "@material-ui/core"; import ArrowBackIcon from "@material-ui/icons/ArrowBack"; import NoteIcon from "@material-ui/icons/Note"; import { openModal } from "Redux/modals/addItemModalSlice"; import { openEditModal } from "Redux/modals/editItemModalSlice"; import { addItem, replaceItems } from "Redux/data/inventorySlice"; import EditItemModal from "Components/modals/editItemModal"; import stockxLogo from "../../../../resources/stockx.png"; import * as am4core from "@amcharts/amcharts4/core"; import * as am4charts from "@amcharts/amcharts4/charts"; import am4themes_animated from "@amcharts/amcharts4/themes/animated"; am4core.useTheme(am4themes_animated); am4core.addLicense("ch-custom-attribution"); const useStyles = makeStyles((theme) => ({ divider: { marginBottom: 12 }, divider2: { marginBottom: 24 }, section: { paddingLeft: 4, paddingRight: 4, marginBottom: 18 }, data: { height: 400, width: "100%" }, root: { width: "100%", "& > * + *": { marginTop: theme.spacing(2), }, }, paper: { padding: theme.spacing(2), color: "theme.palette.text.secondary", display: "flex", alignItems: "center", marginBottom: theme.spacing(1), backgroundColor: "rgba(0, 0, 0, 0.09)", }, rightSpacing: { marginRight: theme.spacing(1), }, })); const StyledMenu = withStyles({ paper: { border: "1px solid #d3d4d5", width: 300, padding: 12, }, })((props) => ( <Menu elevation={0} getContentAnchorEl={null} anchorOrigin={{ vertical: "bottom", horizontal: "center", }} transformOrigin={{ vertical: "top", horizontal: "center", }} {...props} /> )); const ItemInfo = (props) => { const [itemInfo, setItemInfo] = useState({}); const [priceMap, setPriceMap] = useState({}); const [marketData, setMarketData] = useState([]); const [marketSize, setMarketSize] = useState(""); const [stockxLowestAsk, setStockxLowestAsk] = useState(0); const [stockxHighestBid, setStockxHighestBid] = useState(0); const [fetchedProduct, setFetchedProduct] = useState({}); React.useEffect(() => { window.api.store.send(useConfigInMainRequest); window.api.stockxData("receiveProductData", (data) => { setFetchedProduct(data); }); window.api.stockxData("receiveChartData", (data) => { var parsedData = data; console.log(parsedData.series, "received Chart Data"); let stockxData = []; parsedData.series[0].data.map((dataset) => { stockxData.push({ date: new Date(dataset[0]).toLocaleDateString("en-US"), value: dataset[1], }); }); setMarketData(stockxData); }); if (props.location.state == "inventory") { var item = props.inventory.items.filter((obj) => { return ( obj.id == props.location.search.substr(1, props.location.search.length) ); }); } else if (props.location.state == "sales") { var item = props.sales.sales.filter((obj) => { return ( obj.id == props.location.search.substr(1, props.location.search.length) ); }); } else { var item = props.inventory.items.filter((obj) => { return ( obj.id == props.location.search.substr(1, props.location.search.length) ); }); } setMarketSize(item[0].size); setItemInfo(item[0]); window.api.stockxData("getProductData", item[0].siteLinks.stockX.urlKey); console.log(props, "itemInfoPage props"); }, []); React.useEffect(() => { if (Object.keys(fetchedProduct).length > 0) { console.log(fetchedProduct, "fetched product info"); let prices = {}; Object.keys(fetchedProduct.Product.children).map((key) => { prices[fetchedProduct.Product.children[key].shoeSize] = { id: key, highestBid: fetchedProduct.Product.children[key].market.highestBidFloat, lowestAsk: fetchedProduct.Product.children[key].market.lowestAskFloat, }; }); if (prices) { setPriceMap(prices); } } }, [fetchedProduct]); React.useEffect(() => { if (Object.keys(priceMap).length > 0) { updateMarketData(itemInfo.siteLinks.stockX.id, "all", new Date()); } }, [priceMap]); const chart = useRef(null); useLayoutEffect(() => { console.log(marketData, "MARKET DATA"); let x = am4core.create("chartdiv", am4charts.XYChart); x.paddingRight = 20; x.data = marketData; let dateAxis = x.xAxes.push(new am4charts.DateAxis()); dateAxis.renderer.grid.template.location = 0; let valueAxis = x.yAxes.push(new am4charts.ValueAxis()); let series = x.series.push(new am4charts.LineSeries()); series.dataFields.dateX = "date"; series.dataFields.valueY = "value"; series.tooltipText = "${valueY.value}"; series.stroke = am4core.color("#1976d2"); //color of line //series.strokeWidth = 3; line thickness x.cursor = new am4charts.XYCursor(); x.cursor.lineY.disabled = true; // let scrollbarX = new am4charts.XYChartScrollbar(); // scrollbarX.series.push(series); // x.scrollbarX = scrollbarX; chart.current = x; return () => { x.dispose(); }; }, [marketData]); const updateMarketData = (itemId, startDate, endDate) => { console.log("Call made to update:", itemId); if (startDate !== "all") { startDate = new Date( startDate.getTime() - startDate.getTimezoneOffset() * 60000 ) .toISOString() .split("T")[0]; } endDate = new Date(endDate.getTime() - endDate.getTimezoneOffset() * 60000) .toISOString() .split("T")[0]; console.log("getting chart data", itemId, startDate, endDate); window.api.stockxData("getChartData", { itemId, startDate, endDate }); let sizeData = Object.keys(priceMap).filter((size) => { return priceMap[size].id == itemId; }); if (sizeData.length > 0) { setStockxLowestAsk(priceMap[sizeData].lowestAsk.toFixed(2)); setStockxHighestBid(priceMap[sizeData].highestBid.toFixed(2)); } else { setStockxLowestAsk( fetchedProduct.Product.market.lowestAskFloat.toFixed(2) ); setStockxHighestBid( fetchedProduct.Product.market.highestBidFloat.toFixed(2) ); } }; const [anchorEl, setAnchorEl] = useState(null); const handleSizesMenuClick = (e) => { console.log(e.currentTarget); setAnchorEl(e.currentTarget); }; const handleSizesMenuClose = () => { setAnchorEl(null); }; const styles = useStyles(); return ( <React.Fragment> <div className={styles.root}> <Grid xs={12} container> {/* MenuBar */} <Grid xs={12} container className={styles.divider}> <Grid xs={6} item> <Button variant="" startIcon={<ArrowBackIcon />} onClick={(e) => { e.preventDefault(); props.history.goBack(); }} > Back </Button> </Grid> <Grid xs={6} item style={{ justifyContent: "flex-end", display: "flex" }} > <Button color="primary" variant="contained" className={styles.rightSpacing} > Edit </Button> <Button color="secondary" variant="contained"> Delete </Button> </Grid> </Grid> {/* Item Title */} <Grid xs={12} item className={styles.divider}> <Typography variant="h4">{itemInfo.name}</Typography> <Typography variant="h5">Size {itemInfo.size}</Typography> </Grid> <Grid xs={12} container spacing={4}> <Grid xs={8} item> <Card className={styles.divider2}> <CardContent> <Grid xs={12} container> <Grid xs={5} item> <img alt="image" src={itemInfo.image} /> </Grid> <Grid xs={1} container></Grid> <Grid xs={6} container style={{ display: "flex", flexDirection: "column" }} > <Typography variant="button" style={{ fontSize: "1.1rem" }} className={styles.divider} > <span style={{ fontWeight: "bold" }}>SKU/STYLE </span> {itemInfo.sku} </Typography> <Typography variant="button" style={{ fontSize: "1.1rem" }} className={styles.divider} > <span style={{ fontWeight: "bold" }}>COLORWAY </span> {itemInfo.colorway} </Typography> <Typography variant="button" style={{ fontSize: "1.1rem" }} > <span style={{ fontWeight: "bold" }}>BRAND </span> {itemInfo.brand} </Typography> </Grid> </Grid> </CardContent> </Card> <Card className={styles.divider2}> <CardContent> <Grid xs={12} container> <Grid xs={6} item style={{ display: "flex", alignItems: "center", }} className={styles.divider} > <Typography variant="h5" className={styles.rightSpacing}> Notes </Typography> <NoteIcon /> </Grid> <Grid xs={6}> <div style={{ justifyContent: "flex-end", display: "flex", }} className={styles.divider} > <Typography variant="subtitle2"> No changes made </Typography> </div> </Grid> <Grid xs={12}> <TextField id="prodDesc" label="Click to add some notes!" multiline rows={3} variant="filled" size="small" type="date" fullWidth /> </Grid> </Grid> </CardContent> </Card> </Grid> <Grid xs={4} item> <Card> <CardContent> <Grid xs={12} container> <Grid xs={12} item className={styles.divider}> <Typography variant="h5">Purchase Details</Typography> </Grid> <Grid xs={12} container className={styles.divider}> <Grid xs={8} item> <Typography variant="subtitle1">Cost</Typography> </Grid> <Grid xs={4} item style={{ display: "flex" }}> <Typography variant="subtitle1"> ${itemInfo.cost} </Typography> </Grid> </Grid> <Grid xs={12} container className={styles.divider}> <Grid xs={8} item> <Typography variant="subtitle1">Tax</Typography> </Grid> <Grid xs={4} item style={{ display: "flex" }}> <Typography variant="subtitle1"> ${itemInfo.costTax} </Typography> </Grid> </Grid> <Grid xs={12} container className={styles.divider}> <Grid xs={8} item> <Typography variant="subtitle1">Shipping</Typography> </Grid> <Grid xs={4} item style={{ display: "flex" }}> <Typography variant="subtitle1"> ${itemInfo.costShipping} </Typography> </Grid> </Grid> <Grid xs={12} container className={styles.divider}> <Grid xs={8} item> <Typography variant="subtitle1">Total</Typography> </Grid> <Grid xs={4} item style={{ display: "flex" }}> <Typography variant="subtitle1"> $ {( parseFloat(itemInfo.cost) + parseFloat(itemInfo.costTax) + parseFloat(itemInfo.costShipping) ).toFixed(2)} </Typography> </Grid> </Grid> <Grid xs={12} container className={styles.divider}> <Grid xs={8} item> <Typography variant="subtitle1"> Purchase Place </Typography> </Grid> <Grid xs={4} item style={{ display: "flex" }}> <Typography variant="subtitle1"> {itemInfo.store} </Typography> </Grid> </Grid> <Grid xs={12} container> <Grid xs={8} item> <Typography variant="subtitle1"> Purchase Date </Typography> </Grid> <Grid xs={4} item style={{ display: "flex" }}> <Typography variant="subtitle1"> {new Date(itemInfo.dateObtained).toLocaleDateString( "en-US" )} </Typography> </Grid> </Grid> </Grid> </CardContent> </Card> </Grid> </Grid> <Grid xs={12} container> <Grid xs={12} item className={styles.divider}> <Typography variant="h5">Market Price</Typography> </Grid> <Grid xs={12} container spacing={4}> <Grid xs={4} item> <img src={stockxLogo} alt="StockX" style={{ width: 80, cursor: "pointer" }} /> <Grid xs={12} container className={styles.divider}> <Grid xs={6} container> <Typography variant="subtitle1">Lowest Ask</Typography> </Grid> <Grid xs={6} container direction="row" justify="flex-end"> <Typography variant="subtitle1"> ${stockxLowestAsk} </Typography> </Grid> </Grid> <Grid xs={12} container className={styles.divider}> <Grid xs={6} container> <Typography variant="subtitle1">Highest Bid</Typography> </Grid> <Grid xs={6} container direction="row" justify="flex-end"> <Typography variant="subtitle1"> ${stockxHighestBid} </Typography> </Grid> </Grid> <Divider /> </Grid> <Grid xs={8} item> <Grid container> <Grid item xs={6}> <Grid xs={12} container direction="row" alignItems="center" className={styles.divider} > <ButtonGroup variant="contained" color="primary" aria-label=" contained primary button group" > <Button onClick={() => { const newDate = new Date( new Date().setMonth(new Date().getMonth() - 1) ); updateMarketData( itemInfo.siteLinks.stockX.id, newDate, new Date() ); }} > 1M </Button> <Button onClick={() => { const newDate = new Date( new Date().setMonth(new Date().getMonth() - 3) ); updateMarketData( itemInfo.siteLinks.stockX.id, newDate, new Date() ); }} > 3M </Button> <Button onClick={() => { const newDate = new Date( new Date().setMonth(new Date().getMonth() - 6) ); updateMarketData( itemInfo.siteLinks.stockX.id, newDate, new Date() ); }} > 6M </Button> <Button onClick={() => { const newDate = new Date( new Date().setFullYear( new Date().getFullYear() - 1 ) ); updateMarketData( itemInfo.siteLinks.stockX.id, newDate, new Date() ); }} > YTD </Button> <Button onClick={() => { updateMarketData( itemInfo.siteLinks.stockX.id, "all", new Date() ); }} > All </Button> </ButtonGroup> </Grid> </Grid> <Grid xs={6} item className={styles.divider}> <Grid container direction="row" justify="flex-end" alignItems="center" > <Button onClick={handleSizesMenuClick} variant="contained" color="primary" > Size: {marketSize} </Button> <StyledMenu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleSizesMenuClose} > <Grid container direction="row" justify="flex-start" alignItems="center" spacing={1} > <Grid item xs={12}> <Button variant={ marketSize == "all" ? "contained" : "outlined" } fullWidth onClick={() => { setMarketSize("all"); updateMarketData( itemInfo.siteLinks.stockX.parentId, "all", new Date() ); }} > <Typography component="div"> <Box fontWeight="fontWeightBold" fontSize={14} letterSpacing={1} m={1} > ALL </Box> </Typography> </Button> </Grid> {Object.keys(priceMap).map((size) => ( <Grid item xs={3} key={priceMap[size].id}> <Button variant={ marketSize == size ? "contained" : "outlined" } onClick={() => { setMarketSize(size); updateMarketData( priceMap[size].id, "all", new Date() ); }} > <Typography component="div"> <Box fontWeight="fontWeightBold" fontSize={14} m={1} > {size} </Box> </Typography> </Button> </Grid> ))} </Grid> </StyledMenu> </Grid> </Grid> </Grid> <Card> <CardContent> <div id="chartdiv" style={{ width: "100%", height: "500px" }} ></div> </CardContent> </Card> </Grid> </Grid> </Grid> </Grid> </div> </React.Fragment> ); }; const mapStateToProps = (state, props) => ({ addItemModal: state.addItemModal, editItemModal: state.editItemModal, inventory: state.inventory, sales: state.sales, }); const mapDispatch = { openModal, addItem, replaceItems, openEditModal }; export default connect(mapStateToProps, mapDispatch)(ItemInfo);