|
|
// view-user.tsx
// Copyright (C) 2020 Dwayne Harris
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import React, { FC, useEffect, useState } from 'react' import { useSelector, useDispatch } from 'react-redux' import { useParams, useHistory } from 'react-router-dom' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faUserPlus, faUserMinus, faUserClock, faBan } from '@fortawesome/free-solid-svg-icons' import moment from 'moment'
import { handleApiError } from '../../api/errors' import { fetchUser, subscribe, unsubscribe } from '../../actions/users' import { fetchUserPosts } from '../../actions/posts' import { setTheme } from '../../actions/theme' import { getEntity } from '../../selectors/entities' import { getAuthenticatedUser, getChecked } from '../../selectors/authentication' import { getUserPosts } from '../../selectors/posts' import { getThemeName } from '../../selectors/theme'
import { useDeepCompareEffect, useTheme, useSetting } from '../../hooks' import { setTitle } from '../../utils' import { AppState, EntityType, User, Post, AppThunkDispatch, LevelItem } from '../../types'
import Title from '../../components/title' import Subtitle from '../../components/subtitle' import Level from '../../components/level' import PostList from '../../components/post-list' import Section from '../../components/section' import HorizontalRule from '../../components/horizontal-rule' import Loading from '../../components/pages/loading'
interface Params { id: string }
const ViewUser: FC = () => { const { id } = useParams<Params>() const theme = useTheme() const themeName = useSelector(getThemeName) const [selectedThemeName] = useState(themeName) const checked = useSelector(getChecked) const self = useSelector(getAuthenticatedUser) const user = useSelector<AppState, User | undefined>(state => getEntity<User>(state, EntityType.User, id)) const posts = useSelector<AppState, Post[]>(state => getUserPosts(state, id)) const dispatch = useDispatch<AppThunkDispatch>() const history = useHistory() const allowThemeChange = useSetting<boolean>('allowThemeChange', true)
useEffect(() => { const init = async () => { try { await dispatch(fetchUser(id)) await dispatch(fetchUserPosts(id)) } catch (err) { handleApiError(err, dispatch, history) } }
if (checked) init() }, [checked])
useDeepCompareEffect(() => { if (user) { setTitle(user.name) if (allowThemeChange && user.theme) dispatch(setTheme(user.theme)) }
return () => { if (allowThemeChange && selectedThemeName) dispatch(setTheme(selectedThemeName)) } }, [user])
if (!user) return <Loading />
const isSelf = self && self.id === user.id const isGroup = self && self.group && user.group && self.group.id === user.group.id const subscription = self && user.subscriptions ? user.subscriptions.find(subscription => subscription.from === self.id && subscription.to === user.id) : undefined const subscribed = subscription && !subscription.pending const subscriptionPending = subscription && subscription.pending
const items: LevelItem[] = [] items.push({ label: 'Posts', content: user.posts, }) items.push({ label: 'Awards', content: user.awards, }) items.push({ label: 'Points', content: user.points, }) items.push({ label: 'Joined', content: moment(user.created).format('MMMM Do, YYYY'), })
return ( <div> <Section> {user.coverImageUrl && <div className="cover-image"> <img src={user.coverImageUrl} /> </div> }
<div className="header"> {user.imageUrl && <div className="image"> <img src={user.imageUrl} style={{ width: 128 }} /> </div> } <div> <Title>{user.name}</Title> <p style={{ color: theme.text }}>{user.about}</p> </div> </div> <Level items={items} /> <HorizontalRule />
<div className="buttons"> {subscribed && <button style={{ backgroundColor: theme.red, color: 'white' }} onClick={() => dispatch(unsubscribe(user.id))}> <span className="button-icon"> <FontAwesomeIcon icon={faUserMinus} /> </span> <span>Unsusbcribe</span> </button> }
{subscriptionPending && <button style={{ backgroundColor: theme.blue, color: 'white' }}> <span className="button-icon"> <FontAwesomeIcon icon={faUserClock} /> </span> <span>Pending</span> </button> }
{self && !isSelf && !subscribed && !subscriptionPending && <button style={{ backgroundColor: theme.green, color: 'white' }} onClick={() => dispatch(subscribe(user.id))}> <span className="button-icon"> <FontAwesomeIcon icon={faUserPlus} /> </span> <span>Subscribe</span> </button> }
{!isSelf && <button style={{ backgroundColor: theme.red, color: 'white' }}> <span className="button-icon"> <FontAwesomeIcon icon={faBan} /> </span> <span>Block</span> </button> }
{user.group && !isGroup && <button style={{ backgroundColor: theme.red, color: 'white' }}> <span className="button-icon"> <FontAwesomeIcon icon={faBan} /> </span> <span>Block Community: {user.group.name}</span> </button> } </div> </Section>
<div style={{ padding: '0px 1rem' }}> <Subtitle>Posts</Subtitle> </div>
<PostList posts={posts} /> </div> ) }
export default ViewUser
|