Skip to content

Commit

Permalink
Implement favourite player ids
Browse files Browse the repository at this point in the history
  • Loading branch information
gausie committed Jul 13, 2023
1 parent b758ea9 commit 2ac9798
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 15 deletions.
Binary file modified packages/greenbox-web/public/star.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/greenbox-web/public/star_full.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/greenbox-web/public/sun.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion packages/greenbox-web/src/components/AlphaImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,17 @@ type Props = {
sourceWidth?: number;
sourceHeight?: number;
title?: string;
width?: string | number;
height?: string | number;
};

export default function AlphaImage({
src,
title,
sourceWidth = 30,
sourceHeight = sourceWidth,
width = sourceWidth,
height = sourceHeight,
}: Props) {
const [maskImage, setMaskImage] = useState({} as CSSObject);
const url = useMemo(() => `https://s3.amazonaws.com/images.kingdomofloathing.com/${src}`, [src]);
Expand Down Expand Up @@ -91,5 +95,5 @@ export default function AlphaImage({
storeMask();
}, [url, src]);

return <Image alt={title} src={url} width={sourceWidth} height={sourceHeight} sx={maskImage} />;
return <Image alt={title} src={url} width={width} height={height} sx={maskImage} />;
}
42 changes: 42 additions & 0 deletions packages/greenbox-web/src/components/FavouriteButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { IconButton } from "@chakra-ui/react";
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";

import { RootState, updateFavouritePlayerId } from "../store";

import Image from "./Image";

