93 lines
2.9 KiB
TypeScript
93 lines
2.9 KiB
TypeScript
import { AnimatePresence, motion } from "framer-motion";
|
|
import { useAtom } from "jotai";
|
|
import { feedItemsAtom, lootboxResultAtom } from "../../atoms";
|
|
import FeedItemElement from "./FeedItem";
|
|
import { useEffect } from "react";
|
|
import { addMessageListener, removeMessageListener } from "../../wsClient";
|
|
import type { Events } from "../../../shared/events";
|
|
import { useWSQuery } from "../../hooks";
|
|
|
|
const Feed: React.FC = () => {
|
|
const [items, setItems] = useAtom(feedItemsAtom);
|
|
const [, setLootboxResult] = useAtom(lootboxResultAtom);
|
|
const { data: user } = useWSQuery("user.getSelf", null);
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(() => {
|
|
setItems((items) => items.filter((item) => item.decay > Date.now()));
|
|
}, 1000);
|
|
return () => clearInterval(interval);
|
|
}, [setItems]);
|
|
|
|
useEffect(() => {
|
|
const listener = async (event: MessageEvent) => {
|
|
const data = JSON.parse(event.data) as Events;
|
|
const newItems = [...items];
|
|
if (data.type === "new" && data.user !== user) {
|
|
newItems.push({
|
|
type: "gameStarted",
|
|
user: data.user,
|
|
id: crypto.randomUUID(),
|
|
decay: Date.now() + 1000 * 3,
|
|
});
|
|
}
|
|
if (data.type === "loss") {
|
|
newItems.push({
|
|
type: "gameFinished",
|
|
user: data.user,
|
|
id: crypto.randomUUID(),
|
|
decay: Date.now() + 1000 * 3 + data.stage * 500,
|
|
stage: data.stage,
|
|
time: data.time,
|
|
});
|
|
}
|
|
if (data.type === "gemsRewarded" && data.gems > 0) {
|
|
newItems.push({
|
|
type: "gemsEarned",
|
|
id: crypto.randomUUID(),
|
|
decay: Date.now() + 1000 * 3 + data.gems * 500,
|
|
stage: data.stage,
|
|
gems: data.gems,
|
|
});
|
|
}
|
|
if (data.type === "lootboxPurchased" && data.user !== user) {
|
|
newItems.push({
|
|
type: "lootboxPurchased",
|
|
id: crypto.randomUUID(),
|
|
decay: Date.now() + 20_000,
|
|
lootbox: data.lootbox,
|
|
user: data.user,
|
|
reward: data.reward,
|
|
rarity: data.rarity,
|
|
});
|
|
await new Promise((res) => setTimeout(res, 2_000));
|
|
}
|
|
if (data.type === "lootboxPurchased" && data.user === user) {
|
|
setLootboxResult({
|
|
lootbox: data.lootbox,
|
|
result: data.reward,
|
|
});
|
|
}
|
|
setItems(newItems);
|
|
};
|
|
addMessageListener(listener);
|
|
return () => removeMessageListener(listener);
|
|
}, [items, setItems, setLootboxResult, user]);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-4 w-full items-start h-[30%] overflow-y-hidden">
|
|
<div className="text-white relative">
|
|
<motion.div layout>
|
|
<AnimatePresence>
|
|
{items.map((item) => (
|
|
<FeedItemElement key={item.id} item={item} />
|
|
))}
|
|
</AnimatePresence>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Feed;
|