()
| 8 | |
| 9 | const PAGE_SIZE = 9 |
| 10 | export const ArticleCards = () => { |
| 11 | const { t } = useTranslation('product_guides') |
| 12 | const guideTypes: Record<string, string> = t('guide_types') |
| 13 | const { allTopics, includeGuides } = useProductGuidesContext() |
| 14 | const [numVisible, setNumVisible] = useState(PAGE_SIZE) |
| 15 | const [typeFilter, setTypeFilter] = useState<ItemInput | undefined>() |
| 16 | const [topicFilter, setTopicFilter] = useState<ItemInput | undefined>() |
| 17 | const [filteredResults, setFilteredResults] = useState<Array<ArticleGuide>>([]) |
| 18 | const typesRef = useRef<HTMLDivElement>(null) |
| 19 | const topicsRef = useRef<HTMLDivElement>(null) |
| 20 | const articleCardRef = useRef<HTMLUListElement>(null) |
| 21 | |
| 22 | useEffect(() => { |
| 23 | setNumVisible(PAGE_SIZE) |
| 24 | setFilteredResults( |
| 25 | (includeGuides || []).filter((card) => { |
| 26 | const matchesType = card.type === typeFilter?.key |
| 27 | const matchesTopic = card.topics.some((key) => key === topicFilter?.key) |
| 28 | return (typeFilter?.key ? matchesType : true) && (topicFilter?.key ? matchesTopic : true) |
| 29 | }) |
| 30 | ) |
| 31 | }, [typeFilter, topicFilter]) |
| 32 | |
| 33 | const clickDropdown = (e: React.RefObject<HTMLDivElement>) => { |
| 34 | if (e === typesRef && typesRef.current) typesRef.current.focus() |
| 35 | if (e === topicsRef && topicsRef.current) topicsRef.current.focus() |
| 36 | } |
| 37 | |
| 38 | const loadMore = () => { |
| 39 | if (articleCardRef.current) { |
| 40 | const childListLength = articleCardRef.current.childElementCount |
| 41 | // Leading semi-colon due to prettier to prevent possible ASI failures |
| 42 | // Need to explicitly type assert as HTMLDivElement as focus property missing from dom type definitions for Element. |
| 43 | ;(articleCardRef.current.childNodes.item(childListLength - 1) as HTMLDivElement).focus() |
| 44 | } |
| 45 | setNumVisible(numVisible + PAGE_SIZE) |
| 46 | } |
| 47 | |
| 48 | const isUserFiltering = typeFilter !== undefined || topicFilter !== undefined |
| 49 | |
| 50 | const guides = isUserFiltering ? filteredResults : includeGuides || [] |
| 51 | |
| 52 | const types = Object.entries(guideTypes).map(([key, val]) => { |
| 53 | return { text: val, key } |
| 54 | }) as ItemInput[] |
| 55 | |
| 56 | types.unshift({ text: t('filters.all'), key: undefined }) |
| 57 | |
| 58 | const topics = allTopics?.map((topic) => { |
| 59 | return { text: topic, key: topic } |
| 60 | }) as ItemInput[] |
| 61 | |
| 62 | topics.unshift({ text: t('filters.all'), key: undefined }) |
| 63 | |
| 64 | return ( |
| 65 | <div> |
| 66 | <div data-search="hide"> |
| 67 | <label htmlFor="guide-filter-form">{t('filter_instructions')}</label> |
nothing calls this directly
no test coverage detected