feat: better loading

This commit is contained in:
TrèsAbhi committed 2024-09-01 17:41:50 -05:00
1 parent 76625dc7b2
commit ee9dbdaf74
5 files changed
+65 -110

No files matched your search

@@ -1,4 +1,4 @@
import { Flex, Heading, Text } from '@radix-ui/themes';
import { Flex, Heading, Skeleton, Text } from '@radix-ui/themes';
import { memo } from 'react';
import { WargamingLoginButton } from '../../../../../../../../../components/Navbar/components/WargamingLoginButton';
import { formatCompact } from '../../../../../../../../../core/math/formatCompact';
@@ -19,9 +19,11 @@ export const Votes = memo(
return (
<Flex direction="column" gap="3">
<Flex justify="between" align="end">
<Flex justify="between" align="center">
<Heading size="4">
{formatCompact(votes.votes)} {votes.votes === 1 ? 'vote' : 'votes'}
{!votes && <Skeleton height="1em" width="4rem" />}
{votes && formatCompact(votes.votes)}{' '}
{votes && (votes.votes > 1 ? 'votes' : 'vote')}
</Heading>
{!wargaming && (
@@ -37,8 +39,14 @@ export const Votes = memo(
gap={{ initial: '0', sm: '6' }}
direction={{ initial: 'column', sm: 'row' }}
>
<StarRow stars={votes.categories.easiness} children="Easiness" />
<StarRow stars={votes.categories.firepower} children="Firepower" />
<StarRow
stars={votes?.categories.easiness ?? null}
children="Easiness"
/>
<StarRow
stars={votes?.categories.firepower ?? null}
children="Firepower"
/>
</Flex>
<Flex
@@ -46,24 +54,34 @@ export const Votes = memo(
direction={{ initial: 'column', sm: 'row' }}
>
<StarRow
stars={votes.categories.maneuverability}
stars={votes?.categories.maneuverability ?? null}
children="Maneuverability"
/>
<StarRow
stars={votes.categories.survivability}
stars={votes?.categories.survivability ?? null}
children="Survivability"
/>
</Flex>
{wargaming && (
<Text align="center" size="2" color="gray" mt="2">
<Flex justify="center">
<Text size="2" color="gray" mt="2">
<>
{votes.last_updated
? `You voted on ${new Date(votes.last_updated).toLocaleDateString()}`
: `You haven't voted yet`}
{votes ? (
wargaming ? (
votes.last_updated ? (
`You voted on ${new Date(votes.last_updated).toLocaleDateString()}`
) : (
`You haven't voted yet`
)
) : (
'Login to vote'
)
) : (
<Skeleton height="1em" width="5rem" />
)}
</>
</Text>
)}
</Flex>
</Flex>
</Flex>
);
@@ -1,55 +0,0 @@
import { PaperPlaneIcon } from '@radix-ui/react-icons';
import { Button, Flex, Heading, Skeleton, Text } from '@radix-ui/themes';
import { WargamingLoginButton } from '../../../../../../../../components/Navbar/components/WargamingLoginButton';
import * as App from '../../../../../../../../stores/app';
export function VotesSkeleton() {
const wargaming = App.useDeferred(
undefined,
(state) => state.logins.wargaming,
);
return (
<Flex direction="column" gap="3">
<Flex justify="between" align="end">
<Heading size="4">
<Skeleton height="1em" width="6rem" />
</Heading>
{!wargaming && (
<WargamingLoginButton variant="outline">
Login to vote
</WargamingLoginButton>
)}
{wargaming && (
<Button variant="surface">
<PaperPlaneIcon /> Vote
</Button>
)}
</Flex>
<Flex gap="0" direction="column">
<Flex gap="6">
<Flex align="center" justify="between" width="15rem">
<Text>Easiness</Text>
<Skeleton height="1em" width="5rem" />
</Flex>
<Flex align="center" justify="between" width="15rem">
<Text>Firepower</Text>
<Skeleton height="1em" width="5rem" />
</Flex>
</Flex>
<Flex gap="6">
<Flex align="center" justify="between" width="15rem">
<Text>Maneuverability</Text>
<Skeleton height="1em" width="5rem" />
</Flex>
<Flex align="center" justify="between" width="15rem">
<Text>Survivability</Text>
<Skeleton height="1em" width="5rem" />
</Flex>
</Flex>
</Flex>
</Flex>
);
}
@@ -1,6 +1,5 @@
import { ChevronLeftIcon, MixIcon } from '@radix-ui/react-icons';
import { Button, Code, Flex } from '@radix-ui/themes';
import { Suspense } from 'react';
import { classIcons } from '../../../../../../../components/ClassIcon';
import { Link } from '../../../../../../../components/Link';
import { asset } from '../../../../../../../core/blitzkit/asset';
@@ -9,7 +8,6 @@ import * as App from '../../../../../../../stores/app';
import * as Duel from '../../../../../../../stores/duel';
import { Listing } from './components/Listing';
import { Votes } from './components/Votes';
import { VotesSkeleton } from './components/VotesSkeleton';
export function MetaSection() {
const developerMode = App.useDeferred(false, (state) => state.developerMode);
@@ -40,7 +38,10 @@ export function MetaSection() {
</Link>
</Flex>
<Flex gap="6">
<Flex
gap={{ initial: '0', sm: '6' }}
direction={{ initial: 'column', sm: 'row' }}
>
<Flex direction="column" width="100%">
{protagonist.nameFull && (
<Listing label="Full-name">{protagonist.nameFull}</Listing>
@@ -139,9 +140,7 @@ export function MetaSection() {
</Flex>
</Flex>
<Suspense fallback={<VotesSkeleton />}>
<Votes />
</Suspense>
<Votes />
</Flex>
</Flex>
);
@@ -1,6 +1,6 @@
import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons';
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
import { use, useEffect, useMemo, useRef, useState } from 'react';
import { Fragment, use, useEffect, useMemo, useRef, useState } from 'react';
import { asset } from '../../../../../../../core/blitzkit/asset';
import { imgur } from '../../../../../../../core/blitzkit/imgur';
import { tankDefinitions } from '../../../../../../../core/blitzkit/tankDefinitions';
@@ -128,6 +128,7 @@ export function TechTreeSection() {
return (
<Flex
key={multiplier}
style={{
background: `url(${imgur('7hDltb4')})`,
backgroundSize: 'contain',
@@ -141,7 +142,6 @@ export function TechTreeSection() {
draft.xpMultiplier = multiplier;
});
}}
key={multiplier}
width="2.5rem"
justify="center"
align="center"
@@ -164,15 +164,15 @@ export function TechTreeSection() {
const tank = awaitedTankDefinitions[id];
return (
<>
{index > 0 && <Arrow />}
<Fragment key={id}>
{index > 0 && <Arrow key={`${id}-arrow`} />}
<Node
key={id}
key={`${id}-node`}
id={id}
nextIds={last ? tank.successors : [line[index + 1]]}
highlight={last}
/>
</>
</Fragment>
);
})}
@@ -180,14 +180,14 @@ export function TechTreeSection() {
<>
<Arrow />
{master.successors!.map((id, index) => (
<>
<Fragment key={id}>
{index > 0 && (
<Text color="gray">
<Text color="gray" key={`${id}-plus`}>
<PlusIcon />
</Text>
)}
<Node key={id} id={id} />
</>
<Node key={`${id}-node}`} id={id} />
</Fragment>
))}
</>
)}
+19 -26
View File
@@ -1,4 +1,4 @@
import { use, useMemo } from 'react';
import { useEffect, useState } from 'react';
import { TankVotes } from '../app/api/tank-voting/[id]/average/route';
import { unwrapBlitzkitResponse } from '../core/blitzkit/unwrapBlitzkitResponse';
import * as App from '../stores/app';
@@ -20,32 +20,25 @@ const cache: Record<string, Promise<TankVotes> | TankVotes> = {};
export function useTankVotes(id: number) {
const wargaming = App.use((state) => state.logins.wargaming);
const promise = useMemo(
() =>
new Promise<TankVotes>((resolve) => {
if (id in cache) {
resolve(cache[id]);
} else {
const cacheable = fetch(
`http://localhost:3000/api/tank-voting/${id}/average${
wargaming
? `?player=${wargaming.id}&token=${wargaming.token}`
: ''
}`,
)
.then(
(response) =>
response.json() as Promise<BlitzkitResponse<TankVotes>>,
)
.then(unwrapBlitzkitResponse);
cacheable.then(resolve);
const [votes, setVotes] = useState<TankVotes | null>(null);
cache[id] = cacheable;
}
}),
[id, wargaming],
);
const votes = use(promise);
useEffect(() => {
if (id in cache) {
Promise.all([cache[id]]).then(([votes]) => setVotes(votes));
} else {
const cacheable = fetch(
`/api/tank-voting/${id}/average${
wargaming ? `?player=${wargaming.id}&token=${wargaming.token}` : ''
}`,
)
.then(
(response) => response.json() as Promise<BlitzkitResponse<TankVotes>>,
)
.then(unwrapBlitzkitResponse);
cacheable.then(setVotes);
cache[id] = cacheable;
}
}, [id, wargaming]);
return votes;
}