1
0
Fork 0
freesewing/sites/shared/components/wrappers/workbench.js
Joost De Cock 640b7231be fix(shared): Avoid flash of draft error before re-render
When measurments are missing, the useEffect hook will rerender to show
the measurements page. However, before that happens there's a brief
flash of the (failed) draft because it errors without the measurements.

This prevents that by passing down whether or not all required
measurements are available, and if not the draft returns null
2022-06-23 10:11:41 +02:00

153 lines
4.5 KiB
JavaScript

import { useEffect, useState, useMemo,} from 'react'
import {useGist} from 'shared/hooks/useGist'
import Layout from 'shared/components/layouts/default'
import Menu from 'shared/components/workbench/menu/index.js'
import DraftError from 'shared/components/workbench/draft/error.js'
import theme from '@freesewing/plugin-theme'
import preloaders from 'shared/components/workbench/preload.js'
import Modal from 'shared/components/modal'
// Views
import Measurements from 'shared/components/workbench/measurements/index.js'
import LabDraft from 'shared/components/workbench/draft/index.js'
import LabSample from 'shared/components/workbench/sample.js'
import ExportDraft from 'shared/components/workbench/export.js'
import GistAsJson from 'shared/components/workbench/json.js'
import GistAsYaml from 'shared/components/workbench/yaml.js'
import DraftEvents from 'shared/components/workbench/events.js'
import CutLayout from 'shared/components/workbench/layout/cut'
import PrintLayout from 'shared/components/workbench/layout/print'
const views = {
measurements: Measurements,
draft: LabDraft,
test: LabSample,
printingLayout: PrintLayout,
cuttingLayout: CutLayout,
export: ExportDraft,
events: DraftEvents,
yaml: GistAsYaml,
json: GistAsJson,
welcome: () => <p>TODO</p>,
}
const hasRequiredMeasurementsMethod = (design, gist) => {
for (const m of design.config.measurements || []) {
if (!gist?.measurements?.[m]) return false
}
return true
}
/*
* This component wraps the workbench and is in charge of
* keeping the gist state, which will trickle down
* to all workbench subcomponents
*/
const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false }) => {
// State for gist
const [gist, setGist, gistReady] = useGist(design, app);
const [messages, setMessages] = useState([])
const [popup, setPopup] = useState(false)
// We'll use this in more than one location
const hasRequiredMeasurements = hasRequiredMeasurementsMethod(design, gist)
// If we don't have the required measurements,
// force view to measurements
useEffect(() => {
if (gistReady && gist._state?.view !== 'measurements'
&& !hasRequiredMeasurements
) updateGist(['_state', 'view'], 'measurements')
}, [gistReady, gist._state.view, hasRequiredMeasurements])
// If we need to preload the gist, do so
useEffect(() => {
const doPreload = async () => {
if (preload && from && preloaders[from]) {
const g = await preloaders[from](preload, design)
setGist({value: { ...gist, ...g.settings }, type: 'replace'})
}
}
doPreload();
}, [preload, from])
// Helper methods to manage the gist state
const updateGist = useMemo(() => (path, value, closeNav=false) => {
setGist({path, value})
// Force close of menu on mobile if it is open
if (closeNav && app.primaryMenu) app.setPrimaryMenu(false)
}, [app])
const unsetGist = (path) => {
setGist({path, type: 'unset'})
}
// Helper methods to handle messages
const feedback = {
add: msg => {
const newMsgs = [...messages]
if (Array.isArray(msg)) newMsgs.push(...msg)
else newMsgs.push(msg)
setMessages(newMsgs)
},
set: setMessages,
clear: () => setMessages([]),
}
// Generate the draft here so we can pass it down
let draft = false
if (['draft', 'events', 'test'].indexOf(gist._state?.view) !== -1) {
draft = new design(gist)
if (gist.renderer === 'svg') draft.use(theme)
try {
if (gist._state.view !== 'test') draft.draft()
}
catch(error) {
console.log('Failed to draft design', error)
return <DraftError error={error} app={app} draft={draft} at={'draft'} />
}
}
// Props to pass down
const componentProps = {
app,
design,
gist,
updateGist,
unsetGist,
setGist,
draft,
feedback,
gistReady,
showInfo: setPopup,
hasRequiredMeasurements,
}
// Required props for layout
const layoutProps = {
app: app,
noSearch: true,
workbench: true,
AltMenu: <Menu {...componentProps }/>,
showInfo: setPopup,
}
// Layout to use
const LayoutComponent = layout
? layout
: Layout
const Component = views[gist._state?.view]
? views[gist._state.view]
: views.welcome
return <LayoutComponent {...layoutProps}>
{messages}
<Component {...componentProps} />
{popup && <Modal cancel={() => setPopup(false)}>{popup}</Modal>}
</LayoutComponent>
}
export default WorkbenchWrapper