Implemented state structure #19

This commit is contained in:
2025-10-15 21:20:15 +02:00
parent cc4812ef3c
commit e7293aa625
4 changed files with 27 additions and 44 deletions
+1 -3
View File
@@ -12,10 +12,8 @@ export default function DMs() {
return ( return (
<AppSidebar app={app}> <AppSidebar app={app}>
<MessageBox <MessageBox
toggleSidebar={() => app.setSidebarOpen(true)} app={app}
channelName={app.profiles[id]?.display_name || id} channelName={app.profiles[id]?.display_name || id}
userList={app.profiles}
setUserList={app.setProfiles}
messages={app.messages messages={app.messages
.filter( .filter(
(m) => (m) =>
+1 -3
View File
@@ -25,10 +25,8 @@ export default function Server() {
return ( return (
<AppSidebar app={app} server={server}> <AppSidebar app={app} server={server}>
<MessageBox <MessageBox
toggleSidebar={() => app.setSidebarOpen(true)} app={app}
channelName="General" channelName="General"
userList={app.profiles}
setUserList={app.setProfiles}
messages={app.messages messages={app.messages
.filter((m) => m.channel_id === "general") .filter((m) => m.channel_id === "general")
.toReversed()} .toReversed()}
+23 -36
View File
@@ -10,53 +10,46 @@ import {
DropdownMenuContent, DropdownMenuContent,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "./ui/dropdown-menu"; } from "./ui/dropdown-menu";
import { ChevronLeft, ChevronLeftIcon, SmilePlusIcon } from "lucide-react"; import { ChevronLeftIcon, SmilePlusIcon } from "lucide-react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useState } from "react";
import { format, isToday, isYesterday } from "date-fns"; import { format, isToday, isYesterday } from "date-fns";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import { NumberMap, StringMap } from "@/types/typeUtils";
import { UserProfile } from "@/hooks/get-user"; import { UserProfile } from "@/hooks/get-user";
import axios from "axios"; import axios from "axios";
import ProfilePicture from "./ProfilePicture"; import ProfilePicture from "./ProfilePicture";
import { ScrollArea } from "./ui/scroll-area";
import App from "@/types/app";
function MessageContainer({ function MessageContainer({ message, app }: { message: Message; app: App }) {
message,
userList,
setUserList,
}: {
message: Message;
userList: StringMap<UserProfile>;
setUserList: React.Dispatch<React.SetStateAction<NumberMap<UserProfile>>>;
}) {
useEffect(() => { useEffect(() => {
axios axios
.get("/api/profile/", { params: { id: message.from } }) .get("/api/profile/", { params: { id: message.from } })
.then((res) => .then((res) =>
setUserList((prev) => ({ app.setProfiles((prev) => ({
...prev, ...prev,
[message.from]: res.data as UserProfile, [message.from]: res.data as UserProfile,
})) }))
) )
.catch(() => {}); .catch(() => {});
}, [message.from, setUserList]); }, [message.from]);
return ( return (
<div className="flex flex-col gap-3 rounded-lg p-4 hover:bg-accent"> <div className="flex flex-col gap-3 rounded-lg p-4 hover:bg-accent">
<div className="flex gap-2"> <div className="flex gap-2">
{/* <div className="w-8 h-8 rounded-full bg-gray-400" /> */} {/* <div className="w-8 h-8 rounded-full bg-gray-400" /> */}
<ProfilePicture <ProfilePicture
url={userList[message.from]?.avatar_url} url={app.profiles[message.from]?.avatar_url}
name={String( name={String(
userList[message.from] app.profiles[message.from]
? userList[message.from].display_name ? app.profiles[message.from].display_name
: message.from : message.from
)} )}
/> />
<div className="flex flex-col flex-1"> <div className="flex flex-col flex-1">
<span className="font-bold flex gap-1 items-center"> <span className="font-bold flex gap-1 items-center">
{userList[message.from] {app.profiles[message.from]
? userList[message.from].display_name ? app.profiles[message.from].display_name
: message.from} : message.from}
<p className="text-neutral-500 text-xs"> <p className="text-neutral-500 text-xs">
@@ -139,19 +132,15 @@ function MessageContainer({
} }
export default function MessageBox({ export default function MessageBox({
messages, app,
userList,
setUserList,
sendMessage, sendMessage,
channelName, channelName,
toggleSidebar, messages,
}: { }: {
messages: Message[]; app: App;
userList: NumberMap<UserProfile>;
setUserList: React.Dispatch<React.SetStateAction<NumberMap<UserProfile>>>;
sendMessage: (m: string) => void; sendMessage: (m: string) => void;
channelName?: string; channelName?: string;
toggleSidebar: () => void; messages: Message[];
}) { }) {
const [text, setText] = useState(""); const [text, setText] = useState("");
@@ -159,22 +148,20 @@ export default function MessageBox({
<div className="h-full w-full max-h-svh flex flex-col pb-5 pl-5 gap-5"> <div className="h-full w-full max-h-svh flex flex-col pb-5 pl-5 gap-5">
{channelName && ( {channelName && (
<header className="h-12 py-4 flex items-center border-b text-sm font-semibold"> <header className="h-12 py-4 flex items-center border-b text-sm font-semibold">
<span onClick={toggleSidebar} className="cursor-pointer flex"> <span
onClick={() => app.setSidebarOpen(true)}
className="cursor-pointer flex"
>
<ChevronLeftIcon className="w-5 h-5" /> <ChevronLeftIcon className="w-5 h-5" />
{channelName} {channelName}
</span> </span>
</header> </header>
)} )}
<div className="w-full h-full flex-1 overflow-y-scroll flex gap-2 flex-col-reverse pr-5"> <ScrollArea className="w-full h-full flex-1 overflow-y-scroll flex gap-2 flex-col-reverse">
{messages.map((msg) => ( {messages.map((msg) => (
<MessageContainer <MessageContainer key={msg.id} message={msg} app={app} />
key={msg.id}
message={msg}
userList={userList}
setUserList={setUserList}
/>
))} ))}
</div> </ScrollArea>
<footer className="w-full flex gap-3 pr-5 mt-auto"> <footer className="w-full flex gap-3 pr-5 mt-auto">
<Input <Input
className="" className=""
+2 -2
View File
@@ -265,10 +265,10 @@ export default function AppSidebar({
</div> </div>
{app.sidebarOpen ? ( {app.sidebarOpen ? (
<div <div
className="w-screen h-full overflow-x-hidden" className="w-full h-full overflow-x-hidden"
onClick={() => app.setSidebarOpen(false)} onClick={() => app.setSidebarOpen(false)}
> >
<div className="overflow-x-hidden w-screen min-w-max flex-shrink-0"> <div className="overflow-x-hidden min-w-max flex-shrink-0">
{children} {children}
</div> </div>
</div> </div>