Skip to content

Commit

Permalink
Finish Chat
Browse files Browse the repository at this point in the history
  • Loading branch information
stefan-petrov1 committed Apr 21, 2024
1 parent c862f5c commit d63672d
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 84 deletions.
2 changes: 2 additions & 0 deletions client/src/config/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export * from './admin';
export * from './auth';
export * from './events';
export * from './files';
export * from './friends';
export * from './messages';
export * from './oAuth';
export * from './skills';
export * from './userEventStatuses';
Expand Down
8 changes: 8 additions & 0 deletions client/src/config/api/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { baseApiUrl } from './base';

const base = `${baseApiUrl}/messages`;

export const messagesPaths = Object.seal({
get: (userId: number) => `${base}/${userId}`,
send: `${base}/send`,
});
167 changes: 90 additions & 77 deletions client/src/pages/chat/Chat.tsx
Original file line number Diff line number Diff line change
@@ -1,92 +1,100 @@
import { Link } from 'react-router-dom';
import { PageEnum } from '../../types';
import { useEffect, useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import { useFetch } from 'use-http';
import Spinner from '../../components/spinner/Spinner';
import { messagesPaths, usersPaths } from '../../config/api';
import { useAuthContext } from '../../contexts/AuthContext';
import { IFullUser, IMessage, PageEnum } from '../../types';
import './Chat.css';
import ChatLeftMessage from './chat-left-message/ChatLeftMessage';
import ChatRightMessage from './chat-right-message/ChatRightMessage';

function Chat() {
const { user } = useAuthContext();
const { userId: userIdParam } = useParams();
const [messages, setMessages] = useState<IMessage[]>([]);
const [inputValue, setInputValue] = useState<string>('');

const userId = Number(userIdParam || -1);

const { get, data: messagesFetch } = useFetch<IMessage[]>(
messagesPaths.get(userId),
[]
);

const { data: userFetch, loading } = useFetch<IFullUser>(
usersPaths.getById(userId),
[]
);

const { post, response } = useFetch<IMessage>(messagesPaths.send);

const onMessageSend = async () => {
const body = {
id: 0,
content: inputValue,
sentAt: new Date(Date.now()),
senderId: user.id,
receiverId: userId,
};

const message = await post(body);

if (response.ok) {
setInputValue('');
setMessages((prev) => [...prev, message]);
}
};

useEffect(() => {
if (!messagesFetch) {
return;
}
setMessages(messagesFetch);
}, [messagesFetch]);

useEffect(() => {
const interval = setInterval(async () => {
await get();
}, 1000 * 15);

return () => clearInterval(interval);
}, []);

if (loading) {
return <Spinner />;
}

return (
<div className="d-flex flex-column justify-content-center container mt-5 custom-chatter">
<h2 className="text-center">Chat With</h2>
<Link to={PageEnum.Profile} className="mb-5">
<Link
to={PageEnum.Profile.replace(
':userId',
userFetch?.id.toString() as string
)}
className="mb-5">
<h5 className="text-primary text-center text-decoration-underline">
Sarah Anderson
{userFetch?.firstname} {userFetch?.lastname}
</h5>
</Link>
<div className="wrapper">
<div className="main">
<div className="px-2 scroll">
<div className="d-flex align-items-center">
<div className="text-left pr-1">
<img
src="https://img.icons8.com/color/40/000000/guest-female.png"
width={30}
className="img1"
/>
</div>
<div className="pr-2 pl-1">
{' '}
<span className="name">Sarah Anderson</span>
<p className="msg">
Hi Dr. Hendrikson, I haven't been falling well for past few
days.
</p>
</div>
</div>
<div className="d-flex align-items-center text-right justify-content-end ">
<div className="pr-2">
{' '}
<span className="name">Dr. Hendrikson</span>
<p className="msg">Let's jump on a video call</p>
</div>
<div>
<img
src="https://i.imgur.com/HpF4BFG.jpg"
width={30}
className="img1"
/>
</div>
</div>
<div className="d-flex align-items-center">
<div className="text-left pr-1">
<img
src="https://img.icons8.com/color/40/000000/guest-female.png"
width={30}
className="img1"
/>
</div>
<div className="pr-2 pl-1">
{' '}
<span className="name">Sarah Anderson</span>
<p className="msg">How often should i take this?</p>
</div>
</div>
<div className="d-flex align-items-center text-right justify-content-end ">
<div className="pr-2">
{' '}
<span className="name">Dr. Hendrikson</span>
<p className="msg">Twice a day, at breakfast and before bed</p>
</div>
<div>
<img
src="https://i.imgur.com/HpF4BFG.jpg"
width={30}
className="img1"
/>
</div>
</div>
<div className="d-flex align-items-center">
<div className="text-left pr-1">
<img
src="https://img.icons8.com/color/40/000000/guest-female.png"
width={30}
className="img1"
{messages.map((x) => {
if (x.senderId.id === user.id) {
return <ChatRightMessage message={x.content} key={x.id} />;
}

const fullName = `${x.senderId.firstname} ${x.senderId.lastname}`;
return (
<ChatLeftMessage
content={x.content}
senderFullName={fullName}
key={x.id}
/>
</div>
<div className="pr-2 pl-1">
{' '}
<span className="name">Sarah Anderson</span>
<p className="msg">How often should i take this?</p>
</div>
</div>
);
})}
</div>
<nav className="navbar bg-white navbar-expand-sm d-flex justify-content-between">
{' '}
Expand All @@ -95,10 +103,15 @@ function Chat() {
name="text"
className="form-control"
placeholder="Type a message..."
value={inputValue}
onChange={(e) => setInputValue(e.currentTarget.value)}
/>
<div className="icondiv d-flex justify-content-end align-content-center text-center ml-2">
{' '}
<i className="fa fa-arrow-circle-right icon2 text-primary" />{' '}
<i
className="fa fa-arrow-circle-right icon2 text-primary"
onClick={onMessageSend}
/>{' '}
</div>
</nav>
</div>
Expand Down
25 changes: 25 additions & 0 deletions client/src/pages/chat/chat-left-message/ChatLeftMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
interface ChatLeftMessageProps {
content: string;
senderFullName: string;
}

function ChatLeftMessage(props: ChatLeftMessageProps) {
return (
<div className="d-flex align-items-center">
<div className="text-left pr-1">
<img
src="https://img.icons8.com/color/40/000000/guest-female.png"
width={30}
className="img1"
/>
</div>
<div className="pr-2 pl-1">
{' '}
<span className="name">{props.senderFullName}</span>
<p className="msg">{props.content}</p>
</div>
</div>
);
}

export default ChatLeftMessage;
24 changes: 24 additions & 0 deletions client/src/pages/chat/chat-right-message/ChatRightMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
interface ChatRightMessageProps {
message: string;
}

function ChatRightMessage({ message }: ChatRightMessageProps) {
return (
<div className="d-flex align-items-center text-right justify-content-end ">
<div className="pr-2">
{' '}
<span className="name">You</span>
<p className="msg">{message}</p>
</div>
<div>
<img
src="https://i.imgur.com/HpF4BFG.jpg"
width={30}
className="img1"
/>
</div>
</div>
);
}

export default ChatRightMessage;
11 changes: 8 additions & 3 deletions client/src/pages/profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState } from 'react';
import { useParams } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
import { useFetch } from 'use-http';
import Spinner from '../../components/spinner/Spinner';
import { usersPaths } from '../../config/api';
import { friendsPaths } from '../../config/api/friends';
import { useAuthContext } from '../../contexts/AuthContext';
import { IFullUser, IUserFriend } from '../../types';
import { IFullUser, IUserFriend, PageEnum } from '../../types';
import './Profile.scss';
import ProfileFriendRequests from './profile-friend-requests/ProfileFriendRequests';
import ProfileFriends from './profile-friends/ProfileFriends';
Expand Down Expand Up @@ -109,7 +109,12 @@ function Profile() {
Add Friend
</button>
)}
<button className="btn btn-outline-primary">Message</button>
<Link
to={PageEnum.Chat.replace(':userId', user.id.toString())}>
<button className="btn btn-outline-primary">
Message
</button>
</Link>
</div>
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion client/src/types/enums/PageEnum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export enum PageEnum {
Logout = '/logout',
Profile = '/profile/:userId',
Admin = '/admin',
Chat = '/chat',
Chat = '/chat/:userId',
}
2 changes: 2 additions & 0 deletions client/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ export * from './interfaces/auth/IUser';
export * from './interfaces/profile/IUserFriend';
// - skills
export * from './interfaces/skills/ISkill';
// - chat
export * from './interfaces/chat/IMessage';
9 changes: 9 additions & 0 deletions client/src/types/interfaces/chat/IMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IFullUser } from '../auth/IFullUser';
import { IObjectWithId } from '../common/IObjectWithId';

export interface IMessage extends IObjectWithId {
content: string;
sentAt: Date;
senderId: IFullUser;
receiverId: IFullUser;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ public Message sendMessage(MessageDTO message, PublicUserDTO loggedUser) {
message.setSentAt(LocalDateTime.now());

Message savedMessage = modelMapper.map(message, Message.class);
messagesRepository.save(savedMessage);

return savedMessage;
return messagesRepository.save(savedMessage);
}
}

0 comments on commit d63672d

Please sign in to comment.