Created
October 2, 2021 00:03
-
-
Save TheGreatAndrew/63a8b7da0277a9659dad5b64d163c74d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect } from 'react'; | |
import { useDispatch, useSelector } from 'react-redux'; | |
import axios from 'axios'; | |
import socketIOClient from 'socket.io-client'; | |
import { Snackbar } from '@material-ui/core'; | |
import MuiAlert from '@material-ui/lab/Alert'; | |
// Local Imports | |
import Onboard from '../../components/Main/Onboard/index'; | |
import Messages from '../../components/Main/Messages/index'; | |
import MsgInput from '../../components/Main/MsgInput/index'; | |
import MainTopBar from '../../components/Main/TopBar/index'; | |
import SideTopBar from '../../components/Side/TopBar/index'; | |
import BottomBar from '../../components/Side/BottomBar/index'; | |
import Search from '../../components/Side/Search/index'; | |
import Groups from '../../components/Side/Groups/index'; | |
import GroupInfo from '../../components/Side/GroupInfo/index'; | |
import Members from '../../components/Side/Members/index'; | |
import EditProfile from '../../components/Shared/EditProfile/index'; | |
import styles from './styles.module.scss'; | |
import Modal from '../../components/Shared/Modal/index'; | |
import ForrestModal from '../../components/Shared/Modal/ForrestModal'; | |
type GroupData = { | |
_id: string; | |
title: string; | |
description: string; | |
groupClick: () => void; | |
}; | |
type SnackData = { | |
open: boolean; | |
message: string | null; | |
severity: 'success' | 'error' | undefined; | |
}; | |
interface IRootState { | |
auth: { | |
isLogged: boolean; | |
id: string | null; | |
username: string | null; | |
image: string | null; | |
token: string | null; | |
}; | |
app: { | |
inChannel: boolean; | |
currentGroup: GroupData; | |
displayedGroups: GroupData[]; | |
messages: []; | |
members: []; | |
groups: []; | |
modal: null | 'bug' | 'edit' | 'create' | 'forrest'; | |
forrest : number | |
}; | |
} | |
const AppView: React.FC = () => { | |
const dispatch = useDispatch(); | |
const userData = useSelector((state: IRootState) => state.auth); | |
const { inChannel, currentGroup, displayedGroups, messages, members, groups, modal, forrest } = useSelector( | |
(state: IRootState) => state.app | |
); | |
const [mobile, setMobile] = useState(false); | |
const [loading, setLoading] = useState(false); | |
const [snack, setSnack] = useState<SnackData>({ open: false, severity: undefined, message: null }); | |
const [socket, setSocket] = useState<SocketIOClient.Socket | null>(null); | |
useEffect(() => { | |
const socket = socketIOClient(process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SOCKET_URL!, { transports: ['websocket'] }); | |
socket.emit('new user', userData.id); | |
socket.on('fetch messages', (id: string) => fetchMessages(id)); | |
socket.on('fetch group', fetchGroups); | |
// socket.on('fetch forrest', (uid: string) => fetchForrest(uid)); | |
setSocket(socket); | |
fetchGroups(); | |
}, []); | |
// whenever switch to new group | |
useEffect(() => { | |
if (!socket) return; | |
socket.emit('join group', userData.id, currentGroup?._id); | |
fetchMessages(); | |
}, [currentGroup]); | |
// Handlers | |
const logoutHandler = () => { | |
socket?.disconnect(); | |
localStorage.removeItem('userData'); | |
dispatch({ type: 'LOGOUT' }); | |
}; | |
const groupHandler = (id: string) => { | |
setLoading(true); | |
const current = groups.filter((item: GroupData) => item._id === id); | |
if (current.length > 0) { | |
dispatch({ type: 'CHANGE GROUP', payload: { currentGroup: current[0] } }); | |
} | |
}; | |
// Async Requests | |
const createGroup = async (title: string, description: string) => { | |
const { token, id } = userData; | |
if (!token) { | |
setSnack({ open: true, severity: 'error', message: `Guests are not allowed to create groups, please register.` }); | |
return; | |
} | |
let verifiedToken; | |
try { | |
verifiedToken = await axios.post(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/users/verify`, { | |
id, | |
token | |
}); | |
} catch (error) { | |
console.log('[ERROR][AUTH][VERIFY]: ', error); | |
return; | |
} | |
if (!verifiedToken.data.access) { | |
localStorage.removeItem('userData'); | |
return; | |
} | |
let response; | |
try { | |
response = await axios.post(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/groups`, { | |
title, | |
description: description ? description : 'No description.' | |
}); | |
} catch (error) { | |
console.log('[ERROR][GROUPS][CREATE]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not create group.` }); | |
return; | |
} | |
if (!response) return; | |
dispatch({ type: 'MODAL', payload: { modal: null } }); | |
fetchGroups(); | |
socket?.emit('create group', userData.id, title); | |
setSnack({ open: true, severity: 'success', message: `${title} channel created.` }); | |
}; | |
const editProfileRequest = async (username: string, image: string) => { | |
const { token, id } = userData; | |
if (!token) { | |
setSnack({ open: true, severity: 'error', message: `Guests are not allowed to edit profile, please register.` }); | |
return; | |
} | |
let verifiedToken; | |
try { | |
verifiedToken = await axios.post(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/users/verify`, { | |
id, | |
token | |
}); | |
} catch (error) { | |
console.log('[ERROR][AUTH][VERIFY]: ', error); | |
return; | |
} | |
if (!verifiedToken.data.access) { | |
localStorage.removeItem('userData'); | |
return; | |
} | |
let response; | |
try { | |
response = await axios.put(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/users/edit`, { | |
id, | |
username, | |
image | |
}); | |
} catch (error) { | |
console.log('[ERROR][USERS][EDIT]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not edit profile.` }); | |
return; | |
} | |
if (!response) return; | |
setSnack({ open: true, severity: 'success', message: `Profile updated.` }); | |
dispatch({ type: 'MODAL', payload: { modal: null } }); | |
dispatch({ type: 'EDIT', payload: { username: response.data.user.username, image: response.data.user.image } }); | |
}; | |
const createMessage = async (text: string, date: string) => { | |
if (!socket) return; | |
// post the message by this user, into the current group, then instruct socket to reload messages | |
let response; | |
try { | |
response = await axios.post(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/messages`, { | |
gid: currentGroup?._id, | |
text, | |
username: userData.username, | |
image: userData.image, | |
uid: userData.id, | |
date | |
}); | |
} catch (error) { | |
console.log('[ERROR][GROUPS][CREATE]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not send message.` }); | |
return; | |
} | |
if (!response) return; | |
socket?.emit('message', userData.id, currentGroup?._id); | |
}; | |
const fetchGroups = async () => { | |
let response; | |
try { | |
response = await axios.get(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/groups`); | |
} catch (error) { | |
console.log('[ERROR][GROUPS][FETCH]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not fetch groups.` }); | |
return; | |
} | |
if (!response) return; | |
dispatch({ | |
type: 'FETCH GROUPS', | |
payload: { displayedGroups: response.data.groups, groups: response.data.groups } | |
}); | |
}; | |
const fetchMessages = async (gid = currentGroup?._id) => { | |
if (!gid) return; | |
let response; | |
try { | |
response = await axios.get(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/groups/${gid}`); | |
} catch (error) { | |
console.log('[ERROR][MESSAGES][FETCH]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not fetch messages and members.` }); | |
setLoading(false); | |
return; | |
} | |
setLoading(false); | |
if (response.data.error) { | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not fetch messages and members.` }); | |
return; | |
} | |
dispatch({ type: 'FETCH MESSAGES', payload: { messages: response.data.messages, members: response.data.members } }); | |
}; | |
const deleteMessage = async (mid:string) => { | |
console.log(mid) | |
if (!mid) return; | |
let response; | |
try { | |
response = await axios.delete(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/messages/${mid}`); | |
} catch (error) { | |
console.log('[ERROR][MESSAGES][DELETE]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not delete messages.` }); | |
setLoading(false); | |
return; | |
} | |
setLoading(false); | |
if (response.data.error) { | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not delete messages.` }); | |
return; | |
} | |
fetchMessages() | |
dispatch({ type: 'DELETE MESSAGES', payload: { messages: response.data.messages, members: response.data.members } }); | |
}; | |
const reportBug = async (title: string, description: string) => { | |
const { id } = userData; | |
let response; | |
try { | |
response = await axios.post(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/bugs`, { | |
id, | |
title, | |
description: description ? description : 'No description.' | |
}); | |
} catch (error) { | |
console.log('[ERROR][BUGS][CREATE]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not report bug.` }); | |
return; | |
} | |
if (!response) return; | |
dispatch({ type: 'MODAL', payload: { modal: null } }); | |
setSnack({ open: true, severity: 'success', message: `Bug reported, thank you!` }); | |
}; | |
// Render | |
let sideContent; | |
let mainContent; | |
if (inChannel) { | |
sideContent = ( | |
<div className={styles.sideContent}> | |
<GroupInfo currentGroup={currentGroup} /> | |
<Members members={members} loading={loading} /> | |
</div> | |
); | |
mainContent = ( | |
<div className={styles.main}> | |
<MainTopBar title={currentGroup?.title} menuClick={() => setMobile(true)} /> | |
<Messages messages={messages} onClick={() => setMobile(false)} onDelete={deleteMessage}loading={loading} /> | |
{/* TODO */} | |
<MsgInput sendClick={createMessage} onClick={() => setMobile(false)} /> | |
</div> | |
); | |
} else { | |
sideContent = ( | |
<div className={styles.sideContent}> | |
<Search | |
groups={groups} | |
update={filteredGroups => dispatch({ type: 'SEARCH', payload: { displayedGroups: filteredGroups } })} | |
/> | |
<Groups groups={displayedGroups} groupClick={id => groupHandler(id)} /> | |
</div> | |
); | |
mainContent = ( | |
<div className={styles.main}> | |
<MainTopBar title="" menuClick={() => setMobile(true)} /> | |
<Onboard onClick={() => setMobile(false)} /> | |
</div> | |
); | |
} | |
// fetch forrest | |
const fetchForrest = async (uid: string) => { | |
if (!uid) return; | |
let response; | |
try { | |
response = await axios.get(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/users/forrest/${uid}`); | |
} catch (error) { | |
console.log('[ERROR][FORREST]: ', error); | |
setSnack({ open: true, severity: 'error', message: `An error occured: Could not fetch forrest.` }); | |
return; | |
} | |
setLoading(false); | |
dispatch({ type: 'FETCH FORREST', payload: { forrest: response.data.forrest } }); | |
return response.data.forrest; | |
} | |
// save forrest | |
const incrementForrest = async (uid : string, time: Number) => { | |
let response; | |
try { | |
response = await axios.put(`${process.env.REACT_APP_MY_HEROKU_BACKEND_URL || process.env.REACT_APP_SERVER_URL}/users/forrest`, { | |
id : uid, | |
forrest : time | |
}); | |
} catch (error) { | |
console.log('[ERROR][FORREST]: ', error); | |
return; | |
} | |
} | |
// render forrest | |
const renderForrest = ( | |
<div>Hello andrew {forrest}</div> | |
) | |
return ( | |
<div className={styles.container}> | |
<div className={mobile ? styles.mobile : styles.side}> | |
{/* <button onClick={()=>{ | |
// changeForrestRedux(); | |
if(userData.id) fetchForrest(userData.id) | |
if(userData.id) incrementForrest(userData.id, 10) | |
}}/> | |
{renderForrest} */} | |
<SideTopBar | |
inChannel={inChannel} | |
arrowClick={() => { | |
dispatch({ type: 'EXIT' }); | |
}} | |
plusClick={() => { | |
dispatch({ type: 'MODAL', payload: { modal: 'create' } }); | |
setMobile(false); | |
}} | |
/> | |
{sideContent} | |
<BottomBar | |
exitClick={logoutHandler} | |
profileClick={() => { | |
dispatch({ type: 'MODAL', payload: { modal: 'edit' } }); | |
setMobile(false); | |
}} | |
bugClick={() => { | |
dispatch({ type: 'MODAL', payload: { modal: 'bug' } }); | |
setMobile(false); | |
}} | |
forrestClick={() => { | |
dispatch({ type: 'MODAL', payload: { modal: 'forrest' } }); | |
setMobile(false); | |
}} | |
/> | |
</div> | |
{mainContent} | |
{modal === 'create' && <Modal onCreate={createGroup} title="New Channel" />} | |
{modal === 'edit' && <EditProfile onEdit={editProfileRequest} fetchForrest={fetchForrest}/>} | |
{modal === 'bug' && <Modal onCreate={reportBug} title="Bug Report"/>} | |
{modal === 'forrest' && <ForrestModal incrementForrest={incrementForrest} title="Focus" />} | |
<Snackbar | |
open={snack.open} | |
onClose={() => setSnack({ open: false, severity: snack.severity, message: null })} | |
autoHideDuration={5000} | |
> | |
<MuiAlert | |
variant="filled" | |
onClose={() => setSnack({ open: false, severity: snack.severity, message: null })} | |
severity={snack.severity} | |
> | |
{snack.message} | |
</MuiAlert> | |
</Snackbar> | |
</div> | |
); | |
}; | |
export default AppView; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment