Implemented state structure #19
This commit is contained in:
@@ -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) =>
|
||||||
|
|||||||
@@ -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()}
|
||||||
|
|||||||
@@ -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=""
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user