This repository has been archived on 2025-09-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
resolver/src/containers/home/HomeComponent.tsx

372 lines
11 KiB
TypeScript

// - Import react components
import { HomeRouter } from 'routes'
import { Map } from 'immutable'
import React, { Component } from 'react'
import _ from 'lodash'
import { Route, Switch, withRouter, Redirect, NavLink } from 'react-router-dom'
import { connect } from 'react-redux'
import { push } from 'react-router-redux'
import { getTranslate, getActiveLanguage } from 'react-localize-redux'
import config from 'src/config'
import classNames from 'classnames'
import { withStyles } from '@material-ui/core/styles'
import Drawer from '@material-ui/core/Drawer'
import Menu from '@material-ui/core/Menu'
import MenuList from '@material-ui/core/MenuList'
import MenuItem from '@material-ui/core/MenuItem'
import ListItem from '@material-ui/core/ListItem'
import ListIcon from '@material-ui/core/ListItemIcon'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import ListItemText from '@material-ui/core/ListItemText'
import Divider from '@material-ui/core/Divider'
import SvgArrowLeft from '@material-ui/icons/KeyboardArrowLeft'
import SvgHome from '@material-ui/icons/Home'
import SvgFeedback from '@material-ui/icons/Feedback'
import SvgSettings from '@material-ui/icons/Settings'
import SvgAccountCircle from '@material-ui/icons/AccountCircle'
import SvgPeople from '@material-ui/icons/People'
import List from '@material-ui/core/List'
import Typography from '@material-ui/core/Typography'
import IconButton from '@material-ui/core/IconButton'
import Hidden from '@material-ui/core/Hidden'
import MenuIcon from '@material-ui/icons/Menu'
// - Import app components
import Sidebar from 'src/components/sidebar'
import StreamComponent from 'containers/stream'
import HomeHeader from 'src/components/homeHeader'
import SidebarContent from 'src/components/sidebarContent'
import SidebarMain from 'src/components/sidebarMain'
import Profile from 'containers/profile'
import PostPage from 'containers/postPage'
import People from 'containers/people'
// - Import API
// - Import actions
// - Import actions
import {
authorizeActions,
imageGalleryActions,
postActions,
commentActions,
voteActions,
userActions,
globalActions,
circleActions,
notifyActions
} from 'src/store/actions'
import { IHomeComponentProps } from './IHomeComponentProps'
import { IHomeComponentState } from './IHomeComponentState'
const drawerWidth = 220
const styles = (theme: any) => ({
root: {
width: '100%',
marginTop: theme.spacing.unit * 3,
zIndex: 1,
overflow: 'hidden',
},
appFrame: {
position: 'relative',
display: 'flex',
width: '100%',
height: '100%',
},
navIconHide: {
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
drawerHeader: theme.mixins.toolbar,
drawerPaper: {
maxWidth: drawerWidth,
width: drawerWidth,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
position: 'relative',
height: '100%',
},
},
drawerPaperLarge: {
width: drawerWidth,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
height: '100%',
},
top: 70,
backgroundColor: '#fafafa',
borderRight: 0
},
menu: {
height: '100%',
},
content: {
backgroundColor: 'transparent',
width: '100%',
flexGrow: 1,
padding: theme.spacing.unit * 1,
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
height: 'calc(100% - 56px)',
marginTop: 56,
[theme.breakpoints.up('sm')]: {
height: 'calc(100% - 64px)',
marginTop: 64,
},
},
'content-left': {
marginLeft: 0,
},
'content-right': {
marginRight: 0,
},
contentShift: {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
},
'contentShift-left': {
marginLeft: 0,
[theme.breakpoints.up('md')]: {
marginLeft: drawerWidth
}
},
'contentShift-right': {
marginRight: 0,
[theme.breakpoints.up('md')]: {
marginRight: drawerWidth
}
}
})
// - Create Home component class
export class HomeComponent extends Component<IHomeComponentProps, IHomeComponentState> {
// Constructor
constructor(props: IHomeComponentProps) {
super(props)
// Default state
this.state = {
drawerOpen: false
}
// Binding function to `this`
}
/**
* Handle drawer toggle
*/
handleDrawerToggle = () => {
this.setState({ drawerOpen: !this.state.drawerOpen })
}
componentWillMount() {
const { global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
if (!authed) {
goTo!('/login')
return
}
if (!isVerifide) {
goTo!('/emailVerification')
} else if (!global.get('defaultLoadDataStatus')) {
clearData!()
loadData!()
defaultDataEnable!()
}
}
/**
* Render DOM component
*
* @returns DOM
*
* @memberof Home
*/
render() {
const HR = HomeRouter
const { loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback, translate, classes, theme } = this.props
const { drawerOpen } = this.state
const drawer = (
<>
<NavLink to='/'>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgHome />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.home')} />
</MenuItem>
</NavLink>
<NavLink to={`/${this.props.uid}`}>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgAccountCircle />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.profile')} />
</MenuItem>
</NavLink>
<NavLink to='/people'>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgPeople />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.people')} />
</MenuItem>
</NavLink>
<Divider />
<NavLink to='/settings'>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgSettings />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.settings')} />
</MenuItem>
</NavLink>
<MenuItem onClick={() => showSendFeedback!()} style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgFeedback />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.sendFeedback')} />
</MenuItem>
</>
)
const anchor = theme.direction === 'rtl' ? 'right' : 'left'
return (
<div className={classes.root}>
<div className={classes.appFrame}>
<HomeHeader onToggleDrawer={this.handleDrawerToggle} drawerStatus={this.state.drawerOpen} />
<Hidden mdUp>
<Drawer
variant='temporary'
open={this.state.drawerOpen}
classes={{
paper: classes.drawerPaper,
}}
onClose={this.handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
<div>
<div className={classes.drawerHeader} />
<MenuList style={{ color: 'rgb(117, 117, 117)', width: '210px' }}>
<Divider />
{drawer}
</MenuList>
</div>
</Drawer>
</Hidden>
<Hidden smDown implementation='js'>
<Drawer
variant='persistent'
open={this.state.drawerOpen}
classes={{
paper: classes.drawerPaperLarge,
}}
>
<div>
<MenuList className={classes.menu} style={{ color: 'rgb(117, 117, 117)', width: '210px' }}>
{drawer}
</MenuList>
</div>
</Drawer>
</Hidden>
<main
className={classNames(classes.content, classes[`content-${anchor}`], {
[classes.contentShift]: drawerOpen,
[classes[`contentShift-${anchor}`]]: drawerOpen,
})}
>
<HR enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts }} />
</main>
</div>
</div>
)
}
}
// - Map dispatch to props
const mapDispatchToProps = (dispatch: any, ownProps: IHomeComponentProps) => {
return {
loadDataStream:
(page: number, limit: number) => dispatch(postActions.dbGetPosts(page, limit)),
loadData: () => {
dispatch(postActions.dbGetPosts())
dispatch(imageGalleryActions.dbGetImageGallery())
dispatch(userActions.dbGetUserInfo())
dispatch(notifyActions.dbGetNotifications())
dispatch(circleActions.dbGetCircles())
dispatch(circleActions.dbGetUserTies())
dispatch(circleActions.dbGetFollowers())
},
clearData: () => {
dispatch(imageGalleryActions.clearAllData())
dispatch(postActions.clearAllData())
dispatch(userActions.clearAllData())
dispatch(notifyActions.clearAllNotifications())
dispatch(circleActions.clearAllCircles())
dispatch(globalActions.clearTemp())
},
defaultDataDisable: () => {
dispatch(globalActions.defaultDataDisable())
},
defaultDataEnable: () => {
dispatch(globalActions.defaultDataEnable())
},
goTo: (url: string) => dispatch(push(url)),
showSendFeedback: () => dispatch(globalActions.showSendFeedback()),
hideSendFeedback: () => dispatch(globalActions.hideSendFeedback())
}
}
/**
* Map state to props
* @param {object} state is the obeject from redux store
* @param {object} ownProps is the props belong to component
* @return {object} props of component
*/
const mapStateToProps = (state: Map<string, any>, ownProps: IHomeComponentProps) => {
const uid = state.getIn(['authorize', 'uid'], {})
const global = state.get('global', {})
let mergedPosts = Map({})
const circles = state.getIn(['circle', 'circleList'], {})
const followingUsers: Map<string, any> = state.getIn(['circle', 'userTies'], {})
const posts = state.getIn(['post', 'userPosts', uid ], {})
const hasMorePosts = state.getIn(['post', 'stream', 'hasMoreData' ], true)
followingUsers.forEach((user, userId) => {
let newPosts = state.getIn(['post', 'userPosts', userId], {})
mergedPosts = mergedPosts.merge(newPosts)
})
mergedPosts = mergedPosts.merge(posts)
return {
authed: state.getIn(['authorize', 'authed'], false),
isVerifide: state.getIn(['authorize', 'isVerifide'], false),
translate: getTranslate(state.get('locale')),
currentLanguage: getActiveLanguage(state.get('locale')).code,
mergedPosts,
global,
hasMorePosts,
loaded: state.getIn(['user', 'loaded']) && state.getIn(['imageGallery', 'loaded']) && state.getIn(['notify', 'loaded']) && state.getIn(['circle', 'loaded'])
}
}
// - Connect component to redux store
export default withRouter<any>(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles as any, { withTheme: true })(HomeComponent as any) as any)) as typeof HomeComponent