fixed something, added AddGroupMember.tsx
This commit is contained in:
98
client/src/components/chat/AddGroupMember.tsx
Normal file
98
client/src/components/chat/AddGroupMember.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import LoadingWheel from './LoadingWheel.tsx';
|
||||
import { useRef, useState } from 'react';
|
||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||
import { axiosClient } from '../../App.tsx';
|
||||
|
||||
type Inputs = {
|
||||
username: string;
|
||||
};
|
||||
|
||||
function AddGroupMember() {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const modalRef = useRef<HTMLDialogElement | null>(null);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<Inputs>();
|
||||
|
||||
const onSubmit: SubmitHandler<Inputs> = async (data) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await axiosClient.post(`/api/chat/groups/add/`, data);
|
||||
console.log(response.data);
|
||||
if (response.data.ok) {
|
||||
setIsLoading(false);
|
||||
if (modalRef.current) {
|
||||
modalRef.current.close();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to create group: ', e);
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<button
|
||||
className="m-2 border p-1 rounded-md"
|
||||
onClick={() =>
|
||||
(
|
||||
document.getElementById('my_modal_1') as HTMLDialogElement
|
||||
).showModal()
|
||||
}
|
||||
>
|
||||
Add member
|
||||
</button>
|
||||
<dialog id="my_modal_1" className="modal" ref={modalRef}>
|
||||
<div className="modal-box bg-gray-800 text-center relative p-1">
|
||||
<div className="absolute right-2 top-2">
|
||||
<form method="dialog">
|
||||
<button className="btn btn-sm btn-circle btn-ghost">✕</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center justify-center pb-1 mt-6">
|
||||
<h3 className="text-lg mb-4">Enter username</h3>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full max-w-xs relative"
|
||||
>
|
||||
<input
|
||||
className="input input-bordered bg-green-50 w-full text-black rounded-md text-center"
|
||||
{...register('username', {
|
||||
required: true,
|
||||
minLength: 4,
|
||||
maxLength: 20,
|
||||
})}
|
||||
aria-invalid={errors.username ? 'true' : 'false'}
|
||||
/>
|
||||
{errors.username?.type === 'minLength' && (
|
||||
<p className="text-gray-300">Invalid username</p>
|
||||
)}
|
||||
{errors.username?.type === 'maxLength' && (
|
||||
<p className="text-gray-300">Invalid username</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
className="btn btn-sm bg-green-500 text-black hover:bg-green-600"
|
||||
>
|
||||
{isLoading ? <LoadingWheel /> : 'Add'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddGroupMember;
|
||||
@@ -76,7 +76,10 @@ function ContactsList({
|
||||
}}
|
||||
key={contact.conversation_id}
|
||||
>
|
||||
<span className="flex-shrink-0">{contact.username}</span>
|
||||
<span className="flex-shrink-0">
|
||||
{/*user_id: {contact.user_id}, contact id: {contact.id}, username:*/}
|
||||
{contact.username}
|
||||
</span>
|
||||
|
||||
<div className="w-4 h-4 mx-2 flex items-center justify-center mr-auto">
|
||||
<p className="text-center text-2xl text-red-200 leading-none">
|
||||
|
||||
@@ -99,13 +99,14 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
|
||||
|
||||
const tempMessage: ChatMessages = {
|
||||
sender: username,
|
||||
content: data.message.trim(),
|
||||
message: data.message.trim(),
|
||||
recipient: contact,
|
||||
message_id: 0, // Set to 0 because of key={msg.message_id || msg.tempId} in messages list
|
||||
pending: true,
|
||||
tempId: tempId,
|
||||
attachment_url: attachmentUrl || null,
|
||||
sender_id: 0,
|
||||
conversation_id: 0,
|
||||
};
|
||||
|
||||
setMessages((prevMessages) => [...prevMessages, tempMessage]); // Display as gray
|
||||
|
||||
@@ -129,7 +129,7 @@ function MessagesArea({
|
||||
}`}
|
||||
key={msg.message_id || msg.tempId}
|
||||
>
|
||||
{msg.message_id} {msg.sender}: {msg.content}
|
||||
{msg.message_id || msg.tempId} {msg.sender}: {msg.message}
|
||||
{msg.attachment_url ? (
|
||||
<div className="mt-2">
|
||||
{msg.attachment_url.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i) ? (
|
||||
|
||||
@@ -11,7 +11,7 @@ import { getMessages, setContactStatus } from '../api/contactsApi.tsx';
|
||||
|
||||
export type ChatMessages = {
|
||||
sender: string;
|
||||
content: string;
|
||||
message: string;
|
||||
recipient: string;
|
||||
message_id: number;
|
||||
tempId: string;
|
||||
|
||||
122
server/db/db.js
122
server/db/db.js
@@ -297,7 +297,7 @@ async function getMessages(user_id, receiverUsername, limit = 50, cursor = 0) {
|
||||
)
|
||||
SELECT
|
||||
m.message_id,
|
||||
m.content,
|
||||
m.content AS message,
|
||||
m.sent_at,
|
||||
m.attachment_url,
|
||||
a.username AS sender,
|
||||
@@ -341,7 +341,7 @@ async function getMessages(user_id, receiverUsername, limit = 50, cursor = 0) {
|
||||
)
|
||||
SELECT
|
||||
m.message_id,
|
||||
m.content,
|
||||
m.content AS message,
|
||||
m.sent_at,
|
||||
m.attachment_url,
|
||||
a.username AS sender,
|
||||
@@ -453,19 +453,91 @@ async function changePassword(username, newPasswordHash) {
|
||||
}
|
||||
|
||||
async function insertContact(userUsername, receiverUsername, read) {
|
||||
const query = `
|
||||
// Step 1: Get user IDs for the sender and receiver
|
||||
const senderUserId = await getUserId(userUsername);
|
||||
const receiverUserId = await getUserId(receiverUsername);
|
||||
|
||||
if (!senderUserId || !receiverUserId) {
|
||||
console.error("One or both users do not exist.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Step 2: Check if a conversation already exists between the two users
|
||||
let conversationId = await getConversationId(userUsername, receiverUsername);
|
||||
|
||||
// Step 3: If no conversation exists, create a new one
|
||||
if (!conversationId) {
|
||||
const query = `
|
||||
INSERT INTO Conversations (conversation_type)
|
||||
VALUES ('direct')
|
||||
RETURNING conversation_id;
|
||||
`;
|
||||
|
||||
try {
|
||||
const result = await client.query(query);
|
||||
conversationId = result.rows[0].conversation_id;
|
||||
|
||||
// Add both users to the new conversation
|
||||
await addMemberToGroup(conversationId, senderUserId);
|
||||
await addMemberToGroup(conversationId, receiverUserId);
|
||||
} catch (e) {
|
||||
console.error("Failed to create conversation ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Insert the contact
|
||||
const insertContactQuery = `
|
||||
INSERT INTO Contacts (user_id, contact_user_id, read, last_active)
|
||||
VALUES
|
||||
((SELECT user_id FROM Accounts WHERE username = $1),
|
||||
(SELECT user_id FROM Accounts WHERE username = $2),
|
||||
$3,
|
||||
CURRENT_TIMESTAMP)
|
||||
ON CONFLICT DO NOTHING;
|
||||
VALUES ($1, $2, $3, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT DO NOTHING
|
||||
RETURNING contact_id AS id, contact_user_id AS user_id;
|
||||
`;
|
||||
|
||||
try {
|
||||
await client.query(query, [userUsername, receiverUsername, read]);
|
||||
const result = await client.query(insertContactQuery, [
|
||||
senderUserId,
|
||||
receiverUserId,
|
||||
read,
|
||||
]);
|
||||
if (result.rows.length > 0) {
|
||||
return result.rows[0];
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error("Failed to insert contact:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get conversation ID between two users
|
||||
async function getConversationId(senderUsername, receiverUsername) {
|
||||
const query = `
|
||||
SELECT conversation_id FROM Conversations
|
||||
WHERE conversation_type = 'direct'
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM Memberships WHERE conversation_id = Conversations.conversation_id AND user_id = (SELECT user_id FROM Accounts WHERE username = $1)
|
||||
)
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM Memberships WHERE conversation_id = Conversations.conversation_id AND user_id = (SELECT user_id FROM Accounts WHERE username = $2)
|
||||
)
|
||||
LIMIT 1;
|
||||
`;
|
||||
|
||||
try {
|
||||
const result = await client.query(query, [
|
||||
senderUsername,
|
||||
receiverUsername,
|
||||
]);
|
||||
if (result.rowCount > 0) {
|
||||
return result.rows[0].conversation_id;
|
||||
} else {
|
||||
console.log("No conversation found between these users.");
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to get conversation id ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,38 +545,22 @@ async function getContacts(user_id) {
|
||||
const contactsQuery = `
|
||||
SELECT
|
||||
c.contact_id AS id,
|
||||
c.contact_user_id AS contact_user_id,
|
||||
c.contact_user_id AS user_id,
|
||||
a.username AS username,
|
||||
c.last_active,
|
||||
'direct' AS type,
|
||||
COALESCE(m.conversation_id, NULL) AS conversation_id
|
||||
'direct' AS type
|
||||
FROM Contacts c
|
||||
JOIN Accounts a ON a.user_id = c.contact_user_id
|
||||
LEFT JOIN Memberships m ON m.user_id = c.contact_user_id AND m.conversation_id = (
|
||||
SELECT conv.conversation_id
|
||||
FROM Conversations conv
|
||||
JOIN Memberships mem ON conv.conversation_id = mem.conversation_id
|
||||
WHERE mem.user_id = $1
|
||||
AND conv.conversation_type = 'direct'
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM Memberships mem2
|
||||
WHERE mem2.conversation_id = mem.conversation_id
|
||||
AND mem2.user_id = c.contact_user_id
|
||||
)
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE c.user_id = $1
|
||||
ORDER BY c.last_active DESC;
|
||||
`;
|
||||
|
||||
const groupsQuery = `
|
||||
SELECT
|
||||
m.conversation_id AS user_id,
|
||||
c.conversation_id AS id,
|
||||
c.name AS username,
|
||||
c.created_at AS last_active,
|
||||
c.conversation_type AS type,
|
||||
c.conversation_id AS conversation_id
|
||||
c.conversation_type AS type
|
||||
FROM Memberships m
|
||||
JOIN Conversations c ON m.conversation_id = c.conversation_id
|
||||
WHERE m.user_id = $1 AND c.conversation_type = 'group'
|
||||
@@ -517,8 +573,10 @@ async function getContacts(user_id) {
|
||||
|
||||
const contacts = contactsResult.rows;
|
||||
const groups = groupsResult.rows.map((group) => ({
|
||||
...group,
|
||||
contact_id: group.conversation_id, // Ensure user_id is correctly mapped
|
||||
group_id: group.id,
|
||||
username: group.username,
|
||||
last_active: group.last_active,
|
||||
type: group.type,
|
||||
}));
|
||||
|
||||
// Combine contacts and groups
|
||||
|
||||
@@ -282,7 +282,7 @@ app.get("/api/chat/messages/:contact", authorizeUser, async (req, res) => {
|
||||
return res.status(404).json({ message: "No more messages found" });
|
||||
}
|
||||
|
||||
console.log("Sent messages for: ", req.user.user_id, "messages: ", messages);
|
||||
console.log("Sent messages for: ", req.user.user_id);
|
||||
return res.status(200).json({ messages });
|
||||
});
|
||||
|
||||
@@ -303,25 +303,28 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
"/api/chat/creategroup/:groupname",
|
||||
authorizeUser,
|
||||
async (req, res) => {
|
||||
const user_id = req.user.user_id;
|
||||
const groupname = req.params.groupname;
|
||||
if (!groupname) {
|
||||
res.status(400).json({ message: "Missing groupname parameter" });
|
||||
}
|
||||
const group_id = await createGroup(user_id, groupname);
|
||||
if (!group_id) {
|
||||
return res.status(500).json({ message: "Failed to create group" });
|
||||
}
|
||||
return res.status(200).json({
|
||||
message: `Successfully created group: ${groupname}`,
|
||||
group_id: group_id,
|
||||
});
|
||||
},
|
||||
);
|
||||
app.post("/api/chat/groups/create", authorizeUser, async (req, res) => {
|
||||
const user_id = req.user.user_id;
|
||||
const groupname = req.body.groupname;
|
||||
if (!groupname) {
|
||||
res.status(400).json({ message: "Groupname not provided" });
|
||||
}
|
||||
const group_id = await createGroup(user_id, groupname);
|
||||
if (!group_id) {
|
||||
return res.status(500).json({ message: "Failed to create group" });
|
||||
}
|
||||
return res.status(200).json({
|
||||
message: `Successfully created group: ${groupname}`,
|
||||
group_id: group_id,
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/chat/groups/add", async (req, res) => {
|
||||
const username = req.body.username;
|
||||
if (!username) {
|
||||
return res.status(400).json({ message: "Username not provided" });
|
||||
}
|
||||
});
|
||||
|
||||
initializeSocket(io);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user