Skip to content

Commit

Permalink
🎉 ChatApp
Browse files Browse the repository at this point in the history
  • Loading branch information
sluucke committed Dec 8, 2021
1 parent 53dacd2 commit e3af5a2
Show file tree
Hide file tree
Showing 24 changed files with 1,532 additions and 254 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NODE_ENV=production
38 changes: 15 additions & 23 deletions components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,26 @@ type Props = {
title?: string
}

const Layout = ({ children, title = 'This is the default title' }: Props) => (
<div>
const Layout = ({ children, title = 'ChatApp' }: Props) => (
<div >
<Head>
<title>{title}</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<header>
<nav>
<Link href="/">
<a>Home</a>
</Link>{' '}
|{' '}
<Link href="/about">
<a>About</a>
</Link>{' '}
|{' '}
<Link href="/users">
<a>Users List</a>
</Link>{' '}
| <a href="/api/users">Users API</a>
</nav>
</header>
{children}
<footer>
<hr />
<span>I'm here to stay (Footer)</span>
</footer>
<div className="max-w-lg w-full m-auto min-h-screen h-full">
<header className="pb-4 ">
<nav className="bg-gradient-to-r from-purple-600 to-purple-400 py-2 px-3 pb-8 ">
<Link href="/">
<a className="text-white text-2xl font-bold">ChatApp</a>
</Link>
</nav>
</header>
{children}
<footer className="w-full flex items-center justify-center" >
<span>&copy; <Link href="https://github.com/sluucke"><a target="_blank" rel="noreferrer" className="hover:text-purple-600 transition-colors duration-200 ease-in-out">Sluucke</a></Link> - 2021</span>
</footer>
</div>
</div>
)

Expand Down
19 changes: 0 additions & 19 deletions components/List.tsx

This file was deleted.

16 changes: 0 additions & 16 deletions components/ListDetail.tsx

This file was deleted.

18 changes: 0 additions & 18 deletions components/ListItem.tsx

This file was deleted.

4 changes: 4 additions & 0 deletions interfaces/IMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IMessage {
user: string;
message: string;
}
11 changes: 11 additions & 0 deletions interfaces/NextApiResponseIO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Server as NetServer, Socket } from "net";
import { NextApiResponse } from "next";
import { Server as SocketIOServer } from "socket.io";

export type NextApiResponseIO = NextApiResponse & {
socket: Socket & {
server: NetServer & {
io: SocketIOServer;
};
};
};
10 changes: 0 additions & 10 deletions interfaces/index.ts

This file was deleted.

13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
{
"private": true,
"scripts": {
"dev": "next",
"dev": "SET PORT=3002 && next",
"build": "next build",
"start": "next start",
"startdev": "SET PORT=3002 && next start",
"type-check": "tsc"
},
"dependencies": {
"axios": "^0.24.0",
"next": "latest",
"next-connect": "^0.11.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react-dom": "^17.0.2",
"react-icons": "^4.3.1",
"socket.io": "^4.4.0",
"socket.io-client": "^4.4.0"
},
"devDependencies": {
"@fullhuman/postcss-purgecss": "^4.1.3",
"@types/node": "^12.12.21",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.1",
"postcss-preset-env": "^7.0.1",
"tailwindcss": "^2.2.19",
"typescript": "4.0"
}
}
10 changes: 10 additions & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import { AppProps } from 'next/app'

import '../styles/index.css'

function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

export default MyApp
16 changes: 0 additions & 16 deletions pages/about.tsx

This file was deleted.

14 changes: 14 additions & 0 deletions pages/api/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NextApiRequest } from 'next';
import { NextApiResponseIO } from './../../interfaces/NextApiResponseIO';
import nc from 'next-connect'

const handler = nc()

handler.post((req: NextApiRequest, res: NextApiResponseIO) => {
const { message, user } = req.body
res?.socket?.server?.io?.emit('message', { message, user })

res.status(201).json({ message, user })
})

