Skip to content

Instantly share code, notes, and snippets.

@sahilrajput03
Last active August 25, 2022 16:48
Show Gist options
  • Save sahilrajput03/a691c18b3d8b3fc6dbca919a73dd99ba to your computer and use it in GitHub Desktop.
Save sahilrajput03/a691c18b3d8b3fc6dbca919a73dd99ba to your computer and use it in GitHub Desktop.
chat application in nextjs using socket.io
import io from 'socket.io-client';
import {useState, useEffect, useRef} from 'react';
import Header from 'components/header';
import Image from 'next/image';
import desiredChat from '../assets/desired-chat.png';
import Avatar from '@mui/material/Avatar';
import SendMessageIcon from '../assets/send-message-icon.png';
import MessageInputGalleryIcon from '../assets/message-input-gallery-icon.png';
import MessageInputSmileyIcon from '../assets/message-input-smiley-icon.png';
import ClientOnly from 'components/ClientOnly';
import demoBrooklyn from '../assets/demo_brooklyn_simmons.png';
import demoCourtney from '../assets/demo_courtney_henry.png';
import demoJane from '../assets/demo_jane_cooper.png';
import demoKristin from '../assets/demo_kristin_watson.png';
import demoLeslie from '../assets/demo_leslie_alexander.png';
import demoRalph from '../assets/demo_ralph_edwards.png';
import {DeveloperModeSharp} from '@mui/icons-material';
const env = process.env.NODE_ENV;
const isDev = env === 'development';
const isProd = env === 'production';
let socketUrl;
if (isDev) {
socketUrl = 'http://localhost:3000';
}
if (isProd) {
socketUrl = 'https://metoospace.herokuapp.com/';
}
let socket;
type Message = {
author: string;
message: string;
};
// Set static values for demo
// const initialMessages: Message[] = [];
const initialMessages: Message[] = [];
const pseudoNames = [
{id: 1, name: 'Jane Cooper', src: demoJane},
{id: 2, name: 'Courtney Henry', src: demoCourtney},
{id: 3, name: 'Leslie Alexander', src: demoLeslie},
{id: 4, name: 'Brooklyn Simmons', src: demoBrooklyn},
{id: 5, name: 'Ralph Edwards', src: demoRalph},
{id: 6, name: 'Kristnin Watson', src: demoKristin},
];
const getPseudoName = () => pseudoNames[Math.floor(Math.random() * pseudoNames.length)].name;
export default function ChatPageParent() {
return (
<ClientOnly>
<ChatPage />
</ClientOnly>
);
}
function ChatPage() {
console.log({env: process.env});
const [name, setName] = useState(getPseudoName());
const [messages, setMessages] = useState<Array<Message>>(initialMessages);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
socketInitializer();
}, []);
const socketInitializer = async () => {
// We just call it because we don't need anything else out of it
await fetch('/api/socket');
socket = io(socketUrl);
/** Receive message logic */
socket.on('message', (msg) => {
if (msg.author === name) return;
setMessages((currentMsg) => [...currentMsg, {author: msg.author, message: msg.message}]);
console.log(msg.message);
});
};
const imageSrc = pseudoNames.find((n) => n.name === name)?.src ?? '';
const id = pseudoNames.find((n) => n.name === name)?.id ?? '';
const handleSendButton = () => {
const message = inputRef.current?.value;
if (!message) return;
console.log(message);
if (inputRef.current !== null) {
const payload = {author: name, message};
socket.emit('message', payload);
setMessages((currentMsgs) => [...currentMsgs, payload]);
inputRef.current.value = '';
}
};
const inputKeyDown = (e) => {
if (e.key === 'Enter') {
console.log(inputRef.current?.value);
handleSendButton();
}
};
return (
<>
<Header />
<div className='blueTopBar'></div>
<div className='container__chat'>
<div className='contents'>
<div className='left__column'>
<div className='heading'>Chat</div>
{Array.from({length: 3}).map((key, idx) => (
<div key={'user' + idx} className='item'>
{/* For demo */}
{/* <Avatar src={'user.png'} alt='avatar' /> */}
<div className='size54'>
<Image src={imageSrc} />
</div>
<div className='item-details'>
<div className={`user-name ${idx === 1 ? 'user-name--active' : ''}`}>{name}</div>
<div> Hey, did you talk to her?</div>
</div>
<div className='item-time'>2 min ago</div>
</div>
))}
{/* For demo */}
{/* <div className='size54'>
<Image src={demoBrooklyn} />
</div>
<div className='size54'>
<Image src={demoCourtney} />
</div>
<div className='size54'>
<Image src={demoJane} />
</div>
<div className='size54'>
<Image src={demoKristin} />
</div>
<div className='size54'>
<Image src={demoLeslie} />
</div>
<div className='size54'>
<Image src={demoralph} />
</div> */}
</div>
<div className='right__column'>
<div className='top__bar'>
{/* for demo */}
{/* <Avatar className='top__bar__icon' src={'user.png'} alt='avatar' /> */}
<div className='size54'>
<Image src={imageSrc} />
</div>
<div className='top__bar__name'>{name}</div>
</div>
<div className='msg-list'>
{/* Reversing to undo the effect of `flex-direction: column-reverse` */}
{/* Making copy of messages array coz reverse() modifies the original by default */}
{[...messages].reverse().map((m) => (
<div className={'msg ' + (m.author === name ? 'msg--me' : 'msg--other')}>{m.message}</div>
))}
</div>
<div className='input__parent__container'>
{/* Src: https://icons8.com/ */}
<div className='input__message__container'>
<div className='input__message_icon-1'>
<Image src={MessageInputSmileyIcon} />
</div>
<input ref={inputRef} onKeyDown={inputKeyDown} placeholder='Message' className='input__message' />
<div className='input__message_icon-2'>
<Image src={MessageInputGalleryIcon} />
</div>
</div>
<div className='send-message-button' onClick={handleSendButton}>
<Image src={SendMessageIcon} className='send-message-button' />
</div>
</div>
</div>
</div>
</div>
{/* <Image src={desiredChat} alt='desired-chat' /> */}
</>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment