add: added replies to messages

This commit is contained in:
Lukian 2025-05-11 21:10:46 +02:00
parent 05dd75fa74
commit b10a472ed7
10 changed files with 607 additions and 306 deletions

View file

@ -1,14 +1,21 @@
import { Link } from "react-router-dom";
import { Message, User, Channel } from "../types";
import { Message, User, Channel, Users, Emojis } from "../types";
import { useState, createRef, useEffect } from "react";
import axios from "axios";
import "../styles/MessageComponent.css";
export default function MessageComponent({ message, user, channel, deleteMessage }: {
export default function MessageComponent({ message, user, channel }: {
message: Message;
user: User | undefined;
channel: Channel | undefined;
deleteMessage: ((messageId: number) => void) | undefined;
}) {
const [reply, setReply] = useState(false);
const token = localStorage.getItem("token");
const [replyContent, setReplyContent] = useState("");
const [searchedUsers, setSearchedUsers] = useState<Users>([]);
const [searchedEmojis, setSearchedEmojis] = useState<Emojis>([]);
const ref = createRef<HTMLInputElement>();
function getMessageArray(message: Message) {
const array = []
@ -38,6 +45,70 @@ export default function MessageComponent({ message, user, channel, deleteMessage
array.push(string)
return array.filter((word) => word !== '');
}
function handleReply(e: React.FormEvent<HTMLFormElement>, messageId: number) {
e.preventDefault();
axios
.post(`/api/messages/${messageId}/reply`, {
token: token,
message: replyContent,
})
.then(() => {
setReplyContent("");
setReply(false);
setSearchedUsers([]);
setSearchedEmojis([]);
})
.catch((err) => {
console.error(err.response.data);
});
}
function handleDelete() {
if (!window.confirm("Are you sure you want to delete this message?")) {
return;
}
axios
.post(`/api/messages/${message.id}/delete`, {
token: token,
})
.catch((err) => {
console.error(err.response.data);
});
}
useEffect(() => {
const words = replyContent.toString().split(" ");
const lastWord = words[words.length - 1];
if (lastWord && lastWord.startsWith("@")) {
const username = lastWord.slice(1);
axios
.get(`/api/searchuser?search=${username}`)
.then((res) => {
setSearchedUsers(res.data);
})
.catch((err) => {
console.error(err.response.data);
});
} else {
setSearchedUsers([]);
}
if (lastWord && lastWord.startsWith(":")) {
const emojiName = lastWord.slice(1);
axios
.get(`/api/searchemojis?search=${emojiName}`)
.then((res) => {
setSearchedEmojis(res.data);
})
.catch((err) => {
console.error(err.response.data);
});
} else {
setSearchedEmojis([]);
}
}, [replyContent]);
return (
<div key={message.id} className="message">
@ -70,13 +141,81 @@ export default function MessageComponent({ message, user, channel, deleteMessage
<img src="/le_poisson_steve.png" alt="Le poisson steve" className="fish" />
)}
</div>
{channel && deleteMessage ? (
{channel?.owner_id == user?.id || user?.admin == 1 || user?.username == message.username ? (
user?.id === message.user_id || user?.id === channel?.owner_id || user?.admin === 1) && (
<button onClick={() => {deleteMessage(message.id)}}>Delete</button>
) : (
<p>In <Link to={`/c/${message.channel_name}`}>{message.channel_name}</Link></p>
)
}
<button onClick={handleDelete}>Delete</button>
) : (
<p>In <Link to={`/c/${message.channel_name}`}>{message.channel_name}</Link></p>
)}
{channel && user && !reply && (
<button onClick={() => setReply(true)}>Reply</button>
)}
{reply && (
<form onSubmit={(e) => handleReply(e, message.id)} className="message-form">
<input
type="text"
placeholder="Message"
value={replyContent}
onChange={(e) => setReplyContent(e.target.value)}
ref={ref}
/>
<button type="submit">Send</button>
{searchedUsers.length > 0 && (
<div className="mentions">
{searchedUsers.map((user) => (
<div key={user.id} className="mention">
<Link to={`/u/${user.username}`}>{user.username}</Link>
<button
type="button"
onClick={() => {
setReplyContent(
replyContent.split(" ").slice(0, -1).join(" ") + " @" + user.username + " "
);
setSearchedUsers([]);
ref.current?.focus();
}}
>
Mention
</button>
</div>
))}
</div>
)}
{searchedEmojis.length > 0 && (
<div className="emojis">
{searchedEmojis.map((emoji) => (
<div key={emoji.id} className="search-emoji">
<img src={`/api/emojis/${emoji.name}`} alt={emoji.name} className="emojis-emoji" />
<span>:{emoji.name}:</span>
<button
type="button"
onClick={() => {
setReplyContent(
replyContent.split(" ").slice(0, -1).join(" ") + " :" + emoji.name + ": "
);
setSearchedEmojis([]);
ref.current?.focus();
}}
>
Add Emoji
</button>
</div>
))}
</div>
)}
<button onClick={() => setReply(false)}>Cancel</button>
</form>
)}
{message.has_replies == true && (
<div className="message-replies">
{message.replies.map((reply) => (
<MessageComponent message={reply} user={user} channel={channel} key={reply.id} />
))}
</div>
)}
{!channel && (
<p>in: <Link to={`/c/${message.channel_name}`}>{message.channel_name}</Link></p>
)}
</div>
);
}