diff --git a/src/api.js b/src/api.js
index 8b7784d..2ccc9a1 100644
--- a/src/api.js
+++ b/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'})
}
}
diff --git a/src/pages/TrackPage/TrackComments.tsx b/src/pages/TrackPage/TrackComments.tsx
index 4692af5..de2dbc9 100644
--- a/src/pages/TrackPage/TrackComments.tsx
+++ b/src/pages/TrackPage/TrackComments.tsx
@@ -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 (
+
setBody(e.target.value)} />
+
+
+ )
+}
+
+export default function TrackComments({comments, onSubmit, onDelete, login, hideLoader}) {
return (
@@ -24,16 +40,19 @@ export default function TrackComments({comments, login, hideLoader}) {
{comment.body}
+ {login?.username === comment.author.username && (
+
+ {
+ onDelete(comment.id)
+ e.preventDefault()
+ }}>Delete
+
+ )}
))}
- {login && comments != null && (
-
-
-
- )}
+ {login && comments != null && }
)
diff --git a/src/pages/TrackPage/index.tsx b/src/pages/TrackPage/index.tsx
index 15ba5fd..1cdf944 100644
--- a/src/pages/TrackPage/index.tsx
+++ b/src/pages/TrackPage/index.tsx
@@ -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(
-
+
{/* {JSON.stringify(data, null, 2)}
*/}
diff --git a/src/pages/TracksPage.tsx b/src/pages/TracksPage.tsx
index 97e8265..e24c986 100644
--- a/src/pages/TracksPage.tsx
+++ b/src/pages/TracksPage.tsx
@@ -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]