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