From a4f4d55514edeafcf712ea0fd5fe3e7644362e29 Mon Sep 17 00:00:00 2001 From: Diner Date: Mon, 2 Sep 2024 15:00:52 +0100 Subject: [PATCH] Make sure tags are fetched properly on public facing pages --- app/[subdomain]/Web.tsx | 4 +- app/transition/Web.tsx | 262 ----------------------------------- hooks/tags/index.ts | 1 + hooks/tags/useTags.tsx | 12 -- hooks/tags/useTagsPublic.tsx | 33 +++++ 5 files changed, 36 insertions(+), 276 deletions(-) delete mode 100644 app/transition/Web.tsx create mode 100644 hooks/tags/useTagsPublic.tsx diff --git a/app/[subdomain]/Web.tsx b/app/[subdomain]/Web.tsx index abeeeebf..b8e2fd51 100644 --- a/app/[subdomain]/Web.tsx +++ b/app/[subdomain]/Web.tsx @@ -12,7 +12,7 @@ import MainList from '@components/main-list' import AlertBanner from '@components/alert-banner' import { removeNonAlphaNumeric, sortStringsFunc } from '@helpers/utils' import useCategoriesPublic from '@hooks/categories/useCategoriesPublic' -import { useTags } from '@hooks/tags' +import { useTagsPublic } from '@hooks/tags' import { Category } from '@prisma/client' const NetworkComponent = dynamic(() => import('@components/network'), { @@ -78,7 +78,7 @@ export default function Web({ const [_network, setNetwork] = useState() const { categories: fetchedCategories } = useCategoriesPublic() - const { tags: fetchedTags } = useTags() + const { tags: fetchedTags } = useTagsPublic() useEffect(() => { if (!fetchedCategories) return diff --git a/app/transition/Web.tsx b/app/transition/Web.tsx deleted file mode 100644 index 9b838e73..00000000 --- a/app/transition/Web.tsx +++ /dev/null @@ -1,262 +0,0 @@ -'use client' -import { useCallback, useEffect, useState, useMemo } from 'react' -import dynamic from 'next/dynamic' -import { Box } from '@chakra-ui/react' -import { useDebounce } from 'use-debounce' -import intersection from 'lodash/intersection' -import useLocalStorage from 'use-local-storage' -import { useQueryParams, ArrayParam, withDefault } from 'use-query-params' -import Header from '@components/header' -import { useIsMobile } from '@hooks/application' -import MainList from '@components/main-list' -import AlertBanner from '@components/alert-banner' -import { removeNonAlphaNumeric, sortStringsFunc } from '@helpers/utils' -import useCategoriesPublic from '@hooks/categories/useCategoriesPublic' -import { useTags } from '@hooks/tags' -import { Category } from '@prisma/client' - -const NetworkComponent = dynamic(() => import('@components/network'), { - ssr: false, -}) -const Drawer = dynamic(() => import('@components/drawer'), { - ssr: false, -}) - -type INetwork = { - selectNodes: (ids: string[]) => void -} - -export const CENTRAL_NODE_ID = 999 - -export default function Web({ data, webName, webDescription, webIsPublished }) { - const isMobile = useIsMobile() - const [isWebMode, setIsWebMode] = useLocalStorage('is-web-mode', undefined) - const [isVolunteer, setIsVolunteer] = useState(false) - - const [query, setQuery] = useQueryParams({ - categories: withDefault(ArrayParam, []), - tags: withDefault(ArrayParam, []), - }) - - const [searchTerm, setSearchTerm] = useState('') - const [searchTermValue] = useDebounce(searchTerm, 500) - const handleSearchTermChange = useCallback( - (event) => setSearchTerm(event.target.value), - [], - ) - const handleClearSearchTermValue = useCallback(() => setSearchTerm(''), []) - - const [categories, setCategories] = useState([]) - const [tags, setTags] = useState([]) - - const selectedCategories = useMemo(() => { - return query.categories.map((categoryLabel) => { - const categoryColor = categories.find( - (c: Category) => c.label === categoryLabel, - )?.color - return { - value: categoryLabel, - label: categoryLabel, - color: categoryColor, - } - }) - }, [categories, query.categories]) - const selectedTags = useMemo(() => { - return query.tags.map((tagLabel) => ({ - value: tagLabel, - label: tagLabel, - })) - }, [query.tags]) - - const [selectedId, setSelectedId] = useState() - const [_network, setNetwork] = useState() - - const { categories: fetchedCategories } = useCategoriesPublic() - const { tags: fetchedTags } = useTags() - - useEffect(() => { - if (!fetchedCategories) return - - setCategories( - fetchedCategories.map((c) => ({ - value: c.label, - label: c.label, - color: `#${c.color}`, - })), - ) - }, [fetchedCategories]) - - useEffect(() => { - if (!fetchedTags) return - - setTags( - fetchedTags.map((c) => ({ - value: c.label, - label: c.label, - })), - ) - }, [fetchedTags]) - - const handleCategorySelection = useCallback( - (value) => { - const categoryLabels = value.map((c) => c.label) - setQuery({ categories: categoryLabels }) - }, - [setQuery], - ) - - const handleTagSelection = useCallback( - (value) => { - const tagsLabels = value.map((t) => t.value) - setQuery({ tags: tagsLabels }) - }, - [setQuery], - ) - - const filteredItems = useMemo(() => { - if (!data) return [] - let results = data?.nodes - .filter((item) => !item.isDescriptive) - .sort(sortStringsFunc) - .sort((item) => { - if (item.featured) { - return -1 - } else { - return 1 - } - }) - - if (isVolunteer) { - results = results.filter((item) => item.seekingVolunteers) - } - - if (query.categories.length > 0) { - results = results.filter((item) => - query.categories.includes(item.category.label), - ) - } - - if (query.tags.length > 0) { - results = results.filter((item) => { - const itemTags = item.tags.map((c) => c.label) - return intersection(query.tags, itemTags).length > 0 - }) - } - - if (searchTermValue) { - results = results.filter((item) => - removeNonAlphaNumeric(item.title) - .toLowerCase() - .includes(searchTermValue.toLowerCase()), - ) - } - - return results - }, [data, isVolunteer, query.categories, query.tags, searchTermValue]) - - const descriptiveNodes = useMemo( - () => - data - ? data.nodes - .filter((item) => item.isDescriptive) - .filter( - (item) => - item.id === CENTRAL_NODE_ID || - query.categories.length === 0 || - query.categories.some((l) => l === item.label), - ) - : [], - [data, query.categories], - ) - - const filteredNetworkData = useMemo( - () => ({ - edges: data?.edges, - nodes: [...filteredItems, ...descriptiveNodes], - }), - [data?.edges, filteredItems, descriptiveNodes], - ) - - const handleSwitchChange = useCallback( - (event) => { - setSelectedId(null) - setIsWebMode(!(event.target.value == 'true')) - }, - [setIsWebMode], - ) - - const handleVolunteerSwitchChange = useCallback( - (event) => { - setSelectedId(null) - setIsVolunteer(event.target.checked) - }, - [setIsVolunteer], - ) - - useEffect(() => { - if (isMobile) { - setIsWebMode(false) - } - }, [isMobile, setIsWebMode]) - - return ( - <> - {!isMobile && ( - - )} - - {webIsPublished === false && ( - - )} -
- {isWebMode && ( - - )} - - {!isWebMode && ( - - )} - - - ) -} diff --git a/hooks/tags/index.ts b/hooks/tags/index.ts index e24c0065..d082b0ea 100644 --- a/hooks/tags/index.ts +++ b/hooks/tags/index.ts @@ -1,4 +1,5 @@ export { default as useTags } from './useTags' +export { default as useTagsPublic } from './useTagsPublic' export { default as useCreateTag } from './useCreateTag' export { default as useUpdateTag } from './useUpdateTag' export { default as useDeleteTag } from './useDeleteTag' diff --git a/hooks/tags/useTags.tsx b/hooks/tags/useTags.tsx index 2934ac3a..734683eb 100644 --- a/hooks/tags/useTags.tsx +++ b/hooks/tags/useTags.tsx @@ -1,20 +1,8 @@ import { useQuery } from '@tanstack/react-query' import { useAppContext } from '@store/hooks' import { Tag } from '@prisma/client' -import { REMOTE_URL } from '@helpers/config' import { useIsAdminMode } from '@hooks/application' -export async function fetchTagsHydrate({ webSlug }) { - const BASE_URL = - process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview' - ? 'https://resilienceweb.org.uk' - : REMOTE_URL - - const response = await fetch(`${BASE_URL}/api/tags?web=${webSlug}`) - const { data: tags } = await response.json() - return tags -} - async function fetchTagsRequest({ queryKey }) { const [_key, { webSlug, all }] = queryKey const response = await fetch(`/api/tags?web=${webSlug}`) diff --git a/hooks/tags/useTagsPublic.tsx b/hooks/tags/useTagsPublic.tsx new file mode 100644 index 00000000..cb35fde4 --- /dev/null +++ b/hooks/tags/useTagsPublic.tsx @@ -0,0 +1,33 @@ +import { useQuery } from '@tanstack/react-query' +import { Tag } from '@prisma/client' +import { useIsAdminMode } from '@hooks/application' +import useSelectedWebSlug from '@hooks/application/useSelectedWebSlug' + +async function fetchTagsRequest({ queryKey }) { + const [_key, { webSlug, all }] = queryKey + const response = await fetch(`/api/tags?web=${webSlug}`) + const { data: tags } = await response.json() + + return all ? tags : tags.filter((tag) => tag.listings.length > 0) +} + +export default function useTags() { + const isAdminMode = useIsAdminMode() + const selectedWebSlug = useSelectedWebSlug() + const { + data: tags, + isPending, + isError, + } = useQuery({ + queryKey: ['tags', { webSlug: selectedWebSlug, all: isAdminMode }], + queryFn: fetchTagsRequest, + refetchOnWindowFocus: false, + enabled: selectedWebSlug !== undefined, + }) + + return { + tags, + isPending, + isError, + } +}