├── LICENSE
├── README.md
├── jsconfig.json
├── next.config.js
├── package.json
├── postcss.config.js
├── screenshots
├── create_room.png
├── default_room.png
├── login_page.png
└── protected_room.png
├── src
├── components
│ └── Sidebar.jsx
├── context
│ └── connect.js
├── libraries
│ └── withSession.js
├── pages
│ ├── _app.jsx
│ ├── api
│ │ └── socket.js
│ ├── index.jsx
│ └── rooms
│ │ ├── [id].jsx
│ │ ├── create.jsx
│ │ └── index.jsx
└── styles
│ └── globals.css
└── tailwind.config.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 clqu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chat App
2 |
3 | Login Page | Create Room | Default Room | Protected Room
4 | :-------------------------:|:-------------------------:|:-------------------------:|:-------------------------:
5 |  |  |  | 
6 |
7 | #### [Demo](https://chatapp.clqu.repl.co)
8 |
9 |
10 |
11 | ## Getting Started
12 |
13 | ### 🛠 Development Server
14 |
15 | ```bash
16 | npm install --s --f && npm run dev
17 | # or
18 | yarn install && yarn dev
19 | ```
20 | ### 🛠 Production Server
21 | ```bash
22 | npm install --s --f && npm run build && npm run start
23 | # or
24 | yarn install && yarn build && yarn start
25 | ```
26 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
27 | You can start editing the page by modifying `src/pages/index.js`. The page auto-updates as you edit the file.
28 |
29 |
30 | ## Learn More
31 |
32 | To learn more about Next.js, take a look at the following resources:
33 |
34 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
35 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
36 |
37 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
38 |
39 | ## Deploy on Vercel
40 |
41 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new/import?s=https://github.com/clqu/clqu.live&utm_source=clqu.live) from the clqu.
42 |
43 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
44 |
45 | ## ⭐ Star
46 | - Don't forget to star this repo for support :)
47 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./src"
4 | },
5 | }
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | swcMinify: true,
5 | }
6 |
7 | module.exports = nextConfig
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-chat",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@headlessui/react": "^1.6.6",
13 | "next": "12.2.5",
14 | "next-iron-session": "^4.2.0",
15 | "react": "18.2.0",
16 | "react-dom": "18.2.0",
17 | "socket.io": "^4.5.1",
18 | "socket.io-client": "^4.5.1"
19 | },
20 | "devDependencies": {
21 | "autoprefixer": "^10.4.8",
22 | "eslint": "8.22.0",
23 | "eslint-config-next": "12.2.5",
24 | "postcss": "^8.4.16",
25 | "tailwindcss": "^3.1.8"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/screenshots/create_room.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clqu/nextjs-chat-application/519373ffdc1a486eb210530734609a1f8b46d342/screenshots/create_room.png
--------------------------------------------------------------------------------
/screenshots/default_room.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clqu/nextjs-chat-application/519373ffdc1a486eb210530734609a1f8b46d342/screenshots/default_room.png
--------------------------------------------------------------------------------
/screenshots/login_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clqu/nextjs-chat-application/519373ffdc1a486eb210530734609a1f8b46d342/screenshots/login_page.png
--------------------------------------------------------------------------------
/screenshots/protected_room.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/clqu/nextjs-chat-application/519373ffdc1a486eb210530734609a1f8b46d342/screenshots/protected_room.png
--------------------------------------------------------------------------------
/src/components/Sidebar.jsx:
--------------------------------------------------------------------------------
1 | import { Dialog, Transition } from "@headlessui/react";
2 | import { useConnection } from "context/connect";
3 | import { useRouter } from "next/router";
4 | import { Fragment, useEffect, useState } from "react";
5 |
6 | export default function Sidebar() {
7 | const router = useRouter();
8 | let [rooms, setRooms] = useState([]);
9 | let [user, setUser] = useState(null);
10 | let [isOpen, setIsOpen] = useState(false);
11 | let [protectedRoom, setProtected] = useState(false);
12 | let [password, setPassword] = useState('');
13 | const { connection } = useConnection();
14 |
15 | useEffect(() => {
16 | if (connection) {
17 | connection.emit('fetchUser');
18 | connection.on('user', data => {
19 | if (data === null) {
20 | router.push('/');
21 | } else {
22 | setUser(data);
23 | }
24 | });
25 |
26 | return () => {
27 | connection.off('user', data => {
28 | if (data === null) {
29 | router.push('/');
30 | } else {
31 | setUser(data);
32 | }
33 | });
34 | }
35 | }
36 | }, [connection]);
37 |
38 | useEffect(() => {
39 | if (connection) {
40 | connection.emit('fetchRooms');
41 | connection.on('rooms', data => {
42 | setRooms(data.rooms);
43 | });
44 |
45 | return () => {
46 | connection.off('rooms', data => {
47 | if (data.isLogged) {
48 | setUser(data.user);
49 | }
50 | setRooms(data.rooms);
51 | });
52 | }
53 | }
54 | }, []);
55 |
56 | const JoinRoom = room => {
57 | const { id, passwordProtected } = room;
58 | if (passwordProtected) {
59 | setIsOpen(true);
60 | setProtected(room);
61 |
62 | if (password) {
63 | connection.emit('joinRoom', { id, password });
64 | }
65 |
66 | } else {
67 | connection.emit('joinRoom', { id });
68 | }
69 |
70 | connection.off('joinRoom').on('joinRoom', data => {
71 | if (data.success) {
72 | setIsOpen(false);
73 | setPassword('');
74 | router.push('/rooms/' + id);
75 | } else {
76 | if (data?.alreadyIn) {
77 | router.push('/rooms/' + id);
78 | } else {
79 | alert(data.error)
80 | }
81 | }
82 | });
83 | }
84 |
85 | return <>
86 |
87 |
88 |
153 |
154 |
155 |
156 |
157 | Rooms
158 |
159 |
160 |
161 | {rooms.map(room => {
162 | return
JoinRoom(room)}>
163 |

164 |
165 | {room.name}
166 | Created by {room?.owner?.username.split(0, 5) + '...'}
167 |
168 |
169 | {room.passwordProtected &&
}
173 |
{room.users || 0}/{room.maxUsers}
174 |
175 |
176 | })}
177 |
178 |
179 |
180 |
181 |

182 |
{user?.username}
183 |
184 |
185 |
186 | >
187 | }
--------------------------------------------------------------------------------
/src/context/connect.js:
--------------------------------------------------------------------------------
1 | import { useContext, createContext, useState, useEffect } from 'react';
2 | import io from "socket.io-client";
3 |
4 | const Context = createContext();
5 | export const useConnection = () => useContext(Context);
6 |
7 | export const Provider = ({ children }) => {
8 |
9 | const [connection, setConnection] = useState(null);
10 |
11 |
12 | const data = {
13 | connection,
14 | };
15 |
16 | useEffect(() => {
17 | fetch("/api/socket");
18 |
19 | const socket = io();
20 | socket.connect();
21 |
22 | socket.on('connect', () => {
23 | setConnection(socket);
24 | });
25 |
26 |
27 | return () => {
28 | socket.off('connect');
29 | };
30 | }, []);
31 |
32 | return (
33 |
34 | {children}
35 |
36 | );
37 | };
38 |
39 | export default Context;
40 |
--------------------------------------------------------------------------------
/src/libraries/withSession.js:
--------------------------------------------------------------------------------
1 | import { withIronSession } from "next-iron-session";
2 |
3 | export default function withSession(app) {
4 | return withIronSession(app, {
5 | password: "bXlzcWxhc3N3b3JkMTIzNDU2Nzg5MA====",
6 | cookieName: "simple-nextjs-socketio-chat",
7 | cookieOptions: {
8 | secure: process.env.NODE_ENV === "production",
9 | }
10 | });
11 | };
--------------------------------------------------------------------------------
/src/pages/_app.jsx:
--------------------------------------------------------------------------------
1 | import 'styles/globals.css'
2 | import { Provider as ConnectionProvider } from 'context/connect'
3 | import { useRouter } from 'next/router'
4 | import Sidebar from 'components/Sidebar';
5 | import Head from 'next/head';
6 |
7 | function MyApp({ Component, pageProps }) {
8 | const router = useRouter();
9 | return
10 |
11 | Chat App
12 |
13 |
14 |
15 |
16 |
17 | {router.pathname.includes('rooms') ? (
18 |
24 | ) : }
25 |
26 | }
27 |
28 | export default MyApp;
29 |
--------------------------------------------------------------------------------
/src/pages/api/socket.js:
--------------------------------------------------------------------------------
1 | import { Server } from "socket.io";
2 |
3 | export default (async (req, res) => {
4 | if (res.socket.server.io) {
5 | res.end();
6 | return;
7 | }
8 |
9 | const io = new Server(res.socket.server, {
10 | pingInterval: 10000,
11 | pingTimeout: 5000
12 | });
13 | res.socket.server.io = io;
14 |
15 | io.use((socket, next) => {
16 | setInterval(() => {
17 | socket.emit("ping", "pong");
18 | }, 1000);
19 | next();
20 | });
21 |
22 | io.on("connection", (socket) => {
23 | socket.join('global');
24 |
25 | socket.on("login", async (data) => {
26 | const { username } = data;
27 |
28 | const allSockets = await io.fetchSockets();
29 | const userSockets = allSockets.filter((s) => s?.data?.user?.username === username);
30 |
31 | if (userSockets.length > 0) return socket.emit("login", { error: "Username already taken" });
32 |
33 | const user = {
34 | username
35 | };
36 |
37 | socket.data.user = user;
38 | socket.emit("login", {
39 | success: true,
40 | data: user
41 | });
42 | });
43 |
44 | socket.on("fetchUser", () => {
45 | const user = socket.data.user;
46 | if (user) {
47 | socket.emit("user", user);
48 | } else {
49 | socket.emit("user", null);
50 | }
51 | })
52 |
53 | socket.on("fetchRooms", () => {
54 | setInterval(async () => {
55 | const rooms = io.sockets.adapter.rooms;
56 | const allRooms = (await Promise.all(Object.keys(rooms).map(async (room) => {
57 | const sockets = await io.in(room).fetchSockets();
58 | const users = sockets.map((s) => s.data.user);
59 | return {
60 | id: room,
61 | name: rooms[room]?.name,
62 | owner: rooms[room]?.owner,
63 | passwordProtected: rooms[room]?.password ? true : false,
64 | maxUsers: rooms[room]?.maxUsers,
65 | users: users.length
66 | };
67 | }))).filter((r) => r.name !== 'global');
68 | socket.emit("rooms", {
69 | isLogged: socket.data?.user !== undefined ? true : false,
70 | user: socket.data?.user,
71 | rooms: allRooms
72 | });
73 | }, 1000);
74 | });
75 |
76 | socket.on("createRoom", data => {
77 | const { name, password } = data;
78 | if (!name) return socket.emit("createRoom", { success: false, error: "Name is required" });
79 | if (io.sockets.adapter.rooms[name]) return socket.emit("createRoom", { success: false, error: "Room already exists" });
80 | let room = {
81 | id: Math.random().toString(36).substring(2, 9),
82 | name: name.replace(/[^a-zA-Z0-9 ]/g, ""),
83 | owner: socket.data.user,
84 | users: 1,
85 | maxUsers: 10
86 | };
87 |
88 | if (password) room.password = password;
89 |
90 |
91 | io.sockets.adapter.rooms[room.id] = room;
92 |
93 | socket.rooms.forEach((user_room) => {
94 | socket.leave(user_room);
95 | updateMembers(user_room);
96 | socket.to(user_room).emit("message", {
97 | system: true,
98 | message: `${socket.data.user.username} left the room`
99 | });
100 | });
101 | socket.join(room.id);
102 | socket.emit("createRoom", { success: true, data: room });
103 | })
104 |
105 | socket.on("joinRoom", async data => {
106 | const { id, password } = data;
107 | if (!id) return socket.emit("joinRoom", { success: false, error: "Room id is required" });
108 | if (!io.sockets.adapter.rooms[id]) return socket.emit("joinRoom", { success: false, error: "Room not found" });
109 |
110 | const room = io.sockets.adapter.rooms[id];
111 | if (room.password && room.password !== password) return socket.emit("joinRoom", { success: false, error: "Wrong password" });
112 | const sockets = await io.in(id).fetchSockets();
113 | if (sockets.length >= room.maxUsers) return socket.emit("joinRoom", { success: false, error: "Room is full" });
114 | if (sockets.find((s) => s.data.user.username === socket.data.user.username)) return socket.emit("joinRoom", { success: false, alreadyIn: true, error: "You are already in this room" });
115 |
116 | socket.rooms.forEach((user_room) => {
117 | socket.leave(user_room);
118 | updateMembers(user_room);
119 | socket.to(user_room).emit("message", {
120 | system: true,
121 | message: `${socket.data.user.username} left the room`
122 | });
123 | });
124 |
125 | socket.join(id);
126 |
127 | updateMembers(id);
128 | socket.emit("joinRoom", { success: true, data: room });
129 | socket.to(id).emit("message", {
130 | system: true,
131 | message: `${socket.data.user.username} joined the room`
132 | });
133 | });
134 |
135 | socket.on("leaveRoom", async () => {
136 | const room = Array.from(socket.rooms).find(room => room !== socket.id);
137 | if (!room) return socket.emit("leaveRoom", { success: false, error: "You are not in a room" });
138 | socket.leaveAll();
139 | socket.join("global");
140 | socket.emit("leaveRoom", { success: true });
141 |
142 | updateMembers(room);
143 | socket.to(room).emit("message", {
144 | system: true,
145 | message: `${socket.data.user.username} left the room`
146 | });
147 | });
148 |
149 | socket.on("roomMembers", async () => {
150 | const room = Array.from(socket.rooms).find(room => room !== socket.id);
151 | if (!room) return socket.emit("roomMembers", { success: false, error: "You are not in a room" });
152 |
153 | updateMembers(room);
154 | });
155 |
156 | function updateMembers(room) {
157 | io.in(room).fetchSockets().then(sockets => {
158 | const members = sockets.map(socket => socket.data.user);
159 | if (members.length > 0) {
160 | io.in(room).emit("roomMembers", { success: true, data: members });
161 | } else {
162 | delete io.sockets.adapter.rooms[room];
163 | }
164 | });
165 | }
166 |
167 | socket.on("message", async data => {
168 | const room = Array.from(socket.rooms).find(room => room !== socket.id);
169 | if (!room) return;
170 |
171 | const message = {
172 | user: socket.data.user,
173 | message: data.message,
174 | date: new Date()
175 | };
176 |
177 | const sockets = await io.in(room).fetchSockets();
178 | sockets.forEach(s => {
179 | s.emit("message", {
180 | ...message,
181 | self: s.id === socket.id
182 | });
183 | });
184 | });
185 |
186 | socket.on("fetchRoom", async () => {
187 | const room = Array.from(socket.rooms).find(room => room !== socket.id);
188 | if (!room) return socket.emit("fetchRoom", { success: false, error: "You are not in a room" });
189 |
190 | socket.emit("fetchRoom", { success: true, data: io.sockets.adapter.rooms[room] });
191 | });
192 |
193 |
194 |
195 | socket.on("disconnect", (data) => {
196 | socket.rooms.forEach(room => {
197 | socket.to(room).emit("message", {
198 | system: true,
199 | message: `${socket.data.user.username} left the room`
200 | });
201 |
202 | updateMembers(room);
203 | });
204 | socket.leaveAll();
205 | });
206 | });
207 |
208 | res.end();
209 |
210 | });
--------------------------------------------------------------------------------
/src/pages/index.jsx:
--------------------------------------------------------------------------------
1 | import { useConnection } from 'context/connect'
2 | import { useRouter } from 'next/router';
3 | import { useEffect, useState } from 'react';
4 |
5 | export default function Home() {
6 | const { connection } = useConnection();
7 | const router = useRouter();
8 | let [error, setError] = useState(null);
9 |
10 | const Login = event => {
11 | event.preventDefault();
12 | const username = event.target.username.value;
13 | connection.emit('login', { username });
14 | connection.on('login', data => {
15 | if (data.success) {
16 | router.push('/rooms');
17 | } else {
18 | setError(data.error);
19 | }
20 | });
21 | }
22 |
23 | useEffect(() => {
24 | if (connection) {
25 | connection.emit('fetchUser');
26 | connection.on('user', data => {
27 | if (data !== null) {
28 | router.push('/rooms');
29 | }
30 | });
31 | }
32 | }, []);
33 |
34 | return <>
35 |
36 |
37 |
38 |
39 | Login
40 |
41 | {error &&
42 |
{error || "Something went wrong.."}
43 |
}
44 |
55 |
56 |
57 |
58 | >
59 | }
60 |
--------------------------------------------------------------------------------
/src/pages/rooms/[id].jsx:
--------------------------------------------------------------------------------
1 | import { useConnection } from "context/connect";
2 | import { useRouter } from "next/router";
3 | import { useEffect, useState } from "react";
4 |
5 | export default function Room() {
6 | const router = useRouter();
7 | let [room, setRoom] = useState(null);
8 | let [members, setMembers] = useState([]);
9 | let [messages, setMessages] = useState([]);
10 | const { connection } = useConnection();
11 |
12 | useEffect(() => {
13 | if (connection) {
14 | connection.off('message').on('message', data => {
15 | setMessages(messages => [...messages, data]);
16 | });
17 |
18 | return () => {
19 | connection.off('message', data => {
20 | setMessages(messages => [...messages, data]);
21 | });
22 | }
23 | }
24 | }, [connection]);
25 |
26 | useEffect(() => {
27 | if (connection) {
28 | const fetchRoomListener = data => {
29 | if (!data.success) router.push('/rooms');
30 | setRoom(data.data);
31 | }
32 | const roomMembersListener = data => {
33 | if (!data.success) router.push('/rooms');
34 | setMembers(data.data);
35 | }
36 |
37 | connection.emit('roomMembers');
38 | connection.on('roomMembers', roomMembersListener);
39 |
40 | connection.emit('fetchRoom');
41 | connection.on('fetchRoom', fetchRoomListener);
42 |
43 | return () => {
44 | connection.off('roomMembers', roomMembersListener);
45 | connection.off('fetchRoom', fetchRoomListener);
46 | }
47 | }
48 | }, [connection, router]);
49 |
50 | const LeaveRoom = () => {
51 | connection.emit('leaveRoom');
52 | connection.on('leaveRoom', data => {
53 | if (data.success) {
54 | router.push('/rooms');
55 | }
56 | });
57 | }
58 |
59 | const dateNow = date => {
60 | const now = new Date();
61 | const msgDate = new Date(date);
62 | if (now - msgDate < 1000 * 60) {
63 | if (Math.floor((now - msgDate) / 1000) === 1) {
64 | return Math.floor((now - msgDate) / 1000) + ' seconds ago';
65 | } else {
66 | return 'now';
67 | }
68 | }
69 | else if (now.getDate() === msgDate.getDate() && now.getMonth() === msgDate.getMonth() && now.getFullYear() === msgDate.getFullYear()) {
70 | const diff = now.getTime() - msgDate.getTime();
71 | const minutes = Math.floor(diff / 1000 / 60);
72 | return `${minutes} minutes ago`;
73 | }
74 | else if (now.getDate() === msgDate.getDate() && now.getMonth() === msgDate.getMonth() && now.getFullYear() === msgDate.getFullYear()) {
75 | const diff = now.getTime() - msgDate.getTime();
76 | const hours = Math.floor(diff / 1000 / 60 / 60);
77 | return `${hours} hours ago`;
78 | }
79 | else if (now.getMonth() === msgDate.getMonth() && now.getFullYear() === msgDate.getFullYear()) {
80 | const diff = now.getTime() - msgDate.getTime();
81 | const days = Math.floor(diff / 1000 / 60 / 60 / 24);
82 | return `${days} days ago`;
83 | }
84 | else if (now.getFullYear() === msgDate.getFullYear()) {
85 | const diff = now.getTime() - msgDate.getTime();
86 | const months = Math.floor(diff / 1000 / 60 / 60 / 24 / 30);
87 | return `${months} months ago`;
88 | }
89 | else {
90 | const diff = now.getTime() - msgDate.getTime();
91 | const years = Math.floor(diff / 1000 / 60 / 60 / 24 / 30 / 12);
92 | return `${years} years ago`;
93 | }
94 | }
95 |
96 | return <>
97 |
98 |
99 |
100 |
101 |

102 |
103 |
{room?.name}
104 |
{members?.length} members
105 |
106 |
107 |
108 |
113 |
114 |
115 |
116 |
117 | {messages.filter(Boolean).filter(el => {
118 | if (!el.system) {
119 | if (el.user) return true;
120 | if (el.message && el.message.length > 0) return true;
121 |
122 | return false;
123 | } else return true;
124 | }).map((message, index) => {
125 | if (message.system) {
126 | return
127 |
{message.message}
128 |
129 | } else {
130 | if (message.self) {
131 | return
132 |
133 |
{message.user.username}
134 |
135 |
{message.message}
136 |
137 |
{dateNow(message.date)}
138 |
139 |

140 |
141 | } else {
142 | return
143 |

144 |
145 |
{message.user.username}
146 |
147 |
{message.message}
148 |
149 |
{dateNow(message.date)}
150 |
151 |
152 | }
153 | }
154 | })}
155 |
156 |
157 |
158 |
177 |
178 |
179 |
180 | {members?.map(member => (
181 |
182 |
183 |

184 |
185 |
{member?.username}
186 | {room?.owner?.username === member?.username && <>
187 |
190 | >}
191 |
192 |
193 |
194 |
195 | ))}
196 |
197 |
198 |
199 | >
200 | }
--------------------------------------------------------------------------------
/src/pages/rooms/create.jsx:
--------------------------------------------------------------------------------
1 | import { useConnection } from 'context/connect'
2 | import { useRouter } from 'next/router';
3 | import { useEffect, useState } from 'react';
4 |
5 | export default function Home() {
6 | const { connection } = useConnection();
7 | const router = useRouter();
8 | let [error, setError] = useState(null);
9 |
10 | const CreateRoom = event => {
11 | event.preventDefault();
12 | const name = event.target.name.value;
13 | const password = event.target.password.value;
14 | connection.emit('createRoom', { name, password });
15 | connection.on('createRoom', data => {
16 | const result = data;
17 |
18 | if (result.success) {
19 | router.push('/rooms/' + result.data.id);
20 | } else {
21 | setError(data.message);
22 | }
23 | });
24 | }
25 |
26 | useEffect(() => {
27 | if (connection) {
28 | connection.emit('fetchUser');
29 | connection.on('user', data => {
30 | if (data === null) {
31 | router.push('/');
32 | }
33 | });
34 |
35 | return () => {
36 | connection.off('user', data => {
37 | if (data === null) {
38 | router.push('/');
39 | }
40 | });
41 | }
42 | }
43 | }, [connection]);
44 |
45 | return <>
46 |
47 |
48 |
49 |
50 | Create New Room
51 |
52 | {error &&
53 |
{error || "Something went wrong.."}
54 |
}
55 |
70 |
71 |
72 |
73 | >
74 | }
75 |
--------------------------------------------------------------------------------
/src/pages/rooms/index.jsx:
--------------------------------------------------------------------------------
1 | import { useConnection } from "context/connect";
2 | import { useRouter } from "next/router";
3 | import { useEffect, useState } from "react";
4 |
5 | export default function Rooms() {
6 | return <>
7 |
8 |
9 |
Choose a room on the left and start chatting!
10 |
11 |
12 | >
13 | }
--------------------------------------------------------------------------------
/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 |
6 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
7 | @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css');
8 |
9 | * {
10 | font-family: 'Poppins', sans-serif;
11 | }
12 |
13 | body {
14 | background-color: #111214;
15 | overflow-x: hidden;
16 | overflow-y: hidden;
17 | }
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './src/**/*.{js,jsx,ts,tsx}'
5 | ],
6 | theme: {
7 | extend: {
8 | colors: {
9 | 'dark-1': '#111214',
10 | 'dark-2': '#0d0e11',
11 | 'dark-3': '#191c21',
12 | }
13 | },
14 | },
15 | plugins: [],
16 | }
17 |
--------------------------------------------------------------------------------