As described in the question title, I have two problems here. I haven’t had much luck with solving them and I’m at the point where I decided to ask others after exhausting my resources and various attempts at refactoring.
The time keeps coming in a format like “Sun Jan 26 2025 13:59:05 GMT+0200 (Eastern European Standard Time)” and I can’t trace what makes that happen. It shouldn’t be the server, but I don’t understand what is doing this on my front-end either. My ‘formatTimeStamp’ function shows how I intend for the time to appear, depending on how much time has passed since the message.
I can submit messages to channels and they will appear in the messages panel, but they will not be there when I switch channels and then switch back. I have tried many suggestions from online and even asked AI to solve it, but I came across no solution that worked. I hope that somebody can have an answer to this and I would be ever so grateful. Thanks in advance to anybody who can solve this and don’t be afraid to ask for more context.
This is my server file:
const express = require('express');
const cors = require("cors");
const bodyParser = require('body-parser');
const app = express();
const port = 3001;
let corsOptions = {
origin: "http://localhost:3000"
};
app.use(cors(corsOptions));
// In-memory database for channels and messages
let channels = [
{ id: 1, name: 'General', messages: [] },
{ id: 2, name: 'Random', messages: [] },
{ id: 3, name: 'News', messages: [] }
];
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
app.listen(port, () => {
console.log(`nServer is running at http://localhost:${port}`);
});
// GET endpoint for querying channels
app.get('/channels', (req, res) => {
res.json(channels.map(channel => ({ id: channel.id, name: channel.name })));
});
// GET endpoint for querying channel's messages
app.get('/messages/:channel', (req, res) => {
const channelName = req.params.channel;
const channel = channels.find(c => c.name === channelName);
if (channel) {
res.json(channel.messages);
} else {
res.status(404).json({ error: 'Channel not found' });
}
});
// POST endpoint for submitting new messages to a channel
app.post('/:channel', (req, res) => {
const channelName = req.params.channel;
const channel = channels.find(c => c.name === channelName);
if (channel) {
const newMessage = { text: req.body.message, timestamp: new Date().toISOString() };
channel.messages.push(newMessage);
res.status(201).json(newMessage);
} else {
res.status(404).json({ error: 'Channel not found' });
}
});
This is my front-end file:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const App = () => {
const [channels, setChannels] = useState([]);
const [selectedChannel, setSelectedChannel] = useState(null);
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const baseURL = 'http://localhost:3001';
useEffect(() => {
// Fetch initial list of channels
axios.get(`${baseURL}/channels`)
.then(response => setChannels(response.data))
.catch(error => console.error('Error fetching channels:', error));
}, []);
useEffect(() => {
// Fetch messages when a channel is selected
if (selectedChannel) {
axios.get(`${baseURL}/messages/${selectedChannel}`)
.then(response => setMessages(response.data))
.catch(error => console.error(`Error fetching messages for ${selectedChannel}:`, error));
}
}, [selectedChannel]);
const handleChannelSelect = (channel) => {
setSelectedChannel(channel);
setNewMessage('');
};
const formatTimestamp = (timestamp) => {
const messageDate = new Date(timestamp);
console.log(timestamp);
const currentDate = new Date();
let formattedTimestamp = '';
if (messageDate.toDateString() === currentDate.toDateString()) {
formattedTimestamp = messageDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
} else {
if (messageDate.getFullYear() !== currentDate.getFullYear()) {
formattedTimestamp = messageDate.toLocaleTimeString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
} else {
if (Math.abs(currentDate - messageDate) < 7 * 24 * 60 * 60 * 1000) {
formattedTimestamp = messageDate.toLocaleTimeString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
} else {
formattedTimestamp = messageDate.toLocaleTimeString([], { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
}
}
}
return formattedTimestamp;
};
const handleNewMessageSubmit = () => {
if (newMessage) {
axios.post(`${baseURL}/${selectedChannel}`, { message: newMessage })
.then(response => setMessages([response.data, ...messages]))
.catch(error => console.error('Error submitting message:', error));
setNewMessage('');
}
};
return (
<div className="app">
<div className="navigation-panel">
<h2>Channels</h2>
<ul>
{channels.map(channel => (
<li
key={channel.id}
onClick={() => handleChannelSelect(channel.name)}
className={selectedChannel === channel.name ? 'selected' : ''}
>
{channel.name}
</li>
))}
</ul>
</div>
<div className="message-list-panel">
<h2>Messages</h2>
<ul>
{messages.map((message, index) => (
<li key={index}>
{message.text}
<span className="timestamp">{formatTimestamp(message.timestamp)}</span>
</li>
))}
</ul>
</div>
{selectedChannel && (
<div className="editor-panel">
<h2>Editor</h2>
<textarea
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
/>
<button onClick={handleNewMessageSubmit} disabled={!newMessage}>
Submit
</button>
</div>
)}
</div>
);
};
export default App;
Not sure if this matters, but for completion sake, here’s my styles too:
body {
margin: 0;
font-family: 'Roboto', sans-serif;
background-color: #f5f5f5; /* Light gray background */
color: #333; /* Dark text color */
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.app {
display: flex;
max-width: 800px;
width: 100%;
margin: 20px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.1);
}
.navigation-panel,
.message-list-panel,
.editor-panel {
flex: 1;
padding: 20px;
}
.navigation-panel {
background-color: #007bff; /* Primary blue */
color: white;
border-top-left-radius: 12px;
border-bottom-left-radius: 12px;
}
.navigation-panel h2 {
color: white;
font-size: 1.8rem; /* Larger font size for headers */
margin-bottom: 15px;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
margin-bottom: 10px;
padding: 15px;
background-color: #e1e1e1; /* Light gray background */
border-radius: 8px;
transition: background-color 0.3s ease;
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
color: #333; /* Dark text color */
font-size: 1.2rem; /* Slightly larger font size */
}
li:hover {
background-color: #d4d4d4; /* Slightly darker gray on hover */
}
.message-list-panel {
background-color: #ffffff;
border-right: 2px solid #dee2e6;
border-left: 2px solid #dee2e6;
}
.message-list-panel h2 {
color: #007bff;
font-size: 1.8rem; /* Larger font size for headers */
margin-bottom: 15px;
border-bottom: 2px solid #dee2e6;
padding-bottom: 10px;
}
ul li {
background-color: #ffffff;
border-radius: 8px;
margin-bottom: 10px;
padding: 15px;
transition: background-color 0.3s ease;
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.1);
color: #333; /* Dark text color */
font-size: 1.2rem; /* Slightly larger font size */
}
ul li:hover {
background-color: #6c757d;
}
.editor-panel {
background-color: #28a745; /* Green */
color: white;
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
}
.editor-panel h2 {
color: #218838;
font-size: 1.8rem; /* Larger font size for headers */
margin-bottom: 15px;
border-bottom: 2px solid #dee2e6;
padding-bottom: 10px;
}
textarea {
width: calc(100% - 20px);
height: 100px;
margin-bottom: 10px;
padding: 10px;
border: 1px solid #28a745;
border-radius: 5px;
outline: none;
resize: none;
font-size: 1.2rem; /* Slightly larger font size */
color: #333; /* Dark text color */
}
button {
width: 100%;
padding: 10px;
cursor: pointer;
background-color: #6c757d; /* Gray */
color: white;
border: none;
border-radius: 5px;
outline: none;
transition: background-color 0.3s ease;
font-size: 1.2rem; /* Slightly larger font size */
}
button:disabled {
background-color: #cccccc; /* Light gray for disabled state */
cursor: not-allowed;
}
.timestamp {
position: absolute;
display: flex;
font-size: 0.8rem;
color: #888; /* Timestamp color */
}
.selected {
background-color: #6c757d; /* Highlight color for the selected channel */
color: white;
}
@media (min-width: 768px) {
.app {
max-width: 1200px;
}
}