feat: close add machine wizard on success
fix: remove done button fix: auto close on success fix: show success message fix: move add machine to main nav fix: steps overlap fix: no console logs, simplify some lines fix: remove spinner and toast fix: show info3 message on pairing success fix: eslint fix: consider the machine name while verifying if the new machine is paired
This commit is contained in:
parent
92eebd630e
commit
c56d4759bd
9 changed files with 1413 additions and 216 deletions
|
|
@ -1,17 +1,19 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
||||
import { Dialog, DialogContent, SvgIcon, IconButton } from '@material-ui/core'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { Form, Formik, FastField } from 'formik'
|
||||
import gql from 'graphql-tag'
|
||||
import QRCode from 'qrcode.react'
|
||||
import React, { memo, useState } from 'react'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo, useEffect } from 'react'
|
||||
import { useSetState, useCounter, useBoolean, useLifecycles } from 'react-use'
|
||||
import * as Yup from 'yup'
|
||||
|
||||
import Title from 'src/components/Title'
|
||||
import { Button } from 'src/components/buttons'
|
||||
import { TextInput } from 'src/components/inputs/formik'
|
||||
import Sidebar, { Stepper } from 'src/components/layout/Sidebar'
|
||||
import { Info2, P } from 'src/components/typography'
|
||||
import Sidebar from 'src/components/layout/Sidebar'
|
||||
import { Info2, P, Info3 } from 'src/components/typography'
|
||||
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
||||
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg'
|
||||
import { primaryColor } from 'src/styling/variables'
|
||||
|
|
@ -23,12 +25,44 @@ const SAVE_CONFIG = gql`
|
|||
createPairingTotem(name: $name)
|
||||
}
|
||||
`
|
||||
const GET_MACHINES = gql`
|
||||
{
|
||||
machines {
|
||||
name
|
||||
deviceId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const QrCodeComponent = ({ classes, qrCode, close }) => {
|
||||
const [doneButton, setDoneButton] = useState(null)
|
||||
setTimeout(() => setDoneButton(true), 2000)
|
||||
const getSize = R.compose(R.length, R.pathOr([], ['machines']))
|
||||
|
||||
function usePairDevice({ name, count }) {
|
||||
const [on, toggle] = useBoolean(false)
|
||||
const { data, stopPolling, startPolling } = useQuery(GET_MACHINES)
|
||||
const size = getSize(data)
|
||||
|
||||
useLifecycles(() => startPolling(10000), stopPolling)
|
||||
useEffect(() =>
|
||||
size > count && data?.machines?.some(m => m.name === name)
|
||||
? toggle(true)
|
||||
: undefined
|
||||
)
|
||||
|
||||
return [on]
|
||||
}
|
||||
|
||||
const QrCodeComponent = ({ classes, payload, close, onPaired }) => {
|
||||
const { qrcode, count, name } = payload
|
||||
const [paired] = usePairDevice({ name, count })
|
||||
|
||||
useEffect(() => {
|
||||
if (paired) {
|
||||
onPaired(name)
|
||||
setTimeout(() => close(), 3000)
|
||||
}
|
||||
}, [close, name, onPaired, paired])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -37,26 +71,23 @@ const QrCodeComponent = ({ classes, qrCode, close }) => {
|
|||
</Info2>
|
||||
<div className={classes.qrCodeWrapper}>
|
||||
<div>
|
||||
<QRCode size={240} fgColor={primaryColor} value={qrCode} />
|
||||
<QRCode size={240} fgColor={primaryColor} value={qrcode} />
|
||||
</div>
|
||||
<div className={classes.qrTextWrapper}>
|
||||
<div className={classes.qrTextIcon}>
|
||||
<WarningIcon />
|
||||
<div className={classes.qrCodeWrapper}>
|
||||
<div className={classes.qrTextIcon}>
|
||||
<WarningIcon />
|
||||
</div>
|
||||
<P className={classes.qrText}>
|
||||
To pair the machine you need scan the QR code with your machine.
|
||||
To do this either snap a picture of this QR code or download it
|
||||
through the button above and scan it with the scanning bay on your
|
||||
machine.
|
||||
</P>
|
||||
</div>
|
||||
<P className={classes.qrText}>
|
||||
To pair the machine you need scan the QR code with your machine. To
|
||||
do this either snap a picture of this QR code or download it through
|
||||
the button above and scan it with the scanning bay on your machine.
|
||||
</P>
|
||||
{paired && <Info3>✓ Machine has been successfully paired</Info3>}
|
||||
</div>
|
||||
</div>
|
||||
{doneButton && (
|
||||
<div className={classes.button}>
|
||||
<Button type="submit" onClick={close}>
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -71,13 +102,10 @@ const validationSchema = Yup.object().shape({
|
|||
.max(50, 'Too long')
|
||||
})
|
||||
|
||||
const MachineNameComponent = ({ nextStep, classes, setQrCode }) => {
|
||||
const MachineNameComponent = ({ nextStep, classes, setPayload }) => {
|
||||
const [register] = useMutation(SAVE_CONFIG, {
|
||||
onCompleted: data => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log('totem: ', data.createPairingTotem)
|
||||
}
|
||||
setQrCode(data.createPairingTotem)
|
||||
onCompleted: ({ createPairingTotem }) => {
|
||||
setPayload({ qrcode: createPairingTotem })
|
||||
nextStep()
|
||||
},
|
||||
onError: e => console.log(e)
|
||||
|
|
@ -92,6 +120,7 @@ const MachineNameComponent = ({ nextStep, classes, setQrCode }) => {
|
|||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={({ name }) => {
|
||||
setPayload({ name })
|
||||
register({ variables: { name } })
|
||||
}}>
|
||||
<Form className={classes.form}>
|
||||
|
|
@ -122,47 +151,80 @@ const steps = [
|
|||
}
|
||||
]
|
||||
|
||||
const AddMachine = memo(({ close }) => {
|
||||
const renderStepper = (step, it, idx, classes) => {
|
||||
const active = step === idx
|
||||
const past = idx < step
|
||||
const future = idx > step
|
||||
|
||||
return (
|
||||
<div className={classes.item}>
|
||||
<span
|
||||
className={classnames({
|
||||
[classes.itemText]: true,
|
||||
[classes.itemTextActive]: active,
|
||||
[classes.itemTextPast]: past
|
||||
})}>
|
||||
{it.label}
|
||||
</span>
|
||||
{active && <CurrentStageIconZodiac />}
|
||||
{past && <CompleteStageIconZodiac />}
|
||||
{future && <EmptyStageIconZodiac />}
|
||||
{idx < steps.length - 1 && (
|
||||
<div
|
||||
className={classnames({
|
||||
[classes.stepperPath]: true,
|
||||
[classes.stepperPast]: past
|
||||
})}></div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const AddMachine = memo(({ close, onPaired }) => {
|
||||
const classes = useStyles()
|
||||
const [qrCode, setQrCode] = useState(null)
|
||||
const [step, setStep] = useState(0)
|
||||
const { data } = useQuery(GET_MACHINES)
|
||||
const [payload, setPayload] = useSetState({ qrcode: '', name: '', count: 0 })
|
||||
const [step, { inc }] = useCounter(0, steps.length, 0)
|
||||
const count = getSize(data)
|
||||
|
||||
useEffect(() => setPayload({ count }), [count, setPayload])
|
||||
|
||||
const Component = steps[step].component
|
||||
return (
|
||||
<Dialog
|
||||
fullScreen
|
||||
className={classes.dialog}
|
||||
open={true}
|
||||
aria-labelledby="form-dialog-title">
|
||||
<DialogContent className={classes.dialog}>
|
||||
<div className={classes.wrapper}>
|
||||
<div className={classes.headerDiv}>
|
||||
<Title>Add Machine</Title>
|
||||
<IconButton disableRipple={true} onClick={close}>
|
||||
<SvgIcon color="error">
|
||||
<CloseIcon />
|
||||
</SvgIcon>
|
||||
</IconButton>
|
||||
</div>
|
||||
<div className={classes.contentDiv}>
|
||||
<Sidebar>
|
||||
{steps.map((it, idx) => (
|
||||
<Stepper step={step} it={it} idx={idx} steps={steps} />
|
||||
))}
|
||||
</Sidebar>
|
||||
<div className={classes.contentWrapper}>
|
||||
<Component
|
||||
classes={classes}
|
||||
qrCode={qrCode}
|
||||
close={close}
|
||||
setQrCode={setQrCode}
|
||||
nextStep={() => setStep(step + 1)}
|
||||
/>
|
||||
<div>
|
||||
<Dialog
|
||||
fullScreen
|
||||
className={classes.dialog}
|
||||
open={true}
|
||||
aria-labelledby="form-dialog-title">
|
||||
<DialogContent className={classes.dialog}>
|
||||
<div className={classes.wrapper}>
|
||||
<div className={classes.headerDiv}>
|
||||
<Title>Add Machine</Title>
|
||||
<IconButton disableRipple={true} onClick={close}>
|
||||
<SvgIcon color="error">
|
||||
<CloseIcon />
|
||||
</SvgIcon>
|
||||
</IconButton>
|
||||
</div>
|
||||
<div className={classes.contentDiv}>
|
||||
<Sidebar>
|
||||
{steps.map((it, idx) => renderStepper(step, it, idx, classes))}
|
||||
</Sidebar>
|
||||
<div className={classes.contentWrapper}>
|
||||
<Component
|
||||
classes={classes}
|
||||
nextStep={() => inc(1)}
|
||||
close={close}
|
||||
onPaired={onPaired}
|
||||
{...{ payload, setPayload }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue