// Dependencies import { measurements as measurementsTranslations } from '@freesewing/i18n' import { requiredMeasurements as designMeasurements } from '@freesewing/collection' import { cloudflareImageUrl, hasRequiredMeasurements } from '@freesewing/utils' // Context import { LoadingStatusContext } from '@freesewing/react/context/LoadingStatus' import { ModalContext } from '@freesewing/react/context/Modal' // Hooks import React, { useState, useEffect, Fragment, useContext } from 'react' import { useAccount } from '@freesewing/react/hooks/useAccount' import { useBackend } from '@freesewing/react/hooks/useBackend' // Components import { Link as WebLink } from '@freesewing/react/components/Link' import { NoIcon, OkIcon, PlusIcon, TrashIcon, UploadIcon } from '@freesewing/react/components/Icon' import { ModalWrapper } from '@freesewing/react/components/Modal' import { NewSet } from './Set.mjs' /** * The component for the measurements sets in the user's account. * * @component * @param {object} props - All component props * @param {React.Component} props.Link - A framework specific Link component for client-side routing * @returns {JSX.Element} */ export const Sets = ({ Link = false }) => { if (!Link) Link = WebLink // Hooks const { control } = useAccount() const backend = useBackend() // State const [sets, setSets] = useState([]) const [selected, setSelected] = useState({}) const [refresh, setRefresh] = useState(0) // Context const { setLoadingStatus, LoadingProgress } = useContext(LoadingStatusContext) const { setModal } = useContext(ModalContext) // Effects useEffect(() => { const getSets = async () => { const [status, body] = await backend.getSets() if (status === 200 && body.result === 'success') setSets(body.sets) } 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 === sets.length) setSelected({}) else { const newSelected = {} for (const set of sets) newSelected[set.id] = 1 setSelected(newSelected) } } // Helper to delete one or more measurements sets const removeSelectedSets = async () => { let i = 0 for (const id in selected) { i++ await backend.removeSet(id) setLoadingStatus([ true, , ]) } setSelected({}) setRefresh(refresh + 1) setLoadingStatus([true, 'Nailed it', true, true]) } return (

Import Measurements Sets

{sets.map((set, i) => (
))}
) } /** * A component to render a card of a single measurements set. * * This is a pure render component, you need to pass in the data. * * @component * @param {object} props - All component props * @param {React.Component} [props.Link = false] - An optional framework-specific Link component * @param {string} [props.design = false] - An optional design name to check for required measurements in this set * @param {string} [props.href = false] - On optional href for the card to link to * @param {function} [props.onClick = false] - On optional onClick handler method * @param {object} props.set - The data of the measurements set * @param {string} [props.size = 'lg'] - Size of the card, one of lg, md, or sm * @param {bool} [props.useA = false] - Whether to use an A tag or a Link component for href * @returns {JSX.Element} */ export const MsetCard = ({ Link = false, design = false, href = false, onClick = false, set, size = 'lg', useA = false, }) => { if (!Link) Link = WebLink const sizes = { lg: 96, md: 48, sm: 36, } const s = sizes[size] const wrapperProps = { className: `tw:bg-base-300 tw:aspect-square tw:h-${s} tw:w-${s} tw:mb-2 tw:grow tw:w-full tw:hover:cursor-pointer tw:border-0 tw:opacity-80 tw:hover:opacity-100 tw:mx-auto tw:flex tw:flex-col tw:items-start tw:text-center tw:justify-between tw:rounded-none tw:md:rounded shadow`, style: { backgroundImage: `url(${cloudflareImageUrl({ type: 'w500', id: set.img })})`, backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: '50%', }, } if (!set.img || set.img === 'default-avatar') wrapperProps.style.backgroundPosition = 'bottom right' let icon = let missingMeasies = '' let linebreak = '' const maxLength = 75 if (design) { const [hasMeasies, missing] = hasRequiredMeasurements( designMeasurements[design], set.measies, true ) const iconClasses = 'tw:w-8 tw:h-8 tw:p-1 tw:rounded-full tw:-mt-2 tw:-ml-2 tw:shadow' icon = hasMeasies ? ( ) : ( ) if (missing.length > 0) { const translated = missing.map((m) => measurementsTranslations[m]) let missingString = 'Missing:' + translated.join(', ') if (missingString.length > maxLength) { const lastSpace = missingString.lastIndexOf(', ', maxLength) missingString = missingString.substring(0, lastSpace) + ', and more...' } const measieClasses = 'tw:font-normal tw:text-xs' missingMeasies = {missingString} linebreak =
} } const inner = ( <> {icon} {set.name} {linebreak} {missingMeasies} ) // Is it a button with an onClick handler? if (onClick) return ( ) // Returns a link to an internal page if (href && !useA) return ( {inner} ) // Returns a link to an external page if (href && useA) return ( {inner} ) // Returns a div return
{inner}
}