updated backend to provide gems spend statistic
This commit is contained in:
parent
e8d1a8afde
commit
59ec036380
|
|
@ -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,
|
||||
};
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -20,3 +20,8 @@ export const weightedPickRandom = <T>(
|
|||
}
|
||||
return arr[arr.length - 1];
|
||||
};
|
||||
|
||||
export const round = (value: number, digits: number) => {
|
||||
const factor = Math.pow(10, digits);
|
||||
return Math.round(value * factor) / factor;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
|||
</DropdownMenu>
|
||||
)}
|
||||
</div>
|
||||
<Board
|
||||
game={testBoard(theme.id)}
|
||||
onLeftClick={() => {}}
|
||||
restartGame={() => {}}
|
||||
onRightClick={() => {}}
|
||||
width={11 * 32}
|
||||
height={4 * 32}
|
||||
className={cn(
|
||||
selected && "outline-primary outline-4 rounded-md",
|
||||
)}
|
||||
/>
|
||||
<Suspense>
|
||||
<Board
|
||||
game={testBoard(theme.id)}
|
||||
onLeftClick={() => {}}
|
||||
restartGame={() => {}}
|
||||
onRightClick={() => {}}
|
||||
width={11 * 32}
|
||||
height={4 * 32}
|
||||
className={cn(
|
||||
selected && "outline-primary outline-4 rounded-md",
|
||||
)}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -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<EndlessProps> = (props) => {
|
|||
<div className="grow" />
|
||||
<LeaderboardButton label="View Leaderboard" />
|
||||
</div>
|
||||
<Board
|
||||
game={game}
|
||||
restartGame={async () => {
|
||||
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;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Suspense>
|
||||
<Board
|
||||
game={game}
|
||||
restartGame={async () => {
|
||||
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;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
</>
|
||||
) : (
|
||||
<div className="w-full grid md:grid-cols-[350px_1fr]">
|
||||
|
|
@ -76,7 +78,9 @@ const Endless: React.FC<EndlessProps> = (props) => {
|
|||
variant="primary"
|
||||
onClick={async () => {
|
||||
const gameId = await startGame.mutateAsync(null);
|
||||
setGameId(gameId.uuid);
|
||||
startTransition(() => {
|
||||
setGameId(gameId.uuid);
|
||||
});
|
||||
}}
|
||||
>
|
||||
Start Game
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
|||
<p>
|
||||
Average Stage: {Math.round(profile?.averageStage ?? 1 * 100) / 100}
|
||||
</p>
|
||||
<p>
|
||||
Gems Spend:{" "}
|
||||
{(profile?.totalGems ?? 0) - (profile?.currentGems ?? 0)}{" "}
|
||||
<GemsIcon />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
],
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue