feat: useAwait

This commit is contained in:
TrèsAbhi committed 2025-11-30 22:12:46 -06:00
1 parent 42cada1811
commit 4033e8618f
6 files changed
+90 -27

No files matched your search

@@ -1,6 +1,6 @@
import { TankAttributeChange_AttributeName } from "@protos/blitz_static_tank_upgrade_single_stage";
enum CharacteristicsGroup {
export enum CharacteristicsGroup {
Firepower,
Maneuverability,
Survivability,
+10 -1
View File
@@ -1,3 +1,12 @@
import { TankCatalogComponent } from "@protos/blitz_static_tank_component";
import { AbstractAPI } from "./abstract";
export class ClientAPI extends AbstractAPI {}
export class ClientAPI extends AbstractAPI {
async tank(id: string) {
const response = await fetch(`/api/tanks/${id}.pb`);
const buffer = await response.arrayBuffer();
const array = new Uint8Array(buffer);
return TankCatalogComponent.decode(array);
}
}
+19
View File
@@ -0,0 +1,19 @@
import { use } from "react";
const cache = new Map<string, Promise<unknown>>();
export function useAwait<Type>(
creator: () => Promise<Type>,
discriminator: string
) {
let promise;
if (cache.has(discriminator)) {
promise = cache.get(discriminator) as Promise<Type>;
} else {
promise = creator();
cache.set(discriminator, promise);
}
return use(promise);
}
@@ -0,0 +1,14 @@
import { TankCatalogComponent } from "@protos/blitz_static_tank_component";
import type { APIContext, GetStaticPaths } from "astro";
import { api } from "../../../core/api/dynamic";
export const getStaticPaths = (async () => {
const { tanks } = await api.tanks();
return tanks.map(({ id }) => ({ params: { id } }));
}) satisfies GetStaticPaths;
export async function GET({ params }: APIContext<never, { id: string }>) {
const tank = await api.tank(params.id);
return new Response(TankCatalogComponent.encode(tank).finish());
}
@@ -2,45 +2,66 @@ import {
TankAttributeChange_AttributeName,
TankAttributeChange_Modifier,
} from "@protos/blitz_static_tank_upgrade_single_stage";
import { use } from "react";
import { Suspense, useMemo } from "react";
import {
CharacteristicsGroup,
characteristicsOrder,
} from "../../../constants/characteristicsOrder";
import { api } from "../../../core/api/dynamic";
import { useAwait } from "../../../hooks/useAwait";
import { Tankopedia } from "../../../stores/tankopedia";
interface Props {
id: string;
export function Page({ id }: { id: string }) {
return (
<Suspense fallback={null}>
<Content id={id} />
</Suspense>
);
}
export function Page({ id }: Props) {
const tank = use(api.tank(id));
function Content({ id }: { id: string }) {
const tank = useAwait(() => api.tank(id), `tank-${id}`);
const stage = Tankopedia.use((state) => state.stage);
const attributes = useMemo(() => {
const attributes: Partial<
Record<TankAttributeChange_AttributeName, number>
> = {};
for (const { attribute_name, value, modifier } of tank.base_stats!
.attributes) {
if (modifier !== TankAttributeChange_Modifier.MODIFIER_OVERRIDE) {
throw new Error(
`Unexpected modifier ${TankAttributeChange_Modifier[modifier]}`
);
}
attributes[attribute_name] = value;
}
return attributes;
}, [stage]);
return (
<>
<h1>{tank.name?.value}</h1>
<h2>Base stats</h2>
<h2>Characteristics</h2>
{tank.base_stats!.attributes.map((attribute) => (
<p>
{TankAttributeChange_AttributeName[attribute.attribute_name]}:{" "}
{attribute.value} ({TankAttributeChange_Modifier[attribute.modifier]})
</p>
))}
<h2>Upgrades</h2>
{tank.upgrade_stages.map((stage, index) => (
{characteristicsOrder.map((group) => (
<>
<h3>Stage {index}</h3>
<h2>{CharacteristicsGroup[group.group]}</h2>
{stage.attributes.map((attribute) => (
<p>
{TankAttributeChange_AttributeName[attribute.attribute_name]}:{" "}
{attribute.value} (
{TankAttributeChange_Modifier[attribute.modifier]})
</p>
))}
{group.attributes.map(
(attribute) =>
attribute.name in attributes && (
<p>
{TankAttributeChange_AttributeName[attribute.name]}:{" "}
{attributes[attribute.name]}
</p>
)
)}
</>
))}
</>
@@ -15,4 +15,4 @@ export const getStaticPaths = (async () => {
const { id } = Astro.props;
---
<Page {id} />
<Page {id} client:load />