updated backed
This commit is contained in:
parent
86163a61b0
commit
d591553872
|
|
@ -2,10 +2,11 @@
|
|||
import type { ServerWebSocket } from "bun";
|
||||
import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
|
||||
import type { z, ZodType } from "zod";
|
||||
import * as schema from "../schema";
|
||||
|
||||
interface RequestContext {
|
||||
user?: string;
|
||||
db: BunSQLiteDatabase;
|
||||
db: BunSQLiteDatabase<typeof schema>;
|
||||
ws: ServerWebSocket<unknown>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ import {
|
|||
import { getWeight, lootboxes } from "../../shared/lootboxes";
|
||||
import { weightedPickRandom } from "../../shared/utils";
|
||||
import { emit } from "../events";
|
||||
import { Game } from "../schema";
|
||||
import { and, eq, gt } from "drizzle-orm";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const secret = process.env.SECRET!;
|
||||
|
||||
|
|
@ -176,4 +179,28 @@ export const userController = createController({
|
|||
});
|
||||
},
|
||||
),
|
||||
getHeatmap: createEndpoint(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
async ({ id }, { db }) => {
|
||||
const now = dayjs();
|
||||
const firstOfYear = now
|
||||
.set("day", 0)
|
||||
.set("month", 0)
|
||||
.set("hour", 0)
|
||||
.set("minute", 0);
|
||||
const gamesOfUser = await db.query.Game.findMany({
|
||||
where: and(eq(Game.user, id), gt(Game.finished, firstOfYear.valueOf())),
|
||||
});
|
||||
const heat = Array.from<number>({
|
||||
length: now.diff(firstOfYear, "days") + 1,
|
||||
}).fill(0);
|
||||
gamesOfUser.forEach((game) => {
|
||||
const day = dayjs(game.finished).diff(firstOfYear, "days");
|
||||
heat[day] += 1;
|
||||
});
|
||||
return heat;
|
||||
},
|
||||
),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||
import * as schema from "../schema";
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
export const getDb = (filename: string = "sqlite.db") => {
|
||||
const sqlite = new Database(filename);
|
||||
const db = drizzle(sqlite);
|
||||
const db = drizzle(sqlite, { schema });
|
||||
return db;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ import { Collection, type CollectionType } from "../schema";
|
|||
import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
|
||||
import { decode, encode } from "@msgpack/msgpack";
|
||||
import type { UserCollection } from "../../shared/gameType";
|
||||
import * as schema from "../schema";
|
||||
|
||||
export const getCollection = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
): Promise<UserCollection> => {
|
||||
const res = (
|
||||
|
|
@ -24,7 +25,7 @@ export const getCollection = async (
|
|||
};
|
||||
|
||||
export const upsertCollection = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
collection: UserCollection,
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,19 @@ import { Game, type GameType } from "../schema";
|
|||
import { eq, sql, desc, and, not } from "drizzle-orm";
|
||||
import type { ServerGame } from "../../shared/game";
|
||||
import { decode, encode } from "@msgpack/msgpack";
|
||||
import * as schema from "../schema";
|
||||
|
||||
export const getGame = async (db: BunSQLiteDatabase, uuid: string) => {
|
||||
export const getGame = async (
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
uuid: string,
|
||||
) => {
|
||||
return (await db.select().from(Game).where(eq(Game.uuid, uuid)))[0];
|
||||
};
|
||||
|
||||
export const getGames = async (db: BunSQLiteDatabase, user: string) => {
|
||||
export const getGames = async (
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
) => {
|
||||
return await db
|
||||
.select()
|
||||
.from(Game)
|
||||
|
|
@ -16,7 +23,10 @@ export const getGames = async (db: BunSQLiteDatabase, user: string) => {
|
|||
.orderBy(desc(Game.started));
|
||||
};
|
||||
|
||||
export const getCurrentGame = async (db: BunSQLiteDatabase, user: string) => {
|
||||
export const getCurrentGame = async (
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
) => {
|
||||
return (
|
||||
await db
|
||||
.select()
|
||||
|
|
@ -27,7 +37,10 @@ export const getCurrentGame = async (db: BunSQLiteDatabase, user: string) => {
|
|||
)[0];
|
||||
};
|
||||
|
||||
export const getGamesCount = async (db: BunSQLiteDatabase, user: string) => {
|
||||
export const getGamesCount = async (
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
) => {
|
||||
return (
|
||||
await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
|
|
@ -36,7 +49,10 @@ export const getGamesCount = async (db: BunSQLiteDatabase, user: string) => {
|
|||
)[0].count;
|
||||
};
|
||||
|
||||
export const upsertGame = async (db: BunSQLiteDatabase, game: GameType) => {
|
||||
export const upsertGame = async (
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
game: GameType,
|
||||
) => {
|
||||
const { uuid, user, stage, gameState, finished, started } = game;
|
||||
const games = await db.select().from(Game).where(eq(Game.uuid, uuid));
|
||||
if (games.length > 0) {
|
||||
|
|
@ -62,7 +78,7 @@ export const upsertGame = async (db: BunSQLiteDatabase, game: GameType) => {
|
|||
};
|
||||
|
||||
export const upsertGameState = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
game: ServerGame,
|
||||
) => {
|
||||
const { uuid, user, stage, finished, started } = game;
|
||||
|
|
@ -77,7 +93,7 @@ export const upsertGameState = async (
|
|||
};
|
||||
|
||||
export const getTotalGamesPlayed = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user?: string,
|
||||
) => {
|
||||
if (user)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import { eq } from "drizzle-orm";
|
||||
import { Gems } from "../schema";
|
||||
import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
|
||||
import * as schema from "../schema";
|
||||
|
||||
export const getGems = async (db: BunSQLiteDatabase, user: string) => {
|
||||
export const getGems = async (
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
) => {
|
||||
const res = (await db.select().from(Gems).where(eq(Gems.user, user)))[0];
|
||||
const count = res?.count ?? 0;
|
||||
const totalCount = res?.totalCount ?? 0;
|
||||
|
|
@ -10,7 +14,7 @@ export const getGems = async (db: BunSQLiteDatabase, user: string) => {
|
|||
};
|
||||
|
||||
export const addGems = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
gems: number,
|
||||
) => {
|
||||
|
|
@ -28,7 +32,7 @@ export const addGems = async (
|
|||
};
|
||||
|
||||
export const removeGems = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
gems: number,
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { eq, sql, not } from "drizzle-orm";
|
||||
import { Game } from "../schema";
|
||||
import type { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
|
||||
import * as schema from "../schema";
|
||||
|
||||
export const getScoreBoard = async (db: BunSQLiteDatabase) => {
|
||||
export const getScoreBoard = async (db: BunSQLiteDatabase<typeof schema>) => {
|
||||
return (
|
||||
await db
|
||||
.select({ stage: sql<number>`max(${Game.stage})`, user: Game.user })
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ import {
|
|||
userSettings as userSettingsSchema,
|
||||
type UserSettings as UserSettingsType,
|
||||
} from "../../shared/user-settings";
|
||||
import * as schema from "../schema";
|
||||
|
||||
export const registerUser = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
name: string,
|
||||
password: string,
|
||||
) => {
|
||||
|
|
@ -23,7 +24,7 @@ export const registerUser = async (
|
|||
};
|
||||
|
||||
export const loginUser = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
name: string,
|
||||
password: string,
|
||||
) => {
|
||||
|
|
@ -41,7 +42,7 @@ export const loginUser = async (
|
|||
};
|
||||
|
||||
export const getUser = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
name: string,
|
||||
): Promise<UserType | undefined> => {
|
||||
const user = await db
|
||||
|
|
@ -52,7 +53,7 @@ export const getUser = async (
|
|||
};
|
||||
|
||||
export const getUserSettings = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
): Promise<UserSettingsType> => {
|
||||
const userSettings = await db
|
||||
|
|
@ -64,7 +65,7 @@ export const getUserSettings = async (
|
|||
};
|
||||
|
||||
export const upsertUserSettings = async (
|
||||
db: BunSQLiteDatabase,
|
||||
db: BunSQLiteDatabase<typeof schema>,
|
||||
user: string,
|
||||
settings: UserSettingsType,
|
||||
) => {
|
||||
|
|
@ -87,7 +88,7 @@ export const upsertUserSettings = async (
|
|||
}
|
||||
};
|
||||
|
||||
export const getUserCount = async (db: BunSQLiteDatabase) => {
|
||||
export const getUserCount = async (db: BunSQLiteDatabase<typeof schema>) => {
|
||||
return (await db.select({ count: sql<number>`count(*)` }).from(User))[0]
|
||||
.count;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"@uidotdev/usehooks": "^2.4.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"drizzle-orm": "0.33.0",
|
||||
"framer-motion": "^11.11.8",
|
||||
"jotai": "^2.10.0",
|
||||
|
|
|
|||
|
|
@ -246,4 +246,4 @@ export const halloween: Lootbox = {
|
|||
],
|
||||
};
|
||||
|
||||
export const lootboxes = [series1, halloween];
|
||||
export const lootboxes = [series1];
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import MatchHistory from "./views/match-history/MatchHistory.tsx";
|
|||
import Collection from "./views/collection/Collection.tsx";
|
||||
import { AnimatePresence } from "framer-motion";
|
||||
import Store from "./views/store/Store.tsx";
|
||||
import Profile from "./views/profile/Profile.tsx";
|
||||
|
||||
const setup = async () => {
|
||||
const token = localStorage.getItem("loginToken");
|
||||
|
|
@ -44,6 +45,7 @@ setup().then(() => {
|
|||
<Route path="/settings" component={Settings} />
|
||||
<Route path="/collection" component={Collection} />
|
||||
<Route path="/store" component={Store} />
|
||||
<Route path="/profile" component={Profile} />
|
||||
</Switch>
|
||||
</AnimatePresence>
|
||||
</Shell>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import { useMemo } from "react";
|
||||
import { useWSQuery } from "../../hooks";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const Profile: React.FC = () => {
|
||||
const { data: heatmap } = useWSQuery("user.getHeatmap", { id: "Gordon" });
|
||||
const now = useMemo(() => dayjs(), []);
|
||||
const firstOfYear = useMemo(
|
||||
() => now.set("day", 0).set("month", 0).set("hour", 0).set("minute", 0),
|
||||
[now],
|
||||
);
|
||||
const weeks = now.diff(firstOfYear, "weeks") + 1;
|
||||
const maxHeat = heatmap ? Math.max(...heatmap) : 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{heatmap && (
|
||||
<div className="flex gap-2">
|
||||
{Array.from({ length: weeks }).map((_, w) => (
|
||||
<div key={w} className="w-4 flex gap-2 flex-col">
|
||||
{Array.from({ length: 7 }).map((_, d) => (
|
||||
<div key={d} className="w-4 h-4 border border-white">
|
||||
<div
|
||||
className="w-4 h-4 bg-purple-600 -m-px"
|
||||
style={{
|
||||
opacity: heatmap[w * 7 + d] / maxHeat,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Profile;
|
||||
Loading…
Reference in New Issue