|
|
@ -1,18 +1,21 @@ |
|
|
|
import React, { FC, useEffect } from 'react' |
|
|
|
import { useSelector, useDispatch } from 'react-redux' |
|
|
|
import { useParams, useHistory } from 'react-router-dom' |
|
|
|
import classNames from 'classnames' |
|
|
|
import moment from 'moment' |
|
|
|
|
|
|
|
import { handleApiError } from 'src/api/errors' |
|
|
|
import { fetchApp } from 'src/actions/apps' |
|
|
|
import { fetchApp, installApp, uninstallApp } from 'src/actions/apps' |
|
|
|
import { getAuthenticatedUserId } from 'src/selectors/authentication' |
|
|
|
import { getEntity } from 'src/selectors/entities' |
|
|
|
import { getIsFetching } from 'src/selectors/requests' |
|
|
|
|
|
|
|
import { setTitle } from 'src/utils' |
|
|
|
import { AppState, AppThunkDispatch, EntityType, App } from 'src/types' |
|
|
|
import { AppState, AppThunkDispatch, EntityType, App, RequestKey } from 'src/types' |
|
|
|
|
|
|
|
import PageHeader from 'src/components/page-header' |
|
|
|
import Loading from 'src/components/pages/loading' |
|
|
|
import { ClassDictionary } from 'src/types' |
|
|
|
|
|
|
|
interface Params { |
|
|
|
id: string |
|
|
@ -22,6 +25,7 @@ const ViewApp: FC = () => { |
|
|
|
const { id } = useParams<Params>() |
|
|
|
const app = useSelector<AppState, App | undefined>(state => getEntity<App>(state, EntityType.App, id)) |
|
|
|
const selfId = useSelector<AppState, string | undefined>(getAuthenticatedUserId) |
|
|
|
const fetching = useSelector<AppState, boolean>(state => getIsFetching(state, RequestKey.InstallApp) || getIsFetching(state, RequestKey.UninstallApp)) |
|
|
|
const dispatch = useDispatch<AppThunkDispatch>() |
|
|
|
const history = useHistory() |
|
|
|
|
|
|
@ -41,48 +45,79 @@ const ViewApp: FC = () => { |
|
|
|
|
|
|
|
const isCreator = app.user.id === selfId |
|
|
|
|
|
|
|
const renderButton = () => { |
|
|
|
if (app.installed) { |
|
|
|
const handleClick = async () => { |
|
|
|
await dispatch(uninstallApp(id)) |
|
|
|
await dispatch(fetchApp(id)) |
|
|
|
} |
|
|
|
|
|
|
|
const classes: ClassDictionary = { |
|
|
|
'button': true, |
|
|
|
'is-danger': true, |
|
|
|
'is-loading': fetching, |
|
|
|
} |
|
|
|
|
|
|
|
return <button className={classNames(classes)} onClick={() => handleClick()}>Uninstall</button> |
|
|
|
} else { |
|
|
|
const handleClick = async () => { |
|
|
|
await dispatch(installApp(id)) |
|
|
|
await dispatch(fetchApp(id)) |
|
|
|
} |
|
|
|
|
|
|
|
const classes: ClassDictionary = { |
|
|
|
'button': true, |
|
|
|
'is-success': true, |
|
|
|
'is-loading': fetching, |
|
|
|
} |
|
|
|
|
|
|
|
return <button className={classNames(classes)} onClick={() => handleClick()}>Install</button> |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return ( |
|
|
|
<div> |
|
|
|
<PageHeader title={app.name} /> |
|
|
|
|
|
|
|
<div className="main-content"> |
|
|
|
<nav className="level"> |
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Users</p> |
|
|
|
<p className="title">0</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Rating</p> |
|
|
|
<p className="title">{app.rating || '0'}</p> |
|
|
|
<div className="centered-content"> |
|
|
|
<nav className="level"> |
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Users</p> |
|
|
|
<p className="title">{app.users}</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
{app.companyName && |
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Company</p> |
|
|
|
<p className="title">{app.companyName}</p> |
|
|
|
<p className="heading">Rating</p> |
|
|
|
<p className="title">{app.rating}</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
} |
|
|
|
|
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Updated</p> |
|
|
|
<p className="title">{moment(app.updated).format('MMMM Do, YYYY')}</p> |
|
|
|
{app.companyName && |
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Company</p> |
|
|
|
<p className="title">{app.companyName}</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
} |
|
|
|
|
|
|
|
<div className="level-item has-text-centered"> |
|
|
|
<div> |
|
|
|
<p className="heading">Updated</p> |
|
|
|
<p className="title">{moment(app.updated).format('MMMM Do, YYYY')}</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</nav> |
|
|
|
</nav> |
|
|
|
|
|
|
|
<div className="centered-content"> |
|
|
|
<p>{app.about}</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<br /> |
|
|
|
|
|
|
|
{renderButton()} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
) |
|
|
|