import { LoadingSpinner } from 'components/LoadingSpinner' import { ModCard } from 'components/ModCard' import { PaginationWithPageNumbers } from 'components/Pagination' import { MAX_MODS_PER_PAGE, T_TAG_VALUE } from 'constants.ts' import { RelayController } from 'controllers' import { useAppSelector, useMuteLists } from 'hooks' import { Filter, kinds } from 'nostr-tools' import { Subscription } from 'nostr-tools/abstract-relay' import React, { Dispatch, SetStateAction, useEffect, useMemo, useRef, useState } from 'react' import { useParams } from 'react-router-dom' import { toast } from 'react-toastify' import { ModDetails } from 'types' import { extractModData, isModDataComplete, log, LogType } from 'utils' enum SortByEnum { Latest = 'Latest', Oldest = 'Oldest', Best_Rated = 'Best Rated', Worst_Rated = 'Worst Rated' } enum ModeratedFilterEnum { Moderated = 'Moderated', Unmoderated = 'Unmoderated', Unmoderated_Fully = 'Unmoderated Fully' } interface FilterOptions { sort: SortByEnum moderated: ModeratedFilterEnum } export const GamePage = () => { const params = useParams() const { name: gameName } = params const muteLists = useMuteLists() const [filterOptions, setFilterOptions] = useState({ sort: SortByEnum.Latest, moderated: ModeratedFilterEnum.Moderated }) const [mods, setMods] = useState([]) const hasEffectRun = useRef(false) const [isSubscribing, setIsSubscribing] = useState(false) const [currentPage, setCurrentPage] = useState(1) const userState = useAppSelector((state) => state.user) const filteredMods = useMemo(() => { let filtered: ModDetails[] = [...mods] const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB const isUnmoderatedFully = filterOptions.moderated === ModeratedFilterEnum.Unmoderated_Fully // Only apply filtering if the user is not an admin or the admin has not selected "Unmoderated Fully" if (!(isAdmin && isUnmoderatedFully)) { filtered = filtered.filter( (mod) => !muteLists.admin.authors.includes(mod.author) && !muteLists.admin.replaceableEvents.includes(mod.aTag) ) } if (filterOptions.moderated === ModeratedFilterEnum.Moderated) { filtered = filtered.filter( (mod) => !muteLists.user.authors.includes(mod.author) && !muteLists.user.replaceableEvents.includes(mod.aTag) ) } if (filterOptions.sort === SortByEnum.Latest) { filtered.sort((a, b) => b.published_at - a.published_at) } else if (filterOptions.sort === SortByEnum.Oldest) { filtered.sort((a, b) => a.published_at - b.published_at) } return filtered }, [ mods, userState.user?.npub, filterOptions.sort, filterOptions.moderated, muteLists ]) // Pagination logic const totalGames = filteredMods.length const totalPages = Math.ceil(totalGames / MAX_MODS_PER_PAGE) const startIndex = (currentPage - 1) * MAX_MODS_PER_PAGE const endIndex = startIndex + MAX_MODS_PER_PAGE const currentMods = filteredMods.slice(startIndex, endIndex) const handlePageChange = (page: number) => { if (page >= 1 && page <= totalPages) { setCurrentPage(page) } } useEffect(() => { if (hasEffectRun.current) { return } hasEffectRun.current = true // Set it so the effect doesn't run again const filter: Filter = { kinds: [kinds.ClassifiedListing], '#t': [T_TAG_VALUE] } setIsSubscribing(true) let subscriptions: Subscription[] = [] RelayController.getInstance() .subscribeForEvents(filter, [], (event) => { if (isModDataComplete(event)) { const mod = extractModData(event) if (mod.game === gameName) setMods((prev) => [...prev, mod]) } }) .then((subs) => { subscriptions = subs }) .catch((err) => { log( true, LogType.Error, 'An error occurred in subscribing to relays.', err ) toast.error(err.message || err) }) .finally(() => { setIsSubscribing(false) }) // Cleanup function to stop all subscriptions return () => { subscriptions.forEach((sub) => sub.close()) // close each subscription } }, [gameName]) if (!gameName) return null return ( <> {isSubscribing && ( )}

Game:  {gameName}

{currentMods.map((mod) => ( ))}
) } type FiltersProps = { filterOptions: FilterOptions setFilterOptions: Dispatch> } const Filters = React.memo( ({ filterOptions, setFilterOptions }: FiltersProps) => { const userState = useAppSelector((state) => state.user) return (
{Object.values(SortByEnum).map((item, index) => (
setFilterOptions((prev) => ({ ...prev, sort: item })) } > {item}
))}
{Object.values(ModeratedFilterEnum).map((item, index) => { if (item === ModeratedFilterEnum.Unmoderated_Fully) { const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB if (!isAdmin) return null } return (
setFilterOptions((prev) => ({ ...prev, moderated: item })) } > {item}
) })}
) } )