2023-05-05 19:56:51 +02:00
|
|
|
// Dependencies
|
|
|
|
import orderBy from 'lodash.orderby'
|
|
|
|
import { measurements } from 'site/prebuild/design-measurements.mjs'
|
2023-05-08 19:28:03 +02:00
|
|
|
import { siteConfig } from 'site/site.config.mjs'
|
|
|
|
import { capitalize } from 'shared/utils.mjs'
|
2023-05-05 19:56:51 +02:00
|
|
|
// Hooks
|
|
|
|
import { useState, useEffect } from 'react'
|
|
|
|
import { useTranslation } from 'next-i18next'
|
|
|
|
import { useAccount } from 'shared/hooks/use-account.mjs'
|
|
|
|
import { useBackend } from 'shared/hooks/use-backend.mjs'
|
|
|
|
// Components
|
|
|
|
import { SetCandidate, ns as setNs } from 'shared/components/sets/set-candidate.mjs'
|
2023-05-08 09:31:37 +02:00
|
|
|
import { CuratedSetCandidate } from 'shared/components/sets/curated-set-candidate.mjs'
|
|
|
|
import { PopoutWrapper } from 'shared/components/wrappers/popout.mjs'
|
2023-05-08 19:28:03 +02:00
|
|
|
import { Tag } from 'shared/components/tag.mjs'
|
|
|
|
import { FilterIcon } from 'shared/components/icons.mjs'
|
2023-05-05 19:56:51 +02:00
|
|
|
|
|
|
|
export const ns = setNs
|
|
|
|
|
2023-05-08 19:28:03 +02:00
|
|
|
export const CuratedSetPicker = ({ design, language }) => {
|
2023-05-08 09:31:37 +02:00
|
|
|
// Hooks
|
|
|
|
const { account, token } = useAccount()
|
|
|
|
const backend = useBackend(token)
|
|
|
|
const { t } = useTranslation('sets')
|
|
|
|
|
|
|
|
// State
|
2023-05-08 19:28:03 +02:00
|
|
|
const [curatedSets, setCuratedSets] = useState([])
|
|
|
|
const [filter, setFilter] = useState([])
|
|
|
|
const [tags, setTags] = useState([])
|
|
|
|
const [reload, setReload] = useState(0)
|
|
|
|
|
|
|
|
// Force a refresh
|
|
|
|
const refresh = () => setReload(reload + 1)
|
2023-05-08 09:31:37 +02:00
|
|
|
|
|
|
|
// Effects
|
|
|
|
useEffect(() => {
|
|
|
|
const getCuratedSets = async () => {
|
|
|
|
const result = await backend.getCuratedSets()
|
|
|
|
if (result.success) {
|
2023-05-08 19:28:03 +02:00
|
|
|
const all = []
|
|
|
|
const allTags = new Set()
|
|
|
|
for (const set of result.data.curatedSets) {
|
|
|
|
all.push(set)
|
|
|
|
for (const tag of set[`tags${capitalize(language)}`]) allTags.add(tag)
|
|
|
|
}
|
2023-05-08 09:31:37 +02:00
|
|
|
setCuratedSets(all)
|
2023-05-08 19:28:03 +02:00
|
|
|
setTags([...allTags])
|
2023-05-08 09:31:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
getCuratedSets()
|
2023-05-08 19:28:03 +02:00
|
|
|
}, [reload])
|
|
|
|
|
|
|
|
const addFilter = (tag) => {
|
|
|
|
const newFilter = [...filter, tag]
|
|
|
|
setFilter(newFilter)
|
|
|
|
}
|
|
|
|
|
|
|
|
const removeFilter = (tag) => {
|
|
|
|
const newFilter = filter.filter((t) => t !== tag)
|
|
|
|
setFilter(newFilter)
|
|
|
|
}
|
|
|
|
|
|
|
|
const applyFilter = () => {
|
|
|
|
const newList = new Set()
|
|
|
|
for (const set of curatedSets) {
|
|
|
|
const setTags = []
|
|
|
|
for (const lang of siteConfig.languages) {
|
|
|
|
const key = `tags${capitalize(lang)}`
|
|
|
|
setTags.push(...set[key])
|
|
|
|
}
|
|
|
|
let match = 0
|
|
|
|
for (const tag of filter) {
|
|
|
|
if (setTags.includes(tag)) match++
|
|
|
|
}
|
|
|
|
if (match === filter.length) newList.add(set)
|
|
|
|
}
|
|
|
|
|
|
|
|
return [...newList]
|
|
|
|
}
|
|
|
|
|
|
|
|
const list = applyFilter()
|
2023-05-08 09:31:37 +02:00
|
|
|
|
|
|
|
// Need to sort designs by their translated title
|
|
|
|
const translated = {}
|
|
|
|
for (const d of list) translated[t(`${d}.t`)] = d
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
2023-05-08 19:28:03 +02:00
|
|
|
<h3>{t('curatedSets')}</h3>
|
|
|
|
{tags.map((tag) => (
|
|
|
|
<Tag onClick={() => addFilter(tag)}>{tag}</Tag>
|
|
|
|
))}
|
|
|
|
<div className="my-2 p-2 px-4 border rounded-lg bg-secondary bg-opacity-10 max-w-xl">
|
|
|
|
<div className="flex flex-row items-center justify-between gap-2">
|
|
|
|
<FilterIcon className="w-6 h-6 text-secondary" />
|
|
|
|
<span>
|
|
|
|
{list.length} / {curatedSets.length}
|
|
|
|
</span>
|
|
|
|
<button onClick={() => setFilter([])} className="btn btn-secondary btn-sm">
|
|
|
|
clear
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
{filter.map((tag) => (
|
|
|
|
<Tag onClick={() => removeFilter(tag)} color="success" hoverColor="error">
|
|
|
|
{tag}
|
|
|
|
</Tag>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
<div className="flex flex-row flex-wrap gap-2">
|
|
|
|
{orderBy(list, ['name'], ['asc']).map((set) => (
|
|
|
|
<div className="w-full lg:w-96">
|
|
|
|
<CuratedSetCandidate
|
|
|
|
href={`/new/pattern/${design}/cset/${set.id}`}
|
|
|
|
set={set}
|
|
|
|
requiredMeasies={measurements[design]}
|
|
|
|
design={design}
|
|
|
|
/>
|
2023-05-08 09:31:37 +02:00
|
|
|
</div>
|
2023-05-08 19:28:03 +02:00
|
|
|
))}
|
|
|
|
</div>
|
2023-05-08 09:31:37 +02:00
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-05-08 19:28:03 +02:00
|
|
|
export const UserSetPicker = ({ design, t, language }) => {
|
2023-05-05 19:56:51 +02:00
|
|
|
// Hooks
|
|
|
|
const { account, token } = useAccount()
|
|
|
|
const backend = useBackend(token)
|
|
|
|
|
|
|
|
// State
|
|
|
|
const [sets, setSets] = useState({})
|
|
|
|
const [list, setList] = useState([])
|
|
|
|
|
|
|
|
// Effects
|
|
|
|
useEffect(() => {
|
|
|
|
const getSets = async () => {
|
|
|
|
const result = await backend.getSets()
|
|
|
|
if (result.success) {
|
|
|
|
const all = {}
|
|
|
|
for (const set of result.data.sets) all[set.id] = set
|
|
|
|
setSets(all)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getSets()
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
// Need to sort designs by their translated title
|
|
|
|
const translated = {}
|
|
|
|
for (const d of list) translated[t(`${d}.t`)] = d
|
|
|
|
|
2023-05-08 19:28:03 +02:00
|
|
|
return Object.keys(sets).length < 1 ? (
|
|
|
|
<PopoutWrapper tip>
|
|
|
|
<h5>{t('patternForWhichSet')}</h5>
|
|
|
|
<p>{t('fsmtm')}</p>
|
|
|
|
</PopoutWrapper>
|
|
|
|
) : (
|
2023-05-05 19:56:51 +02:00
|
|
|
<>
|
2023-05-08 19:28:03 +02:00
|
|
|
<h3>{t('yourSets')}</h3>
|
2023-05-05 19:56:51 +02:00
|
|
|
{Object.keys(sets).length > 0 ? (
|
2023-05-08 09:31:37 +02:00
|
|
|
<>
|
|
|
|
<div className="flex flex-row flex-wrap gap-2">
|
|
|
|
{orderBy(sets, ['name'], ['asc']).map((set) => (
|
|
|
|
<div className="w-full lg:w-96">
|
|
|
|
<SetCandidate set={set} requiredMeasies={measurements[design]} design={design} />
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
</>
|
2023-05-05 19:56:51 +02:00
|
|
|
) : (
|
2023-05-08 09:31:37 +02:00
|
|
|
<PopoutWrapper fixme compact>
|
|
|
|
Implement UI for when there are no sets
|
|
|
|
</PopoutWrapper>
|
2023-05-05 19:56:51 +02:00
|
|
|
)}
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
2023-05-08 09:31:37 +02:00
|
|
|
|
2023-05-08 19:28:03 +02:00
|
|
|
export const BookmarkedSetPicker = ({ design, t }) => (
|
2023-05-08 09:31:37 +02:00
|
|
|
<>
|
2023-05-08 19:28:03 +02:00
|
|
|
<h3>{t('bookmarkedSets')}</h3>
|
|
|
|
<PopoutWrapper fixme>Implement bookmarked set picker (also implement bookmarks)</PopoutWrapper>
|
2023-05-08 09:31:37 +02:00
|
|
|
</>
|
|
|
|
)
|
2023-05-08 19:28:03 +02:00
|
|
|
|
|
|
|
export const SetPicker = ({ design }) => {
|
|
|
|
const { t, i18n } = useTranslation('sets')
|
|
|
|
const { language } = i18n
|
|
|
|
|
|
|
|
const pickerProps = { design, t, language }
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<h2>{t('chooseSet')}</h2>
|
|
|
|
<UserSetPicker {...pickerProps} />
|
|
|
|
<BookmarkedSetPicker {...pickerProps} />
|
|
|
|
<CuratedSetPicker {...pickerProps} />
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|