next cursor is now extracted on client site, timestamp is now generated by postgres, LoadingWheel on fetching previous messages,
This commit is contained in:
@@ -21,7 +21,7 @@ function messageForm({ contact }: MessaFormProps) {
|
||||
if (!data.message) {
|
||||
return;
|
||||
}
|
||||
// for (let i = 0; i < 100; i++) {
|
||||
// for (let i = 0; i <= 200; i++) {
|
||||
// let ii = i.toString();
|
||||
// sendMessage(ii, contact);
|
||||
// }
|
||||
|
||||
@@ -3,6 +3,7 @@ import { socket } from '../../socket/socket.tsx';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { UsernameType } from '../../utils/ProtectedRoutes.tsx';
|
||||
import { sendContact } from '../../api/contactsApi.tsx';
|
||||
import LoadingWheel from './LoadingWheel.tsx';
|
||||
|
||||
type ChatMessages = {
|
||||
sender: string;
|
||||
@@ -47,15 +48,17 @@ function MessagesArea({
|
||||
const { username }: UsernameType = useOutletContext();
|
||||
const prevScrollHeight = useRef(0);
|
||||
const [isFetchingHistory, setIsFetchingHistory] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const handleScroll = () => {
|
||||
const container = containerRef.current;
|
||||
if (container && container.scrollTop < 30) {
|
||||
if (container && container.scrollTop === 0) {
|
||||
setIsLoading(true);
|
||||
prevScrollHeight.current = container.scrollHeight;
|
||||
setIsFetchingHistory(true);
|
||||
fetchPreviousMessages(currentContact).catch((e) =>
|
||||
console.error('Failed to fetch messages: ', e),
|
||||
);
|
||||
fetchPreviousMessages(currentContact)
|
||||
.then(() => setIsLoading(false))
|
||||
.catch((e) => console.error('Failed to fetch messages: ', e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -127,7 +130,10 @@ function MessagesArea({
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="flex flex-col h-full overflow-y-auto">
|
||||
<ul className="flex-grow list-none">{messageList}</ul>
|
||||
<ul className="flex-grow list-none">
|
||||
{isLoading ? <LoadingWheel /> : null}
|
||||
{messageList}
|
||||
</ul>
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './index.css';
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
createRoot(document.getElementById('root')!).render(<App />);
|
||||
|
||||
@@ -64,13 +64,17 @@ function Chat() {
|
||||
const fetchMessages = async (currentContact: string | null) => {
|
||||
const messages = await getMessages(currentContact);
|
||||
console.log('Fetching messages for: ', currentContact);
|
||||
setCursor(() => {
|
||||
return Math.min(
|
||||
...messages.messages.map((message) => message.message_id),
|
||||
);
|
||||
});
|
||||
messages.messages.forEach(messageHandler);
|
||||
};
|
||||
|
||||
const fetchPreviousMessages = async (contact: string | null) => {
|
||||
const messages = await getMessages(contact, cursor, 50);
|
||||
console.log('Fetching messages for: ', contact);
|
||||
setCursor(messages.nextCursor);
|
||||
console.log('Fetching messages for: ', contact, 'with cursor: ', cursor);
|
||||
messages.messages.forEach((msg) => {
|
||||
setMessages((prevMessages) => {
|
||||
if (!prevMessages.some((m) => m.message_id === msg.message_id)) {
|
||||
@@ -79,6 +83,11 @@ function Chat() {
|
||||
return prevMessages;
|
||||
});
|
||||
});
|
||||
setCursor(() => {
|
||||
return Math.min(
|
||||
...messages.messages.map((message) => message.message_id),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
function messageHandler(msg: ChatMessages) {
|
||||
@@ -140,8 +149,6 @@ function Chat() {
|
||||
currentContact={currentContact}
|
||||
setContactStatus={setContactStatus}
|
||||
updateContactStatus={updateContactStatus}
|
||||
setCursor={setCursor}
|
||||
cursor={cursor}
|
||||
messageHandler={messageHandler}
|
||||
setContactsList={setContactsList}
|
||||
fetchPreviousMessages={fetchPreviousMessages}
|
||||
|
||||
@@ -26,26 +26,14 @@ function sendMessage(message: string, recipient: string | null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = ('0' + (now.getMonth() + 1)).slice(-2);
|
||||
const day = ('0' + now.getDate()).slice(-2);
|
||||
|
||||
const hour = ('0' + now.getHours()).slice(-2);
|
||||
const minute = ('0' + now.getMinutes()).slice(-2);
|
||||
const second = ('0' + now.getSeconds()).slice(-2);
|
||||
const timestamp = `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||||
|
||||
socket.emit('chat message', {
|
||||
message: message,
|
||||
recipient: recipient,
|
||||
timestamp: timestamp,
|
||||
});
|
||||
|
||||
console.log('sent message: ', {
|
||||
message: message,
|
||||
recipient: recipient,
|
||||
timestamp: timestamp,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ async function createTables() {
|
||||
username VARCHAR(20) NOT NULL UNIQUE,
|
||||
password VARCHAR(128) NOT NULL,
|
||||
user_id VARCHAR(128) PRIMARY KEY,
|
||||
created_at VARCHAR(100)
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
`);
|
||||
} catch (e) {
|
||||
@@ -45,8 +45,8 @@ async function createTables() {
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
sender VARCHAR(128) NOT NULL,
|
||||
recipient VARCHAR(128) NOT NULL,
|
||||
message VARCHAR(500) NOT NULL,
|
||||
timestamp TIMESTAMP NOT NULL,
|
||||
message VARCHAR(10000) NOT NULL,
|
||||
timestamp TIMESTAMPTZ DEFAULT NOW(),
|
||||
message_id SERIAL PRIMARY KEY,
|
||||
UNIQUE (sender, recipient, message_id)
|
||||
);
|
||||
@@ -73,14 +73,13 @@ async function createTables() {
|
||||
|
||||
async function insertUser(username, password) {
|
||||
const user_id = crypto.randomUUID();
|
||||
const created_at = new Date().toLocaleString("pl-PL");
|
||||
|
||||
const query = `
|
||||
INSERT INTO accounts (username, password, user_id, created_at)
|
||||
VALUES ($1, $2, $3, $4);
|
||||
INSERT INTO accounts (username, password, user_id)
|
||||
VALUES ($1, $2, $3);
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [username, password, user_id, created_at]);
|
||||
await client.query(query, [username, password, user_id]);
|
||||
} catch (e) {
|
||||
console.error("Failed to insert user ", e);
|
||||
}
|
||||
@@ -99,19 +98,14 @@ async function getUserId(username) {
|
||||
console.error("Failed to get user id", e);
|
||||
}
|
||||
}
|
||||
async function insertMessage(sender, recipient, message, timestamp) {
|
||||
async function insertMessage(sender, recipient, message) {
|
||||
const query = `
|
||||
INSERT INTO messages (sender, recipient, message, timestamp)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING message timestamp, message_id;
|
||||
INSERT INTO messages (sender, recipient, message)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING message, timestamp, message_id;
|
||||
`;
|
||||
try {
|
||||
const results = await client.query(query, [
|
||||
sender,
|
||||
recipient,
|
||||
message,
|
||||
timestamp,
|
||||
]);
|
||||
const results = await client.query(query, [sender, recipient, message]);
|
||||
return results.rows[0];
|
||||
} catch (e) {
|
||||
console.error("Failed to insert message ", e);
|
||||
@@ -130,7 +124,7 @@ async function getMessages(username, recipient, limit = 50, cursor = 0) {
|
||||
SELECT * FROM messages
|
||||
WHERE ((sender = $1 AND recipient = $2) OR (sender = $2 AND recipient = $1))
|
||||
AND message_id < $3
|
||||
ORDER BY message_id ASC
|
||||
ORDER BY message_id DESC
|
||||
LIMIT $4;
|
||||
`;
|
||||
params = [username, recipient, cursor, limit + 1];
|
||||
@@ -146,12 +140,15 @@ async function getMessages(username, recipient, limit = 50, cursor = 0) {
|
||||
|
||||
try {
|
||||
const results = await client.query(query, params);
|
||||
const messages = results.rows;
|
||||
let messages = results.rows;
|
||||
if (!cursor) {
|
||||
messages = messages.reverse();
|
||||
}
|
||||
|
||||
const nextCursor =
|
||||
messages.length > limit ? messages[limit - 2].message_id : null;
|
||||
|
||||
return { messages: messages.reverse(), nextCursor: nextCursor };
|
||||
return { messages: messages, nextCursor: nextCursor };
|
||||
} catch (e) {
|
||||
console.error("Failed to get messages ", e);
|
||||
}
|
||||
@@ -200,7 +197,6 @@ async function changePassword(username, newPassword) {
|
||||
}
|
||||
|
||||
async function insertContact(username, usernameContact, read) {
|
||||
const timestamp = getTime();
|
||||
console.log(
|
||||
`insertContact username: ${username}, usernameContact: ${usernameContact}, read: ${read}`,
|
||||
);
|
||||
@@ -212,7 +208,7 @@ async function insertContact(username, usernameContact, read) {
|
||||
DO NOTHING;
|
||||
`;
|
||||
try {
|
||||
await client.query(query, [username, usernameContact, timestamp, read]);
|
||||
await client.query(query, [username, usernameContact, read]);
|
||||
} catch (e) {
|
||||
console.error("Failed to insert contact ", e);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ function initializeSocket(io) {
|
||||
socket.join(username); // join username room
|
||||
|
||||
socket.on("chat message", async (msg) => {
|
||||
const { message, timestamp } = msg;
|
||||
const { message } = msg;
|
||||
let { recipient } = msg;
|
||||
recipient = filter(recipient);
|
||||
const sender = username;
|
||||
@@ -59,20 +59,14 @@ function initializeSocket(io) {
|
||||
return;
|
||||
}
|
||||
|
||||
const insertedMessage = await insertMessage(
|
||||
username,
|
||||
recipient,
|
||||
message,
|
||||
timestamp,
|
||||
);
|
||||
const message_id = insertedMessage.message_id;
|
||||
const insertedMessage = await insertMessage(username, recipient, message);
|
||||
const { message_id, timestamp } = insertedMessage;
|
||||
console.log("(socket) received from chat message", msg);
|
||||
|
||||
io.to(username).to(recipient).emit("chat message", {
|
||||
sender,
|
||||
message,
|
||||
recipient,
|
||||
timestamp,
|
||||
message_id,
|
||||
});
|
||||
console.log("(socket) sent on 'chat message' socket: ", {
|
||||
|
||||
Reference in New Issue
Block a user