-
-
Save haris-aqeel/692396c649dd2dcfe6bfab9c2b59e7d0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Button, Dialog, DialogContent, Divider, Grid, MenuItem, Stack, TextField, Typography } from '@mui/material'; | |
import PropTypes from 'prop-types'; | |
import { useForm } from 'react-hook-form'; | |
import * as Yup from 'yup'; | |
import { yupResolver } from '@hookform/resolvers/yup'; | |
import { createFilterOptions } from "@mui/material/Autocomplete"; | |
import { collection, doc, setDoc } from 'firebase/firestore'; | |
import { useSnackbar } from 'notistack'; | |
import { useEffect, useMemo, useRef, useState } from 'react'; | |
import { LoadingButton } from '@mui/lab'; | |
import { httpsCallable } from 'firebase/functions'; | |
import { DEPENDENCY_TAGS_OPTION, INTEGRATION_TAGS_OPTION } from '../../../assets/data'; | |
import { CLOUD_FUNCTIONS, DB } from '../../../auth/FirebaseApp'; | |
import ConfirmDialog from '../../../components/confirm-dialog/ConfirmDialog'; | |
import FormProvider, { | |
RHFAutocomplete, | |
RHFMultiLineText, | |
RHFSelect | |
} from '../../../components/hook-form'; | |
import Iconify from '../../../components/iconify/Iconify'; | |
import { setCompanyOperation, setCompanyProducts, setProductOperation } from '../../../redux/slices/user'; | |
import { dispatch, useSelector } from '../../../redux/store'; | |
IntegrationWizard.propTypes = { | |
fromPopup: PropTypes.bool, | |
source: PropTypes.string, | |
target: PropTypes.string, | |
handleClose: PropTypes.func, | |
open: PropTypes.bool, | |
} | |
export default function IntegrationWizard({ open = false, fromPopup = false, source, target, handleClose = () => { } }) { | |
const { enqueueSnackbar } = useSnackbar(); | |
const filter = createFilterOptions(); | |
const { companyProducts, selectedCompany, adminProductsList, companies } = useSelector(state => state.user); | |
const [productList, setProductList] = useState([]); | |
const [completeProductsList, setCompleteProductsList] = useState([]); | |
const emailRef = useRef(null); | |
const companyRef = useRef(null); | |
const product2Ref = useRef(null); | |
const [isNew, setIsNew] = useState(false); | |
const defaultValues = useMemo( | |
() => ({ | |
typeSelection: 'integration', | |
integrationA: null, | |
integrationB: null, | |
tags: [], | |
description: '', | |
}), | |
[] | |
); | |
const NewIntegrationSchema = Yup.object().shape({ | |
typeSelection: Yup.string().required('Required'), | |
integrationA: Yup.object().required('Required'), | |
integrationB: Yup.object().required('Required'), | |
tags: Yup.array().required('Required'), | |
description: Yup.string().required('Required'), | |
}); | |
const editStatus = false | |
const methods = useForm({ | |
resolver: yupResolver(NewIntegrationSchema), | |
defaultValues, | |
shouldFocusError: true, | |
}); | |
const { | |
reset, | |
handleSubmit, | |
watch, | |
setValue, | |
formState: { isSubmitting } | |
} = methods; | |
const values = watch(); | |
useEffect(() => { | |
reset(); | |
if (companyProducts) { | |
const tempProductList = []; | |
companyProducts.forEach((product) => { | |
if (product) { | |
tempProductList.push({ label: product?.name, value: product?.id, company: product?.companyName }); | |
if (product?.id === source) | |
setValue("integrationA", { label: product?.name, value: product?.id }); | |
} | |
}); | |
setProductList(tempProductList); | |
} | |
}, [companyProducts, reset, selectedCompany, setValue, source]); | |
useEffect(() => { | |
if (adminProductsList) { | |
const tempAllProductList = []; | |
adminProductsList.forEach((product) => { | |
if (product && product?.id !== source) { | |
tempAllProductList.push({ label: product?.title, value: product?.id, company: product?.companyName }); | |
if (product?.id === target) | |
setValue("integrationB", { label: product?.title, value: product?.id }); | |
} | |
}); | |
setCompleteProductsList(tempAllProductList); | |
} | |
}, [adminProductsList, companies, setValue, source, target]); | |
useEffect(() => { | |
if (values?.integrationB?.isNew && !isNew) { | |
setIsNew(true); | |
} else { | |
setIsNew(false); | |
} | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [values?.integrationB]) | |
const onSubmit = async (data) => { | |
try { | |
// reset(); | |
const fieldName = data.typeSelection === "integration" ? "integrations" : "dependencies"; | |
const tagField = data.typeSelection === "integration" ? "integrationTags" : "dependencyTags"; | |
if (data.integrationB.isNew) { | |
const returnedCompanyId = await dispatch(setCompanyOperation( | |
"create", | |
{ | |
companyName: data.companyName, | |
richTextDescription: "generated", | |
images: [], | |
}, | |
null, | |
null, | |
false | |
)); | |
const returnedProductId = await dispatch(setProductOperation( | |
"dataentry-create", | |
{ | |
companyId: returnedCompanyId, | |
companyRef: doc(DB, 'company', returnedCompanyId), | |
name: data.productName, | |
images: [], | |
mitreCategory: [], | |
targetMarket: [], | |
tags: [], | |
category: [], | |
description: "", | |
richTextDescription: "" | |
}, | |
null, | |
false, | |
)); | |
data.integrationB = { | |
label: data.productName, | |
value: returnedProductId, | |
} | |
} | |
const productRef = doc(collection(DB, 'products'), data.integrationA.value); | |
const productRefOfConnectedProduct = doc(DB, 'products', data.integrationB.value); | |
const cloudFunctionData = { | |
productId: productRef.id, | |
productIdOfConnectedProduct: productRefOfConnectedProduct.id, | |
dialogValue: { | |
cid: data.integrationB.value, | |
title: data.integrationB.label, | |
[tagField]: data.tags, | |
description: data.description, | |
}, | |
activeProduct: { | |
name: data.integrationA.label, | |
}, | |
tagField, | |
fieldName, | |
}; | |
const newIntegration = httpsCallable(CLOUD_FUNCTIONS, 'newIntegration'); | |
await newIntegration(JSON.stringify(cloudFunctionData)); | |
reset(); | |
enqueueSnackbar('Create success!'); | |
dispatch(setCompanyProducts()); | |
} catch (e) { | |
console.error(e); | |
enqueueSnackbar('Create failed!', { variant: 'error' }); | |
} finally { | |
handleClose(); | |
}; | |
} | |
const handleInvite = () => { | |
// put the product name in to a new product in firebase | |
const companiesRef = doc(collection(DB, 'company')); | |
const newProduct = { | |
name: product2Ref.current.value, | |
company: companiesRef | |
} | |
// push that to firebase using setDoc | |
const productRef = doc(collection(DB, 'products')); | |
setDoc(productRef, newProduct); | |
const newCompany = { | |
name: companyRef.current.value, | |
companyProducts: [ | |
{ | |
name: product2Ref.current.value, | |
productRef | |
} | |
] | |
} | |
setDoc(companiesRef, newCompany); | |
// const inviteData = JSON.stringify({ | |
// email, | |
// user, | |
// selectedCompany | |
// }) | |
// const handleUserInvitations = httpsCallable(CLOUD_FUNCTIONS, 'handleUserInvitations'); | |
} | |
return ( | |
<Dialog | |
maxWidth="md" | |
open={open || false} | |
onClose={handleClose} | |
aria-labelledby="alert-dialog-title" | |
aria-describedby="alert-dialog-description" | |
> | |
<DialogContent sx={{ p: 3 }}> | |
{/* <Card sx={{ p: 3 }} > */} | |
<Stack divider={<Divider orientation="vertical" flexItem />}> | |
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}> | |
<Typography variant="h4" gutterBottom> | |
Create New Relation | |
</Typography> | |
<Stack spacing={5}> | |
<RHFSelect | |
name="typeSelection" | |
size="Large" | |
helperText={ | |
<Typography variant="caption" color="text.secondary"> | |
Select the type of connection | |
</Typography> | |
} | |
> | |
<MenuItem value="integration"> | |
Integration | |
</MenuItem> | |
<MenuItem value="dependency"> | |
Dependency | |
</MenuItem> | |
</RHFSelect> | |
</Stack> | |
<Stack spacing={2}> | |
<Typography variant="body1" mt={3} mb={3}> | |
Select the products you want to show how they integrate or depend on each other. Every connection is directional, as in A depends on B or A integrates with B. You can add multiple connections for each product. | |
</Typography> | |
</Stack> | |
<Grid container spacing={3} > | |
<Grid item xs={12} md={6}> | |
<Stack direction='column' spacing={2} size={3} justifyContent="center"> | |
<RHFAutocomplete | |
disabled | |
name="integrationA" | |
label="Product 1" | |
options={productList.map((option) => option)} | |
ChipProps={{ size: 'Large' }} | |
isOptionEqualToValue={(option, value) => option.value === value.value | |
} | |
getOptionLabel={(option) => option.label || ""} | |
/> | |
{!isNew && <RHFAutocomplete | |
disabled={Boolean(target)} | |
name="integrationB" | |
label="Product 2" | |
options={completeProductsList.map((option) => option)} | |
ChipProps={{ size: 'Large' }} | |
isOptionEqualToValue={(option, value) => | |
option.value === value.value | |
} | |
filterOptions={(options, params) => { | |
const filtered = filter(options, params); | |
if (params.inputValue !== '') { | |
filtered.push({ | |
inputValue: params.inputValue, | |
company: "", | |
label: `Invite a new Partner`, | |
isNew: true | |
}); | |
} | |
return filtered.map((option) => { | |
if (option.company) { | |
return { | |
...option, | |
displayTitle: `${option.company} - ${option.label}`, | |
}; | |
} | |
return { ...option, displayTitle: option.label }; | |
}); | |
}} | |
renderOption={(props, option) => <li {...props} style={{ backgroundColor: values.integrationA?.company === option.company ? 'lightgreen' : 'default' }}>{option.displayTitle || ""}</li>} | |
/>} | |
</Stack> | |
</Grid> | |
<Grid item xs={12} md={6}> | |
<Stack direction='column' spacing={2} size={3}> | |
<RHFAutocomplete | |
name="tags" | |
label="Tags" | |
multiple freeSolo | |
options={values.typeSelection === "integration" ? INTEGRATION_TAGS_OPTION : DEPENDENCY_TAGS_OPTION} | |
ChipProps={{ size: 'small' }} | |
/> | |
<RHFMultiLineText | |
multiline | |
label="Description of Integration" | |
id="description" | |
name="description" | |
/> | |
<Stack direction='row-reverse' spacing={2} size={3}> | |
<Button | |
variant="contained" | |
color="error" | |
disabled={isSubmitting} | |
onClick={() => { | |
reset(); | |
handleClose(); | |
}} | |
> | |
Cancel | |
</Button> | |
<LoadingButton | |
type="submit" | |
variant="contained" | |
size="large" | |
startIcon={<Iconify icon="carbon:add-filled" />} | |
loadingPosition="start" | |
loading={isSubmitting} | |
> | |
{editStatus ? "Update" : "Add"} | |
</LoadingButton> | |
</Stack> | |
</Stack> | |
</Grid> | |
</Grid > | |
</FormProvider > | |
</Stack> | |
{/* </Card > */} | |
</DialogContent> | |
<ConfirmDialog | |
open={isNew} | |
onClose={() => setIsNew(false)} | |
title="Invite New Product" | |
content={ | |
<Stack direction="column" spacing={2} mt={2}> | |
<TextField | |
placeholder='Search by Email' | |
fullWidth | |
type="email" | |
inputValue={emailRef} | |
/> | |
<TextField | |
name="companyName" | |
label="Company Name" | |
inputValue={companyRef} | |
/> | |
<TextField | |
name="productName" | |
label="Product 2" | |
inputValue={product2Ref} | |
/> | |
</Stack> | |
} | |
action={ | |
<LoadingButton | |
loading={false} | |
variant="contained" | |
color="primary" | |
// !validateEmail(emailInvite) | |
disabled={false} | |
startIcon={<Iconify icon="mdi:invite" />} | |
loadingPosition="start" | |
onClick={() => { | |
handleInvite(); | |
}} | |
> | |
Invite | |
</LoadingButton> | |
} | |
/> | |
</Dialog> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment