From 59ec0363807e670476ca8f28ce46a558bfae9df3 Mon Sep 17 00:00:00 2001 From: MasterGordon Date: Sat, 28 Jun 2025 15:05:36 +0200 Subject: [PATCH] updated backend to provide gems spend statistic --- backend/controller/userController.ts | 15 +++++-- shared/utils.ts | 5 +++ src/views/collection/Collection.tsx | 25 ++++++------ src/views/endless/Endless.tsx | 58 +++++++++++++++------------- src/views/profile/Profile.tsx | 6 +++ vite.config.ts | 9 ++++- 6 files changed, 75 insertions(+), 43 deletions(-) diff --git a/backend/controller/userController.ts b/backend/controller/userController.ts index 21d40af..7193600 100644 --- a/backend/controller/userController.ts +++ b/backend/controller/userController.ts @@ -17,9 +17,9 @@ import { upsertCollection, } from "../repositories/collectionRepository"; import { getWeight, lootboxes } from "../../shared/lootboxes"; -import { weightedPickRandom } from "../../shared/utils"; +import { round, weightedPickRandom } from "../../shared/utils"; import { emit } from "../events"; -import { Game } from "../schema"; +import { Game, Gems } from "../schema"; import { and, count, eq, gt, max, not, sum } from "drizzle-orm"; import dayjs from "dayjs"; @@ -222,10 +222,19 @@ export const userController = createController({ }) .from(Game) .where(and(eq(Game.user, id), not(eq(Game.finished, 0)))); + const [{ totalGems, currentGems }] = await db + .select({ + totalGems: Gems.totalCount, + currentGems: Gems.count, + }) + .from(Gems) + .where(eq(Gems.user, id)); return { totalGames, highestStage, - averageStage: Number(totalStages) / totalGames, + averageStage: round(Number(totalStages) / totalGames, 3), + totalGems, + currentGems, }; }, ), diff --git a/shared/utils.ts b/shared/utils.ts index 0df594c..68046ee 100644 --- a/shared/utils.ts +++ b/shared/utils.ts @@ -20,3 +20,8 @@ export const weightedPickRandom = ( } return arr[arr.length - 1]; }; + +export const round = (value: number, digits: number) => { + const factor = Math.pow(10, digits); + return Math.round(value * factor) / factor; +}; diff --git a/src/views/collection/Collection.tsx b/src/views/collection/Collection.tsx index 2e528a4..c865c66 100644 --- a/src/views/collection/Collection.tsx +++ b/src/views/collection/Collection.tsx @@ -11,6 +11,7 @@ import { } from "../../components/DropdownMenu"; import { cn } from "../../lib/utils"; import { useWSMutation, useWSQuery } from "../../hooks"; +import { Suspense } from "react"; const Collection = () => { const { data: collection, refetch } = useWSQuery( @@ -75,17 +76,19 @@ const Collection = () => { )} - {}} - restartGame={() => {}} - onRightClick={() => {}} - width={11 * 32} - height={4 * 32} - className={cn( - selected && "outline-primary outline-4 rounded-md", - )} - /> + + {}} + restartGame={() => {}} + onRightClick={() => {}} + width={11 * 32} + height={4 * 32} + className={cn( + selected && "outline-primary outline-4 rounded-md", + )} + /> + ); })} diff --git a/src/views/endless/Endless.tsx b/src/views/endless/Endless.tsx index ef80503..60b9b6e 100644 --- a/src/views/endless/Endless.tsx +++ b/src/views/endless/Endless.tsx @@ -3,7 +3,7 @@ import { useAtom } from "jotai"; import { gameIdAtom } from "../../atoms"; import { Button } from "../../components/Button"; import LeaderboardButton from "../../components/LeaderboardButton"; -import { Fragment, useEffect } from "react"; +import { Fragment, startTransition, Suspense, useEffect } from "react"; import { Board } from "../../components/LazyBoard"; interface EndlessProps { @@ -41,31 +41,33 @@ const Endless: React.FC = (props) => {
- { - const gameId = await startGame.mutateAsync(null); - setGameId(gameId.uuid); - }} - onLeftClick={(x, y) => { - reveal.mutateAsync({ x, y }); - }} - onRightClick={(x, y) => { - const isFlagged = game.isFlagged[x][y]; - const isQuestionMark = game.isQuestionMark[x][y]; - if (!isFlagged && !isQuestionMark) { - placeFlag.mutateAsync({ x, y }); - return; - } - if (isFlagged && settings?.placeQuestionMark) { - placeQuestionMark.mutateAsync({ x, y }); - return; - } else { - clearTile.mutateAsync({ x, y }); - return; - } - }} - /> + + { + const gameId = await startGame.mutateAsync(null); + setGameId(gameId.uuid); + }} + onLeftClick={(x, y) => { + reveal.mutateAsync({ x, y }); + }} + onRightClick={(x, y) => { + const isFlagged = game.isFlagged[x][y]; + const isQuestionMark = game.isQuestionMark[x][y]; + if (!isFlagged && !isQuestionMark) { + placeFlag.mutateAsync({ x, y }); + return; + } + if (isFlagged && settings?.placeQuestionMark) { + placeQuestionMark.mutateAsync({ x, y }); + return; + } else { + clearTile.mutateAsync({ x, y }); + return; + } + }} + /> + ) : (
@@ -76,7 +78,9 @@ const Endless: React.FC = (props) => { variant="primary" onClick={async () => { const gameId = await startGame.mutateAsync(null); - setGameId(gameId.uuid); + startTransition(() => { + setGameId(gameId.uuid); + }); }} > Start Game diff --git a/src/views/profile/Profile.tsx b/src/views/profile/Profile.tsx index 03f3754..05b68d3 100644 --- a/src/views/profile/Profile.tsx +++ b/src/views/profile/Profile.tsx @@ -7,6 +7,7 @@ import { TooltipTrigger, } from "../../components/Tooltip"; import PastMatch from "../../components/PastMatch"; +import GemsIcon from "../../components/GemIcon"; const Profile: React.FC = () => { const { data: username } = useWSQuery("user.getSelf", null); @@ -43,6 +44,11 @@ const Profile: React.FC = () => {

Average Stage: {Math.round(profile?.averageStage ?? 1 * 100) / 100}

+

+ Gems Spend:{" "} + {(profile?.totalGems ?? 0) - (profile?.currentGems ?? 0)}{" "} + +

diff --git a/vite.config.ts b/vite.config.ts index 34e8257..435d5c5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,12 +2,17 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react-swc"; import tailwindcss from "@tailwindcss/vite"; import { imagetools } from "vite-imagetools"; -import { analyzer } from "vite-bundle-analyzer"; +// import { analyzer } from "vite-bundle-analyzer"; // https://vitejs.dev/config/ export default defineConfig({ server: { port: 3003, }, - plugins: [react(), tailwindcss(), imagetools(), analyzer()], + plugins: [ + react(), + tailwindcss(), + imagetools(), + // analyzer() + ], });