Improvements & add leaderboards
This commit is contained in:
@@ -2,13 +2,29 @@ import { faArrowLeft } from '@fortawesome/free-solid-svg-icons'
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
export function BackButton ({ href }: { href: string }) {
|
export function BackButton ({
|
||||||
|
href,
|
||||||
|
onClick
|
||||||
|
}: {
|
||||||
|
href?: string
|
||||||
|
onClick?: () => void
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<Link href={href} className='top-button absolute -top-4 -left-4'>
|
{href && (
|
||||||
<FontAwesomeIcon icon={faArrowLeft} />
|
<Link href={href} className='top-button absolute -top-4 -left-4'>
|
||||||
</Link>
|
<FontAwesomeIcon icon={faArrowLeft} />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
{onClick && (
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
className='top-button absolute -top-4 -left-4'
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faArrowLeft} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ interface WSMessage {
|
|||||||
data: any
|
data: any
|
||||||
}
|
}
|
||||||
|
|
||||||
type BirdColor = [number, number, number]
|
export type BirdColor = [number, number, number]
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
username: string
|
username: string
|
||||||
@@ -35,7 +35,7 @@ interface Message {
|
|||||||
editing: boolean
|
editing: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CustomIconEntry {
|
export interface CustomIconEntry {
|
||||||
data: string
|
data: string
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export default function BerryDashIconMarketplace () {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p>Bird Name: {icon.name}</p>
|
<p>Bird Name: {icon.name}</p>
|
||||||
<p>Price: {icon.price}</p>
|
<p>Price: {icon.price.toLocaleString('en-US')}</p>
|
||||||
<p>Designer Name: {icon.username}</p>
|
<p>Designer Name: {icon.username}</p>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ export default function BerryDashSubmitIcon () {
|
|||||||
? 'N/A'
|
? 'N/A'
|
||||||
: name}
|
: name}
|
||||||
</p>
|
</p>
|
||||||
<p>Price: {price}</p>
|
<p>Price: {price.toLocaleString('en-US')}</p>
|
||||||
<p>Designer Name: {getCookie('accountUsername', '-1')}</p>
|
<p>Designer Name: {getCookie('accountUsername', '-1')}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
173
src/app/game/berry-dash/leaderboards/page.tsx
Normal file
173
src/app/game/berry-dash/leaderboards/page.tsx
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { BackButton } from '@/app/components/BackButton'
|
||||||
|
import { DiscordButton } from '@/app/components/DiscordButton'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { BirdColor, CustomIconEntry } from '../chatroom/page'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { GetIconForUser } from '@/util/bd'
|
||||||
|
|
||||||
|
interface LeaderboardEntry {
|
||||||
|
id: number
|
||||||
|
username: string
|
||||||
|
value: number
|
||||||
|
icon: number
|
||||||
|
overlay: number
|
||||||
|
birdColor: BirdColor
|
||||||
|
overlayColor: BirdColor
|
||||||
|
customIcon: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BerryDashLeaderboards () {
|
||||||
|
const [selected, setSelected] = useState<number>(-1)
|
||||||
|
const [selectedBerryOption, setSelectedBerryOption] = useState<number>(0)
|
||||||
|
const [gettingEntries, setGettingEntries] = useState<boolean>(false)
|
||||||
|
const [entries, setEntries] = useState<LeaderboardEntry[]>([])
|
||||||
|
const [customIconCache, setCustomIconCache] = useState<CustomIconEntry[]>([])
|
||||||
|
|
||||||
|
const Refresh = async () => {
|
||||||
|
setGettingEntries(true)
|
||||||
|
try {
|
||||||
|
const result = await axios.get(
|
||||||
|
'/api/berrydash/leaderboard/' +
|
||||||
|
(selected == 0
|
||||||
|
? 'score'
|
||||||
|
: selected == 1
|
||||||
|
? 'berry?berry=' + selectedBerryOption
|
||||||
|
: selected == 2
|
||||||
|
? 'coin'
|
||||||
|
: selected == 3
|
||||||
|
? 'legacy'
|
||||||
|
: 'total')
|
||||||
|
)
|
||||||
|
if (result.data.success) {
|
||||||
|
setEntries(result.data.data)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setEntries([])
|
||||||
|
}
|
||||||
|
setGettingEntries(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = 'Lncvrt Games - Berry Dash Leaderboards'
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selected != -1) Refresh()
|
||||||
|
}, [selected])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const all = customIconCache.map(icon => icon.id)
|
||||||
|
const allFromMessages = Array.from(
|
||||||
|
new Set(
|
||||||
|
entries
|
||||||
|
.filter(icon => icon.customIcon != null)
|
||||||
|
.map(icon => icon.customIcon as string)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
const notInAllIds = allFromMessages
|
||||||
|
.filter(id => !all.includes(id))
|
||||||
|
.map(id => `"${id}"`)
|
||||||
|
.join(',')
|
||||||
|
|
||||||
|
if (notInAllIds.length != 0) {
|
||||||
|
;(async () => {
|
||||||
|
const result = await axios.get(
|
||||||
|
`/api/berrydash/icon-marketplace/icon?ids=[${notInAllIds}]`
|
||||||
|
)
|
||||||
|
if (result.data.success) {
|
||||||
|
const add: CustomIconEntry[] = []
|
||||||
|
for (const item of result.data.data) {
|
||||||
|
add.push({
|
||||||
|
data: item.data,
|
||||||
|
id: item.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
setCustomIconCache(prev => [
|
||||||
|
...prev,
|
||||||
|
...result.data.data.map((item: CustomIconEntry) => ({
|
||||||
|
data: item.data,
|
||||||
|
id: item.id
|
||||||
|
}))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
}, [entries])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='box'>
|
||||||
|
{selected == -1 ? (
|
||||||
|
<BackButton href='/game/berry-dash' />
|
||||||
|
) : (
|
||||||
|
<BackButton
|
||||||
|
onClick={() => {
|
||||||
|
if (gettingEntries) return
|
||||||
|
setEntries([])
|
||||||
|
setSelectedBerryOption(0)
|
||||||
|
setSelected(-1)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<DiscordButton />
|
||||||
|
<p className='px-20 mb-2 -mt-2 text-center text-2xl'>
|
||||||
|
Berry Dash Leaderboards
|
||||||
|
</p>
|
||||||
|
{selected == -1 ? (
|
||||||
|
<>
|
||||||
|
<p className='text-center mt-4 text-xl'>Select a Leaderboard</p>
|
||||||
|
<div className='flex flex-col gap-2 mt-4 items-center justify-center'>
|
||||||
|
<button onClick={() => setSelected(0)}>Score Leaderboard</button>
|
||||||
|
<button onClick={() => setSelected(1)}>Berry Leaderboard</button>
|
||||||
|
<button onClick={() => setSelected(2)}>Coins Leaderboard</button>
|
||||||
|
<button onClick={() => setSelected(3)}>Legacy Leaderboard</button>
|
||||||
|
<button onClick={() => setSelected(4)}>
|
||||||
|
Total Berries Leaderboard
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className='flex flex-col gap-2'>
|
||||||
|
{entries.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className='flex justify-between items-center'
|
||||||
|
>
|
||||||
|
<div className='flex items-center gap-1'>
|
||||||
|
<img
|
||||||
|
src={
|
||||||
|
!item.customIcon
|
||||||
|
? `https://games-r2.lncvrt.xyz/game-assets/berrydash/icons/bird_${
|
||||||
|
item.icon == 1
|
||||||
|
? GetIconForUser(item.id)
|
||||||
|
: item.icon
|
||||||
|
}.png`
|
||||||
|
: customIconCache.find(i => i.id === item.customIcon)
|
||||||
|
? 'data:image/png;base64,' +
|
||||||
|
customIconCache.find(i => i.id === item.customIcon)
|
||||||
|
?.data
|
||||||
|
: 'https://games-r2.lncvrt.xyz/game-assets/berrydash/other/loading.png'
|
||||||
|
}
|
||||||
|
width={48}
|
||||||
|
height={48}
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
{item.username} (#{index + 1})
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
{selected != 2 ? 'Berries' : 'Coins'}:{' '}
|
||||||
|
{item.value.toLocaleString('en-US')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -113,6 +113,9 @@ export default function BerryDashGameInfo () {
|
|||||||
<Link href='/game/berry-dash/chatroom' draggable={false}>
|
<Link href='/game/berry-dash/chatroom' draggable={false}>
|
||||||
View & interact with the Chatroom!
|
View & interact with the Chatroom!
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link href='/game/berry-dash/leaderboards' draggable={false}>
|
||||||
|
View the Leaderboards
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<p className='text-2xl my-1'>Downloads</p>
|
<p className='text-2xl my-1'>Downloads</p>
|
||||||
<div className='downloads'>
|
<div className='downloads'>
|
||||||
|
|||||||
Reference in New Issue
Block a user