added the marketplace page to be able to add the jd and cnh features
This commit is contained in:
parent
2816884771
commit
411ff5b14c
5 changed files with 336 additions and 0 deletions
|
|
@ -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) {
|
|||
<Route path="api" element={<APIDocs />} />
|
||||
}
|
||||
<Route path="fields" element={<Fields />} />
|
||||
<Route path="marketplace" element={<Marketplace />} />
|
||||
|
||||
{/* Map pages */}
|
||||
<Route path="visualFarm" element={<FieldMap />} />
|
||||
|
|
|
|||
|
|
@ -366,6 +366,18 @@ export default function SideNavigator(props: Props) {
|
|||
</ListItemButton>
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip title="Marketplace" placement="right">
|
||||
<ListItemButton
|
||||
id="tour-marketplace"
|
||||
onClick={() => goTo("/marketplace")}
|
||||
classes={getClasses("/marketplace")}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Code />
|
||||
</ListItemIcon>
|
||||
{open && <ListItemText primary="Marketplace" />}
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
</List>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
10
src/pages/Marketplace.tsx
Normal file
10
src/pages/Marketplace.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import PageContainer from "./PageContainer";
|
||||
import UserFeatures from "userFeatures/UserFeatures";
|
||||
|
||||
export default function Marketplace() {
|
||||
return (
|
||||
<PageContainer>
|
||||
<UserFeatures />
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
169
src/userFeatures/FeatureCard.tsx
Normal file
169
src/userFeatures/FeatureCard.tsx
Normal file
|
|
@ -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 (
|
||||
<ResponsiveDialog
|
||||
open={openDialog}
|
||||
onClose={() => {
|
||||
setOpenDialog(false);
|
||||
}}>
|
||||
<DialogActions style={{ padding: 0 }}>
|
||||
<img width="100%" alt={feature.featureName} src={feature.cardImage} />
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenDialog(false);
|
||||
}}
|
||||
style={{ position: "absolute", top: "10px" }}>
|
||||
<Close />
|
||||
</Button>
|
||||
</DialogActions>
|
||||
<DialogContent style={{ padding: 8 }}>
|
||||
<List>
|
||||
<ListItem>
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
wrap="nowrap"
|
||||
justifyContent="space-between">
|
||||
<Grid>
|
||||
<Avatar style={{ height: 40, width: 40 }}>{feature.featureLogo}</Avatar>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Typography style={{ fontWeight: 650, fontSize: 15 }}>
|
||||
{feature.featureTitle}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
updateFeature(!hasFeature);
|
||||
}}>
|
||||
{hasFeature ? "Deactivate" : "Activate"}
|
||||
</Button>
|
||||
<Typography style={{ fontWeight: 350, fontSize: 15 }}>
|
||||
{feature.featureCost > 0 ? feature.featureCost : "Free"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ListItem>
|
||||
{/* <Divider />
|
||||
<ListItem>
|
||||
Possibly put Screenshots Here
|
||||
</ListItem> */}
|
||||
<Divider />
|
||||
<ListItem>
|
||||
<Box>
|
||||
<Typography style={{ fontWeight: 350, fontSize: 13 }}>
|
||||
{feature.longDescription}
|
||||
</Typography>
|
||||
{/* {feature.bulletPoints && (
|
||||
<ul>
|
||||
{feature.bulletPoints.map((b, i) => (
|
||||
<li key={i} style={{ display: "list-item" }}>
|
||||
<Typography style={{ fontWeight: 350, fontSize: 13 }}>{b}</Typography>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)} */}
|
||||
</Box>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem disableGutters>
|
||||
<Box style={{ width: "100%" }}>
|
||||
{/* {feature.questions.map((q, i) => (
|
||||
<Accordion
|
||||
key={i}
|
||||
expanded={currentQuestion === i + 1}
|
||||
onChange={() => handleExpand(i + 1)}>
|
||||
<AccordionSummary expandIcon={<ExpandMore />}>
|
||||
<Typography style={{ fontWeight: 650, fontSize: 13 }}>
|
||||
{q.question}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography style={{ fontWeight: 350, fontSize: 13 }}>{q.answer}</Typography>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))} */}
|
||||
</Box>
|
||||
</ListItem>
|
||||
</List>
|
||||
</DialogContent>
|
||||
</ResponsiveDialog>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{productDialog()}
|
||||
<Card
|
||||
style={{ height: "100%", cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
setOpenDialog(true);
|
||||
}}>
|
||||
<Box width="100%" alignItems="center" display="flex" justifyContent="center">
|
||||
<img width="100%" alt={feature.featureName} src={feature.cardImage} />
|
||||
</Box>
|
||||
<Grid
|
||||
style={{ padding: 10 }}
|
||||
container
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={1}
|
||||
wrap="nowrap">
|
||||
<Grid>
|
||||
<Avatar style={{ height: 40, width: 40 }}>{feature.featureLogo}</Avatar>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Typography style={{ fontWeight: 650, fontSize: 17 }}>
|
||||
{feature.featureTitle}
|
||||
</Typography>
|
||||
<Typography style={{ fontWeight: 350, fontSize: 15 }}>
|
||||
{feature.featureCost > 0 ? feature.featureCost : "Free"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
143
src/userFeatures/UserFeatures.tsx
Normal file
143
src/userFeatures/UserFeatures.tsx
Normal file
|
|
@ -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: <JohnDeereIcon />,
|
||||
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: <CNHiIcon />,
|
||||
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<string[]>([]);
|
||||
const [featureList, setFeaturList] = useState<ProductDetails[]>([]);
|
||||
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 (
|
||||
<Box padding={2}>
|
||||
<Grid container spacing={3} justifyContent="space-between" alignItems="center" alignContent="center">
|
||||
{featureList.map(feat => {
|
||||
if (!feat.hidden || user.hasFeature("beta")) {
|
||||
return (
|
||||
<Grid key={feat.featureName} size={{ xs:12, sm:6, md:4, lg:4}}>
|
||||
<FeatureCard
|
||||
feature={feat}
|
||||
updateFeature={checked => {
|
||||
updateUser(feat.featureName, checked);
|
||||
}}
|
||||
hasFeature={userFeatures.includes(feat.featureName)}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue