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

166 lines
4.9 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
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
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
4 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
  1. import { apiFetch } from '../api'
  2. import { setEntities } from '../actions/entities'
  3. import { listSet, listAppend } from '../actions/lists'
  4. import { startRequest, finishRequest } from '../actions/requests'
  5. import { objectToQuerystring } from '../utils'
  6. import { normalize } from '../utils/normalization'
  7. import { AppThunkAction, Entity, RequestKey, EntityType, User, Post, Attachment, EntityListKey } from '../types'
  8. interface CreatePostResponse {
  9. id: string
  10. }
  11. interface CreatePostOptions {
  12. installation: string
  13. visible: boolean
  14. text?: string
  15. cover?: string
  16. attachments: Attachment[]
  17. data?: object
  18. parent?: string
  19. }
  20. export const createPost = (options: CreatePostOptions): AppThunkAction<string> => {
  21. return async dispatch => {
  22. const { installation, visible, text, cover, attachments, data, parent } = options
  23. dispatch(startRequest(RequestKey.CreatePost))
  24. try {
  25. const post = await apiFetch<CreatePostResponse>({
  26. path: `/v1/post`,
  27. method: 'post',
  28. body: {
  29. installation,
  30. visible,
  31. text,
  32. cover,
  33. attachments,
  34. data,
  35. parent,
  36. },
  37. })
  38. dispatch(finishRequest(RequestKey.CreatePost, true))
  39. return post.id
  40. } catch (err) {
  41. dispatch(finishRequest(RequestKey.CreatePost, false))
  42. throw err
  43. }
  44. }
  45. }
  46. interface FetchPostResponse {
  47. post: Post,
  48. parents: Post[],
  49. children: Post[],
  50. users: User[],
  51. }
  52. export const fetchPost = (id: string): AppThunkAction => {
  53. return async dispatch => {
  54. dispatch(startRequest(RequestKey.FetchPost))
  55. try {
  56. const response = await apiFetch<FetchPostResponse>({
  57. path: `/v1/post/${id}`
  58. })
  59. const parents = normalize(response.parents.map(p => ({
  60. ...p,
  61. user: response.users.find(u => u.id === p.userId),
  62. userId: undefined,
  63. })), EntityType.Post)
  64. dispatch(setEntities(parents.entities))
  65. dispatch(listSet(`post:${id}:parents`, parents.keys))
  66. const children = normalize(response.children.map(p => ({
  67. ...p,
  68. user: response.users.find(u => u.id === p.userId),
  69. userId: undefined,
  70. })), EntityType.Post)
  71. dispatch(setEntities(children.entities))
  72. dispatch(listSet(`post:${id}:children`, children.keys))
  73. const post: Entity = {
  74. ...response.post,
  75. user: response.users.find(u => u.id === response.post.userId),
  76. userId: undefined,
  77. }
  78. const posts = normalize([post], EntityType.Post)
  79. dispatch(setEntities(posts.entities))
  80. dispatch(finishRequest(RequestKey.FetchPost, true))
  81. } catch (err) {
  82. dispatch(finishRequest(RequestKey.FetchPost, false))
  83. throw err
  84. }
  85. }
  86. }
  87. interface TimelineResponse {
  88. posts: Post[]
  89. continuation?: string
  90. }
  91. export const fetchTimeline = (continuation?: string): AppThunkAction => async dispatch => {
  92. dispatch(startRequest(RequestKey.FetchTimeline))
  93. try {
  94. const response = await apiFetch<TimelineResponse>({
  95. path: `/v1/timeline?${objectToQuerystring({ continuation })}`,
  96. })
  97. const posts = normalize(response.posts, EntityType.Post)
  98. dispatch(setEntities(posts.entities))
  99. if (continuation) {
  100. dispatch(listAppend(EntityListKey.Timeline, posts.keys, response.continuation))
  101. } else {
  102. dispatch(listSet(EntityListKey.Timeline, posts.keys, response.continuation))
  103. }
  104. dispatch(finishRequest(RequestKey.FetchTimeline, true))
  105. } catch (err) {
  106. dispatch(finishRequest(RequestKey.FetchTimeline, false))
  107. throw err
  108. }
  109. }
  110. interface UserPostsResponse {
  111. user: User
  112. posts: Post[]
  113. continuation?: string
  114. }
  115. export const fetchUserPosts = (id: string, continuation?: string): AppThunkAction => async dispatch => {
  116. dispatch(startRequest(RequestKey.FetchUserPosts))
  117. try {
  118. const response = await apiFetch<UserPostsResponse>({
  119. path: `/v1/user/${id}/posts`,
  120. })
  121. const posts = normalize(response.posts.map(p => ({
  122. ...p,
  123. user: response.user,
  124. })), EntityType.Post)
  125. dispatch(setEntities(posts.entities))
  126. if (continuation) {
  127. dispatch(listAppend(`user:${id}:posts`, posts.keys, response.continuation))
  128. } else {
  129. dispatch(listSet(`user:${id}:posts`, posts.keys, response.continuation))
  130. }
  131. dispatch(finishRequest(RequestKey.FetchUserPosts, true))
  132. } catch (err) {
  133. dispatch(finishRequest(RequestKey.FetchUserPosts, false))
  134. throw err
  135. }
  136. }