export function FavouriteButton() {
const playerId = useSelector((state: RootState) => state.playerId);

const favouritePlayerId = useSelector((state: RootState) => state.favouritePlayerId);

const current = favouritePlayerId === playerId;

const icon = current ? "star_full" : "star";

const title = current
? "Stop remembering this player"
: `Remember this player${
favouritePlayerId ? ` (currently your favourite is #${favouritePlayerId})` : ""
}`;

const dispatch = useDispatch();
const toggle = useCallback(
(event: React.MouseEvent) => {
event.preventDefault();
dispatch(updateFavouritePlayerId(current ? null : playerId));
},
[dispatch, current, playerId],
);

return (
<IconButton
size="xs"
onClick={toggle}
aria-label={title}
title={title}
icon={<Image height="60%" src={`/${icon}.png`} />}
/>
);
}
5 changes: 3 additions & 2 deletions packages/greenbox-web/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import SwitchButton from "./SwitchButton";

type Props = {
meta?: RawSnapshotData["meta"];
direct?: boolean;
loading?: boolean;
error?: boolean;
errorMessage?: string;
Expand All @@ -38,7 +39,7 @@ Press it if some new content is not appearing at all.
It will not collect any new information about you specifically - you still need to run the command in KoLmafia!
`;

export default function Header({ meta, loading, error, errorMessage }: Props) {
export default function Header({ meta, direct, loading, error, errorMessage }: Props) {
const dispatch = useDispatch<typeof store.dispatch>();

const forceUpdate = useCallback(() => {
Expand All @@ -56,7 +57,7 @@ export default function Header({ meta, loading, error, errorMessage }: Props) {
<Box flex={1} />
<Box textAlign="right">
{meta ? (
<MetaInfo meta={meta} />
<MetaInfo direct={direct} meta={meta} />
) : loading ? (
<Spinner />
) : error ? (
Expand Down
8 changes: 5 additions & 3 deletions packages/greenbox-web/src/components/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ import Trophies from "./Trophies";
export default function MainPage() {
const [directValue] = useQueryParam("d", StringParam);
const [playerId] = useQueryParam("u", NumberParam);
const favouritePlayerId = useSelector((state: RootState) => state.favouritePlayerId);

const dispatch = useDispatch<typeof store.dispatch>();

useEffect(() => {
if (!playerId) return;
dispatch(fetchPlayerData(playerId));
}, [playerId, dispatch]);
const id = playerId || favouritePlayerId;
if (id) dispatch(fetchPlayerData(id));
}, [playerId, dispatch, favouritePlayerId]);

useEffect(() => {
if (!directValue) return;
Expand Down Expand Up @@ -70,6 +71,7 @@ export default function MainPage() {
<Container maxWidth="1000px" width="100%">
<Accordion allowMultiple defaultIndex={[0]}>
<Header
direct={!!directValue}
meta={data?.meta}
loading={loading.playerData}
error={error.playerData}
Expand Down
18 changes: 14 additions & 4 deletions packages/greenbox-web/src/components/MetaInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Text } from "@chakra-ui/react";
import { HStack, IconButton, Text } from "@chakra-ui/react";
import { formatDistance, intlFormat } from "date-fns";
import { RawSnapshotData } from "greenbox-data";
import { useEffect, useMemo, useState } from "react";

import { FavouriteButton } from "./FavouriteButton";
import Image from "./Image";

type Props = {
meta: RawSnapshotData["meta"];
direct?: boolean;
};

export default function MetaInfo({ meta }: Props) {
export default function MetaInfo({ meta, direct }: Props) {
const [now, setNow] = useState(new Date());
const date = useMemo(() => new Date(meta.timestamp), [meta.timestamp]);
const humanDate = useMemo(
Expand All @@ -32,8 +36,14 @@ export default function MetaInfo({ meta }: Props) {

return (
<Text fontSize="large">
<span title={`r${meta.revision}`}>Snapshot</span> by{" "}
<b title={`Player #${meta.id}`}>{meta.name}</b> from <span title={humanDate}>{timeago}</span>
<HStack spacing="0.25em">
<span title={`r${meta.revision}`}>{direct ? "Private s" : "S"}napshot</span>
<span>by</span>
<b title={`Player #${meta.id}`}>{meta.name}</b>
<span>from</span>
<span title={humanDate}>{timeago}</span>
{!direct && <FavouriteButton />}
</HStack>
</Text>
);
}
16 changes: 13 additions & 3 deletions packages/greenbox-web/src/components/SwitchButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { IconButton, Image, useColorMode, useColorModeValue } from "@chakra-ui/react";
import { IconButton, useColorMode, useColorModeValue } from "@chakra-ui/react";
import { useCallback } from "react";

import Image from "./Image";

export default function SwitchButton() {
const { toggleColorMode } = useColorMode();
const next = useColorModeValue("dark", "light");
const colorIcon = useColorModeValue("moon", "star");
const colorIcon = useColorModeValue("moon", "sun");
const label = `Switch to ${next} mode`;
const toggle = useCallback(
(event: React.MouseEvent) => {
event.preventDefault();
toggleColorMode();
},
[toggleColorMode],
);

return (
<IconButton
size="xs"
onClick={toggleColorMode}
onClick={toggle}
aria-label={label}
title={label}
icon={<Image height="60%" src={`/${colorIcon}.png`} />}
Expand Down
22 changes: 20 additions & 2 deletions packages/greenbox-web/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export type EntityTypes = GreenboxState[(typeof entities)[number]];

export interface GreenboxState {
playerData: api.RawSnapshotData | null;
playerId: number | null;
favouritePlayerId: number | null;
classes: ClassDef[];
effects: EffectDef[];
familiars: FamiliarDef[];
Expand All @@ -58,6 +60,8 @@ export interface GreenboxState {
}

const initialState: GreenboxState = {
playerId: null,
favouritePlayerId: null,
playerData: null,
classes: [],
effects: [],
Expand Down Expand Up @@ -151,6 +155,8 @@ export const fetchPlayerData = createAsyncThunk("playerData/fetch", async (playe

export const loadPlayerData = createAction<string>("playerData/load");

export const updateFavouritePlayerId = createAction<number | null>("favouritePlayerId/update");

export const greenboxSlice = createSlice({
name: "greenbox",
initialState,
Expand Down Expand Up @@ -267,29 +273,41 @@ export const greenboxSlice = createSlice({
.addCase(processWikiClashes.rejected, (state) => {
state.error.wikiClashes = true;
})
.addCase(fetchPlayerData.pending, (state) => {
.addCase(fetchPlayerData.pending, (state, action) => {
state.loading.playerData = true;
})
.addCase(fetchPlayerData.fulfilled, (state, action) => {
// Set current player id
state.playerId = action.meta.arg;
// Parse and load greenbox string
const greenboxString = action.payload;
state.playerData = api.expand(greenboxString);
state.loading.playerData = false;
state.error.playerData = false;
state.errorMessage.playerData = undefined;
})
.addCase(loadPlayerData, (state, action) => {
state.playerId = null;
const greenboxString = action.payload;
state.playerData = api.expand(greenboxString);
})
.addCase(fetchPlayerData.rejected, (state, action) => {
state.loading.playerData = false;
state.error.playerData = true;
state.errorMessage.playerData = action.error.message;
})
.addCase(updateFavouritePlayerId, (state, action) => {
state.favouritePlayerId = action.payload;
});
},
});

const whitelist: (keyof GreenboxState)[] = [...entities, "wikiClashes", "sizeAtLastFetch"];
const whitelist: (keyof GreenboxState)[] = [
...entities,
"wikiClashes",
"sizeAtLastFetch",
"favouritePlayerId",
];

const persistedReducer = persistReducer(
{
Expand Down

0 comments on commit 2ac9798

Please sign in to comment.