Commit
·
b2a31fd
1
Parent(s):
cdf301a
upload debug
Browse files
frontend/.env.development
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
NEXT_PUBLIC_SERVICES_URL = "http://192.168.1.3:8766"
|
2 |
-
NEXT_PUBLIC_RELAY_URL = "WS://192.168.1.3:8765
|
|
|
1 |
NEXT_PUBLIC_SERVICES_URL = "http://192.168.1.3:8766"
|
2 |
+
NEXT_PUBLIC_RELAY_URL = "WS://192.168.1.3:8765"
|
frontend/app/layout.js
CHANGED
@@ -6,9 +6,12 @@ import { NexusAuthWrapper } from "@components/NexusAuth";
|
|
6 |
import { ToastContainer, Flip } from 'react-toastify';
|
7 |
import { CheckCircleIcon, InformationCircleIcon, ExclamationCircleIcon } from '@heroicons/react/20/solid';
|
8 |
|
|
|
|
|
9 |
import { ToastProvider } from "@lib/ToastContext";
|
10 |
|
11 |
export default function RootLayout({ children }) {
|
|
|
12 |
|
13 |
return (
|
14 |
<html lang="en">
|
@@ -33,8 +36,10 @@ export default function RootLayout({ children }) {
|
|
33 |
}}
|
34 |
/>
|
35 |
<NexusAuthWrapper>
|
36 |
-
<
|
37 |
-
|
|
|
|
|
38 |
</NexusAuthWrapper>
|
39 |
</ToastProvider>
|
40 |
</body>
|
|
|
6 |
import { ToastContainer, Flip } from 'react-toastify';
|
7 |
import { CheckCircleIcon, InformationCircleIcon, ExclamationCircleIcon } from '@heroicons/react/20/solid';
|
8 |
|
9 |
+
import { RelayAPIProvider } from '@components/RelayAPI';
|
10 |
+
|
11 |
import { ToastProvider } from "@lib/ToastContext";
|
12 |
|
13 |
export default function RootLayout({ children }) {
|
14 |
+
const userID = localStorage.getItem('u_id');
|
15 |
|
16 |
return (
|
17 |
<html lang="en">
|
|
|
36 |
}}
|
37 |
/>
|
38 |
<NexusAuthWrapper>
|
39 |
+
<RelayAPIProvider userId={userID}>
|
40 |
+
<Sidebar />
|
41 |
+
{children}
|
42 |
+
</RelayAPIProvider>
|
43 |
</NexusAuthWrapper>
|
44 |
</ToastProvider>
|
45 |
</body>
|
frontend/app/page.js
CHANGED
@@ -1,12 +1,23 @@
|
|
1 |
'use client';
|
2 |
|
3 |
import { useState, useEffect } from 'react';
|
4 |
-
import
|
5 |
-
import
|
6 |
|
7 |
export default function ChatPage() {
|
|
|
8 |
const [me, setMe] = useState('');
|
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
useEffect(() => {
|
11 |
// Retrieve 'me' from localStorage because who doesn't like remembering things?
|
12 |
const storedMe = localStorage.getItem('me');
|
@@ -24,6 +35,9 @@ export default function ChatPage() {
|
|
24 |
<h1 style={{ color: '#4a4a4a', fontSize: '24px', marginBottom: '20px' }}>Nexus MS</h1>
|
25 |
<RecentChats/>
|
26 |
</div>
|
|
|
|
|
|
|
27 |
</div>
|
28 |
</div>
|
29 |
);
|
|
|
1 |
'use client';
|
2 |
|
3 |
import { useState, useEffect } from 'react';
|
4 |
+
import RecentChats from '@components/RecentChats';
|
5 |
+
import { useRelayAPI } from '@components/RelayAPI';
|
6 |
|
7 |
export default function ChatPage() {
|
8 |
+
const relayApi = useRelayAPI();
|
9 |
const [me, setMe] = useState('');
|
10 |
|
11 |
+
const sendNotify = ()=> {
|
12 |
+
relayApi.broadcast('NOTIFY','This is a notification')
|
13 |
+
}
|
14 |
+
const joinNotifyChannel = ()=> {
|
15 |
+
relayApi.joinChannel('NOTIFY')
|
16 |
+
}
|
17 |
+
const leaveNotifyChannel = ()=> {
|
18 |
+
relayApi.leaveChannel('NOTIFY')
|
19 |
+
}
|
20 |
+
|
21 |
useEffect(() => {
|
22 |
// Retrieve 'me' from localStorage because who doesn't like remembering things?
|
23 |
const storedMe = localStorage.getItem('me');
|
|
|
35 |
<h1 style={{ color: '#4a4a4a', fontSize: '24px', marginBottom: '20px' }}>Nexus MS</h1>
|
36 |
<RecentChats/>
|
37 |
</div>
|
38 |
+
<button onClick={joinNotifyChannel}>Join Notify</button>
|
39 |
+
<button onClick={leaveNotifyChannel}>Leave Notify</button>
|
40 |
+
<button onClick={sendNotify}>Send Notify</button>
|
41 |
</div>
|
42 |
</div>
|
43 |
);
|
frontend/app/u/[recipientusername]/page.js
CHANGED
@@ -3,18 +3,21 @@
|
|
3 |
import { useState, useEffect } from "react";
|
4 |
import { useParams, useRouter } from "next/navigation";
|
5 |
import Image from "next/image";
|
6 |
-
import NexusAuthApi from "
|
|
|
7 |
import { toast } from "react-toastify";
|
8 |
|
9 |
export default function ChatPage() {
|
10 |
const { recipientusername } = useParams();
|
11 |
const [recipient, setRecipient] = useState(null);
|
|
|
12 |
const [message, setMessage] = useState("");
|
13 |
const [chatLog, setChatLog] = useState([]);
|
14 |
|
15 |
const [me, setMe] = useState("");
|
16 |
const [recipientExists, setRecipientExists] = useState(true);
|
17 |
const router = useRouter();
|
|
|
18 |
|
19 |
useEffect(() => {
|
20 |
const fetchRecipientData = async () => {
|
@@ -29,6 +32,9 @@ export default function ChatPage() {
|
|
29 |
setRecipient(recipientusername);
|
30 |
if (response.username === recipientusername && response.is_available === false) {
|
31 |
setRecipientExists(true);
|
|
|
|
|
|
|
32 |
} else if (response.username === recipientusername && response.is_available === true) {
|
33 |
setRecipientExists(false);
|
34 |
}
|
@@ -50,9 +56,9 @@ export default function ChatPage() {
|
|
50 |
|
51 |
const handleSendMessage = () => {
|
52 |
|
53 |
-
if (recipient
|
54 |
const msgData = JSON.stringify({ recipient, message });
|
55 |
-
|
56 |
|
57 |
const newMessage = {
|
58 |
from: "You",
|
|
|
3 |
import { useState, useEffect } from "react";
|
4 |
import { useParams, useRouter } from "next/navigation";
|
5 |
import Image from "next/image";
|
6 |
+
import NexusAuthApi from "@lib/Nexus_Auth_API";
|
7 |
+
import { useRelayAPI } from "@components/RelayAPI";
|
8 |
import { toast } from "react-toastify";
|
9 |
|
10 |
export default function ChatPage() {
|
11 |
const { recipientusername } = useParams();
|
12 |
const [recipient, setRecipient] = useState(null);
|
13 |
+
const [recipientUserId, setRecipientUserId] = useState(null);
|
14 |
const [message, setMessage] = useState("");
|
15 |
const [chatLog, setChatLog] = useState([]);
|
16 |
|
17 |
const [me, setMe] = useState("");
|
18 |
const [recipientExists, setRecipientExists] = useState(true);
|
19 |
const router = useRouter();
|
20 |
+
const relayApi = useRelayAPI();
|
21 |
|
22 |
useEffect(() => {
|
23 |
const fetchRecipientData = async () => {
|
|
|
32 |
setRecipient(recipientusername);
|
33 |
if (response.username === recipientusername && response.is_available === false) {
|
34 |
setRecipientExists(true);
|
35 |
+
const userId = await NexusAuthApi.getUserId(recipientusername);
|
36 |
+
setRecipientUserId(userId);
|
37 |
+
toast.info(userId);
|
38 |
} else if (response.username === recipientusername && response.is_available === true) {
|
39 |
setRecipientExists(false);
|
40 |
}
|
|
|
56 |
|
57 |
const handleSendMessage = () => {
|
58 |
|
59 |
+
if (recipient ) {
|
60 |
const msgData = JSON.stringify({ recipient, message });
|
61 |
+
relayApi.sendToUser(recipientUserId,msgData);
|
62 |
|
63 |
const newMessage = {
|
64 |
from: "You",
|
frontend/components/NexusAuth.js
CHANGED
@@ -242,16 +242,16 @@ export const NexusAuthWrapper = ({ children }) => {
|
|
242 |
localStorage.setItem("a_l", response.data.access_level);
|
243 |
} else if (response.status === 401) {
|
244 |
// Token is invalid; clear local storage
|
245 |
-
console.
|
246 |
clearLocalStorage();
|
247 |
} else {
|
248 |
// Handle other errors (e.g., network issues)
|
249 |
-
console.
|
250 |
toast.error("Unable to validate token. Please check your connection.");
|
251 |
}
|
252 |
} catch (error) {
|
253 |
// Handle other errors (e.g., network issues)
|
254 |
-
console.
|
255 |
toast.error("Unable to validate token. Please check your connection.");
|
256 |
|
257 |
}
|
@@ -282,7 +282,7 @@ export const NexusAuthWrapper = ({ children }) => {
|
|
282 |
setIsSignup(false);
|
283 |
} catch (error) {
|
284 |
setIsLoading(false);
|
285 |
-
console.
|
286 |
toast.error("Signup failed");
|
287 |
}
|
288 |
};
|
@@ -303,7 +303,7 @@ export const NexusAuthWrapper = ({ children }) => {
|
|
303 |
setIsLoading(false);
|
304 |
} catch (error) {
|
305 |
setIsLoading(false);
|
306 |
-
console.
|
307 |
toast.error("Login failed");
|
308 |
}
|
309 |
};
|
|
|
242 |
localStorage.setItem("a_l", response.data.access_level);
|
243 |
} else if (response.status === 401) {
|
244 |
// Token is invalid; clear local storage
|
245 |
+
console.info("Token validation failed with status 401:");
|
246 |
clearLocalStorage();
|
247 |
} else {
|
248 |
// Handle other errors (e.g., network issues)
|
249 |
+
console.debug("Token validation failed due to an unexpected error:", response.data);
|
250 |
toast.error("Unable to validate token. Please check your connection.");
|
251 |
}
|
252 |
} catch (error) {
|
253 |
// Handle other errors (e.g., network issues)
|
254 |
+
console.debug("Token validation failed due to an unexpected error:", error);
|
255 |
toast.error("Unable to validate token. Please check your connection.");
|
256 |
|
257 |
}
|
|
|
282 |
setIsSignup(false);
|
283 |
} catch (error) {
|
284 |
setIsLoading(false);
|
285 |
+
console.debug("Signup failed:", error);
|
286 |
toast.error("Signup failed");
|
287 |
}
|
288 |
};
|
|
|
303 |
setIsLoading(false);
|
304 |
} catch (error) {
|
305 |
setIsLoading(false);
|
306 |
+
console.debug("Login failed:", error);
|
307 |
toast.error("Login failed");
|
308 |
}
|
309 |
};
|
frontend/components/RelayAPI.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
// RelayAPI.js - Next.js Wrapper for the WebSocket Server
|
2 |
|
3 |
import { useEffect, useState, useCallback, useRef } from "react";
|
|
|
4 |
|
5 |
const useWebSocket = (userId) => {
|
6 |
const [socket, setSocket] = useState(null);
|
@@ -9,7 +10,7 @@ const useWebSocket = (userId) => {
|
|
9 |
const reconnectInterval = useRef(null);
|
10 |
|
11 |
const connect = useCallback(() => {
|
12 |
-
const ws = new WebSocket(`${process.env.
|
13 |
|
14 |
ws.onopen = () => {
|
15 |
console.debug("WebSocket connected.");
|
@@ -21,8 +22,9 @@ const useWebSocket = (userId) => {
|
|
21 |
const data = JSON.parse(event.data);
|
22 |
console.debug("Received message:", data);
|
23 |
setMessages((prev) => [...prev, data]);
|
|
|
24 |
} catch (error) {
|
25 |
-
console.
|
26 |
}
|
27 |
};
|
28 |
|
@@ -32,7 +34,7 @@ const useWebSocket = (userId) => {
|
|
32 |
};
|
33 |
|
34 |
ws.onerror = (error) => {
|
35 |
-
console.
|
36 |
ws.close();
|
37 |
};
|
38 |
|
@@ -46,9 +48,10 @@ const useWebSocket = (userId) => {
|
|
46 |
|
47 |
return () => {
|
48 |
clearInterval(reconnectInterval.current);
|
|
|
49 |
if (socket) socket.close();
|
50 |
};
|
51 |
-
}, [connect, userId
|
52 |
|
53 |
const sendMessage = useCallback(
|
54 |
(action, channel, message, targetUserId = null) => {
|
@@ -64,7 +67,7 @@ const useWebSocket = (userId) => {
|
|
64 |
socket.send(JSON.stringify(payload));
|
65 |
console.debug("Sent message:", payload);
|
66 |
} catch (error) {
|
67 |
-
console.
|
68 |
}
|
69 |
},
|
70 |
[socket, userId]
|
@@ -75,7 +78,7 @@ const useWebSocket = (userId) => {
|
|
75 |
if (connectedChannels.has(channel)) return;
|
76 |
|
77 |
sendMessage("join", channel);
|
78 |
-
setConnectedChannels((prev) => new Set(prev
|
79 |
},
|
80 |
[sendMessage, connectedChannels]
|
81 |
);
|
|
|
1 |
// RelayAPI.js - Next.js Wrapper for the WebSocket Server
|
2 |
|
3 |
import { useEffect, useState, useCallback, useRef } from "react";
|
4 |
+
import { toast } from "react-toastify";
|
5 |
|
6 |
const useWebSocket = (userId) => {
|
7 |
const [socket, setSocket] = useState(null);
|
|
|
10 |
const reconnectInterval = useRef(null);
|
11 |
|
12 |
const connect = useCallback(() => {
|
13 |
+
const ws = new WebSocket(`${process.env.NEXT_PUBLIC_RELAY_URL}/ws?user_id=${userId}`);
|
14 |
|
15 |
ws.onopen = () => {
|
16 |
console.debug("WebSocket connected.");
|
|
|
22 |
const data = JSON.parse(event.data);
|
23 |
console.debug("Received message:", data);
|
24 |
setMessages((prev) => [...prev, data]);
|
25 |
+
console.debug(messages);
|
26 |
} catch (error) {
|
27 |
+
console.debug("Failed to parse WebSocket message:", event.data);
|
28 |
}
|
29 |
};
|
30 |
|
|
|
34 |
};
|
35 |
|
36 |
ws.onerror = (error) => {
|
37 |
+
console.debug("WebSocket error:", error);
|
38 |
ws.close();
|
39 |
};
|
40 |
|
|
|
48 |
|
49 |
return () => {
|
50 |
clearInterval(reconnectInterval.current);
|
51 |
+
setConnectedChannels(new Set());
|
52 |
if (socket) socket.close();
|
53 |
};
|
54 |
+
}, [connect, userId]);
|
55 |
|
56 |
const sendMessage = useCallback(
|
57 |
(action, channel, message, targetUserId = null) => {
|
|
|
67 |
socket.send(JSON.stringify(payload));
|
68 |
console.debug("Sent message:", payload);
|
69 |
} catch (error) {
|
70 |
+
console.debug("Failed to send WebSocket message:", error);
|
71 |
}
|
72 |
},
|
73 |
[socket, userId]
|
|
|
78 |
if (connectedChannels.has(channel)) return;
|
79 |
|
80 |
sendMessage("join", channel);
|
81 |
+
setConnectedChannels((prev) => new Set([...prev, channel]));
|
82 |
},
|
83 |
[sendMessage, connectedChannels]
|
84 |
);
|
frontend/components/Sidebar.js
CHANGED
@@ -6,6 +6,7 @@ import { useEffect, useState, useRef } from "react";
|
|
6 |
import { useRouter } from "next/navigation";
|
7 |
import Image from "next/image";
|
8 |
import logo from "@assets/logo.jpg";
|
|
|
9 |
|
10 |
export default function ChatSidebar() {
|
11 |
const pathname = usePathname();
|
@@ -17,6 +18,13 @@ export default function ChatSidebar() {
|
|
17 |
setIsCollapsed(!isCollapsed);
|
18 |
};
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
useEffect(() => {
|
21 |
const handleClickOutside = (event) => {
|
22 |
if (sidebarRef.current && !sidebarRef.current.contains(event.target)) {
|
@@ -148,11 +156,11 @@ export default function ChatSidebar() {
|
|
148 |
</Link>
|
149 |
</li>
|
150 |
<li>
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
</Link>
|
157 |
</li>
|
158 |
</ul>
|
|
|
6 |
import { useRouter } from "next/navigation";
|
7 |
import Image from "next/image";
|
8 |
import logo from "@assets/logo.jpg";
|
9 |
+
import NexusAuthApi from "@/lib/Nexus_Auth_API";
|
10 |
|
11 |
export default function ChatSidebar() {
|
12 |
const pathname = usePathname();
|
|
|
18 |
setIsCollapsed(!isCollapsed);
|
19 |
};
|
20 |
|
21 |
+
const clearLocalStorage = () => {
|
22 |
+
localStorage.removeItem("me");
|
23 |
+
localStorage.removeItem("s_tkn");
|
24 |
+
localStorage.removeItem("u_id");
|
25 |
+
localStorage.removeItem("a_l");
|
26 |
+
};
|
27 |
+
|
28 |
useEffect(() => {
|
29 |
const handleClickOutside = (event) => {
|
30 |
if (sidebarRef.current && !sidebarRef.current.contains(event.target)) {
|
|
|
156 |
</Link>
|
157 |
</li>
|
158 |
<li>
|
159 |
+
<Link href="#logout" legacyBehavior>
|
160 |
+
<a style={{ ...navLinkStyle, ...(pathname === "#logout" && activeNavLinkStyle) }} onClick={handleLogout}>
|
161 |
+
<ArrowRightStartOnRectangleIcon style={iconStyle} />
|
162 |
+
<span style={textStyle}>Logout</span>
|
163 |
+
</a>
|
164 |
</Link>
|
165 |
</li>
|
166 |
</ul>
|