[ABANDONED] React/Redux front end for the Flexor social network.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
4.5 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. import React, { FC, useEffect } from 'react'
  2. import { useSelector, useDispatch } from 'react-redux'
  3. import { Link, useParams, useHistory } from 'react-router-dom'
  4. import { faPlusSquare, faMinusSquare } from '@fortawesome/free-solid-svg-icons'
  5. import moment from 'moment'
  6. import { handleApiError } from '../../api/errors'
  7. import { fetchApp, installApp, uninstallApp } from '../../actions/apps'
  8. import { fetchInstallations } from '../../actions/composer'
  9. import { getAuthenticatedUserId } from '../../selectors/authentication'
  10. import { getInstallations } from '../../selectors/composer'
  11. import { getEntity } from '../../selectors/entities'
  12. import { getIsFetching } from '../../selectors/requests'
  13. import { useTheme } from '../../hooks'
  14. import { setTitle } from '../../utils'
  15. import { AppState, AppThunkDispatch, EntityType, App, RequestKey, LevelItem } from '../../types'
  16. import Title from '../../components/title'
  17. import Section from '../../components/section'
  18. import HorizontalRule from '../../components/horizontal-rule'
  19. import Button from '../../components/controls/button'
  20. import Level from '../../components/level'
  21. import Loading from '../../components/pages/loading'
  22. interface Params {
  23. id: string
  24. }
  25. const ViewApp: FC = () => {
  26. const { id } = useParams<Params>()
  27. const theme = useTheme()
  28. const app = useSelector<AppState, App | undefined>(state => getEntity<App>(state, EntityType.App, id))
  29. const installations = useSelector(getInstallations)
  30. const selfId = useSelector(getAuthenticatedUserId)
  31. const fetching = useSelector<AppState, boolean>(state => getIsFetching(state, RequestKey.InstallApp) || getIsFetching(state, RequestKey.UninstallApp))
  32. const dispatch = useDispatch<AppThunkDispatch>()
  33. const history = useHistory()
  34. useEffect(() => {
  35. try {
  36. dispatch(fetchApp(id))
  37. dispatch(fetchInstallations())
  38. } catch (err) {
  39. handleApiError(err, dispatch, history)
  40. }
  41. }, [])
  42. useEffect(() => {
  43. if (app) setTitle(app.name)
  44. }, [app])
  45. if (!app) return <Loading />
  46. const isCreator = app.user.id === selfId
  47. const installed = !!installations.find(i => i.app.id === app.id)
  48. const renderButton = () => {
  49. if (installed) {
  50. const handleClick = async () => {
  51. await dispatch(uninstallApp(id))
  52. await dispatch(fetchApp(id))
  53. }
  54. return (
  55. <Button text="Uninstall" icon={faMinusSquare} loading={fetching} onClick={() => handleClick()} color="#fff" backgroundColor={theme.red} />
  56. )
  57. } else {
  58. const handleClick = async () => {
  59. await dispatch(installApp(id))
  60. await dispatch(fetchApp(id))
  61. }
  62. return (
  63. <Button text="Install" icon={faPlusSquare} loading={fetching} onClick={() => handleClick()} color={theme.primaryAlternate} backgroundColor={theme.primary} />
  64. )
  65. }
  66. }
  67. const items: LevelItem[] = []
  68. items.push({
  69. label: 'Users',
  70. content: app.users,
  71. })
  72. items.push({
  73. label: 'Rating',
  74. content: app.rating.toString(),
  75. })
  76. if (app.companyName) {
  77. items.push({
  78. label: 'Company',
  79. content: app.companyName,
  80. })
  81. }
  82. items.push({
  83. label: 'Updated',
  84. content: moment(app.updated).format('MMMM Do, YYYY'),
  85. })
  86. return (
  87. <div>
  88. <Section>
  89. {app.coverImageUrl &&
  90. <div className="cover-image">
  91. <img src={app.coverImageUrl} />
  92. </div>
  93. }
  94. <div className="header">
  95. {app.imageUrl &&
  96. <div className="image">
  97. <img src={app.imageUrl} />
  98. </div>
  99. }
  100. <div>
  101. <Title>{app.name}</Title>
  102. <p style={{ color: theme.text }}>{app.about}</p>
  103. </div>
  104. </div>
  105. <Level items={items} />
  106. <div style={{ textAlign: 'center', padding: '1rem' }}>
  107. {renderButton()}
  108. </div>
  109. <HorizontalRule />
  110. <div className="buttons">
  111. {isCreator && <Link style={{ color: theme.secondary }} to={`/a/${id}/edit`}>View/Edit App</Link>}
  112. </div>
  113. </Section>
  114. </div>
  115. )
  116. }
  117. export default ViewApp