Multi-file games lists, clicking a game leads to mod search for that game, search redirects, pagination optimizations #38
37
src/hooks/useMuteLists.ts
Normal file
37
src/hooks/useMuteLists.ts
Normal 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
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user