Skip to content

Commit f085535

Browse files
committed
added reply-to-message feature
1 parent f4e4c97 commit f085535

4 files changed

Lines changed: 125 additions & 4 deletions

File tree

‎chat-app/backEnd/server.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ app.get("/getMessages", (req, res) => {
3333
});
3434

3535
app.post("/sendMessage", (req, res) => {
36-
const { message, sender } = req.body;
36+
const { message, sender, replyTo } = req.body;
3737
if (message && sender) {
3838
const timestamp = Date.now();
3939
messages.push({
@@ -43,6 +43,7 @@ app.post("/sendMessage", (req, res) => {
4343
timestamp,
4444
likes: 0,
4545
dislikes: 0,
46+
replyTo: replyTo || null,
4647
});
4748

4849
res.status(200).json({ success: true });

‎chat-app/frontEnd/index.html‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
</div>
2222

2323
<form class="chat-input-area">
24+
<div class="reply-preview hidden" id="replyPreview">
25+
<span class="reply-preview-text" id="replyPreviewText"></span>
26+
<button type="button" id="cancelReplyButton">Cancel</button>
27+
</div>
2428
<input type="text" id="messageText" placeholder="Type a message..." />
2529
<button type="submit" id="submitMessage">Send</button>
2630
</form>

‎chat-app/frontEnd/script.js‎

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,45 @@ const appServerURL = "http://localhost:3000/";
55
const currentUser = prompt("Enter your name:") || "Unknown";
66
let lastTimestamp = 0;
77
let displayedMessages = [];
8+
let replyToMessage = null;
89

910
async function setup() {
1011
await renderMessages();
1112

1213
const messageText = document.getElementById("messageText");
1314
const submitMessage = document.getElementById("submitMessage");
1415
const messagesContainer = document.querySelector(".chat-messages");
16+
const cancelReplyButton = document.getElementById("cancelReplyButton");
1517

1618
submitMessage.addEventListener("click", async (e) => {
1719
e.preventDefault();
1820
const message = messageText.value.trim();
1921
if (message) {
20-
const success = await sendMessage(message);
22+
const success = await sendMessage(message, replyToMessage?.id);
2123
if (success) {
2224
messageText.value = "";
25+
clearReplyPreview();
2326
await renderMessages();
2427
} else {
2528
alert("Failed to send message. Please try again.");
2629
}
2730
}
2831
});
2932

33+
cancelReplyButton.addEventListener("click", () => {
34+
clearReplyPreview();
35+
});
36+
3037
messagesContainer.addEventListener("click", async (e) => {
3138
const likeButton = e.target.closest(".like-button");
3239
const dislikeButton = e.target.closest(".dislike-button");
40+
const replyButton = e.target.closest(".reply-button");
41+
42+
if (replyButton) {
43+
const messageId = replyButton.dataset.id;
44+
handleReplyClick(messageId);
45+
return;
46+
}
3347

3448
if (likeButton || dislikeButton) {
3549
const button = likeButton || dislikeButton;
@@ -74,12 +88,27 @@ function appendMessages(messages) {
7488
senderName.className = "sender-name";
7589
senderName.textContent = message.sender;
7690

91+
if (message.replyTo) {
92+
const originalMessage = displayedMessages.find((m) => String(m.id) === String(message.replyTo));
93+
const replyPreview = document.createElement("div");
94+
replyPreview.className = "message-reply";
95+
replyPreview.textContent = originalMessage
96+
? `${originalMessage.sender}: ${originalMessage.message}`
97+
: "Replied to a message";
98+
div.append(replyPreview);
99+
}
100+
77101
const text = document.createElement("p");
78102
text.textContent = message.message;
79103

80104
const reactionRow = document.createElement("div");
81105
reactionRow.className = "reaction-row";
82106

107+
const replyButton = document.createElement("button");
108+
replyButton.className = "reply-button";
109+
replyButton.dataset.id = message.id;
110+
replyButton.textContent = "Reply";
111+
83112
const likeButton = document.createElement("button");
84113
likeButton.className = "reaction-button like-button";
85114
likeButton.dataset.id = message.id;
@@ -90,7 +119,11 @@ function appendMessages(messages) {
90119
dislikeButton.dataset.id = message.id;
91120
dislikeButton.textContent = `👎 ${message.dislikes || 0}`;
92121

122+
if (role === "received") {
123+
reactionRow.append(replyButton);
124+
}
93125
reactionRow.append(likeButton, dislikeButton);
126+
94127
div.append(senderName, text, reactionRow);
95128
messagesContainer.appendChild(div);
96129
});
@@ -110,12 +143,12 @@ async function fetchMessages(lastTimestamp = 0) {
110143
}
111144
}
112145

113-
async function sendMessage(message) {
146+
async function sendMessage(message, replyTo = null) {
114147
try {
115148
const response = await fetch(`${appServerURL}sendMessage`, {
116149
method: "POST",
117150
headers: { "Content-Type": "application/json" },
118-
body: JSON.stringify({ message, sender: currentUser }),
151+
body: JSON.stringify({ message, sender: currentUser, replyTo }),
119152
});
120153
const data = await response.json();
121154
return data.success;
@@ -124,6 +157,35 @@ async function sendMessage(message) {
124157
}
125158
}
126159

160+
function handleReplyClick(messageId) {
161+
const message = displayedMessages.find((m) => String(m.id) === String(messageId));
162+
if (!message) {
163+
return;
164+
}
165+
166+
replyToMessage = message;
167+
renderReplyPreview();
168+
}
169+
170+
function renderReplyPreview() {
171+
const replyPreview = document.getElementById("replyPreview");
172+
const replyPreviewText = document.getElementById("replyPreviewText");
173+
174+
if (!replyToMessage) {
175+
replyPreview.classList.add("hidden");
176+
replyPreviewText.textContent = "";
177+
return;
178+
}
179+
180+
replyPreviewText.textContent = `${replyToMessage.sender}: ${replyToMessage.message}`;
181+
replyPreview.classList.remove("hidden");
182+
}
183+
184+
function clearReplyPreview() {
185+
replyToMessage = null;
186+
renderReplyPreview();
187+
}
188+
127189
async function reactToMessage(id, reaction) {
128190
try {
129191
const response = await fetch(`${appServerURL}reactMessage`, {

‎chat-app/frontEnd/style.css‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,59 @@ body {
8888
transform: translateY(-1px);
8989
}
9090

91+
.reply-button {
92+
border: none;
93+
border-radius: 999px;
94+
padding: 7px 12px;
95+
font-size: 13px;
96+
cursor: pointer;
97+
background-color: rgba(255, 255, 255, 0.08);
98+
color: #fff;
99+
}
100+
101+
.message-reply {
102+
border-left: 3px solid rgba(255, 255, 255, 0.35);
103+
padding-left: 10px;
104+
margin-bottom: 8px;
105+
font-size: 13px;
106+
opacity: 0.9;
107+
max-height: 4.2em;
108+
overflow: hidden;
109+
white-space: nowrap;
110+
text-overflow: ellipsis;
111+
}
112+
113+
.reply-preview {
114+
display: flex;
115+
align-items: center;
116+
justify-content: space-between;
117+
gap: 10px;
118+
padding: 8px 10px;
119+
border-radius: 8px;
120+
background-color: rgba(255, 255, 255, 0.08);
121+
color: #fff;
122+
margin-bottom: 10px;
123+
}
124+
125+
.reply-preview.hidden {
126+
display: none;
127+
}
128+
129+
.reply-preview-text {
130+
flex: 1;
131+
font-size: 14px;
132+
overflow: hidden;
133+
text-overflow: ellipsis;
134+
white-space: nowrap;
135+
}
136+
137+
#cancelReplyButton {
138+
border: none;
139+
background: transparent;
140+
color: #ffbaba;
141+
cursor: pointer;
142+
}
143+
91144
.like-button {
92145
background-color: rgba(255, 255, 255, 0.12);
93146
color: #c8f0ff;
@@ -100,6 +153,7 @@ body {
100153

101154
.chat-input-area {
102155
display: flex;
156+
flex-direction: column;
103157
padding: 10px;
104158
background-color: #2a2a2a;
105159
}

0 commit comments

Comments
 (0)