|
|
// view-app.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 } from 'react' import { useSelector, useDispatch } from 'react-redux' import { Link, useParams, useHistory } from 'react-router-dom' import { faPlusSquare, faMinusSquare } from '@fortawesome/free-solid-svg-icons' import moment from 'moment'
import { handleApiError } from '../../api/errors' import { fetchApp, installApp, uninstallApp } from '../../actions/apps' import { fetchInstallations } from '../../actions/composer' import { getAuthenticatedUserId } from '../../selectors/authentication' import { getInstallations } from '../../selectors/composer' import { getEntity } from '../../selectors/entities' import { getIsFetching } from '../../selectors/requests'
import { useTheme } from '../../hooks' import { setTitle } from '../../utils' import { AppState, AppThunkDispatch, EntityType, App, RequestKey, LevelItem } from '../../types'
import Title from '../../components/title' import Section from '../../components/section' import HorizontalRule from '../../components/horizontal-rule' import Button from '../../components/controls/button' import Level from '../../components/level' import Loading from '../../components/pages/loading'
interface Params { id: string }
const ViewApp: FC = () => { const { id } = useParams<Params>() const theme = useTheme() const app = useSelector<AppState, App | undefined>(state => getEntity<App>(state, EntityType.App, id)) const installations = useSelector(getInstallations) const selfId = useSelector(getAuthenticatedUserId) const fetching = useSelector<AppState, boolean>(state => getIsFetching(state, RequestKey.InstallApp) || getIsFetching(state, RequestKey.UninstallApp)) const dispatch = useDispatch<AppThunkDispatch>() const history = useHistory()
useEffect(() => { try { dispatch(fetchApp(id)) dispatch(fetchInstallations()) } catch (err) { handleApiError(err, dispatch, history) } }, [])
useEffect(() => { if (app) setTitle(app.name) }, [app])
if (!app) return <Loading />
const isCreator = app.user.id === selfId const installed = !!installations.find(i => i.app.id === app.id)
const renderButton = () => { if (installed) { const handleClick = async () => { await dispatch(uninstallApp(id)) await dispatch(fetchApp(id)) }
return ( <Button text="Uninstall" icon={faMinusSquare} loading={fetching} onClick={() => handleClick()} color="#fff" backgroundColor={theme.red} /> ) } else { const handleClick = async () => { await dispatch(installApp(id)) await dispatch(fetchApp(id)) }
return ( <Button text="Install" icon={faPlusSquare} loading={fetching} onClick={() => handleClick()} color={theme.primaryAlternate} backgroundColor={theme.primary} /> ) } }
const items: LevelItem[] = [] items.push({ label: 'Users', content: app.users, }) items.push({ label: 'Rating', content: app.rating.toString(), }) if (app.companyName) { items.push({ label: 'Company', content: app.companyName, }) }
items.push({ label: 'Updated', content: moment(app.updated).format('MMMM Do, YYYY'), })
return ( <div> <Section> {app.coverImageUrl && <div className="cover-image"> <img src={app.coverImageUrl} /> </div> }
<div className="header"> {app.imageUrl && <div className="image"> <img src={app.imageUrl} /> </div> } <div> <Title>{app.name}</Title> <p style={{ color: theme.text }}>{app.about}</p> </div> </div> <Level items={items} />
<div style={{ textAlign: 'center', padding: '1rem' }}> {renderButton()} </div>
<HorizontalRule />
<div className="buttons"> {isCreator && <Link style={{ color: theme.secondary }} to={`/a/${id}/edit`}>View/Edit App</Link>} </div> </Section> </div> ) }
export default ViewApp
|