diff --git a/.env.defaults b/.env.defaults index bfeb12fff..7a244cd80 100644 --- a/.env.defaults +++ b/.env.defaults @@ -12,7 +12,6 @@ LBRY_WEB_API=https://api.na-backend.odysee.com LBRY_WEB_STREAMING_API=https://cdn.lbryplayer.xyz LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video COMMENT_SERVER_API=https://comments.odysee.com/api/v2 -COMMENT_SERVER_NAME=Odysee SEARCH_SERVER_API=https://lighthouse.odysee.com/search SOCKETY_SERVER_API=wss://sockety.odysee.com/ws THUMBNAIL_CDN_URL=https://image-processor.vanwanet.com/optimize/ diff --git a/config.js b/config.js index 89c916654..a6c6b2a5c 100644 --- a/config.js +++ b/config.js @@ -15,7 +15,6 @@ const config = { LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API, SEARCH_SERVER_API: process.env.SEARCH_SERVER_API, COMMENT_SERVER_API: process.env.COMMENT_SERVER_API, - COMMENT_SERVER_NAME: process.env.COMMENT_SERVER_NAME, SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API, WELCOME_VERSION: process.env.WELCOME_VERSION, DOMAIN: process.env.DOMAIN, diff --git a/flow-typed/Comment.js b/flow-typed/Comment.js index 17d8eac53..fdfa7880b 100644 --- a/flow-typed/Comment.js +++ b/flow-typed/Comment.js @@ -38,7 +38,6 @@ declare type CommentsState = { topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron. commentById: { [string]: Comment }, linkedCommentAncestors: { [string]: Array }, // {"linkedCommentId": ["parentId", "grandParentId", ...]} - pinnedCommentsById: {}, // ClaimId -> array of pinned comment IDs isLoading: boolean, isLoadingByParentId: { [string]: boolean }, myComments: ?Set, 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/static/app-strings.json b/static/app-strings.json index 86ee18263..a4476a78e 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2038,13 +2038,6 @@ "Your publish is being confirmed and will be live soon": "Your publish is being confirmed and will be live soon", "Clear Edits": "Clear Edits", "Something not quite right..": "Something not quite right..", - "Comments server": "Comments server", - "Default comments server (%name%)": "Default comments server (%name%)", - "Custom comments server": "Custom comments server", - "Failed to fetch comments.": "Failed to fetch comments.", - "Failed to fetch comments. Verify custom server settings.": "Failed to fetch comments. Verify custom server settings.", - "Commenting server is not set.": "Commenting server is not set.", - "Comments are not currently enabled.": "Comments are not currently enabled.", "See All": "See All", "Supporting content requires %lbc%": "Supporting content requires %lbc%", "With %lbc%, you can send tips to your favorite creators, or help boost their content for more people to see.": "With %lbc%, you can send tips to your favorite creators, or help boost their content for more people to see.", diff --git a/ui/comments.js b/ui/comments.js index 9069e49d3..8e9c5121e 100644 --- a/ui/comments.js +++ b/ui/comments.js @@ -4,13 +4,6 @@ import { COMMENT_SERVER_API } from 'config'; const Comments = { url: COMMENT_SERVER_API, enabled: Boolean(COMMENT_SERVER_API), - isCustomServer: false, - - setServerUrl: (customUrl: ?string) => { - Comments.url = customUrl === undefined ? COMMENT_SERVER_API : customUrl; - Comments.enabled = Boolean(Comments.url); - Comments.isCustomServer = Comments.url !== COMMENT_SERVER_API; - }, moderation_block: (params: ModerationBlockParams) => fetchCommentsApi('moderation.Block', params), moderation_unblock: (params: ModerationBlockParams) => fetchCommentsApi('moderation.UnBlock', params), @@ -38,10 +31,8 @@ const Comments = { }; function fetchCommentsApi(method: string, params: {}) { - if (!Comments.url) { - return Promise.reject(new Error('Commenting server is not set.')); - } else if (!Comments.enabled) { - return Promise.reject('Comments are not currently enabled.'); // eslint-disable-line + if (!Comments.enabled) { + return Promise.reject('Comments are not currently enabled'); // eslint-disable-line } const url = `${Comments.url}?m=${method}`; 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/claimMenuList/index.js b/ui/component/claimMenuList/index.js index 262a356f5..ddf7ebdf7 100644 --- a/ui/component/claimMenuList/index.js +++ b/ui/component/claimMenuList/index.js @@ -8,7 +8,6 @@ import { makeSelectCollectionIsMine, COLLECTIONS_CONSTS, makeSelectEditedCollectionForId, - makeSelectClaimIsMine, } from 'lbry-redux'; import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked'; @@ -25,6 +24,7 @@ import { makeSelectChannelIsAdminBlocked, } from 'redux/selectors/comments'; import { doToast } from 'redux/actions/notifications'; +import { makeSelectSigningIsMine } from 'redux/selectors/content'; import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; @@ -45,7 +45,7 @@ const select = (state, props) => { contentClaim, contentSigningChannel, contentChannelUri, - claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claimIsMine: makeSelectSigningIsMine(props.uri)(state), hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl( COLLECTIONS_CONSTS.WATCH_LATER_ID, contentPermanentUri diff --git a/ui/component/commentCreate/view.jsx b/ui/component/commentCreate/view.jsx index 238187cb4..8e113f269 100644 --- a/ui/component/commentCreate/view.jsx +++ b/ui/component/commentCreate/view.jsx @@ -131,7 +131,6 @@ export function CommentCreate(props: Props) { return; } - // if comment post didn't work, but tip was already made, try again to create comment if (commentFailure && tipAmount === successTip.tipAmount) { handleCreateComment(successTip.txid); return; @@ -148,19 +147,6 @@ export function CommentCreate(props: Props) { const activeChannelName = activeChannelClaim && activeChannelClaim.name; const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; - // setup variables for tip API - let channelClaimId, tipChannelName; - // if there is a signing channel it's on a file - if (claim.signing_channel) { - channelClaimId = claim.signing_channel.claim_id; - tipChannelName = claim.signing_channel.name; - - // otherwise it's on the channel page - } else { - channelClaimId = claim.claim_id; - tipChannelName = claim.name; - } - setIsSubmitting(true); if (activeTab === TAB_LBC) { @@ -174,14 +160,6 @@ export function CommentCreate(props: Props) { setTimeout(() => { handleCreateComment(txid); }, 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, - }), - }); - setSuccessTip({ txid, tipAmount }); }, () => { @@ -190,14 +168,27 @@ export function CommentCreate(props: Props) { } ); } else { + // setup variables for tip API + let channelClaimId, tipChannelName; + // if there is a signing channel it's on a file + if (claim.signing_channel) { + channelClaimId = claim.signing_channel.claim_id; + tipChannelName = claim.signing_channel.name; + + // otherwise it's on the channel page + } else { + channelClaimId = claim.claim_id; + tipChannelName = claim.name; + } + const sourceClaimId = claim.claim_id; const roundedAmount = Math.round(tipAmount * 100) / 100; Lbryio.call( 'customer', 'tip', - { // round to deal with floating point precision - amount: Math.round(100 * roundedAmount), // convert from dollars to cents + { + amount: 100 * roundedAmount, // convert from dollars to cents creator_channel_name: tipChannelName, // creator_channel_name creator_channel_claim_id: channelClaimId, tipper_channel_name: activeChannelName, @@ -341,12 +332,7 @@ export function CommentCreate(props: Props) { } onClick={handleSupportComment} /> - - {isPinned && ( - - - {__('Pinned')} - - )} -
@@ -97,8 +78,6 @@ function LivestreamComment(props: Props) { authorUri={authorUri} commentIsMine={commentIsMine} disableEdit - isTopLevel - isPinned={isPinned} disableRemove={supportAmount > 0} /> diff --git a/ui/component/livestreamComments/index.js b/ui/component/livestreamComments/index.js index 97cac2e75..a90e75abe 100644 --- a/ui/component/livestreamComments/index.js +++ b/ui/component/livestreamComments/index.js @@ -3,7 +3,6 @@ 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, @@ -18,7 +17,6 @@ const select = (state, props) => ({ 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 4341acc87..f4b073fef 100644 --- a/ui/component/livestreamComments/view.jsx +++ b/ui/component/livestreamComments/view.jsx @@ -22,8 +22,8 @@ type Props = { fetchingComments: boolean, doSuperChatList: (string) => void, superChats: Array, + superChatsTotalAmount: number, myChannels: ?Array, - pinnedCommentsById: { [claimId: string]: Array }, }; const VIEW_MODE_CHAT = 'view_chat'; @@ -38,32 +38,36 @@ export default function LivestreamComments(props: Props) { embed, doCommentSocketConnect, doCommentSocketDisconnect, - comments: commentsByChronologicalOrder, + comments, doCommentList, fetchingComments, doSuperChatList, + superChats, + superChatsTotalAmount, myChannels, - superChats: superChatsByTipAmount, - pinnedCommentsById, } = props; - let superChatsFiatAmount, superChatsTotalAmount; - const commentsRef = React.createRef(); const [scrollBottom, setScrollBottom] = React.useState(true); const [viewMode, setViewMode] = React.useState(VIEW_MODE_CHAT); const [performedInitialScroll, setPerformedInitialScroll] = React.useState(false); const claimId = claim && claim.claim_id; - const commentsLength = commentsByChronologicalOrder && commentsByChronologicalOrder.length; - const commentsToDisplay = viewMode === VIEW_MODE_CHAT ? commentsByChronologicalOrder : superChatsByTipAmount; + const commentsLength = comments && comments.length; + const commentsToDisplay = viewMode === VIEW_MODE_CHAT ? comments : superChats; const discussionElement = document.querySelector('.livestream__comments'); const commentElement = document.querySelector('.livestream-comment'); - let pinnedComment; - const pinnedCommentIds = (claimId && pinnedCommentsById[claimId]) || []; - if (pinnedCommentIds.length > 0) { - pinnedComment = commentsByChronologicalOrder.find((c) => c.comment_id === pinnedCommentIds[0]); + // todo: implement comment_list --mine in SDK so redux can grab with selectCommentIsMine + function isMyComment(channelId: string) { + if (myChannels != null && channelId != null) { + for (let i = 0; i < myChannels.length; i++) { + if (myChannels[i].claim_id === channelId) { + return true; + } + } + } + return false; } React.useEffect(() => { @@ -111,51 +115,6 @@ export default function LivestreamComments(props: Props) { } }, [commentsLength, discussionElement, handleScroll, performedInitialScroll, setPerformedInitialScroll]); - // sum total amounts for fiat tips and lbc tips - if (superChatsByTipAmount) { - let fiatAmount = 0; - let LBCAmount = 0; - for (const superChat of superChatsByTipAmount) { - if (superChat.is_fiat) { - fiatAmount = fiatAmount + superChat.support_amount; - } else { - LBCAmount = LBCAmount + superChat.support_amount; - } - } - - superChatsFiatAmount = fiatAmount; - superChatsTotalAmount = LBCAmount; - } - - let superChatsReversed; - // array of superchats organized by fiat or not first, then support amount - if (superChatsByTipAmount) { - const clonedSuperchats = JSON.parse(JSON.stringify(superChatsByTipAmount)); - - // sort by fiat first then by support amount - superChatsReversed = clonedSuperchats.sort(function(a, b) { - // if both are fiat, organize by support - if (a.is_fiat === b.is_fiat) { - return b.support_amount - a.support_amount; - // otherwise, if they are not both fiat, put the fiat transaction first - } else { - return (a.is_fiat === b.is_fiat) ? 0 : a.is_fiat ? -1 : 1; - } - }).reverse(); - } - - // todo: implement comment_list --mine in SDK so redux can grab with selectCommentIsMine - function isMyComment(channelId: string) { - if (myChannels != null && channelId != null) { - for (let i = 0; i < myChannels.length; i++) { - if (myChannels[i].claim_id === channelId) { - return true; - } - } - } - return false; - } - if (!claim) { return null; } @@ -171,55 +130,41 @@ export default function LivestreamComments(props: Props) {
{__('Live discussion')}
- {(superChatsTotalAmount || 0) > 0 && ( + {superChatsTotalAmount > 0 && (
- - {/* the superchats in chronological order button */}
)}
<> - {fetchingComments && !commentsByChronologicalOrder && ( + {fetchingComments && !comments && (
)}
- {viewMode === VIEW_MODE_CHAT && superChatsByTipAmount && (superChatsTotalAmount || 0) > 0 && ( + {viewMode === VIEW_MODE_CHAT && superChatsTotalAmount > 0 && superChats && (
- {superChatsByTipAmount.map((superChat: Comment) => ( + {superChats.map((superChat: Comment) => (
@@ -242,39 +187,9 @@ export default function LivestreamComments(props: Props) {
)} - {pinnedComment && ( -
- -
- )} - - {/* top to bottom comment display */} - {!fetchingComments && commentsByChronologicalOrder.length > 0 ? ( + {!fetchingComments && comments.length > 0 ? (
- {viewMode === VIEW_MODE_CHAT && commentsToDisplay.map((comment) => ( - - ))} - - {viewMode === VIEW_MODE_SUPER_CHAT && superChatsReversed && superChatsReversed.map((comment) => ( + {commentsToDisplay.map((comment) => ( { @@ -380,11 +381,9 @@ function RepostCreate(props: Props) { error={repostBidError} helper={ <> - + {__('Winning amount: %amount%', { + amount: Number(takeoverAmount).toFixed(2), + })} } diff --git a/ui/component/settingCommentsServer/index.js b/ui/component/settingCommentsServer/index.js deleted file mode 100644 index 9ad06707b..000000000 --- a/ui/component/settingCommentsServer/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import { connect } from 'react-redux'; -import { SETTINGS } from 'lbry-redux'; -import { doSetClientSetting } from 'redux/actions/settings'; -import { makeSelectClientSetting } from 'redux/selectors/settings'; -import SettingCommentsServer from './view'; - -const select = (state) => ({ - customServerEnabled: makeSelectClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVER_ENABLED)(state), - customServerUrl: makeSelectClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVER_URL)(state), -}); - -const perform = (dispatch) => ({ - setCustomServerEnabled: (val) => dispatch(doSetClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVER_ENABLED, val, true)), - setCustomServerUrl: (url) => dispatch(doSetClientSetting(SETTINGS.CUSTOM_COMMENTS_SERVER_URL, url, true)), -}); - -export default connect(select, perform)(SettingCommentsServer); diff --git a/ui/component/settingCommentsServer/view.jsx b/ui/component/settingCommentsServer/view.jsx deleted file mode 100644 index 5421398da..000000000 --- a/ui/component/settingCommentsServer/view.jsx +++ /dev/null @@ -1,70 +0,0 @@ -// @flow -import { COMMENT_SERVER_NAME } from 'config'; -import React from 'react'; -import Comments from 'comments'; -import { FormField } from 'component/common/form'; - -const DEBOUNCE_TEXT_INPUT_MS = 500; - -type Props = { - customServerEnabled: boolean, - customServerUrl: string, - setCustomServerEnabled: (boolean) => void, - setCustomServerUrl: (string) => void, -}; - -function SettingCommentsServer(props: Props) { - const { customServerEnabled, customServerUrl, setCustomServerEnabled, setCustomServerUrl } = props; - const [customUrl, setCustomUrl] = React.useState(customServerUrl); - - React.useEffect(() => { - const timer = setTimeout(() => { - setCustomServerUrl(customUrl); - Comments.url = customUrl; - }, DEBOUNCE_TEXT_INPUT_MS); - - return () => clearTimeout(timer); - }, [customUrl, setCustomServerUrl]); - - return ( - - - { - if (e.target.checked) { - setCustomServerEnabled(false); - } - }} - /> - { - if (e.target.checked) { - setCustomServerEnabled(true); - } - }} - /> - - {customServerEnabled && ( -
- setCustomUrl(e.target.value)} - /> -
- )} -
-
- ); -} - -export default SettingCommentsServer; 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/component/walletSendTip/view.jsx b/ui/component/walletSendTip/view.jsx index 7af9b6046..97fe1186e 100644 --- a/ui/component/walletSendTip/view.jsx +++ b/ui/component/walletSendTip/view.jsx @@ -122,7 +122,7 @@ function WalletSendTip(props: Props) { // check if creator has an account saved React.useEffect(() => { - const tipInputElement = document.getElementById('tip-input'); + var tipInputElement = document.getElementById('tip-input'); if (tipInputElement) { tipInputElement.focus() } }, []); @@ -141,8 +141,6 @@ function WalletSendTip(props: Props) { .then((accountCheckResponse) => { if (accountCheckResponse === true && canReceiveFiatTip !== true) { setCanReceiveFiatTip(true); - } else { - setCanReceiveFiatTip(false); } }) .catch(function (error) { @@ -171,8 +169,7 @@ function WalletSendTip(props: Props) { } const claimTypeText = setClaimTypeText(); - let iconToUse; - let explainerText = ''; + let iconToUse, explainerText; if (activeTab === TAB_BOOST) { iconToUse = ICONS.LBC; explainerText = __('This refundable boost will improve the discoverability of this %claimTypeText% while active.', {claimTypeText}); @@ -276,8 +273,8 @@ function WalletSendTip(props: Props) { Lbryio.call( 'customer', 'tip', - { // round to fix issues with floating point numbers - amount: Math.round(100 * tipAmount), // convert from dollars to cents + { + amount: 100 * tipAmount, // convert from dollars to cents creator_channel_name: tipChannelName, // creator_channel_name creator_channel_claim_id: channelClaimId, tipper_channel_name: sendAnonymously ? '' : activeChannelName, @@ -298,7 +295,7 @@ function WalletSendTip(props: Props) { }); }) .catch(function(error) { - let displayError = 'Sorry, there was an error in processing your payment!'; + var displayError = 'Sorry, there was an error in processing your payment!'; if (error.message !== 'payment intent failed to confirm') { displayError = error.message; @@ -316,53 +313,10 @@ function WalletSendTip(props: Props) { } } - const countDecimals = function(value) { - const text = value.toString(); - const index = text.indexOf('.'); - return (text.length - index - 1); - }; - function handleCustomPriceChange(event: SyntheticInputEvent<*>) { - let tipAmountAsString = event.target.value; + const tipAmount = parseFloat(event.target.value); - let tipAmount = parseFloat(tipAmountAsString); - - const howManyDecimals = countDecimals(tipAmountAsString); - - // fiat tip input - if (activeTab === TAB_FIAT) { - if (Number.isNaN(tipAmount)) { - setCustomTipAmount(''); - } - - // allow maximum of two decimal places - if (howManyDecimals > 2) { - tipAmount = Math.floor(tipAmount * 100) / 100; - } - - // remove decimals, and then get number of digits - const howManyDigits = Math.trunc(tipAmount).toString().length; - - if (howManyDigits > 4 && tipAmount !== 1000) { - setTipError('Amount cannot be over 1000 dollars'); - setCustomTipAmount(tipAmount); - } else if (tipAmount > 1000) { - setTipError('Amount cannot be over 1000 dollars'); - setCustomTipAmount(tipAmount); - } else { - setCustomTipAmount(tipAmount); - } - // LBC tip input - } else { - // TODO: this is a bit buggy, needs a touchup - // if (howManyDecimals > 9) { - // // only allows up to 8 decimal places - // tipAmount = Number(tipAmount.toString().match(/^-?\d+(?:\.\d{0,8})?/)[0]); - // - // setTipError('Please only use up to 8 decimals'); - // } - setCustomTipAmount(tipAmount); - } + setCustomTipAmount(tipAmount); } function buildButtonText() { @@ -377,14 +331,8 @@ function WalletSendTip(props: Props) { return false; } - function convertToTwoDecimals(number) { - return (Math.round(number * 100) / 100).toFixed(2); - } - - const amountToShow = activeTab === TAB_FIAT ? convertToTwoDecimals(tipAmount) : tipAmount; - // if it's a valid number display it, otherwise do an empty string - const displayAmount = !isNan(tipAmount) ? amountToShow : ''; + const displayAmount = !isNan(tipAmount) ? tipAmount : ''; if (activeTab === TAB_BOOST) { return (claimIsMine ? __('Boost Your %claimTypeText%', {claimTypeText}) : __('Boost This %claimTypeText%', {claimTypeText})); @@ -414,242 +362,240 @@ function WalletSendTip(props: Props) { return (
{/* if there is no LBC balance, show user frontend to get credits */} - {/* if there is lbc, the main tip/boost gui with the 3 tabs at the top */} - } - subtitle={ - - {!claimIsMine && ( -
- {/* tip LBC tab button */} -
- )} - - {/* short explainer under the button */} -
- {explainerText + ' '} - {/* {activeTab === TAB_FIAT && !hasCardSaved &&
-
- } - actions={ - // confirmation modal, allow user to confirm or cancel transaction - isConfirming ? ( - <> -
+ } + /> + ) : ( + // if there is lbc, the main tip/boost gui with the 3 tabs at the top + } + subtitle={ + + {!claimIsMine && (
-
{__('To --[the tip recipient]--')}
-
{channelName || title}
-
{__('From --[the tip sender]--')}
-
- {activeChannelClaim && !incognito ? activeChannelClaim.name : __('Anonymous')} -
-
{setConfirmLabel()}
-
- {activeTab === TAB_FIAT ?

$ {(Math.round(tipAmount * 100) / 100).toFixed(2)}

: } -
+ {/* tip LBC tab button */} +
-
-
-
- - // only show the prompt to earn more if its lbc or boost tab and no balance - // otherwise you can show the full prompt - ) : (!((activeTab === TAB_LBC || activeTab === TAB_BOOST) && noBalance) - ? <> -
- -
- - {activeTab === TAB_FIAT && !hasCardSaved && ( -

-

)} - {/* section to pick tip/boost amount */} -
- {DEFAULT_TIP_AMOUNTS.map((amount) => ( + {/* short explainer under the button */} +
+ {explainerText} + {/* {activeTab === TAB_FIAT && !hasCardSaved &&
+ + } + actions={ + // confirmation modal, allow user to confirm or cancel transaction + isConfirming ? ( + <> +
+
+
{__('To --[the tip recipient]--')}
+
{channelName || title}
+
{__('From --[the tip sender]--')}
+
+ {activeChannelClaim && !incognito ? activeChannelClaim.name : __('Anonymous')} +
+
{setConfirmLabel()}
+
+ {activeTab === TAB_FIAT ?

$ {tipAmount}

: } +
+
+
+
+
+ + ) : ( + <> +
+ +
+ + {activeTab === TAB_FIAT && !hasCardSaved && ( +

+

+ )} + + {/* section to pick tip/boost amount */} +
+ {DEFAULT_TIP_AMOUNTS.map((amount) => ( +
- - {useCustomTip && ( -
- - {__('Custom support amount')}{' '} - {activeTab !== TAB_FIAT ? ( - }} - > - (%lbc_balance% Credits available) - - ) : ( - 'in USD' - )} - - } - error={tipError} - min="0" - step="any" - type="number" - style={{ - width: activeTab === TAB_FIAT ? '99px' : '160px', - }} - placeholder="1.23" - value={customTipAmount} - onChange={(event) => handleCustomPriceChange(event)} - /> + {DEFAULT_TIP_AMOUNTS.some((val) => val > balance) && activeTab !== TAB_FIAT && ( +
- )} - {/* send tip/boost button */} -
-
- {activeTab !== TAB_FIAT ? ( - - ) : !canReceiveFiatTip ? ( -
{__('Only select creators can receive tips at this time')}
- ) : ( -
{__('The payment will be made from your saved card')}
- )} - - // if it's LBC and there is no balance, you can prompt to purchase LBC - : }}>Supporting content requires %lbc%} - subtitle={ - }}> - With %lbc%, you can send tips to your favorite creators, or help boost their content for more people to - see. - - } - actions={ -
-
- } - /> - ) - } - /> + {useCustomTip && ( +
+ + {__('Custom support amount')}{' '} + {activeTab !== TAB_FIAT ? ( + }} + > + (%lbc_balance% Credits available) + + ) : ( + 'in USD' + )} + + } + className="form-field--price-amount" + error={tipError} + min="0" + step="any" + type="number" + placeholder="1.23" + value={customTipAmount} + onChange={(event) => handleCustomPriceChange(event)} + /> +
+ )} + + {/* send tip/boost button */} +
+
+ {activeTab !== TAB_FIAT ? ( + + ) : !canReceiveFiatTip ? ( +
{__('Only select creators can receive tips at this time')}
+ ) : ( +
{__('The payment will be made from your saved card')}
+ )} + + ) + } + /> + )} ); } diff --git a/ui/component/walletTipAmountSelector/view.jsx b/ui/component/walletTipAmountSelector/view.jsx index 76a571da3..db5c4abd2 100644 --- a/ui/component/walletTipAmountSelector/view.jsx +++ b/ui/component/walletTipAmountSelector/view.jsx @@ -263,6 +263,7 @@ function WalletTipAmountSelector(props: Props) { //
// } + className="form-field--price-amount" error={tipError} min="0" step="any" 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/modal/modalRemoveFile/index.js b/ui/modal/modalRemoveFile/index.js index 529364bde..9d8dbfb9c 100644 --- a/ui/modal/modalRemoveFile/index.js +++ b/ui/modal/modalRemoveFile/index.js @@ -5,13 +5,13 @@ import { doResolveUri, makeSelectClaimForUri, makeSelectIsAbandoningClaimForUri, - makeSelectClaimIsMine, } from 'lbry-redux'; import { doHideModal } from 'redux/actions/app'; import ModalRemoveFile from './view'; +import { makeSelectSigningIsMine } from 'redux/selectors/content'; const select = (state, props) => ({ - claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claimIsMine: makeSelectSigningIsMine(props.uri)(state), title: makeSelectTitleForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state), isAbandoning: makeSelectIsAbandoningClaimForUri(props.uri)(state), 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/page/settingsAdvanced/view.jsx b/ui/page/settingsAdvanced/view.jsx index 4807eaa9e..4850d35f0 100644 --- a/ui/page/settingsAdvanced/view.jsx +++ b/ui/page/settingsAdvanced/view.jsx @@ -5,7 +5,6 @@ import { FormField, FormFieldPrice } from 'component/common/form'; import Button from 'component/button'; import I18nMessage from 'component/i18nMessage'; import Page from 'component/page'; -import SettingCommentsServer from 'component/settingCommentsServer'; import SettingWalletServer from 'component/settingWalletServer'; import SettingAutoLaunch from 'component/settingAutoLaunch'; import SettingClosingBehavior from 'component/settingClosingBehavior'; @@ -508,10 +507,6 @@ class SettingsAdvancedPage extends React.PureComponent { /> )} - {/* @if TARGET='app' */} - } /> - {/* @endif */} - } /> {/* @if TARGET='app' */} diff --git a/ui/page/settingsStripeAccount/index.js b/ui/page/settingsStripeAccount/index.js index fd03b4f49..633726701 100644 --- a/ui/page/settingsStripeAccount/index.js +++ b/ui/page/settingsStripeAccount/index.js @@ -2,14 +2,12 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import StripeAccountConnection from './view'; import { selectUser } from 'redux/selectors/user'; -import { doToast } from 'redux/actions/notifications'; +// function that receives state parameter and returns object of functions that accept state const select = (state) => ({ user: selectUser(state), }); -const perform = (dispatch) => ({ - doToast: (options) => dispatch(doToast(options)), -}); +// const perform = (dispatch) => ({}); -export default withRouter(connect(select, perform)(StripeAccountConnection)); +export default withRouter(connect(select)(StripeAccountConnection)); diff --git a/ui/page/settingsStripeAccount/view.jsx b/ui/page/settingsStripeAccount/view.jsx index 2821b4423..4276ca306 100644 --- a/ui/page/settingsStripeAccount/view.jsx +++ b/ui/page/settingsStripeAccount/view.jsx @@ -31,8 +31,6 @@ if (isDev) { type Props = { source: string, user: User, - doOpenModal: (string, {}) => void, - doToast: ({ message: string }) => void, }; type State = { @@ -70,8 +68,6 @@ class StripeAccountConnection extends React.Component { componentDidMount() { const { user } = this.props; - let doToast = this.props.doToast; - // $FlowFixMe this.experimentalUiEnabled = user && user.experimental_ui; @@ -131,8 +127,10 @@ class StripeAccountConnection extends React.Component { ).then((accountListResponse: any) => { // TODO type this that.setState({ - accountTransactions: accountListResponse.reverse(), + accountTransactions: accountListResponse, }); + + console.log(accountListResponse); }); } @@ -167,9 +165,6 @@ class StripeAccountConnection extends React.Component { // get stripe link and set it on the frontend getAndSetAccountLink(true); } else { - // probably an error from stripe - const displayString = __('There was an error getting your account setup, please try again later'); - doToast({ message: displayString, isError: true }); // not an error from Beamer, throw it throw new Error(error); } @@ -301,7 +296,7 @@ class StripeAccountConnection extends React.Component { {accountTransactions && - accountTransactions.map((transaction) => ( + accountTransactions.reverse().map((transaction) => ( {moment(transaction.created_at).format('LLL')} diff --git a/ui/page/settingsStripeCard/view.jsx b/ui/page/settingsStripeCard/view.jsx index ba8763143..7fd138038 100644 --- a/ui/page/settingsStripeCard/view.jsx +++ b/ui/page/settingsStripeCard/view.jsx @@ -19,9 +19,6 @@ if (STRIPE_PUBLIC_KEY.indexOf('pk_live') > -1) { stripeEnvironment = 'live'; } -const APIS_DOWN_ERROR_RESPONSE = __('There was an error from the server, please try again later'); -const CARD_SETUP_ERROR_RESPONSE = __('There was an error getting your card setup, please try again later'); - // eslint-disable-next-line flowtype/no-types-missing-file-annotation type Props = { disabled: boolean, @@ -60,6 +57,8 @@ class SettingsStripeCard extends React.Component { componentDidMount() { let that = this; + console.log(this.props); + let doToast = this.props.doToast; const script = document.createElement('script'); @@ -101,6 +100,8 @@ class SettingsStripeCard extends React.Component { let topOfDisplay = customer.email.split('@')[0]; let bottomOfDisplay = '@' + customer.email.split('@')[1]; + console.log(customerStatusResponse.Customer); + let cardDetails = { brand: card.brand, expiryYear: card.exp_year, @@ -132,6 +133,8 @@ class SettingsStripeCard extends React.Component { }, 'post' ).then((customerSetupResponse) => { + console.log(customerSetupResponse); + clientSecret = customerSetupResponse.client_secret; // instantiate stripe elements @@ -151,10 +154,14 @@ class SettingsStripeCard extends React.Component { that.setState({ customerTransactions: customerTransactionsResponse, }); + + console.log(customerTransactionsResponse); }); // if the status call fails, either an actual error or need to run setup first }) .catch(function (error) { + console.log(error); + // errorString passed from the API (with a 403 error) const errorString = 'user as customer is not setup yet'; @@ -174,17 +181,18 @@ class SettingsStripeCard extends React.Component { }, 'post' ).then((customerSetupResponse) => { + console.log(customerSetupResponse); + clientSecret = customerSetupResponse.client_secret; // instantiate stripe elements setupStripe(); }); - // 500 error from the backend being down } else if (error === 'internal_apis_down') { - doToast({ message: APIS_DOWN_ERROR_RESPONSE, isError: true }); + var displayString = 'There was an error from the server, please let support know'; + doToast({ message: displayString, isError: true }); } else { - // probably an error from stripe - doToast({ message: CARD_SETUP_ERROR_RESPONSE, isError: true }); + console.log('Unseen before error'); } }); }, 250); @@ -253,6 +261,8 @@ class SettingsStripeCard extends React.Component { }) .then(function (result) { if (result.error) { + console.log(result); + changeLoadingState(false); var displayError = document.getElementById('card-errors'); displayError.textContent = result.error.message; @@ -336,6 +346,8 @@ class SettingsStripeCard extends React.Component { }); }); + console.log(result); + changeLoadingState(false); }); }; diff --git a/ui/redux/actions/comments.js b/ui/redux/actions/comments.js index b4eac5e5e..36bb55353 100644 --- a/ui/redux/actions/comments.js +++ b/ui/redux/actions/comments.js @@ -28,7 +28,6 @@ import { selectPrefsReady } from 'redux/selectors/sync'; import { doAlertWaitingForSync } from 'redux/actions/app'; const isDev = process.env.NODE_ENV !== 'production'; -const FETCH_API_FAILED_TO_FETCH = 'Failed to fetch'; const COMMENTRON_MSG_REMAP = { // <-- Commentron msg --> : <-- App msg --> @@ -112,32 +111,20 @@ export function doCommentList( return result; }) .catch((error) => { - switch (error.message) { - case 'comments are disabled by the creator': - dispatch({ - type: ACTIONS.COMMENT_LIST_COMPLETED, - data: { - authorClaimId: authorChannelClaim ? authorChannelClaim.claim_id : undefined, - disabled: true, - }, - }); - break; - - case FETCH_API_FAILED_TO_FETCH: - dispatch( - doToast({ - isError: true, - message: Comments.isCustomServer - ? __('Failed to fetch comments. Verify custom server settings.') - : __('Failed to fetch comments.'), - }) - ); - dispatch({ type: ACTIONS.COMMENT_LIST_FAILED, data: error }); - break; - - default: - dispatch(doToast({ isError: true, message: `${error.message}` })); - dispatch({ type: ACTIONS.COMMENT_LIST_FAILED, data: error }); + if (error.message === 'comments are disabled by the creator') { + dispatch({ + type: ACTIONS.COMMENT_LIST_COMPLETED, + data: { + authorClaimId: authorChannelClaim ? authorChannelClaim.claim_id : undefined, + disabled: true, + }, + }); + } else { + devToast(dispatch, `doCommentList: ${error.message}`); + dispatch({ + type: ACTIONS.COMMENT_LIST_FAILED, + data: error, + }); } }); }; @@ -274,6 +261,7 @@ export function doCommentReactList(commentIds: Array) { }); }) .catch((error) => { + devToast(dispatch, `doCommentReactList: ${error.message}`); dispatch({ type: ACTIONS.COMMENT_REACTION_LIST_FAILED, data: error, 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/actions/websocket.js b/ui/redux/actions/websocket.js index 78552ab18..7c5532ea4 100644 --- a/ui/redux/actions/websocket.js +++ b/ui/redux/actions/websocket.js @@ -110,17 +110,6 @@ export const doCommentSocketConnect = (uri, claimId) => (dispatch) => { data: { connected, claimId }, }); } - if (response.type === 'pinned') { - const pinnedComment = response.data.comment; - dispatch({ - type: ACTIONS.COMMENT_PIN_COMPLETED, - data: { - pinnedComment: pinnedComment, - claimId, - unpin: !pinnedComment.is_pinned, - }, - }); - } }); }; diff --git a/ui/redux/reducers/comments.js b/ui/redux/reducers/comments.js index 4b5af666a..c81725a1e 100644 --- a/ui/redux/reducers/comments.js +++ b/ui/redux/reducers/comments.js @@ -19,7 +19,6 @@ const defaultState: CommentsState = { commentsByUri: {}, // URI -> claimId linkedCommentAncestors: {}, // {"linkedCommentId": ["parentId", "grandParentId", ...]} superChatsByUri: {}, - pinnedCommentsById: {}, // ClaimId -> array of pinned comment IDs isLoading: false, isLoadingByParentId: {}, isCommenting: false, @@ -286,7 +285,6 @@ export default handleActions( const commentsByUri = Object.assign({}, state.commentsByUri); const repliesByParentId = Object.assign({}, state.repliesByParentId); const totalCommentsById = Object.assign({}, state.totalCommentsById); - const pinnedCommentsById = Object.assign({}, state.pinnedCommentsById); const totalRepliesByParentId = Object.assign({}, state.totalRepliesByParentId); const isLoadingByParentId = Object.assign({}, state.isLoadingByParentId); @@ -317,9 +315,6 @@ export default handleActions( 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); - } } } // --- Replies --- @@ -342,7 +337,6 @@ export default handleActions( topLevelTotalPagesById, repliesByParentId, totalCommentsById, - pinnedCommentsById, totalRepliesByParentId, byId, commentById, @@ -627,20 +621,12 @@ export default handleActions( const { pinnedComment, claimId, unpin } = action.data; const commentById = Object.assign({}, state.commentById); 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 (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 @@ -648,26 +634,9 @@ export default handleActions( topLevelCommentsById[claimId].push(pinnedComment.comment_id); } else { topLevelCommentsById[claimId].unshift(pinnedComment.comment_id); - 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; - } + commentById[pinnedComment.comment_id] = pinnedComment; } } @@ -675,7 +644,6 @@ export default handleActions( ...state, commentById, topLevelCommentsById, - pinnedCommentsById, }; }, 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/reducers/settings.js b/ui/redux/reducers/settings.js index 3b791e34a..dc87fca6b 100644 --- a/ui/redux/reducers/settings.js +++ b/ui/redux/reducers/settings.js @@ -4,7 +4,6 @@ import { ACTIONS as LBRY_REDUX_ACTIONS, SETTINGS, SHARED_PREFERENCES } from 'lbr import { getSubsetFromKeysArray } from 'util/sync-settings'; import { getDefaultLanguage } from 'util/default-languages'; import { UNSYNCED_SETTINGS, SIMPLE_SITE } from 'config'; -import Comments from 'comments'; const { CLIENT_SYNC_KEYS } = SHARED_PREFERENCES; const settingsToIgnore = (UNSYNCED_SETTINGS && UNSYNCED_SETTINGS.trim().split(' ')) || []; @@ -52,8 +51,6 @@ const defaultState = { [SETTINGS.VIDEO_THEATER_MODE]: false, [SETTINGS.VIDEO_PLAYBACK_RATE]: 1, [SETTINGS.DESKTOP_WINDOW_ZOOM]: 1, - [SETTINGS.CUSTOM_COMMENTS_SERVER_ENABLED]: false, - [SETTINGS.CUSTOM_COMMENTS_SERVER_URL]: '', [SETTINGS.DARK_MODE_TIMES]: { from: { hour: '21', min: '00', formattedTime: '21:00' }, @@ -172,13 +169,6 @@ reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => { const selectedSettings = sharedPreferences ? getSubsetFromKeysArray(sharedPreferences, clientSyncKeys) : {}; const mergedClientSettings = { ...currentClientSettings, ...selectedSettings }; const newSharedPreferences = sharedPreferences || {}; - - Comments.setServerUrl( - mergedClientSettings[SETTINGS.CUSTOM_COMMENTS_SERVER_ENABLED] - ? mergedClientSettings[SETTINGS.CUSTOM_COMMENTS_SERVER_URL] - : undefined - ); - return Object.assign({}, state, { sharedPreferences: newSharedPreferences, clientSettings: mergedClientSettings, diff --git a/ui/redux/selectors/comments.js b/ui/redux/selectors/comments.js index 1a2ec9e78..8d7a898ff 100644 --- a/ui/redux/selectors/comments.js +++ b/ui/redux/selectors/comments.js @@ -17,7 +17,6 @@ export const selectCommentsDisabledChannelIds = createSelector( (state) => state.commentsDisabledChannelIds ); export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId); -export const selectPinnedCommentsById = createSelector(selectState, (state) => state.pinnedCommentsById); export const selectModerationBlockList = createSelector(selectState, (state) => state.moderationBlockList ? state.moderationBlockList.reverse() : [] diff --git a/ui/redux/selectors/content.js b/ui/redux/selectors/content.js index 67fcf9e6b..faaa4acc5 100644 --- a/ui/redux/selectors/content.js +++ b/ui/redux/selectors/content.js @@ -11,6 +11,8 @@ import { parseURI, makeSelectContentTypeForUri, makeSelectFileNameForUri, + normalizeURI, + selectMyActiveClaims, selectClaimIdsByUri, } from 'lbry-redux'; import { makeSelectRecommendedContentForUri } from 'redux/selectors/search'; @@ -245,6 +247,24 @@ export const makeSelectInsufficientCreditsForUri = (uri: string) => } ); +export const makeSelectSigningIsMine = (rawUri: string) => { + let uri; + try { + uri = normalizeURI(rawUri); + } catch (e) {} + + return createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => { + try { + parseURI(uri); + } catch (e) { + return false; + } + const signingChannel = claims && claims[uri] && (claims[uri].signing_channel || claims[uri]); + + return signingChannel && myClaims.has(signingChannel.claim_id); + }); +}; + export const makeSelectRecommendationId = (claimId: string) => createSelector(selectState, (state) => state.recommendationId[claimId]); 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/scss/component/_comments.scss b/ui/scss/component/_comments.scss index 065987e7f..e99a2345a 100644 --- a/ui/scss/component/_comments.scss +++ b/ui/scss/component/_comments.scss @@ -217,7 +217,6 @@ $thumbnailWidthSmall: 1rem; .comment__pin { margin-left: var(--spacing-s); - font-size: var(--font-xsmall); .icon { padding-top: 1px; diff --git a/ui/scss/component/_livestream.scss b/ui/scss/component/_livestream.scss index 4654cb9a4..22fdbe239 100644 --- a/ui/scss/component/_livestream.scss +++ b/ui/scss/component/_livestream.scss @@ -223,27 +223,6 @@ $discussion-header__height: 3rem; } } -.livestream-pinned__wrapper { - flex-shrink: 0; - position: relative; - padding: var(--spacing-s) var(--spacing-xs); - border-bottom: 1px solid var(--color-border); - font-size: var(--font-small); - background-color: var(--color-card-background-highlighted); - width: 100%; - - .livestream-comment { - padding-top: var(--spacing-xs); - max-height: 6rem; - overflow-y: scroll; - } - - @media (min-width: $breakpoint-small) { - padding: var(--spacing-xs); - width: var(--livestream-comments-width); - } -} - .livestream-superchat__amount-large { .credit-amount { display: flex; 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)); } diff --git a/yarn.lock b/yarn.lock index 0862f56f9..9ac3c7109 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12020,11 +12020,15 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.5, path-parse@^1.0.6: +path-parse@^1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"