export default handler
23 changes: 23 additions & 0 deletions pages/api/socketio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NextApiResponseIO } from '../../interfaces/NextApiResponseIO';
import type { NextApiRequest } from 'next';
import { Server as NetServer } from 'http';
import { Server as ServerIO } from 'socket.io'
export const config = {
api: {
bodyParser: false,
}
}


export default function handler(req: NextApiRequest, res: NextApiResponseIO) {
if (!res.socket.server.io) {
console.log('[SOCKET.IO] New connection stablished')

const httpServer: NetServer = res.socket.server as any;
const io = new ServerIO(httpServer, {
path: '/api/socketio',
});
res.socket.server.io = io
}
res.end()
}
16 changes: 0 additions & 16 deletions pages/api/users/index.ts

This file was deleted.

105 changes: 105 additions & 0 deletions pages/chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import Link from 'next/link'
import Layout from '../components/Layout'
import { FaArrowRight } from 'react-icons/fa'
import { useEffect, useRef, useState } from 'react'
import { useRouter } from 'next/router'
import { IMessage } from '../interfaces/IMessage'
import { io } from 'socket.io-client'
import axios from 'axios'

const ChatPage = () => {
const router = useRouter()
const inputRef = useRef<HTMLInputElement>(null)
const [connected, setConnected] = useState<boolean>(false)
const [message, setMessage] = useState<string>('')
const [chat, setChat] = useState<IMessage[]>([])
const [user, setUser] = useState<string>('')
useEffect((): any => {
const name = localStorage.getItem('name') || ''
setUser(name)
if (!name) {
router.push('/')
}
const socket = io('http://132.226.245.108:3002', {
path: "/api/socketio",
})

socket.on('connect', () => {
setConnected(true)
})
socket.on('message', (data: IMessage) => {
chat.push(data)
setChat([...chat])
})

if (socket) return () => socket.disconnect()

}, [])

const sendMessage = async () => {
if (message) {
const msg: IMessage = {
user,
message
}
const res = await axios.post('/api/chat', msg)

if (res.status == 201) {
setMessage('')
}
}

inputRef?.current?.focus()
}
return (
<Layout title="ChatApp">
<div id="content-footer" className="bg-white rounded-xl -mt-10 py-2">
<h2 className="text-2xl font-bold px-2">Chat</h2>
{/* <div className="flex flex-col justify-between"> */}
<div id="chat" className="overflow-y-scroll px-2 flex flex-col">
{chat.length ? (
chat.map((msg, i) => (
<div key={i} className={`relative flex ${msg.user == user ? 'self-end bg-gradient-to-r from-purple-600 to-purple-400 py-2 px-3 rounded-t-lg rounded-l-lg my-2 text-white text-start' : 'self-start bg-gradient-to-r from-indigo-600 to-indigo-400 py-2 px-3 rounded-t-lg rounded-r-lg my-2 text-white text-left'}`}>
{msg.user !== user && (
<span className="text-white">{msg.user}:&nbsp;</span>
)}
<p>{msg.message}</p>
</div>
))
) : (
<p className="text-lg">No chat messages</p>
)}
</div>
<div className="flex items-center px-2">
<input
ref={inputRef}
type="text"
value={message}
placeholder={connected ? "Type a message..." : "Connecting..."}
disabled={!connected}
onChange={(e) => {
setMessage(e.target.value);
}}
onKeyPress={(e) => {
if (e.key === "Enter") {
sendMessage();
}
}}
className="w-full rounded-l-lg ring-2 py-2 px-3 outline-none ring-purple-500"
/>
<button
className="bg-purple-500 py-3 px-3 rounded-r-lg shadow text-sm text-white h-full px-2"
onClick={sendMessage}
disabled={!connected}
>
SEND
</button>
</div>
</div>

{/* </div> */}
</Layout>
)
}

export default ChatPage
Loading

1 comment on commit e3af5a2

@vercel
Copy link

@vercel vercel bot commented on e3af5a2 Dec 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.