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.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.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;
+ })}
+
+
+ );
+}