fixed contacts
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import { axiosClient } from '../App.tsx';
|
||||
import { ChatMessages } from '../pages/Chat.tsx';
|
||||
type ContactsProps = {
|
||||
usernamecontact: string;
|
||||
read: boolean;
|
||||
};
|
||||
import { ContactsProps } from '../pages/Chat.tsx';
|
||||
|
||||
export async function getContactsList(): Promise<ContactsProps[]> {
|
||||
try {
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { useForm, SubmitHandler } from 'react-hook-form';
|
||||
import { sendContact } from '../../api/contactsApi.tsx';
|
||||
|
||||
import { ContactsProps } from '../../pages/Chat.tsx';
|
||||
import { axiosClient } from '../../App.tsx';
|
||||
import { AxiosResponse } from 'axios';
|
||||
type Input = {
|
||||
contact: string;
|
||||
};
|
||||
|
||||
type ContactsProps = {
|
||||
usernamecontact: string;
|
||||
read: boolean;
|
||||
};
|
||||
|
||||
type ContactFormProps = {
|
||||
InitializeContact: (contact: string) => void;
|
||||
setContactsList: React.Dispatch<React.SetStateAction<ContactsProps[]>>;
|
||||
@@ -18,19 +14,49 @@ type ContactFormProps = {
|
||||
function ContactForm({ InitializeContact, setContactsList }: ContactFormProps) {
|
||||
const { register, handleSubmit, reset } = useForm<Input>();
|
||||
|
||||
const submitContact: SubmitHandler<Input> = (data) => {
|
||||
const submitContact: SubmitHandler<Input> = async (data) => {
|
||||
const contact = data.contact.trim();
|
||||
setContactsList((prevContacts) => {
|
||||
if (!prevContacts.some((c) => c.usernamecontact === contact)) {
|
||||
sendContact(contact);
|
||||
InitializeContact(contact);
|
||||
return [...prevContacts, { usernamecontact: contact, read: true }];
|
||||
}
|
||||
return prevContacts;
|
||||
});
|
||||
|
||||
reset({ contact: '' });
|
||||
try {
|
||||
// Checks if contact username already exist on the list
|
||||
setContactsList((prevContacts) => {
|
||||
if (prevContacts.some((c) => c.contact_username === contact)) {
|
||||
return prevContacts;
|
||||
}
|
||||
return prevContacts;
|
||||
});
|
||||
|
||||
const response: AxiosResponse<{
|
||||
contact_user_id: number;
|
||||
contact_id: number;
|
||||
}> = await axiosClient.post(`/api/chat/contact/${contact}`);
|
||||
|
||||
console.log(response.data);
|
||||
const { contact_user_id, contact_id } = response.data;
|
||||
|
||||
InitializeContact(contact);
|
||||
|
||||
setContactsList((prevContacts) => {
|
||||
if (!prevContacts.some((c) => c.contact_username === contact)) {
|
||||
return [
|
||||
...prevContacts,
|
||||
{
|
||||
contact_username: contact,
|
||||
read: true,
|
||||
contact_user_id,
|
||||
contact_id,
|
||||
},
|
||||
];
|
||||
}
|
||||
return prevContacts;
|
||||
});
|
||||
|
||||
reset({ contact: '' });
|
||||
} catch (error) {
|
||||
console.error('Error adding contact:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="text-center">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useEffect } from 'react';
|
||||
import { deleteContact, getContactsList } from '../../api/contactsApi.tsx';
|
||||
import { getContactsList } from '../../api/contactsApi.tsx';
|
||||
import { ChatMessages } from '../../pages/Chat.tsx';
|
||||
import { ContactsProps } from '../../pages/Chat.tsx';
|
||||
import { axiosClient } from '../../App.tsx';
|
||||
|
||||
type ContactsListProps = {
|
||||
InitializeContact: (contact: string) => void;
|
||||
@@ -25,7 +26,9 @@ function ContactsList({
|
||||
setContactsList((prevContacts) => {
|
||||
// Check if the contact already exists in the state
|
||||
if (
|
||||
!prevContacts.some((c) => c.contact_name === contactsList.contact_name)
|
||||
!prevContacts.some(
|
||||
(c) => c.contact_username === contactsList.contact_username,
|
||||
)
|
||||
) {
|
||||
return [...prevContacts, contactsList];
|
||||
}
|
||||
@@ -45,14 +48,20 @@ function ContactsList({
|
||||
);
|
||||
}, []);
|
||||
|
||||
function removeContact(contact_username: string) {
|
||||
deleteContact(contact_username); // Remove contact from server
|
||||
async function removeContact(contact_id: number) {
|
||||
try {
|
||||
const response = await axiosClient.delete(
|
||||
`/api/chat/contacts/${contact_id}`,
|
||||
);
|
||||
console.log(response.data);
|
||||
} catch (e) {
|
||||
console.error('Failed to delete contact: ', e);
|
||||
}
|
||||
|
||||
setMessages([]);
|
||||
// Remove contact on client
|
||||
setContactsList((prevContacts) =>
|
||||
prevContacts.filter(
|
||||
(contact) => contact.contact_username !== contact_username,
|
||||
),
|
||||
prevContacts.filter((contact) => contact.contact_id !== contact_id),
|
||||
);
|
||||
}
|
||||
const sortedContacts = [...contactsList].sort((a, b) => {
|
||||
@@ -71,7 +80,9 @@ function ContactsList({
|
||||
}}
|
||||
key={contact.contact_id}
|
||||
>
|
||||
<span className="flex-shrink-0">{contact.contact_username}</span>
|
||||
<span className="flex-shrink-0">
|
||||
{contact.contact_user_id} {contact.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">
|
||||
@@ -82,7 +93,7 @@ function ContactsList({
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
removeContact(contact.contact_username);
|
||||
removeContact(contact.contact_id);
|
||||
setCurrentContact(null);
|
||||
localStorage.removeItem('contact');
|
||||
}}
|
||||
|
||||
@@ -5,22 +5,14 @@ import { sendContact } from '../../api/contactsApi.tsx';
|
||||
import LoadingWheel from './LoadingWheel.tsx';
|
||||
import { ChatMessages } from '../../pages/Chat.tsx';
|
||||
import FileBox from './FIleBox.tsx';
|
||||
|
||||
type ContactProps = {
|
||||
usernamecontact: string;
|
||||
read: boolean;
|
||||
};
|
||||
type ContactsProps = {
|
||||
usernamecontact: string;
|
||||
read: boolean;
|
||||
};
|
||||
import { ContactsProps } from '../../pages/Chat.tsx';
|
||||
|
||||
type MessagesAreaProps = {
|
||||
messages: ChatMessages[];
|
||||
setMessages: React.Dispatch<React.SetStateAction<ChatMessages[]>>;
|
||||
currentContact: string | null;
|
||||
setContactStatus: (contact: string, read: boolean) => void;
|
||||
updateContactStatus: (contact: ContactProps, read: boolean) => void;
|
||||
updateContactStatus: (contact: ContactsProps, read: boolean) => void;
|
||||
messageHandler: (msg: ChatMessages) => void;
|
||||
setContactsList: React.Dispatch<React.SetStateAction<ContactsProps[]>>;
|
||||
fetchPreviousMessages: (contact: string | null) => Promise<void>;
|
||||
@@ -70,17 +62,17 @@ function MessagesArea({
|
||||
console.log('Received message: ', msg);
|
||||
if (msg.sender !== currentContact && msg.sender !== username) {
|
||||
setContactsList((prevContacts) => {
|
||||
if (!prevContacts.some((c) => c.usernamecontact === msg.sender)) {
|
||||
if (!prevContacts.some((c) => c.contact_username === msg.sender)) {
|
||||
sendContact(msg.sender);
|
||||
return [
|
||||
...prevContacts,
|
||||
{ usernamecontact: msg.sender, read: false },
|
||||
{ contact_username: msg.sender, read: false },
|
||||
];
|
||||
}
|
||||
return prevContacts;
|
||||
});
|
||||
updateContactStatus(
|
||||
{ usernamecontact: msg.sender, read: false },
|
||||
{ contact_username: msg.sender, read: false },
|
||||
false,
|
||||
);
|
||||
console.log('changed status to false for: ', msg.sender);
|
||||
|
||||
@@ -55,7 +55,7 @@ function Chat() {
|
||||
);
|
||||
setContactsList((prevContacts) =>
|
||||
prevContacts.map((c) =>
|
||||
c.usernamecontact === newContact ? { ...c, read: true } : c,
|
||||
c.contact_username === newContact ? { ...c, read: true } : c,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -113,9 +113,9 @@ function Chat() {
|
||||
function updateContactStatus(contactObj: ContactsProps, read: boolean) {
|
||||
setContactsList((prevContacts) =>
|
||||
prevContacts.map((contact) => {
|
||||
if (contact.usernamecontact === contactObj.usernamecontact) {
|
||||
if (contact.contact_username === contactObj.contact_username) {
|
||||
if (!contactObj.read) {
|
||||
setContactStatus(contactObj.usernamecontact, read);
|
||||
setContactStatus(contactObj.contact_username, read);
|
||||
}
|
||||
return { ...contact, read: read };
|
||||
} else {
|
||||
|
||||
@@ -154,9 +154,15 @@ async function getUserId(username) {
|
||||
|
||||
async function insertMessage(sender_id, recipient_id, content, attachmentUrl) {
|
||||
const query = `
|
||||
WITH sender AS (
|
||||
SELECT user_id
|
||||
FROM Accounts
|
||||
WHERE username = $2
|
||||
)
|
||||
INSERT INTO Messages (conversation_id, sender_id, content, attachment_url)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING message_id, content, sent_at, attachment_url;
|
||||
SELECT $1, sender.user_id, $3, $4
|
||||
FROM sender
|
||||
RETURNING message_id, content, sent_at, attachment_url;
|
||||
`;
|
||||
try {
|
||||
const conversation_id = await getOrCreateConversation(
|
||||
@@ -178,15 +184,22 @@ async function insertMessage(sender_id, recipient_id, content, attachmentUrl) {
|
||||
async function getOrCreateConversation(sender_id, recipient_id) {
|
||||
// Check if a conversation between these two users already exists
|
||||
const query = `
|
||||
SELECT conversation_id FROM Conversations
|
||||
SELECT conversation_id
|
||||
FROM Conversations
|
||||
WHERE conversation_type = 'direct'
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM Memberships WHERE conversation_id = Conversations.conversation_id AND user_id = $1
|
||||
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 = $2
|
||||
SELECT 1
|
||||
FROM Memberships
|
||||
WHERE conversation_id = Conversations.conversation_id
|
||||
AND user_id = (SELECT user_id FROM Accounts WHERE username = $2)
|
||||
)
|
||||
LIMIT 1;
|
||||
LIMIT 1;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [sender_id, recipient_id]);
|
||||
@@ -215,7 +228,7 @@ async function createConversation(sender_id, recipient_id) {
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO Memberships (conversation_id, user_id)
|
||||
VALUES ($1, $2), ($1, $3);
|
||||
VALUES ($1, (SELECT user_id FROM Accounts WHERE username = $2)), ($1, $3);
|
||||
`,
|
||||
[conversation_id, sender_id, recipient_id],
|
||||
);
|
||||
@@ -347,24 +360,38 @@ async function insertContact(sender_id, receiverUsername, read) {
|
||||
`insertContact sender_id: ${sender_id}, receiverUsername: ${receiverUsername}, read: ${read}`,
|
||||
);
|
||||
|
||||
const receiver_id = await getUserId(receiverUsername);
|
||||
|
||||
const query = `
|
||||
INSERT INTO Contacts (sender_id, receiver_id, last_active, read)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT ON CONSTRAINT unique_contact
|
||||
DO NOTHING;
|
||||
WITH user_check AS (
|
||||
SELECT user_id AS receiver_id
|
||||
FROM Accounts
|
||||
WHERE username = $2
|
||||
LIMIT 1
|
||||
),
|
||||
inserted_contact AS (
|
||||
INSERT INTO Contacts (sender_id, receiver_id, last_active, read)
|
||||
SELECT $1, uc.receiver_id, $3, $4
|
||||
FROM user_check uc
|
||||
ON CONFLICT ON CONSTRAINT unique_contact
|
||||
DO NOTHING
|
||||
RETURNING contact_id, receiver_id
|
||||
)
|
||||
SELECT i.contact_id, i.receiver_id AS contact_user_id
|
||||
FROM inserted_contact i;
|
||||
`;
|
||||
|
||||
try {
|
||||
const result = await client.query(query, [
|
||||
sender_id,
|
||||
receiver_id,
|
||||
receiverUsername,
|
||||
timestamp,
|
||||
read,
|
||||
]);
|
||||
// if (result.rowCount === 0) {
|
||||
// throw new Error("Failed to insert contact");
|
||||
// }
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
return result.rows[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to insert contact ", e);
|
||||
throw e;
|
||||
@@ -380,7 +407,7 @@ async function getContacts(user_id) {
|
||||
WHEN c.sender_id = $1 THEN c.receiver_id
|
||||
ELSE c.sender_id
|
||||
END AS contact_user_id,
|
||||
a.username as contact_username, -- Added username
|
||||
a.username as contact_username,
|
||||
c.read,
|
||||
c.last_active
|
||||
FROM Contacts c
|
||||
@@ -391,7 +418,7 @@ async function getContacts(user_id) {
|
||||
END
|
||||
)
|
||||
WHERE c.sender_id = $1 OR c.receiver_id = $1
|
||||
ORDER BY c.last_active DESC; -- Added ordering
|
||||
ORDER BY c.last_active DESC;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [user_id]);
|
||||
@@ -403,18 +430,18 @@ async function getContacts(user_id) {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteContact(user_id, receiver_id) {
|
||||
async function deleteContact(user_id, contact_id) {
|
||||
const query = `
|
||||
DELETE FROM Contacts
|
||||
WHERE sender_id = $1 AND receiver_id = $2
|
||||
WHERE sender_id = $1 AND contact_id = $2
|
||||
RETURNING *;
|
||||
`;
|
||||
try {
|
||||
const result = await client.query(query, [user_id, receiver_id]);
|
||||
const result = await client.query(query, [user_id, contact_id]);
|
||||
if (result.rowCount === 0) {
|
||||
console.log("No matching contact found with:", {
|
||||
user_id,
|
||||
receiver_id,
|
||||
contact_id,
|
||||
});
|
||||
} else {
|
||||
console.log("Successfully deleted contact");
|
||||
@@ -426,8 +453,14 @@ async function deleteContact(user_id, receiver_id) {
|
||||
|
||||
async function updateContactStatus(user_id, receiver_id, read) {
|
||||
const query = `
|
||||
WITH users AS (
|
||||
SELECT
|
||||
(SELECT user_id FROM Accounts WHERE username = $2) as sender_id,
|
||||
(SELECT user_id FROM Accounts WHERE username = $3) as receiver_id
|
||||
)
|
||||
UPDATE Contacts SET read = $1
|
||||
WHERE sender_id = $2 AND receiver_id = $3;
|
||||
WHERE sender_id = (SELECT sender_id FROM users)
|
||||
AND receiver_id = (SELECT receiver_id FROM users);
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [read, user_id, receiver_id]);
|
||||
@@ -443,7 +476,8 @@ async function updateContactLastActive(user_id, receiver_id) {
|
||||
const query = `
|
||||
UPDATE Contacts
|
||||
SET last_active = $1
|
||||
WHERE sender_id = $2 AND receiver_id = $3;
|
||||
WHERE sender_id = (SELECT user_id FROM Accounts WHERE username = $2)
|
||||
AND receiver_id = (SELECT user_id FROM Accounts WHERE username = $3);
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [timestamp, user_id, receiver_id]);
|
||||
|
||||
@@ -196,22 +196,19 @@ app.get("/api/auth/validate", authorizeUser, (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
app.delete("/api/chat/contacts/:contact", authorizeUser, async (req, res) => {
|
||||
if (!req.params.contact) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "Missing usernameContact parameter" });
|
||||
}
|
||||
const usernameContact = req.params.contact;
|
||||
app.delete(
|
||||
"/api/chat/contacts/:contact_id",
|
||||
authorizeUser,
|
||||
async (req, res) => {
|
||||
if (!req.params.contact_id) {
|
||||
return res.status(400).json({ message: "Missing contact_id parameter" });
|
||||
}
|
||||
const contact_id = parseInt(req.params.contact_id);
|
||||
|
||||
// Validate username for invalid characters, length, and type
|
||||
if (!isValidUsername(usernameContact)) {
|
||||
return res.status(400).json({ message: "Invalid username provided" });
|
||||
}
|
||||
|
||||
await deleteContact(req.user.user_id, usernameContact);
|
||||
return res.status(200).json({ message: "Successfully deleted contact" });
|
||||
});
|
||||
await deleteContact(req.user.user_id, contact_id);
|
||||
return res.status(200).json({ message: "Successfully deleted contact" });
|
||||
},
|
||||
);
|
||||
|
||||
app.put("/api/chat/contacts/:contact", authorizeUser, async (req, res) => {
|
||||
if (!req.params.contact) {
|
||||
@@ -244,8 +241,8 @@ app.post("/api/chat/contact/:contact", authorizeUser, async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
await insertContact(req.user.user_id, usernameContact, true);
|
||||
return res.status(200).json({ message: "Successfully inserted contact" });
|
||||
const result = await insertContact(req.user.user_id, usernameContact, true);
|
||||
return res.status(200).json(result);
|
||||
} catch (e) {
|
||||
console.error("Failed to insert contact: ", e);
|
||||
return res.status(500).json({ message: "Failed to insert contact" });
|
||||
|
||||
Reference in New Issue
Block a user