Commit 600e5846 authored by Paul Kaplan's avatar Paul Kaplan

Move activity loading to studio-activity-actions, include pagination

parent dbec1c7a
// TODO move this to studio-activity-actions, include pagination
const activityFetcher = studioId =>
fetch(`${process.env.API_HOST}/studios/${studioId}/activity`)
.then(response => response.json())
.then(data => ({items: data, moreToLoad: false})); // No pagination on the activity feed
export {
activityFetcher
};
import keyMirror from 'keymirror';
import api from '../../../lib/api';
import {activity} from './redux-modules';
import {selectStudioId} from '../../../redux/studio';
const Errors = keyMirror({
NETWORK: null,
SERVER: null,
PERMISSION: null
});
const normalizeError = (err, body, res) => {
if (err) return Errors.NETWORK;
if (res.statusCode === 401 || res.statusCode === 403) return Errors.PERMISSION;
if (res.statusCode !== 200) return Errors.SERVER;
return null;
};
const loadActivity = () => ((dispatch, getState) => {
const state = getState();
const studioId = selectStudioId(state);
const items = activity.selector(state).items;
const params = {limit: 20};
if (items.length > 0) {
// dateLimit is the newest notification you want to get back, which is
// the date of the oldest one we've already loaded
params.dateLimit = items[items.length - 1].datetime_created;
}
api({
uri: `/studios/${studioId}/activity/`,
params
}, (err, body, res) => {
const error = normalizeError(err, body, res);
if (error) return dispatch(activity.actions.error(error));
const ids = items.map(item => item.id);
// Deduplication is needed because pagination based on date can contain duplicates
const deduped = body.filter(item => ids.indexOf(item.id) === -1);
dispatch(activity.actions.append(deduped, body.length === params.limit));
});
});
export {loadActivity};
......@@ -2,20 +2,15 @@ import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {useParams} from 'react-router';
import {activity} from './lib/redux-modules';
import {activityFetcher} from './lib/fetchers';
import {loadActivity} from './lib/studio-activity-actions';
import Debug from './debug.jsx';
const StudioActivity = ({items, loading, error, onInitialLoad}) => {
const {studioId} = useParams();
// Fetch the data if none has been loaded yet. This would run only once,
// since studioId doesnt change, but the component is potentially mounted
// multiple times because of tab routing, so need to check for empty items.
const StudioActivity = ({items, loading, error, moreToLoad, onLoadMore}) => {
useEffect(() => {
if (studioId && items.length === 0) onInitialLoad(studioId);
}, [studioId]); // items.length intentionally left out
if (items.length === 0) onLoadMore();
}, []);
return (
<div>
......@@ -33,6 +28,15 @@ const StudioActivity = ({items, loading, error, onInitialLoad}) => {
key={index}
/>)
)}
<div>
{loading ? <small>Loading...</small> : (
moreToLoad ?
<button onClick={onLoadMore}>
Load more
</button> :
<small>No more to load</small>
)}
</div>
</div>
</div>
);
......@@ -42,13 +46,13 @@ StudioActivity.propTypes = {
items: PropTypes.array, // eslint-disable-line react/forbid-prop-types
loading: PropTypes.bool,
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types
onInitialLoad: PropTypes.func
moreToLoad: PropTypes.bool,
onLoadMore: PropTypes.func
};
export default connect(
state => activity.selector(state),
dispatch => ({
onInitialLoad: studioId => dispatch(
activity.actions.loadMore(activityFetcher.bind(null, studioId, 0)))
})
{
onLoadMore: loadActivity
}
)(StudioActivity);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment