From 5f55603fb26c58c26f52f73a7090707d984cea46 Mon Sep 17 00:00:00 2001 From: jessopb <36554050+jessopb@users.noreply.github.com> Date: Tue, 17 Aug 2021 10:03:25 -0400 Subject: [PATCH 01/10] send recsys powered-by (#6875) * send recsys powered-by * update lighthouse call in useLighthouse * rename select selectors * update channel search too --- flow-typed/search.js | 3 +- ui/component/channelContent/view.jsx | 2 +- .../internal/plugins/videojs-recsys/plugin.js | 3 +- ui/effects/use-lighthouse.js | 2 +- ui/page/search/index.js | 4 +- ui/redux/actions/search.js | 14 ++--- ui/redux/reducers/search.js | 12 +++-- ui/redux/selectors/search.js | 54 +++++++++++++++---- ui/util/handle-fetch.js | 7 ++- 9 files changed, 72 insertions(+), 29 deletions(-) diff --git a/flow-typed/search.js b/flow-typed/search.js index adfb768f6..b795f9c12 100644 --- a/flow-typed/search.js +++ b/flow-typed/search.js @@ -28,7 +28,7 @@ declare type SearchOptions = { declare type SearchState = { options: SearchOptions, - urisByQuery: {}, + resultsByQuery: {}, hasReachedMaxResultsLength: {}, searching: boolean, }; @@ -40,6 +40,7 @@ declare type SearchSuccess = { from: number, size: number, uris: Array, + recsys: string, }, }; diff --git a/ui/component/channelContent/view.jsx b/ui/component/channelContent/view.jsx index 3498e5799..c069428a5 100644 --- a/ui/component/channelContent/view.jsx +++ b/ui/component/channelContent/view.jsx @@ -81,7 +81,7 @@ function ChannelContent(props: Props) { !showMature ? '&nsfw=false&size=50&from=0' : '' }` ) - .then((results) => { + .then(({ body: results }) => { const urls = results.map(({ name, claimId }) => { return `lbry://${name}#${claimId}`; }); diff --git a/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js b/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js index 5ee3f3c8d..01fd9a117 100644 --- a/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js +++ b/ui/component/viewers/videoViewer/internal/plugins/videojs-recsys/plugin.js @@ -6,6 +6,7 @@ import { makeSelectRecommendedClaimIds, makeSelectRecommendationClicks, } from 'redux/selectors/content'; +import { makeSelectRecommendedRecsysIdForClaimId } from 'redux/selectors/search'; const VERSION = '0.0.1'; @@ -36,7 +37,7 @@ function createRecsys(claimId, userId, events, loadedAt, isEmbed) { claimId: claimId, pageLoadedAt: pageLoadedAt, pageExitedAt: pageExitedAt, - recsysId: recsysId, + recsysId: makeSelectRecommendedRecsysIdForClaimId(claimId)(state) || recsysId, recClaimIds: makeSelectRecommendedClaimIds(claimId)(state), recClickedVideoIdx: makeSelectRecommendationClicks(claimId)(state), events: events, diff --git a/ui/effects/use-lighthouse.js b/ui/effects/use-lighthouse.js index 029668c20..b5b9f31e5 100644 --- a/ui/effects/use-lighthouse.js +++ b/ui/effects/use-lighthouse.js @@ -25,7 +25,7 @@ export default function useLighthouse( let isSubscribed = true; lighthouse .search(throttledQuery) - .then((results) => { + .then(({ body: results }) => { if (isSubscribed) { setResults( results.map((result) => `lbry://${result.name}#${result.claimId}`).filter((uri) => isURIValid(uri)) diff --git a/ui/page/search/index.js b/ui/page/search/index.js index 30558e61a..d1c140fd1 100644 --- a/ui/page/search/index.js +++ b/ui/page/search/index.js @@ -3,7 +3,7 @@ import { withRouter } from 'react-router'; import { doSearch } from 'redux/actions/search'; import { selectIsSearching, - makeSelectSearchUris, + makeSelectSearchUrisForQuery, selectSearchOptions, makeSelectHasReachedMaxResultsLength, } from 'redux/selectors/search'; @@ -28,7 +28,7 @@ const select = (state, props) => { }; const query = getSearchQueryString(urlQuery, searchOptions); - const uris = makeSelectSearchUris(query)(state); + const uris = makeSelectSearchUrisForQuery(query)(state); const hasReachedMaxResultsLength = makeSelectHasReachedMaxResultsLength(query)(state); return { diff --git a/ui/redux/actions/search.js b/ui/redux/actions/search.js index 0da0039d0..28b1a724c 100644 --- a/ui/redux/actions/search.js +++ b/ui/redux/actions/search.js @@ -2,7 +2,7 @@ import * as ACTIONS from 'constants/action_types'; import { SEARCH_OPTIONS } from 'constants/search'; import { buildURI, doResolveUris, batchActions, isURIValid, makeSelectClaimForUri } from 'lbry-redux'; -import { makeSelectSearchUris, selectSearchValue } from 'redux/selectors/search'; +import { makeSelectSearchUrisForQuery, selectSearchValue } from 'redux/selectors/search'; import handleFetchResponse from 'util/handle-fetch'; import { getSearchQueryString } from 'util/query-params'; import { SIMPLE_SITE, SEARCH_SERVER_API } from 'config'; @@ -48,7 +48,7 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( const from = searchOptions.from; // If we have already searched for something, we don't need to do anything - const urisForQuery = makeSelectSearchUris(queryWithOptions)(state); + const urisForQuery = makeSelectSearchUrisForQuery(queryWithOptions)(state); if (urisForQuery && !!urisForQuery.length) { if (!size || !from || from + size < urisForQuery.length) { return; @@ -61,13 +61,14 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( lighthouse .search(queryWithOptions) - .then((data: Array<{ name: string, claimId: string }>) => { + .then((data: { body: Array<{ name: string, claimId: string }>, poweredBy: string }) => { + const { body: result, poweredBy } = data; const uris = []; const actions = []; - data.forEach((result) => { - if (result) { - const { name, claimId } = result; + result.forEach((item) => { + if (item) { + const { name, claimId } = item; const urlObj: LbryUrlObj = {}; if (name.startsWith('@')) { @@ -94,6 +95,7 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( from: from, size: size, uris, + recsys: poweredBy, }, }); dispatch(batchActions(...actions)); diff --git a/ui/redux/reducers/search.js b/ui/redux/reducers/search.js index 7730eeaa5..e97f868ec 100644 --- a/ui/redux/reducers/search.js +++ b/ui/redux/reducers/search.js @@ -17,7 +17,7 @@ const defaultState: SearchState = { [SEARCH_OPTIONS.MEDIA_IMAGE]: defaultSearchTypes.includes(SEARCH_OPTIONS.MEDIA_IMAGE), [SEARCH_OPTIONS.MEDIA_APPLICATION]: defaultSearchTypes.includes(SEARCH_OPTIONS.MEDIA_APPLICATION), }, - urisByQuery: {}, + resultsByQuery: {}, hasReachedMaxResultsLength: {}, searching: false, }; @@ -29,21 +29,23 @@ export default handleActions( searching: true, }), [ACTIONS.SEARCH_SUCCESS]: (state: SearchState, action: SearchSuccess): SearchState => { - const { query, uris, from, size } = action.data; + const { query, uris, from, size, recsys } = action.data; const normalizedQuery = createNormalizedSearchKey(query); + const urisForQuery = state.resultsByQuery[normalizedQuery] && state.resultsByQuery[normalizedQuery]['uris']; let newUris = uris; - if (from !== 0 && state.urisByQuery[normalizedQuery]) { - newUris = Array.from(new Set(state.urisByQuery[normalizedQuery].concat(uris))); + if (from !== 0 && urisForQuery) { + newUris = Array.from(new Set(urisForQuery.concat(uris))); } // The returned number of urls is less than the page size, so we're on the last page const noMoreResults = size && uris.length < size; + const results = { uris: newUris, recsys }; return { ...state, searching: false, - urisByQuery: Object.assign({}, state.urisByQuery, { [normalizedQuery]: newUris }), + resultsByQuery: Object.assign({}, state.resultsByQuery, { [normalizedQuery]: results }), hasReachedMaxResultsLength: Object.assign({}, state.hasReachedMaxResultsLength, { [normalizedQuery]: noMoreResults, }), diff --git a/ui/redux/selectors/search.js b/ui/redux/selectors/search.js index d864ea00d..1d97b1976 100644 --- a/ui/redux/selectors/search.js +++ b/ui/redux/selectors/search.js @@ -4,6 +4,7 @@ import { selectShowMatureContent } from 'redux/selectors/settings'; import { parseURI, makeSelectClaimForUri, + makeSelectClaimForClaimId, makeSelectClaimIsNsfw, buildURI, isClaimNsfw, @@ -26,9 +27,9 @@ export const selectSearchOptions: (state: State) => SearchOptions = createSelect export const selectIsSearching: (state: State) => boolean = createSelector(selectState, (state) => state.searching); -export const selectSearchUrisByQuery: (state: State) => { [string]: Array } = createSelector( +export const selectSearchResultByQuery: (state: State) => { [string]: Array } = createSelector( selectState, - (state) => state.urisByQuery + (state) => state.resultsByQuery ); export const selectHasReachedMaxResultsLength: (state: State) => { [boolean]: Array } = createSelector( @@ -36,15 +37,15 @@ export const selectHasReachedMaxResultsLength: (state: State) => { [boolean]: Ar (state) => state.hasReachedMaxResultsLength ); -export const makeSelectSearchUris = (query: string): ((state: State) => Array) => +export const makeSelectSearchUrisForQuery = (query: string): ((state: State) => Array) => // replace statement below is kind of ugly, and repeated in doSearch action - createSelector(selectSearchUrisByQuery, (byQuery) => { + createSelector(selectSearchResultByQuery, (byQuery) => { if (query) { query = query.replace(/^lbry:\/\//i, '').replace(/\//, ' '); const normalizedQuery = createNormalizedSearchKey(query); - return byQuery[normalizedQuery]; + return byQuery[normalizedQuery] && byQuery[normalizedQuery]['uris']; } - return byQuery[query]; + return byQuery[query] && byQuery[query]['uris']; }); export const makeSelectHasReachedMaxResultsLength = (query: string): ((state: State) => boolean) => @@ -60,7 +61,7 @@ export const makeSelectHasReachedMaxResultsLength = (query: string): ((state: St export const makeSelectRecommendedContentForUri = (uri: string) => createSelector( makeSelectClaimForUri(uri), - selectSearchUrisByQuery, + selectSearchResultByQuery, makeSelectClaimIsNsfw(uri), (claim, searchUrisByQuery, isMature) => { let recommendedContent; @@ -84,16 +85,47 @@ export const makeSelectRecommendedContentForUri = (uri: string) => const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options); const normalizedSearchQuery = createNormalizedSearchKey(searchQuery); - let searchUris = searchUrisByQuery[normalizedSearchQuery]; - if (searchUris) { - searchUris = searchUris.filter((searchUri) => searchUri !== currentUri); - recommendedContent = searchUris; + let searchResult = searchUrisByQuery[normalizedSearchQuery]; + if (searchResult) { + recommendedContent = searchResult['uris'].filter((searchUri) => searchUri !== currentUri); } } return recommendedContent; } ); +export const makeSelectRecommendedRecsysIdForClaimId = (claimId: string) => + createSelector(makeSelectClaimForClaimId(claimId), selectSearchResultByQuery, (claim, searchUrisByQuery) => { + // TODO: DRY this out. + let poweredBy; + if (claim) { + const isMature = isClaimNsfw(claim); + const { title } = claim.value; + + if (!title) { + return; + } + + const options: { + related_to?: string, + nsfw?: boolean, + isBackgroundSearch?: boolean, + } = { related_to: claim.claim_id, isBackgroundSearch: true }; + + options['nsfw'] = isMature; + const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options); + const normalizedSearchQuery = createNormalizedSearchKey(searchQuery); + + let searchResult = searchUrisByQuery[normalizedSearchQuery]; + if (searchResult) { + poweredBy = searchResult.recsys; + } else { + return normalizedSearchQuery; + } + } + return poweredBy; + }); + export const makeSelectWinningUriForQuery = (query: string) => { const uriFromQuery = `lbry://${query}`; diff --git a/ui/util/handle-fetch.js b/ui/util/handle-fetch.js index 83ce10513..4686b9b1a 100644 --- a/ui/util/handle-fetch.js +++ b/ui/util/handle-fetch.js @@ -1,4 +1,9 @@ // @flow export default function handleFetchResponse(response: Response): Promise { - return response.status === 200 ? Promise.resolve(response.json()) : Promise.reject(new Error(response.statusText)); + const headers = response.headers; + const poweredBy = headers.get('x-powered-by'); + + return response.status === 200 + ? response.json().then((body) => ({ body, poweredBy })) + : Promise.reject(new Error(response.statusText)); } -- 2.45.2 From 4688b4bf58dce79ec2ce928fc8c9c5fa77903dcf Mon Sep 17 00:00:00 2001 From: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com> Date: Tue, 17 Aug 2021 09:09:55 -0700 Subject: [PATCH 02/10] Livestream: stop pinned comments from appearing as latest (#6888) ## Ticket 6879: Previously pinned livestream comments show as latest ## Issue `comment.List` will always display the pinned comment first, hence the problem when the chat is refreshed. ## Approach Completely split pinned comments from top-level comments in the Reducer, and the let the GUI (e.g. regular comments, livestream comments) decide how they want to display it. For the case of livestream, there is no need to repeat the pinned comments in the regular chat area, since there is a dedicated area on top. --- ui/component/commentsList/index.js | 2 + ui/component/commentsList/view.jsx | 61 +++++++++--------- ui/component/livestreamComments/index.js | 4 +- ui/component/livestreamComments/view.jsx | 10 +-- ui/redux/reducers/comments.js | 78 +++++++++++++----------- ui/redux/selectors/comments.js | 20 ++++++ 6 files changed, 101 insertions(+), 74 deletions(-) diff --git a/ui/component/commentsList/index.js b/ui/component/commentsList/index.js index 5d54af205..e56b6ca6d 100644 --- a/ui/component/commentsList/index.js +++ b/ui/component/commentsList/index.js @@ -15,6 +15,7 @@ import { selectMyReactionsByCommentId, makeSelectCommentIdsForUri, selectSettingsByChannelId, + makeSelectPinnedCommentsForUri, } from 'redux/selectors/comments'; import { doCommentReset, doCommentList, doCommentById, doCommentReactList } from 'redux/actions/comments'; import { selectActiveChannelClaim } from 'redux/selectors/app'; @@ -25,6 +26,7 @@ const select = (state, props) => { return { myChannels: selectMyChannelClaims(state), allCommentIds: makeSelectCommentIdsForUri(props.uri)(state), + pinnedComments: makeSelectPinnedCommentsForUri(props.uri)(state), topLevelComments: makeSelectTopLevelCommentsForUri(props.uri)(state), topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(props.uri)(state), totalComments: makeSelectTotalCommentsCountForUri(props.uri)(state), diff --git a/ui/component/commentsList/view.jsx b/ui/component/commentsList/view.jsx index 6e750bd3d..ae3ee5b12 100644 --- a/ui/component/commentsList/view.jsx +++ b/ui/component/commentsList/view.jsx @@ -28,6 +28,7 @@ function scaleToDevicePixelRatio(value) { type Props = { allCommentIds: any, + pinnedComments: Array, topLevelComments: Array, topLevelTotalPages: number, fetchTopLevelComments: (string, number, number, number) => void, @@ -57,6 +58,7 @@ function CommentList(props: Props) { fetchReacts, resetComments, uri, + pinnedComments, topLevelComments, topLevelTotalPages, claim, @@ -111,6 +113,34 @@ function CommentList(props: Props) { } } + function getCommentElems(comments) { + return comments.map((comment) => { + return ( + + ); + }); + } + // Reset comments useEffect(() => { if (page === 0) { @@ -223,8 +253,6 @@ function CommentList(props: Props) { topLevelTotalPages, ]); - const displayedComments = readyToDisplayComments ? topLevelComments : []; - return ( - {topLevelComments && - displayedComments && - displayedComments.map((comment) => { - return ( - - ); - })} + {readyToDisplayComments && pinnedComments && getCommentElems(pinnedComments)} + {readyToDisplayComments && topLevelComments && getCommentElems(topLevelComments)} {isMobile && ( diff --git a/ui/component/livestreamComments/index.js b/ui/component/livestreamComments/index.js index 97cac2e75..10ee56c06 100644 --- a/ui/component/livestreamComments/index.js +++ b/ui/component/livestreamComments/index.js @@ -3,22 +3,22 @@ import { makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux'; import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket'; import { doCommentList, doSuperChatList } from 'redux/actions/comments'; import { - selectPinnedCommentsById, makeSelectTopLevelCommentsForUri, selectIsFetchingComments, makeSelectSuperChatsForUri, makeSelectSuperChatTotalAmountForUri, + makeSelectPinnedCommentsForUri, } from 'redux/selectors/comments'; import LivestreamComments from './view'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), comments: makeSelectTopLevelCommentsForUri(props.uri)(state).slice(0, 75), + pinnedComments: makeSelectPinnedCommentsForUri(props.uri)(state), fetchingComments: selectIsFetchingComments(state), superChats: makeSelectSuperChatsForUri(props.uri)(state), superChatsTotalAmount: makeSelectSuperChatTotalAmountForUri(props.uri)(state), myChannels: selectMyChannelClaims(state), - pinnedCommentsById: selectPinnedCommentsById(state), }); export default connect(select, { diff --git a/ui/component/livestreamComments/view.jsx b/ui/component/livestreamComments/view.jsx index a6f9e6c91..b434592f3 100644 --- a/ui/component/livestreamComments/view.jsx +++ b/ui/component/livestreamComments/view.jsx @@ -19,11 +19,11 @@ type Props = { doCommentSocketDisconnect: (string) => void, doCommentList: (string, string, number, number) => void, comments: Array, + pinnedComments: Array, fetchingComments: boolean, doSuperChatList: (string) => void, superChats: Array, myChannels: ?Array, - pinnedCommentsById: { [claimId: string]: Array }, }; const VIEW_MODE_CHAT = 'view_chat'; @@ -38,12 +38,12 @@ export default function LivestreamComments(props: Props) { doCommentSocketConnect, doCommentSocketDisconnect, comments: commentsByChronologicalOrder, + pinnedComments, doCommentList, fetchingComments, doSuperChatList, myChannels, superChats: superChatsByTipAmount, - pinnedCommentsById, } = props; let superChatsFiatAmount, superChatsTotalAmount; @@ -57,11 +57,7 @@ export default function LivestreamComments(props: Props) { const discussionElement = document.querySelector('.livestream__comments'); - let pinnedComment; - const pinnedCommentIds = (claimId && pinnedCommentsById[claimId]) || []; - if (pinnedCommentIds.length > 0) { - pinnedComment = commentsByChronologicalOrder.find((c) => c.comment_id === pinnedCommentIds[0]); - } + const pinnedComment = pinnedComments.length > 0 ? pinnedComments[0] : null; function restoreScrollPos() { if (discussionElement) { diff --git a/ui/redux/reducers/comments.js b/ui/redux/reducers/comments.js index 4e539e67c..30a558fe7 100644 --- a/ui/redux/reducers/comments.js +++ b/ui/redux/reducers/comments.js @@ -301,9 +301,10 @@ export default handleActions( for (let i = 0; i < comments.length; ++i) { const comment = comments[i]; commonUpdateAction(comment, commentById, commentIds, i); - pushToArrayInObject(topLevelCommentsById, claimId, comment.comment_id); if (comment.is_pinned) { pushToArrayInObject(pinnedCommentsById, claimId, comment.comment_id); + } else { + pushToArrayInObject(topLevelCommentsById, claimId, comment.comment_id); } } } @@ -615,45 +616,50 @@ export default handleActions( const topLevelCommentsById = Object.assign({}, state.topLevelCommentsById); const pinnedCommentsById = Object.assign({}, state.pinnedCommentsById); - if (pinnedComment && topLevelCommentsById[claimId]) { - const index = topLevelCommentsById[claimId].indexOf(pinnedComment.comment_id); - if (index > -1) { - topLevelCommentsById[claimId].splice(index, 1); - - if (pinnedCommentsById[claimId]) { - // Remove here so that the 'unshift' below will be a unique entry. - pinnedCommentsById[claimId] = pinnedCommentsById[claimId].filter((x) => x !== pinnedComment.comment_id); - } else { - pinnedCommentsById[claimId] = []; + if (pinnedComment) { + if (topLevelCommentsById[claimId]) { + const index = topLevelCommentsById[claimId].indexOf(pinnedComment.comment_id); + if (index > -1) { + topLevelCommentsById[claimId].splice(index, 1); } + } else { + topLevelCommentsById[claimId] = []; + } - if (unpin) { - // Without the sort score, I have no idea where to put it. Just - // dump it at the bottom. Users can refresh if they want it back to - // the correct sorted position. - topLevelCommentsById[claimId].push(pinnedComment.comment_id); - } else { - topLevelCommentsById[claimId].unshift(pinnedComment.comment_id); - pinnedCommentsById[claimId].unshift(pinnedComment.comment_id); + if (pinnedCommentsById[claimId]) { + const index = pinnedCommentsById[claimId].indexOf(pinnedComment.comment_id); + if (index > -1) { + pinnedCommentsById[claimId].splice(index, 1); } + } else { + pinnedCommentsById[claimId] = []; + } - if (commentById[pinnedComment.comment_id]) { - // Commentron's `comment.Pin` response places the creator's credentials - // in the 'channel_*' fields, which doesn't make sense. Maybe it is to - // show who signed/pinned it, but even if so, it shouldn't overload - // these variables which are already used by existing comment data structure. - // Ensure we don't override the existing/correct values, but fallback - // to whatever was given. - const { channel_id, channel_name, channel_url } = commentById[pinnedComment.comment_id]; - commentById[pinnedComment.comment_id] = { - ...pinnedComment, - channel_id: channel_id || pinnedComment.channel_id, - channel_name: channel_name || pinnedComment.channel_name, - channel_url: channel_url || pinnedComment.channel_url, - }; - } else { - commentById[pinnedComment.comment_id] = pinnedComment; - } + if (unpin) { + // Without the sort score, I have no idea where to put it. Just + // dump it at the top. Users can refresh if they want it back to + // the correct sorted position. + topLevelCommentsById[claimId].unshift(pinnedComment.comment_id); + } else { + pinnedCommentsById[claimId].unshift(pinnedComment.comment_id); + } + + if (commentById[pinnedComment.comment_id]) { + // Commentron's `comment.Pin` response places the creator's credentials + // in the 'channel_*' fields, which doesn't make sense. Maybe it is to + // show who signed/pinned it, but even if so, it shouldn't overload + // these variables which are already used by existing comment data structure. + // Ensure we don't override the existing/correct values, but fallback + // to whatever was given. + const { channel_id, channel_name, channel_url } = commentById[pinnedComment.comment_id]; + commentById[pinnedComment.comment_id] = { + ...pinnedComment, + channel_id: channel_id || pinnedComment.channel_id, + channel_name: channel_name || pinnedComment.channel_name, + channel_url: channel_url || pinnedComment.channel_url, + }; + } else { + commentById[pinnedComment.comment_id] = pinnedComment; } } diff --git a/ui/redux/selectors/comments.js b/ui/redux/selectors/comments.js index a724a27f3..e1f53738c 100644 --- a/ui/redux/selectors/comments.js +++ b/ui/redux/selectors/comments.js @@ -13,7 +13,27 @@ export const selectIsFetchingCommentsByParentId = createSelector(selectState, (s export const selectIsPostingComment = createSelector(selectState, (state) => state.isCommenting); export const selectIsFetchingReacts = createSelector(selectState, (state) => state.isFetchingReacts); export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId); + export const selectPinnedCommentsById = createSelector(selectState, (state) => state.pinnedCommentsById); +export const makeSelectPinnedCommentsForUri = (uri: string) => + createSelector( + selectCommentsByUri, + selectCommentsById, + selectPinnedCommentsById, + (byUri, byId, pinnedCommentsById) => { + const claimId = byUri[uri]; + const pinnedCommentIds = pinnedCommentsById && pinnedCommentsById[claimId]; + const pinnedComments = []; + + if (pinnedCommentIds) { + pinnedCommentIds.forEach((commentId) => { + pinnedComments.push(byId[commentId]); + }); + } + + return pinnedComments; + } + ); export const selectModerationBlockList = createSelector(selectState, (state) => state.moderationBlockList ? state.moderationBlockList.reverse() : [] -- 2.45.2 From 98c85fbc8e0ba1eac9e76fe30e524e965164554b Mon Sep 17 00:00:00 2001 From: zeppi Date: Tue, 17 Aug 2021 13:36:43 -0400 Subject: [PATCH 03/10] some desktop cleanup --- .env.defaults | 2 +- static/app-strings.json | 7 + ui/component/commentCreate/view.jsx | 25 +-- ui/component/walletSendTip/view.jsx | 168 ++++++++------- ui/component/walletTipAmountSelector/view.jsx | 84 ++++---- ui/constants/stripe.js | 2 + ui/page/file/view.jsx | 5 - ui/page/settingsStripeCard/view.jsx | 197 +++++++++--------- ui/page/show/view.jsx | 4 +- ui/page/wallet/view.jsx | 28 +-- ui/util/stripe.js | 13 ++ 11 files changed, 286 insertions(+), 249 deletions(-) create mode 100644 ui/constants/stripe.js create mode 100644 ui/util/stripe.js diff --git a/.env.defaults b/.env.defaults index bfeb12fff..5274f8c68 100644 --- a/.env.defaults +++ b/.env.defaults @@ -19,7 +19,7 @@ THUMBNAIL_CDN_URL=https://image-processor.vanwanet.com/optimize/ WELCOME_VERSION=1.0 # STRIPE -STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo' +# STRIPE_PUBLIC_KEY='pk_test_NoL1JWL7i1ipfhVId5KfDZgo' # Analytics MATOMO_URL=https://analytics.lbry.com/ diff --git a/static/app-strings.json b/static/app-strings.json index e5f45808b..924511e61 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2090,5 +2090,12 @@ "Expand Comments": "Expand Comments", "Expand": "Expand", "Load More": "Load More", + "You followed @Danheim!": "You followed @Danheim!", + "Collection": "Collection", + "%channelName% isn't live right now, but the chat is! Check back later to watch the stream.": "%channelName% isn't live right now, but the chat is! Check back later to watch the stream.", + "Show this channel your appreciation by sending a donation of Credits. ": "Show this channel your appreciation by sending a donation of Credits. ", + "Review": "Review", + "Add a Card ": "Add a Card ", + " Tip Creators": " Tip Creators", "--end--": "--end--" } diff --git a/ui/component/commentCreate/view.jsx b/ui/component/commentCreate/view.jsx index 008a28aa1..23b899d99 100644 --- a/ui/component/commentCreate/view.jsx +++ b/ui/component/commentCreate/view.jsx @@ -24,7 +24,7 @@ import { Lbryio } from 'lbryinc'; let stripeEnvironment = 'test'; // if the key contains pk_live it's a live key // update the environment for the calls to the backend to indicate which environment to hit -if (STRIPE_PUBLIC_KEY.indexOf('pk_live') > -1) { +if (STRIPE_PUBLIC_KEY && STRIPE_PUBLIC_KEY.indexOf('pk_live') > -1) { stripeEnvironment = 'live'; } @@ -245,10 +245,13 @@ export function CommentCreate(props: Props) { }, 1500); doToast({ - message: __("You sent %tipAmount% LBRY Credits as a tip to %tipChannelName%, I'm sure they appreciate it!", { - tipAmount: tipAmount, // force show decimal places - tipChannelName, - }), + message: __( + "You sent %tipAmount% LBRY Credits as a tip to %tipChannelName%, I'm sure they appreciate it!", + { + tipAmount: tipAmount, // force show decimal places + tipChannelName, + } + ), }); setSuccessTip({ txid, tipAmount }); @@ -265,7 +268,8 @@ export function CommentCreate(props: Props) { Lbryio.call( 'customer', 'tip', - { // round to deal with floating point precision + { + // round to deal with floating point precision amount: Math.round(100 * roundedAmount), // convert from dollars to cents creator_channel_name: tipChannelName, // creator_channel_name creator_channel_claim_id: channelClaimId, @@ -387,12 +391,7 @@ export function CommentCreate(props: Props) { } }} > - +
@@ -534,6 +533,7 @@ export function CommentCreate(props: Props) { }} /> )} + {/* @if TARGET='web' */} {!claimIsMine && (