1
0
Fork 0
freesewing/sites/shared/components/workbench/views/save/index.mjs
2023-05-31 15:32:54 +02:00

265 lines
6.8 KiB
JavaScript

// Dependencies
import { capitalize, shortDate } from 'shared/utils.mjs'
// Hooks
import { useState, useContext } from 'react'
import { useTranslation } from 'next-i18next'
import { useRouter } from 'next/router'
import { useAccount } from 'shared/hooks/use-account.mjs'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
// Context
import { LoadingContext } from 'shared/context/loading-context.mjs'
// Components
import { Spinner } from 'shared/components/spinner.mjs'
export const ns = ['wbsave']
const whereAreWe = (router = false, design, from) => {
const info = {}
if (router?.asPath) {
info.locale = router.locale
if (from && from.type) {
if (from.type === 'pattern') {
// Editing an existing pattern
info.edit = true
info.patternId = from.data.id
if (from.data.set) info.set = from.data.setId
else if (from.data.cset) info.cset = from.data.csetId
} else if (from.type === 'new') {
// Creating a new pattern
const chunks = router.asPath.split('/')
info.design = chunks[3]
info.from = chunks[4]
info.fromId = chunks[5].split('#').shift()
if (info.design !== design) throw 'Design passed to view does not match URL state'
}
}
}
return info
}
const defaultName = (info) =>
`${capitalize(info.design)} / ${info.from}-${info.fromId} / ${shortDate(info.locale)}`
const SaveNewPattern = ({
t,
design,
settings,
info,
backend,
loading,
startLoading,
stopLoading,
toast,
router,
}) => {
// State
const [name, setName] = useState(defaultName(info))
const update = async (evt) => {
evt.preventDefault()
if (evt.target.value !== name) setName(evt.target.value)
}
const save = async () => {
startLoading()
const data = {
data: {},
design,
name,
settings,
}
if (data.settings.measurements) delete data.settings.measurements
if (data.settings.embed) delete data.settings.embed
if (info.from === 'set' && info.fromId) data.set = Number(info.fromId)
else if (info.from === 'cset' && info.fromId) data.cset = Number(info.fromId)
else return toast.error(<span>¯\_()_/¯</span>)
const result = await backend.createPattern(data)
if (result.success) {
toast.for.settingsSaved()
router.push(`/patterns/${result.data.pattern.id}`)
} else toast.for.backendError()
stopLoading()
}
return (
<div className="max-w-sm w-full">
<h2>Save to your FreeSewing account</h2>
<label className="font-bold">{t('wbsave:giveItAName')}</label>
<input
value={name}
onChange={update}
className="input w-full input-bordered flex flex-row"
type="text"
placeholder={t('title')}
/>
<button className="btn mt-4 capitalize btn-primary w-full" onClick={save}>
<span className="flex flex-row items-center gap-2">
{loading ? (
<>
<Spinner />
<span>{t('processing')}</span>
</>
) : (
t('save')
)}
</span>
</button>
</div>
)
}
const SaveExistingPattern = ({
t,
design,
settings,
info,
backend,
loading,
startLoading,
stopLoading,
toast,
router,
from,
}) => {
// State
const [name, setName] = useState(from.name ? from.name : defaultName(info))
const update = async (evt) => {
evt.preventDefault()
if (evt.target.value !== name) setName(evt.target.value)
}
const save = async () => {
startLoading()
const data = {
settings: {
...settings,
measurements: { ...settings.measurements },
},
}
if (data.settings.measurements) delete data.settings.measurements
if (data.settings.embed) delete data.settings.embed
const result = await backend.updatePattern(from.data.id, data)
if (result.success) {
toast.for.settingsSaved()
} else toast.for.backendError()
stopLoading()
}
const saveAs = async () => {
startLoading()
const data = {
data: {},
design,
name,
settings: {
...settings,
measurements: { ...settings.measurements },
},
}
if (data.settings.measurements) delete data.settings.measurements
if (data.settings.embed) delete data.settings.embed
if (info.set) data.set = info.set
else if (info.cset) data.cset = info.cset
else return toast.error(<span>¯\_()_/¯</span>)
const result = await backend.createPattern(data)
if (result.success) {
toast.for.settingsSaved()
router.push(`/patterns/${result.data.pattern.id}`)
} else toast.for.backendError()
stopLoading()
}
return (
<>
<div className="max-w-sm w-full">
<h2>{t('savePattern')}</h2>
<button className="btn mt-4 capitalize btn-primary w-full" onClick={save}>
<span className="flex flex-row items-center gap-2">
{loading ? (
<>
<Spinner />
<span>{t('processing')}</span>
</>
) : (
t('save')
)}
</span>
</button>
</div>
<div className="max-w-sm w-full">
<h2>{t('saveAsPattern')}</h2>
<label className="font-bold">{t('wbsave:giveItAName')}</label>
<input
value={name}
onChange={update}
className="input w-full input-bordered flex flex-row"
type="text"
placeholder={from.data.name ? from.data.name : t('title')}
/>
<button className="btn mt-4 capitalize btn-primary w-full" onClick={saveAs}>
<span className="flex flex-row items-center gap-2">
{loading ? (
<>
<Spinner />
<span>{t('processing')}</span>
</>
) : (
t('save')
)}
</span>
</button>
</div>
</>
)
}
export const SaveView = ({
design,
setView,
settings,
ui,
update,
language,
DynamicDocs,
from = false,
}) => {
// Hooks
const { t } = useTranslation(ns)
const { token } = useAccount()
const backend = useBackend(token)
const router = useRouter()
const toast = useToast()
// Context
const { loading, startLoading, stopLoading } = useContext(LoadingContext)
const info = whereAreWe(router, design, from)
const saveProps = {
t,
design,
settings,
info,
backend,
loading,
startLoading,
stopLoading,
toast,
router,
}
return (
<div className="m-auto mt-24">
<h1 className="max-w-6xl m-auto text-center">{t('wbsave:title')}</h1>
<div className="px-4 lg:px-12 flex flex-row flex-wrap gap-4 lg:gap-8 justify-around">
{info.new ? <SaveNewPattern {...saveProps} /> : null}
{info.edit ? <SaveExistingPattern {...saveProps} from={from} /> : null}
</div>
</div>
)
}