Compare commits

...

2 commits

Author SHA1 Message Date
zeppi
8a81f3d46b note infinite claim_search 2021-07-01 16:21:45 -04:00
zeppi
8d0d207f08 try better api down experience 2021-07-01 15:40:13 -04:00
24 changed files with 174 additions and 91 deletions

View file

@ -36,6 +36,7 @@ const Nag = React.lazy(() => import('component/common/nag' /* webpackChunkName:
const NagContinueFirstRun = React.lazy(() =>
import('component/nagContinueFirstRun' /* webpackChunkName: "secondary" */)
);
const NagFatalError = React.lazy(() => import('web/component/nag-fatal-error' /* webpackChunkName: "secondary" */));
const OpenInAppLink = React.lazy(() => import('web/component/openInAppLink' /* webpackChunkName: "secondary" */));
// @if TARGET='web'
@ -51,7 +52,6 @@ const YoutubeWelcome = React.lazy(() =>
);
// @endif
const SyncFatalError = React.lazy(() => import('component/syncFatalError' /* webpackChunkName: "syncFatalError" */));
const Yrbl = React.lazy(() => import('component/yrbl' /* webpackChunkName: "yrbl" */));
// ****************************************************************************
@ -391,18 +391,6 @@ function App(props: Props) {
}
// @endif
if (syncFatalError) {
return (
<React.Suspense fallback={null}>
<SyncFatalError
// @if TARGET='web'
lbryTvApiStatus={lbryTvApiStatus}
// @endif
/>
</React.Suspense>
);
}
return (
<div
className={classnames(MAIN_WRAPPER_CLASS, {
@ -455,6 +443,7 @@ function App(props: Props) {
<NagDataCollection onClose={handleAnalyticsDismiss} />
)}
{user === null && <NagNoUser />}
{syncFatalError && <NagFatalError />}
{/* @endif */}
</React.Suspense>
</React.Fragment>

View file

@ -2,11 +2,13 @@ import Button from './view';
import React, { forwardRef } from 'react';
import { connect } from 'react-redux';
import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectSyncFatalError } from 'redux/selectors/sync';
const mapStateToProps = (state) => ({
pathname: state.router.location.pathname,
emailVerified: selectUserVerifiedEmail(state),
user: selectUser(state),
fatal: selectSyncFatalError(state),
});
const ConnectedButton = connect(mapStateToProps)(Button);

View file

@ -39,6 +39,8 @@ type Props = {
dispatch: any,
'aria-label'?: string,
user: ?User,
disableOnFatal?: boolean,
fatal: boolean,
};
// use forwardRef to allow consumers to pass refs to the button content if they want to
@ -72,10 +74,12 @@ const Button = forwardRef<any, {}>((props: Props, ref: any) => {
pathname,
user,
authSrc,
disableOnFatal,
fatal,
...otherProps
} = props;
const disable = disabled || (user === null && requiresAuth);
const disable = disabled || (user === null && requiresAuth) || (fatal && disableOnFatal);
const combinedClassName = classnames(
'button',

View file

@ -89,7 +89,14 @@ function ChannelBlockButton(props: Props) {
}
}
return <Button button={isBlocked ? 'alt' : 'secondary'} label={getButtonText(blockLevel)} onClick={handleClick} />;
return (
<Button
button={isBlocked ? 'alt' : 'secondary'}
label={getButtonText(blockLevel)}
onClick={handleClick}
disableOnFatal
/>
);
}
export default ChannelBlockButton;

View file

@ -458,6 +458,7 @@ function ChannelForm(props: Props) {
disabled={
creatingChannel || updatingChannel || nameError || bidError || (isNewChannel && !params.name)
}
disableOnFatal
label={creatingChannel || updatingChannel ? __('Submitting') : __('Submit')}
onClick={handleSubmit}
/>

View file

@ -24,7 +24,6 @@ type Props = {
doClaimSearch: ({}) => void,
loading: boolean,
personalView: boolean,
doToggleTagFollowDesktop: (string) => void,
meta?: Node,
showNsfw: boolean,
hideReposts: boolean,

View file

@ -10,6 +10,7 @@ import {
COLLECTIONS_CONSTS,
makeSelectEditedCollectionForId,
} from 'lbry-redux';
import { selectSyncFatalError } from 'redux/selectors/sync';
import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked';
import { doSetActiveChannel, doSetIncognito, doOpenModal } from 'redux/actions/app';
@ -48,6 +49,7 @@ const select = (state, props) => {
collectionName: makeSelectNameForCollectionId(props.collectionId)(state),
isMyCollection: makeSelectCollectionIsMine(props.collectionId)(state),
editedCollection: makeSelectEditedCollectionForId(props.collectionId)(state),
fatal: selectSyncFatalError(state),
};
};

View file

@ -53,6 +53,7 @@ type Props = {
doChannelUnsubscribe: (SubscriptionArgs) => void,
isChannelPage: boolean,
editedCollection: Collection,
fatal?: boolean,
};
function ClaimMenuList(props: Props) {
@ -87,6 +88,7 @@ function ClaimMenuList(props: Props) {
doChannelUnsubscribe,
isChannelPage = false,
editedCollection,
fatal,
} = props;
const repostedContent = claim && claim.reposted_claim;
const contentClaim = repostedContent || claim;
@ -202,12 +204,19 @@ function ClaimMenuList(props: Props) {
>
<Icon size={20} icon={ICONS.MORE_VERTICAL} />
</MenuButton>
<MenuList className="menu__list">
<MenuList
className="menu__list"
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
}}
>
{/* WATCH LATER */}
<>
{isPlayable && !collectionId && (
<MenuItem
className="comment__menu-option"
disabled={fatal}
onSelect={() => {
doToast({
message: __('Item %action% Watch Later', {
@ -236,6 +245,7 @@ function ClaimMenuList(props: Props) {
<MenuItem
className="comment__menu-option"
onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}?view=edit`)}
disabled={fatal}
>
<div className="menu__link">
<Icon aria-hidden iconColor={'red'} icon={ICONS.PUBLISH} />
@ -243,7 +253,11 @@ function ClaimMenuList(props: Props) {
</div>
</MenuItem>
)}
<MenuItem className="comment__menu-option" onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}`)}>
<MenuItem
className="comment__menu-option"
onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}`)}
disabled={fatal}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.VIEW} />
{__('View List')}
@ -252,6 +266,7 @@ function ClaimMenuList(props: Props) {
<MenuItem
className="comment__menu-option"
onSelect={() => openModal(MODALS.COLLECTION_DELETE, { collectionId })}
disabled={fatal}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.DELETE} />
@ -265,6 +280,7 @@ function ClaimMenuList(props: Props) {
<MenuItem
className="comment__menu-option"
onSelect={() => openModal(MODALS.COLLECTION_ADD, { uri, type: 'playlist' })}
disabled={fatal}
>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.STACK} />
@ -276,7 +292,7 @@ function ClaimMenuList(props: Props) {
{!isChannelPage && (
<>
<hr className="menu__separator" />
<MenuItem className="comment__menu-option" onSelect={handleSupport}>
<MenuItem className="comment__menu-option" onSelect={handleSupport} disabled={fatal}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.LBC} />
{__('Support')}
@ -288,7 +304,7 @@ function ClaimMenuList(props: Props) {
{!incognitoClaim && !isRepost && !claimIsMine && !isChannelPage && (
<>
<hr className="menu__separator" />
<MenuItem className="comment__menu-option" onSelect={handleFollow}>
<MenuItem className="comment__menu-option" onSelect={handleFollow} disabled={fatal}>
<div className="menu__link">
<Icon aria-hidden icon={ICONS.SUBSCRIBE} />
{subscriptionLabel}

View file

@ -30,6 +30,7 @@ export default function ClaimSupportButton(props: Props) {
label={isRepost ? __('Support Repost') : __('Support --[button to support a claim]--')}
requiresAuth={IS_WEB}
title={__('Support this claim')}
disableOnFatal
onClick={() => doOpenModal(MODALS.SEND_TIP, { uri, isSupport: true })}
/>
);

View file

@ -621,6 +621,7 @@ function PublishForm(props: Props) {
button="primary"
onClick={handlePublish}
label={submitLabel}
disableOnFatal
disabled={
formDisabled ||
!formValid ||

View file

@ -52,7 +52,7 @@ export default function SettingAccountPassword(props: Props) {
name="setting_set_old_password"
label={__('Old Password')}
value={oldPassword}
onChange={e => setOldPassword(e.target.value)}
onChange={(e) => setOldPassword(e.target.value)}
/>
)}
<FormField
@ -60,13 +60,24 @@ export default function SettingAccountPassword(props: Props) {
name="setting_set_new_password"
label={__('New Password')}
value={newPassword}
onChange={e => setNewPassword(e.target.value)}
onChange={(e) => setNewPassword(e.target.value)}
/>
<div className="section__actions">
<Button button="primary" type="submit" label={__('Set Password')} disabled={!newPassword} />
<Button
button="primary"
type="submit"
label={__('Set Password')}
disabled={!newPassword}
disableOnFatal
/>
{hasPassword ? (
<Button button="link" label={__('Forgot Password?')} navigate={`/$/${PAGES.AUTH_PASSWORD_RESET}`} />
<Button
button="link"
label={__('Forgot Password?')}
navigate={`/$/${PAGES.AUTH_PASSWORD_RESET}`}
disableOnFatal
/>
) : (
<Button button="link" label={__('Cancel')} onClick={() => setIsAddingPassword(false)} />
)}
@ -82,6 +93,7 @@ export default function SettingAccountPassword(props: Props) {
<Button
button="primary"
label={hasPassword ? __('Update Your Password') : __('Add A Password')}
disableOnFatal
onClick={() => setIsAddingPassword(true)}
/>
)

View file

@ -70,6 +70,7 @@ export default function SubscribeButton(props: Props) {
requiresAuth={IS_WEB}
label={label}
title={titlePrefix}
disableOnFatal
onClick={(e) => {
e.stopPropagation();
@ -95,6 +96,7 @@ export default function SubscribeButton(props: Props) {
requiresAuth={IS_WEB}
label={label}
title={titlePrefix}
disableOnFatal
onClick={(e) => {
e.stopPropagation();
@ -114,6 +116,7 @@ export default function SubscribeButton(props: Props) {
button="alt"
icon={notificationsDisabled ? ICONS.BELL : ICONS.BELL_ON}
aria-label={notificationsDisabled ? __('Turn on notifications') : __('Turn off notifications')}
disableOnFatal
onClick={() => {
const newNotificationsDisabled = !notificationsDisabled;

View file

@ -48,6 +48,7 @@ class TransactionListTableItem extends React.PureComponent<Props, State> {
return (
<Button
disabled={abandonState === ABANDON_STATES.DONE}
disableOnFatal
button="secondary"
icon={ICONS.UNLOCK}
onClick={this.abandonClaim}
@ -59,6 +60,7 @@ class TransactionListTableItem extends React.PureComponent<Props, State> {
return (
<Button
disabled={abandonState === ABANDON_STATES.DONE}
disableOnFatal
button="secondary"
icon={ICONS.DELETE}
onClick={this.abandonClaim}

View file

@ -325,6 +325,7 @@ function VideoViewer(props: Props) {
button="secondary"
className="ads__video-link"
label={__('Sign Up')}
disableOnFatal
navigate={`/$/${PAGES.AUTH}?redirect=${pathname}&src=video-ad`}
/>
),

View file

@ -84,6 +84,7 @@ function ModalRemoveFile(props: Props) {
<>
<div className="section__actions">
<Button
disableOnFatal
button="primary"
label={isAbandoning ? __('Removing...') : __('OK')}
disabled={isAbandoning}

View file

@ -29,79 +29,79 @@ type ChannelsFollowingItem = {
function ChannelsFollowingDiscover(props: Props) {
const { followedTags, subscribedChannels, blockedChannels, homepageData } = props;
const { PRIMARY_CONTENT_CHANNEL_IDS } = homepageData;
let rowData: Array<ChannelsFollowingItem> = [];
// let rowData: Array<ChannelsFollowingItem> = [];
const notChannels = subscribedChannels
.map(({ uri }) => uri)
.concat(blockedChannels)
.map(uri => uri.split('#')[1]);
rowData.push({
title: 'Top Channels Of All Time',
link: `/$/${PAGES.DISCOVER}?claim_type=channel&${CS.ORDER_BY_KEY}=${CS.ORDER_BY_TOP}&${CS.FRESH_KEY}=${CS.FRESH_ALL}`,
options: {
pageSize: 12,
claimType: 'channel',
orderBy: ['effective_amount'],
},
});
rowData.push({
title: 'Latest From @lbrycast',
link: `/@lbrycast:4`,
options: {
orderBy: ['release_time'],
pageSize: 8,
channelIds: ['4c29f8b013adea4d5cca1861fb2161d5089613ea'],
},
});
rowData.push({
title: 'Trending Channels',
link: `/$/${PAGES.DISCOVER}?claim_type=channel`,
options: {
pageSize: 8,
claimType: 'channel',
orderBy: ['trending_group', 'trending_mixed'],
},
});
if (followedTags.length > 0 && followedTags.length < 5) {
const followedRows = followedTags.map((tag: Tag) => ({
title: `Trending Channels for #${toCapitalCase(tag.name)}`,
link: `/$/${PAGES.DISCOVER}?t=${tag.name}&claim_type=channel`,
const getRowData = () => {
const rData = [];
rData.push({
title: 'Top Channels Of All Time',
link: `/$/${PAGES.DISCOVER}?claim_type=channel&${CS.ORDER_BY_KEY}=${CS.ORDER_BY_TOP}&${CS.FRESH_KEY}=${CS.FRESH_ALL}`,
options: {
pageSize: 12,
claimType: 'channel',
pageSize: 4,
tags: [tag.name],
},
}));
rowData.push(...followedRows);
}
if (followedTags.length > 4) {
rowData.push({
title: 'Trending For Your Tags',
link: `/$/${PAGES.TAGS_FOLLOWING}?claim_type=channel`,
options: {
claimType: 'channel',
tags: followedTags.map(tag => tag.name),
},
});
}
const rowDataWithGenericOptions = rowData.map(row => {
return {
...row,
options: {
...row.options,
orderBy: ['effective_amount'],
notChannels,
},
};
});
});
rData.push({
title: 'Latest From @lbrycast',
link: `/@lbrycast:4`,
options: {
orderBy: ['release_time'],
pageSize: 8,
channelIds: ['4c29f8b013adea4d5cca1861fb2161d5089613ea'],
notChannels,
},
});
rData.push({
title: 'Trending Channels',
link: `/$/${PAGES.DISCOVER}?claim_type=channel`,
options: {
pageSize: 8,
claimType: 'channel',
orderBy: ['trending_group', 'trending_mixed'],
notChannels,
},
});
if (followedTags.length > 0 && followedTags.length < 5) {
const followedRows = followedTags.map((tag: Tag) => ({
title: `Trending Channels for #${toCapitalCase(tag.name)}`,
link: `/$/${PAGES.DISCOVER}?t=${tag.name}&claim_type=channel`,
options: {
claimType: 'channel',
pageSize: 4,
tags: [tag.name],
notChannels,
},
}));
rData.push(...followedRows);
}
if (followedTags.length > 4) {
rData.push({
title: 'Trending For Your Tags',
link: `/$/${PAGES.TAGS_FOLLOWING}?claim_type=channel`,
options: {
claimType: 'channel',
tags: followedTags.map(tag => tag.name),
notChannels,
},
});
}
return rData;
};
const [rowData] = React.useState(getRowData() || []);
return (
<Page>
{rowDataWithGenericOptions.map(({ title, link, help, options = {} }) => (
{rowData.map(({ title, link, help, options = {} }) => (
<div key={title} className="claim-grid__wrapper">
<h1 className="section__actions">
{link ? (
@ -117,7 +117,7 @@ function ChannelsFollowingDiscover(props: Props) {
)}
{help}
</h1>
{ /* This does infinite claim_search if apis are down */ }
<ClaimTilesDiscover {...options} />
</div>
))}
@ -125,6 +125,7 @@ function ChannelsFollowingDiscover(props: Props) {
{__('More Channels')}
</h1>
{/* odysee: claimIds = PRIMARY_CONTENT_CHANNEL_IDS if simplesite CLD */}
<ClaimListDiscover
defaultOrderBy={CS.ORDER_BY_TRENDING}
defaultFreshness={CS.FRESH_ALL}
@ -132,6 +133,7 @@ function ChannelsFollowingDiscover(props: Props) {
claimIds={SIMPLE_SITE ? PRIMARY_CONTENT_CHANNEL_IDS : undefined}
scrollAnchor={MORE_CHANNELS_ANCHOR}
/>
</Page>
);
}

View file

@ -19,7 +19,7 @@ export default function CheckoutPage() {
}
actions={
<div className="section__actions">
<Button button="primary" label={__('Checkout')} />
<Button button="primary" label={__('Checkout')} disableOnFatal />
<div>
<img src={CreditCards} style={{ height: '1.5rem' }} />
</div>

View file

@ -246,6 +246,7 @@ export default function LivestreamSetupPage(props: Props) {
<div className="section__actions">
<Button
button="primary"
disableOnFatal
onClick={() =>
doNewLivestream(`/$/${PAGES.UPLOAD}?type=${PUBLISH_MODES.LIVESTREAM.toLowerCase()}`)
}

View file

@ -148,6 +148,7 @@ function ShowPage(props: Props) {
button="primary"
label={__('Publish Something')}
onClick={() => beginPublish(contentName)}
disableOnFatal
/>
<Button
button="secondary"

View file

@ -33,6 +33,7 @@ function TagsFollowingPage(props: Props) {
icon={ICONS.EDIT}
label={__('Manage')}
requiresAuth={IS_WEB}
disableOnFatal
navigate={`/$/${PAGES.TAGS_FOLLOWING_MANAGE}`}
/>
}

View file

@ -40,7 +40,14 @@ function TopPage(props: Props) {
label={__('Repost Here')}
/>
),
publish: <Button button="secondary" onClick={() => beginPublish(queryName)} label={'Publish Here'} />,
publish: (
<Button
button="secondary"
onClick={() => beginPublish(queryName)}
label={'Publish Here'}
disableOnFatal
/>
),
}}
>
%repost% %publish%

View file

@ -185,6 +185,7 @@ export default function YoutubeSync(props: Props) {
button="primary"
type="submit"
disabled={nameError || !channel || !acknowledgedTerms}
disableOnFatal
label={__('Claim Now')}
/>

View file

@ -59,9 +59,13 @@ export function doToggleSubscription(subscription: SubscriptionArgs, isSubscribe
}
}
dispatch(doToast({
message: __(!isSubscribed ? 'You followed %CHANNEL_NAME%!' : 'Unfollowed %CHANNEL_NAME%.', { CHANNEL_NAME: subscription.channelName }),
}));
dispatch(
doToast({
message: __(!isSubscribed ? 'You followed %CHANNEL_NAME%!' : 'Unfollowed %CHANNEL_NAME%.', {
CHANNEL_NAME: subscription.channelName,
}),
})
);
};
}

View file

@ -0,0 +1,25 @@
// @flow
import { SITE_NAME } from 'config';
import React from 'react';
import Nag from 'component/common/nag';
import I18nMessage from 'component/i18nMessage';
export default function NagFatalError() {
return (
<Nag
type="error"
message={
<I18nMessage
tokens={{
SITE_NAME,
}}
>
There was a problem connecting to your account. Some features will not be available but you can keep enjoying
content.
</I18nMessage>
}
actionText={__('Refresh')}
onClick={() => window.location.reload()}
/>
);
}