[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.

156 lines
5.5 KiB

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
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
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 { faCheckCircle, faIdCard } from '@fortawesome/free-solid-svg-icons'
  5. import { handleApiError } from '../../api/errors'
  6. import { initForm, initField } from '../../actions/forms'
  7. import { fetchGroup, updateGroup } from '../../actions/groups'
  8. import { getEntity } from '../../selectors/entities'
  9. import { getForm } from '../../selectors/forms'
  10. import { useDeepCompareEffect, useTheme } from '../../hooks'
  11. import { setTitle, valueFromForm } from '../../utils'
  12. import {
  13. AppState,
  14. AppThunkDispatch,
  15. Group,
  16. GroupMembershipType,
  17. Tab,
  18. EntityType,
  19. } from '../../types'
  20. import Title from '../../components/title'
  21. import Subtitle from '../../components/subtitle'
  22. import Section from '../../components/section'
  23. import HorizontalRule from '../../components/horizontal-rule'
  24. import PrimaryButton from '../../components/controls/primary-button'
  25. import MemberList from '../../components/member-list'
  26. import GroupInvitations from '../../components/group-invitations'
  27. import GroupLogs from '../../components/group-logs'
  28. import Loading from '../../components/pages/loading'
  29. import TextareaField from '../../components/controls/textarea-field'
  30. import ImageField from '../../components/controls/image-field'
  31. import CoverImageField from '../../components/controls/cover-image-field'
  32. import IconImageField from '../../components/controls/icon-image-field'
  33. import StaticField from '../../components/controls/static-field'
  34. interface Params {
  35. id: string
  36. tab: string
  37. }
  38. const tabs: Tab[] = [
  39. { id: '', label: 'General' },
  40. { id: 'members', label: 'Members' },
  41. { id: 'logs', label: 'Logs' },
  42. ]
  43. const GroupAdmin: FC = () => {
  44. const theme = useTheme()
  45. const { id, tab = '' } = useParams<Params>()
  46. const history = useHistory()
  47. const group = useSelector<AppState, Group | undefined>(state => getEntity<Group>(state, EntityType.Group, id))
  48. const form = useSelector(getForm)
  49. const dispatch = useDispatch<AppThunkDispatch>()
  50. useEffect(() => {
  51. try {
  52. dispatch(fetchGroup(id))
  53. } catch (err) {
  54. handleApiError(err, dispatch, history)
  55. }
  56. }, [])
  57. useDeepCompareEffect(() => {
  58. if (group && group.membership) {
  59. if (group.membership !== GroupMembershipType.Admin) {
  60. history.push(`/c/${group.id}`)
  61. return
  62. }
  63. dispatch(initForm())
  64. dispatch(initField('about', group.about))
  65. dispatch(initField('expiration', '0'))
  66. dispatch(initField('limit', '0'))
  67. dispatch(initField('image', group.imageUrl))
  68. dispatch(initField('coverImage', group.coverImageUrl))
  69. dispatch(initField('iconImage', group.iconImageUrl))
  70. setTitle(`${group.name} Administration`)
  71. }
  72. }, [group])
  73. const handleUpdateGroup = async () => {
  74. try {
  75. await dispatch(updateGroup(id, {
  76. about: valueFromForm<string>(form, 'about'),
  77. imageUrl: valueFromForm<string>(form, 'image'),
  78. coverImageUrl: valueFromForm<string>(form, 'coverImage'),
  79. iconImageUrl: valueFromForm<string>(form, 'iconImage'),
  80. }))
  81. await dispatch(fetchGroup(id))
  82. } catch (err) {
  83. handleApiError(err, dispatch, history)
  84. }
  85. }
  86. if (!group) return <Loading />
  87. return (
  88. <div>
  89. <Section>
  90. <Title>{group.name}</Title>
  91. <Subtitle>Administration</Subtitle>
  92. <HorizontalRule />
  93. <div className="tabs" style={{ backgroundColor: theme.backgroundSecondary }}>
  94. {tabs.map(t => (
  95. <div key={t.id} className={tab === t.id ? 'active': ''} style={{ borderColor: theme.primary }}>
  96. <Link style={{ color: theme.secondary}} to={`/c/${group.id}/admin/${t.id}`}>
  97. {t.label}
  98. </Link>
  99. </div>
  100. ))}
  101. </div>
  102. <div>
  103. {tab === '' &&
  104. <div>
  105. <StaticField label="ID" icon={faIdCard} value={group.id} />
  106. <StaticField label="Name" value={group.name} />
  107. <TextareaField name="about" label="About" placeholder="About this Community" />
  108. <ImageField name="image" />
  109. <CoverImageField name="coverImage" />
  110. <IconImageField name="iconImage" />
  111. <br />
  112. <PrimaryButton text="Save" icon={faCheckCircle} onClick={e => handleUpdateGroup()} />
  113. </div>
  114. }
  115. {tab === 'members' &&
  116. <div>
  117. <GroupInvitations group={id} />
  118. <HorizontalRule />
  119. <Subtitle>Members</Subtitle>
  120. <MemberList group={id} />
  121. </div>
  122. }
  123. {tab === 'logs' &&
  124. <div>
  125. <GroupLogs group={id} />
  126. </div>
  127. }
  128. </div>
  129. </Section>
  130. </div>
  131. )
  132. }
  133. export default GroupAdmin