├── .gitignore ├── README.md ├── netlify.toml ├── package-lock.json ├── package.json ├── public ├── index.html ├── logo.png ├── manifest.json └── robots.txt └── src ├── App.js ├── Data └── Home.js ├── assets ├── friends.png ├── groups.png ├── messenger.png ├── no_feed.svg └── selectFriends.svg ├── components ├── Auth │ ├── LoginForm.js │ ├── RecentAccount │ │ ├── AccountCard.js │ │ ├── AddAccount.js │ │ ├── LoginCard.js │ │ └── RecentAccounts.js │ ├── SignupForm.js │ └── hooks │ │ ├── useLoginUser.js │ │ └── useSignupUser.js ├── Chat │ ├── FriendNotSelected.js │ ├── Friends.js │ ├── MessageTextArea.js │ └── Messages.js ├── Comment │ ├── Comment.js │ └── CommentTextArea.js ├── Friends │ ├── Friend.js │ ├── MyFriendLists.js │ ├── SearchFriends.js │ ├── UserLists.js │ └── styles.js ├── InputField.js ├── Loader.js ├── Navbar │ ├── BottomNav.js │ ├── CreatePostMenu.js │ ├── DrawerBar.js │ ├── MiddleMenu.js │ ├── Navbar.js │ ├── ProfileMenu.js │ ├── RightMenu.js │ └── styles.js ├── NotificationMenu.js ├── PeopleYouMayKnow.js ├── Post │ ├── LikePost.js │ ├── Post.js │ ├── PostContent.js │ ├── PostFooter.js │ ├── PostForm │ │ ├── PostDialog │ │ │ ├── CameraField.js │ │ │ ├── CustomHeaderText.js │ │ │ ├── DialogHeader.js │ │ │ ├── FeelingsCard.js │ │ │ ├── FileField.js │ │ │ ├── LocationField.js │ │ │ ├── PostFormCard.js │ │ │ ├── PreviewImage.js │ │ │ └── TagUserCard.js │ │ └── WritePostCard.js │ ├── PostSubContent.js │ ├── Posts.js │ └── hooks │ │ └── useCreatePost.js ├── Profile │ ├── Friends.js │ ├── Photos.js │ ├── PopoverProfile.js │ ├── PopoverProfileCard.js │ ├── ProfileHeader.js │ ├── ProfileTimeline.js │ ├── UpdateCoverImage.js │ ├── UpdateProfileImage.js │ └── UserProfile.js ├── Search.js ├── Sidebar.js ├── UI │ ├── AvartarText.js │ ├── DialogLoading.js │ ├── GoogleMap.js │ └── StyledBadge.js └── settings │ ├── Blocking.js │ ├── General.js │ ├── General │ └── EditInput.js │ ├── Location.js │ ├── Location │ └── EditLocation.js │ ├── Privacy.js │ ├── SecurityAndLogin.js │ ├── SecurityAndLogin │ └── EditPassword.js │ └── TrigoInformation.js ├── context ├── ChatContext.js ├── PostContext.js ├── UIContext.js └── UserContext.js ├── firebase └── firebase.js ├── hooks ├── useCreateComment.js ├── useFetchComments.js ├── useFetchPost.js ├── useFriendActions.js ├── useLocationService.js ├── useSearchFriends.js ├── useSendMessage.js ├── useTheme.js ├── useUpdateProfile.js └── useUpdateProfilePic.js ├── index.css ├── index.js ├── screens ├── Auth.js ├── Friends.js ├── Home.js ├── Messenger.js ├── Post.js ├── Profile.js └── Settings.js ├── services ├── AuthService.js ├── ChatService.js ├── PostServices.js └── UserServices.js └── utils ├── FilterArray.js └── ProtectedRoute.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | .env.local 18 | .env.development 19 | .env.test.local 20 | .env.production 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # Local Netlify folder 27 | .netlify -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "CI= npm run build" 3 | publish = "build" 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "facebook-clone-app-react-client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/fontawesome-svg-core": "^1.2.30", 7 | "@fortawesome/free-brands-svg-icons": "^5.14.0", 8 | "@fortawesome/free-regular-svg-icons": "^5.14.0", 9 | "@fortawesome/free-solid-svg-icons": "^5.14.0", 10 | "@fortawesome/react-fontawesome": "^0.1.11", 11 | "@material-ui/core": "^4.11.0", 12 | "@material-ui/icons": "^4.9.1", 13 | "@material-ui/lab": "^4.0.0-alpha.56", 14 | "axios": "^0.20.0", 15 | "classnames": "^2.2.6", 16 | "dotenv": "^8.2.0", 17 | "emoji-picker-react": "^3.2.4", 18 | "firebase": "^7.22.0", 19 | "jwt-decode": "^3.0.0", 20 | "moment": "^2.29.1", 21 | "react": "^16.13.1", 22 | "react-dom": "^16.13.1", 23 | "react-eva-icons": "0.0.8", 24 | "react-hook-google-maps": "0.0.3", 25 | "react-router-dom": "^5.2.0", 26 | "react-scripts": "3.4.1", 27 | "socket.io-client": "^2.3.1", 28 | "words-to-numbers": "^1.5.1" 29 | }, 30 | "scripts": { 31 | "start": "react-scripts start", 32 | "build": "react-scripts build", 33 | "test": "react-scripts test", 34 | "eject": "react-scripts eject" 35 | }, 36 | "eslintConfig": { 37 | "extends": "react-app" 38 | }, 39 | "browserslist": { 40 | "production": [ 41 | ">0.2%", 42 | "not dead", 43 | "not op_mini all" 44 | ], 45 | "development": [ 46 | "last 1 chrome version", 47 | "last 1 firefox version", 48 | "last 1 safari version" 49 | ] 50 | }, 51 | "devDependencies": {} 52 | } 53 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Facebook Clone 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harshmangalam/facebook-clone-app-react-client/4831ea375b710bf63477cc67ac2147b2c6e960a5/public/logo.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "logo.png", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/Data/Home.js: -------------------------------------------------------------------------------- 1 | export const homeLeftItems = [ 2 | { title: 'Friends', img: 'friends.png', to: '/friends' }, 3 | { title: 'Messenger', img: 'messenger.png', to: '/messenger' }, 4 | ] 5 | -------------------------------------------------------------------------------- /src/assets/friends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harshmangalam/facebook-clone-app-react-client/4831ea375b710bf63477cc67ac2147b2c6e960a5/src/assets/friends.png -------------------------------------------------------------------------------- /src/assets/groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harshmangalam/facebook-clone-app-react-client/4831ea375b710bf63477cc67ac2147b2c6e960a5/src/assets/groups.png -------------------------------------------------------------------------------- /src/assets/messenger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harshmangalam/facebook-clone-app-react-client/4831ea375b710bf63477cc67ac2147b2c6e960a5/src/assets/messenger.png -------------------------------------------------------------------------------- /src/assets/no_feed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/selectFriends.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/components/Auth/LoginForm.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useEffect } from 'react' 2 | 3 | import { 4 | Button, 5 | CircularProgress, 6 | FormControl, 7 | TextField, 8 | } from '@material-ui/core' 9 | 10 | import useLoginUser from './hooks/useLoginUser' 11 | 12 | function LoginForm() { 13 | const { 14 | loading, 15 | error, 16 | handleLoginUser, 17 | handlePasswordChange, 18 | handleEmailChange, 19 | } = useLoginUser() 20 | 21 | return ( 22 | 23 |
24 | 25 | 32 | 33 | 34 | 35 | 44 | 45 | 66 |
67 |
68 | ) 69 | } 70 | 71 | export default LoginForm 72 | -------------------------------------------------------------------------------- /src/components/Auth/RecentAccount/AccountCard.js: -------------------------------------------------------------------------------- 1 | import { 2 | Badge, 3 | Card, 4 | CardActionArea, 5 | CardHeader, 6 | CardMedia, 7 | IconButton, 8 | Typography, 9 | } from '@material-ui/core' 10 | import { UserContext, UIContext } from '../../../App' 11 | 12 | import { Close, Notifications } from '@material-ui/icons' 13 | import React, { useContext, useState } from 'react' 14 | import AvartarText from '../../UI/AvartarText' 15 | import LoginCard from './LoginCard' 16 | 17 | function AccountCard({ account }) { 18 | const { userState, userDispatch } = useContext(UserContext) 19 | const { uiDispatch } = useContext(UIContext) 20 | 21 | const [loginOpen, setLoginOpen] = React.useState(false) 22 | const [userData, setUserData] = useState(null) 23 | const handleRemoveAccount = (account_id) => { 24 | userDispatch({ type: 'REMOVE_ACCOUNT', payload: account_id }) 25 | uiDispatch({ 26 | type: 'SET_MESSAGE', 27 | payload: { 28 | color: 'success', 29 | text: 'Account removed', 30 | display: true, 31 | }, 32 | }) 33 | } 34 | 35 | const handleClickOpen = (account_id) => { 36 | const user = userState.recentAccounts.find( 37 | (account) => account.id == account_id, 38 | ) 39 | 40 | if (user) { 41 | setUserData(user) 42 | setLoginOpen(true) 43 | } 44 | } 45 | return ( 46 | <> 47 | 48 | handleClickOpen(account.id)}> 49 | {account.profile_pic ? ( 50 | 54 | ) : ( 55 | 64 | 70 | 71 | )} 72 | 75 | 76 | 77 | } 78 | subheader={ 79 | 80 | {account.name.slice(0, 6)}.. 81 | 82 | } 83 | /> 84 | 85 | handleRemoveAccount(account.id)} 87 | size="small" 88 | style={{ 89 | position: 'absolute', 90 | background: 'tomato', 91 | color: '#fff', 92 | top: 0, 93 | right: 0, 94 | }} 95 | > 96 | 97 | 98 | 99 | 100 | {loginOpen && ( 101 | 107 | )} 108 | 109 | ) 110 | } 111 | 112 | export default AccountCard 113 | -------------------------------------------------------------------------------- /src/components/Auth/RecentAccount/AddAccount.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Card, 4 | CardActionArea, 5 | CardContent, 6 | CardHeader, 7 | CardMedia, 8 | Dialog, 9 | IconButton, 10 | Typography, 11 | } from '@material-ui/core' 12 | import { Add, Close } from '@material-ui/icons' 13 | import React, { useContext } from 'react' 14 | import { UIContext } from '../../../App' 15 | import LoginForm from '../LoginForm' 16 | 17 | function AddAccount() { 18 | const [addAccount, handleAddAccount] = React.useState(false) 19 | const {uiState} = useContext(UIContext) 20 | return ( 21 | <> 22 | 23 | handleAddAccount(true)}> 24 | 33 | 41 | 42 | 43 | 44 | 45 | Add Account 46 | 47 | 48 | 49 | {addAccount && ( 50 | handleAddAccount(false)} 58 | style={{ width: '100%' }} 59 | > 60 | 61 | 64 | Add Accounts 65 | 66 | } 67 | action={ 68 | handleAddAccount(false)} 71 | > 72 | 73 | 74 | } 75 | /> 76 | 77 | 78 | 79 | 80 | 81 | 82 | )} 83 | 84 | 85 | 86 | ) 87 | } 88 | 89 | export default AddAccount 90 | -------------------------------------------------------------------------------- /src/components/Auth/RecentAccount/LoginCard.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Button, 4 | Card, 5 | CardContent, 6 | CardHeader, 7 | CardMedia, 8 | CircularProgress, 9 | Dialog, 10 | FormControl, 11 | IconButton, 12 | TextField, 13 | Typography, 14 | } from '@material-ui/core' 15 | import { Close } from '@material-ui/icons' 16 | import React, { useState } from 'react' 17 | import AvartarText from '../../UI/AvartarText' 18 | import useLoginUser from '../hooks/useLoginUser' 19 | 20 | function LoginCard({ account, loginOpen, setLoginOpen, userData }) { 21 | const { 22 | loading, 23 | error, 24 | handleLoginUser, 25 | handlePasswordChange, 26 | } = useLoginUser(userData) 27 | 28 | return ( 29 | setLoginOpen(false)} 37 | style={{ width: '100%' }} 38 | > 39 | 40 | setLoginOpen(false)} 45 | > 46 | 47 | 48 | } 49 | /> 50 | 51 | {account.profile_pic ? ( 52 | 61 | 62 | 63 | ) : ( 64 | 72 | 78 | 79 | )} 80 | 81 |
90 | 97 | {userData && userData.name} 98 | 99 |
100 |
101 | 102 | 111 | 112 | 133 |
134 |
135 |
136 |
137 | ) 138 | } 139 | 140 | export default LoginCard 141 | -------------------------------------------------------------------------------- /src/components/Auth/RecentAccount/RecentAccounts.js: -------------------------------------------------------------------------------- 1 | import { Grid } from '@material-ui/core' 2 | 3 | import { UserContext } from '../../../App' 4 | 5 | import React, { useContext } from 'react' 6 | 7 | import AccountCard from './AccountCard' 8 | import AddAccount from './AddAccount' 9 | 10 | function RecentAccounts() { 11 | const { userState } = useContext(UserContext) 12 | 13 | return ( 14 | <> 15 | 16 | {userState.recentAccounts.map((account) => ( 17 | 18 | 19 | 20 | ))} 21 | 22 | 23 | 24 | 25 | 26 | ) 27 | } 28 | 29 | export default RecentAccounts 30 | -------------------------------------------------------------------------------- /src/components/Auth/SignupForm.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useEffect } from 'react' 2 | 3 | import { 4 | Button, 5 | CircularProgress, 6 | FormControl, 7 | TextField, 8 | } from '@material-ui/core' 9 | 10 | import useSignupUser from './hooks/useSignupUser' 11 | 12 | function LoginForm() { 13 | const { 14 | loading, 15 | error, 16 | handleSignupUser, 17 | handleNameChange, 18 | handlePasswordChange, 19 | handleEmailChange, 20 | } = useSignupUser() 21 | 22 | return ( 23 | 24 |
25 | 26 | 34 | 35 | 36 | 45 | 46 | 47 | 48 | 57 | 58 | 79 |
80 |
81 | ) 82 | } 83 | 84 | export default LoginForm 85 | -------------------------------------------------------------------------------- /src/components/Auth/hooks/useLoginUser.js: -------------------------------------------------------------------------------- 1 | import { useState, useContext, useEffect } from 'react' 2 | import axios from 'axios' 3 | import { UserContext, UIContext } from '../../../App' 4 | import { useHistory } from 'react-router-dom' 5 | import { fetchCurrentUser } from '../../../services/AuthService' 6 | 7 | const url = process.env.REACT_APP_ENDPOINT 8 | 9 | const useLoginUser = (userData = null) => { 10 | const { uiDispatch } = useContext(UIContext) 11 | const { userDispatch } = useContext(UserContext) 12 | 13 | const history = useHistory() 14 | 15 | const [loading, setLoading] = useState(false) 16 | const [error, setError] = useState(null) 17 | const [initialState, setInitialState] = useState({ 18 | email: '', 19 | password: '', 20 | }) 21 | 22 | useEffect(() => { 23 | 24 | setInitialState({ ...initialState, email: userData ? userData.email : '' }) 25 | return () => { 26 | 27 | } 28 | }, []) 29 | 30 | const handlePasswordChange = (e) => { 31 | setInitialState({ ...initialState, password: e.target.value }) 32 | setError({ ...error, password: '' }) 33 | } 34 | 35 | const handleEmailChange = (e) => { 36 | setInitialState({ ...initialState, email: e.target.value }) 37 | setError({ ...error, email: '' }) 38 | } 39 | 40 | async function handleLoginUser(e) { 41 | e.preventDefault() 42 | 43 | setLoading(true) 44 | try { 45 | const { data } = await axios.post(`${url}/api/auth/login`, initialState) 46 | localStorage.setItem('token', JSON.stringify(data.data.token)) 47 | const me = await fetchCurrentUser() 48 | setLoading(false) 49 | 50 | userDispatch({ type: 'SET_CURRENT_USER', payload: me.data.user }) 51 | 52 | uiDispatch({ 53 | type: 'SET_MESSAGE', 54 | payload: { color: 'success', display: true, text: data.message }, 55 | }) 56 | 57 | 58 | history.push('/home') 59 | } catch (err) { 60 | setLoading(false) 61 | 62 | console.log(err) 63 | if (err && err.response) { 64 | if (err.response.status === 422) { 65 | setError({ ...err.response.data.error }) 66 | } 67 | 68 | if (err.response.status === 400) { 69 | uiDispatch({ 70 | type: 'SET_MESSAGE', 71 | payload: { 72 | color: 'error', 73 | display: true, 74 | text: err.response.data.error, 75 | }, 76 | }) 77 | } 78 | } 79 | } 80 | } 81 | 82 | return { 83 | loading, 84 | error, 85 | handleLoginUser, 86 | handleEmailChange, 87 | handlePasswordChange, 88 | } 89 | } 90 | 91 | export default useLoginUser 92 | -------------------------------------------------------------------------------- /src/components/Auth/hooks/useSignupUser.js: -------------------------------------------------------------------------------- 1 | import { useState, useContext } from 'react' 2 | import axios from 'axios' 3 | import { UserContext, UIContext } from '../../../App' 4 | import { useHistory } from 'react-router-dom' 5 | import { fetchCurrentUser } from '../../../services/AuthService' 6 | 7 | const url = process.env.REACT_APP_ENDPOINT 8 | 9 | const useSignupUser = () => { 10 | const { uiDispatch } = useContext(UIContext) 11 | const { userDispatch } = useContext(UserContext) 12 | 13 | const history = useHistory() 14 | 15 | const [loading, setLoading] = useState(false) 16 | const [error, setError] = useState(null) 17 | const [initialState, setInitialState] = useState({ 18 | name: '', 19 | email: '', 20 | password: '', 21 | }) 22 | const handleNameChange = (e) => { 23 | setError({ ...error, name: '' }) 24 | setInitialState({ ...initialState, name: e.target.value }) 25 | } 26 | 27 | const handleEmailChange = (e) => { 28 | setError({ ...error, email: '' }) 29 | setInitialState({ ...initialState, email: e.target.value }) 30 | } 31 | 32 | const handlePasswordChange = (e) => { 33 | setInitialState({ ...initialState, password: e.target.value }) 34 | setError({ ...error, password: '' }) 35 | } 36 | 37 | async function handleSignupUser(e) { 38 | e.preventDefault() 39 | 40 | setLoading(true) 41 | try { 42 | const { data } = await axios.post(`${url}/api/auth/signup`, initialState) 43 | localStorage.setItem('token', JSON.stringify(data.data.token)) 44 | const me = await fetchCurrentUser() 45 | setLoading(false) 46 | 47 | userDispatch({ type: 'SET_CURRENT_USER', payload: me.data.user }) 48 | 49 | uiDispatch({ 50 | type: 'SET_MESSAGE', 51 | payload: { color: 'success', display: true, text: data.message }, 52 | }) 53 | 54 | 55 | history.push('/home') 56 | } catch (err) { 57 | setLoading(false) 58 | 59 | console.log(err) 60 | if (err && err.response) { 61 | if (err.response.status === 422) { 62 | setError({ ...err.response.data.error }) 63 | } 64 | 65 | if (err.response.status === 400) { 66 | uiDispatch({ 67 | type: 'SET_MESSAGE', 68 | payload: { 69 | color: 'error', 70 | display: true, 71 | text: err.response.data.error, 72 | }, 73 | }) 74 | } 75 | } 76 | } 77 | } 78 | 79 | return { 80 | loading, 81 | error, 82 | handleSignupUser, 83 | handleNameChange, 84 | handleEmailChange, 85 | handlePasswordChange, 86 | } 87 | } 88 | 89 | export default useSignupUser 90 | -------------------------------------------------------------------------------- /src/components/Chat/FriendNotSelected.js: -------------------------------------------------------------------------------- 1 | import { Avatar, Grid, Paper, Typography } from '@material-ui/core' 2 | import React from 'react' 3 | 4 | function FriendNotSelected() { 5 | return ( 6 | 20 | 21 | 25 | 26 | 27 | 28 | Select friends from friend lists to start chat 29 | 30 | 31 | ) 32 | } 33 | 34 | export default FriendNotSelected 35 | -------------------------------------------------------------------------------- /src/components/Chat/Friends.js: -------------------------------------------------------------------------------- 1 | import { 2 | List, 3 | ListItem, 4 | ListItemAvatar, 5 | ListItemText, 6 | Avatar, 7 | ListSubheader, 8 | Typography, 9 | } from '@material-ui/core' 10 | import React, { useContext } from 'react' 11 | import { UserContext, ChatContext, UIContext } from '../../App' 12 | import { fetchFriendMessages } from '../../services/ChatService' 13 | import AvartarText from '../UI/AvartarText' 14 | 15 | function Friends() { 16 | const { userState } = useContext(UserContext) 17 | const { chatDispatch } = useContext(ChatContext) 18 | const { uiState, uiDispatch } = useContext(UIContext) 19 | 20 | const handleFriendSelect = (friend) => { 21 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 22 | chatDispatch({ type: 'SET_SELECTED_FRIEND', payload: friend }) 23 | fetchFriendMessages(friend.id) 24 | .then((res) => { 25 | if (res.data) { 26 | chatDispatch({ type: 'SET_MESSAGES', payload: res.data.data }) 27 | } 28 | }) 29 | .catch((err) => console.log(err)) 30 | } 31 | return ( 32 | Your Friends} 34 | style={{ backgroundColor: uiState.darkMode && 'rgb(36,37,38)' }} 35 | > 36 | {userState.currentUser.friends && userState.currentUser.friends.length 37 | ? userState.currentUser.friends.map((friend) => { 38 | return ( 39 | handleFriendSelect(friend)} 43 | > 44 | 45 | {friend.profile_pic ? ( 46 | 47 | ) : ( 48 | 52 | )} 53 | 54 | 55 | 56 | ) 57 | }) 58 | : No Friends} 59 | 60 | ) 61 | } 62 | 63 | export default Friends 64 | -------------------------------------------------------------------------------- /src/components/Chat/MessageTextArea.js: -------------------------------------------------------------------------------- 1 | import { IconButton, InputBase, Paper, makeStyles } from '@material-ui/core' 2 | import { Send } from '@material-ui/icons' 3 | import React, { useContext, useState } from 'react' 4 | import { UIContext } from '../../App' 5 | import useSendMessage from '../../hooks/useSendMessage' 6 | 7 | const useStyles = makeStyles((theme) => ({ 8 | inputRoot: { 9 | padding: '16px 8px 16px 8px', 10 | }, 11 | inputInput: { 12 | flexGrow: 1, 13 | paddingLeft: '4px', 14 | }, 15 | })) 16 | 17 | function MessageTextArea() { 18 | const { uiState } = useContext(UIContext) 19 | const classes = useStyles() 20 | const [textMessage, setTextMessage] = useState('') 21 | 22 | const { sendMessage } = useSendMessage({ textMessage, setTextMessage }) 23 | 24 | const handleSendMessage = (e) => { 25 | e.preventDefault() 26 | sendMessage() 27 | } 28 | return ( 29 | 39 | setTextMessage(e.target.value)} 42 | placeholder="Enter Your Text..." 43 | multiline 44 | rowsMax={4} 45 | classes={{ 46 | root: classes.inputRoot, 47 | input: classes.inputInput, 48 | }} 49 | style={{ 50 | borderRadius: '20px 20px 20px 20px', 51 | backgroundColor: uiState.darkMode ? 'rgb(24,25,26)' : 'whitesmoke', 52 | width: '100%', 53 | }} 54 | /> 55 | 63 | 64 | 65 | 66 | ) 67 | } 68 | 69 | export default MessageTextArea 70 | -------------------------------------------------------------------------------- /src/components/Chat/Messages.js: -------------------------------------------------------------------------------- 1 | import { Avatar, Grid, makeStyles, Paper, Typography } from '@material-ui/core' 2 | import React, { Fragment, useContext, useEffect, useRef } from 'react' 3 | import { ChatContext, UIContext, UserContext } from '../../App' 4 | import moment from 'moment' 5 | const useStyles = makeStyles((theme) => ({ 6 | me: { 7 | padding: '8px', 8 | maxWidth: '60%', 9 | float: 'right', 10 | marginTop: '16px', 11 | }, 12 | 13 | partner: { 14 | padding: '8px', 15 | maxWidth: '60%', 16 | 17 | margin: 'auto', 18 | float: 'left', 19 | padding: '8px', 20 | marginTop: '16px', 21 | }, 22 | date: { 23 | fontSize: '12px', 24 | 25 | display: 'flex', 26 | alignItems: 'center', 27 | justifyContent: 'flex-end', 28 | padding: '8px', 29 | margin: 'auto', 30 | }, 31 | })) 32 | function Messages() { 33 | const classes = useStyles() 34 | 35 | const scrollDiv = useRef(null) 36 | 37 | const { chatState } = useContext(ChatContext) 38 | const { userState } = useContext(UserContext) 39 | const { uiState } = useContext(UIContext) 40 | 41 | useEffect(() => { 42 | scrollToBottom() 43 | }, [chatState.messages.length]) 44 | 45 | function scrollToBottom() { 46 | scrollDiv.current.scrollIntoView({ behavior: 'smooth' }) 47 | } 48 | return ( 49 | 50 | {chatState.messages.length 51 | ? chatState.messages.map((message) => ( 52 | 53 | {userState.currentUser.id !== message.sender.id ? ( 54 | 55 | 64 | {message.body.text && ( 65 | 66 | {message.body.text} 67 | 68 | )} 69 | {message.body.image && ( 70 | 71 | 76 | 77 | )} 78 | 79 | {moment(message.createdAt).fromNow()} 80 | 81 | 82 | 83 | ) : ( 84 | 91 | 100 | {message.body.text && ( 101 | 102 | {message.body.text} 103 | 104 | )} 105 | {message.body.image && ( 106 | 107 | 112 | 113 | )} 114 | 118 | {moment(message.createdAt).fromNow()} 119 | 120 | 121 | 122 | )} 123 | 124 | )) 125 | : null} 126 |
127 | 128 | ) 129 | } 130 | 131 | export default Messages 132 | -------------------------------------------------------------------------------- /src/components/Comment/Comment.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Button, 4 | Divider, 5 | Paper, 6 | Typography, 7 | List, 8 | ListItem, 9 | ListItemText, 10 | ListItemAvatar, 11 | } from '@material-ui/core' 12 | import React, { useContext } from 'react' 13 | import AvartarText from '../UI/AvartarText' 14 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 15 | import { faThumbsUp as filledLike } from '@fortawesome/free-solid-svg-icons' 16 | import { faThumbsUp } from '@fortawesome/free-regular-svg-icons' 17 | import { likeDislikeComment } from '../../services/PostServices' 18 | import { PostContext, UserContext, UIContext } from '../../App' 19 | function Comment({ comment }) { 20 | const { postDispatch } = useContext(PostContext) 21 | const { userState } = useContext(UserContext) 22 | const { uiDispatch, uiState } = useContext(UIContext) 23 | 24 | function handleLikeComment() { 25 | likeDislikeComment(comment.id).then((res) => { 26 | if (res.data) { 27 | postDispatch({ type: 'LIKE_UNLIKE_COMMENT', payload: res.data.comment }) 28 | uiDispatch({ 29 | type: 'SET_MESSAGE', 30 | payload: { color: 'success', text: res.data.message, display: true }, 31 | }) 32 | } 33 | }) 34 | } 35 | 36 | function isLiked() { 37 | return comment.likes.includes(userState.currentUser.id) 38 | } 39 | 40 | const listItems = ( 41 | 42 | 43 | {comment.user.profile_pic ? ( 44 | 45 | {comment.user.name} 50 | 51 | ) : ( 52 | 56 | )} 57 | 58 | 61 | {comment.user.name} 62 | 63 | } 64 | secondary={ 65 | <> 66 | {comment.body.text && comment.body.text} 67 | 68 | {comment.body.image && ( 69 | 70 | 74 | 79 | 80 | 81 | )} 82 | 83 | } 84 | /> 85 | 86 | ) 87 | return ( 88 |
91 | 92 | {listItems} 93 | 94 |
101 | 115 |
116 | 117 |
118 |
119 | ) 120 | } 121 | 122 | export default Comment 123 | -------------------------------------------------------------------------------- /src/components/Comment/CommentTextArea.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Grid, 4 | IconButton, 5 | LinearProgress, 6 | Paper, 7 | TextField, 8 | } from '@material-ui/core' 9 | import React, { useContext, useState } from 'react' 10 | import AvartarText from '../UI/AvartarText' 11 | import StyledBadge from '../UI/StyledBadge' 12 | import { UIContext, UserContext } from '../../App' 13 | import { SendOutlined } from '@material-ui/icons' 14 | import useCreateComment from '../../hooks/useCreateComment' 15 | function CommentTextArea({ post }) { 16 | const { userState } = useContext(UserContext) 17 | const { uiState } = useContext(UIContext) 18 | 19 | const [commentText, setCommentText] = useState('') 20 | const [commentImage, setCommentImage] = useState() 21 | const [error, setError] = useState('') 22 | 23 | const { createComment, loading } = useCreateComment({ 24 | post_id: post.id, 25 | commentText, 26 | setCommentText, 27 | setCommentImage, 28 | commentImage, 29 | setError, 30 | }) 31 | 32 | const handleCommentChange = (e) => { 33 | setError('') 34 | setCommentText(e.target.value) 35 | } 36 | 37 | return ( 38 | <> 39 | 48 | 49 | 50 | {userState.currentUser.profile_pic ? ( 51 | 52 | {userState.currentUser.name} 57 | 58 | ) : ( 59 | 60 | )} 61 | 62 | 63 | 64 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | {loading ? ( 90 | 100 | 101 | 102 | ) : null} 103 | 104 | ) 105 | } 106 | 107 | export default CommentTextArea 108 | -------------------------------------------------------------------------------- /src/components/Friends/Friend.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext } from 'react' 2 | import { 3 | Avatar, 4 | Typography, 5 | makeStyles, 6 | Card, 7 | CardActionArea, 8 | CardContent, 9 | } from '@material-ui/core' 10 | import { UIContext, UserContext } from '../../App' 11 | import AvartarText from '../UI/AvartarText' 12 | 13 | const useStyles = makeStyles((theme) => ({ 14 | container: { 15 | paddingLeft: '6px', 16 | paddingTop: '6px', 17 | paddingBottom: '8px', 18 | '&:hover': { background: 'whitesmoke', cursor: 'pointer' }, 19 | }, 20 | })) 21 | function Friend({ user, children }) { 22 | const { userDispatch } = useContext(UserContext) 23 | const { uiState, uiDispatch } = useContext(UIContext) 24 | const classes = useStyles() 25 | 26 | return ( 27 | 28 | 35 | { 37 | userDispatch({ type: 'ADD_SELECTED_USER_PROFILE', payload: user }) 38 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 39 | }} 40 | > 41 | 48 | {user.profile_pic ? ( 49 | 50 | 54 | 55 | ) : ( 56 | 60 | )} 61 | 62 |
69 | 73 | {user.name} 74 | 75 | {7} mutual friends 76 |
77 |
78 |
79 | 80 | {children} 81 |
82 |
83 | ) 84 | } 85 | 86 | export default Friend 87 | -------------------------------------------------------------------------------- /src/components/Friends/MyFriendLists.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Grid, 4 | List, 5 | ListItem, 6 | ListItemAvatar, 7 | ListItemText, 8 | ListSubheader, 9 | Typography, 10 | } from '@material-ui/core' 11 | import React, { useContext } from 'react' 12 | import { UIContext, UserContext } from '../../App' 13 | import AvartarText from '../UI/AvartarText' 14 | import StyledBadge from '../UI/StyledBadge' 15 | import PopoverProfile from '../Profile/PopoverProfile' 16 | import { Link } from 'react-router-dom' 17 | function MyFriendLists() { 18 | const { userState } = useContext(UserContext) 19 | const { uiState } = useContext(UIContext) 20 | const friendsItem = (user) => ( 21 | 22 | 23 | 24 | {user.profile_pic ? ( 25 | 26 | ) : ( 27 | 31 | )} 32 | 33 | 34 | 35 | 36 | 37 | ) 38 | return ( 39 | <> 40 | {userState.currentUser.friends && userState.currentUser.friends.length ? ( 41 | 45 | 46 | 52 | Contacts 53 | 54 | 55 | 56 | } 57 | > 58 | {userState.currentUser.friends.map((user) => ( 59 |
60 | {uiState.mdScreen ? ( 61 | {friendsItem(user)} 62 | ) : ( 63 | friendsItem(user) 64 | )} 65 |
66 | ))} 67 |
68 | ) : null} 69 | 70 | ) 71 | } 72 | 73 | export default MyFriendLists 74 | -------------------------------------------------------------------------------- /src/components/Friends/SearchFriends.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { 3 | Avatar, 4 | Button, 5 | Dialog, 6 | DialogActions, 7 | DialogContent, 8 | IconButton, 9 | List, 10 | ListItemIcon, 11 | ListItemText, 12 | TextField, 13 | Typography, 14 | ListItem, 15 | CircularProgress, 16 | } from '@material-ui/core' 17 | import { Link } from 'react-router-dom' 18 | import useSearchFriends from '../../hooks/useSearchFriends' 19 | import { Search } from '@material-ui/icons' 20 | import AvartarText from '../UI/AvartarText' 21 | 22 | function SearchFriends() { 23 | const [open, setOpen] = useState(null) 24 | const [name, setName] = useState('') 25 | const { searchFriends, friends, loading } = useSearchFriends() 26 | 27 | const handleSearch = () => { 28 | searchFriends(name) 29 | } 30 | const handleClose = () => { 31 | setOpen(false) 32 | } 33 | 34 | const handleOpen = () => { 35 | setOpen(true) 36 | } 37 | 38 | return ( 39 |
40 | 41 | 42 | 43 | 44 | 45 | setName(e.target.value)} 49 | variant="outlined" 50 | placeholder="Enter Friends Name" 51 | /> 52 | 60 | {friends.length ? ( 61 | 62 | Search Friends ({friends.length}) 63 | 64 | ) : null} 65 | {loading ? ( 66 |
74 | 75 |
76 | ) : ( 77 | 78 | {friends && 79 | friends.map((user) => ( 80 | 87 | 88 | {user.profile_pic ? ( 89 | 95 | {user.name} 101 | 102 | ) : ( 103 | 107 | )} 108 | 109 | 110 | 113 | {user.name} 114 | 115 | {user.email} 116 | 117 | 118 | ))} 119 | 120 | )} 121 |
122 | 123 | 124 | 125 |
126 |
127 | ) 128 | } 129 | 130 | export default SearchFriends 131 | -------------------------------------------------------------------------------- /src/components/Friends/UserLists.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import Friend from './Friend' 3 | import { Button, CardActions, Grid, Typography } from '@material-ui/core' 4 | import { UserContext } from '../../App' 5 | import useFriendActions from '../../hooks/useFriendActions' 6 | function UserLists({ users }) { 7 | const { userState } = useContext(UserContext) 8 | 9 | const { sendFriendRequest } = useFriendActions() 10 | 11 | const handleSendFriendRequest = (user_id) => { 12 | sendFriendRequest(user_id) 13 | } 14 | 15 | const filterUser = (user) => { 16 | let s_index = userState.sendedFriendRequests.findIndex( 17 | (request) => request.user.id == user.id, 18 | ) 19 | let r_index = userState.receivedFriendRequests.findIndex( 20 | (request) => request.user.id == user.id, 21 | ) 22 | let already_friend = userState.currentUser.friends.findIndex( 23 | (friend) => friend.id == user.id, 24 | ) 25 | let currentUser = userState.currentUser.id == user.id 26 | 27 | if ( 28 | s_index === -1 && 29 | r_index === -1 && 30 | already_friend === -1 && 31 | !currentUser 32 | ) { 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | return ( 39 |
49 | 57 | People You May Know 58 | 59 | {users && users.length 60 | ? users.map((user) => ( 61 |
62 | {filterUser(user) && ( 63 | 64 | 65 | 75 | 84 | 85 | 86 | )} 87 |
88 | )) 89 | : null} 90 |
91 | ) 92 | } 93 | 94 | export default UserLists 95 | -------------------------------------------------------------------------------- /src/components/Friends/styles.js: -------------------------------------------------------------------------------- 1 | const { makeStyles } = require("@material-ui/core"); 2 | 3 | const drawerWidth = 380; 4 | export default makeStyles((theme) => ({ 5 | drawer: { 6 | width: drawerWidth, 7 | flexShrink: 0, 8 | }, 9 | drawerPaper: { 10 | width: drawerWidth, 11 | backgroundColor: "white", 12 | boxShadow:'1px 1px 3px rgba(0,0,0,0.1)' 13 | }, 14 | drawerContainer: { 15 | overflow: "auto", 16 | }, 17 | })); 18 | -------------------------------------------------------------------------------- /src/components/InputField.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { makeStyles, InputBase } from '@material-ui/core' 3 | import { Search as SearchIcon } from '@material-ui/icons' 4 | const useStyles = makeStyles((theme) => ({ 5 | search: { 6 | position: 'relative', 7 | borderRadius: '50px 50px 50px 50px', 8 | backgroundColor: '#F0F2F5', 9 | width:'100%', 10 | marginLeft:'8px' 11 | }, 12 | 13 | searchIcon: { 14 | color: '#606770;', 15 | padding: theme.spacing(0, 2), 16 | height: '100%', 17 | position: 'absolute', 18 | display: 'flex', 19 | alignItems: 'center', 20 | justifyContent: 'center', 21 | right:0, 22 | marginLeft:'16px', 23 | cursor:"pointer" 24 | }, 25 | inputRoot: { 26 | color: 'black', 27 | width:'70%', 28 | 29 | }, 30 | inputInput: { 31 | flexGrow: 1, 32 | paddingLeft: '8px', 33 | width:'100%' 34 | 35 | 36 | }, 37 | })) 38 | function Search({ placeholder,children }) { 39 | const classes = useStyles() 40 | return ( 41 |
42 |
43 | {children} 44 |
45 | 53 |
54 | ) 55 | } 56 | 57 | export default Search 58 | -------------------------------------------------------------------------------- /src/components/Loader.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Paper, CircularProgress, Backdrop, LinearProgress } from "@material-ui/core"; 3 | function Loader() { 4 | return ( 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | ) 15 | } 16 | 17 | export default Loader 18 | -------------------------------------------------------------------------------- /src/components/Navbar/BottomNav.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { BottomNavigation, Paper } from '@material-ui/core' 3 | import { UIContext } from "../../App"; 4 | import MiddleMenu from './MiddleMenu' 5 | 6 | function BottomNav() { 7 | const {uiState} = useContext(UIContext) 8 | return ( 9 | 13 | 23 | 24 | 25 | 26 | ) 27 | } 28 | 29 | export default BottomNav 30 | -------------------------------------------------------------------------------- /src/components/Navbar/CreatePostMenu.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react' 2 | import { UIContext } from '../../App' 3 | import { useHistory } from 'react-router-dom' 4 | import { 5 | Menu, 6 | IconButton, 7 | List, 8 | ListItem, 9 | ListItemIcon, 10 | ListItemText, 11 | ListSubheader, 12 | Typography, 13 | Avatar, 14 | useTheme, 15 | useMediaQuery, 16 | } from '@material-ui/core' 17 | import { 18 | Add as AddIcon, 19 | PostAdd as PostIcon, 20 | } from '@material-ui/icons' 21 | 22 | function CreatePostMenu() { 23 | const history = useHistory() 24 | const { uiState, uiDispatch } = useContext(UIContext) 25 | 26 | const [postMenu, setPostMenu] = useState(null) 27 | const theme = useTheme() 28 | const xsScreen = useMediaQuery(theme.breakpoints.only('xs')) 29 | 30 | const handlePostOpen = () => { 31 | history.push('/') 32 | uiDispatch({ type: 'SET_POST_MODEL', payload: true }) 33 | setPostMenu(null) 34 | } 35 | return ( 36 |
37 | setPostMenu(e.currentTarget)} 44 | > 45 | 48 | 49 | 50 | setPostMenu(null)} 56 | style={{ marginTop: '50px' }} 57 | elevation={7} 58 | > 59 | 60 | 63 | 64 | Create 65 | 66 | 67 | } 68 | > 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | Post 82 | 88 | Share a Post on News Feed 89 | 90 | 91 | 92 | 93 | 94 | 95 |
96 | ) 97 | } 98 | 99 | export default CreatePostMenu 100 | -------------------------------------------------------------------------------- /src/components/Navbar/DrawerBar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { UIContext } from '../../App' 3 | import { makeStyles } from '@material-ui/core/styles' 4 | import Drawer from '@material-ui/core/Drawer' 5 | import Toolbar from '@material-ui/core/Toolbar' 6 | import { Button } from '@material-ui/core' 7 | 8 | const drawerWidth = '100vw' 9 | 10 | const useStyles = makeStyles((theme) => ({ 11 | root: { 12 | display: 'flex', 13 | }, 14 | 15 | drawer: { 16 | width: drawerWidth, 17 | flexShrink: 0, 18 | }, 19 | drawerPaper: (darkMode) => ({ 20 | width: drawerWidth, 21 | backgroundColor: darkMode && 'rgb(36,37,38)', 22 | }), 23 | })) 24 | 25 | export default function DrawerBar({ children }) { 26 | const { uiState, uiDispatch } = useContext(UIContext) 27 | const classes = useStyles(uiState.darkMode) 28 | 29 | return ( 30 |
31 | uiDispatch({ type: 'SET_DRAWER', payload: false })} 39 | > 40 | 41 |
{children}
42 | 51 |
52 |
53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /src/components/Navbar/MiddleMenu.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { NavLink, useLocation } from 'react-router-dom' 3 | import { Button } from '@material-ui/core' 4 | 5 | import useStyles from './styles' 6 | 7 | import { Home, HomeOutlined, Person, PersonOutlined } from '@material-ui/icons' 8 | 9 | function MiddleMenu() { 10 | const classes = useStyles() 11 | const location = useLocation() 12 | 13 | return ( 14 | 15 | 32 | 44 | 45 | ) 46 | } 47 | 48 | export default MiddleMenu 49 | -------------------------------------------------------------------------------- /src/components/Navbar/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext } from 'react' 2 | import { UIContext, UserContext } from '../../App' 3 | import useStyles from './styles' 4 | import MiddleMenu from './MiddleMenu' 5 | import RightMenu from './RightMenu' 6 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 7 | import { faFacebook } from '@fortawesome/free-brands-svg-icons' 8 | import { 9 | AppBar, 10 | Toolbar, 11 | IconButton, 12 | useMediaQuery, 13 | useTheme, 14 | Tooltip, 15 | } from '@material-ui/core' 16 | import {Menu as MenuIcon } from '@material-ui/icons' 17 | import SearchFriends from '../Friends/SearchFriends' 18 | function Navbar() { 19 | const { uiState, uiDispatch } = useContext(UIContext) 20 | const classes = useStyles() 21 | const theme = useTheme() 22 | const match = useMediaQuery(theme.breakpoints.between(960, 1400)) 23 | const xsScreen = useMediaQuery(theme.breakpoints.only('xs')) 24 | 25 | return ( 26 | 27 | 38 | 39 |
40 | 50 | 51 | 52 | 53 | 54 | 55 | {!uiState.mdScreen && uiState.navDrawerMenu && ( 56 | 64 | 66 | uiDispatch({ type: 'SET_DRAWER', payload: !uiState.drawer }) 67 | } 68 | > 69 | 70 | 71 | 72 | )} 73 |
74 | 75 | {uiState.mdScreen && ( 76 |
77 | 78 |
79 | )} 80 |
81 | 82 |
83 |
84 |
85 |
86 | ) 87 | } 88 | 89 | export default Navbar 90 | -------------------------------------------------------------------------------- /src/components/Navbar/RightMenu.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext } from 'react' 2 | import { NavLink } from 'react-router-dom' 3 | import { UIContext, UserContext } from '../../App' 4 | 5 | import { 6 | Chip, 7 | Avatar, 8 | IconButton, 9 | Badge, 10 | useMediaQuery, 11 | useTheme, 12 | } from '@material-ui/core' 13 | import useStyles from './styles' 14 | 15 | import { faFacebookMessenger } from '@fortawesome/free-brands-svg-icons' 16 | import { faBell } from '@fortawesome/free-regular-svg-icons' 17 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 18 | import ProfileMenu from './ProfileMenu' 19 | import CreatePostMenu from './CreatePostMenu' 20 | import AvartarText from '../UI/AvartarText' 21 | import NotificationMenu from '../NotificationMenu' 22 | function RightMenu() { 23 | const classes = useStyles() 24 | const { uiState } = useContext(UIContext) 25 | const { userState } = useContext(UserContext) 26 | const theme = useTheme() 27 | const xsScreen = useMediaQuery(theme.breakpoints.only('xs')) 28 | 29 | const defaultPropsNotif = { 30 | color: 'error', 31 | children: , 32 | } 33 | 34 | return ( 35 | 36 | {uiState.mdScreen && ( 37 | 43 | {userState.currentUser.name.split(' ')[0].slice(0, 5) + '..'} 44 | 45 | } 46 | className={classes.profile_chip} 47 | avatar={ 48 | userState.currentUser.profile_pic ? ( 49 | 50 | ) : ( 51 | 55 | ) 56 | } 57 | /> 58 | )} 59 | 60 | 61 | 71 | 75 | 76 | 77 | 82 | 83 | 84 | 85 | 86 | ) 87 | } 88 | 89 | export default RightMenu 90 | -------------------------------------------------------------------------------- /src/components/Navbar/styles.js: -------------------------------------------------------------------------------- 1 | import { makeStyles, fade } from '@material-ui/core' 2 | 3 | const drawerWidth = 380 4 | export default makeStyles((theme) => ({ 5 | root: { 6 | flexGrow: 1, 7 | zIndex: theme.zIndex.drawer + 1, 8 | }, 9 | 10 | leftMenu: { 11 | flexGrow: 1, 12 | display: 'flex', 13 | flexDirection: 'row', 14 | alignItems: 'center', 15 | }, 16 | 17 | logoImg: { 18 | width: theme.spacing(7), 19 | height: theme.spacing(7), 20 | }, 21 | 22 | middleMenu: { 23 | flexGrow: 5, 24 | display: 'flex', 25 | flexDirection: 'row', 26 | alignItems: 'center', 27 | justifyContent: 'center', 28 | }, 29 | 30 | buttonItemMiddle: { 31 | width: 'auto', 32 | height: 'auto', 33 | padding: '10px 50px 10px 50px', 34 | borderRadius: '10px 10px 10px 10px', 35 | }, 36 | 37 | activeBtn: { 38 | borderBottom: '4px solid #3578E5', 39 | borderRadius: '0px', 40 | background: 'transparent', 41 | }, 42 | 43 | rightMenu: { 44 | flexGrow: 2, 45 | display: 'flex', 46 | flexDirection: 'row', 47 | justifyContent: 'flex-end', 48 | alignItems: 'center', 49 | }, 50 | 51 | profile_chip: { 52 | paddingTop: '16px', 53 | paddingBottom: '16px', 54 | '&:hover': { 55 | cursor: 'pointer', 56 | }, 57 | }, 58 | })) 59 | -------------------------------------------------------------------------------- /src/components/NotificationMenu.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react' 2 | import { UIContext } from '../App' 3 | import moment from 'moment' 4 | import { 5 | Menu, 6 | IconButton, 7 | List, 8 | ListItem, 9 | ListItemIcon, 10 | ListItemText, 11 | ListSubheader, 12 | Typography, 13 | Avatar, 14 | useTheme, 15 | useMediaQuery, 16 | } from '@material-ui/core' 17 | import { 18 | DeleteOutlined, 19 | Notifications as NotificationIcon, 20 | } from '@material-ui/icons' 21 | import useUpdateProfile from '../hooks/useUpdateProfile' 22 | 23 | function NotificationMenu({ children }) { 24 | const { uiState } = useContext(UIContext) 25 | const [menu, setMenu] = useState(null) 26 | const theme = useTheme() 27 | const xsScreen = useMediaQuery(theme.breakpoints.only('xs')) 28 | 29 | const { clearNotification } = useUpdateProfile() 30 | return ( 31 |
32 | setMenu(e.currentTarget)} 39 | > 40 | {children} 41 | 42 | 43 | setMenu(null)} 49 | style={{ marginTop: '50px' }} 50 | elevation={7} 51 | > 52 | 61 | 62 | Notifications 63 | 64 | {uiState.notifications.length ? ( 65 | clearNotification()}> 66 | 67 | 68 | ) : null} 69 | 70 | } 71 | > 72 | {uiState.notifications ? ( 73 | uiState.notifications.map((notification) => ( 74 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | {notification.body} 88 | 89 | 96 | {moment(notification.createdAt).fromNow()} 97 | 98 | 99 | 100 | )) 101 | ) : ( 102 | 103 | 104 | 105 | No Notifications 106 | 107 | 108 | 109 | )} 110 | 111 | 112 |
113 | ) 114 | } 115 | 116 | export default NotificationMenu 117 | -------------------------------------------------------------------------------- /src/components/PeopleYouMayKnow.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { 3 | Paper, 4 | Avatar, 5 | Typography, 6 | Button, 7 | Grid, 8 | Card, 9 | CardMedia, 10 | CardContent, 11 | IconButton, 12 | } from '@material-ui/core' 13 | import { UIContext, UserContext } from '../App' 14 | import { 15 | MoreHoriz as MoreHorizIcon, 16 | PeopleAlt as PeopleAltIcon, 17 | } from '@material-ui/icons' 18 | import AvartarText from './UI/AvartarText' 19 | function PeopleYouMayKnow({ users }) { 20 | const { userState } = useContext(UserContext) 21 | 22 | return ( 23 | 24 | 25 | 26 | 33 | People You may Know 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 49 | {users.map((user) => ( 50 | 51 | 52 | {user.profile_pic && ( 53 | 58 | )} 59 | 60 | 61 | {user.name} 62 | 63 | {user.friends && user.friends.length 64 | ? user.friends.map((friend) => ( 65 |
66 | {friend.profile_pic ? ( 67 | 72 | ) : ( 73 | 78 | )} 79 | 80 | 86 | {user.friends.length} friends 87 | 88 |
89 | )) 90 | : null} 91 |
92 |
93 |
94 |
95 | ))} 96 |
97 |
98 | ) 99 | } 100 | 101 | export default PeopleYouMayKnow 102 | -------------------------------------------------------------------------------- /src/components/Post/LikePost.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext } from 'react' 2 | import { Button } from '@material-ui/core' 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 4 | import { faThumbsUp } from '@fortawesome/free-regular-svg-icons' 5 | import {faThumbsUp as filledLike} from "@fortawesome/free-solid-svg-icons"; 6 | 7 | import { PostContext, UIContext, UserContext } from '../../App' 8 | import { likeDislikePost } from '../../services/PostServices' 9 | 10 | 11 | function LikePost({ post }) { 12 | 13 | const { postDispatch } = useContext(PostContext) 14 | const { uiDispatch } = useContext(UIContext) 15 | const { userState } = useContext(UserContext) 16 | 17 | const isLiked = () => { 18 | return post.likes.includes(userState.currentUser.id) 19 | } 20 | const handleLike = () => { 21 | likeDislikePost(post.id) 22 | .then((res) => { 23 | if (res.data) { 24 | postDispatch({ 25 | type: 'LIKE_UNLIKE_POST', 26 | payload: res.data.post, 27 | }) 28 | uiDispatch({ 29 | type: 'SET_MESSAGE', 30 | payload: { 31 | color: 'success', 32 | text: res.data.message, 33 | display: true, 34 | }, 35 | }) 36 | } 37 | if (res.error) { 38 | uiDispatch({ 39 | type: 'SET_MESSAGE', 40 | payload: { 41 | color: 'error', 42 | text: res.data.error, 43 | display: true, 44 | }, 45 | }) 46 | } 47 | }) 48 | .catch((err) => console.log(err)) 49 | } 50 | 51 | return ( 52 | 53 | 67 | 68 | ) 69 | } 70 | 71 | 72 | export default LikePost 73 | -------------------------------------------------------------------------------- /src/components/Post/Post.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react' 2 | import moment from 'moment' 3 | import { 4 | Avatar, 5 | Card, 6 | CardHeader, 7 | IconButton, 8 | Typography, 9 | } from '@material-ui/core' 10 | import PostContent from './PostContent' 11 | import PostFooter from './PostFooter' 12 | import AvartarText from '../UI/AvartarText' 13 | import { MoreHoriz } from '@material-ui/icons' 14 | import { UIContext } from '../../App' 15 | 16 | function Post({ post }) { 17 | const { uiState } = useContext(UIContext) 18 | return ( 19 | 25 | 29 | 33 | 34 | ) : ( 35 | 39 | ) 40 | } 41 | action={ 42 | 43 | 44 | 45 | } 46 | title={ 47 | post && ( 48 | 49 | {post.user.name} 50 | 51 | ) 52 | } 53 | subheader={post && moment(post.createdAt).fromNow()} 54 | /> 55 | 56 | 57 | 58 | ) 59 | } 60 | 61 | export default Post 62 | -------------------------------------------------------------------------------- /src/components/Post/PostContent.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext } from 'react' 2 | import { UIContext } from "../../App"; 3 | import { 4 | CardContent, 5 | CardMedia, 6 | Typography, 7 | Avatar, 8 | Divider, 9 | useTheme, 10 | useMediaQuery, 11 | } from '@material-ui/core' 12 | import PostSubContent from './PostSubContent' 13 | 14 | function PostContent({ post }) { 15 | const {uiState} = useContext(UIContext) 16 | function isContent() { 17 | return ( 18 | post.body.feelings || 19 | post.body.with.length || 20 | post.body.at || 21 | post.body.date 22 | ) 23 | } 24 | const theme = useTheme() 25 | const xsScreen = useMediaQuery(theme.breakpoints.only('xs')) 26 | return ( 27 | 28 | {isContent() && ( 29 | 36 | 37 | 38 | )} 39 | 40 | 43 | {post.content && post.content} 44 | 45 | 46 | {post.image && ( 47 | 53 | )} 54 | {Object.keys(post.profilePostData).length ? ( 55 | <> 56 | 61 | 62 | 74 | {post.profilePostData.profileImage} 80 | 81 | 82 | ) : null} 83 | 84 | 85 | ) 86 | } 87 | 88 | export default PostContent 89 | -------------------------------------------------------------------------------- /src/components/Post/PostFooter.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from 'react' 2 | import { Link } from 'react-router-dom' 3 | import { Button, Typography, Divider, Grid } from '@material-ui/core' 4 | 5 | import LikePost from './LikePost' 6 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 7 | import { faThumbsUp, faPaperPlane } from '@fortawesome/free-regular-svg-icons' 8 | import { UserContext } from '../../App' 9 | 10 | function PostFooter({ post }) { 11 | const { userState } = useContext(UserContext) 12 | 13 | useEffect(() => { 14 | filterLike() 15 | }, [post.likes.length]) 16 | 17 | const filterLike = () => { 18 | let users = userState.currentUser.friends.filter((friend) => 19 | post.likes.includes(friend.id), 20 | ) 21 | if (post.likes.includes(userState.currentUser.id)) { 22 | users.push(userState.currentUser) 23 | } 24 | 25 | return users.slice(0, 4) 26 | } 27 | 28 | return ( 29 |
30 |
39 | 49 | 56 | {filterLike().length ? ( 57 | <> 58 | {filterLike().map((user) => ( 59 | {user.name} , 60 | ))} ... 61 | 62 | ) : null} 63 | 64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 82 | 83 | 84 |
85 | ) 86 | } 87 | 88 | export default PostFooter 89 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/CustomHeaderText.js: -------------------------------------------------------------------------------- 1 | import { Avatar, Typography } from '@material-ui/core' 2 | import React from 'react' 3 | import AvartarText from '../../../UI/AvartarText' 4 | 5 | function CustomHeaderText({ userState, body }) { 6 | function filterUserById(user_id) { 7 | return userState.users.find((usr) => usr.id == user_id) 8 | } 9 | return ( 10 | 11 | 12 | {userState.currentUser.name} 13 | {body.feelings ? ( 14 | <> 15 |   is feeling {body.feelings} 16 | 17 | ) : null} 18 | {body.with.length ? ( 19 | <> 20 | {` with `} 21 | 22 | {body.with.map((u) => ( 23 | <>  {filterUserById(u).name}, 24 | ))} 25 | 26 | 27 | ) : null} 28 | {body.at ? ( 29 | <> 30 | {` at `} {body.at} 31 | 32 | ) : null} 33 | {body.date ? ( 34 | <> 35 | {new Date(body.date).toLocaleDateString()} 36 | 37 | ) : null} 38 | 39 | ) 40 | } 41 | 42 | export default CustomHeaderText 43 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/DialogHeader.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | CardHeader, 4 | DialogContent, 5 | IconButton, 6 | Paper, 7 | Typography, 8 | } from '@material-ui/core' 9 | import { Close } from '@material-ui/icons' 10 | import React from 'react' 11 | import AvartarText from '../../../UI/AvartarText' 12 | import CustomHeaderText from './CustomHeaderText' 13 | 14 | function DialogHeader({ userState, handleCloseDialog, body }) { 15 | return ( 16 |
17 | 21 | 25 | 26 | ) : ( 27 | 28 | ) 29 | } 30 | title={ 31 | <> 32 | 33 | {userState.currentUser.name} 34 | 35 | 36 | } 37 | action={ 38 | handleCloseDialog()}> 39 | 40 | 41 | } 42 | /> 43 | 44 | 50 | 51 | 52 | 53 |
54 | ) 55 | } 56 | 57 | export default DialogHeader 58 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/FeelingsCard.js: -------------------------------------------------------------------------------- 1 | import { faSmile } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { 4 | Button, 5 | CardHeader, 6 | Container, 7 | Dialog, 8 | DialogContent, 9 | Grid, 10 | IconButton, 11 | TextField, 12 | Tooltip, 13 | Typography, 14 | } from '@material-ui/core' 15 | import { ArrowBack } from '@material-ui/icons' 16 | import React, { useState } from 'react' 17 | 18 | function FeelingsCard({ body, setBody }) { 19 | const [open, setOpen] = useState(false) 20 | return ( 21 | <> 22 | 23 | setOpen(true)}> 24 | 25 | 26 | 27 | 28 | setOpen(false)} 34 | style={{ width: '100%' }} 35 | > 36 | setOpen(false)}> 39 | 40 | 41 | } 42 | subheader={ 43 | 44 | Express Your Feelings 45 | 46 | } 47 | /> 48 | 49 | 50 | 51 | 52 | 53 | 58 | setBody({ ...body, feelings: e.target.value }) 59 | } 60 | style={{ width: '100%' }} 61 | /> 62 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ) 81 | } 82 | 83 | export default FeelingsCard 84 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/FileField.js: -------------------------------------------------------------------------------- 1 | import { faImage } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { IconButton, Tooltip } from '@material-ui/core' 4 | import React from 'react' 5 | 6 | function FileField({fileRef}) { 7 | 8 | 9 | const handleImageClick = (e) => { 10 | e.preventDefault() 11 | fileRef.current.click() 12 | } 13 | 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | } 22 | 23 | export default FileField 24 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/LocationField.js: -------------------------------------------------------------------------------- 1 | import { faMap, faSmile } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import { 4 | Button, 5 | CardHeader, 6 | Container, 7 | Dialog, 8 | DialogContent, 9 | Grid, 10 | IconButton, 11 | TextField, 12 | Tooltip, 13 | Typography, 14 | } from '@material-ui/core' 15 | import { ArrowBack } from '@material-ui/icons' 16 | import React, { useState } from 'react' 17 | 18 | function LocationField({ body, setBody }) { 19 | const [open, setOpen] = useState(false) 20 | return ( 21 | <> 22 | 23 | setOpen(true)}> 24 | 25 | 26 | 27 | 28 | setOpen(false)} 36 | style={{ width: '100%' }} 37 | > 38 | setOpen(false)}> 41 | 42 | 43 | } 44 | subheader={ 45 | 46 | Add your Places 47 | 48 | } 49 | /> 50 | 51 | 52 | 53 | 54 | 55 | setBody({ ...body, at: e.target.value })} 60 | style={{ width: '100%' }} 61 | /> 62 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ) 81 | } 82 | 83 | export default LocationField 84 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/PreviewImage.js: -------------------------------------------------------------------------------- 1 | import { Avatar, CardMedia, IconButton } from '@material-ui/core' 2 | import { Close } from '@material-ui/icons' 3 | import React from 'react' 4 | 5 | function PreviewImage({ previewImage, removeFileImage }) { 6 | return ( 7 | <> 8 | 12 |
22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | ) 30 | } 31 | 32 | export default PreviewImage 33 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/PostDialog/TagUserCard.js: -------------------------------------------------------------------------------- 1 | import { faUserTag } from '@fortawesome/free-solid-svg-icons' 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 3 | import React, { useContext, useState } from 'react' 4 | import { 5 | Button, 6 | CardHeader, 7 | Checkbox, 8 | Container, 9 | DialogContent, 10 | 11 | Grid, 12 | IconButton, 13 | List, 14 | ListItem, 15 | ListItemIcon, 16 | ListItemSecondaryAction, 17 | ListItemText, 18 | 19 | Tooltip, 20 | Dialog, 21 | Typography, 22 | } from '@material-ui/core' 23 | import { UserContext } from '../../../../App' 24 | import { ArrowBack } from '@material-ui/icons' 25 | 26 | 27 | function TagUserCard({ body, setBody }) { 28 | const [open, setOpen] = useState(false) 29 | const { userState } = useContext(UserContext) 30 | const [checked, setChecked] = React.useState([]) 31 | 32 | const handleToggle = (value) => () => { 33 | const currentIndex = checked.indexOf(value) 34 | const newChecked = [...checked] 35 | 36 | if (currentIndex === -1) { 37 | newChecked.push(value) 38 | } else { 39 | newChecked.splice(currentIndex, 1) 40 | } 41 | 42 | setChecked(newChecked) 43 | } 44 | return ( 45 | <> 46 | 47 | { 49 | setOpen(true) 50 | }} 51 | > 52 | 53 | 54 | 55 | 56 | setOpen(false)} 64 | style={{ width: '100%' }} 65 | > 66 | setOpen(false)}> 69 | 70 | 71 | } 72 | subheader={ 73 | 74 | Express Your Feelings 75 | 76 | } 77 | /> 78 | 79 | 80 | 81 | 82 | 83 | {userState.users.length 84 | ? userState.users.map((user) => ( 85 | 90 | 91 | 98 | 99 | 100 | 101 | 109 | 110 | 111 | )) 112 | : null} 113 | 114 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | ) 136 | } 137 | 138 | export default TagUserCard 139 | -------------------------------------------------------------------------------- /src/components/Post/PostForm/WritePostCard.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { UIContext, UserContext } from '../../../App' 3 | 4 | import { Paper, Avatar } from '@material-ui/core' 5 | 6 | import PostFormCard from './PostDialog/PostFormCard' 7 | import AvartarText from '../../UI/AvartarText' 8 | 9 | function PostCard({ user }) { 10 | const { userState } = useContext(UserContext) 11 | const { uiState } = useContext(UIContext) 12 | 13 | return ( 14 |
15 | 22 |
29 | {userState.currentUser.profile_pic ? ( 30 | 31 | 36 | 37 | ) : ( 38 | 42 | )} 43 |
46 | 47 |
48 |
49 |
50 |
51 | ) 52 | } 53 | 54 | export default PostCard 55 | -------------------------------------------------------------------------------- /src/components/Post/PostSubContent.js: -------------------------------------------------------------------------------- 1 | import { Typography } from '@material-ui/core' 2 | import React from 'react' 3 | 4 | function PostSubContent({ post }) { 5 | const isContent = () => { 6 | return ( 7 | post.body.feelings || 8 | post.body.with.length || 9 | post.body.at || 10 | post.body.date 11 | ) 12 | } 13 | return ( 14 |
15 | 16 | {isContent() && post.user.name} 17 | {post.body.feelings ? ( 18 | <> 19 |   is feeling {post.body.feelings} 20 | 21 | ) : null} 22 | {post.body.with.length ? ( 23 | <> 24 | {` with `} 25 | 26 | {post.body.with.map((u) => ( 27 |  {u.name}, 28 | ))} 29 | 30 | 31 | ) : null} 32 | {post.body.at ? ( 33 | <> 34 | {` at `} {post.body.at} 35 | 36 | ) : null} 37 | {post.body.date ? ( 38 | <> 39 | {new Date(post.body.date).toLocaleDateString()} 40 | 41 | ) : null} 42 | 43 |
44 | ) 45 | } 46 | 47 | export default PostSubContent 48 | -------------------------------------------------------------------------------- /src/components/Post/Posts.js: -------------------------------------------------------------------------------- 1 | import { Button, Typography } from '@material-ui/core' 2 | import React, { useContext } from 'react' 3 | import { PostContext } from '../../App' 4 | import useFetchPost from '../../hooks/useFetchPost' 5 | import Post from './Post' 6 | 7 | function Posts({ posts }) { 8 | const { postState } = useContext(PostContext) 9 | 10 | const { fetchPosts } = useFetchPost() 11 | 12 | const handleFetchPosts = () => { 13 | fetchPosts() 14 | } 15 | return ( 16 |
17 | {posts.length 18 | ? posts.map((post) => ( 19 |
20 | 21 |
22 | )) 23 | : null} 24 | 25 |
28 | {postState.postPagination.totalPage <= 29 | postState.postPagination.currentPage ? ( 30 | 31 | No more posts 32 | 33 | ) : ( 34 | 41 | )} 42 |
43 |
44 | ) 45 | } 46 | 47 | export default Posts 48 | -------------------------------------------------------------------------------- /src/components/Post/hooks/useCreatePost.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { UIContext, PostContext } from '../../../App' 4 | import { useHistory } from 'react-router-dom' 5 | import { storage } from '../../../firebase/firebase' 6 | const url = process.env.REACT_APP_ENDPOINT 7 | 8 | const useCreatePost = ({ 9 | postData, 10 | body, 11 | isImageCaptured, 12 | postImage, 13 | blob, 14 | }) => { 15 | const history = useHistory() 16 | 17 | const [loading, setLoading] = useState(false) 18 | const { uiDispatch } = useContext(UIContext) 19 | const { postDispatch } = useContext(PostContext) 20 | 21 | const createPost = async (data) => { 22 | setLoading(true) 23 | let token = localStorage.token && JSON.parse(localStorage.getItem('token')) 24 | try { 25 | const response = await axios.post(`${url}/api/post/`, data, { 26 | headers: { 27 | Authorization: `Bearer ${token}`, 28 | }, 29 | }) 30 | 31 | setLoading(false) 32 | postDispatch({ type: 'ADD_POST', payload: response.data.post }) 33 | uiDispatch({ 34 | type: 'SET_MESSAGE', 35 | payload: { 36 | color: 'success', 37 | display: true, 38 | text: response.data.message, 39 | }, 40 | }) 41 | uiDispatch({ type: 'SET_POST_MODEL', payload: false }) 42 | history.push('/') 43 | } catch (err) { 44 | setLoading(false) 45 | if (err && err.response) { 46 | uiDispatch({ 47 | type: 'SET_MESSAGE', 48 | payload: { 49 | display: true, 50 | text: err.response.data.error, 51 | color: 'error', 52 | }, 53 | }) 54 | } 55 | console.log(err) 56 | } 57 | } 58 | 59 | const createUserPost = async (uri = '') => { 60 | await createPost({ 61 | ...postData, 62 | image: uri ? uri : '', 63 | body: { 64 | ...body, 65 | }, 66 | }) 67 | } 68 | 69 | const handleSubmitPost = (e) => { 70 | e.preventDefault() 71 | 72 | if (isImageCaptured) { 73 | let filename = `post/post-${Date.now()}.png` 74 | const task = storage.ref(`images/${filename}`).put(blob) 75 | 76 | task.on( 77 | 'state_changed', 78 | 79 | function () { 80 | setLoading(true) 81 | }, 82 | function (error) { 83 | console.log('error from firebase') 84 | setLoading(false) 85 | uiDispatch({ type: 'SET_POST_MODEL', payload: false }) 86 | }, 87 | function () { 88 | storage 89 | .ref('images') 90 | .child(filename) 91 | .getDownloadURL() 92 | .then((uri) => { 93 | createUserPost(uri) 94 | setLoading(false) 95 | }) 96 | }, 97 | ) 98 | } else if (postImage) { 99 | let filename = `post/post-${Date.now()}-${postImage.name}` 100 | const uploadTask = storage.ref(`images/${filename}`).put(postImage) 101 | uploadTask.on( 102 | 'state_changed', 103 | () => { 104 | setLoading(true) 105 | }, 106 | (err) => { 107 | console.log('error from firebase') 108 | setLoading(false) 109 | uiDispatch({ type: 'SET_POST_MODEL', payload: false }) 110 | }, 111 | () => { 112 | storage 113 | .ref('images') 114 | .child(filename) 115 | .getDownloadURL() 116 | .then((uri) => { 117 | createUserPost(uri) 118 | }) 119 | }, 120 | ) 121 | } else { 122 | createUserPost() 123 | } 124 | } 125 | return { 126 | handleSubmitPost, 127 | loading, 128 | } 129 | } 130 | 131 | export default useCreatePost 132 | -------------------------------------------------------------------------------- /src/components/Profile/Friends.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Paper, Grid, Typography, Button, Avatar } from '@material-ui/core' 3 | import AvartarText from '../UI/AvartarText' 4 | 5 | function Friends({ user }) { 6 | return ( 7 | 8 | {user.friends && 9 | user.friends.map((friend) => ( 10 | 11 | 19 | {friend.profile_pic ? ( 20 | 21 | ) : ( 22 | 27 | )} 28 | 33 | {friend.name} 34 | 35 | 40 | {friend.email} 41 | 42 | 52 | 53 | 54 | ))} 55 | 56 | ) 57 | } 58 | 59 | export default Friends 60 | -------------------------------------------------------------------------------- /src/components/Profile/Photos.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Paper, Grid, Avatar, Typography, Button } from '@material-ui/core' 3 | 4 | function Photos() { 5 | return ( 6 | 7 | 8 | 9 | Photos 10 | 11 | 12 | 13 | 14 | 15 | 22 | {[...new Array(6)].map((photo) => ( 23 | 24 | 25 | 30 | 31 | 32 | ))} 33 | 34 | 35 | ) 36 | } 37 | 38 | export default Photos 39 | -------------------------------------------------------------------------------- /src/components/Profile/PopoverProfile.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Popover from '@material-ui/core/Popover' 3 | import Typography from '@material-ui/core/Typography' 4 | import { makeStyles } from '@material-ui/core/styles' 5 | import PopoverProfileCard from "./PopoverProfileCard" 6 | const useStyles = makeStyles((theme) => ({ 7 | popover: { 8 | pointerEvents: 'none', 9 | }, 10 | paper: { 11 | padding: theme.spacing(1), 12 | }, 13 | })) 14 | 15 | export default function MouseOverPopover({ children,user }) { 16 | const classes = useStyles() 17 | const [anchorEl, setAnchorEl] = React.useState(null) 18 | 19 | const handlePopoverOpen = (event) => { 20 | setAnchorEl(event.currentTarget) 21 | } 22 | 23 | const handlePopoverClose = () => { 24 | setAnchorEl(null) 25 | } 26 | 27 | const open = Boolean(anchorEl) 28 | 29 | return ( 30 |
31 |
37 | {children} 38 |
39 | 58 | 59 | 60 |
61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /src/components/Profile/PopoverProfileCard.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Card, 4 | CardActions, 5 | CardHeader, 6 | Chip, 7 | Grid, 8 | Typography, 9 | } from '@material-ui/core' 10 | import React from 'react' 11 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 12 | import StyledBadge from '../UI/StyledBadge' 13 | import AvartarText from '../UI/AvartarText' 14 | 15 | import { 16 | faMapMarkerAlt, 17 | faUserGraduate, 18 | faUsers, 19 | } from '@fortawesome/free-solid-svg-icons' 20 | function PopoverProfileCard({ user }) { 21 | return ( 22 | 23 | 30 | 35 | 36 | ) : ( 37 | 41 | 46 | 47 | ) 48 | } 49 | title={ 50 | 53 | {user.name} 54 | 55 | } 56 | subheader={ 57 | <> 58 | {user.location && ( 59 | 60 | 61 | 68 | 69 | 70 | 71 | 72 | 73 | {user.location.city || user.location.region} 74 | 75 | 76 | 77 | )} 78 | {user.education && ( 79 | 85 | 86 | 93 | 94 | 95 | 96 | 97 | 98 | {user.education} 99 | 100 | 101 | 102 | )} 103 | 104 | } 105 | /> 106 | 107 | 108 | 109 | } 111 | size="medium" 112 | color="primary" 113 | label={`Friends ${user.friends.length}`} 114 | /> 115 | 116 | 117 | 118 | ) 119 | } 120 | 121 | export default PopoverProfileCard 122 | -------------------------------------------------------------------------------- /src/components/Profile/ProfileHeader.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { Paper, Typography, makeStyles, Grid, Button } from '@material-ui/core' 3 | import UpdateProfileImage from './UpdateProfileImage' 4 | import UpdateCoverImage from './UpdateCoverImage' 5 | import { UserContext } from '../../App' 6 | const useStyles = makeStyles((theme) => ({ 7 | paper: { 8 | width: '100%', 9 | height: '40vh', 10 | marginTop: '60px', 11 | position: 'relative', 12 | backgroundRepeat: 'no-repeat', 13 | backgroundPosition: 'center', 14 | backgroundSize: '100% 40vh', 15 | }, 16 | 17 | overlay: { 18 | position: 'absolute', 19 | background: 'rgba(0,0,0,0.5)', 20 | width: '100%', 21 | height: '40vh', 22 | top: 0, 23 | }, 24 | })) 25 | function ProfileHeader({ user }) { 26 | const { userState } = useContext(UserContext) 27 | const classes = useStyles() 28 | return ( 29 |
30 | 31 | 32 | 41 | 42 | {userState.currentUser.id == user.id && ( 43 | <> 44 | 45 | 46 | )} 47 |
48 |
49 |
50 |
51 | 57 | 70 | 71 | {user.name} 72 | 73 | 74 | 75 | 76 |
77 | ) 78 | } 79 | 80 | export default ProfileHeader 81 | -------------------------------------------------------------------------------- /src/components/Profile/ProfileTimeline.js: -------------------------------------------------------------------------------- 1 | import { Grid} from '@material-ui/core' 2 | import React, { useContext } from 'react' 3 | import WritePostCard from '../Post/PostForm/WritePostCard' 4 | import { UserContext, PostContext } from '../../App' 5 | import Posts from '../Post/Posts' 6 | 7 | 8 | function ProfileTimeline({ user }) { 9 | const { userState } = useContext(UserContext) 10 | const { postState } = useContext(PostContext) 11 | 12 | const getUserPost = () => { 13 | return postState.posts.filter((post) => post.user.id == user.id) 14 | } 15 | return ( 16 | 17 | 18 | {userState.currentUser.id == user.id && } 19 | 20 | 21 | 22 | ) 23 | } 24 | 25 | export default ProfileTimeline 26 | -------------------------------------------------------------------------------- /src/components/Profile/UpdateCoverImage.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Button, 4 | DialogActions, 5 | DialogTitle, 6 | IconButton, 7 | Dialog, 8 | DialogContent, 9 | } from '@material-ui/core' 10 | import React, { useState, useRef } from 'react' 11 | import { CameraAlt as CameraIcon } from '@material-ui/icons' 12 | import useUpdateProfilePic from '../../hooks/useUpdateProfilePic' 13 | import DialogLoading from '../UI/DialogLoading' 14 | import { useHistory } from 'react-router-dom' 15 | function UpdateCoverImage() { 16 | const history = useHistory() 17 | const [coverPic, setCoverPic] = useState(null) 18 | const [previewImage, setPreviewImage] = useState(null) 19 | const [menu, setMenu] = useState(false) 20 | 21 | const inputFileRef = useRef(null) 22 | 23 | const { updateCoverPic, loading } = useUpdateProfilePic({ 24 | cover_pic: coverPic, 25 | history 26 | }) 27 | 28 | const handleImageChange = (e) => { 29 | setCoverPic(e.target.files[0]) 30 | const reader = new FileReader() 31 | reader.readAsDataURL(e.target.files[0]) 32 | reader.onload = () => { 33 | setPreviewImage(reader.result) 34 | setMenu(true) 35 | } 36 | } 37 | 38 | const handleImageClick = () => { 39 | inputFileRef.current.click() 40 | } 41 | 42 | const handleUpload = () => { 43 | updateCoverPic() 44 | handleCancel() 45 | } 46 | 47 | const handleCancel = () => { 48 | setCoverPic(null) 49 | setPreviewImage(null) 50 | setMenu(false) 51 | } 52 | 53 | return ( 54 |
55 | 59 | 60 | 61 | 62 | 63 | 64 | {loading && ( 65 | 66 | )} 67 | 68 | 75 | 76 | setMenu(false)} 84 | style={{ width: '100%' }} 85 | > 86 | Cover Picture 87 | 88 | {previewImage && ( 89 | preview 90 | )} 91 | 92 | 93 | 96 | 103 | 104 | 105 |
106 | ) 107 | } 108 | 109 | export default UpdateCoverImage 110 | -------------------------------------------------------------------------------- /src/components/Profile/UpdateProfileImage.js: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Badge, 4 | Button, 5 | DialogActions, 6 | DialogTitle, 7 | IconButton, 8 | Dialog, 9 | DialogContent, 10 | } from '@material-ui/core' 11 | import { useHistory } from 'react-router-dom' 12 | 13 | import React, { useContext, useRef, useState } from 'react' 14 | import AvartarText from '../UI/AvartarText' 15 | import useUpdateProfilePic from '../../hooks/useUpdateProfilePic' 16 | import { CameraAlt as CameraIcon } from '@material-ui/icons' 17 | import DialogLoading from '../UI/DialogLoading' 18 | import { UserContext } from '../../App' 19 | function UpdateProfileImage({ user }) { 20 | const {userState} = useContext(UserContext) 21 | const history = useHistory() 22 | const [profilePic, setProfilePic] = useState(null) 23 | const [previewImage, setPreviewImage] = useState(null) 24 | const [menu, setMenu] = useState(false) 25 | 26 | const inputFileRef = useRef(null) 27 | 28 | const { updateProfilePic, loading } = useUpdateProfilePic({ 29 | profile_pic: profilePic, 30 | history, 31 | }) 32 | 33 | const handleImageChange = (e) => { 34 | setProfilePic(e.target.files[0]) 35 | const reader = new FileReader() 36 | reader.readAsDataURL(e.target.files[0]) 37 | reader.onload = () => { 38 | setPreviewImage(reader.result) 39 | setMenu(true) 40 | } 41 | } 42 | 43 | const handleImageClick = () => { 44 | inputFileRef.current.click() 45 | } 46 | 47 | const handleUpload = () => { 48 | updateProfilePic() 49 | handleCancel() 50 | } 51 | 52 | const handleCancel = () => { 53 | setProfilePic(null) 54 | setPreviewImage(null) 55 | setMenu(false) 56 | } 57 | 58 | return ( 59 |
60 | 67 | 68 | 69 | 70 | 71 | ) 72 | } 73 | style={{ 74 | position: 'absolute', 75 | bottom: -30, 76 | width: '170px', 77 | height: '170px', 78 | zIndex: 2, 79 | left: '40%', 80 | }} 81 | > 82 | {user.profile_pic ? ( 83 | 89 | {user.name} 90 | 91 | ) : ( 92 | 98 | )} 99 | 100 | 107 | setMenu(false)} 115 | style={{ width: '100%' }} 116 | > 117 | Profile Picture 118 | 119 | {previewImage && ( 120 | 121 | )} 122 | 123 | 124 | 127 | 134 | 135 | 136 | 137 | {loading && ( 138 | 139 | )} 140 |
141 | ) 142 | } 143 | 144 | export default UpdateProfileImage 145 | -------------------------------------------------------------------------------- /src/components/Profile/UserProfile.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { MoreHoriz, Edit, SearchOutlined } from '@material-ui/icons' 3 | import { Paper, AppBar, Tabs, Tab, Box, Grid, Divider } from '@material-ui/core' 4 | 5 | import ProfileHeader from './ProfileHeader' 6 | import ProfileTimeline from './ProfileTimeline' 7 | import Friends from './Friends' 8 | import { UIContext } from '../../App' 9 | 10 | function UserProfile({ user, conScreen }) { 11 | const { uiState } = useContext(UIContext) 12 | const [value, setValue] = React.useState(0) 13 | const handleChange = (event, newValue) => { 14 | setValue(newValue) 15 | } 16 | return ( 17 |
18 | 24 | 25 | 26 | 27 | 28 | 37 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 | ) 65 | } 66 | 67 | function TabPanel(props) { 68 | const { children, value, index, ...other } = props 69 | 70 | return ( 71 | 74 | ) 75 | } 76 | 77 | export default UserProfile 78 | -------------------------------------------------------------------------------- /src/components/Search.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { makeStyles, InputBase } from '@material-ui/core' 3 | import { Search as SearchIcon } from '@material-ui/icons' 4 | import { UIContext } from '../App' 5 | const useStyles = makeStyles((theme) => ({ 6 | search: { 7 | position: 'relative', 8 | borderRadius: '50px 50px 50px 50px', 9 | width: '100%', 10 | }, 11 | 12 | searchIcon: { 13 | padding: theme.spacing(0, 2), 14 | height: '100%', 15 | position: 'absolute', 16 | pointerEvents: 'none', 17 | display: 'flex', 18 | alignItems: 'center', 19 | justifyContent: 'center', 20 | }, 21 | inputRoot: { 22 | padding: '3px 10px 3px 0px', 23 | }, 24 | inputInput: { 25 | flexGrow: 1, 26 | paddingLeft: `calc(1em + ${theme.spacing(4)}px)`, 27 | }, 28 | })) 29 | function Search({ placeholder }) { 30 | const classes = useStyles() 31 | const { uiState } = useContext(UIContext) 32 | return ( 33 |
37 |
41 | 42 |
43 | 54 |
55 | ) 56 | } 57 | 58 | export default Search 59 | -------------------------------------------------------------------------------- /src/components/Sidebar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import { Drawer, Toolbar, useMediaQuery, useTheme } from '@material-ui/core' 3 | import { UIContext } from '../App' 4 | 5 | function Sidebar({ 6 | children, 7 | anchor = 'left', 8 | background = 'white', 9 | boxShadow = true, 10 | drawerWidth = 380, 11 | }) { 12 | const theme = useTheme() 13 | const matches = useMediaQuery(theme.breakpoints.between(960, 1400)) 14 | const { uiState } = useContext(UIContext) 15 | return ( 16 | 33 | 34 |
{children}
35 |
36 | ) 37 | } 38 | 39 | export default Sidebar 40 | -------------------------------------------------------------------------------- /src/components/UI/AvartarText.js: -------------------------------------------------------------------------------- 1 | import { Avatar, Typography } from '@material-ui/core' 2 | import React from 'react' 3 | 4 | function AvartarText({ text, bg, size = '40px', fontSize = '16px' }) { 5 | return ( 6 | 9 | 12 | {text.split('')[0]} 13 | 14 | 15 | ) 16 | } 17 | 18 | export default AvartarText 19 | -------------------------------------------------------------------------------- /src/components/UI/DialogLoading.js: -------------------------------------------------------------------------------- 1 | import { Dialog, LinearProgress, Paper, Typography } from '@material-ui/core' 2 | import React, { useState } from 'react' 3 | 4 | function DialogLoading({ loading, text }) { 5 | const [open, setOpen] = useState(loading) 6 | return ( 7 | setOpen(false)} 15 | style={{ width: '100%' }} 16 | > 17 | 29 | 36 | {text} 37 | 38 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default DialogLoading 45 | -------------------------------------------------------------------------------- /src/components/UI/GoogleMap.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useGoogleMaps } from 'react-hook-google-maps' 3 | function GoogleMap({coords,zoom=17}) { 4 | const { ref } = useGoogleMaps( 5 | 'AIzaSyBMZsZfaghR7UAmCwaNU4fHrnFfn7lYtFw', 6 | { 7 | center: coords, 8 | zoom, 9 | }, 10 | ) 11 | return
12 | } 13 | 14 | export default GoogleMap 15 | -------------------------------------------------------------------------------- /src/components/UI/StyledBadge.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Badge from '@material-ui/core/Badge' 3 | import { withStyles } from '@material-ui/core/styles' 4 | 5 | const UIBadge = withStyles((theme) => ({ 6 | badge: { 7 | right: 8, 8 | top: 32, 9 | border: `2px solid ${theme.palette.background.paper}`, 10 | padding: '5px 5px', 11 | borderRadius: '100%', 12 | }, 13 | }))(Badge) 14 | 15 | export default function StyledBadge({ isActive, children,border }) { 16 | return ( 17 | 22 | {children} 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /src/components/settings/Blocking.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function Blocking() { 4 | return ( 5 |
6 | Blockings 7 |
8 | ) 9 | } 10 | 11 | export default Blocking 12 | -------------------------------------------------------------------------------- /src/components/settings/General.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react' 2 | import {Divider, Grid, Typography } from '@material-ui/core' 3 | import { UserContext } from '../../App' 4 | import EditInput from './General/EditInput' 5 | import useUpdateProfile from '../../hooks/useUpdateProfile' 6 | function General() { 7 | const { userState } = useContext(UserContext) 8 | const { 9 | loading, 10 | editName, 11 | editEmail, 12 | editBio, 13 | editEducation, 14 | } = useUpdateProfile() 15 | 16 | const [name, setName] = useState(userState.currentUser.name) 17 | const [email, setEmail] = useState(userState.currentUser.email) 18 | const [bio, setBio] = useState(userState.currentUser.bio) 19 | const [education, setEducation] = useState(userState.currentUser.education) 20 | 21 | const handleEditName = () => { 22 | editName(name) 23 | } 24 | const handleEditEmail = () => { 25 | editEmail(email) 26 | } 27 | const handleEditBio = () => { 28 | editBio(bio) 29 | } 30 | 31 | const handleEditEducation = () => { 32 | editEducation(education) 33 | } 34 | return ( 35 |
36 | 44 | General Account Setting 45 | 46 | 47 |
48 | 49 | 50 | Name 51 | 52 | 53 | 54 | {userState.currentUser.name} 55 | 56 | 57 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Email 72 | 73 | 74 | 75 | {userState.currentUser.email} 76 | 77 | 78 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Bio 92 | 93 | 94 | 95 | {userState.currentUser.bio} 96 | 97 | 98 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | Education 112 | 113 | 114 | 115 | 116 | {userState.currentUser.education} 117 | 118 | 119 | 120 | 127 | 128 | 129 |
130 | 131 |
132 | ) 133 | } 134 | 135 | export default General 136 | -------------------------------------------------------------------------------- /src/components/settings/General/EditInput.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { 3 | Grid, 4 | Typography, 5 | Button, 6 | Dialog, 7 | DialogTitle, 8 | DialogContent, 9 | TextField, 10 | DialogActions, 11 | } from '@material-ui/core' 12 | 13 | function EditInput({ label, input, setInput, editAction, loading }) { 14 | const [dialog, setDialog] = useState(false) 15 | const handleChange = (value) => { 16 | setInput(value) 17 | } 18 | 19 | const handleUpdate = () => { 20 | setDialog(false) 21 | editAction() 22 | } 23 | return ( 24 |
25 | 28 | 29 | setDialog(false)} 32 | maxWidth="sm" 33 | fullWidth 34 | > 35 | Update {label} 36 | 37 | handleChange(e.target.value)} 42 | /> 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | ) 51 | } 52 | 53 | export default EditInput 54 | -------------------------------------------------------------------------------- /src/components/settings/Location.js: -------------------------------------------------------------------------------- 1 | import { 2 | Grid, 3 | List, 4 | ListItem, 5 | ListItemIcon, 6 | ListItemText, 7 | Typography, 8 | } from '@material-ui/core' 9 | import React, { useContext, useState } from 'react' 10 | import { UserContext } from '../../App' 11 | import EditLocation from './Location/EditLocation' 12 | import useUpdateProfile from '../../hooks/useUpdateProfile' 13 | import GoogleMap from '../UI/GoogleMap' 14 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 15 | import { 16 | faCity, 17 | faHouseUser, 18 | faMapPin, 19 | } from '@fortawesome/free-solid-svg-icons' 20 | import { faClock, faMap } from '@fortawesome/free-regular-svg-icons' 21 | function Location() { 22 | const { userState } = useContext(UserContext) 23 | const [location, setLocation] = useState(null) 24 | 25 | const { editLocation, loading } = useUpdateProfile() 26 | 27 | const updateLocation = () => { 28 | editLocation(location) 29 | } 30 | return ( 31 |
32 | 33 | 34 | 42 | Location Setting 43 | 44 | 45 | 46 | 52 | 53 | 54 |
55 | {userState.currentUser.location && ( 56 | 57 | 58 | 59 | 60 | 61 | {userState.currentUser.location.city} 62 | 63 | 64 | 65 | 66 | 67 | 68 | {userState.currentUser.location.state} 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | {userState.currentUser.location.country} 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | {userState.currentUser.location.lat} {' , '} 85 | {userState.currentUser.location.lng} 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | {userState.currentUser.location.region} 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | {userState.currentUser.location.timezone} 103 | 104 | 105 | 106 | )} 107 | 108 | {userState.currentUser.location && ( 109 | 110 | 111 | 117 | 118 | 119 | )} 120 |
121 |
122 | ) 123 | } 124 | 125 | export default Location 126 | -------------------------------------------------------------------------------- /src/components/settings/Location/EditLocation.js: -------------------------------------------------------------------------------- 1 | import { 2 | Button, 3 | Dialog, 4 | DialogTitle, 5 | DialogContent, 6 | DialogActions, 7 | CircularProgress, 8 | Typography, 9 | } from '@material-ui/core' 10 | import { Alert } from '@material-ui/lab' 11 | import { LocationOn } from '@material-ui/icons' 12 | import React, { useEffect, useState } from 'react' 13 | import useLocationService from '../../../hooks/useLocationService' 14 | 15 | function EditLocation({ location, setLocation, updateLocation, loading }) { 16 | const [dialog, setDialog] = useState(false) 17 | const { 18 | loading: locationLoading, 19 | error, 20 | data, 21 | setError, 22 | getLocation, 23 | } = useLocationService() 24 | 25 | useEffect(() => { 26 | setLocation(data) 27 | }, [data]) 28 | 29 | const handleUpdate = () => { 30 | setDialog(false) 31 | updateLocation() 32 | } 33 | 34 | const handleFetchLocation = () => { 35 | setError(null) 36 | getLocation() 37 | } 38 | 39 | return ( 40 | <> 41 | 48 | 49 | setDialog(false)} 52 | maxWidth="sm" 53 | fullWidth 54 | > 55 | Update Location 56 | 57 | {error && {error}} 58 | {location && ( 59 | 60 | {location.city},{location.state},{location.country} 61 | 62 | )} 63 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ) 88 | } 89 | 90 | export default EditLocation 91 | -------------------------------------------------------------------------------- /src/components/settings/Privacy.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function Privacy() { 4 | return ( 5 |
6 | Privacy 7 |
8 | ) 9 | } 10 | 11 | export default Privacy 12 | -------------------------------------------------------------------------------- /src/components/settings/SecurityAndLogin.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { 3 | Grid, 4 | List, 5 | ListItem, 6 | ListItemSecondaryAction, 7 | ListItemText, 8 | Typography, 9 | Divider, 10 | ListItemIcon, 11 | } from '@material-ui/core' 12 | 13 | import useUpdateProfile from '../../hooks/useUpdateProfile' 14 | import { Lock } from '@material-ui/icons' 15 | import EditPassword from './SecurityAndLogin/EditPassword' 16 | function SecurityAndLogin() { 17 | const [password, setPassword] = useState({ 18 | currentPassword: '', 19 | newPassword: '', 20 | showNewPassword: false, 21 | showCurrentPassword: false, 22 | }) 23 | 24 | const { updatePassword } = useUpdateProfile() 25 | 26 | const handleUpdatePassword = () => { 27 | updatePassword({ 28 | newPassword: password.newPassword, 29 | currentPassword: password.currentPassword, 30 | }) 31 | } 32 | return ( 33 |
34 | 42 | Security And Login 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Change password} 54 | secondary={ 55 | 56 | Use a strong password that you're not using elsewhere 57 | 58 | } 59 | /> 60 | 61 | 66 | 67 | 68 | 69 | 70 |
71 | ) 72 | } 73 | 74 | 75 | export default SecurityAndLogin 76 | -------------------------------------------------------------------------------- /src/components/settings/SecurityAndLogin/EditPassword.js: -------------------------------------------------------------------------------- 1 | import { 2 | Button, 3 | Dialog, 4 | DialogTitle, 5 | DialogContent, 6 | DialogActions, 7 | InputAdornment, 8 | IconButton, 9 | OutlinedInput, 10 | } from '@material-ui/core' 11 | 12 | import { Visibility, VisibilityOff } from '@material-ui/icons' 13 | import React, { useState } from 'react' 14 | 15 | function EditPassword({ password, setPassword, updatePassword }) { 16 | const [dialog, setDialog] = useState(false) 17 | 18 | const handleChangeCurrentPassword = (e) => { 19 | setPassword({ ...password, currentPassword: e.target.value }) 20 | } 21 | const handleChangeNewPassword = (e) => { 22 | setPassword({ ...password, newPassword: e.target.value }) 23 | } 24 | 25 | const handleUpdatePassword = () => { 26 | setDialog(false) 27 | updatePassword() 28 | } 29 | 30 | return ( 31 | <> 32 | 39 | 40 | setDialog(false)} 43 | maxWidth="sm" 44 | fullWidth 45 | > 46 | Update Password 47 | 48 | {/* {error && {error}} */} 49 | 50 | 57 | 59 | setPassword({ 60 | ...password, 61 | showCurrentPassword: !password.showCurrentPassword, 62 | }) 63 | } 64 | edge="end" 65 | > 66 | {password.showCurrentPassword ? ( 67 | 68 | ) : ( 69 | 70 | )} 71 | 72 | 73 | } 74 | style={{ width: '100%', marginBottom: '8px' }} 75 | /> 76 | 83 | 85 | setPassword({ 86 | ...password, 87 | showNewPassword: !password.showNewPassword, 88 | }) 89 | } 90 | edge="end" 91 | > 92 | {password.showNewPassword ? ( 93 | 94 | ) : ( 95 | 96 | )} 97 | 98 | 99 | } 100 | style={{ width: '100%' }} 101 | /> 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | ) 110 | } 111 | 112 | export default EditPassword 113 | -------------------------------------------------------------------------------- /src/components/settings/TrigoInformation.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function TrigoInformation() { 4 | return ( 5 |
6 | Trigo TrigoInformation 7 |
8 | ) 9 | } 10 | 11 | export default TrigoInformation 12 | -------------------------------------------------------------------------------- /src/context/ChatContext.js: -------------------------------------------------------------------------------- 1 | export const initialChatState = { 2 | selectedFriend: null, 3 | messages: [], 4 | } 5 | 6 | export const ChatReducer = (state, action) => { 7 | switch (action.type) { 8 | case 'SET_MESSAGES': 9 | return { 10 | ...state, 11 | messages: action.payload, 12 | } 13 | case 'ADD_MESSAGE': 14 | return { 15 | ...state, 16 | messages: [...state.messages, action.payload], 17 | } 18 | 19 | case 'SET_SELECTED_FRIEND': 20 | return { 21 | ...state, 22 | selectedFriend: action.payload, 23 | } 24 | 25 | default: 26 | throw new Error(`action type ${action.type} is undefined`) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/context/PostContext.js: -------------------------------------------------------------------------------- 1 | export const initialPostState = { 2 | posts: [], 3 | postPagination: { 4 | currentPage: 0, 5 | totalPage: 0, 6 | }, 7 | post: { 8 | comments: [], 9 | commentPagination: { 10 | currentPage: 0, 11 | totalPage: 0, 12 | }, 13 | }, 14 | } 15 | 16 | export const PostReducer = (state, action) => { 17 | switch (action.type) { 18 | case 'SET_POSTS': 19 | return { 20 | ...state, 21 | posts: action.payload, 22 | } 23 | 24 | case 'SET_CURRENT_POST': 25 | return { 26 | ...state, 27 | post: action.payload, 28 | } 29 | 30 | case 'REMOVE_CURRENT_POST': 31 | return { 32 | ...state, 33 | post: { 34 | comments: [], 35 | commentPagination: { 36 | currentPage: 0, 37 | totalPage: 0, 38 | }, 39 | }, 40 | } 41 | 42 | case 'ADD_POST': 43 | return { 44 | ...state, 45 | posts: [action.payload, ...state.posts], 46 | } 47 | 48 | case 'POST_PAGINATION': 49 | return { 50 | ...state, 51 | posts: [...state.posts, ...action.payload.posts], 52 | postPagination: { 53 | ...state.postPagination, 54 | currentPage: action.payload.currentPage, 55 | totalPage: action.payload.totalPage, 56 | }, 57 | } 58 | 59 | case 'COMMENT_PAGINATION': 60 | return { 61 | ...state, 62 | post: { 63 | ...state.post, 64 | commentPagination: { 65 | ...state.post.commentPagination, 66 | currentPage: action.payload.currentPage, 67 | totalPage: action.payload.totalPage, 68 | }, 69 | comments: 70 | state.post.comments && state.post.comments.length 71 | ? [...state.post.comments, ...action.payload.comments] 72 | : [...action.payload.comments], 73 | }, 74 | } 75 | 76 | case 'LIKE_UNLIKE_POST': 77 | let l_postIndex = state.posts.findIndex( 78 | (post) => post.id == action.payload.id, 79 | ) 80 | state.posts[l_postIndex] = action.payload 81 | if (state.post.id == action.payload.id) { 82 | state.post = action.payload 83 | } 84 | 85 | return { 86 | ...state, 87 | } 88 | 89 | case 'SET_POST_COMMENTS': 90 | return { 91 | ...state, 92 | post: { 93 | ...state.post, 94 | comments: action.payload, 95 | }, 96 | } 97 | 98 | case 'ADD_POST_COMMENT': 99 | return { 100 | ...state, 101 | post: { 102 | ...state.post, 103 | comments: [action.payload, ...state.post.comments], 104 | }, 105 | } 106 | 107 | case 'LIKE_UNLIKE_COMMENT': 108 | let index1 = state.post.comments.findIndex( 109 | (comment) => comment.id == action.payload.id, 110 | ) 111 | state.post.comments[index1] = action.payload 112 | 113 | return { 114 | ...state, 115 | } 116 | 117 | default: 118 | throw new Error(`action type ${action.type} is undefined`) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/context/UIContext.js: -------------------------------------------------------------------------------- 1 | export const initialUIState = { 2 | mdScreen: false, 3 | drawer: false, 4 | navDrawerMenu: false, 5 | postModel: false, 6 | message: null, 7 | notifications: [], 8 | loading: false, 9 | darkMode: false, 10 | } 11 | 12 | export const UIReducer = (state, action) => { 13 | switch (action.type) { 14 | case 'SET_USER_SCREEN': 15 | return { 16 | ...state, 17 | mdScreen: action.payload, 18 | } 19 | 20 | case 'SET_DRAWER': 21 | return { 22 | ...state, 23 | drawer: action.payload, 24 | } 25 | 26 | case 'SET_MESSAGE': 27 | return { 28 | ...state, 29 | message: action.payload, 30 | } 31 | case 'SET_NAV_MENU': 32 | return { 33 | ...state, 34 | navDrawerMenu: action.payload, 35 | } 36 | 37 | case 'SET_POST_MODEL': 38 | return { 39 | ...state, 40 | postModel: action.payload, 41 | } 42 | 43 | case 'SET_NOTIFICATIONS': 44 | return { 45 | ...state, 46 | notifications: action.payload, 47 | } 48 | 49 | case 'ADD_NOTIFICATION': 50 | return { 51 | ...state, 52 | notifications: [action.payload, ...state.notifications], 53 | } 54 | 55 | case 'SET_LOADING': 56 | return { 57 | ...state, 58 | loading: action.payload, 59 | } 60 | case 'SET_DARK_MODE': 61 | return { 62 | ...state, 63 | darkMode: action.payload, 64 | } 65 | 66 | default: 67 | throw new Error(`action type ${action.type} is undefined`) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/firebase/firebase.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase/app' 2 | import 'firebase/storage' 3 | 4 | const firebaseConfig = { 5 | apiKey: process.env.REACT_APP_API_KEY, 6 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGEING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | } 13 | 14 | firebase.initializeApp(firebaseConfig) 15 | 16 | const storage = firebase.storage() 17 | 18 | export { firebase as default, storage } 19 | -------------------------------------------------------------------------------- /src/hooks/useCreateComment.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { PostContext, UIContext } from '../App' 4 | 5 | const url = process.env.REACT_APP_ENDPOINT 6 | 7 | const useCreateComment = ({ 8 | post_id, 9 | commentText, 10 | setError, 11 | setCommentText, 12 | }) => { 13 | const [loading, setLoading] = useState(false) 14 | 15 | const { postDispatch } = useContext(PostContext) 16 | const { uiDispatch } = useContext(UIContext) 17 | 18 | const createComment = async () => { 19 | setLoading(true) 20 | try { 21 | let token = JSON.parse(localStorage.getItem('token')) 22 | const response = await axios.post( 23 | `${url}/api/post/${post_id}/comment`, 24 | { text: commentText }, 25 | { 26 | headers: { 27 | Authorization: `Bearer ${token}`, 28 | }, 29 | }, 30 | ) 31 | if (response.data) { 32 | setCommentText('') 33 | postDispatch({ type: 'ADD_POST_COMMENT', payload: response.data.comment }) 34 | uiDispatch({ 35 | type: 'SET_MESSAGE', 36 | payload: { 37 | color: 'success', 38 | display: true, 39 | text: response.data.message, 40 | }, 41 | }) 42 | } 43 | setLoading(false) 44 | } catch (err) { 45 | setLoading(false) 46 | console.log(err) 47 | if (err && err.response) { 48 | if (err.response.status === 422) { 49 | setError(err.response.data.error) 50 | } 51 | 52 | uiDispatch({ type: 'SET_MESSAGE', payload: err.response.data.error }) 53 | } 54 | } 55 | } 56 | 57 | return { 58 | createComment, 59 | loading, 60 | } 61 | } 62 | 63 | export default useCreateComment 64 | -------------------------------------------------------------------------------- /src/hooks/useFetchComments.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { PostContext } from '../App' 4 | 5 | const url = process.env.REACT_APP_ENDPOINT 6 | 7 | const useFetchComments = (post_id) => { 8 | const [loading, setLoading] = useState(false) 9 | const { postDispatch } = useContext(PostContext) 10 | 11 | const fetchComments = async () => { 12 | setLoading(true) 13 | try { 14 | let token = JSON.parse(localStorage.getItem('token')) 15 | const response = await axios.get(`${url}/api/post/${post_id}/comment`, { 16 | headers: { 17 | Authorization: `Bearer ${token}`, 18 | }, 19 | }) 20 | if (response.data) { 21 | console.log(response.data) 22 | postDispatch({ 23 | type: 'SET_COMMENTS', 24 | payload: response.data.comments, 25 | }) 26 | } 27 | setLoading(false) 28 | } catch (err) { 29 | setLoading(false) 30 | console.log(err) 31 | } 32 | } 33 | 34 | return { 35 | fetchComments, 36 | loading, 37 | } 38 | } 39 | 40 | export default useFetchComments 41 | -------------------------------------------------------------------------------- /src/hooks/useFetchPost.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { PostContext } from '../App' 4 | 5 | const url = process.env.REACT_APP_ENDPOINT 6 | 7 | const useFetchPost = () => { 8 | const [loading, setLoading] = useState(false) 9 | const { postState, postDispatch } = useContext(PostContext) 10 | 11 | let token = JSON.parse(localStorage.getItem('token')) 12 | 13 | const fetchComments = async (post_id) => { 14 | if ( 15 | postState.post.commentPagination.currentPage > 16 | postState.post.commentPagination.totalPage 17 | ) { 18 | return 19 | } 20 | setLoading(true) 21 | try { 22 | const res = await axios.get( 23 | `${url}/api/post/${post_id}/comment/?page=${postState.post.commentPagination.currentPage}`, 24 | { 25 | headers: { 26 | Authorization: `Bearer ${token}`, 27 | }, 28 | }, 29 | ) 30 | if (res.data) { 31 | postDispatch({ 32 | type: 'COMMENT_PAGINATION', 33 | payload: { 34 | currentPage: res.data.pagination.currentPage + 1, 35 | totalPage: res.data.pagination.totalPage, 36 | comments: res.data.comments, 37 | }, 38 | }) 39 | } 40 | setLoading(false) 41 | } catch (err) { 42 | setLoading(false) 43 | console.log(err) 44 | } 45 | } 46 | 47 | const fetchPosts = async () => { 48 | if ( 49 | postState.postPagination.currentPage > postState.postPagination.totalPage 50 | ) { 51 | return 52 | } else { 53 | setLoading(true) 54 | try { 55 | const { data } = await axios.get( 56 | `${url}/api/post/?page=${postState.postPagination.currentPage}`, 57 | { 58 | headers: { 59 | Authorization: `Bearer ${token}`, 60 | }, 61 | }, 62 | ) 63 | if (data) { 64 | postDispatch({ 65 | type: 'POST_PAGINATION', 66 | payload: { 67 | currentPage: data.pagination.currentPage + 1, 68 | totalPage: data.pagination.totalPage, 69 | posts: data.posts, 70 | }, 71 | }) 72 | } 73 | setLoading(false) 74 | } catch (err) { 75 | setLoading(false) 76 | console.log(err) 77 | } 78 | } 79 | } 80 | 81 | return { 82 | fetchPosts, 83 | fetchComments, 84 | loading, 85 | } 86 | } 87 | 88 | export default useFetchPost 89 | -------------------------------------------------------------------------------- /src/hooks/useFriendActions.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { UserContext, UIContext } from '../App' 4 | 5 | const url = process.env.REACT_APP_ENDPOINT 6 | 7 | const useFriendAction = () => { 8 | const [loading, setLoading] = useState(false) 9 | const { userDispatch } = useContext(UserContext) 10 | const { uiDispatch } = useContext(UIContext) 11 | 12 | const acceptFriendRequest = async (request_id) => { 13 | let token = JSON.parse(localStorage.getItem('token')) 14 | 15 | try { 16 | setLoading(true) 17 | 18 | const { data } = await axios.get( 19 | `${url}/api/user/friend_request/${request_id}/accept`, 20 | { 21 | headers: { 22 | Authorization: `Bearer ${token}`, 23 | }, 24 | }, 25 | ) 26 | setLoading(false) 27 | if (data) { 28 | userDispatch({ 29 | type: 'ADD_FRIEND', 30 | payload: data.user, 31 | }) 32 | userDispatch({ 33 | type: 'REMOVE_FRIENDS_REQUEST_RECEIVED', 34 | payload: request_id, 35 | }) 36 | 37 | uiDispatch({ 38 | type: 'SET_MESSAGE', 39 | payload: { color: 'success', display: true, text: data.message }, 40 | }) 41 | } 42 | } catch (err) { 43 | setLoading(false) 44 | 45 | if (err && err.response) { 46 | uiDispatch({ 47 | type: 'SET_MESSAGE', 48 | payload: { 49 | color: 'error', 50 | display: true, 51 | text: err.response.data.error, 52 | }, 53 | }) 54 | } 55 | } 56 | } 57 | 58 | const declineFriendRequest = async (request_id) => { 59 | let token = JSON.parse(localStorage.getItem('token')) 60 | 61 | try { 62 | setLoading(true) 63 | 64 | const { data } = await axios.get( 65 | `${url}/api/user/friend_request/${request_id}/decline`, 66 | { 67 | headers: { 68 | Authorization: `Bearer ${token}`, 69 | }, 70 | }, 71 | ) 72 | setLoading(false) 73 | if (data) { 74 | userDispatch({ 75 | type: 'REMOVE_FRIENDS_REQUEST_RECEIVED', 76 | payload: request_id, 77 | }) 78 | uiDispatch({ 79 | type: 'SET_MESSAGE', 80 | payload: { color: 'success', display: true, text: data.message }, 81 | }) 82 | } 83 | } catch (err) { 84 | setLoading(false) 85 | 86 | if (err && err.response) { 87 | uiDispatch({ 88 | type: 'SET_MESSAGE', 89 | payload: { 90 | color: 'error', 91 | display: true, 92 | text: err.response.data.error, 93 | }, 94 | }) 95 | } 96 | } 97 | } 98 | 99 | const sendFriendRequest = async (user_id) => { 100 | let token = JSON.parse(localStorage.getItem('token')) 101 | 102 | try { 103 | setLoading(true) 104 | 105 | const { data } = await axios.get( 106 | `${url}/api/user/friend_request/${user_id}/send`, 107 | { 108 | headers: { 109 | Authorization: `Bearer ${token}`, 110 | }, 111 | }, 112 | ) 113 | setLoading(false) 114 | if (data) { 115 | userDispatch({ 116 | type: 'ADD_FRIENDS_REQUEST_SENDED', 117 | payload: data.friend, 118 | }) 119 | uiDispatch({ 120 | type: 'SET_MESSAGE', 121 | payload: { color: 'success', display: true, text: data.message }, 122 | }) 123 | } 124 | } catch (err) { 125 | setLoading(false) 126 | 127 | if (err && err.response) { 128 | uiDispatch({ 129 | type: 'SET_MESSAGE', 130 | payload: { 131 | color: 'error', 132 | display: true, 133 | text: err.response.data.error, 134 | }, 135 | }) 136 | } 137 | } 138 | } 139 | 140 | const cancelFriendRequest = async (request_id) => { 141 | let token = JSON.parse(localStorage.token) 142 | try { 143 | const { data } = await axios.get( 144 | `${url}/api/user/friend_request/${request_id}/cancel`, 145 | { 146 | headers: { 147 | Authorization: `Bearer ${token}`, 148 | }, 149 | }, 150 | ) 151 | if (data) { 152 | userDispatch({ 153 | type: 'REMOVE_FRIENDS_REQUEST_SENDED', 154 | payload: request_id, 155 | }) 156 | uiDispatch({ 157 | type: 'SET_MESSAGE', 158 | payload: { color: 'success', display: true, text: data.message }, 159 | }) 160 | } 161 | } catch (err) { 162 | if (err && err.response) { 163 | uiDispatch({ 164 | type: 'SET_MESSAGE', 165 | payload: { 166 | color: 'error', 167 | display: true, 168 | text: err.response.data.error, 169 | }, 170 | }) 171 | } 172 | } 173 | } 174 | 175 | return { 176 | sendFriendRequest, 177 | declineFriendRequest, 178 | acceptFriendRequest, 179 | cancelFriendRequest, 180 | loading, 181 | } 182 | } 183 | 184 | export default useFriendAction 185 | -------------------------------------------------------------------------------- /src/hooks/useLocationService.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import axios from 'axios' 3 | 4 | function useLocationService() { 5 | const [loading, setLoading] = useState(false) 6 | const [error, setError] = useState(null) 7 | const [data, setData] = useState(null) 8 | 9 | const getLocation = () => { 10 | setLoading(true) 11 | navigator.geolocation.getCurrentPosition( 12 | (position) => { 13 | getCityAndCountry(position) 14 | }, 15 | (err) => { 16 | locationError() 17 | }, 18 | { timeout: 7000 }, 19 | ) 20 | } 21 | 22 | function getCityAndCountry(position) { 23 | let apiUrl = `https://geocode.xyz/${position.coords.latitude},${position.coords.longitude}?json=1` 24 | axios 25 | .get(apiUrl) 26 | .then((result) => { 27 | locationSuccess(result.data) 28 | }) 29 | .catch((err) => { 30 | locationError() 31 | }) 32 | } 33 | 34 | function locationSuccess(result) { 35 | setData({ 36 | city: result?.city, 37 | country: result?.country, 38 | lat: result?.latt, 39 | lng: result?.longt, 40 | region: result?.region, 41 | state: result?.state, 42 | timezone: result?.timezone, 43 | }) 44 | setLoading(false) 45 | } 46 | 47 | function locationError() { 48 | setError('Could not find location . Enter location manually') 49 | 50 | setLoading(false) 51 | } 52 | 53 | return { 54 | loading, 55 | data, 56 | error, 57 | getLocation, 58 | setError, 59 | } 60 | } 61 | 62 | export default useLocationService 63 | -------------------------------------------------------------------------------- /src/hooks/useSearchFriends.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import axios from 'axios' 3 | 4 | const url = process.env.REACT_APP_ENDPOINT 5 | 6 | function useSearchFriends() { 7 | const [friends, setFriends] = useState([]) 8 | const [loading, setLoading] = useState(false) 9 | 10 | const searchFriends = async (name) => { 11 | try { 12 | setLoading(true) 13 | const res = await axios.get(`${url}/api/user/search?name=${name}`) 14 | setFriends(res.data.users) 15 | setLoading(false) 16 | } catch (err) { 17 | setLoading(false) 18 | console.log(err) 19 | } 20 | } 21 | return { 22 | searchFriends, 23 | friends, 24 | loading 25 | } 26 | } 27 | 28 | export default useSearchFriends 29 | -------------------------------------------------------------------------------- /src/hooks/useSendMessage.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { ChatContext, UIContext } from '../App' 4 | 5 | const url = process.env.REACT_APP_ENDPOINT 6 | 7 | const useSendMessage = ({ textMessage, setTextMessage }) => { 8 | const [loading, setLoading] = useState(false) 9 | 10 | const { chatState, chatDispatch } = useContext(ChatContext) 11 | const { uiDispatch } = useContext(UIContext) 12 | 13 | const sendMessage = async () => { 14 | setLoading(true) 15 | let friendId = chatState.selectedFriend.id 16 | try { 17 | let token = JSON.parse(localStorage.getItem('token')) 18 | const response = await axios.post( 19 | `${url}/api/user/chat/${friendId}/send`, 20 | { text: textMessage }, 21 | { 22 | headers: { 23 | Authorization: `Bearer ${token}`, 24 | }, 25 | }, 26 | ) 27 | if (response.data) { 28 | setTextMessage('') 29 | chatDispatch({ type: 'ADD_MESSAGE', payload: response.data.data }) 30 | } 31 | setLoading(false) 32 | } catch (err) { 33 | setLoading(false) 34 | console.log(err) 35 | if (err && err.response) { 36 | if (err.response.status === 422) { 37 | uiDispatch({ 38 | type: 'SET_MESSAGE', 39 | payload: { 40 | display: true, 41 | text: err.response.data.error, 42 | color: 'error', 43 | }, 44 | }) 45 | } 46 | } 47 | } 48 | } 49 | 50 | return { 51 | sendMessage, 52 | loading, 53 | } 54 | } 55 | 56 | export default useSendMessage 57 | -------------------------------------------------------------------------------- /src/hooks/useTheme.js: -------------------------------------------------------------------------------- 1 | import { createMuiTheme } from '@material-ui/core/styles' 2 | import { UIContext } from '../App' 3 | import { useContext } from 'react' 4 | 5 | const useTheme = (darkMode) => { 6 | return createMuiTheme({ 7 | active: { 8 | success: 'rgb(63,162,76)', 9 | }, 10 | palette: { 11 | type: darkMode ? 'dark' : 'light', 12 | primary: { 13 | main: 'rgb(1,133,243)', 14 | }, 15 | 16 | secondary: { 17 | main: 'rgb(63,162,76)', 18 | }, 19 | }, 20 | }) 21 | } 22 | 23 | export default useTheme 24 | -------------------------------------------------------------------------------- /src/hooks/useUpdateProfilePic.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from 'react' 2 | import axios from 'axios' 3 | import { UserContext, UIContext } from '../App' 4 | import { storage } from '../firebase/firebase' 5 | const url = process.env.REACT_APP_ENDPOINT 6 | 7 | const useUpdateProfilePic = ({ profile_pic, cover_pic, history }) => { 8 | const [loading, setLoading] = useState(false) 9 | 10 | const { userState, userDispatch } = useContext(UserContext) 11 | const { uiDispatch } = useContext(UIContext) 12 | 13 | const updateProfilePic = () => { 14 | let filename = `profile_pic/${userState.currentUser.name}-${Date.now()}-${ 15 | profile_pic.name 16 | }` 17 | const uploadTask = storage.ref(`images/${filename}`).put(profile_pic) 18 | uploadTask.on( 19 | 'state_changed', 20 | () => { 21 | setLoading(true) 22 | }, 23 | (err) => { 24 | console.log('error from firebase') 25 | setLoading(false) 26 | }, 27 | () => { 28 | storage 29 | .ref('images') 30 | .child(filename) 31 | .getDownloadURL() 32 | .then((uri) => { 33 | saveProfilePic(uri) 34 | }) 35 | }, 36 | ) 37 | } 38 | 39 | const updateCoverPic = () => { 40 | let filename = `cover_pic/${userState.currentUser.name}-${Date.now()}-${ 41 | cover_pic.name 42 | }` 43 | const uploadTask = storage.ref(`images/${filename}`).put(cover_pic) 44 | uploadTask.on( 45 | 'state_changed', 46 | () => { 47 | setLoading(true) 48 | }, 49 | (err) => { 50 | console.log('error from firebase') 51 | setLoading(false) 52 | }, 53 | () => { 54 | storage 55 | .ref('images') 56 | .child(filename) 57 | .getDownloadURL() 58 | .then((uri) => { 59 | saveCoverImage(uri) 60 | }) 61 | }, 62 | ) 63 | } 64 | 65 | const saveProfilePic = async (profile_url) => { 66 | setLoading(true) 67 | try { 68 | let token = JSON.parse(localStorage.getItem('token')) 69 | const response = await axios.put( 70 | `${url}/api/user/profile_pic/update`, 71 | { profile_url }, 72 | { 73 | headers: { 74 | Authorization: `Bearer ${token}`, 75 | }, 76 | }, 77 | ) 78 | if (response.data) { 79 | uiDispatch({ 80 | type: 'SET_MESSAGE', 81 | payload: { 82 | text: response.data.message, 83 | color: 'success', 84 | display: true, 85 | }, 86 | }) 87 | userDispatch({ type: 'UPDATE_USER', payload: response.data.user }) 88 | } 89 | setLoading(false) 90 | history.push('/home') 91 | } catch (err) { 92 | setLoading(false) 93 | console.log(err) 94 | } 95 | } 96 | 97 | const saveCoverImage = async (cover_url) => { 98 | setLoading(true) 99 | try { 100 | let token = JSON.parse(localStorage.getItem('token')) 101 | const response = await axios.put( 102 | `${url}/api/user/cover_pic/update`, 103 | { cover_url }, 104 | { 105 | headers: { 106 | Authorization: `Bearer ${token}`, 107 | }, 108 | }, 109 | ) 110 | if (response.data) { 111 | uiDispatch({ 112 | type: 'SET_MESSAGE', 113 | payload: { 114 | text: response.data.message, 115 | color: 'success', 116 | display: true, 117 | }, 118 | }) 119 | userDispatch({ type: 'UPDATE_USER', payload: response.data.user }) 120 | } 121 | setLoading(false) 122 | history.push('/home') 123 | } catch (err) { 124 | setLoading(false) 125 | console.log(err) 126 | } 127 | } 128 | 129 | return { 130 | updateProfilePic, 131 | updateCoverPic, 132 | 133 | loading, 134 | } 135 | } 136 | 137 | export default useUpdateProfilePic 138 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | #root, 2 | html, 3 | body { 4 | margin: 0; 5 | } 6 | 7 | * { 8 | box-sizing: border-box; 9 | } 10 | html { 11 | scroll-behavior: smooth; 12 | } 13 | 14 | 15 | .MuiAppBar-root{ 16 | z-index: "10000"; 17 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom' 3 | import "./index.css" 4 | import App from "./App" 5 | 6 | ReactDOM.render(,document.getElementById("root")) -------------------------------------------------------------------------------- /src/screens/Auth.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react' 2 | import RecentAccounts from '../components/Auth/RecentAccount/RecentAccounts' 3 | import LoginForm from '../components/Auth/LoginForm' 4 | import SignupForm from '../components/Auth/SignupForm' 5 | import { 6 | Button, 7 | Container, 8 | Divider, 9 | Grid, 10 | Paper, 11 | Typography, 12 | } from '@material-ui/core' 13 | import { UIContext } from '../App' 14 | 15 | const Auth = () => { 16 | const [toggleLoginForm, setToggleLoginForm] = useState(true) 17 | const { uiState } = useContext(UIContext) 18 | return ( 19 |
20 | 21 | 28 | 35 | Facebook 36 | 37 | 44 | Recents Login 45 | 46 | 54 | click your picture or add an account 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 71 | {toggleLoginForm ? : } 72 | 73 | 74 | 86 | 87 | 88 | 89 | 90 |
91 | ) 92 | } 93 | 94 | export default Auth 95 | -------------------------------------------------------------------------------- /src/screens/Home.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext, useEffect } from 'react' 2 | import { Link } from 'react-router-dom' 3 | import { PostContext, UIContext, UserContext } from '../App' 4 | import { 5 | List, 6 | ListItemIcon, 7 | Avatar, 8 | ListItem, 9 | ListItemText, 10 | useTheme, 11 | useMediaQuery, 12 | } from '@material-ui/core' 13 | import Sidebar from '../components/Sidebar' 14 | import WritePostCard from '../components/Post/PostForm/WritePostCard' 15 | 16 | import { homeLeftItems } from '../Data/Home' 17 | 18 | import DrawerBar from '../components/Navbar/DrawerBar' 19 | 20 | import AvartarText from '../components/UI/AvartarText' 21 | 22 | import Posts from '../components/Post/Posts' 23 | import MyFriendLists from '../components/Friends/MyFriendLists' 24 | import useFetchPost from '../hooks/useFetchPost' 25 | 26 | function Home() { 27 | const { uiState, uiDispatch } = useContext(UIContext) 28 | const { userState } = useContext(UserContext) 29 | const { postState } = useContext(PostContext) 30 | const theme = useTheme() 31 | const match = useMediaQuery(theme.breakpoints.between(960, 1400)) 32 | 33 | const { fetchPosts } = useFetchPost() 34 | useEffect(() => { 35 | uiDispatch({ type: 'SET_NAV_MENU', payload: true }) 36 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 37 | 38 | async function loadPosts() { 39 | await fetchPosts() 40 | } 41 | 42 | loadPosts() 43 | 44 | return () => { 45 | uiDispatch({ type: 'SET_NAV_MENU', payload: false }) 46 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 47 | } 48 | }, []) 49 | 50 | return ( 51 |
52 | {uiState.mdScreen ? ( 53 | 54 | 61 | 62 | 67 | 68 | {userState.currentUser.profile_pic ? ( 69 | 75 | 80 | 81 | ) : ( 82 | 86 | )} 87 | 88 | 92 | 93 | {homeLeftItems.map((list, index) => ( 94 | 95 | 96 | 100 | 101 | 102 | 103 | ))} 104 | 105 | 106 | 114 | 115 | 116 | 117 | ) : ( 118 | 119 | 120 | 121 | )} 122 | 123 |
132 | 133 | 134 | 135 |
136 |
137 | ) 138 | } 139 | 140 | export default Home 141 | -------------------------------------------------------------------------------- /src/screens/Messenger.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from 'react' 2 | import { 3 | Avatar, 4 | Container, 5 | Grid, 6 | Paper, 7 | Typography, 8 | } from '@material-ui/core' 9 | import { ChatContext, UIContext } from '../App' 10 | import Messages from '../components/Chat/Messages' 11 | import DrawerBar from '../components/Navbar/DrawerBar' 12 | 13 | import Friends from '../components/Chat/Friends' 14 | import MessageTextArea from '../components/Chat/MessageTextArea' 15 | import FriendNotSelected from '../components/Chat/FriendNotSelected' 16 | import AvartarText from '../components/UI/AvartarText' 17 | 18 | function Messenger() { 19 | const { uiDispatch, uiState } = useContext(UIContext) 20 | const { chatState, chatDispatch } = useContext(ChatContext) 21 | useEffect(() => { 22 | uiDispatch({ type: 'SET_NAV_MENU', payload: true }) 23 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 24 | 25 | return () => { 26 | uiDispatch({ type: 'SET_NAV_MENU', payload: false }) 27 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 28 | chatDispatch({ type: 'SET_SELECTED_FRIEND', payload: null }) 29 | } 30 | }, []) 31 | 32 | return ( 33 |
40 | {!uiState.mdScreen && ( 41 | 42 | 43 | 44 | )} 45 | 46 | 47 | 54 | {uiState.mdScreen && ( 55 | 69 | 70 | 71 | 72 | 73 | )} 74 | {chatState.selectedFriend ? ( 75 | 89 | 101 | {chatState.selectedFriend.profile_pic ? ( 102 | 103 | 107 | 108 | ) : ( 109 | 115 | )} 116 | 117 | {chatState.selectedFriend.name} 118 | 119 | 120 | 121 | 136 | 137 | 138 | 139 |
147 | 148 |
149 |
150 | ) : ( 151 | 152 | )} 153 |
154 |
155 |
156 |
157 | ) 158 | } 159 | 160 | export default Messenger 161 | -------------------------------------------------------------------------------- /src/screens/Profile.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from 'react' 2 | import { UserContext } from '../App' 3 | import { useParams } from 'react-router-dom' 4 | import { fetchUserById } from "../services/UserServices" 5 | import UserProfile from '../components/Profile/UserProfile' 6 | 7 | function Profile() { 8 | const params = useParams() 9 | const { userState,userDispatch } = useContext(UserContext) 10 | const [user, setUser] = useState(null) 11 | 12 | useEffect(() => { 13 | if (userState.currentUser.id == params.userId) { 14 | setUser(userState.currentUser) 15 | } 16 | else { 17 | let userIndex = userState.users.findIndex(user => user.id == params.userId) 18 | if (userIndex !== -1) { 19 | setUser(userState.users[userIndex]) 20 | } 21 | else { 22 | fetchUserById(params.userId).then((res) => { 23 | if (res.data) { 24 | setUser(res.data.user) 25 | userDispatch({type:"ADD_USER",payload:res.data.user}) 26 | } 27 | if (res.error) { 28 | console.log(res.error) 29 | } 30 | }).catch(err => console.log(err)) 31 | } 32 | } 33 | 34 | }, [params.userId]) 35 | 36 | return
{user && }
37 | } 38 | 39 | export default Profile 40 | -------------------------------------------------------------------------------- /src/screens/Settings.js: -------------------------------------------------------------------------------- 1 | import React, { Suspense, useContext, useEffect, useState } from 'react' 2 | import { UIContext } from '../App' 3 | import { 4 | Container, 5 | Divider, 6 | Grid, 7 | List, 8 | ListItem, 9 | ListItemIcon, 10 | ListItemText, 11 | Paper, 12 | Typography, 13 | } from '@material-ui/core' 14 | import { SecurityOutlined,LocationCityOutlined,PersonOutline } from '@material-ui/icons' 15 | import DrawerBar from '../components/Navbar/DrawerBar' 16 | const General = React.lazy(() => import('../components/settings/General')) 17 | const SecurityAndLogin = React.lazy(() => 18 | import('../components/settings/SecurityAndLogin'), 19 | ) 20 | 21 | const Location = React.lazy(() => import('../components/settings/Location')) 22 | 23 | function Settings() { 24 | const { uiState, uiDispatch } = useContext(UIContext) 25 | const [tab, setTab] = useState('general') 26 | 27 | useEffect(() => { 28 | uiDispatch({ type: 'SET_NAV_MENU', payload: true }) 29 | uiDispatch({ type: 'SET_DRAWER', payload: true }) 30 | 31 | return () => { 32 | uiDispatch({ type: 'SET_NAV_MENU', payload: false }) 33 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 34 | } 35 | }, []) 36 | const handleTabClick = (tab_data) => { 37 | setTab(tab_data) 38 | uiDispatch({ type: 'SET_DRAWER', payload: false }) 39 | } 40 | const ListContents = ( 41 | <> 42 | 43 | handleTabClick('general')} 46 | style={{ 47 | backgroundColor: 48 | tab === 'general' 49 | ? uiState.darkMode 50 | ? 'rgb(76,76,76)' 51 | : 'rgb(235,237,240)' 52 | : null, 53 | }} 54 | > 55 | 56 | 57 | 58 | 59 | 60 | handleTabClick('security_and_login')} 63 | style={{ 64 | backgroundColor: 65 | tab === 'security_and_login' 66 | ? uiState.darkMode 67 | ? 'rgb(76,76,76)' 68 | : 'rgb(235,237,240)' 69 | : null, 70 | }} 71 | > 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | handleTabClick('location')} 83 | style={{ 84 | backgroundColor: 85 | tab === 'location' 86 | ? uiState.darkMode 87 | ? 'rgb(76,76,76)' 88 | : 'rgb(235,237,240)' 89 | : null, 90 | }} 91 | > 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | ) 100 | return ( 101 | 108 | {!uiState.mdScreen && {ListContents}} 109 | 110 | {uiState.mdScreen && ( 111 | 112 | 113 | {ListContents} 114 | 115 | 116 | )} 117 | 118 | 119 | Loading}> 120 | {tab === 'general' && } 121 | 122 | {tab === 'security_and_login' && } 123 | 124 | {tab === 'location' && } 125 | 126 | 127 | 128 | 129 | 130 | ) 131 | } 132 | 133 | export default Settings 134 | -------------------------------------------------------------------------------- /src/services/AuthService.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | const url = process.env.REACT_APP_ENDPOINT 3 | 4 | export const fetchCurrentUser = async () => { 5 | let token = localStorage.token && JSON.parse(localStorage.token) 6 | 7 | try { 8 | const { data } = await axios.get(`${url}/api/user/me`, { 9 | headers: { 10 | Authorization: `Bearer ${token}`, 11 | }, 12 | }) 13 | if (data) { 14 | return { 15 | data, 16 | } 17 | } 18 | } catch (err) { 19 | if (err && err.response) { 20 | return { 21 | error: err.response.data.error, 22 | } 23 | } 24 | } 25 | } 26 | 27 | export const loginUser = async (userData, loading, setLoading) => { 28 | try { 29 | setLoading(true) 30 | const { data } = await axios.post( 31 | `${process.env.REACT_APP_ENDPOINT}/api/auth/login`, 32 | userData, 33 | ) 34 | setLoading(false) 35 | if (data) { 36 | return { 37 | data, 38 | } 39 | } 40 | } catch (err) { 41 | setLoading(false) 42 | if (err && err.response) { 43 | return { 44 | error: err.response.data.error, 45 | } 46 | } 47 | } 48 | } 49 | 50 | export const LogoutUser = async () => { 51 | let token = localStorage.token && JSON.parse(localStorage.token) 52 | 53 | try { 54 | const { data } = await axios.get(`${url}/api/auth/logout`, { 55 | headers: { 56 | Authorization: `Bearer ${token}`, 57 | }, 58 | }) 59 | if (data) { 60 | return { 61 | data, 62 | } 63 | } 64 | } catch (err) { 65 | if (localStorage.token) { 66 | localStorage.removeItem('token') 67 | } 68 | if (err && err.response) { 69 | return { 70 | status: err.response.status, 71 | error: err.response.data.error, 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/services/ChatService.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | const url = process.env.REACT_APP_ENDPOINT 3 | 4 | 5 | export const fetchFriendMessages = async (friend_id) => { 6 | let token = localStorage.token && JSON.parse(localStorage.token) 7 | try{ 8 | const res = await axios.get(`${url}/api/user/chat/${friend_id}/get_messages`,{headers:{ 9 | Authorization:`Bearer ${token}` 10 | }}) 11 | return { 12 | data:res.data 13 | } 14 | 15 | }catch(err){ 16 | console.log(err) 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/services/PostServices.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | const url = process.env.REACT_APP_ENDPOINT 3 | 4 | export const fetchAllPosts = async () => { 5 | let token = JSON.parse(localStorage.token) 6 | 7 | try { 8 | const response = await axios.get(`${url}/api/post/`, { 9 | headers: { 10 | Authorization: `Bearer ${token}`, 11 | }, 12 | }) 13 | if (response.data) { 14 | return { 15 | data: response.data, 16 | } 17 | } 18 | } catch (err) { 19 | console.log(err) 20 | } 21 | } 22 | 23 | // export const fetchPostById = async (post_id) => { 24 | // let token = JSON.parse(localStorage.token) 25 | 26 | // try { 27 | // const response = await axios.get(`${url}/api/post/${post_id}`, { 28 | // headers: { 29 | // Authorization: `Bearer ${token}`, 30 | // }, 31 | // }) 32 | // if (response.data) { 33 | // return { 34 | // data: response.data, 35 | // } 36 | // } 37 | // } catch (err) { 38 | // console.log(err) 39 | // } 40 | // } 41 | 42 | export const likeDislikePost = async (post_id) => { 43 | let token = JSON.parse(localStorage.token) 44 | 45 | try { 46 | const response = await axios.get( 47 | `${url}/api/post/${post_id}/like_dislike`, 48 | { 49 | headers: { 50 | Authorization: `Bearer ${token}`, 51 | }, 52 | }, 53 | ) 54 | if (response.data) { 55 | return { 56 | data: response.data, 57 | } 58 | } 59 | } catch (err) { 60 | console.log(err) 61 | if (err && err.response) { 62 | return { 63 | status: err.response.status, 64 | error: err.response.data.error, 65 | } 66 | } 67 | } 68 | } 69 | 70 | export const likeDislikeComment = async (comment_id) => { 71 | try { 72 | let token = JSON.parse(localStorage.token) 73 | const response = await axios.get( 74 | `${url}/api/post/comment/${comment_id}/like_dislike`, 75 | { 76 | headers: { 77 | Authorization: `Bearer ${token}`, 78 | }, 79 | }, 80 | ) 81 | if (response.data) { 82 | return { 83 | data: response.data, 84 | } 85 | } 86 | } catch (err) { 87 | console.log(err) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/services/UserServices.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | const url = process.env.REACT_APP_ENDPOINT 3 | 4 | export const fetchUserById = async (user_id) => { 5 | let token = JSON.parse(localStorage.token) 6 | try { 7 | const { data } = await axios.get(`${url}/api/user/${user_id}`, { 8 | headers: { 9 | Authorization: `Bearer ${token}`, 10 | }, 11 | }) 12 | if (data) { 13 | return { 14 | data, 15 | } 16 | } 17 | } catch (err) { 18 | if (err && err.response) { 19 | return { 20 | error: err.response.data.error, 21 | } 22 | } 23 | } 24 | } 25 | 26 | export const fetchRecommandedUsers = async () => { 27 | let token = JSON.parse(localStorage.token) 28 | try { 29 | const { data } = await axios.get(`${url}/api/user/recommanded_users`, { 30 | headers: { 31 | Authorization: `Bearer ${token}`, 32 | }, 33 | }) 34 | if (data) { 35 | return { 36 | data, 37 | } 38 | } 39 | } catch (err) { 40 | if (err && err.response) { 41 | return { 42 | error: err.response.data.error, 43 | } 44 | } 45 | } 46 | } 47 | 48 | 49 | export const sendFriendRequest = async (user_id) => { 50 | let token = JSON.parse(localStorage.token) 51 | try { 52 | const { data } = await axios.get(`${url}/api/user/friend_request/${user_id}/send`, { 53 | headers: { 54 | Authorization: `Bearer ${token}`, 55 | }, 56 | }) 57 | if (data) { 58 | return { 59 | data, 60 | } 61 | } 62 | } catch (err) { 63 | if (err && err.response) { 64 | return { 65 | error: err.response.data.error, 66 | } 67 | } 68 | } 69 | } 70 | 71 | 72 | export const fetchIncommingFriendRequests = async () => { 73 | let token = JSON.parse(localStorage.token) 74 | try { 75 | const { data } = await axios.get(`${url}/api/user/friend_request/received`, { 76 | headers: { 77 | Authorization: `Bearer ${token}`, 78 | }, 79 | }) 80 | if (data) { 81 | return { 82 | data, 83 | } 84 | } 85 | } catch (err) { 86 | if (err && err.response) { 87 | return { 88 | error: err.response.data.error, 89 | } 90 | } 91 | } 92 | } 93 | 94 | 95 | 96 | export const fetchSendedFriendRequests = async () => { 97 | let token = JSON.parse(localStorage.token) 98 | try { 99 | const { data } = await axios.get(`${url}/api/user/friend_request/sended`, { 100 | headers: { 101 | Authorization: `Bearer ${token}`, 102 | }, 103 | }) 104 | if (data) { 105 | return { 106 | data, 107 | } 108 | } 109 | } catch (err) { 110 | if (err && err.response) { 111 | return { 112 | error: err.response.data.error, 113 | } 114 | } 115 | } 116 | } 117 | 118 | 119 | 120 | export const acceptFriendRequest = async (request_id) => { 121 | let token = JSON.parse(localStorage.token) 122 | try { 123 | const { data } = await axios.get(`${url}/api/user/friend_request/${request_id}/accept`, { 124 | headers: { 125 | Authorization: `Bearer ${token}`, 126 | }, 127 | }) 128 | if (data) { 129 | return { 130 | data, 131 | } 132 | } 133 | } catch (err) { 134 | if (err && err.response) { 135 | return { 136 | error: err.response.data.error, 137 | } 138 | } 139 | } 140 | } 141 | 142 | 143 | export const declineFriendRequest = async (request_id) => { 144 | let token = JSON.parse(localStorage.token) 145 | try { 146 | const { data } = await axios.get(`${url}/api/user/friend_request/${request_id}/decline`, { 147 | headers: { 148 | Authorization: `Bearer ${token}`, 149 | }, 150 | }) 151 | if (data) { 152 | return { 153 | data, 154 | } 155 | } 156 | } catch (err) { 157 | if (err && err.response) { 158 | return { 159 | error: err.response.data.error, 160 | } 161 | } 162 | } 163 | } 164 | 165 | 166 | 167 | 168 | export const cancelFriendRequest = async (request_id) => { 169 | let token = JSON.parse(localStorage.token) 170 | try { 171 | const { data } = await axios.get(`${url}/api/user/friend_request/${request_id}/cancel`, { 172 | headers: { 173 | Authorization: `Bearer ${token}`, 174 | }, 175 | }) 176 | if (data) { 177 | return { 178 | data, 179 | } 180 | } 181 | } catch (err) { 182 | if (err && err.response) { 183 | return { 184 | error: err.response.data.error, 185 | } 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/utils/FilterArray.js: -------------------------------------------------------------------------------- 1 | export const filterArray = (originalArray) => { 2 | var newArray = [] 3 | var lookupObject = {} 4 | 5 | for (var i in originalArray) { 6 | lookupObject[originalArray[i].id] = originalArray[i] 7 | } 8 | 9 | for (i in lookupObject) { 10 | newArray.push(lookupObject[i]) 11 | } 12 | return newArray 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/utils/ProtectedRoute.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Redirect, Route } from 'react-router-dom' 3 | 4 | function ProtectedRoute({ component: Component, isLoggedIn, ...rest }) { 5 | return ( 6 | { 9 | if (isLoggedIn) { 10 | return 11 | } else { 12 | return ( 13 | 14 | ) 15 | } 16 | }} 17 | /> 18 | ) 19 | } 20 | 21 | export default ProtectedRoute 22 | --------------------------------------------------------------------------------