Skip to content

Commit

Permalink
Merge branch 'main' into implement-profile-picture-Dun-sin#343
Browse files Browse the repository at this point in the history
  • Loading branch information
Dun-sin authored Nov 7, 2023
2 parents 2c3d10d + b602f92 commit 7dd8889
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 32 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

### General guidelines
- Do read the `readme.md` file
- If there's no PR for an issue in the allocated time, you will be unassigned, the following labels determine the time. `easy: 4days`, `medium: 7 days(1week)`, `hard: 2 weeks`
- If there's no PR for an issue in the allocated time, you will be unassigned, the following labels determine the time. `2days`, `4days`, `7 days(1week)`, `2 weeks`
- Fill out issue and pull request(PR) templates properly, if you don't know how, check out previous issues/PR to know how they are filled, this video👇🏾 or [this](#-how-to-fill-a-pull-request-templatetext)

#### 👌🏾 How to fill a pull request template(video)
Expand Down
1 change: 1 addition & 0 deletions client/.env_sample
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
VITE_IMPORTANT=test-d4a1c830-a65f-4c43-a871-abafcc31066d
VITE_SOCKET_URL="http://localhost:4000"
VITE_SECRET_KEY=decryption101
7 changes: 6 additions & 1 deletion client/src/components/Anonymous.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ import Chat from 'components/Chat';
import { createClassesFromArray, isExplicitDisconnection } from 'src/lib/utils';

import useKeyPress, { ShortcutFlags } from 'src/hooks/useKeyPress';
import useCheckTimePassed from 'src/hooks/useCheckTimePassed';

const centerItems = `flex items-center justify-center`;

const Anonymous = ({ onChatClosed }) => {
const { app, endSearch } = useApp();
const { currentChatId, onlineStatus } = app;
const { clearTimer } = useCheckTimePassed()

const currentChatIdRef = useRef(currentChatId);

const [isTyping, setIsTyping] = useState(false);
Expand Down Expand Up @@ -103,6 +106,8 @@ const Anonymous = ({ onChatClosed }) => {
} else {
navigate('/');
}

clearTimer()
});
};

Expand Down Expand Up @@ -295,4 +300,4 @@ export default Anonymous;

Anonymous.propTypes = {
onChatClosed: PropTypes.func,
};
};
28 changes: 10 additions & 18 deletions client/src/components/Chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,18 @@ import { createBrowserNotification } from 'src/lib/browserNotification';
import chatHelper,
{
adjustTextareaHeight,
checkPartnerResponse,
getTime
getTime,
} from '../lib/chatHelper';

import MessageSeen from './Chat/MessageSeen';
import MessageInput from './Chat/MessageInput';
import DropDownOptions from './Chat/DropDownOption';
import PreviousMessages from './Chat/PreviousMessages';
import decryptMessage from 'src/lib/decryptMessage';
import useInactiveChat from 'src/hooks/useInactiveChat';


const inactiveTimeThreshold = 180000; // 3 mins delay
let senderId;
let inactiveTimeOut;

const Chat = () => {
const { app } = useApp();
Expand All @@ -70,8 +68,6 @@ const Chat = () => {

const inputRef = useRef('');

const [lastMessageTime, setLastMessageTime] = useState(null);

senderId = authState.loginId;

const md = new MarkdownIt({
Expand Down Expand Up @@ -289,19 +285,15 @@ const Chat = () => {
};
}, []);

useEffect(() => {
const newLastMessageTime = sortedMessages
.filter((message) => message.senderId !== senderId)
.pop()?.time;
if (newLastMessageTime !== lastMessageTime) {
setLastMessageTime(newLastMessageTime);
clearTimeout(inactiveTimeOut);
inactiveTimeOut = setTimeout(() => {
checkPartnerResponse(lastMessageTime, inactiveTimeThreshold);
}, inactiveTimeThreshold);
// this is used to send the notification for inactive chat to the respective user
// get the last message sent
const getLastMessage = sortedMessages.at(-1);

const amITheSender = getLastMessage && getLastMessage.senderId === senderId

// pass it to the hook
useInactiveChat(getLastMessage, amITheSender)

}
}, [sortedMessages]);

useEffect(() => {
inputRef.current.focus()
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Chat/MessageSeen.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const MessageSeen = ({ isRead, isSender }) => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
if (entry.isIntersecting && !isSender) {
// Mark the message as read
const messageId = entry.target.getAttribute('id').split('-')[1]
try {
Expand Down
38 changes: 38 additions & 0 deletions client/src/hooks/useCheckTimePassed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEffect, useState } from 'react';

/*
* {timeInMilliseconds} is the time to track e.g 5 o'clock
* {timeToCheck} is the time to track against also in ms e.g 3 minutes
*/
export default (timeInMilliseconds, timeToCheck) => {
const [timePassed, setTimePassed] = useState(false);
const [timer, setTimer] = useState(null);

// Function to clear the timer externally
const clearTimer = () => {
clearInterval(timer);
return { timePassed: false, clearTimer };
};

useEffect(() => {
if (!timeInMilliseconds) {
return;
}

// check if the time if it's greater or equal to the `timeToCheck`
const checkTime = () => {
const currentTime = Date.now();
const timeDifference = currentTime - timeInMilliseconds;
setTimePassed(timeDifference >= timeToCheck);
};

// set the interval to state
setTimer(setInterval(checkTime, 1000));
}, [timeInMilliseconds]);

if (!timeInMilliseconds) {
return { timePassed: false, clearTimer };
}

return { timePassed, clearTimer };
};
53 changes: 53 additions & 0 deletions client/src/hooks/useInactiveChat.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useEffect, useState } from 'react';

import { createBrowserNotification } from 'src/lib/browserNotification';
import useCheckTimePassed from './useCheckTimePassed';
import { isGreaterThan3Minutes } from 'src/lib/chatHelper';

const inactiveTimeThreshold = 180000;

export default (getLastMessage, amITheSender) => {
const [lastMessageTime, setLastMessageTime] = useState(null);
const { timePassed, clearTimer } = useCheckTimePassed(lastMessageTime, inactiveTimeThreshold);


useEffect(() => {
if (
amITheSender === null
|| amITheSender === undefined
|| !getLastMessage) {
return
}

// get the time of the last message
const newMessageTime = getLastMessage.time;

// if the lastMessageTime stored in state is the same as
// the newmessagetime then we return
// if the newMessageTime is greater than 3 minutes we also return
// this is so that the hook doesn't always run on render
if (newMessageTime === lastMessageTime
|| isGreaterThan3Minutes(inactiveTimeThreshold, newMessageTime)
) {
return;
}

setLastMessageTime(newMessageTime);
}, [getLastMessage]);


useEffect(() => {
if (timePassed) {
if (amITheSender) {
createBrowserNotification('Inactive Chat', `Your Partner isn't responding, want to leave?`)
} else if (!amITheSender) {
createBrowserNotification('Inactive Chat', `You haven't replied your partner yet`)
} else {
return
}

clearTimer();
setLastMessageTime(null);
}
}, [timePassed]);
}
15 changes: 13 additions & 2 deletions client/src/lib/browserNotification.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,21 @@ export const createBrowserNotification = (title, body) => {
return;
}

const message = badwords.filter(decryptMessage(body));
if (title !== 'Inactive Chat') {
if (badwords.check(decryptMessage(body))) {
const message = badwords.filter(decryptMessage(body));
new Notification(title, {
body: message,
icon: '/favicon.ico',
});

return;
}
body = decryptMessage(body);
}

new Notification(title, {
body: message,
body,
icon: '/favicon.ico',
});
};
16 changes: 8 additions & 8 deletions client/src/lib/chatHelper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { createBrowserNotification } from 'src/lib/browserNotification';

export default (state, app) => {
const getMessage = (id) => {
if (!state[app.currentChatId]) {
Expand Down Expand Up @@ -55,7 +53,7 @@ export default (state, app) => {
});

if (!animate) {
return
return;
}

if (alreadyHighlighted) {
Expand Down Expand Up @@ -96,10 +94,12 @@ export const getTime = (time) => {
return new Date(time).toLocaleTimeString();
};

export const checkPartnerResponse = (lastMessageTime, inactiveTimeThreshold) => {
const currentTime = new Date().getTime();
const isInactive = lastMessageTime && currentTime - lastMessageTime > inactiveTimeThreshold;
if (isInactive) {
createBrowserNotification("your partner isn't responding, want to leave?");
export const isGreaterThan3Minutes = (interval, time) => {
const currentTime = Date.now();
const timeDifference = currentTime - time;

if (timeDifference > interval) {
return true;
}
return false;
};
2 changes: 1 addition & 1 deletion client/src/pages/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const Login = () => {
<button
disabled={isLoading}
onClick={loginAnonymously}
className={`dark:text-white bg-secondary h-10 px-10 font-light cursor-pointer rounded-md`}
className={`text-white bg-secondary h-10 px-10 font-light cursor-pointer rounded-md`}
>
Login Anonymously
</button>
Expand Down

0 comments on commit 7dd8889

Please sign in to comment.