diff --git a/src/navigation/Router.tsx b/src/navigation/Router.tsx index a576a50..27b9995 100644 --- a/src/navigation/Router.tsx +++ b/src/navigation/Router.tsx @@ -21,6 +21,7 @@ import Ventilation from "pages/VentEditor"; // import Transactions from "pages/Transactions"; // import BinCableEstimator from "pages/BinCableEstimator"; import { useGlobalState } from "providers"; +import Marketplace from "userFeatures/UserFeatures"; // import Fields from "pages/Fields"; //import Site from "pages/Site"; @@ -329,6 +330,7 @@ export default function Router(props: Props) { } /> } } /> + } /> {/* Map pages */} } /> diff --git a/src/navigation/SideNavigator.tsx b/src/navigation/SideNavigator.tsx index 007b345..2b8e46d 100644 --- a/src/navigation/SideNavigator.tsx +++ b/src/navigation/SideNavigator.tsx @@ -366,6 +366,18 @@ export default function SideNavigator(props: Props) { } + + goTo("/marketplace")} + classes={getClasses("/marketplace")} + > + + + + {open && } + + ) } diff --git a/src/pages/Marketplace.tsx b/src/pages/Marketplace.tsx new file mode 100644 index 0000000..9015b38 --- /dev/null +++ b/src/pages/Marketplace.tsx @@ -0,0 +1,10 @@ +import PageContainer from "./PageContainer"; +import UserFeatures from "userFeatures/UserFeatures"; + +export default function Marketplace() { + return ( + + + + ); +} \ No newline at end of file diff --git a/src/userFeatures/FeatureCard.tsx b/src/userFeatures/FeatureCard.tsx new file mode 100644 index 0000000..34e9478 --- /dev/null +++ b/src/userFeatures/FeatureCard.tsx @@ -0,0 +1,169 @@ +import { + // Accordion, + // AccordionDetails, + // AccordionSummary, + Avatar, + Box, + Button, + Card, + DialogActions, + DialogContent, + Divider, + Grid2 as Grid, + List, + ListItem, + Typography +} from "@mui/material"; +// import { Close, ExpandMore } from "@material-ui/icons"; +import { Close } from "@mui/icons-material"; +import ResponsiveDialog from "common/ResponsiveDialog"; +//import { useMobile } from "hooks"; +import React, { useState } from "react"; +import { ProductDetails } from "./UserFeatures"; + +interface Props { + feature: ProductDetails; + hasFeature: boolean; + updateFeature: (add: boolean) => void; +} + +export default function FeatureCard(props: Props) { + const { feature, hasFeature, updateFeature } = props; + const [openDialog, setOpenDialog] = useState(false); + // const [currentQuestion, setCurrentQuestion] = useState(0); + //const isMobile = useMobile() + + // const handleExpand = (index: number) => { + // setCurrentQuestion(index === currentQuestion ? 0 : index); + // }; + + const productDialog = () => { + return ( + { + setOpenDialog(false); + }}> + + {feature.featureName} + + + + + + + + {feature.featureLogo} + + + + {feature.featureTitle} + + + + + + {feature.featureCost > 0 ? feature.featureCost : "Free"} + + + + + {/* + + Possibly put Screenshots Here + */} + + + + + {feature.longDescription} + + {/* {feature.bulletPoints && ( +
    + {feature.bulletPoints.map((b, i) => ( +
  • + {b} +
  • + ))} +
