feat: use randomized user in chat
This commit is contained in:
@@ -1,9 +1,19 @@
|
||||
class User {
|
||||
constructor(name, avatar) {
|
||||
this.name = name;
|
||||
this.avatar = avatar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ChatMessage {
|
||||
constructor(userId, message, timestamp) {
|
||||
this.userId = userId;
|
||||
static nextId = 0;
|
||||
constructor(user, message, timestamp) {
|
||||
this.id = ChatMessage.nextId++;
|
||||
this.user = user;
|
||||
this.message = message;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChatMessage;
|
||||
module.exports = { ChatMessage, User };
|
||||
@@ -1,4 +1,4 @@
|
||||
const ChatMessage = require('../models/ChatMessage');
|
||||
const { ChatMessage, User } = require('../models/ChatMessage');
|
||||
|
||||
// At the moment, this service is not used! It is only a placeholder for future development for a persistent chat.
|
||||
class ChatService {
|
||||
@@ -6,8 +6,8 @@ class ChatService {
|
||||
this.messages = [];
|
||||
}
|
||||
|
||||
addMessage(userId, message, timestamp) {
|
||||
const newChatMessage = new ChatMessage(userId, message, timestamp);
|
||||
addMessage(userName, userAvatar, message, timestamp) {
|
||||
const newChatMessage = new ChatMessage(new User(userName, userAvatar), message, timestamp);
|
||||
this.messages.push(newChatMessage);
|
||||
return newChatMessage;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ const ChatService = require('../services/ChatService');
|
||||
const ChatMessage = require('../models/ChatMessage');
|
||||
|
||||
module.exports = (io, socket) => {
|
||||
socket.on('send-message', ({ userId, message, timestamp }) => {
|
||||
socket.on('send-message', ({ userName, userAvatar, message, timestamp }) => {
|
||||
|
||||
const chatMessage = ChatService.addMessage(userId, message, timestamp);
|
||||
const chatMessage = ChatService.addMessage(userName, userAvatar, message, timestamp);
|
||||
socket.broadcast.emit('chat-message', chatMessage) // Broadcast to all clients except sender
|
||||
});
|
||||
};
|
||||
|
||||
@@ -29,8 +29,6 @@ function App() {
|
||||
.catch((error) => console.error('Error loading current channel:', error));
|
||||
|
||||
|
||||
socketService.connect();
|
||||
|
||||
console.log('Subscribing to events');
|
||||
const channelAddedListener = (channel: Channel) => {
|
||||
setChannels((prevChannels) => [...prevChannels, channel]);
|
||||
@@ -43,6 +41,8 @@ function App() {
|
||||
socketService.subscribeToEvent('channel-added', channelAddedListener);
|
||||
socketService.subscribeToEvent('channel-selected', channelSelectedListener);
|
||||
|
||||
socketService.connect();
|
||||
|
||||
return () => {
|
||||
socketService.unsubscribeFromEvent('channel-added', channelAddedListener);
|
||||
socketService.unsubscribeFromEvent('channel-selected', channelSelectedListener);
|
||||
|
||||
@@ -1,29 +1,50 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Send, MessageSquare } from 'lucide-react';
|
||||
import socketService from '../../services/SocketService';
|
||||
import { Channel, ChatMessage } from '../../types';
|
||||
import { Channel, ChatMessage, RandomUser, User } from '../../types';
|
||||
import { SendMessage } from './SendMessage';
|
||||
import { SystemMessage } from './SystemMessage';
|
||||
import { ReceivedMessage } from './ReceivedMessage';
|
||||
import apiService from '../../services/ApiService';
|
||||
|
||||
function Chat() {
|
||||
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
||||
const [newMessage, setNewMessage] = useState('');
|
||||
const [userName] = useState('You');
|
||||
const [user, setUser] = useState<User>();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
apiService
|
||||
.request<RandomUser>('/api', 'GET', 'https://randomuser.me')
|
||||
.then((randomUser) => {
|
||||
const name = randomUser.results[0].name;
|
||||
const picture = randomUser.results[0].picture;
|
||||
setUser({
|
||||
name: `${name.first} ${name.last}`,
|
||||
avatar: picture.medium,
|
||||
});
|
||||
})
|
||||
.catch((error) => console.error('Error fetching random user:', error));
|
||||
|
||||
const messageListener = (message: ChatMessage) => {
|
||||
setMessages((prevMessages) => [...prevMessages, message]);
|
||||
};
|
||||
socketService.subscribeToEvent('chat-message', messageListener);
|
||||
|
||||
const channelSelectedListener = (selectedChannel: Channel) => {
|
||||
const systemMessage = {
|
||||
message: `Switched to ${selectedChannel.name}'s stream`,
|
||||
timestamp: new Date().toISOString(),
|
||||
userId: 'System',
|
||||
};
|
||||
setMessages((prevMessages) => [...prevMessages, systemMessage]);
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{
|
||||
id: prev.length ? prev[prev.length -1].id + 1 : 1,
|
||||
user: {
|
||||
name: 'System',
|
||||
avatar: '',
|
||||
},
|
||||
message: `Switched to ${selectedChannel.name}'s stream`,
|
||||
timestamp: new Date().toISOString(),
|
||||
userId: 'System',
|
||||
}
|
||||
]);
|
||||
}
|
||||
socketService.subscribeToEvent('channel-selected', channelSelectedListener);
|
||||
|
||||
@@ -35,14 +56,15 @@ function Chat() {
|
||||
|
||||
const handleSendMessage = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!newMessage.trim()) return;
|
||||
if (!newMessage.trim() || !user) return;
|
||||
|
||||
socketService.sendMessage(userName, newMessage, new Date().toISOString());
|
||||
socketService.sendMessage(user.name, user.avatar, newMessage, new Date().toISOString());
|
||||
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{
|
||||
userId: userName,
|
||||
id: prev.length ? prev[prev.length -1].id + 1 : 1,
|
||||
user: user,
|
||||
message: newMessage,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
@@ -59,12 +81,12 @@ function Chat() {
|
||||
|
||||
<div className="h-[calc(100vh-13rem)] overflow-y-auto p-4 space-y-4 scroll-container vertical-scroll-container">
|
||||
{messages.map((msg) => {
|
||||
if(msg.userId === userName) {
|
||||
return <SendMessage msg={msg}></SendMessage>;
|
||||
} else if(msg.userId === 'System') {
|
||||
return <SystemMessage msg={msg}></SystemMessage>;
|
||||
if(msg.user.name === user?.name) {
|
||||
return <SendMessage key={msg.id} msg={msg}></SendMessage>;
|
||||
} else if(msg.user.name === 'System') {
|
||||
return <SystemMessage key={msg.id} msg={msg}></SystemMessage>;
|
||||
} else {
|
||||
return <ReceivedMessage msg={msg}></ReceivedMessage>;
|
||||
return <ReceivedMessage key={msg.id} msg={msg}></ReceivedMessage>;
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -5,11 +5,10 @@ export function ReceivedMessage({ msg }: {
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-start space-x-3 pr-10">
|
||||
{/* TODO: fetch random images */}
|
||||
<img src={`https://images.unsplash.com/photo-${Math.floor(Math.random() * 1000)}?w=64&h=64&fit=crop&crop=faces`} alt={msg.userId} className="w-8 h-8 rounded-full" />
|
||||
<img src={msg.user.avatar} alt={msg.user.name} className="w-8 h-8 rounded-full" />
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="font-medium">{msg.userId}</span>
|
||||
<span className="font-medium">{msg.user.name}</span>
|
||||
<span className="text-xs text-gray-400">
|
||||
{new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</span>
|
||||
|
||||
@@ -5,11 +5,10 @@ export function SendMessage({ msg }: {
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-start justify-end space-x-3 pl-10">
|
||||
{/* TODO: fetch random images */}
|
||||
<img src={`https://images.unsplash.com/photo-${Math.floor(Math.random() * 1000)}?w=64&h=64&fit=crop&crop=faces`} alt={msg.userId} className="w-8 h-8 rounded-full" />
|
||||
<img src={msg.user.avatar} alt={msg.user.name} className="w-8 h-8 rounded-full" />
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="font-medium">{msg.userId}</span>
|
||||
<span className="font-medium">{msg.user.name}</span>
|
||||
<span className="text-xs text-gray-400">
|
||||
{new Date(msg.timestamp).toLocaleTimeString()}
|
||||
</span>
|
||||
|
||||
@@ -10,7 +10,7 @@ const apiService = {
|
||||
* @param body - The request body (e.g. POST)
|
||||
* @returns Ein Promise with the parsed JSON response to class T
|
||||
*/
|
||||
async request<T>(path: string, method: HttpMethod = 'GET', body?: unknown): Promise<T> {
|
||||
async request<T>(path: string, method: HttpMethod = 'GET', api_url: string = API_BASE_URL, body?: unknown): Promise<T> {
|
||||
try {
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
@@ -23,7 +23,7 @@ const apiService = {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}${path}`, options);
|
||||
const response = await fetch(`${api_url}${path}`, options);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
|
||||
@@ -61,10 +61,10 @@ class SocketService {
|
||||
|
||||
|
||||
// Nachricht senden
|
||||
sendMessage(userId: string, message: string, timestamp: string) {
|
||||
sendMessage(userName: string, userAvatar: string, message: string, timestamp: string) {
|
||||
if (!this.socket) throw new Error('Socket is not connected.');
|
||||
|
||||
this.socket.emit('send-message', { userId, message, timestamp });
|
||||
this.socket.emit('send-message', { userName, userAvatar, message, timestamp });
|
||||
}
|
||||
|
||||
// Channel hinzufügen
|
||||
|
||||
@@ -4,6 +4,20 @@ export interface User {
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
export interface RandomUser {
|
||||
results: {
|
||||
name: {
|
||||
first: string;
|
||||
last: string;
|
||||
},
|
||||
picture: {
|
||||
large: string;
|
||||
medium: string;
|
||||
thumbnail: string;
|
||||
}
|
||||
}[];
|
||||
};
|
||||
|
||||
export interface Channel {
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -13,7 +27,8 @@ export interface Channel {
|
||||
}
|
||||
|
||||
export interface ChatMessage {
|
||||
userId: string;
|
||||
id: number;
|
||||
user: User;
|
||||
message: string;
|
||||
timestamp: string;
|
||||
}
|
||||
Reference in New Issue
Block a user