import { kinds, nip19 } from 'nostr-tools'
import { useMemo, useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { A11y, Autoplay, Navigation, Pagination } from 'swiper/modules'
import { Swiper, SwiperSlide } from 'swiper/react'
import { BlogCard } from '../components/BlogCard'
import { GameCard } from '../components/GameCard'
import { ModCard } from '../components/ModCard'
import { LANDING_PAGE_DATA } from '../constants'
import {
useDidMount,
useGames,
useMuteLists,
useNDKContext,
useNSFWList
} from '../hooks'
import { appRoutes, getModPageRoute } from '../routes'
import { BlogCardDetails, ModDetails } from '../types'
import {
extractModData,
handleModImageError,
log,
LogType,
npubToHex
} from '../utils'
import '../styles/cardLists.css'
import '../styles/SimpleSlider.css'
import '../styles/styles.css'
// Import Swiper styles
import { filterForEventsTaggingId, NDKFilter } from '@nostr-dev-kit/ndk'
import 'swiper/css'
import 'swiper/css/navigation'
import 'swiper/css/pagination'
import { extractBlogCardDetails } from 'utils/blog'
export const HomePage = () => {
const navigate = useNavigate()
const games = useGames()
const featuredGames = useMemo(() => {
return games.filter((game) =>
LANDING_PAGE_DATA.featuredGames.includes(game['Game Name'])
)
}, [games])
return (
{LANDING_PAGE_DATA.featuredSlider.map((naddr) => (
))}
Cool Games
{featuredGames.map((game) => (
))}
Awesome Mods
{LANDING_PAGE_DATA.awesomeMods.map((naddr) => (
))}
)
}
type SlideContentProps = {
naddr: string
}
const SlideContent = ({ naddr }: SlideContentProps) => {
const navigate = useNavigate()
const { fetchEvent } = useNDKContext()
const [mod, setMod] = useState()
useDidMount(() => {
const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`)
const { identifier, kind, pubkey } = decoded.data
const ndkFilter: NDKFilter = {
'#a': [identifier],
authors: [pubkey],
kinds: [kind]
}
fetchEvent(ndkFilter)
.then((ndkEvent) => {
if (ndkEvent) {
const extracted = extractModData(ndkEvent)
setMod(extracted)
}
})
.catch((err) => {
log(
true,
LogType.Error,
'An error occurred in fetching mod details from relays',
err
)
})
})
if (!mod) return
return (
<>
>
)
}
type DisplayModProps = {
naddr: string
}
const DisplayMod = ({ naddr }: DisplayModProps) => {
const [mod, setMod] = useState()
const { fetchEvent } = useNDKContext()
useDidMount(() => {
const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`)
const { identifier, kind, pubkey } = decoded.data
const ndkFilter: NDKFilter = {
'#a': [identifier],
authors: [pubkey],
kinds: [kind]
}
fetchEvent(ndkFilter)
.then((ndkEvent) => {
if (ndkEvent) {
const extracted = extractModData(ndkEvent)
setMod(extracted)
}
})
.catch((err) => {
log(
true,
LogType.Error,
'An error occurred in fetching mod details from relays',
err
)
})
})
if (!mod) return
return
}
const DisplayLatestMods = () => {
const navigate = useNavigate()
const { fetchMods } = useNDKContext()
const [isFetchingLatestMods, setIsFetchingLatestMods] = useState(true)
const [latestMods, setLatestMods] = useState([])
const muteLists = useMuteLists()
const nsfwList = useNSFWList()
useDidMount(() => {
fetchMods({ source: window.location.host })
.then((mods) => {
setLatestMods(mods)
})
.finally(() => {
setIsFetchingLatestMods(false)
})
})
const filteredMods = useMemo(() => {
const mutedAuthors = [...muteLists.admin.authors, ...muteLists.user.authors]
const mutedEvents = [
...muteLists.admin.replaceableEvents,
...muteLists.user.replaceableEvents
]
const filtered = latestMods.filter(
(mod) =>
!mutedAuthors.includes(mod.author) &&
!mutedEvents.includes(mod.aTag) &&
!nsfwList.includes(mod.aTag) &&
!mod.nsfw
)
return filtered.slice(0, 4)
}, [muteLists, nsfwList, latestMods])
return (
Latest Mods
{isFetchingLatestMods ? (
) : (
filteredMods.map((mod) => {
return
})
)}
)
}
const Spinner = () => {
return (
)
}
const DisplayLatestBlogs = () => {
const [blogs, setBlogs] = useState[]>()
const { fetchEvents } = useNDKContext()
useDidMount(() => {
const fetchBlogs = async () => {
try {
// Show maximum of 4 blog posts
// 2 should be featured and the most recent 2 from blog npubs
// Populate the filter from known naddr (constants.ts)
const filters: NDKFilter[] = []
for (let i = 0; i < LANDING_PAGE_DATA.featuredBlogPosts.length; i++) {
try {
const naddr = LANDING_PAGE_DATA.featuredBlogPosts[i]
const filterId = filterForEventsTaggingId(naddr)
if (filterId) {
filters.push(filterId)
}
} catch (error) {
// Silently ignore
}
}
// Create a single filter based on multiple #a's
const filter = filters.reduce(
(filter, id) => {
const a = id['#a']
if (a) {
filter['#a']?.push(a[0])
}
return filter
},
{
'#a': []
} as NDKFilter
)
// Fetch featured blogs posts
const featuredBlogPosts = await fetchEvents(filter)
// Fetch latest blog npubs posts
const blogNpubs = import.meta.env.VITE_BLOG_NPUBS.split(',')
const blogHexkeys = blogNpubs
.map(npubToHex)
.filter((hexkey) => hexkey !== null)
// We fetch 4 posts in case of duplicates (from featured)
const latestBlogPosts = await fetchEvents({
authors: blogHexkeys,
kinds: [kinds.LongFormArticle],
limit: 4
})
// Remove duplicates
const unique = Array.from(
[...featuredBlogPosts, ...latestBlogPosts]
.reduce((map, obj) => {
map.set(obj.id, obj)
return map
}, new Map())
.values()
)
const latest = unique.slice(0, 4)
setBlogs(latest.map(extractBlogCardDetails))
} catch (error) {
log(
true,
LogType.Error,
'An error occurred in fetching blog details from relays',
error
)
return null
}
}
fetchBlogs()
})
return (
Blog Posts
{blogs?.map((b) => (
))}
View All
)
}