From 569fb276a92099b3ba3b9bf8f56ec1cf76a79291 Mon Sep 17 00:00:00 2001 From: Lncvrt Date: Mon, 2 Feb 2026 00:57:53 -0700 Subject: [PATCH] Improvements & add leaderboards --- src/app/components/BackButton.tsx | 24 ++- src/app/game/berry-dash/chatroom/page.tsx | 4 +- .../game/berry-dash/icon-marketplace/page.tsx | 2 +- .../icon-marketplace/upload/page.tsx | 2 +- src/app/game/berry-dash/leaderboards/page.tsx | 173 ++++++++++++++++++ src/app/game/berry-dash/page.tsx | 3 + 6 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 src/app/game/berry-dash/leaderboards/page.tsx diff --git a/src/app/components/BackButton.tsx b/src/app/components/BackButton.tsx index 5500d50..b3718ad 100644 --- a/src/app/components/BackButton.tsx +++ b/src/app/components/BackButton.tsx @@ -2,13 +2,29 @@ import { faArrowLeft } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import Link from 'next/link' -export function BackButton ({ href }: { href: string }) { +export function BackButton ({ + href, + onClick +}: { + href?: string + onClick?: () => void +}) { return ( <>
- - - + {href && ( + + + + )} + {onClick && ( + + )}
) diff --git a/src/app/game/berry-dash/chatroom/page.tsx b/src/app/game/berry-dash/chatroom/page.tsx index 54a7a5d..2453435 100644 --- a/src/app/game/berry-dash/chatroom/page.tsx +++ b/src/app/game/berry-dash/chatroom/page.tsx @@ -18,7 +18,7 @@ interface WSMessage { data: any } -type BirdColor = [number, number, number] +export type BirdColor = [number, number, number] interface Message { username: string @@ -35,7 +35,7 @@ interface Message { editing: boolean } -interface CustomIconEntry { +export interface CustomIconEntry { data: string id: string } diff --git a/src/app/game/berry-dash/icon-marketplace/page.tsx b/src/app/game/berry-dash/icon-marketplace/page.tsx index 51f6e1b..e1672c7 100644 --- a/src/app/game/berry-dash/icon-marketplace/page.tsx +++ b/src/app/game/berry-dash/icon-marketplace/page.tsx @@ -64,7 +64,7 @@ export default function BerryDashIconMarketplace () { />

Bird Name: {icon.name}

-

Price: {icon.price}

+

Price: {icon.price.toLocaleString('en-US')}

Designer Name: {icon.username}

)) diff --git a/src/app/game/berry-dash/icon-marketplace/upload/page.tsx b/src/app/game/berry-dash/icon-marketplace/upload/page.tsx index 137935b..b11d591 100644 --- a/src/app/game/berry-dash/icon-marketplace/upload/page.tsx +++ b/src/app/game/berry-dash/icon-marketplace/upload/page.tsx @@ -176,7 +176,7 @@ export default function BerryDashSubmitIcon () { ? 'N/A' : name}

-

Price: {price}

+

Price: {price.toLocaleString('en-US')}

Designer Name: {getCookie('accountUsername', '-1')}

diff --git a/src/app/game/berry-dash/leaderboards/page.tsx b/src/app/game/berry-dash/leaderboards/page.tsx new file mode 100644 index 0000000..1844ddf --- /dev/null +++ b/src/app/game/berry-dash/leaderboards/page.tsx @@ -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(-1) + const [selectedBerryOption, setSelectedBerryOption] = useState(0) + const [gettingEntries, setGettingEntries] = useState(false) + const [entries, setEntries] = useState([]) + const [customIconCache, setCustomIconCache] = useState([]) + + 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 ( +
+ {selected == -1 ? ( + + ) : ( + { + if (gettingEntries) return + setEntries([]) + setSelectedBerryOption(0) + setSelected(-1) + }} + /> + )} + +

+ Berry Dash Leaderboards +

+ {selected == -1 ? ( + <> +

Select a Leaderboard

+
+ + + + + +
+ + ) : ( + <> +
+ {entries.map((item, index) => { + return ( +
+
+ 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} + /> +

+ {item.username} (#{index + 1}) +

+
+

+ {selected != 2 ? 'Berries' : 'Coins'}:{' '} + {item.value.toLocaleString('en-US')} +

+
+ ) + })} +
+ + )} +
+ ) +} diff --git a/src/app/game/berry-dash/page.tsx b/src/app/game/berry-dash/page.tsx index 12d9a44..9312c4e 100644 --- a/src/app/game/berry-dash/page.tsx +++ b/src/app/game/berry-dash/page.tsx @@ -113,6 +113,9 @@ export default function BerryDashGameInfo () { View & interact with the Chatroom! + + View the Leaderboards +

Downloads