import { kinds, nip19 } from 'nostr-tools' import React, { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react' import { useNavigate } from 'react-router-dom' import { LoadingSpinner } from '../components/LoadingSpinner' import { ModCard } from '../components/ModCard' import { MetadataController } from '../controllers' import { useDidMount } from '../hooks' import { getModsInnerPageRoute } from '../routes' import '../styles/filters.css' import '../styles/pagination.css' import '../styles/search.css' import '../styles/styles.css' import { ModDetails, MuteLists } from '../types' import { fetchMods } from '../utils' import { MOD_FILTER_LIMIT } from '../constants' enum SortBy { Latest = 'Latest', Oldest = 'Oldest', Best_Rated = 'Best Rated', Worst_Rated = 'Worst Rated' } enum NSFWFilter { Hide_NSFW = 'Hide NSFW', Show_NSFW = 'Show NSFW', Only_NSFW = 'Only NSFW' } enum ModeratedFilter { Moderated = 'Moderated', Unmoderated = 'Unmoderated' } interface FilterOptions { sort: SortBy nsfw: NSFWFilter source: string moderated: ModeratedFilter } export const ModsPage = () => { const navigate = useNavigate() const [isFetching, setIsFetching] = useState(false) const [mods, setMods] = useState([]) const [filterOptions, setFilterOptions] = useState({ sort: SortBy.Latest, nsfw: NSFWFilter.Hide_NSFW, source: window.location.host, moderated: ModeratedFilter.Moderated }) const [muteLists, setMuteLists] = useState({ authors: [], eventIds: [] }) const [page, setPage] = useState(1) useDidMount(async () => { const metadataController = await MetadataController.getInstance() metadataController.getAdminsMuteLists().then((lists) => { setMuteLists(lists) }) }) useEffect(() => { setIsFetching(true) fetchMods(filterOptions.source) .then((res) => { setMods(res) }) .finally(() => { setIsFetching(false) }) }, [filterOptions.source]) const handleNext = useCallback(() => { setIsFetching(true) const until = mods.length > 0 ? mods[mods.length - 1].edited_at - 1 : undefined fetchMods(filterOptions.source, until) .then((res) => { setMods(res) setPage((prev) => prev + 1) }) .finally(() => { setIsFetching(false) }) }, [filterOptions.source, mods]) const handlePrev = useCallback(() => { setIsFetching(true) const since = mods.length > 0 ? mods[0].edited_at + 1 : undefined fetchMods(filterOptions.source, undefined, since) .then((res) => { setMods(res) setPage((prev) => prev - 1) }) .finally(() => { setIsFetching(false) }) }, [filterOptions.source, mods]) const filteredModList = useMemo(() => { const nsfwFilter = (mods: ModDetails[]) => { // Determine the filtering logic based on the NSFW filter option switch (filterOptions.nsfw) { case NSFWFilter.Hide_NSFW: // If 'Hide_NSFW' is selected, filter out NSFW mods return mods.filter((mod) => !mod.nsfw) case NSFWFilter.Show_NSFW: // If 'Show_NSFW' is selected, return all mods (no filtering) return mods case NSFWFilter.Only_NSFW: // If 'Only_NSFW' is selected, filter to show only NSFW mods return mods.filter((mod) => mod.nsfw) } } let filtered = nsfwFilter(mods) if (filterOptions.moderated === ModeratedFilter.Moderated) { filtered = filtered.filter( (mod) => !muteLists.authors.includes(mod.author) && !muteLists.eventIds.includes(mod.id) ) } if (filterOptions.sort === SortBy.Latest) { filtered.sort((a, b) => b.edited_at - a.edited_at) } else if (filterOptions.sort === SortBy.Oldest) { filtered.sort((a, b) => a.edited_at - b.edited_at) } return filtered }, [ filterOptions.sort, filterOptions.moderated, filterOptions.nsfw, mods, muteLists ]) return ( <> {isFetching && }
{filteredModList.map((mod) => ( navigate( getModsInnerPageRoute( nip19.neventEncode({ id: mod.id, author: mod.author, kind: kinds.ClassifiedListing }) ) ) } /> ))}
) } const PageTitleRow = React.memo(() => { return (

Mods

) }) type FiltersProps = { filterOptions: FilterOptions setFilterOptions: Dispatch> } const Filters = React.memo( ({ filterOptions, setFilterOptions }: FiltersProps) => { return (
{Object.values(SortBy).map((item, index) => (
setFilterOptions((prev) => ({ ...prev, sort: item })) } > {item}
))}
{Object.values(ModeratedFilter).map((item, index) => (
setFilterOptions((prev) => ({ ...prev, moderated: item })) } > {item}
))}
{Object.values(NSFWFilter).map((item, index) => (
setFilterOptions((prev) => ({ ...prev, nsfw: item })) } > {item}
))}
setFilterOptions((prev) => ({ ...prev, source: window.location.host })) } > Show From: {window.location.host}
setFilterOptions((prev) => ({ ...prev, source: 'Show All' })) } > Show All
) } ) type PaginationProps = { page: number disabledNext: boolean handlePrev: () => void handleNext: () => void } const Pagination = React.memo( ({ page, disabledNext, handlePrev, handleNext }: PaginationProps) => { return (
) } )