+ )} */} +
+
+ + + + {/* {feature.questions.map((q, i) => ( + handleExpand(i + 1)}> + }> + + {q.question} + + + + {q.answer} + + + ))} */} + + +
+
+
+ ); + }; + + return ( + + {productDialog()} + { + setOpenDialog(true); + }}> + + {feature.featureName} + + + + {feature.featureLogo} + + + + {feature.featureTitle} + + + {feature.featureCost > 0 ? feature.featureCost : "Free"} + + + + + + ); +} \ No newline at end of file diff --git a/src/userFeatures/UserFeatures.tsx b/src/userFeatures/UserFeatures.tsx new file mode 100644 index 0000000..9f9a2f4 --- /dev/null +++ b/src/userFeatures/UserFeatures.tsx @@ -0,0 +1,143 @@ +import { Box, Grid2 as Grid } from "@mui/material"; + +import { useGlobalState } from "providers"; +import { useSnackbar, useUserAPI } from "hooks"; +import React, { useEffect, useState } from "react"; +import JohnDeereIcon from "products/CommonIcons/johnDeereIcon"; +import CNHiIcon from "products/CommonIcons/cnhiIcon"; +//import AgLogo from "assets/whitelabels/AdaptiveAgriculture/AGLogoSquare.png"; +import { + IsAdaptiveAgriculture + // IsAdCon, + // IsMiVent, + // IsOmniAir +} from "services/whiteLabel"; +import FeatureCard from "./FeatureCard"; +//import { ImgIcon } from "common/ImgIcon"; +//images to import for the image in the card for the feature make sure to have a 2:1 aspect ratio to keep the cards symmetrical +import FeatureImageTest from "assets/marketplaceImages/VisualFarmMPImage.png"; + +// export interface FAQ { +// question: string; +// answer: string; +// } + +export interface ProductDetails { + featureName: string; //string matching the entry in the features array found in Users.tsx + featureTitle: string; //title of feature to display to user + featureCost: number; + cardImage: string; //image to display on the feature card + featureLogo: JSX.Element; //image to display in the logo section of the card and product dialog + //galleryImages: string[] //screenshots to show the feature in action + longDescription: string; //a longer description of the feature to show in the dialog + // bulletPoints?: string[]; + // questions: FAQ[]; + hidden?: boolean; //if the feature is not quite ready for the public ie in testing, if a user has the beta flag they will see these hidden features +} + +const agFeatureList: ProductDetails[] = [ + { + featureName: "john-deere", + featureLogo: , + featureCost: 0, + cardImage: FeatureImageTest, + featureTitle: "John Deere Operations Center", + longDescription: + "Integrate with the John Deere Operations Center to bring your data into our platform" + // bulletPoints: ["bullet one", "bullet two"], + // questions: [ + // { question: "question 1", answer: "answer 1" }, + // { question: "question 2", answer: "answer 2" } + // ] + }, + { + featureName: "cnhi", + featureLogo: , + featureCost: 0, + cardImage: FeatureImageTest, + featureTitle: "Case New Holland Industrial Center", + longDescription: + "Integrate with the Case New Holland Industrial Center to bring your data into our platform" + // bulletPoints: ["bullet one", "bullet two"], + // questions: [], + } +]; + +// const constructionFeatureList: ProductDetails[] = [] + +// const aviationFeatureList: ProductDetails[] = [] + +// const miningFeatureList: ProductDetails[] = [] + +// const universalFeatureList: ProductDetails[] = [] + +export default function Marketplace() { + const [{ user }, dispatch] = useGlobalState(); + const userAPI = useUserAPI(); + const [userFeatures, setUserFeatures] = useState([]); + const [featureList, setFeaturList] = useState([]); + const { error, success } = useSnackbar(); + + useEffect(() => { + let list: ProductDetails[] = []; + if (IsAdaptiveAgriculture()) { + list = list.concat(agFeatureList); + } + // if(IsAdCon()){ + // list = list.concat(constructionFeatureList) + // } + // if(IsOmniAir()){ + // list = list.concat(aviationFeatureList) + // } + // if(IsMiVent()){ + // list = list.concat(miningFeatureList) + // } + // list = list.concat(universalFeatureList) + setFeaturList(list); + }, []); + + useEffect(() => { + setUserFeatures(user.settings.features); + }, [user]); + + const updateUser = (feature: string, added: boolean) => { + if (added) { + user.settings.features.push(feature); + } else { + user.settings.features = user.settings.features.filter(v => v !== feature); + } + setUserFeatures([...user.settings.features]); + userAPI + .updateUser(user.id(), user.protobuf()) + .then(resp => { + success("Updated " + feature + " feature"); + dispatch({ key: "user", value: user }); + }) + .catch(err => { + error("Failed to update " + feature + " feature"); + }); + }; + + return ( + + + {featureList.map(feat => { + if (!feat.hidden || user.hasFeature("beta")) { + return ( + + { + updateUser(feat.featureName, checked); + }} + hasFeature={userFeatures.includes(feat.featureName)} + /> + + ); + } + return null; + })} + + + ); +}