add file reactions code from odysee

This commit is contained in:
Sean Yesmunt 2020-10-02 15:18:53 -04:00
parent dc42df3bf2
commit eb84a366d2
10 changed files with 294 additions and 1 deletions

View file

@ -25,6 +25,7 @@ SHOW_ADS=true
YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a YRBL_HAPPY_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-happy/7aa50a7e5adaf48691935d55e45d697547392929/839d9a
YRBL_SAD_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd YRBL_SAD_IMG_URL=https://cdn.lbryplayer.xyz/api/v3/streams/free/yrbl-sad/c2d9649633d974e5ffb503925e1f17d951f1bd0f/f262dd
ENABLE_COMMENT_REACTIONS=false ENABLE_COMMENT_REACTIONS=false
ENABLE_FILE_REACTIONS=false
# OG # OG
OG_TITLE_SUFFIX=| lbry.tv OG_TITLE_SUFFIX=| lbry.tv

View file

@ -30,6 +30,7 @@ const config = {
AUTO_FOLLOW_CHANNELS: process.env.AUTO_FOLLOW_CHANNELS, AUTO_FOLLOW_CHANNELS: process.env.AUTO_FOLLOW_CHANNELS,
UNSYNCED_SETTINGS: process.env.UNSYNCED_SETTINGS, UNSYNCED_SETTINGS: process.env.UNSYNCED_SETTINGS,
ENABLE_COMMENT_REACTIONS: process.env.ENABLE_COMMENT_REACTIONS === 'true', ENABLE_COMMENT_REACTIONS: process.env.ENABLE_COMMENT_REACTIONS === 'true',
ENABLE_FILE_REACTIONS: process.env.ENABLE_FILE_REACTIONS === 'true',
SIMPLE_SITE: process.env.SIMPLE_SITE === 'true', SIMPLE_SITE: process.env.SIMPLE_SITE === 'true',
SHOW_ADS: process.env.SHOW_ADS === 'true', SHOW_ADS: process.env.SHOW_ADS === 'true',
PINNED_URI_1: process.env.PINNED_URI_1, PINNED_URI_1: process.env.PINNED_URI_1,

View file

@ -1,5 +1,5 @@
// @flow // @flow
import { SIMPLE_SITE, SITE_NAME } from 'config'; import { SIMPLE_SITE, SITE_NAME, ENABLE_FILE_REACTIONS } from 'config';
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
@ -11,6 +11,7 @@ import * as RENDER_MODES from 'constants/file_render_modes';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import ClaimSupportButton from 'component/claimSupportButton'; import ClaimSupportButton from 'component/claimSupportButton';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import FileReactions from 'component/fileReactions';
type Props = { type Props = {
uri: string, uri: string,
@ -79,6 +80,7 @@ function FileActions(props: Props) {
const lhsSection = ( const lhsSection = (
<> <>
{ENABLE_FILE_REACTIONS && <FileReactions uri={uri} />}
<ClaimSupportButton uri={uri} fileAction /> <ClaimSupportButton uri={uri} fileAction />
<Button <Button
button="alt" button="alt"

View file

@ -0,0 +1,26 @@
import { connect } from 'react-redux';
import {
makeSelectReactionsForUri,
makeSelectMyReactionForUri,
makeSelectLikeCountForUri,
makeSelectDislikeCountForUri,
} from 'redux/selectors/reactions';
import { doFetchReactions, doReactionLike, doReactionDislike } from 'redux/actions/reactions';
import { selectThemePath } from 'redux/selectors/settings';
import FileViewCount from './view';
import { makeSelectClaimForUri } from 'lbry-redux';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
reactions: makeSelectReactionsForUri(props.uri)(state),
myReaction: makeSelectMyReactionForUri(props.uri)(state),
likeCount: makeSelectLikeCountForUri(props.uri)(state),
dislikeCount: makeSelectDislikeCountForUri(props.uri)(state),
theme: selectThemePath(state),
});
export default connect(select, {
doFetchReactions,
doReactionLike,
doReactionDislike,
})(FileViewCount);

View file

@ -0,0 +1,52 @@
// @flow
import * as ICONS from 'constants/icons';
import React from 'react';
import classnames from 'classnames';
import Button from 'component/button';
type Props = {
claim: StreamClaim,
doFetchReactions: string => void,
doReactionLike: string => void,
doReactionDislike: string => void,
uri: string,
likeCount: number,
dislikeCount: number,
myReaction: ?string,
};
function FileReactions(props: Props) {
const { claim, uri, doFetchReactions, doReactionLike, doReactionDislike, likeCount, dislikeCount } = props;
const claimId = claim && claim.claim_id;
React.useEffect(() => {
if (claimId) {
doFetchReactions(claimId);
}
}, [claimId, doFetchReactions]);
return (
<>
<Button
title={__('I like this')}
requiresAuth
className={classnames('button--file-action')}
label={String(likeCount)}
iconSize={18}
icon={ICONS.UPVOTE}
onClick={() => doReactionLike(uri)}
/>
<Button
requiresAuth
title={__('I dislike this')}
className={classnames('button--file-action')}
label={String(dislikeCount)}
iconSize={18}
icon={ICONS.DOWNVOTE}
onClick={() => doReactionDislike(uri)}
/>
</>
);
}
export default FileReactions;

View file

@ -278,3 +278,11 @@ export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL';
// Notifications // Notifications
export const WS_CONNECT = 'WS_CONNECT'; export const WS_CONNECT = 'WS_CONNECT';
export const WS_DISCONNECT = 'WS_DISCONNECT'; export const WS_DISCONNECT = 'WS_DISCONNECT';
export const REACTIONS_LIST_STARTED = 'REACTIONS_LIST_STARTED';
export const REACTIONS_LIST_FAILED = 'REACTIONS_LIST_FAILED';
export const REACTIONS_LIST_COMPLETED = 'REACTIONS_LIST_COMPLETED';
export const REACTIONS_NEW_STARTED = 'REACTIONS_NEW_STARTED';
export const REACTIONS_NEW_FAILED = 'REACTIONS_NEW_FAILED';
export const REACTIONS_LIKE_COMPLETED = 'REACTIONS_LIKE_COMPLETED';
export const REACTIONS_DISLIKE_COMPLETED = 'REACTIONS_DISLIKE_COMPLETED';

View file

@ -20,6 +20,7 @@ import userReducer from 'redux/reducers/user';
import commentsReducer from 'redux/reducers/comments'; import commentsReducer from 'redux/reducers/comments';
import blockedReducer from 'redux/reducers/blocked'; import blockedReducer from 'redux/reducers/blocked';
import searchReducer from 'redux/reducers/search'; import searchReducer from 'redux/reducers/search';
import reactionsReducer from 'redux/reducers/reactions';
export default history => export default history =>
combineReducers({ combineReducers({
@ -35,6 +36,7 @@ export default history =>
homepage: homepageReducer, homepage: homepageReducer,
notifications: notificationsReducer, notifications: notificationsReducer,
publish: publishReducer, publish: publishReducer,
reactions: reactionsReducer,
rewards: rewardsReducer, rewards: rewardsReducer,
search: searchReducer, search: searchReducer,
settings: settingsReducer, settings: settingsReducer,

View file

@ -0,0 +1,70 @@
// @flow
import { Lbryio } from 'lbryinc';
import * as ACTIONS from 'constants/action_types';
import * as REACTION_TYPES from 'constants/reactions';
import { makeSelectMyReactionForUri } from '../selectors/reactions';
import { makeSelectClaimForUri } from 'lbry-redux';
export const doFetchReactions = (claimId: string) => (dispatch: Dispatch) => {
dispatch({ type: ACTIONS.REACTIONS_LIST_STARTED });
return Lbryio.call('reaction', 'list', { claim_ids: claimId }, 'post')
.then((reactions: Array<number>) => {
dispatch({ type: ACTIONS.REACTIONS_LIST_COMPLETED, data: { claimId, reactions } });
})
.catch(error => {
dispatch({ type: ACTIONS.REACTIONS_LIST_FAILED, data: error });
});
};
export const doReactionLike = (uri: string) => (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const myReaction = makeSelectMyReactionForUri(uri)(state);
const claim = makeSelectClaimForUri(uri)(state);
const claimId = claim.claim_id;
const shouldRemove = myReaction === REACTION_TYPES.LIKE;
return Lbryio.call(
'reaction',
'react',
{
claim_ids: claimId,
type: REACTION_TYPES.LIKE,
clear_types: REACTION_TYPES.DISLIKE,
...(shouldRemove ? { remove: true } : {}),
},
'post'
)
.then(() => {
dispatch({ type: ACTIONS.REACTIONS_LIKE_COMPLETED, data: { claimId, shouldRemove } });
})
.catch(error => {
dispatch({ type: ACTIONS.REACTIONS_NEW_FAILED, data: error });
});
};
export const doReactionDislike = (uri: string) => (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const myReaction = makeSelectMyReactionForUri(uri)(state);
const claim = makeSelectClaimForUri(uri)(state);
const claimId = claim.claim_id;
const shouldRemove = myReaction === REACTION_TYPES.DISLIKE;
return Lbryio.call(
'reaction',
'react',
{
claim_ids: claimId,
type: REACTION_TYPES.DISLIKE,
clear_types: REACTION_TYPES.LIKE,
...(shouldRemove ? { remove: true } : {}),
},
'post'
)
.then(() => {
dispatch({ type: ACTIONS.REACTIONS_DISLIKE_COMPLETED, data: { claimId, shouldRemove } });
})
.catch(error => {
dispatch({ type: ACTIONS.REACTIONS_NEW_FAILED, data: error });
});
};

View file

@ -0,0 +1,55 @@
// @flow
import { handleActions } from 'util/redux-utils';
import * as ACTIONS from 'constants/action_types';
import * as REACTION_TYPES from 'constants/reactions';
const defaultState = {
fetchingReactions: false,
reactionsError: undefined,
reactionsById: {},
};
export default handleActions(
{
[ACTIONS.REACTIONS_LIST_STARTED]: state => ({ ...state, fetchingReactions: true }),
[ACTIONS.REACTIONS_LIST_FAILED]: (state, action) => ({
...state,
reactionsError: action.data,
}),
[ACTIONS.REACTIONS_LIST_COMPLETED]: (state, action) => {
const { claimId, reactions } = action.data;
const reactionsById = { ...state.reactionsById, [claimId]: reactions };
return {
...state,
fetchingreactions: false,
reactionsById,
};
},
[ACTIONS.REACTIONS_LIKE_COMPLETED]: (state, action) => {
const { claimId, shouldRemove } = action.data;
const reactionsById = { ...state.reactionsById };
reactionsById[claimId].my_reactions[claimId][REACTION_TYPES.LIKE] = shouldRemove ? 0 : 1;
reactionsById[claimId].my_reactions[claimId][REACTION_TYPES.DISLIKE] = 0;
return {
...state,
fetchingreactions: false,
reactionsById,
};
},
[ACTIONS.REACTIONS_DISLIKE_COMPLETED]: (state, action) => {
const { claimId, shouldRemove } = action.data;
const reactionsById = { ...state.reactionsById };
reactionsById[claimId].my_reactions[claimId][REACTION_TYPES.DISLIKE] = shouldRemove ? 0 : 1;
reactionsById[claimId].my_reactions[claimId][REACTION_TYPES.LIKE] = 0;
return {
...state,
fetchingreactions: false,
reactionsById,
};
},
},
defaultState
);

View file

@ -0,0 +1,76 @@
import * as REACTION_TYPES from 'constants/reactions';
import { createSelector } from 'reselect';
import { makeSelectClaimForUri } from 'lbry-redux';
const selectState = state => state.reactions || {};
export const selectReactionsById = createSelector(selectState, state => state.reactionsById);
export const selectFetchingReactions = createSelector(selectState, state => state.fetchingReactions);
export const makeSelectReactionsForUri = uri =>
createSelector(makeSelectClaimForUri(uri), selectReactionsById, (claim, reactionsById) => {
return claim ? reactionsById[claim.claim_id] : {};
});
export const makeSelectMyReactionForUri = uri =>
createSelector(makeSelectClaimForUri(uri), makeSelectReactionsForUri(uri), (claim, reactions) => {
const claimId = claim.claim_id;
if (!reactions || reactions.my_reactions === null) {
return undefined;
}
const myReactions = reactions.my_reactions[claimId];
if (myReactions[REACTION_TYPES.LIKE]) {
return REACTION_TYPES.LIKE;
} else if (myReactions[REACTION_TYPES.DISLIKE]) {
return REACTION_TYPES.DISLIKE;
} else {
// Ignore other types of reactions for now
return undefined;
}
});
export const makeSelectLikeCountForUri = uri =>
createSelector(makeSelectClaimForUri(uri), makeSelectReactionsForUri(uri), (claim, reactions) => {
const claimId = claim.claim_id;
if (!reactions || reactions.my_reactions === null || reactions.others_reactions === null) {
return 0;
}
let count = 0;
if (reactions.others_reactions) {
const likeCount = reactions.others_reactions[claimId][REACTION_TYPES.LIKE] || 0;
count += likeCount;
}
if (reactions.my_reactions) {
const likeCount = reactions.my_reactions[claimId][REACTION_TYPES.LIKE] || 0;
count += likeCount;
}
return count;
});
export const makeSelectDislikeCountForUri = uri =>
createSelector(makeSelectClaimForUri(uri), makeSelectReactionsForUri(uri), (claim, reactions) => {
const claimId = claim.claim_id;
if (!reactions || reactions.my_reactions === null || reactions.others_reactions === null) {
return 0;
}
let count = 0;
if (reactions.others_reactions) {
const dislikeCount = reactions.others_reactions[claimId][REACTION_TYPES.DISLIKE] || 0;
count += dislikeCount;
}
if (reactions.my_reactions) {
const dislikeCount = reactions.my_reactions[claimId][REACTION_TYPES.DISLIKE] || 0;
count += dislikeCount;
}
return count;
});