Multi-file games lists, clicking a game leads to mod search for that game, search redirects, pagination optimizations #38

Merged
freakoverse merged 11 commits from staging into master 2024-09-18 19:30:26 +00:00
3 changed files with 52 additions and 104 deletions
Showing only changes of commit c62c1a29b9 - Show all commits

37
src/hooks/useMuteLists.ts Normal file
View File

@ -0,0 +1,37 @@
import { useEffect, useState } from 'react'
import { MuteLists } from 'types'
import { useAppSelector } from './redux'
import { MetadataController } from 'controllers'
export const useMuteLists = () => {
const [muteLists, setMuteLists] = useState<{
admin: MuteLists
user: MuteLists
}>({
admin: {
authors: [],
replaceableEvents: []
},
user: {
authors: [],
replaceableEvents: []
}
})
const userState = useAppSelector((state) => state.user)
useEffect(() => {
const getMuteLists = async () => {
const pubkey = userState.user?.pubkey as string | undefined
const metadataController = await MetadataController.getInstance()
metadataController.getMuteLists(pubkey).then((lists) => {
setMuteLists(lists)
})
}
getMuteLists()
}, [userState])
return muteLists
}

View File

@ -1,3 +1,4 @@
import { Pagination } from 'components/Pagination'
import { kinds, nip19 } from 'nostr-tools' import { kinds, nip19 } from 'nostr-tools'
import React, { import React, {
Dispatch, Dispatch,
@ -9,17 +10,16 @@ import React, {
} from 'react' } from 'react'
import { LoadingSpinner } from '../components/LoadingSpinner' import { LoadingSpinner } from '../components/LoadingSpinner'
import { ModCard } from '../components/ModCard' import { ModCard } from '../components/ModCard'
import { MOD_FILTER_LIMIT } from '../constants'
import { MetadataController } from '../controllers' import { MetadataController } from '../controllers'
import { useAppSelector, useDidMount } from '../hooks' import { useAppSelector, useDidMount, useMuteLists } from '../hooks'
import { getModPageRoute } from '../routes' import { getModPageRoute } from '../routes'
import '../styles/filters.css' import '../styles/filters.css'
import '../styles/pagination.css' import '../styles/pagination.css'
import '../styles/search.css' import '../styles/search.css'
import '../styles/styles.css' import '../styles/styles.css'
import { ModDetails, MuteLists } from '../types' import { ModDetails } from '../types'
import { fetchMods } from '../utils' import { fetchMods } from '../utils'
import { MOD_FILTER_LIMIT } from '../constants'
import { Pagination } from 'components/Pagination'
enum SortBy { enum SortBy {
Latest = 'Latest', Latest = 'Latest',
@ -56,19 +56,8 @@ export const ModsPage = () => {
source: window.location.host, source: window.location.host,
moderated: ModeratedFilter.Moderated moderated: ModeratedFilter.Moderated
}) })
const [muteLists, setMuteLists] = useState<{ const muteLists = useMuteLists()
admin: MuteLists
user: MuteLists
}>({
admin: {
authors: [],
replaceableEvents: []
},
user: {
authors: [],
replaceableEvents: []
}
})
const [nsfwList, setNSFWList] = useState<string[]>([]) const [nsfwList, setNSFWList] = useState<string[]>([])
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
@ -76,12 +65,7 @@ export const ModsPage = () => {
const userState = useAppSelector((state) => state.user) const userState = useAppSelector((state) => state.user)
useDidMount(async () => { useDidMount(async () => {
const pubkey = userState.user?.pubkey as string | undefined
const metadataController = await MetadataController.getInstance() const metadataController = await MetadataController.getInstance()
metadataController.getMuteLists(pubkey).then((lists) => {
setMuteLists(lists)
})
metadataController.getNSFWList().then((list) => { metadataController.getNSFWList().then((list) => {
setNSFWList(list) setNSFWList(list)

View File

@ -5,12 +5,15 @@ import { LoadingSpinner } from 'components/LoadingSpinner'
import { ModCard } from 'components/ModCard' import { ModCard } from 'components/ModCard'
import { Pagination } from 'components/Pagination' import { Pagination } from 'components/Pagination'
import { Profile } from 'components/ProfileSection' import { Profile } from 'components/ProfileSection'
import { T_TAG_VALUE } from 'constants.ts' import {
import { MetadataController, RelayController } from 'controllers' MAX_GAMES_PER_PAGE,
import { useAppSelector, useDidMount } from 'hooks' MAX_MODS_PER_PAGE,
T_TAG_VALUE
} from 'constants.ts'
import { RelayController } from 'controllers'
import { useAppSelector, useGames, useMuteLists } from 'hooks'
import { Filter, kinds, nip19 } from 'nostr-tools' import { Filter, kinds, nip19 } from 'nostr-tools'
import { Subscription } from 'nostr-tools/abstract-relay' import { Subscription } from 'nostr-tools/abstract-relay'
import Papa from 'papaparse'
import React, { import React, {
Dispatch, Dispatch,
SetStateAction, SetStateAction,
@ -50,6 +53,7 @@ interface FilterOptions {
} }
export const SearchPage = () => { export const SearchPage = () => {
const muteLists = useMuteLists()
const searchTermRef = useRef<HTMLInputElement>(null) const searchTermRef = useRef<HTMLInputElement>(null)
const [filterOptions, setFilterOptions] = useState<FilterOptions>({ const [filterOptions, setFilterOptions] = useState<FilterOptions>({
sort: SortByEnum.Latest, sort: SortByEnum.Latest,
@ -57,30 +61,6 @@ export const SearchPage = () => {
searching: SearchingFilterEnum.Mods searching: SearchingFilterEnum.Mods
}) })
const [searchTerm, setSearchTerm] = useState('') const [searchTerm, setSearchTerm] = useState('')
const [muteLists, setMuteLists] = useState<{
admin: MuteLists
user: MuteLists
}>({
admin: {
authors: [],
replaceableEvents: []
},
user: {
authors: [],
replaceableEvents: []
}
})
const userState = useAppSelector((state) => state.user)
useDidMount(async () => {
const pubkey = userState.user?.pubkey as string | undefined
const metadataController = await MetadataController.getInstance()
metadataController.getMuteLists(pubkey).then((lists) => {
setMuteLists(lists)
})
})
const handleSearch = () => { const handleSearch = () => {
const value = searchTermRef.current?.value || '' // Access the input value from the ref const value = searchTermRef.current?.value || '' // Access the input value from the ref
@ -278,8 +258,6 @@ const Filters = React.memo(
} }
) )
const MAX_MODS_PER_PAGE = 10
type ModsResultProps = { type ModsResultProps = {
filterOptions: FilterOptions filterOptions: FilterOptions
searchTerm: string searchTerm: string
@ -544,64 +522,14 @@ const UsersResult = ({
) )
} }
type Game = {
'Game Name': string
'16 by 9 image': string
'Boxart image': string
}
const MAX_GAMES_PER_PAGE = 10
type GamesResultProps = { type GamesResultProps = {
searchTerm: string searchTerm: string
} }
const GamesResult = ({ searchTerm }: GamesResultProps) => { const GamesResult = ({ searchTerm }: GamesResultProps) => {
const hasProcessedCSV = useRef(false) const games = useGames()
const [isProcessingCSVFile, setIsProcessingCSVFile] = useState(false)
const [games, setGames] = useState<Game[]>([])
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
useEffect(() => {
if (hasProcessedCSV.current) return
hasProcessedCSV.current = true
setIsProcessingCSVFile(true)
// Fetch the CSV file from the public folder
fetch('/assets/games.csv')
.then((response) => response.text())
.then((csvText) => {
// Parse the CSV text using PapaParse
Papa.parse<Game>(csvText, {
worker: true,
header: true,
complete: (results) => {
const uniqueGames: Game[] = []
const gameNames = new Set<string>()
// Remove duplicate games based on 'Game Name'
results.data.forEach((game) => {
if (!gameNames.has(game['Game Name'])) {
gameNames.add(game['Game Name'])
uniqueGames.push(game)
}
})
// Set the unique games list
setGames(uniqueGames)
}
})
})
.catch((err) => {
log(true, LogType.Error, 'Error occurred in processing csv file', err)
toast.error(err.message || err)
})
.finally(() => {
setIsProcessingCSVFile(false)
})
}, [])
// Reset the page to 1 whenever searchTerm changes // Reset the page to 1 whenever searchTerm changes
useEffect(() => { useEffect(() => {
setPage(1) setPage(1)
@ -627,7 +555,6 @@ const GamesResult = ({ searchTerm }: GamesResultProps) => {
return ( return (
<> <>
{isProcessingCSVFile && <LoadingSpinner desc='Processing games file' />}
<div className='IBMSecMain IBMSMListWrapper'> <div className='IBMSecMain IBMSMListWrapper'>
<div className='IBMSMList IBMSMListFeaturedAlt'> <div className='IBMSMList IBMSMListFeaturedAlt'>
{filteredGames {filteredGames