Generated
+74
-5
@@ -27,6 +27,7 @@
|
||||
"@types/http-status-codes": "^1.2.0",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"axios": "^1.12.2",
|
||||
"axios-cache-interceptor": "^1.8.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -45,11 +46,12 @@
|
||||
"react-markdown": "^10.1.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1"
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"zustand": "^5.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20.19.11",
|
||||
"@types/node": "^20.19.21",
|
||||
"@types/pg": "^8.15.5",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
@@ -2321,9 +2323,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.11.tgz",
|
||||
"integrity": "sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==",
|
||||
"version": "20.19.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.21.tgz",
|
||||
"integrity": "sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
@@ -2416,6 +2418,26 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios-cache-interceptor": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-1.8.3.tgz",
|
||||
"integrity": "sha512-ifuSBoCEkVaiugg1UTjVuTdK+SjSOJ35pdv2OrzhRT3wDMr52QiayQxUqs7jd7GDsfPOjMcw3T3ek0TysbyZZw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cache-parser": "1.2.5",
|
||||
"fast-defer": "1.1.8",
|
||||
"object-code": "1.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/arthurfiorette/axios-cache-interceptor?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"axios": "^1"
|
||||
}
|
||||
},
|
||||
"node_modules/bail": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
|
||||
@@ -2426,6 +2448,12 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/cache-parser": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.5.tgz",
|
||||
"integrity": "sha512-Md/4VhAHByQ9frQ15WD6LrMNiVw9AEl/J7vWIXw+sxT6fSOpbtt6LHTp76vy8+bOESPBO94117Hm2bIjlI7XjA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
@@ -2838,6 +2866,12 @@
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-defer": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.8.tgz",
|
||||
"integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/flairup": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/flairup/-/flairup-1.0.0.tgz",
|
||||
@@ -4512,6 +4546,12 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/object-code": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/object-code/-/object-code-1.3.3.tgz",
|
||||
"integrity": "sha512-/Ds4Xd5xzrtUOJ+xJQ57iAy0BZsZltOHssnDgcZ8DOhgh41q1YJCnTPnWdWSLkNGNnxYzhYChjc5dgC9mEERCA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/parse-entities": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
|
||||
@@ -5443,6 +5483,35 @@
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
|
||||
"integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=18.0.0",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=18.0.0",
|
||||
"use-sync-external-store": ">=1.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/zwitch": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
|
||||
|
||||
+4
-2
@@ -30,6 +30,7 @@
|
||||
"@types/http-status-codes": "^1.2.0",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"axios": "^1.12.2",
|
||||
"axios-cache-interceptor": "^1.8.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
@@ -48,11 +49,12 @@
|
||||
"react-markdown": "^10.1.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1"
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"zustand": "^5.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20.19.11",
|
||||
"@types/node": "^20.19.21",
|
||||
"@types/pg": "^8.15.5",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Message } from "@/types/types";
|
||||
import { UserProfile } from "@/hooks/get-user";
|
||||
import { StringMap } from "@/types/typeUtils";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useMessages } from "@/hooks/use-messages";
|
||||
|
||||
// In this testing instance we are assuming that the target's node is localhost
|
||||
// To make this functional we need to add a settings feature to the api
|
||||
@@ -14,7 +15,8 @@ import { useParams } from "next/navigation";
|
||||
export default function DMs() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const messages = useMessages((s) => s.messages);
|
||||
const setMessages = useMessages((s) => s.setMessages);
|
||||
const [userList, setUserList] = useState<StringMap<UserProfile>>({});
|
||||
const [user, setUser] = useState<UserProfile | undefined>();
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@ import { StringMap } from "@/types/typeUtils";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import ProfilePicture from "@/components/ProfilePicture";
|
||||
import { Message } from "@/types/types";
|
||||
import { useMessages } from "@/hooks/use-messages";
|
||||
|
||||
export default function Chat() {
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const [userList, setUserList] = useState<StringMap<UserProfile>>({});
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const messages = useMessages((s) => s.messages);
|
||||
const setMessages = useMessages((s) => s.setMessages);
|
||||
|
||||
return (
|
||||
<AppSidebar
|
||||
|
||||
@@ -19,7 +19,9 @@ export default function Server() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!ip) return;
|
||||
auth(ip, wsServerRef, setServer, setMessages);
|
||||
auth(ip, wsServerRef, setServer, setMessages, (m) => {
|
||||
setMessages((prev) => [...prev, m]);
|
||||
});
|
||||
}, [ip]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -34,6 +34,7 @@ import { StringMap } from "@/types/typeUtils";
|
||||
import SettingsDialog from "./settings/SettingsDialog";
|
||||
import Link from "next/link";
|
||||
import axios from "axios";
|
||||
import { get, Response } from "@/lib/request";
|
||||
|
||||
export default function AppSidebar({
|
||||
children,
|
||||
@@ -47,7 +48,7 @@ export default function AppSidebar({
|
||||
}: Readonly<{
|
||||
wsRef: React.RefObject<WebSocket | null>;
|
||||
messages?: Message[];
|
||||
setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
|
||||
setMessages: (m: Message[]) => void;
|
||||
onNewMessage?: (msg: Message) => void;
|
||||
userList: StringMap<UserProfile>;
|
||||
setUserList: React.Dispatch<React.SetStateAction<StringMap<UserProfile>>>;
|
||||
@@ -327,15 +328,15 @@ function getUser(
|
||||
) {
|
||||
if (userList[id]) return userList[id];
|
||||
|
||||
axios
|
||||
.get(`/api/profile/?id=${id}`)
|
||||
?.then((res) => {
|
||||
console.log("Fetched user", res.data);
|
||||
const onResponse = (res: Response<UserProfile>) => {
|
||||
setUserList((prev) => {
|
||||
prev[id] = res.data as UserProfile;
|
||||
return prev;
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
get(`/api/profile/?id=${id}`, onResponse)
|
||||
?.then(onResponse)
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { ProfileSettings } from "@/types/settings";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { get } from "@/lib/request";
|
||||
|
||||
export interface UserProfile extends ProfileSettings {
|
||||
id: string;
|
||||
@@ -23,9 +23,7 @@ export default function useUser() {
|
||||
}
|
||||
|
||||
try {
|
||||
const res = (await axios.get("/api/profile")).data as UserProfile;
|
||||
|
||||
setUser(res);
|
||||
setUser((await get("/api/profile")).data);
|
||||
} catch {
|
||||
router.push("/login");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Message } from "@/types/types";
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
|
||||
interface MessageStore {
|
||||
messages: Message[];
|
||||
setMessages: (msgs: Message[]) => void;
|
||||
addMessage: (msg: Message) => void;
|
||||
clearMessages: () => void;
|
||||
}
|
||||
|
||||
export const useMessages = create<MessageStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
messages: [],
|
||||
setMessages: (msgs) => set({ messages: msgs }),
|
||||
addMessage: (msg) =>
|
||||
set((state) =>
|
||||
state.messages.some((m) => m.id === msg.id)
|
||||
? state
|
||||
: { messages: [...state.messages, msg] }
|
||||
),
|
||||
clearMessages: () => set({ messages: [] }),
|
||||
}),
|
||||
{ name: "chat-messages" }
|
||||
)
|
||||
);
|
||||
+5
-4
@@ -1,18 +1,19 @@
|
||||
import { Message, Server } from "@/types/types";
|
||||
import axios from "axios";
|
||||
import { Dispatch, RefObject, SetStateAction } from "react";
|
||||
import { get } from "./request";
|
||||
|
||||
export default async function auth(
|
||||
id: string,
|
||||
wsRef: RefObject<WebSocket | null>,
|
||||
setServer: Dispatch<SetStateAction<Server | undefined>>,
|
||||
setMessages: Dispatch<SetStateAction<Message[]>>,
|
||||
setMessages: (m: Message[]) => void,
|
||||
addMessage: (m: Message) => void,
|
||||
onNewMessage?: (m: Message) => void
|
||||
) {
|
||||
console.log("Authenticating with server id:", id);
|
||||
|
||||
const ip = ((await axios.get(`/api/server/${id}`)).data as any)
|
||||
.address as string;
|
||||
const ip = ((await get(`/api/server/${id}`)).data as any).address as string;
|
||||
|
||||
console.log("Authenticating with server at:", ip);
|
||||
const server_auth = (
|
||||
@@ -50,7 +51,7 @@ export default async function auth(
|
||||
|
||||
case "message_create":
|
||||
if (onNewMessage) onNewMessage(data.params as Message);
|
||||
setMessages((prev) => [...prev, data.params]);
|
||||
addMessage(data.params as Message);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import Axios from "axios";
|
||||
import { CacheRequestConfig, setupCache } from "axios-cache-interceptor";
|
||||
|
||||
const axiosInstance = Axios.create({});
|
||||
const axios = setupCache(axiosInstance);
|
||||
|
||||
export interface Response<T> {
|
||||
data: T;
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: { [index: string]: any };
|
||||
cached: boolean;
|
||||
}
|
||||
|
||||
export async function get<T = any, D = any>(
|
||||
url: string,
|
||||
onResponse?: (response: Response<T>) => void,
|
||||
config?: CacheRequestConfig<T, D>
|
||||
): Promise<Response<T>> {
|
||||
const response = (await axios.get<T, D>(
|
||||
url,
|
||||
config
|
||||
)) as unknown as Response<T>;
|
||||
|
||||
if (onResponse && response.cached) {
|
||||
Axios.get(url).then((response) =>
|
||||
onResponse(response as unknown as Response<T>)
|
||||
);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
Reference in New Issue
Block a user