mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-25 15:56:19 -05:00
Builds query to user page
This commit is contained in:
parent
0efff0c907
commit
f4234b0aa0
36
app/db/models/builds/buildsByUserId.sql
Normal file
36
app/db/models/builds/buildsByUserId.sql
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
with "BuildWithWeapon" as (
|
||||
select
|
||||
"id",
|
||||
"title",
|
||||
"description",
|
||||
"modes",
|
||||
"headGearSplId",
|
||||
"clothesGearSplId",
|
||||
"shoesGearSplId",
|
||||
"updatedAt",
|
||||
json_group_array("BuildWeapon"."weaponSplId") as "weapons"
|
||||
from
|
||||
"Build"
|
||||
left join "BuildWeapon" on "BuildWeapon"."buildId" = "Build"."id"
|
||||
where
|
||||
"Build"."ownerId" = @userId
|
||||
group by
|
||||
"Build"."id"
|
||||
)
|
||||
select
|
||||
"BuildWithWeapon".*,
|
||||
json_group_array(
|
||||
json_object(
|
||||
'ability',
|
||||
"BuildAbility"."ability",
|
||||
'gearType',
|
||||
"BuildAbility"."gearType",
|
||||
'slotIndex',
|
||||
"BuildAbility"."slotIndex"
|
||||
)
|
||||
) as "abilities"
|
||||
from
|
||||
"BuildWithWeapon"
|
||||
left join "BuildAbility" on "BuildAbility"."buildId" = "BuildWithWeapon"."id"
|
||||
group by
|
||||
"BuildWithWeapon"."id";
|
||||
6
app/db/models/builds/countByUserId.sql
Normal file
6
app/db/models/builds/countByUserId.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
select
|
||||
count(*)
|
||||
from
|
||||
"Build"
|
||||
where
|
||||
"ownerId" = @userId;
|
||||
|
|
@ -1,13 +1,19 @@
|
|||
import { sql } from "~/db/sql";
|
||||
import type { Build, BuildAbility, BuildWeapon } from "~/db/types";
|
||||
import type { Ability, ModeShort } from "~/modules/in-game-lists";
|
||||
|
||||
import createBuildSql from "./createBuild.sql";
|
||||
import createBuildWeaponSql from "./createBuildWeapon.sql";
|
||||
import createBuildAbilitySql from "./createBuildAbility.sql";
|
||||
import countByUserIdSql from "./countByUserId.sql";
|
||||
import buildsByUserIdSql from "./buildsByUserId.sql";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const createBuildStm = sql.prepare(createBuildSql);
|
||||
const createBuildWeaponStm = sql.prepare(createBuildWeaponSql);
|
||||
const createBuildAbilityStm = sql.prepare(createBuildAbilitySql);
|
||||
const countByUserIdStm = sql.prepare(countByUserIdSql);
|
||||
const buildsByUserIdStm = sql.prepare(buildsByUserIdSql);
|
||||
|
||||
interface CreateArgs {
|
||||
ownerId: Build["ownerId"];
|
||||
|
|
@ -51,3 +57,67 @@ export const create = sql.transaction((build: CreateArgs) => {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
export function countByUserId(userId: Build["ownerId"]) {
|
||||
return (countByUserIdStm.get({ userId })?.count ?? 0) as number;
|
||||
}
|
||||
|
||||
type BuildsByUserRow = Pick<
|
||||
Build,
|
||||
| "id"
|
||||
| "title"
|
||||
| "description"
|
||||
| "modes"
|
||||
| "headGearSplId"
|
||||
| "clothesGearSplId"
|
||||
| "shoesGearSplId"
|
||||
| "updatedAt"
|
||||
> & { weapons: string; abilities: string };
|
||||
export function buildsByUserId(userId: Build["ownerId"]) {
|
||||
const rows = buildsByUserIdStm.all({ userId }) as Array<BuildsByUserRow>;
|
||||
|
||||
return rows.map(augmentBuild);
|
||||
}
|
||||
|
||||
function augmentBuild<T>(
|
||||
row: T & { modes: Build["modes"]; weapons: string; abilities: string }
|
||||
) {
|
||||
const modes = row.modes ? (row.modes.split(",") as ModeShort[]) : null;
|
||||
const weapons = JSON.parse(row.weapons) as Array<BuildWeapon["weaponSplId"]>;
|
||||
const abilities = JSON.parse(row.abilities) as Array<
|
||||
Pick<BuildAbility, "ability" | "gearType" | "slotIndex">
|
||||
>;
|
||||
|
||||
return {
|
||||
...row,
|
||||
modes,
|
||||
weapons,
|
||||
abilities: dbAbilitiesToArrayOfArrays(abilities),
|
||||
};
|
||||
}
|
||||
|
||||
const gearOrder: Array<BuildAbility["gearType"]> = ["HEAD", "CLOTHES", "SHOES"];
|
||||
function dbAbilitiesToArrayOfArrays(
|
||||
abilities: Array<Pick<BuildAbility, "ability" | "gearType" | "slotIndex">>
|
||||
): [
|
||||
head: [main: Ability, s1: Ability, s2: Ability, s3: Ability],
|
||||
clothes: [main: Ability, s1: Ability, s2: Ability, s3: Ability],
|
||||
shoes: [main: Ability, s1: Ability, s2: Ability, s3: Ability]
|
||||
] {
|
||||
const sorted = abilities
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
if (a.gearType === b.gearType) return a.slotIndex - b.slotIndex;
|
||||
|
||||
return gearOrder.indexOf(a.gearType) - gearOrder.indexOf(b.gearType);
|
||||
})
|
||||
.map((a) => a.ability);
|
||||
|
||||
invariant(sorted.length === 12, "expected 12 abilities");
|
||||
|
||||
return [
|
||||
[sorted[0]!, sorted[1]!, sorted[2]!, sorted[3]!],
|
||||
[sorted[4]!, sorted[5]!, sorted[6]!, sorted[7]!],
|
||||
[sorted[8]!, sorted[9]!, sorted[10]!, sorted[11]!],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ export const loader = async ({ request, params }: LoaderArgs) => {
|
|||
: undefined,
|
||||
badges: db.badges.countsByUserId(user.id),
|
||||
results: db.calendarEvents.findResultsByUserId(user.id),
|
||||
buildsCount: db.builds.countByUserId(user.id),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -91,6 +92,11 @@ export default function UserPageLayout() {
|
|||
{t("results")}
|
||||
</SubNavLink>
|
||||
)}
|
||||
{(isOwnPage || data.buildsCount > 0) && (
|
||||
<SubNavLink to="builds" data-cy="builds-page-link">
|
||||
{t("pages.builds")} ({data.buildsCount})
|
||||
</SubNavLink>
|
||||
)}
|
||||
</SubNav>
|
||||
<Outlet />
|
||||
</>
|
||||
|
|
|
|||
23
app/routes/u.$identifier/builds.tsx
Normal file
23
app/routes/u.$identifier/builds.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { json, type LoaderArgs } from "@remix-run/node";
|
||||
// import { useLoaderData } from "@remix-run/react";
|
||||
import { Main } from "~/components/Main";
|
||||
import { db } from "~/db";
|
||||
import { notFoundIfFalsy } from "~/utils/remix";
|
||||
import { userParamsSchema } from "../u.$identifier";
|
||||
|
||||
export const loader = ({ params }: LoaderArgs) => {
|
||||
const { identifier } = userParamsSchema.parse(params);
|
||||
const user = notFoundIfFalsy(db.users.findByIdentifier(identifier));
|
||||
|
||||
const builds = db.builds.buildsByUserId(user.id);
|
||||
|
||||
return json({ builds });
|
||||
};
|
||||
|
||||
export default function UserBuildsPage() {
|
||||
// const data = useLoaderData<typeof loader>();
|
||||
|
||||
// console.log({ data });
|
||||
|
||||
return <Main>hey</Main>;
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
"pages.contributors": "Contributors",
|
||||
"pages.calendar": "Calendar",
|
||||
"pages.faq": "FAQ",
|
||||
"pages.builds": "Builds",
|
||||
|
||||
"header.profile": "Profile",
|
||||
"header.logout": "Log out",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-console */
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import invariant from "tiny-invariant";
|
||||
|
|
@ -32,7 +33,7 @@ async function main() {
|
|||
.replace("Path_Wst_", "");
|
||||
|
||||
const weaponId = weapons.find(
|
||||
(w) => w.internalName === weaponInternalName
|
||||
(w: any) => w.internalName === weaponInternalName
|
||||
).id;
|
||||
invariant(typeof weaponId === "number", weaponInternalName + " has no id");
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ async function main() {
|
|||
invariant(internalName);
|
||||
|
||||
const gearId = gear.find(
|
||||
(g) => g.internalName === internalName && g.type === type
|
||||
(g: any) => g.internalName === internalName && g.type === type
|
||||
)?.id;
|
||||
invariant(typeof gearId === "number", internalName + " has no id");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user