Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
I_Helmet
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
21_22-J 62
I_Helmet
Commits
da4148ab
Commit
da4148ab
authored
May 26, 2022
by
Balasuriya D.A.M.
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create Group Chat Modal Part 1
parent
a70b4c26
Changes
33
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
4821 additions
and
3734 deletions
+4821
-3734
IT18021080/Telemedicine-Chat-App/backend/config/db.js
IT18021080/Telemedicine-Chat-App/backend/config/db.js
+1
-1
IT18021080/Telemedicine-Chat-App/backend/config/generateToken.js
...080/Telemedicine-Chat-App/backend/config/generateToken.js
+2
-2
IT18021080/Telemedicine-Chat-App/backend/controllers/chatControllers.js
...emedicine-Chat-App/backend/controllers/chatControllers.js
+5
-1
IT18021080/Telemedicine-Chat-App/backend/controllers/userControllers.js
...emedicine-Chat-App/backend/controllers/userControllers.js
+9
-4
IT18021080/Telemedicine-Chat-App/backend/data/data.js
IT18021080/Telemedicine-Chat-App/backend/data/data.js
+0
-1
IT18021080/Telemedicine-Chat-App/backend/middleware/authMiddleware.js
...elemedicine-Chat-App/backend/middleware/authMiddleware.js
+1
-1
IT18021080/Telemedicine-Chat-App/backend/middleware/errorMiddleware.js
...lemedicine-Chat-App/backend/middleware/errorMiddleware.js
+1
-1
IT18021080/Telemedicine-Chat-App/backend/models/messageModel.js
...1080/Telemedicine-Chat-App/backend/models/messageModel.js
+1
-1
IT18021080/Telemedicine-Chat-App/backend/models/userModel.js
IT18021080/Telemedicine-Chat-App/backend/models/userModel.js
+4
-1
IT18021080/Telemedicine-Chat-App/backend/routes/chatRoutes.js
...021080/Telemedicine-Chat-App/backend/routes/chatRoutes.js
+1
-3
IT18021080/Telemedicine-Chat-App/backend/routes/userRoutes.js
...021080/Telemedicine-Chat-App/backend/routes/userRoutes.js
+1
-3
IT18021080/Telemedicine-Chat-App/backend/server.js
IT18021080/Telemedicine-Chat-App/backend/server.js
+7
-6
IT18021080/Telemedicine-Chat-App/frontend/package-lock.json
IT18021080/Telemedicine-Chat-App/frontend/package-lock.json
+3477
-3371
IT18021080/Telemedicine-Chat-App/frontend/package.json
IT18021080/Telemedicine-Chat-App/frontend/package.json
+10
-12
IT18021080/Telemedicine-Chat-App/frontend/public/index.html
IT18021080/Telemedicine-Chat-App/frontend/public/index.html
+8
-5
IT18021080/Telemedicine-Chat-App/frontend/src/App.css
IT18021080/Telemedicine-Chat-App/frontend/src/App.css
+2
-2
IT18021080/Telemedicine-Chat-App/frontend/src/App.js
IT18021080/Telemedicine-Chat-App/frontend/src/App.js
+2
-4
IT18021080/Telemedicine-Chat-App/frontend/src/Context/ChatProvider.js
...elemedicine-Chat-App/frontend/src/Context/ChatProvider.js
+1
-2
IT18021080/Telemedicine-Chat-App/frontend/src/Pages/ChatPage.js
...1080/Telemedicine-Chat-App/frontend/src/Pages/ChatPage.js
+14
-12
IT18021080/Telemedicine-Chat-App/frontend/src/Pages/Homepage.js
...1080/Telemedicine-Chat-App/frontend/src/Pages/Homepage.js
+7
-2
IT18021080/Telemedicine-Chat-App/frontend/src/components/Authentication/Login.js
...-Chat-App/frontend/src/components/Authentication/Login.js
+19
-10
IT18021080/Telemedicine-Chat-App/frontend/src/components/Authentication/Signup.js
...Chat-App/frontend/src/components/Authentication/Signup.js
+12
-4
IT18021080/Telemedicine-Chat-App/frontend/src/components/ChatBox.js
.../Telemedicine-Chat-App/frontend/src/components/ChatBox.js
+1
-1
IT18021080/Telemedicine-Chat-App/frontend/src/components/ChatLoading.js
...emedicine-Chat-App/frontend/src/components/ChatLoading.js
+16
-15
IT18021080/Telemedicine-Chat-App/frontend/src/components/MyChats.js
.../Telemedicine-Chat-App/frontend/src/components/MyChats.js
+22
-23
IT18021080/Telemedicine-Chat-App/frontend/src/components/UserAvatar/UserListItem.js
...at-App/frontend/src/components/UserAvatar/UserListItem.js
+6
-10
IT18021080/Telemedicine-Chat-App/frontend/src/components/miscellaneous/GroupChatModal.js
...p/frontend/src/components/miscellaneous/GroupChatModal.js
+117
-0
IT18021080/Telemedicine-Chat-App/frontend/src/components/miscellaneous/ProfileModal.js
...App/frontend/src/components/miscellaneous/ProfileModal.js
+5
-13
IT18021080/Telemedicine-Chat-App/frontend/src/components/miscellaneous/SideDrawer.js
...t-App/frontend/src/components/miscellaneous/SideDrawer.js
+33
-53
IT18021080/Telemedicine-Chat-App/frontend/src/config/ChatLogics.js
...0/Telemedicine-Chat-App/frontend/src/config/ChatLogics.js
+0
-2
IT18021080/Telemedicine-Chat-App/frontend/src/index.js
IT18021080/Telemedicine-Chat-App/frontend/src/index.js
+5
-1
IT18021080/Telemedicine-Chat-App/package-lock.json
IT18021080/Telemedicine-Chat-App/package-lock.json
+1022
-163
IT18021080/Telemedicine-Chat-App/package.json
IT18021080/Telemedicine-Chat-App/package.json
+9
-4
No files found.
IT18021080/Telemedicine-Chat-App/backend/config/db.js
View file @
da4148ab
...
...
@@ -19,4 +19,4 @@ const connectDB = async () => {
}
};
module
.
exports
=
connectDB
;
\ No newline at end of file
module
.
exports
=
connectDB
;
IT18021080/Telemedicine-Chat-App/backend/config/generateToken.js
View file @
da4148ab
...
...
@@ -5,10 +5,10 @@ const generateToken = (id) => {
//add jwt secret from .env
return
jwt
.
sign
({
id
},
process
.
env
.
JWT_SECRET
,
{
//can change the count of days as i want (secret days)
expiresIn
:
"
3
0d
"
,
expiresIn
:
"
20
0d
"
,
});
};
module
.
exports
=
generateToken
;
//JWT use for pass user data to backend through JWT
\ No newline at end of file
//JWT use for pass user data to backend through JWT
IT18021080/Telemedicine-Chat-App/backend/controllers/chatControllers.js
View file @
da4148ab
...
...
@@ -172,4 +172,8 @@ const removeFromGroup = asyncHandler(async (req, res) => {
}
});
module
.
exports
=
{
accessChat
,
fetchChats
,
createGroupChat
,
renameGroup
,
addToGroup
,
removeFromGroup
};
\ No newline at end of file
module
.
exports
=
{
accessChat
,
fetchChats
,
createGroupChat
,
renameGroup
,
addToGroup
,
removeFromGroup
};
IT18021080/Telemedicine-Chat-App/backend/controllers/userControllers.js
View file @
da4148ab
...
...
@@ -25,7 +25,9 @@ const registerUser = asyncHandler(async (req, res) => {
password
,
pic
,
});
//after register..also want send JWT token
//after register..also want send JWT token
if
(
user
)
{
res
.
status
(
201
).
json
({
_id
:
user
.
_id
,
...
...
@@ -49,7 +51,7 @@ const authUser = asyncHandler(async (req, res) => {
const
user
=
await
User
.
findOne
({
email
});
//If user is already exist check it with DB data such as password
if
(
user
&&
(
await
user
.
matchPassword
(
password
)))
{
if
(
user
&&
(
await
user
.
matchPassword
(
password
)))
{
res
.
json
({
_id
:
user
.
_id
,
name
:
user
.
name
,
...
...
@@ -63,11 +65,13 @@ const authUser = asyncHandler(async (req, res) => {
}
});
// /api/user?search = minosh - goint to creat search query
//This is how to access the query (search query)
const
allUsers
=
asyncHandler
(
async
(
req
,
res
)
=>
{
const
keyword
=
req
.
query
.
search
?
{
//use $or operation
$or
:
[
//references from MongoDB pages.can get more information from that about $regex
...
...
@@ -79,11 +83,12 @@ const allUsers = asyncHandler(async (req, res) => {
:
{};
//query write to database
const
users
=
await
User
.
find
(
keyword
).
find
({
_id
:
{
$ne
:
req
.
user
.
_id
}
});
const
users
=
await
User
.
find
(
keyword
).
find
({
_id
:
{
$ne
:
req
.
user
.
_id
}
});
// find({_id:{$ne:req.user._id}}) - current id user loged in
res
.
send
(
users
);
//to return
});
module
.
exports
=
{
registerUser
,
authUser
,
allUsers
};
\ No newline at end of file
module
.
exports
=
{
registerUser
,
authUser
,
allUsers
};
IT18021080/Telemedicine-Chat-App/backend/data/data.js
View file @
da4148ab
...
...
@@ -107,5 +107,4 @@ const chats = [
},
];
module
.
exports
=
{
chats
};
\ No newline at end of file
IT18021080/Telemedicine-Chat-App/backend/middleware/authMiddleware.js
View file @
da4148ab
...
...
@@ -35,4 +35,4 @@ const protect = asyncHandler(async (req, res, next) => {
}
});
module
.
exports
=
{
protect
};
\ No newline at end of file
module
.
exports
=
{
protect
};
IT18021080/Telemedicine-Chat-App/backend/middleware/errorMiddleware.js
View file @
da4148ab
...
...
@@ -15,4 +15,4 @@ const errorHandler = (err, req, res, next) => {
});
};
module
.
exports
=
{
notFound
,
errorHandler
};
\ No newline at end of file
module
.
exports
=
{
notFound
,
errorHandler
};
IT18021080/Telemedicine-Chat-App/backend/models/messageModel.js
View file @
da4148ab
...
...
@@ -15,4 +15,4 @@ const messageModel = mongoose.Schema({
const
Message
=
mongoose
.
model
(
"
Message
"
,
messageModel
);
module
.
exports
=
Message
;
\ No newline at end of file
module
.
exports
=
Message
;
IT18021080/Telemedicine-Chat-App/backend/models/userModel.js
View file @
da4148ab
const
mongoose
=
require
(
"
mongoose
"
);
const
bcrypt
=
require
(
"
bcryptjs
"
);
const
userSchema
=
mongoose
.
Schema
({
name
:
{
type
:
String
,
required
:
true
},
email
:
{
type
:
String
,
required
:
true
,
unique
:
true
},
...
...
@@ -8,6 +9,7 @@ const userSchema = mongoose.Schema({
pic
:
{
type
:
String
,
//required: true, if it is required i can use this reuired as true
default
:
"
https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg
"
,
},
...
...
@@ -31,6 +33,7 @@ userSchema.pre("save", async function (next) {
this
.
password
=
await
bcrypt
.
hash
(
this
.
password
,
salt
);
//add Hash and bcrypt
});
const
User
=
mongoose
.
model
(
"
User
"
,
userSchema
);
module
.
exports
=
User
;
\ No newline at end of file
module
.
exports
=
User
;
IT18021080/Telemedicine-Chat-App/backend/routes/chatRoutes.js
View file @
da4148ab
...
...
@@ -3,18 +3,16 @@ const { accessChat, fetchChats, createGroupChat, renameGroup, addToGroup, remove
const
{
protect
}
=
require
(
"
../middleware/authMiddleware
"
);
//create router object
const
router
=
express
.
Router
();
//only login user can access this route.
router
.
route
(
"
/
"
).
post
(
protect
,
accessChat
);
//API route for one on one chat
router
.
route
(
"
/
"
).
post
(
protect
,
accessChat
);
router
.
route
(
"
/
"
).
get
(
protect
,
fetchChats
);
router
.
route
(
"
/group
"
).
post
(
protect
,
createGroupChat
);
//create group
router
.
route
(
"
/rename
"
).
put
(
protect
,
renameGroup
);
//update group
router
.
route
(
"
/groupadd
"
).
put
(
protect
,
addToGroup
);
//add someone to group
router
.
route
(
"
/groupremove
"
).
put
(
protect
,
removeFromGroup
);
//remove from group
module
.
exports
=
router
;
IT18021080/Telemedicine-Chat-App/backend/routes/userRoutes.js
View file @
da4148ab
...
...
@@ -3,12 +3,10 @@ const { registerUser, authUser, allUsers } = require("../controllers/userControl
const
{
protect
}
=
require
(
"
../middleware/authMiddleware
"
);
const
router
=
express
.
Router
();
router
.
route
(
"
/
"
).
post
(
registerUser
).
get
(
protect
,
allUsers
);
//User searching API end point
router
.
post
(
"
/login
"
,
authUser
);
router
.
post
(
"
/login
"
,
authUser
);
module
.
exports
=
router
;
IT18021080/Telemedicine-Chat-App/backend/server.js
View file @
da4148ab
const
express
=
require
(
"
express
"
);
const
dotenv
=
require
(
"
dotenv
"
);
const
{
chats
}
=
require
(
"
./data/data
"
);
...
...
@@ -6,22 +5,22 @@ const connectDB = require("./config/db");
const
colors
=
require
(
"
colors
"
);
const
userRoutes
=
require
(
"
./routes/userRoutes
"
);
const
chatRoutes
=
require
(
"
./routes/chatRoutes
"
);
const
{
notFound
,
errorHandler
}
=
require
(
"
./middleware/errorMiddleware
"
);
dotenv
.
config
();
dotenv
.
config
();
connectDB
();
const
app
=
express
();
app
.
use
(
express
.
json
());
//to accept JSON data
app
.
get
(
"
/
"
,
(
req
,
res
)
=>
{
res
.
send
(
"
API is Running Suc
c
essfully
"
);
res
.
send
(
"
API is Running Sucessfully
"
);
});
//create API end points
app
.
use
(
"
/api/user
"
,
userRoutes
);
app
.
use
(
"
/api/chat
"
,
chatRoutes
);
...
...
@@ -29,6 +28,8 @@ app.use("/api/chat", chatRoutes);
app
.
use
(
notFound
);
app
.
use
(
errorHandler
);
const
PORT
=
process
.
env
.
PORT
||
5000
;
app
.
listen
(
5000
,
console
.
log
(
`Server Started on PORT
${
PORT
}
`
.
yellow
.
bold
));
\ No newline at end of file
app
.
listen
(
5000
,
console
.
log
(
`Server Started on PORT
${
PORT
}
`
.
yellow
.
bold
));
IT18021080/Telemedicine-Chat-App/frontend/package-lock.json
View file @
da4148ab
This diff is collapsed.
Click to expand it.
IT18021080/Telemedicine-Chat-App/frontend/package.json
View file @
da4148ab
...
...
@@ -4,21 +4,19 @@
"private"
:
true
,
"proxy"
:
"http://127.0.0.1:5000"
,
"dependencies"
:
{
"@chakra-ui/button"
:
"^1.5.10"
,
"@chakra-ui/icons"
:
"^1.1.7"
,
"@chakra-ui/layout"
:
"^1.8.0"
,
"@chakra-ui/react"
:
"^1.8.8"
,
"@chakra-ui/icons"
:
"^2.0.0"
,
"@chakra-ui/react"
:
"^2.0.0"
,
"@emotion/react"
:
"^11.9.0"
,
"@emotion/styled"
:
"^11.8.1"
,
"@testing-library/jest-dom"
:
"^5.16.
3
"
,
"@testing-library/react"
:
"^1
2.1.4
"
,
"@testing-library/jest-dom"
:
"^5.16.
4
"
,
"@testing-library/react"
:
"^1
3.2.0
"
,
"@testing-library/user-event"
:
"^13.5.0"
,
"axios"
:
"^0.2
6.1
"
,
"framer-motion"
:
"^
6.2.10
"
,
"react"
:
"^18.
0
.0"
,
"react-dom"
:
"^18.
0
.0"
,
"react-router-dom"
:
"^5.3.
0
"
,
"react-scripts"
:
"5.0.
0
"
,
"axios"
:
"^0.2
7.2
"
,
"framer-motion"
:
"^
4.1.17
"
,
"react"
:
"^18.
1
.0"
,
"react-dom"
:
"^18.
1
.0"
,
"react-router-dom"
:
"^5.3.
1
"
,
"react-scripts"
:
"5.0.
1
"
,
"web-vitals"
:
"^2.1.4"
},
"scripts"
:
{
...
...
IT18021080/Telemedicine-Chat-App/frontend/public/index.html
View file @
da4148ab
...
...
@@ -15,11 +15,14 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link
rel=
"manifest"
href=
"%PUBLIC_URL%/manifest.json"
/>
<link
rel=
"stylesheet"
href=
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity=
"sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin=
"anonymous"
referrerpolicy=
"no-referrer"
/>
<link
rel=
"stylesheet"
href=
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity=
"sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin=
"anonymous"
referrerpolicy=
"no-referrer"
/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
...
...
IT18021080/Telemedicine-Chat-App/frontend/src/App.css
View file @
da4148ab
@import
url('https://fonts.googleapis.com/css2?family=Work+Sans:wght@300&display=swap')
;
.App
{
.App
{
min-height
:
100vh
;
display
:
flex
;
background-image
:
url("./background.jpg")
;
background-size
:
cover
;
background-position
:
center
;
color
:
black
;
color
:
black
;
}
\ No newline at end of file
IT18021080/Telemedicine-Chat-App/frontend/src/App.js
View file @
da4148ab
import
"
./App.css
"
;
import
{
Route
}
from
"
react-router-dom
"
;
import
Homepage
from
"
./Pages/Homepage
"
;
import
ChatPage
from
"
./Pages/ChatPage
"
;
function
App
()
{
return
(
<
div
className
=
"
App
"
>
<
Route
path
=
"
/
"
component
=
{
Homepage
}
exact
/>
<
Route
path
=
"
/chats
"
component
=
{
ChatPage
}
/
>
<
Route
path
=
"
/
"
component
=
{
Homepage
}
exact
/>
<
Route
path
=
"
/chats
"
component
=
{
ChatPage
}
/>
<
/div
>
);
...
...
IT18021080/Telemedicine-Chat-App/frontend/src/Context/ChatProvider.js
View file @
da4148ab
...
...
@@ -22,8 +22,7 @@ const ChatProvider = ({ children }) => {
},
[
history
]);
return
(
<
ChatContext
.
Provider
value
=
{{
user
,
setUser
,
selectedChat
,
setSelectedChat
,
chats
,
setChats
}}
>
<
ChatContext
.
Provider
value
=
{{
user
,
setUser
,
selectedChat
,
setSelectedChat
,
chats
,
setChats
}}
>
{
children
}
<
/ChatContext.Provider
>
);
...
...
IT18021080/Telemedicine-Chat-App/frontend/src/Pages/ChatPage.js
View file @
da4148ab
//import React from "react";
import
{
Box
}
from
"
@chakra-ui/react
"
;
import
{
ChatState
}
from
"
../Context/ChatProvider
"
;
import
SideDrawer
from
"
../components/miscellaneous/SideDrawer
"
;
import
MyChats
from
"
../components/MyChats
"
;
import
ChatBox
from
"
../components/ChatBox
"
;
const
ChatPage
=
()
=>
{
const
{
user
}
=
ChatState
();
return
(
<
div
style
=
{{
width
:
"
100%
"
}}
>
{
user
&&
<
SideDrawer
/>
}
{
user
&&
<
SideDrawer
/>
}
<
Box
d
=
"
flex
"
d
isplay
=
"
flex
"
justifyContent
=
"
space-between
"
w
=
"
100%
"
h
=
"
91.5vh
"
p
=
"
10px
"
width
=
"
100%
"
height
=
"
91.5vh
"
padding
=
"
10px
"
>
{
user
&&
<
MyChats
/>
}
{
user
&&
<
ChatBox
/>
}
<
/Box
>
{
user
&&
<
MyChats
/>
}
{
user
&&
<
ChatBox
/>
}
<
/Box
>
<
/div
>
);
};
export
default
ChatPage
;
\ No newline at end of file
export
default
ChatPage
;
IT18021080/Telemedicine-Chat-App/frontend/src/Pages/Homepage.js
View file @
da4148ab
...
...
@@ -14,6 +14,8 @@ import Login from "../components/Authentication/Login";
import
Signup
from
"
../components/Authentication/Signup
"
;
import
{
useHistory
}
from
"
react-router-dom
"
;
const
Homepage
=
()
=>
{
const
history
=
useHistory
();
...
...
@@ -21,12 +23,13 @@ const Homepage = () => {
useEffect
(()
=>
{
const
user
=
JSON
.
parse
(
localStorage
.
getItem
(
"
userInfo
"
));
//check if user is loged in
push back to the chat page
//check if user is loged in
if
(
user
)
history
.
push
(
"
/chats
"
);
},
[
history
]);
return
(
//use container from chakra ui and remove div
<
Container
maxW
=
"
xl
"
centerContent
>
...
...
@@ -66,8 +69,10 @@ const Homepage = () => {
<
/TabPanels
>
<
/Tabs
>
<
/Box
>
<
/Container
>
);
};
export
default
Homepage
;
\ No newline at end of file
export
default
Homepage
;
IT18021080/Telemedicine-Chat-App/frontend/src/components/Authentication/Login.js
View file @
da4148ab
...
...
@@ -9,18 +9,22 @@ import { useToast } from "@chakra-ui/react";
import
axios
from
"
axios
"
;
import
{
useHistory
}
from
"
react-router-dom
"
;
const
Login
=
()
=>
{
const
[
show
,
setShow
]
=
useState
(
false
);
const
[
email
,
setEmail
]
=
useState
();
const
[
password
,
setPassword
]
=
useState
();
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
show
,
setShow
]
=
useState
(
false
);
const
[
email
,
setEmail
]
=
useState
();
const
[
password
,
setPassword
]
=
useState
();
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
toast
=
useToast
();
const
history
=
useHistory
();
const
toast
=
useToast
();
const
history
=
useHistory
();
const
handleClick
=
()
=>
setShow
(
!
show
);
const
submitHandler
=
async
()
=>
{
const
submitHandler
=
async
()
=>
{
setLoading
(
true
);
if
(
!
email
||
!
password
)
{
toast
({
...
...
@@ -77,6 +81,8 @@ const Login = () => {
}
};
return
(
//Use vstack to allign verticaly
<
VStack
spacing
=
"
5px
"
color
=
"
black
"
>
...
...
@@ -84,8 +90,9 @@ const Login = () => {
<
FormControl
id
=
"
email
"
isRequired
>
<
FormLabel
>
Email
<
/FormLabel
>
<
Input
<
Input
value
=
{
email
}
placeholder
=
"
Enter Your Email
"
onChange
=
{(
e
)
=>
setEmail
(
e
.
target
.
value
)}
...
...
@@ -100,7 +107,7 @@ const Login = () => {
<
Input
type
=
{
show
?
"
text
"
:
"
password
"
}
placeholder
=
"
Enter Your Password
"
value
=
{
password
}
value
=
{
password
}
onChange
=
{(
e
)
=>
setPassword
(
e
.
target
.
value
)}
/
>
...
...
@@ -120,6 +127,7 @@ const Login = () => {
style
=
{{
marginTop
:
15
}}
onClick
=
{
submitHandler
}
isLoading
=
{
loading
}
>
Login
...
...
@@ -137,7 +145,8 @@ const Login = () => {
<
/Button
>
<
/VStack
>
);
}
export
default
Login
;
\ No newline at end of file
export
default
Login
;
IT18021080/Telemedicine-Chat-App/frontend/src/components/Authentication/Signup.js
View file @
da4148ab
...
...
@@ -9,9 +9,11 @@ import { useToast } from "@chakra-ui/react";
import
axios
from
"
axios
"
;
import
{
useHistory
}
from
"
react-router-dom
"
;
const
Signup
=
()
=>
{
const
[
show
,
setShow
]
=
useState
(
false
);
const
[
show
,
setShow
]
=
useState
(
false
);
const
[
name
,
setName
]
=
useState
();
const
[
email
,
setEmail
]
=
useState
();
const
[
confirmpassword
,
setConfirmpassword
]
=
useState
();
...
...
@@ -21,6 +23,7 @@ const Signup = () => {
const
toast
=
useToast
();
const
history
=
useHistory
();
const
handleClick
=
()
=>
setShow
(
!
show
);
const
postDetails
=
(
pics
)
=>
{
...
...
@@ -133,10 +136,14 @@ const Signup = () => {
});
setLoading
(
false
);
}
};
return
(
//Use vstack to allign verticaly
return
(
//Use vstack to allign verticaly
<
VStack
spacing
=
"
5px
"
color
=
"
black
"
>
<
FormControl
id
=
"
first-name
"
isRequired
>
<
FormLabel
>
Name
<
/FormLabel
>
...
...
@@ -220,7 +227,8 @@ const Signup = () => {
<
/VStack
>
);
}
export
default
Signup
;
\ No newline at end of file
export
default
Signup
;
IT18021080/Telemedicine-Chat-App/frontend/src/components/ChatBox.js
View file @
da4148ab
...
...
@@ -6,4 +6,4 @@ const ChatBox = () => {
);
};
export
default
ChatBox
;
\ No newline at end of file
export
default
ChatBox
;
IT18021080/Telemedicine-Chat-App/frontend/src/components/ChatLoading.js
View file @
da4148ab
import
{
Stack
}
from
"
@chakra-ui/layout
"
;
import
{
Skeleton
}
from
"
@chakra-ui/react
"
;
import
{
Stack
,
Skeleton
}
from
"
@chakra-ui/react
"
;
import
React
from
"
react
"
;
const
ChatLoading
=
()
=>
{
return
(
<
Stack
>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
"
45px
"
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
Skeleton
height
=
'
40px
'
/>
<
/Stack
>
);
};
export
default
ChatLoading
;
\ No newline at end of file
export
default
ChatLoading
\ No newline at end of file
IT18021080/Telemedicine-Chat-App/frontend/src/components/MyChats.js
View file @
da4148ab
import
{
useToast
}
from
"
@chakra-ui/react
"
;
import
{
AddIcon
}
from
"
@chakra-ui/icons
"
;
import
{
Box
,
Button
,
Stack
,
useToast
,
Text
}
from
"
@chakra-ui/react
"
;
import
axios
from
"
axios
"
;
import
React
,
{
useEffect
,
useState
}
from
"
react
"
;
import
{
ChatState
}
from
"
../Context/ChatProvider
"
;
import
{
Box
,
Stack
,
Text
}
from
"
@chakra-ui/layout
"
;
import
{
Button
}
from
"
@chakra-ui/button
"
;
import
{
AddIcon
}
from
"
@chakra-ui/icons
"
;
import
ChatLoading
from
"
./ChatLoading
"
;
import
{
getSender
}
from
"
../config/ChatLogics
"
;
import
GroupChatModal
from
"
./miscellaneous/GroupChatModal
"
;
const
MyChats
=
()
=>
{
const
[
loggedUser
,
setLoggedUser
]
=
useState
();
const
{
selectedChat
,
setSelectedChat
,
user
,
chats
,
setChats
}
=
ChatState
();
const
{
user
,
selectedChat
,
setSelectedChat
,
chats
,
setChats
}
=
ChatState
();
const
toast
=
useToast
();
...
...
@@ -22,11 +20,13 @@ const MyChats = () => {
const
config
=
{
headers
:
{
Authorization
:
`Bearer
${
user
.
token
}
`
,
},
};
const
{
data
}
=
await
axios
.
get
(
"
/api/chat
"
,
config
);
console
.
log
(
data
);
setChats
(
data
);
//setting all of the chats
setChats
(
data
);
}
catch
(
error
)
{
toast
({
title
:
"
Error Occured!
"
,
...
...
@@ -35,7 +35,6 @@ const MyChats = () => {
duration
:
5000
,
isClosable
:
true
,
position
:
"
bottom-left
"
,
});
}
};
...
...
@@ -43,11 +42,11 @@ const MyChats = () => {
useEffect
(()
=>
{
setLoggedUser
(
JSON
.
parse
(
localStorage
.
getItem
(
"
userInfo
"
)));
fetchChats
();
},
[]);
},
[])
return
(
<
Box
d
=
{{
base
:
selectedChat
?
"
none
"
:
"
flex
"
,
md
:
"
flex
"
}}
d
isplay
=
{{
base
:
selectedChat
?
"
none
"
:
"
flex
"
,
md
:
"
flex
"
}}
flexDir
=
"
column
"
alignItems
=
"
center
"
p
=
{
3
}
...
...
@@ -61,23 +60,25 @@ const MyChats = () => {
px
=
{
3
}
fontSize
=
{{
base
:
"
28px
"
,
md
:
"
30px
"
}}
fontFamily
=
"
Work sans
"
d
=
"
flex
"
d
isplay
=
"
flex
"
w
=
"
100%
"
justifyContent
=
"
space-between
"
alignItems
=
"
center
"
>
My
Chats
<
GroupChatModal
>
<
Button
d
=
"
flex
"
d
isplay
=
"
flex
"
fontSize
=
{{
base
:
"
17px
"
,
md
:
"
10px
"
,
lg
:
"
17px
"
}}
rightIcon
=
{
<
AddIcon
/>
}
>
New
Organization
Chat
<
/
Button
>
New
Organization
Chat
<
/Button
>
<
/
GroupChatModal
>
<
/Box
>
<
Box
d
=
"
flex
"
d
isplay
=
"
flex
"
flexDir
=
"
column
"
p
=
{
3
}
bg
=
"
#F8F8F8
"
...
...
@@ -100,21 +101,19 @@ const MyChats = () => {
key
=
{
chat
.
_id
}
>
<
Text
>
{
!
chat
.
isGroupChat
?
getSender
(
loggedUser
,
chat
.
users
)
:
chat
.
chatName
}
{
!
chat
.
isGoupChat
?
getSender
(
loggedUser
,
chat
.
users
):
chat
.
chatName
}
<
/Text
>
<
/Box
>
))}
<
/Stack
>
):
(
<
ChatLoading
/>
<
ChatLoading
/>
)}
<
/Box
>
<
/Box
>
<
/Box
>
);
};
export
default
MyChats
;
\ No newline at end of file
export
default
MyChats
;
IT18021080/Telemedicine-Chat-App/frontend/src/components/UserAvatar/UserListItem.js
View file @
da4148ab
import
{
Box
,
Text
}
from
"
@chakra-ui/layout
"
;
import
{
Avatar
}
from
"
@chakra-ui/react
"
;
import
{
Avatar
,
Box
,
Text
}
from
"
@chakra-ui/react
"
;
import
React
from
"
react
"
;
import
{
ChatState
}
from
"
../../Context/ChatProvider
"
;
const
UserListItem
=
({
user
,
handleFunction
})
=>
{
const
UserListItem
=
({
user
,
handleFunction
})
=>
{
return
(
<
Box
onClick
=
{
handleFunction
}
cursor
=
"
pointer
"
bg
=
"
#E8E8E8
"
_hover
=
{{
background
:
"
#38BAC
"
,
background
:
"
#38B
2
AC
"
,
color
:
"
white
"
,
}}
w
=
"
100%
"
d
=
"
flex
"
alignItems
=
"
center
"
color
=
"
black
"
px
=
{
3
}
...
...
@@ -32,7 +29,6 @@ const UserListItem = ({user, handleFunction }) => {
cursor
=
"
pointer
"
name
=
{
user
.
name
}
src
=
{
user
.
pic
}
/
>
<
Box
>
<
Text
>
{
user
.
name
}
<
/Text
>
...
...
@@ -47,4 +43,4 @@ const UserListItem = ({user, handleFunction }) => {
);
};
export
default
UserListItem
;
\ No newline at end of file
export
default
UserListItem
\ No newline at end of file
IT18021080/Telemedicine-Chat-App/frontend/src/components/miscellaneous/GroupChatModal.js
0 → 100644
View file @
da4148ab
import
React
,
{
useState
}
from
"
react
"
;
import
{
useDisclosure
,
Modal
,
ModalBody
,
ModalCloseButton
,
ModalContent
,
ModalFooter
,
ModalHeader
,
ModalOverlay
,
Button
,
useToast
,
FormControl
,
Input
}
from
"
@chakra-ui/react
"
;
import
{
ChatState
}
from
"
../../Context/ChatProvider
"
;
import
axios
from
"
axios
"
;
import
UserListItem
from
"
../UserAvatar/UserListItem
"
;
const
GroupChatModal
=
({
children
})
=>
{
const
{
isOpen
,
onOpen
,
onClose
}
=
useDisclosure
();
const
[
groupChatName
,
setGroupChatName
]
=
useState
();
const
[
selectedUsers
,
setSelectedUsers
]
=
useState
([]);
const
[
search
,
setSearch
]
=
useState
(
""
);
const
[
searchResult
,
setSearchResult
]
=
useState
([]);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
toast
=
useToast
();
const
{
user
,
chats
,
setChats
}
=
ChatState
();
const
handleSearch
=
async
(
query
)
=>
{
setSearch
(
query
);
if
(
!
query
){
return
;
}
try
{
setLoading
(
true
);
const
config
=
{
headers
:
{
Authorization
:
`Bearer
${
user
.
token
}
`
,
},
};
const
{
data
}
=
await
axios
.
get
(
`/api/user?search=
${
search
}
`
,
config
);
console
.
log
(
data
);
setLoading
(
false
);
setSearchResult
(
data
);
}
catch
(
error
)
{
toast
({
title
:
"
Error Occured!
"
,
description
:
"
Failed to Load the Search Result
"
,
status
:
"
error
"
,
duration
:
5000
,
isClosable
:
true
,
position
:
"
bottom-left
"
,
});
}
};
const
handleSubmit
=
()
=>
{
};
const
handleGroup
=
()
=>
{
};
return
(
<>
<
span
onClick
=
{
onOpen
}
>
{
children
}
<
/span
>
<
Modal
isOpen
=
{
isOpen
}
onClose
=
{
onClose
}
>
<
ModalOverlay
/>
<
ModalContent
>
<
ModalHeader
fontSize
=
"
35px
"
fontFamily
=
"
Work sans
"
display
=
"
flex
"
justifyContent
=
"
center
"
>
Create
Organization
Chat
<
/ModalHeader
>
<
ModalCloseButton
/>
<
ModalBody
display
=
"
flex
"
flexDir
=
"
column
"
alignItems
=
"
center
"
>
<
FormControl
>
<
Input
placeholder
=
"
Organization Name
"
marginBottom
=
{
3
}
onChange
=
{(
e
)
=>
setGroupChatName
(
e
.
target
.
value
)}
/>
<
/FormControl
>
<
FormControl
>
<
Input
placeholder
=
"
Add Users eg:Doctors,Mining Engineers,Emergency Units
"
marginBottom
=
{
1
}
onChange
=
{(
e
)
=>
handleSearch
(
e
.
target
.
value
)}
/>
<
/FormControl
>
{
/* selected users */
}
{
loading
?
(
<
div
>
loading
<
/div
>
)
:
(
searchResult
?.
slice
(
0
,
4
)
.
map
((
user
)
=>
(
<
UserListItem
key
=
{
user
.
_id
}
user
=
{
user
}
handleFunction
=
{()
=>
handleGroup
(
user
)}
/
>
))
)}
<
/ModalBody
>
<
ModalFooter
>
<
Button
colorScheme
=
"
blue
"
onClick
=
{
handleSubmit
}
>
Create
Organization
<
/Button
>
<
/ModalFooter
>
<
/ModalContent
>
<
/Modal
>
<
/
>
);
};
export
default
GroupChatModal
;
\ No newline at end of file
IT18021080/Telemedicine-Chat-App/frontend/src/components/miscellaneous/ProfileModal.js
View file @
da4148ab
import
{
ViewIcon
}
from
"
@chakra-ui/icons
"
;
import
{
useDisclosure
}
from
"
@chakra-ui/react
"
;
import
React
from
"
react
"
;
import
{
IconButton
}
from
"
@chakra-ui/button
"
;
import
{
Modal
}
from
"
@chakra-ui/react
"
;
import
{
ModalOverlay
}
from
"
@chakra-ui/react
"
;
import
{
ModalContent
}
from
"
@chakra-ui/react
"
;
import
{
ModalHeader
}
from
"
@chakra-ui/react
"
;
import
{
ModalCloseButton
}
from
"
@chakra-ui/react
"
;
import
{
ModalBody
}
from
"
@chakra-ui/react
"
;
import
{
Button
}
from
"
@chakra-ui/button
"
;
import
{
ModalFooter
}
from
"
@chakra-ui/react
"
;
import
{
Image
,
Text
}
from
"
@chakra-ui/react
"
;
import
{
ViewIcon
}
from
"
@chakra-ui/icons
"
;
import
{
useDisclosure
,
IconButton
,
Modal
,
ModalOverlay
,
ModalContent
,
ModalHeader
,
ModalCloseButton
,
ModalBody
,
Button
,
ModalFooter
,
Image
,
Text
}
from
"
@chakra-ui/react
"
;
...
...
@@ -72,4 +64,4 @@ const ProfileModal = ({user, children}) => {
);
};
export
default
ProfileModal
;
\ No newline at end of file
export
default
ProfileModal
;
IT18021080/Telemedicine-Chat-App/frontend/src/components/miscellaneous/SideDrawer.js
View file @
da4148ab
import
{
Tooltip
,
Menu
,
MenuButton
,
MenuList
,
Avatar
,
MenuItem
,
MenuDivider
,
Drawer
,
useDisclosure
,
DrawerOverlay
,
DrawerContent
,
DrawerHeader
,
DrawerBody
,
Input
,
useToast
,
Spinner
,
}
from
"
@chakra-ui/react
"
;
//import React from "react";
import
{
Tooltip
,
Menu
,
MenuButton
,
MenuList
,
Avatar
,
MenuItem
,
MenuDivider
,
Box
,
Text
,
Button
,
Drawer
,
useDisclosure
,
DrawerOverlay
,
DrawerContent
,
DrawerHeader
,
DrawerBody
,
Input
,
useToast
,
Spinner
}
from
"
@chakra-ui/react
"
;
import
React
,
{
useState
}
from
"
react
"
;
import
{
BellIcon
,
ChevronDownIcon
}
from
"
@chakra-ui/icons
"
;
import
{
Box
,
Text
}
from
"
@chakra-ui/layout
"
;
import
{
Button
}
from
"
@chakra-ui/button
"
;
import
{
ChatState
}
from
"
../../Context/ChatProvider
"
;
import
ProfileModal
from
"
./ProfileModal
"
;
import
{
useHistory
}
from
"
react-router-dom
"
;
import
axios
from
"
axios
"
;
import
ChatLoading
from
"
../ChatLoading
"
;
import
axios
from
"
axios
"
;
import
UserListItem
from
"
../UserAvatar/UserListItem
"
;
const
SideDrawer
=
()
=>
{
const
[
search
,
setSearch
]
=
useState
(
""
);
const
[
searchResult
,
setSearchResult
]
=
useState
([]);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
loadingChat
,
setLoadingChat
]
=
useState
();
const
{
user
,
setSelectedChat
,
chats
,
setChats
}
=
ChatState
();
const
{
user
,
setSelectedChat
,
chats
,
setChats
}
=
ChatState
();
const
history
=
useHistory
();
const
{
isOpen
,
onOpen
,
onClose
}
=
useDisclosure
();
const
logoutHandler
=
()
=>
{
localStorage
.
removeItem
(
"
userInfo
"
);
history
.
push
(
"
/
"
);
localStorage
.
removeItem
(
"
userInfo
"
);
history
.
push
(
"
/
"
);
};
const
toast
=
useToast
();
const
handleSearch
=
async
()
=>
{
const
handleSearch
=
async
()
=>
{
if
(
!
search
)
{
toast
({
title
:
"
Please Enter something in search
"
,
...
...
@@ -59,7 +43,7 @@ const SideDrawer = () => {
}
try
{
setLoading
(
true
)
setLoading
(
true
)
;
const
config
=
{
headers
:
{
...
...
@@ -68,7 +52,7 @@ const SideDrawer = () => {
};
const
{
data
}
=
await
axios
.
get
(
`/api/user?search=
${
search
}
`
,
config
);
setLoading
(
false
);
setSearchResult
(
data
);
}
catch
(
error
)
{
...
...
@@ -82,20 +66,21 @@ const SideDrawer = () => {
});
}
};
const
accessChat
=
async
(
userId
)
=>
{
const
accessChat
=
async
(
userId
)
=>
{
try
{
setLoadingChat
(
true
);
const
config
=
{
headers
:
{
"
Content-type
"
:
"
application/json
"
,
"
Content-type
"
:
"
application/json
"
,
Authorization
:
`Bearer
${
user
.
token
}
`
,
},
};
const
{
data
}
=
await
axios
.
post
(
"
/api/chat
"
,
{
userId
},
config
);
if
(
!
chats
.
find
((
c
)
=>
c
.
_id
===
data
.
_id
))
setChats
([
data
,
...
chats
]);
//normal find function in java scripts
//normal find function in java script
if
(
!
chats
.
find
((
c
)
=>
c
.
_id
===
data
.
_id
))
setChats
([
data
,
...
chats
]);
setSelectedChat
(
data
);
setLoadingChat
(
false
);
...
...
@@ -105,30 +90,26 @@ const SideDrawer = () => {
title
:
"
Error fetching the chat
"
,
description
:
error
.
message
,
status
:
"
error
"
,
duration
:
5000
,
duration
:
"
5000
"
,
isClosable
:
true
,
position
:
"
bottom-left
"
,
});
}
};
};
return
(
<>
<>
<
Box
d
=
"
flex
"
d
isplay
=
"
flex
"
justifyContent
=
"
space-between
"
alignItems
=
"
center
"
bg
=
"
white
"
w
=
"
100%
"
p
=
"
5px 10px 5px 10px
"
bg
Color
=
"
white
"
w
idth
=
"
100%
"
p
adding
=
"
5px 10px 5px 10px
"
borderWidth
=
"
5px
"
>
<
Tooltip
label
=
"
Search User to chat
"
hasArrow
placement
=
"
bottom-end
"
>
<
Tooltip
label
=
"
Search User to chat
"
hasArrow
placement
=
"
bottom-end
"
>
<
Button
variant
=
"
ghost
"
onClick
=
{
onOpen
}
>
<
i
class
=
"
fas fa-search
"
><
/i
>
<
Text
d
=
{{
base
:
"
none
"
,
md
:
"
flex
"
}}
px
=
"
4
"
>
...
...
@@ -174,19 +155,17 @@ const SideDrawer = () => {
<
DrawerOverlay
/>
<
DrawerContent
>
<
DrawerHeader
borderBottomWidth
=
"
1px
"
>
Search
User
<
/DrawerHeader
>
<
DrawerBody
>
<
Box
d
=
"
flex
"
pb
=
{
2
}
>
<
DrawerBody
>
<
Box
d
isplay
=
"
flex
"
paddingBottom
=
{
2
}
>
<
Input
placeholder
=
"
Search by name or email
"
m
r
=
{
2
}
m
argin
=
{
2
}
value
=
{
search
}
onChange
=
{(
e
)
=>
setSearch
(
e
.
target
.
value
)}
/
>
<
Button
onClick
=
{
handleSearch
}
>
Go
<
/Button
>
>
Go
<
/Button
>
<
/Box
>
{
loading
?
<
ChatLoading
/>
:
(
...
...
@@ -199,13 +178,14 @@ const SideDrawer = () => {
))
)
}
{
loadingChat
&&
<
Spinner
ml
=
"
auto
"
d
=
"
flex
"
/>
}
{
loadingChat
&&
<
Spinner
ml
=
"
auto
"
d
isplay
=
"
flex
"
/>
}
<
/DrawerBody
>
<
/DrawerContent
>
<
/Drawer
>
<
/
>
);
};
export
default
SideDrawer
;
\ No newline at end of file
export
default
SideDrawer
;
IT18021080/Telemedicine-Chat-App/frontend/src/config/ChatLogics.js
View file @
da4148ab
export
const
getSender
=
(
loggedUser
,
users
)
=>
{
//if it is not a organization chat nelow logic will helpfull
return
users
[
0
].
_id
===
loggedUser
.
_id
?
users
[
1
].
name
:
users
[
0
].
name
;
};
\ No newline at end of file
IT18021080/Telemedicine-Chat-App/frontend/src/index.js
View file @
da4148ab
...
...
@@ -7,15 +7,19 @@ import { BrowserRouter } from "react-router-dom";
import
ChatProvider
from
"
./Context/ChatProvider
"
;
ReactDOM
.
render
(
<
ChatProvider
>
<
BrowserRouter
>
<
ChakraProvider
>
<
App
/>
<
/ChakraProvider
>
<
/BrowserRouter
>
<
/ChatProvider>
,
document
.
getElementById
(
"
root
"
)
//rendering everything on root tag
);
IT18021080/Telemedicine-Chat-App/package-lock.json
View file @
da4148ab
This diff is collapsed.
Click to expand it.
IT18021080/Telemedicine-Chat-App/package.json
View file @
da4148ab
{
"name"
:
"
tele-medicine
"
,
"name"
:
"
miner-doc
"
,
"version"
:
"1.0.0"
,
"description"
:
""
,
"main"
:
"server.js"
,
...
...
@@ -9,8 +9,13 @@
"author"
:
"Minosh Balasuriya"
,
"license"
:
"ISC"
,
"dependencies"
:
{
"dotenv"
:
"^16.0.0"
,
"express"
:
"^4.17.3"
,
"nodemon"
:
"^2.0.15"
"bcryptjs"
:
"^2.4.3"
,
"colors"
:
"^1.4.0"
,
"dotenv"
:
"^16.0.1"
,
"express"
:
"^4.18.1"
,
"express-async-handler"
:
"^1.2.0"
,
"jsonwebtoken"
:
"^8.5.1"
,
"mongoose"
:
"^6.3.3"
,
"nodemon"
:
"^2.0.16"
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment