Cleanup API calls
This commit is contained in:
parent
2e7cdc24f3
commit
281a7ac90c
27
src/api.js
27
src/api.js
|
@ -1,3 +1,5 @@
|
|||
import {stringifyParams} from 'query'
|
||||
|
||||
class API {
|
||||
setAuthorizationHeader(authorization) {
|
||||
this.authorization = authorization
|
||||
|
@ -12,7 +14,30 @@ class API {
|
|||
},
|
||||
})
|
||||
|
||||
return await response.json()
|
||||
if (response.status === 200) {
|
||||
return await response.json()
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async post(url, {body: body_, ...options}) {
|
||||
const body = typeof body_ !== 'string' ? JSON.stringify(body_) : body_
|
||||
return await this.fetch(url, {...options, body, method: 'post',
|
||||
headers: {
|
||||
...(options.headers || {}),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async get(url, {query, ...options} = {}) {
|
||||
const queryString = query ? stringifyParams(query) : null
|
||||
return await this.fetch(url + (queryString ? '?' + queryString : ''), {method: 'get', ...options})
|
||||
}
|
||||
|
||||
async delete(url, options = {}) {
|
||||
return await this.get(url, {...options, method: 'delete'})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,23 @@ import {Segment, Form, Button, Loader, Header, Comment} from 'semantic-ui-react'
|
|||
|
||||
import {FormattedDate} from 'components'
|
||||
|
||||
export default function TrackComments({comments, login, hideLoader}) {
|
||||
function CommentForm({onSubmit}) {
|
||||
const [body, setBody] = React.useState('')
|
||||
|
||||
const onSubmitComment = React.useCallback(() => {
|
||||
onSubmit({body})
|
||||
setBody('')
|
||||
}, [onSubmit, body])
|
||||
|
||||
return (
|
||||
<Form reply onSubmit={onSubmitComment}>
|
||||
<Form.TextArea rows={4} value={body} onChange={(e) => setBody(e.target.value)} />
|
||||
<Button content="Post comment" labelPosition="left" icon="edit" primary />
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export default function TrackComments({comments, onSubmit, onDelete, login, hideLoader}) {
|
||||
return (
|
||||
<Segment basic>
|
||||
<Comment.Group>
|
||||
|
@ -24,16 +40,19 @@ export default function TrackComments({comments, login, hideLoader}) {
|
|||
</div>
|
||||
</Comment.Metadata>
|
||||
<Comment.Text>{comment.body}</Comment.Text>
|
||||
{login?.username === comment.author.username && (
|
||||
<Comment.Actions>
|
||||
<Comment.Action onClick={(e) => {
|
||||
onDelete(comment.id)
|
||||
e.preventDefault()
|
||||
}}>Delete</Comment.Action>
|
||||
</Comment.Actions>
|
||||
)}
|
||||
</Comment.Content>
|
||||
</Comment>
|
||||
))}
|
||||
|
||||
{login && comments != null && (
|
||||
<Form reply>
|
||||
<Form.TextArea rows={4} />
|
||||
<Button content="Post comment" labelPosition="left" icon="edit" primary />
|
||||
</Form>
|
||||
)}
|
||||
{login && comments != null && <CommentForm onSubmit={onSubmit} />}
|
||||
</Comment.Group>
|
||||
</Segment>
|
||||
)
|
||||
|
|
|
@ -2,8 +2,8 @@ import React from 'react'
|
|||
import {connect} from 'react-redux'
|
||||
import {Segment, Dimmer, Grid, Loader, Header} from 'semantic-ui-react'
|
||||
import {useParams} from 'react-router-dom'
|
||||
import {concat, combineLatest, of, from} from 'rxjs'
|
||||
import {pluck, distinctUntilChanged, map, switchMap, startWith} from 'rxjs/operators'
|
||||
import {concat, combineLatest, of, from, Subject} from 'rxjs'
|
||||
import {pluck, distinctUntilChanged, map, switchMap, startWith, sample} from 'rxjs/operators'
|
||||
import {useObservable} from 'rxjs-hooks'
|
||||
|
||||
import api from 'api'
|
||||
|
@ -15,9 +15,17 @@ import TrackComments from './TrackComments'
|
|||
import TrackDetails from './TrackDetails'
|
||||
import TrackMap from './TrackMap'
|
||||
|
||||
function useTriggerSubject() {
|
||||
const subject$ = React.useMemo(() => new Subject(), [])
|
||||
const trigger = React.useCallback(() => subject$.next(null), [])
|
||||
return [trigger, subject$]
|
||||
}
|
||||
|
||||
const TrackPage = connect((state) => ({login: state.login}))(function TrackPage({login}) {
|
||||
const {slug} = useParams()
|
||||
|
||||
const [reloadComments, reloadComments$] = useTriggerSubject()
|
||||
|
||||
const data: {
|
||||
track: null | Track
|
||||
trackData: null | TrackData
|
||||
|
@ -26,21 +34,22 @@ const TrackPage = connect((state) => ({login: state.login}))(function TrackPage(
|
|||
(_$, args$) => {
|
||||
const slug$ = args$.pipe(pluck(0), distinctUntilChanged())
|
||||
const track$ = slug$.pipe(
|
||||
map((slug) => '/tracks/' + slug),
|
||||
switchMap((url) => concat(of(null), from(api.fetch(url)))),
|
||||
map((slug) => `/tracks/${slug}`),
|
||||
switchMap((url) => concat(of(null), from(api.get(url)))),
|
||||
pluck('track')
|
||||
)
|
||||
|
||||
const trackData$ = slug$.pipe(
|
||||
map((slug) => '/tracks/' + slug + '/data'),
|
||||
switchMap((url) => concat(of(null), from(api.fetch(url)))),
|
||||
map((slug) => `/tracks/${slug}/data`),
|
||||
switchMap((url) => concat(of(null), from(api.get(url)))),
|
||||
pluck('trackData'),
|
||||
startWith(null) // show track infos before track data is loaded
|
||||
)
|
||||
|
||||
const comments$ = slug$.pipe(
|
||||
map((slug) => '/tracks/' + slug + '/comments'),
|
||||
switchMap((url) => concat(of(null), from(api.fetch(url)))),
|
||||
const comments$ = concat(of(null), reloadComments$).pipe(
|
||||
switchMap(() => slug$),
|
||||
map((slug) => `/tracks/${slug}/comments`),
|
||||
switchMap(url => api.get(url)),
|
||||
pluck('comments'),
|
||||
startWith(null) // show track infos before comments are loaded
|
||||
)
|
||||
|
@ -53,6 +62,18 @@ const TrackPage = connect((state) => ({login: state.login}))(function TrackPage(
|
|||
[slug]
|
||||
)
|
||||
|
||||
const onSubmitComment = React.useCallback(async ({body}) => {
|
||||
await api.post(`/tracks/${slug}/comments`, {
|
||||
body: {comment: {body}}
|
||||
})
|
||||
reloadComments()
|
||||
}, [])
|
||||
|
||||
const onDeleteComment = React.useCallback(async (id) => {
|
||||
await api.delete(`/tracks/${slug}/comments/${id}`)
|
||||
reloadComments()
|
||||
}, [])
|
||||
|
||||
const isAuthor = login?.username === data?.track?.author?.username
|
||||
|
||||
const {track, trackData, comments} = data || {}
|
||||
|
@ -85,7 +106,7 @@ const TrackPage = connect((state) => ({login: state.login}))(function TrackPage(
|
|||
</Grid.Row>
|
||||
</Grid>
|
||||
|
||||
<TrackComments {...{hideLoader: loading, comments, login}} />
|
||||
<TrackComments {...{hideLoader: loading, comments, login}} onSubmit={onSubmitComment} onDelete={onDeleteComment} />
|
||||
|
||||
{/* <pre>{JSON.stringify(data, null, 2)}</pre> */}
|
||||
</Page>
|
||||
|
|
|
@ -4,13 +4,13 @@ import {Item, Tab, Loader, Pagination, Icon} from 'semantic-ui-react'
|
|||
import {useObservable} from 'rxjs-hooks'
|
||||
import {Link, useHistory, useRouteMatch} from 'react-router-dom'
|
||||
import {of, from, concat} from 'rxjs'
|
||||
import {map, switchMap, distinctUntilChanged, debounceTime} from 'rxjs/operators'
|
||||
import {map, switchMap, distinctUntilChanged} from 'rxjs/operators'
|
||||
import _ from 'lodash'
|
||||
|
||||
import type {Track} from '../types'
|
||||
import {Page} from '../components'
|
||||
import api from '../api'
|
||||
import {useQueryParam, stringifyParams} from '../query'
|
||||
import {useQueryParam} from '../query'
|
||||
|
||||
function TracksPageTabs() {
|
||||
const history = useHistory()
|
||||
|
@ -49,11 +49,11 @@ function TrackList({privateFeed}: {privateFeed: boolean}) {
|
|||
inputs$.pipe(
|
||||
map(([page, privateFeed]) => {
|
||||
const url = '/tracks' + (privateFeed ? '/feed' : '')
|
||||
const params = {limit: pageSize, offset: pageSize * (page - 1)}
|
||||
return {url, params}
|
||||
const query = {limit: pageSize, offset: pageSize * (page - 1)}
|
||||
return {url, query}
|
||||
}),
|
||||
distinctUntilChanged(_.isEqual),
|
||||
switchMap((request) => concat(of(null), from(api.fetch(request.url + '?' + stringifyParams(request.params)))))
|
||||
switchMap((request) => concat(of(null), from(api.get(request.url, {query: request.query})))),
|
||||
),
|
||||
null,
|
||||
[page, privateFeed]
|
||||
|
|
Loading…
Reference in a new issue