generated from lucien/api-template
add: added replies to messages
This commit is contained in:
parent
05dd75fa74
commit
b10a472ed7
10 changed files with 607 additions and 306 deletions
|
@ -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>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue