diff --git a/src/reducer/appReducer.ts b/src/reducer/appReducer.ts
index 5a206494..9131cb97 100644
--- a/src/reducer/appReducer.ts
+++ b/src/reducer/appReducer.ts
@@ -11,6 +11,7 @@ export const initialState: AppType = {
currentChatId: null,
isSearching: false,
onlineStatus: null,
+ disconnected: false,
};
export default function appReducer(state: AppType, action: any) {
@@ -53,6 +54,12 @@ export default function appReducer(state: AppType, action: any) {
break;
}
+ case 'DISCONNECTED': {
+ const { disconnected } = action.payload;
+
+ clonedState.disconnected = disconnected;
+ break;
+ }
default:
throw new Error('No action provided!');
}
diff --git a/src/reducer/chatReducer.ts b/src/reducer/chatReducer.ts
index 40801ffe..8114d31e 100644
--- a/src/reducer/chatReducer.ts
+++ b/src/reducer/chatReducer.ts
@@ -18,7 +18,6 @@ export const initialState: ChatIdType = {};
export default function chatReducer(state: ChatIdType, action: any) {
const clonedState = cloneState(state);
-
switch (action.type) {
case 'CREATE_CHAT': {
const {
@@ -28,6 +27,7 @@ export default function chatReducer(state: ChatIdType, action: any) {
createdAt = new Date(),
} = action.payload;
+ console.log('context', { chatId, userIds });
clonedState[chatId] = {
userIds,
messages,
@@ -61,7 +61,7 @@ export default function chatReducer(state: ChatIdType, action: any) {
status,
containsBadword,
replyTo,
- } = action.payload;
+ } = action.payload || {};
if (!clonedState[room]) {
throw new Error('Room not found!');
@@ -157,7 +157,8 @@ export default function chatReducer(state: ChatIdType, action: any) {
break;
}
default:
- throw new Error('No action provided!');
+ console.warn('Unhandled action type:', action.type);
+ return clonedState;
}
// Save auth state to localStorage on each change
diff --git a/src/service/mailService.ts b/src/service/mailService.ts
new file mode 100644
index 00000000..73df8375
--- /dev/null
+++ b/src/service/mailService.ts
@@ -0,0 +1,29 @@
+import nodemailer from 'nodemailer';
+
+const sendMail = async (subject: string, toEmail: string, otpText: string) => {
+ const transporter = nodemailer.createTransport({
+ service: 'gmail',
+ auth: {
+ user: process.env.NODEMAILER_EMAIL,
+ pass: process.env.NODEMAILER_PW,
+ },
+ });
+
+ const mailOptions = {
+ from: process.env.NODEMAILER_EMAIL,
+ to: toEmail,
+ subject,
+ text: otpText,
+ };
+
+ transporter.sendMail(mailOptions, (error, info) => {
+ if (error) {
+ throw new Error(error as unknown as string);
+ } else {
+ console.log('email sent');
+ return true;
+ }
+ });
+};
+
+export default sendMail;
diff --git a/src/mongo.ts b/src/service/mongo.ts
similarity index 98%
rename from src/mongo.ts
rename to src/service/mongo.ts
index 91773c54..bef78fad 100644
--- a/src/mongo.ts
+++ b/src/service/mongo.ts
@@ -1,5 +1,5 @@
import mongoose, { Connection, Error, Mongoose } from 'mongoose';
-import { init } from './lib/lib';
+import { init } from '../lib/lib';
// Initialize variables to store the MongoDB connection and Mongoose instance.
let connection: Connection | null = null;
diff --git a/src/sockets/close.ts b/src/sockets/close.ts
index 0c50b396..429fd904 100644
--- a/src/sockets/close.ts
+++ b/src/sockets/close.ts
@@ -1,6 +1,6 @@
import { Socket } from 'socket.io';
-import constants from '@/constants.json';
+import constants from '@/constants';
import { getActiveUser, chatExists, closeChat } from '@/lib/lib';
const CloseChatHandler = (socket: Socket) => {
diff --git a/src/sockets/deleteMessage.ts b/src/sockets/deleteMessage.ts
index a56330cc..e60d8f1d 100644
--- a/src/sockets/deleteMessage.ts
+++ b/src/sockets/deleteMessage.ts
@@ -1,10 +1,10 @@
-import { NEW_EVENT_DELETE_MESSAGE } from '@/constants.json';
+import events from '@/constants';
import { getActiveUser, removeMessage } from '@/lib/lib';
import { Socket } from 'socket.io';
const DeleteManagerHandler = (socket: Socket) => {
socket.on(
- NEW_EVENT_DELETE_MESSAGE,
+ events.NEW_EVENT_DELETE_MESSAGE,
async ({ id: messageId, chatId }, messageWasDeletedSuccessfully) => {
const user = getActiveUser({
socketId: socket.id,
@@ -19,7 +19,7 @@ const DeleteManagerHandler = (socket: Socket) => {
socket.broadcast
.to(chatId)
- .emit(NEW_EVENT_DELETE_MESSAGE, { id: messageId, chatId });
+ .emit(events.NEW_EVENT_DELETE_MESSAGE, { id: messageId, chatId });
messageWasDeletedSuccessfully(messageDeleted);
}
);
diff --git a/src/sockets/editMessage.ts b/src/sockets/editMessage.ts
index caa52c2e..12ef2822 100644
--- a/src/sockets/editMessage.ts
+++ b/src/sockets/editMessage.ts
@@ -1,10 +1,10 @@
-import { NEW_EVENT_EDIT_MESSAGE } from '@/constants.json';
+import events from '@/constants';
import { getActiveUser, editMessage } from '@/lib/lib';
import { Socket } from 'socket.io';
const EditMessageHandler = (socket: Socket) => {
socket.on(
- NEW_EVENT_EDIT_MESSAGE,
+ events.NEW_EVENT_EDIT_MESSAGE,
async (
{ id: messageId, chatId, newMessage, oldMessage },
messageWasEditedSuccessfully
@@ -23,7 +23,9 @@ const EditMessageHandler = (socket: Socket) => {
message: newMessage,
oldMessage,
});
- socket.broadcast.to(chatId).emit(NEW_EVENT_EDIT_MESSAGE, messageEdited);
+ socket.broadcast
+ .to(chatId)
+ .emit(events.NEW_EVENT_EDIT_MESSAGE, messageEdited);
messageWasEditedSuccessfully(messageEdited);
}
);
diff --git a/src/sockets/join.ts b/src/sockets/join.ts
index 8ec2a436..35daad60 100644
--- a/src/sockets/join.ts
+++ b/src/sockets/join.ts
@@ -1,8 +1,4 @@
-import {
- NEW_EVENT_JOIN,
- NEW_EVENT_JOINED,
- NEW_EVENT_CHAT_RESTORE,
-} from '@/constants.json';
+import events from '@/constants';
import {
isUserActive,
addToWaitingList,
@@ -22,30 +18,26 @@ import { Server, Socket } from 'socket.io';
const matchMaker = async (io: Server) => {
while (getWaitingUserLen() > 1) {
const chat = await createChat(getRandomPairFromWaitingList());
-
- io.to(chat.id).emit(NEW_EVENT_JOINED, {
+ const roomId: string = chat.id as unknown as string;
+ io.to(roomId).emit(events.NEW_EVENT_JOINED, {
roomId: chat.id,
userIds: chat.userIds,
});
}
};
const JoinHandler = (io: Server, socket: Socket) => {
- socket.on(NEW_EVENT_JOIN, ({ loginId, email }) => {
+ socket.on(events.NEW_EVENT_JOIN, ({ loginId, email }) => {
/**
* This is necessary to enable us send notifications to users
* using multiple devices to chat
*/
socket.join(loginId);
- // Email is possibly null for anonymous users
- if (email) {
- socket.join(email);
- }
/**
* First we check if the user is already chatting.
* If the user is already chatting, continue the chat from where the user left
*/
- if (isUserActive(email ?? loginId)) {
+ if (isUserActive(loginId)) {
const user = getActiveUser({
socketId: socket.id,
loginId,
@@ -66,7 +58,7 @@ const JoinHandler = (io: Server, socket: Socket) => {
});
// Then return all chat messages
- socket.emit(NEW_EVENT_CHAT_RESTORE, {
+ socket.emit(events.NEW_EVENT_CHAT_RESTORE, {
chats,
currentChatId: user?.currentChatId,
});
@@ -77,7 +69,7 @@ const JoinHandler = (io: Server, socket: Socket) => {
addToWaitingList({ loginId, email, socket });
// Finally, run matchMaker to pair all users on the waiting list
- void matchMaker(io);
+ matchMaker(io);
});
};
diff --git a/src/sockets/logout.ts b/src/sockets/logout.ts
index 4056aba3..19dcd3db 100644
--- a/src/sockets/logout.ts
+++ b/src/sockets/logout.ts
@@ -1,13 +1,9 @@
-import {
- NEW_EVENT_LOGOUT,
- NEW_EVENT_CLOSE,
- NEW_EVENT_INACTIVE,
-} from '@/constants.json';
+import events from '@/constants';
import { getActiveUser, delWaitingUser, closeChat } from '@/lib/lib';
import { Server, Socket } from 'socket.io';
const LogOutHandler = (io: Server, socket: Socket) => {
- socket.on(NEW_EVENT_LOGOUT, async ({ loginId, email }) => {
+ socket.on(events.NEW_EVENT_LOGOUT, async ({ loginId, email }) => {
const user = getActiveUser({
socketId: socket.id,
});
@@ -22,9 +18,9 @@ const LogOutHandler = (io: Server, socket: Socket) => {
if (!user.email) {
for (const chatId of user.chatIds) {
const inactiveList = await closeChat(chatId);
- io.to(chatId).emit(NEW_EVENT_CLOSE, chatId);
+ io.to(chatId).emit(events.NEW_EVENT_CLOSE, chatId);
inactiveList?.forEach(emailOrLoginId => {
- socket.broadcast.to(emailOrLoginId).emit(NEW_EVENT_INACTIVE);
+ socket.broadcast.to(emailOrLoginId).emit(events.NEW_EVENT_INACTIVE);
});
}
}
diff --git a/src/sockets/onlineStatus.ts b/src/sockets/onlineStatus.ts
index 2234cdce..5d8a6429 100644
--- a/src/sockets/onlineStatus.ts
+++ b/src/sockets/onlineStatus.ts
@@ -1,11 +1,11 @@
import { OnlineStatus } from '@/types/types';
import { Socket } from 'socket.io';
-import { NEW_EVENT_ONLINE_STATUS } from '@/constants.json';
+import events from '@/constants';
const OnlineStatusHandler = (socket: Socket) => {
socket.on(
- NEW_EVENT_ONLINE_STATUS,
+ events.NEW_EVENT_ONLINE_STATUS,
({
onlineStatus,
chatId,
@@ -13,7 +13,9 @@ const OnlineStatusHandler = (socket: Socket) => {
onlineStatus: OnlineStatus;
chatId: string;
}): void => {
- socket.broadcast.to(chatId).emit(NEW_EVENT_ONLINE_STATUS, onlineStatus);
+ socket.broadcast
+ .to(chatId)
+ .emit(events.NEW_EVENT_ONLINE_STATUS, onlineStatus);
}
);
};
diff --git a/src/sockets/seenMesage.ts b/src/sockets/seenMesage.ts
index ca8b76c1..c819bd67 100644
--- a/src/sockets/seenMesage.ts
+++ b/src/sockets/seenMesage.ts
@@ -1,10 +1,10 @@
-import { NEW_EVENT_READ_MESSAGE } from '@/constants.json';
+import events from '@/constants';
import { getActiveUser, seenMessage } from '@/lib/lib';
import { Socket } from 'socket.io';
const SeenMessageHandler = (socket: Socket) => {
socket.on(
- NEW_EVENT_READ_MESSAGE,
+ events.NEW_EVENT_READ_MESSAGE,
async ({ messageId, chatId }, messageSuccessfullySeen) => {
const user = getActiveUser({ socketId: socket.id });
@@ -15,7 +15,7 @@ const SeenMessageHandler = (socket: Socket) => {
const messageSeen = await seenMessage(chatId, messageId);
- socket.broadcast.to(chatId).emit(NEW_EVENT_READ_MESSAGE, {
+ socket.broadcast.to(chatId).emit(events.NEW_EVENT_READ_MESSAGE, {
messageId,
chatId,
});
diff --git a/src/sockets/sendMessage.ts b/src/sockets/sendMessage.ts
index 547a12e2..e7b90471 100644
--- a/src/sockets/sendMessage.ts
+++ b/src/sockets/sendMessage.ts
@@ -1,8 +1,4 @@
-import {
- NEW_EVENT_SEND_MESSAGE,
- NEW_EVENT_SEND_FAILED,
- NEW_EVENT_RECEIVE_MESSAGE,
-} from '@/constants.json';
+import events from '@/constants';
import { addMessage, getActiveUser } from '@/lib/lib';
import { Socket } from 'socket.io';
@@ -13,7 +9,7 @@ const messageCounts: {
const SendMessageHandler = (socket: Socket) => {
socket.on(
- NEW_EVENT_SEND_MESSAGE,
+ events.NEW_EVENT_SEND_MESSAGE,
async (
{ senderId, message, time, chatId, containsBadword, replyTo },
returnMessageToSender
@@ -29,7 +25,7 @@ const SendMessageHandler = (socket: Socket) => {
});
if (!user) {
- socket.emit(NEW_EVENT_SEND_FAILED, {
+ socket.emit(events.NEW_EVENT_SEND_FAILED, {
message:
'Hmmm. It seems your login session has expired. ' +
'Re-login and try again',
@@ -42,7 +38,7 @@ const SendMessageHandler = (socket: Socket) => {
if (userMessageCount >= 25) {
// User has exceeded the message limit
- socket.emit(NEW_EVENT_SEND_FAILED, {
+ socket.emit(events.NEW_EVENT_SEND_FAILED, {
message:
'You have exceeded the message limit. Please try again later.',
});
@@ -71,7 +67,7 @@ const SendMessageHandler = (socket: Socket) => {
socket.broadcast
.to(chatId)
- .emit(NEW_EVENT_RECEIVE_MESSAGE, messageDetails);
+ .emit(events.NEW_EVENT_RECEIVE_MESSAGE, messageDetails);
// Update the message count for the user
messageCounts[senderId] = userMessageCount + 1;
diff --git a/src/sockets/stopSearch.ts b/src/sockets/stopSearch.ts
index bc029780..20cd9834 100644
--- a/src/sockets/stopSearch.ts
+++ b/src/sockets/stopSearch.ts
@@ -1,15 +1,12 @@
-import {
- NEW_EVENT_STOP_SEARCH,
- NEW_EVENT_STOP_SEARCH_SUCCESS,
-} from '@/constants.json';
+import events from '@/constants';
import { delWaitingUser } from '@/lib/lib';
import { Socket } from 'socket.io';
const StopSearchHandler = (socket: Socket) => {
try {
- socket.on(NEW_EVENT_STOP_SEARCH, async ({ loginId, email }) => {
- delWaitingUser(email ?? loginId);
- socket.emit(NEW_EVENT_STOP_SEARCH_SUCCESS);
+ socket.on(events.NEW_EVENT_STOP_SEARCH, async ({ loginId }) => {
+ delWaitingUser(loginId);
+ socket.emit(events.NEW_EVENT_STOP_SEARCH_SUCCESS);
});
} catch (err) {
console.error(err);
diff --git a/src/sockets/typing.ts b/src/sockets/typing.ts
index 2c20cdee..45e18d68 100644
--- a/src/sockets/typing.ts
+++ b/src/sockets/typing.ts
@@ -1,13 +1,13 @@
import { Socket } from 'socket.io';
-import { NEW_EVENT_TYPING, NEW_EVENT_DISPLAY } from '@/constants.json';
+import events from '@/constants';
const TypingHandler = (socket: Socket) => {
- socket.on(NEW_EVENT_TYPING, ({ chatId, isTyping }) => {
+ socket.on(events.NEW_EVENT_TYPING, ({ chatId, isTyping }) => {
socket
.to(chatId)
.timeout(5000)
- .emit(NEW_EVENT_DISPLAY, { isTyping, chatId });
+ .emit(events.NEW_EVENT_DISPLAY, { isTyping, chatId });
});
};
diff --git a/src/types/contextTypes.ts b/src/types/contextTypes.ts
index 9578a31e..2ee0dbdf 100644
--- a/src/types/contextTypes.ts
+++ b/src/types/contextTypes.ts
@@ -1,3 +1,13 @@
+import { Dispatch } from 'react';
+import {
+ AppType,
+ AuthType,
+ ChatIdType,
+ MessageIdType,
+ MessageType,
+ SettingsType,
+} from './types';
+
export type DialogType = {
isOpen: boolean;
text: string;
@@ -5,3 +15,42 @@ export type DialogType = {
noBtnText?: string;
yesBtnText?: string;
};
+
+export type ChatContextType = {
+ createChat: (
+ chatId: string,
+ userIds: [string, string],
+ messages?: MessageIdType,
+ createdAt?: Date
+ ) => void;
+ messages: ChatIdType;
+ removeMessage: (id: string, chatid: string) => void;
+ addMessage: (message: MessageType) => void;
+ updateMessage: (message: any) => void;
+ closeChat: (chatId: string) => void;
+ currentReplyMessage: MessageType | null;
+ currentReplyMessageId: string;
+ closeAllChats: () => void;
+ receiveMessage: (id: string, chatId: string) => void;
+ startReply: (messageId: string) => void;
+ cancelReply: () => void;
+};
+
+export type AppContextType = {
+ app: AppType;
+ hasUnsavedSettings: boolean;
+ updateSettings: () => undefined;
+ updateTmpSettings: (newSettings: SettingsType) => void;
+ cancelSettingsUpdate: () => void;
+ startSearch: () => undefined;
+ endSearch: (currentChatId: null | string) => undefined;
+ loadUserSettings: (settings: SettingsType) => void;
+ updateOnlineStatus: (onlineStatus: Date | string | null) => void;
+ updateConnection: (isDisconnected: boolean) => void;
+};
+
+export type AuthContextType = {
+ authState: AuthType;
+ dispatchAuth: Dispatch;
+ isLoggedIn: boolean;
+};
diff --git a/src/types/types.ts b/src/types/types.ts
index c173c8c0..830f7568 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -23,6 +23,7 @@ export type AppType = {
currentChatId: string | null;
isSearching: boolean;
onlineStatus: OnlineStatus;
+ disconnected: boolean;
};
export type AuthType = {
@@ -52,7 +53,6 @@ export type MessageIdType = {
};
export type ChatType = {
- id: string;
messages: MessageIdType;
createdAt: Date | number;
userIds: [string, string];
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 13d21fa0..468acd8b 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -1,17 +1,19 @@
import type { Config } from 'tailwindcss';
const config: Config = {
- content: [
- './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
- './src/components/**/*.{js,ts,jsx,tsx,mdx}',
- './src/app/**/*.{js,ts,jsx,tsx,mdx}',
- ],
+ content: ['./src/**/*.{js,jsx,ts,tsx}'],
+ darkMode: 'class',
theme: {
extend: {
- backgroundImage: {
- 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
- 'gradient-conic':
- 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
+ screens: {
+ mdl: { max: '768px' },
+ },
+ colors: {
+ primary: '#011627',
+ secondary: '#162938',
+ highlight: '#FF9F1C',
+ red: '#FF3A46',
+ light: '#f0f8ff',
},
},
},