├── .gitignore
├── App.js
├── app.json
├── assets
├── adaptive-icon.png
├── favicon.png
├── home-image.jpg
├── icon.png
└── splash.png
├── babel.config.js
├── components
├── Chatcomponent.js
├── Messagecomponent.js
└── Modal.js
├── context
└── index.js
├── package-lock.json
├── package.json
├── screens
├── Chatscreen.js
├── Homescreen.js
└── Messagescreen.js
└── utils
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # Temporary files created by Metro to check the health of the file watcher
17 | .metro-health-check*
18 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import { StatusBar } from "expo-status-bar";
2 | import { StyleSheet } from "react-native";
3 | import Homescreen from "./screens/Homescreen";
4 | import Chatscreen from "./screens/Chatscreen";
5 | import Messagescreen from "./screens/Messagescreen";
6 |
7 | import { NavigationContainer } from "@react-navigation/native";
8 | import { createNativeStackNavigator } from "@react-navigation/native-stack";
9 | import GlobalState from "./context";
10 |
11 | const Stack = createNativeStackNavigator();
12 |
13 | export default function App() {
14 | return (
15 |
16 |
17 |
18 | {/* all the screens here */}
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 | }
36 |
37 | const styles = StyleSheet.create({
38 | container: {
39 | flex: 1,
40 | backgroundColor: "#fff",
41 | alignItems: "center",
42 | justifyContent: "center",
43 | },
44 | });
45 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "frontend",
4 | "slug": "frontend",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "userInterfaceStyle": "light",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "contain",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "assetBundlePatterns": [
15 | "**/*"
16 | ],
17 | "ios": {
18 | "supportsTablet": true
19 | },
20 | "android": {
21 | "adaptiveIcon": {
22 | "foregroundImage": "./assets/adaptive-icon.png",
23 | "backgroundColor": "#ffffff"
24 | }
25 | },
26 | "web": {
27 | "favicon": "./assets/favicon.png"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/React-Native-Chat-App-Frontend/d950f30d26d244c78d7aceba80325708b6013afd/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/React-Native-Chat-App-Frontend/d950f30d26d244c78d7aceba80325708b6013afd/assets/favicon.png
--------------------------------------------------------------------------------
/assets/home-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/React-Native-Chat-App-Frontend/d950f30d26d244c78d7aceba80325708b6013afd/assets/home-image.jpg
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/React-Native-Chat-App-Frontend/d950f30d26d244c78d7aceba80325708b6013afd/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/React-Native-Chat-App-Frontend/d950f30d26d244c78d7aceba80325708b6013afd/assets/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/components/Chatcomponent.js:
--------------------------------------------------------------------------------
1 | import { Pressable, StyleSheet, Text, View } from "react-native";
2 | import { FontAwesome } from "@expo/vector-icons";
3 | import { useContext, useEffect } from "react";
4 | import { GlobalContext } from "../context";
5 | import { useNavigation } from "@react-navigation/native";
6 |
7 | export default function Chatcomponent({ item }) {
8 | const navigation = useNavigation();
9 |
10 | console.log(item.messages[item.messages.length - 1]);
11 |
12 |
13 |
14 | function handleNavigateToMessageScreen() {
15 | navigation.navigate("Messagescreen", {
16 | currentGroupName: item.currentGroupName,
17 | currentGroupID: item.id,
18 | });
19 | }
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 |
28 | {item.currentGroupName}
29 |
30 | {item && item.messages && item.messages.length ? item.messages[item.messages.length - 1].text : "Tap to start messaging"}
31 |
32 |
33 |
34 |
35 | {item && item.messages && item.messages.length ? item.messages[item.messages.length - 1].time : "Now"}
36 |
37 |
38 |
39 |
40 | );
41 | }
42 |
43 | const styles = StyleSheet.create({
44 | chat: {
45 | width: "100%",
46 | flexDirection: "row",
47 | alignItems: "center",
48 | borderRadius: 5,
49 | padding: 10,
50 | backgroundColor: "#fff",
51 | height: 80,
52 | marginBottom: 10,
53 | },
54 | userName: {
55 | fontSize: 18,
56 | marginBottom: 5,
57 | fontWeight: "bold",
58 | },
59 | message: {
60 | fontSize: 14,
61 | opacity: 0.8,
62 | },
63 | rightContainer: {
64 | flexDirection: "row",
65 | justifyContent: "space-between",
66 | flex: 1,
67 | },
68 | time: {
69 | opacity: 0.6,
70 | },
71 | circle: {
72 | width: 50,
73 | borderRadius: 50,
74 | height: 50,
75 | alignItems: "center",
76 | justifyContent: "center",
77 | borderWidth: 2,
78 | marginRight: 10,
79 | },
80 | });
81 |
--------------------------------------------------------------------------------
/components/Messagecomponent.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from "react-native";
2 |
3 | export default function Messagecomponent({ currentUser, item }) {
4 | const currentUserStatus = item.currentUser !== currentUser;
5 |
6 | console.log(currentUserStatus , item);
7 |
8 | return (
9 |
10 |
11 |
12 |
19 |
24 | {item.text}
25 |
26 |
27 |
28 | {item.time}
29 |
30 |
31 | );
32 | }
33 |
34 | const styles = StyleSheet.create({
35 | messageItemWrapper: {
36 | maxWidth: "50%",
37 | marginBottom: 15,
38 | },
39 | messageItemInnerWrapper: {
40 | flexDirection: "row",
41 | alignItems: "center",
42 | },
43 | messageItem: {
44 | width: "100%",
45 | backgroundColor: "#ffffff",
46 | padding: 20,
47 | borderRadius: 10,
48 | marginBottom: 2,
49 | },
50 | messageTime : {
51 | marginLeft : 10
52 | }
53 | });
54 |
--------------------------------------------------------------------------------
/components/Modal.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import {
3 | Alert,
4 | Modal,
5 | StyleSheet,
6 | Text,
7 | Pressable,
8 | View,
9 | TextInput,
10 | StatusBar,
11 | Keyboard,
12 | } from "react-native";
13 | import { GlobalContext } from "../context";
14 | import { socket } from "../utils";
15 |
16 | const NewGroupModal = () => {
17 | const {
18 | modalVisible,
19 | setModalVisible,
20 | currentGroupName,
21 | setCurrentGroupName,
22 | } = useContext(GlobalContext);
23 |
24 | function handleCreateNewRoom() {
25 | console.log(currentGroupName);
26 | socket.emit("createNewGroup", currentGroupName);
27 | setModalVisible(false);
28 | setCurrentGroupName("");
29 | Keyboard.dismiss();
30 | }
31 |
32 | return (
33 | {
38 | Alert.alert("Modal has been closed.");
39 | setModalVisible(!modalVisible);
40 | }}
41 | >
42 |
43 |
44 | setCurrentGroupName(value)}
49 | value={currentGroupName}
50 | />
51 |
52 |
53 |
54 | Add
55 |
56 |
57 | setModalVisible(false)}
59 | style={styles.button}
60 | >
61 |
62 | Cancel
63 |
64 |
65 |
66 |
67 |
68 |
69 | );
70 | };
71 |
72 | const styles = StyleSheet.create({
73 | centeredView: {
74 | flex: 1,
75 | justifyContent: "center",
76 | alignItems: "center",
77 | },
78 | modalView: {
79 | margin: 20,
80 | backgroundColor: "white",
81 | borderRadius: 20,
82 | padding: 35,
83 | // alignItems: "center",
84 | shadowColor: "#000",
85 | shadowOffset: {
86 | width: 0,
87 | height: 2,
88 | },
89 | shadowOpacity: 0.25,
90 | shadowRadius: 4,
91 | elevation: 5,
92 | },
93 | textStyle: {
94 | color: "white",
95 | fontWeight: "bold",
96 | textAlign: "center",
97 | },
98 | modalText: {
99 | marginBottom: 15,
100 | textAlign: "center",
101 | },
102 | loginInput: {
103 | borderRadius: 50,
104 | borderWidth: 1,
105 | padding: 8,
106 | },
107 | button: {
108 | backgroundColor: "#703efe",
109 | padding: 15,
110 | marginVertical: 10,
111 | elevation: 1,
112 | borderRadius: 50,
113 | },
114 | buttonWrapper: {
115 | flexDirection: "row",
116 | gap: 10,
117 | },
118 | buttonText: {
119 | textAlign: "center",
120 | color: "#fff",
121 | fontWeight: "bold",
122 | fontSize: 15,
123 | },
124 | });
125 |
126 | export default NewGroupModal;
127 |
--------------------------------------------------------------------------------
/context/index.js:
--------------------------------------------------------------------------------
1 | import { createContext, useState } from "react";
2 |
3 | export const GlobalContext = createContext(null);
4 |
5 | function GlobalState({ children }) {
6 | const [showLoginView, setShowLoginView] = useState(false);
7 | const [currentUserName, setCurrentUserName] = useState("");
8 | const [currentUser, setCurrentUser] = useState("");
9 | const [allUsers, setAllUsers] = useState([]);
10 | const [allChatRooms, setAllChatRooms] = useState([]);
11 | const [modalVisible, setModalVisible] = useState(false);
12 | const [currentGroupName, setCurrentGroupName] = useState("");
13 | const [allChatMessages, setAllChatMessages] = useState([]);
14 | const [currentChatMesage, setCurrentChatMessage] = useState('')
15 |
16 | return (
17 |
38 | {children}
39 |
40 | );
41 | }
42 |
43 | export default GlobalState;
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "1.0.0",
4 | "main": "node_modules/expo/AppEntry.js",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web"
10 | },
11 | "dependencies": {
12 | "@react-navigation/native": "^6.1.6",
13 | "@react-navigation/native-stack": "^6.9.12",
14 | "expo": "~48.0.18",
15 | "expo-status-bar": "~1.4.4",
16 | "react": "18.2.0",
17 | "react-native": "0.71.8",
18 | "react-native-safe-area-context": "^4.5.3",
19 | "react-native-screens": "^3.21.0",
20 | "socket.io-client": "^4.6.2"
21 | },
22 | "devDependencies": {
23 | "@babel/core": "^7.20.0"
24 | },
25 | "private": true
26 | }
27 |
--------------------------------------------------------------------------------
/screens/Chatscreen.js:
--------------------------------------------------------------------------------
1 | import { useContext, useEffect } from "react";
2 | import {
3 | FlatList,
4 | Pressable,
5 | StatusBar,
6 | StyleSheet,
7 | Text,
8 | View,
9 | } from "react-native";
10 | import { GlobalContext } from "../context";
11 | import { AntDesign } from "@expo/vector-icons";
12 | import Chatcomponent from "../components/Chatcomponent";
13 | import NewGroupModal from "../components/Modal";
14 | import { socket } from "../utils";
15 | export default function Chatscreen({ navigation }) {
16 | const {
17 | currentUser,
18 | allChatRooms,
19 | setAllChatRooms,
20 | modalVisible,
21 | setModalVisible,
22 | setCurrentUser,
23 | setShowLoginView,
24 | } = useContext(GlobalContext);
25 |
26 | useEffect(() => {
27 | socket.emit("getAllGroups");
28 |
29 | socket.on("groupList", (groups) => {
30 | console.log(groups ,'hhhhhhhhhhhhhhhhhhhhhhh');
31 | setAllChatRooms(groups);
32 | });
33 | }, [socket]);
34 |
35 | function handleLogout() {
36 | setCurrentUser("");
37 | setShowLoginView(false);
38 | }
39 |
40 | useEffect(() => {
41 | if (currentUser.trim() === "") navigation.navigate("Homescreen");
42 | }, [currentUser]);
43 |
44 | return (
45 |
46 |
47 |
48 | Welcome {currentUser}!
49 |
50 |
51 |
52 |
53 |
54 |
55 | {allChatRooms && allChatRooms.length > 0 ? (
56 | }
59 | keyExtractor={(item) => item.id}
60 | />
61 | ) : null}
62 |
63 |
64 | setModalVisible(true)} style={styles.button}>
65 |
66 | Create New Group
67 |
68 |
69 |
70 | {modalVisible && }
71 |
72 | );
73 | }
74 |
75 | const styles = StyleSheet.create({
76 | mainWrapper: {
77 | backgroundColor: "#eee",
78 | flex: 1,
79 | },
80 | topContainer: {
81 | backgroundColor: "#fff",
82 | height: 70,
83 | width: "100%",
84 | padding: 20,
85 | justifyContent: "center",
86 | marginBottom: 15,
87 | flex: 0.3,
88 | },
89 | header: {
90 | flexDirection: "row",
91 | alignItems: "center",
92 | justifyContent: "center",
93 | },
94 | heading: {
95 | fontSize: 30,
96 | fontWeight: "bold",
97 | textDecorationLine: "underline",
98 | },
99 | listContainer: {
100 | flex: 3.4,
101 | paddingHorizontal: 10,
102 | },
103 | bottomContainer: {
104 | flex: 0.3,
105 | padding: 10,
106 | },
107 | button: {
108 | backgroundColor: "#703efe",
109 | padding: 12,
110 | width: "100%",
111 | elevation: 1,
112 | borderRadius: 50,
113 | },
114 | buttonText: {
115 | textAlign: "center",
116 | color: "#fff",
117 | fontWeight: "bold",
118 | fontSize: 20,
119 | },
120 | });
121 |
--------------------------------------------------------------------------------
/screens/Homescreen.js:
--------------------------------------------------------------------------------
1 | import {
2 | Alert,
3 | ImageBackground,
4 | Keyboard,
5 | Pressable,
6 | StyleSheet,
7 | Text,
8 | TextInput,
9 | View,
10 | } from "react-native";
11 | import homeImage from "../assets/home-image.jpg";
12 | import { useContext, useEffect } from "react";
13 | import { GlobalContext } from "../context";
14 |
15 | export default function Homescreen({ navigation }) {
16 | const {
17 | showLoginView,
18 | setShowLoginView,
19 | currentUserName,
20 | setCurrentUserName,
21 | currentUser,
22 | setCurrentUser,
23 | allUsers,
24 | setAllUsers,
25 | } = useContext(GlobalContext);
26 |
27 | function handleRegisterAndSignIn(isLogin) {
28 | if (currentUserName.trim() !== "") {
29 | const index = allUsers.findIndex(
30 | (userItem) => userItem === currentUserName
31 | );
32 |
33 | if (isLogin) {
34 | if (index === -1) {
35 | Alert.alert("Please register first");
36 | } else {
37 | setCurrentUser(currentUserName);
38 | }
39 | } else {
40 | if (index === -1) {
41 | allUsers.push(currentUserName);
42 | setAllUsers(allUsers);
43 | setCurrentUser(currentUserName);
44 | } else {
45 | Alert.alert("Already registered ! Please login");
46 | }
47 | }
48 |
49 | setCurrentUserName("");
50 | } else {
51 | Alert.alert("User name field is empty");
52 | }
53 |
54 | Keyboard.dismiss();
55 | }
56 |
57 | useEffect(() => {
58 | if (currentUser.trim() !== "") navigation.navigate("Chatscreen");
59 | }, [currentUser]);
60 |
61 | console.log(allUsers, currentUser);
62 |
63 | return (
64 |
65 |
66 |
67 | {showLoginView ? (
68 |
69 |
70 | Enter Your User Name
71 | setCurrentUserName(value)}
76 | value={currentUserName}
77 | />
78 |
79 |
80 | handleRegisterAndSignIn(false)}
82 | style={styles.button}
83 | >
84 |
85 | Register
86 |
87 |
88 | handleRegisterAndSignIn(true)}
90 | style={styles.button}
91 | >
92 |
93 | Login
94 |
95 |
96 |
97 |
98 | ) : (
99 |
100 | Connect , Grow and Inspire
101 |
102 | Connect people around the world for free
103 |
104 | setShowLoginView(true)}
107 | >
108 |
109 | Get Started
110 |
111 |
112 |
113 | )}
114 |
115 |
116 | );
117 | }
118 |
119 | const styles = StyleSheet.create({
120 | mainWrapper: {
121 | flex: 1,
122 | },
123 | homeImage: {
124 | width: "100%",
125 | flex: 3,
126 | justifyContent: "center",
127 | },
128 | content: {
129 | flex: 1,
130 | alignItems: "center",
131 | justifyContent: "center",
132 | width: "100%",
133 | backgroundColor: "#fff",
134 | },
135 | infoBlock: {
136 | width: "100%",
137 | alignItems: "center",
138 | justifyContent: "center",
139 | },
140 | heading: {
141 | fontSize: 28,
142 | fontWeight: "bold",
143 | color: "#000",
144 | marginBottom: 10,
145 | },
146 | subHeading: {
147 | fontSize: 15,
148 | color: "#acacac",
149 | marginBottom: 15,
150 | },
151 | loginInput: {
152 | borderRadius: 50,
153 | borderWidth: 1,
154 | padding: 8,
155 | },
156 | button: {
157 | backgroundColor: "#703efe",
158 | padding: 15,
159 | marginVertical: 10,
160 | width: "34%",
161 | elevation: 1,
162 | borderRadius: 50,
163 | },
164 | buttonWrapper: {
165 | flexDirection: "row",
166 | gap: 10,
167 | },
168 | buttonText: {
169 | textAlign: "center",
170 | color: "#fff",
171 | fontWeight: "bold",
172 | fontSize: 15,
173 | },
174 | });
175 |
--------------------------------------------------------------------------------
/screens/Messagescreen.js:
--------------------------------------------------------------------------------
1 | import { useContext, useEffect, useLayoutEffect } from "react";
2 | import {
3 | FlatList,
4 | Keyboard,
5 | Pressable,
6 | StyleSheet,
7 | Text,
8 | TextInput,
9 | View,
10 | } from "react-native";
11 | import { GlobalContext } from "../context";
12 | import Messagecomponent from "../components/Messagecomponent";
13 | import {socket} from "../utils/index";
14 |
15 | export default function Messagescreen({ navigation, route }) {
16 | const { currentGroupName, currentGroupID } = route.params;
17 | const {
18 | allChatMessages,
19 | setAllChatMessages,
20 | currentUser,
21 | currentChatMesage,
22 | setCurrentChatMessage,
23 | } = useContext(GlobalContext);
24 |
25 | function handleAddNewMessage() {
26 | const timeData = {
27 | hr:
28 | new Date().getHours() < 10
29 | ? `0${new Date().getHours()}`
30 | : new Date().getHours(),
31 | mins:
32 | new Date().getMinutes() < 10
33 | ? `0${new Date().getMinutes()}`
34 | : new Date().getMinutes(),
35 | };
36 |
37 | if (currentUser) {
38 | socket.emit("newChatMessage", {
39 | currentChatMesage,
40 | groupIdentifier: currentGroupID,
41 | currentUser,
42 | timeData,
43 | });
44 |
45 | setCurrentChatMessage("");
46 | Keyboard.dismiss();
47 | }
48 | }
49 |
50 |
51 | useEffect(()=>{
52 | socket.emit('findGroup', currentGroupID)
53 | socket.on('foundGroup', (allChats)=> setAllChatMessages(allChats))
54 | },[socket])
55 |
56 |
57 | return (
58 |
59 |
62 | {allChatMessages && allChatMessages[0] ? (
63 | (
66 |
67 | )}
68 | keyExtractor={(item) => item.id}
69 | />
70 | ) : (
71 | ""
72 | )}
73 |
74 |
75 | setCurrentChatMessage(value)}
79 | placeholder="Enter your message"
80 | />
81 |
82 |
83 |
84 | SEND
85 |
86 |
87 |
88 |
89 | );
90 | }
91 |
92 | const styles = StyleSheet.create({
93 | wrapper: {
94 | flex: 1,
95 | backgroundColor: "#eee",
96 | },
97 | messageInputContainer: {
98 | width: "100%",
99 | backgroundColor: "#fff",
100 | paddingVertical: 30,
101 | paddingHorizontal: 15,
102 | justifyContent: "center",
103 | flexDirection: "row",
104 | },
105 | messageInput: {
106 | borderWidth: 1,
107 | padding: 15,
108 | flex: 1,
109 | borderRadius: 50,
110 | marginRight: 10,
111 | },
112 | button: {
113 | width: "30%",
114 | backgroundColor: "#703efe",
115 | alignItems: "center",
116 | justifyContent: "center",
117 | borderRadius: 50,
118 | },
119 | buttonText: {
120 | color: "#fff",
121 | fontSize: 20,
122 | },
123 | });
124 |
--------------------------------------------------------------------------------
/utils/index.js:
--------------------------------------------------------------------------------
1 | import { Platform } from "react-native";
2 | import { io } from "socket.io-client";
3 | export const BaseUrl =
4 | Platform.OS === "android" ? "http://10.0.2.2:3000/" : "http://localhost:3000";
5 |
6 | export const socket = io.connect("http://10.0.2.2:4000/");
7 |
--------------------------------------------------------------------------------