implementing groups chat - client site

This commit is contained in:
slawk0
2024-11-22 22:05:36 +01:00
parent 50c62cd853
commit eeecdbaec8
5 changed files with 116 additions and 9 deletions

View File

@@ -1,14 +1,100 @@
import { useForm, SubmitHandler } from 'react-hook-form';
import profile from '../../../assets/profile.svg';
import { createRoom } from '../../socket/socket.tsx';
import { useState } from 'react';
import LoadingWheel from './LoadingWheel.tsx';
type Contact = {
contact: string | null;
};
type Inputs = {
roomName: string;
};
function ContactProfile({ contact }: Contact) {
const [isLoading, setIsLoading] = useState<boolean>(false);
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Inputs>();
const onSubmit: SubmitHandler<Inputs> = async (data) => {
console.log('sent create room: ', data.roomName);
try {
setIsLoading(true);
const response = await createRoom(data.roomName);
if (response?.status == 'ok') {
setIsLoading(false);
console.log(`Create room status: ${response.status}`);
}
} catch (e) {
console.error('Failed to create room: ', e);
}
};
return (
<>
<div className="m-2 flex items-center">
<div className="text-center text-gray-200 flex">
<img className="w-4 mr-2 invert" src={profile} alt="profile img" />
<p>{contact ? contact : null}</p>
<div className="flex">
<div className="m-2 flex items-center">
<div className="text-center text-gray-200 flex">
<img className="w-4 mr-2 invert" src={profile} alt="profile img" />
<p>{contact ? contact : null}</p>
</div>
</div>
<div className="ml-auto">
<button
className="m-2 border p-1 rounded-md"
onClick={() =>
(
document.getElementById('my_modal_1') as HTMLDialogElement
).showModal()
}
>
create room
</button>
<dialog id="my_modal_1" className="modal">
<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 room name</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('roomName', {
required: true,
minLength: 4,
maxLength: 20,
})}
aria-invalid={errors.roomName ? 'true' : 'false'}
/>
{errors.roomName?.type === 'minLength' && (
<p className="text-gray-300">room name is too short</p>
)}
{errors.roomName?.type === 'maxLength' && (
<p className="text-gray-300">room name is too long</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 /> : 'Create'}
</button>
</div>
</div>
</dialog>
</div>
</div>
</>

View File

@@ -126,7 +126,7 @@ function MessagesArea({
}`}
key={msg.message_id || msg.tempId}
>
{msg.message_id} {msg.tempId} {msg.sender}: {msg.message}
{msg.sender}: {msg.message}
{msg.attachment_url ? (
<div className="mt-2">
{msg.attachment_url.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i) ? (

View File

@@ -25,7 +25,7 @@ export default function Signup() {
const [match, setMatch] = useState(true);
const [message, setMessage] = useState('');
const [IsLoading, setIsLoading] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const onSubmit: SubmitHandler<Inputs> = (data) => {
if (data.password !== data.sPassword) {
@@ -171,11 +171,11 @@ export default function Signup() {
)}
<div>
<button
disabled={IsLoading}
disabled={isLoading}
type="submit"
className="text-black w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
{IsLoading ? <LoadingWheel /> : 'Sign up'}
{isLoading ? <LoadingWheel /> : 'Sign up'}
</button>
</div>
<div className="text-red-400 text-sm">{message}</div>

View File

@@ -44,4 +44,19 @@ function sendMessage(message: string, recipient: string, tempId: string) {
});
}
export { initializeSocket, sendMessage, socket };
async function createRoom(
roomName: string,
): Promise<{ status: string } | undefined> {
return new Promise((resolve, reject) => {
if (!socket) {
reject('Socket not initialized');
return;
}
socket.emit('create room', roomName, (response: { status: string }) => {
resolve(response);
});
});
}
export { initializeSocket, sendMessage, createRoom, socket };

View File

@@ -3,6 +3,7 @@ const { insertMessage } = require("../db/db");
const { isValidUsername } = require("../utils/filter");
const { verifyJwtToken } = require("../auth/jwt");
const console = require("node:console");
const { callback } = require("pg/lib/native/query");
function initializeSocket(io) {
io.use((socket, next) => {
@@ -60,6 +61,11 @@ function initializeSocket(io) {
});
return;
}
socket.on("create room", async (msg, callback) => {
const { roomName } = msg;
callback({ status: "ok" });
});
socket.join(username); // join username room
socket.on("chat message", async (msg, callback) => {