diff --git a/src/app/server/[ip]/page.tsx b/src/app/server/[ip]/page.tsx index fba3c96..a9133cd 100644 --- a/src/app/server/[ip]/page.tsx +++ b/src/app/server/[ip]/page.tsx @@ -2,14 +2,13 @@ import { useEffect, useRef, useState } from "react"; import { useParams, useSearchParams } from "next/navigation"; -import MessageBox from "@/components/channel/MessageBox"; import AppLayout from "@/components/app/AppLayout"; -import { Server as ServerType } from "@/types/types"; import auth from "@/lib/auth"; import useMessages from "@/hooks/use-messages"; import useApp from "@/hooks/use-app"; import { useEffectOnceWhenReady } from "@/hooks/use-once"; import ChannelView from "@/components/channel/ChannelView"; +import { IndicatorContext } from "@/types/protocol"; export default function Server() { const { ip } = useParams<{ ip: string }>(); @@ -17,6 +16,7 @@ export default function Server() { const serverRef = useRef(null); const app = useApp(); const messageStore = useMessages(); + const [indicators, setIndicators] = useState([]); useEffectOnceWhenReady( () => { @@ -26,12 +26,44 @@ export default function Server() { wsRef: serverRef, setServer: app.setServer, messageStore: messageStore, + onIndicator: (i) => { + setIndicators((prev) => { + const combined = [...prev, { ...i }]; + const uniqueByUser = combined.reduce>( + (acc, curr) => { + const userId = curr.indicator.params.user_id; + if (!acc[userId] || curr.expires > acc[userId].expires) { + acc[userId] = curr; + } + return acc; + }, + {} + ); + + return Object.values(uniqueByUser); + }); + }, }); }, [ip, messageStore.messages], [undefined, (v) => v] ); + useEffect(() => { + const interval = setInterval(() => { + setIndicators((prev) => + prev + .map((item) => ({ + ...item, + expires: item.expires - 1, + })) + .filter((item) => item.expires > 0) + ); + }, 1000); + + return () => clearInterval(interval); + }, []); + useEffect(() => { const channelId = searchParams.get("ch"); if (channelId) { @@ -54,6 +86,7 @@ export default function Server() { )} ip={ip} serverRef={serverRef} + indicators={indicators} /> ); diff --git a/src/components/channel/ChannelView.tsx b/src/components/channel/ChannelView.tsx index ba3cc18..8f39c46 100644 --- a/src/components/channel/ChannelView.tsx +++ b/src/components/channel/ChannelView.tsx @@ -1,19 +1,22 @@ -import { Channel, Message, Server } from "@/types/types"; +import { Message } from "@/types/types"; import MessageBox from "./MessageBox"; import App from "@/types/app"; -import React, { Ref, useEffect, useRef } from "react"; +import React from "react"; import PluginChannel from "./PluginChannel"; +import { IndicatorContext } from "@/types/protocol"; export default function ChannelView({ app, messages, ip, serverRef, + indicators, }: { app: App; messages: Message[]; ip: string; serverRef: React.RefObject; + indicators: IndicatorContext[]; }) { if (!app.currentChannel) return ( @@ -27,6 +30,7 @@ export default function ChannelView({ channelName={app.currentChannel.name} messages={messages} sendRequest={(req) => serverRef.current?.send(JSON.stringify(req))} + indicators={indicators} /> ); diff --git a/src/components/channel/MessageBox.tsx b/src/components/channel/MessageBox.tsx index d22cf06..b049547 100644 --- a/src/components/channel/MessageBox.tsx +++ b/src/components/channel/MessageBox.tsx @@ -25,7 +25,7 @@ import { ContextMenuItem, ContextMenuTrigger, } from "@/components/ui/context-menu"; -import { ClientMessage } from "@/types/protocol"; +import { ClientMessage, IndicatorContext } from "@/types/protocol"; import { AnimatePresence, motion } from "framer-motion"; function MessageContainer({ @@ -213,7 +213,7 @@ function MessageInput({ onEnter: () => void; onTyping?: () => void; }) { - const TYPING_INTERVAL = 2000; + const TYPING_INTERVAL = 1000; const inputRef = useRef(null); const lastTypingSent = useRef(0); const stopTypingTimeout = useRef(null); @@ -303,12 +303,14 @@ export default function MessageBox({ channelName, channelIcon, messages, + indicators, }: { app: App; sendRequest: (req: ClientMessage) => void; channelName?: string; channelIcon?: string; messages: Message[]; + indicators: IndicatorContext[]; }) { const [text, setText] = useState(""); @@ -406,45 +408,71 @@ export default function MessageBox({
-