// __SDEFILE__ - This file is a dependency for the stand-alone environment // Dependencies import { useState, useEffect, useContext } from 'react' import { useTranslation } from 'next-i18next' import { freeSewingConfig as conf, controlLevels } from 'shared/config/freesewing.config.mjs' import { siteConfig } from 'site/site.config.mjs' import { horFlexClasses, objUpdate, shortDate, cloudflareImageUrl, capitalize, notEmpty, } from 'shared/utils.mjs' import { measurements } from 'config/measurements.mjs' import { measurements as designMeasurements } from 'shared/prebuild/data/design-measurements.mjs' import orderBy from 'lodash.orderby' // Hooks import { useAccount } from 'shared/hooks/use-account.mjs' import { useBackend } from 'shared/hooks/use-backend.mjs' // Context import { ModalContext } from 'shared/context/modal-context.mjs' import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs' // Components import { DisplayRow } from './account/shared.mjs' import { ModalWrapper } from 'shared/components/wrappers/modal.mjs' import { Mdx } from 'shared/components/mdx/dynamic.mjs' import Timeago from 'react-timeago' import { MeasieVal } from './account/sets.mjs' import { TrashIcon, CameraIcon, UploadIcon, OkIcon, NoIcon, BoolNoIcon, BoolYesIcon, } from 'shared/components/icons.mjs' import { Link, PageLink } from 'shared/components/link.mjs' import { StringInput, PassiveImageInput, MarkdownInput, MeasieInput, DesignDropdown, ListInput, NumberInput, ns as inputNs, } from 'shared/components/inputs.mjs' export const ns = ['account', 'patterns', 'status', 'measurements', 'sets', inputNs] const SetLineup = ({ sets = [], href = false, onClick = false }) => (
1 ? 'justify-start px-8' : 'justify-center' } overflow-x-scroll`} style={{ backgroundImage: `url(/img/lineup-backdrop.svg)`, width: 'auto', backgroundSize: 'auto 100%', backgroundRepeat: 'repeat-x', }} > {sets.map((set) => { const props = { className: 'aspect-[1/3] w-auto h-96', style: { backgroundImage: `url(${cloudflareImageUrl({ id: `cset-${set.id}`, type: 'lineup' })})`, width: 'auto', backgroundSize: 'contain', backgroundRepeat: 'no-repeat', backgroundPosition: 'center', }, } if (onClick) props.onClick = () => onClick(set) else if (typeof href === 'function') props.href = href(set.id) if (onClick) return else if (href) return else return
})}
) const ShowCuratedSet = ({ cset }) => { const { control } = useAccount() const { t, i18n } = useTranslation(ns) const lang = i18n.language const { setModal } = useContext(ModalContext) if (!cset) return null return ( <>

{cset[`name${capitalize(lang)}`]}

{control > 3 && ( <> JSON YAML )}

{t('data')}

{cset.height}cm {control >= controlLevels.sets.notes && ( )} {control >= controlLevels.sets.createdAt && ( | {shortDate(i18n.language, cset.createdAt, false)} )} {control >= controlLevels.sets.updatedAt && ( | {shortDate(i18n.language, cset.updatedAt, false)} )} {control >= controlLevels.sets.id && {cset.id}}

{t('measies')}

{Object.entries(cset.measies).map(([m, val]) => val > 0 ? ( } key={m}> {t(m)} ) : null )} ) } export const CuratedSet = ({ id }) => { // Hooks const { setLoadingStatus } = useContext(LoadingStatusContext) const backend = useBackend() // State const [cset, setCset] = useState() // Effect useEffect(() => { const getCset = async () => { setLoadingStatus([true, 'status:contactingBackend']) const result = await backend.getCuratedSet(id) if (result.success) { setCset(result.data.curatedSet) setLoadingStatus([true, 'status:dataLoaded', true, true]) } else setLoadingStatus([true, 'status:backendError', true, false]) } if (id) getCset() }, [id]) if (!id || !cset) return null return (
) } // Picker version export const CuratedSetPicker = (props) => // Component for the curated-sets page export const CuratedSets = ({ href = false, clickHandler = false, published = true }) => { // Hooks const backend = useBackend() const { setLoadingStatus } = useContext(LoadingStatusContext) // State const [sets, setSets] = useState([]) const [selected, setSelected] = useState(false) // Effects useEffect(() => { const getSets = async () => { setLoadingStatus([true, 'contactingBackend']) const result = await backend.getCuratedSets() if (result.success) { const allSets = {} for (const set of result.data.curatedSets) { if (!published || set.published) allSets[set.id] = set } setSets(allSets) setLoadingStatus([true, 'status:dataLoaded', true, true]) } else setLoadingStatus([true, 'status:backendError', true, false]) } getSets() }, []) const lineupProps = { sets: orderBy(sets, 'height', 'asc'), } if (typeof href === 'function') lineupProps.href = href else lineupProps.onClick = clickHandler ? clickHandler : (set) => setSelected(set.id) return (
{selected && }
) } // Component for the maintaining the list of curated-sets export const CuratedSetsList = ({ href = false }) => { // Hooks const { t } = useTranslation(ns) const backend = useBackend() const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext) const [refresh, setRefresh] = useState(0) // State const [sets, setSets] = useState([]) const [selected, setSelected] = useState(false) // Effects useEffect(() => { const getSets = async () => { setLoadingStatus([true, 'contactingBackend']) const result = await backend.getCuratedSets() if (result.success) { const allSets = [] for (const set of result.data.curatedSets) allSets.push(set) setSets(allSets) setLoadingStatus([true, 'status:dataLoaded', true, true]) } else setLoadingStatus([true, 'status:backendError', true, false]) } getSets() }, [refresh]) // Helper var to see how many are selected const selCount = Object.keys(selected).length // Helper method to toggle single selection const toggleSelect = (id) => { const newSelected = { ...selected } if (newSelected[id]) delete newSelected[id] else newSelected[id] = 1 setSelected(newSelected) } // Helper method to toggle select all const toggleSelectAll = () => { if (selCount === selected.length) setSelected({}) else { const newSelected = {} for (const set of selected) newSelected[set.id] = 1 setSelected(newSelected) } } // Helper to delete one or more sets const removeSelected = async () => { let i = 0 for (const key in selected) { i++ await backend.removeCuratedMeasurementsSet(key) setLoadingStatus([ true, , ]) } setSelected({}) setRefresh(refresh + 1) setLoadingStatus([true, 'nailedIt', true, true]) } const lineupProps = { sets: Object.values(sets), } if (typeof href === 'function') lineupProps.href = href else lineupProps.onClick = setSelected return (
{selCount ? ( ) : null} {sets.map((set) => ( ))}
{t('curate:id')} {t('curate:img')} {t('curate:name')} {t('curate:published')} {t('curate:height')} {t('curate:createdAt')}
toggleSelect(set.id)} /> {set.published ? : } {set.height}cm {set.createdAt}
) } export const EditCuratedSet = ({ id }) => { // Hooks const { account } = useAccount() const { setLoadingStatus } = useContext(LoadingStatusContext) const backend = useBackend() const { t } = useTranslation(ns) const [filter, setFilter] = useState(false) const [cset, setCset] = useState() const [data, setData] = useState({}) // Effect useEffect(() => { const getCuratedSet = async () => { setLoadingStatus([true, t('backendLoadingStarted')]) const result = await backend.getCuratedSet(id) if (result.success) { setCset(result.data.curatedSet) const initData = { img: result.data.curatedSet.img, published: result.data.curatedSet.published, measies: { ...result.data.curatedSet.measies }, } for (const lang of siteConfig.languages) { let k = `name${capitalize(lang)}` initData[k] = result.data.curatedSet[k] k = `notes${capitalize(lang)}` initData[k] = result.data.curatedSet[k] } setData(initData) setLoadingStatus([true, 'backendLoadingCompleted', true, true]) } else setLoadingStatus([true, 'backendError', true, false]) } if (id) getCuratedSet() }, [id]) const filterMeasurements = () => { if (!filter) return measurements.map((m) => t(`measurements:${m}`) + `|${m}`).sort() else return designMeasurements[filter].map((m) => t(`measurements:${m}`) + `|${m}`).sort() } if (!id || !cset) return

nope {id}

//null const updateData = (path, val) => setData(objUpdate({ ...data }, path, val)) const save = async () => { setLoadingStatus([true, 'savingSet']) const changes = { measies: {} } for (const lang of siteConfig.languages) { let k = `name${capitalize(lang)}` if (data[k] !== cset[k]) changes[k] = data[k] k = `notes${capitalize(lang)}` if (data[k] !== cset[k]) changes[k] = data[k] } if (data.height !== cset.height) changes.height = Number(data.height) if (data.img !== cset.img) changes.img = data.img if (data.published !== cset.published) changes.published = data.published for (const m in data.measies) { if (data.measies[m] !== cset.measies[m]) changes.measies[m] = data.measies[m] } const result = await backend.updateCuratedSet(cset.id, changes) if (result.success) { setCset(result.data.curatedSet) setLoadingStatus([true, 'nailedIt', true, true]) } else setLoadingStatus([true, 'backendError', true, false]) } return (
updateData('published', val)} list={[ { val: true, label: (
{t('curate:published')}
), desc: t('curate:publishedDesc'), }, { val: false, label: (
{t('curate:unpublished')}
), desc: t('curate:unpublishedDesc'), }, ]} current={data.published} /> updateData('height', val)} current={Number(data.height)} valid={notEmpty} />

{t('measies')}

{t('noFilter')}} />
{filterMeasurements().map((mplus) => { const [translated, m] = mplus.split('|') return ( updateData(['measies', m], val)} /> ) })}

{t('account:data')}

{t('account:name')}

{/* Name is always shown */} {siteConfig.languages.map((lang) => { const key = `name${capitalize(lang)}` return ( updateData(key, val)} current={data[key]} valid={notEmpty} /> ) })}

{t('account:notes')}

{/* notes: Control level determines whether or not to show this */} {siteConfig.languages.map((lang) => { const key = `notes${capitalize(lang)}` return ( updateData(key, val)} current={data[key]} placeholder={t('mdSupport')} /> ) })} {/* img: Control level determines whether or not to show this */} updateData('img', val)} current={data.img} valid={notEmpty} />
) }