next cursor is now extracted on client site, timestamp is now generated by postgres, LoadingWheel on fetching previous messages,

This commit is contained in:
slawk0
2024-11-13 19:13:05 +01:00
parent 3fd2ee1282
commit b7b6053120
7 changed files with 49 additions and 62 deletions

View File

@@ -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);
// }

View File

@@ -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>
);

View File

@@ -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 />);

View File

@@ -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}

View File

@@ -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,
});
}

View File

@@ -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);
}

View File

@@ -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: ", {