Batch resolve pin urls in 2 ways
Expanded homepage pins to support 2 types of input (if both are passed in, pinnedUrls take precedence): (1) pinnedUrls --> uses doResolveUris (resolve) (2) pinnedClaimIds --> uses doResolveClaimIds (claim_search) Instead of injecting the pinned URLs directly, we inject from `resolvedPinUris`, which will be blank until the uris are resolved, thus preventing it from being resolved individually from the tiles. There's additional complexity with the `claim_search` method, as the rest of the code deals with uris instead of IDs. Fortunately, it's all contained with `useResolvePins`, so removal would be easier when the batch `resolve` issue is fixed.
This commit is contained in:
parent
dd5f4872fc
commit
f5034f74ca
10 changed files with 134 additions and 31 deletions
1
flow-typed/homepage.js
vendored
1
flow-typed/homepage.js
vendored
|
@ -19,6 +19,7 @@ declare type RowDataItem = {
|
||||||
icon?: string,
|
icon?: string,
|
||||||
extra?: any,
|
extra?: any,
|
||||||
pinnedUrls?: Array<string>,
|
pinnedUrls?: Array<string>,
|
||||||
|
pinnedClaimIds?: Array<string>, // pinnedUrls takes precedence
|
||||||
options?: {
|
options?: {
|
||||||
channelIds?: Array<string>,
|
channelIds?: Array<string>,
|
||||||
limitClaimsPerChannel?: number,
|
limitClaimsPerChannel?: number,
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
|
selectById,
|
||||||
selectClaimsByUri,
|
selectClaimsByUri,
|
||||||
selectClaimSearchByQuery,
|
selectClaimSearchByQuery,
|
||||||
selectClaimSearchByQueryLastPageReached,
|
selectClaimSearchByQueryLastPageReached,
|
||||||
selectFetchingClaimSearch,
|
selectFetchingClaimSearch,
|
||||||
} from 'redux/selectors/claims';
|
} from 'redux/selectors/claims';
|
||||||
import { doClaimSearch } from 'redux/actions/claims';
|
import { doClaimSearch, doResolveClaimIds, doResolveUris } from 'redux/actions/claims';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import * as SETTINGS from 'constants/settings';
|
||||||
import { selectFollowedTags } from 'redux/selectors/tags';
|
import { selectFollowedTags } from 'redux/selectors/tags';
|
||||||
import { selectMutedChannels } from 'redux/selectors/blocked';
|
import { selectMutedChannels } from 'redux/selectors/blocked';
|
||||||
|
@ -20,6 +21,7 @@ const select = (state, props) => ({
|
||||||
claimSearchByQuery: selectClaimSearchByQuery(state),
|
claimSearchByQuery: selectClaimSearchByQuery(state),
|
||||||
claimSearchByQueryLastPageReached: selectClaimSearchByQueryLastPageReached(state),
|
claimSearchByQueryLastPageReached: selectClaimSearchByQueryLastPageReached(state),
|
||||||
claimsByUri: selectClaimsByUri(state),
|
claimsByUri: selectClaimsByUri(state),
|
||||||
|
claimsById: selectById(state),
|
||||||
loading: props.loading !== undefined ? props.loading : selectFetchingClaimSearch(state),
|
loading: props.loading !== undefined ? props.loading : selectFetchingClaimSearch(state),
|
||||||
showNsfw: selectShowMatureContent(state),
|
showNsfw: selectShowMatureContent(state),
|
||||||
hideReposts: selectClientSetting(state, SETTINGS.HIDE_REPOSTS),
|
hideReposts: selectClientSetting(state, SETTINGS.HIDE_REPOSTS),
|
||||||
|
@ -33,6 +35,8 @@ const perform = {
|
||||||
doClaimSearch,
|
doClaimSearch,
|
||||||
doFetchViewCount,
|
doFetchViewCount,
|
||||||
doFetchUserMemberships,
|
doFetchUserMemberships,
|
||||||
|
doResolveClaimIds,
|
||||||
|
doResolveUris,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(select, perform)(ClaimListDiscover);
|
export default connect(select, perform)(ClaimListDiscover);
|
||||||
|
|
|
@ -18,13 +18,14 @@ import I18nMessage from 'component/i18nMessage';
|
||||||
import LangFilterIndicator from 'component/langFilterIndicator';
|
import LangFilterIndicator from 'component/langFilterIndicator';
|
||||||
import ClaimListHeader from 'component/claimListHeader';
|
import ClaimListHeader from 'component/claimListHeader';
|
||||||
import useFetchViewCount from 'effects/use-fetch-view-count';
|
import useFetchViewCount from 'effects/use-fetch-view-count';
|
||||||
|
import useResolvePins from 'effects/use-resolve-pins';
|
||||||
import { useIsLargeScreen } from 'effects/use-screensize';
|
import { useIsLargeScreen } from 'effects/use-screensize';
|
||||||
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uris: Array<string>,
|
uris: Array<string>,
|
||||||
prefixUris?: Array<string>,
|
prefixUris?: Array<string>,
|
||||||
pins?: { urls: Array<string>, onlyPinForOrder?: string },
|
pins?: { urls?: Array<string>, claimIds?: Array<string>, onlyPinForOrder?: string },
|
||||||
name?: string,
|
name?: string,
|
||||||
type: string,
|
type: string,
|
||||||
pageSize?: number,
|
pageSize?: number,
|
||||||
|
@ -88,6 +89,7 @@ type Props = {
|
||||||
claimSearchByQuery: { [string]: Array<string> },
|
claimSearchByQuery: { [string]: Array<string> },
|
||||||
claimSearchByQueryLastPageReached: { [string]: boolean },
|
claimSearchByQueryLastPageReached: { [string]: boolean },
|
||||||
claimsByUri: { [string]: any },
|
claimsByUri: { [string]: any },
|
||||||
|
claimsById: { [string]: any },
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
showNsfw: boolean,
|
showNsfw: boolean,
|
||||||
hideReposts: boolean,
|
hideReposts: boolean,
|
||||||
|
@ -100,6 +102,8 @@ type Props = {
|
||||||
doClaimSearch: ({}) => void,
|
doClaimSearch: ({}) => void,
|
||||||
doFetchViewCount: (claimIdCsv: string) => void,
|
doFetchViewCount: (claimIdCsv: string) => void,
|
||||||
doFetchUserMemberships: (claimIdCsv: string) => void,
|
doFetchUserMemberships: (claimIdCsv: string) => void,
|
||||||
|
doResolveClaimIds: (Array<string>) => Promise<any>,
|
||||||
|
doResolveUris: (Array<string>, boolean) => Promise<any>,
|
||||||
|
|
||||||
hideLayoutButton?: boolean,
|
hideLayoutButton?: boolean,
|
||||||
loadedCallback?: (number) => void,
|
loadedCallback?: (number) => void,
|
||||||
|
@ -173,6 +177,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
showNoSourceClaims,
|
showNoSourceClaims,
|
||||||
empty,
|
empty,
|
||||||
claimsByUri,
|
claimsByUri,
|
||||||
|
claimsById,
|
||||||
doFetchViewCount,
|
doFetchViewCount,
|
||||||
hideLayoutButton = false,
|
hideLayoutButton = false,
|
||||||
loadedCallback,
|
loadedCallback,
|
||||||
|
@ -181,7 +186,11 @@ function ClaimListDiscover(props: Props) {
|
||||||
excludeUris = [],
|
excludeUris = [],
|
||||||
doFetchUserMemberships,
|
doFetchUserMemberships,
|
||||||
swipeLayout = false,
|
swipeLayout = false,
|
||||||
|
doResolveUris,
|
||||||
|
doResolveClaimIds,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const resolvedPinUris = useResolvePins({ pins, claimsById, doResolveClaimIds, doResolveUris });
|
||||||
const didNavigateForward = history.action === 'PUSH';
|
const didNavigateForward = history.action === 'PUSH';
|
||||||
const { search } = location;
|
const { search } = location;
|
||||||
const prevUris = React.useRef();
|
const prevUris = React.useRef();
|
||||||
|
@ -525,7 +534,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
if (uris) {
|
if (uris) {
|
||||||
// --- direct uris
|
// --- direct uris
|
||||||
finalUris = uris;
|
finalUris = uris;
|
||||||
injectPinUrls(finalUris, orderParam, pins);
|
injectPinUrls(finalUris, orderParam, pins, resolvedPinUris);
|
||||||
finalUris = filterExcludedUris(finalUris, excludeUris);
|
finalUris = filterExcludedUris(finalUris, excludeUris);
|
||||||
} else {
|
} else {
|
||||||
// --- searched uris
|
// --- searched uris
|
||||||
|
@ -533,7 +542,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
finalUris = prevUris.current;
|
finalUris = prevUris.current;
|
||||||
} else {
|
} else {
|
||||||
finalUris = claimSearchResult;
|
finalUris = claimSearchResult;
|
||||||
injectPinUrls(finalUris, orderParam, pins);
|
injectPinUrls(finalUris, orderParam, pins, resolvedPinUris);
|
||||||
finalUris = filterExcludedUris(finalUris, excludeUris);
|
finalUris = filterExcludedUris(finalUris, excludeUris);
|
||||||
prevUris.current = finalUris;
|
prevUris.current = finalUris;
|
||||||
}
|
}
|
||||||
|
@ -611,14 +620,13 @@ function ClaimListDiscover(props: Props) {
|
||||||
return order_by;
|
return order_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
function injectPinUrls(uris, order, pins) {
|
function injectPinUrls(uris, order, pins, resolvedPinUris) {
|
||||||
if (!pins || !pins.urls || (pins.onlyPinForOrder && pins.onlyPinForOrder !== order)) {
|
if (!pins || !uris || uris.length <= 2 || (pins.onlyPinForOrder && pins.onlyPinForOrder !== order)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pinUrls = pins.urls;
|
if (resolvedPinUris) {
|
||||||
if (pinUrls && uris && uris.length > 2) {
|
resolvedPinUris.forEach((pin) => {
|
||||||
pinUrls.forEach((pin) => {
|
|
||||||
if (uris.includes(pin)) {
|
if (uris.includes(pin)) {
|
||||||
uris.splice(uris.indexOf(pin), 1);
|
uris.splice(uris.indexOf(pin), 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -626,7 +634,7 @@ function ClaimListDiscover(props: Props) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
uris.splice(2, 0, ...pinUrls);
|
uris.splice(2, 0, ...resolvedPinUris);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { selectClaimSearchByQuery, selectFetchingClaimSearchByQuery, selectClaimsByUri } from 'redux/selectors/claims';
|
import {
|
||||||
import { doClaimSearch } from 'redux/actions/claims';
|
selectClaimSearchByQuery,
|
||||||
|
selectFetchingClaimSearchByQuery,
|
||||||
|
selectClaimsByUri,
|
||||||
|
selectById,
|
||||||
|
} from 'redux/selectors/claims';
|
||||||
|
import { doClaimSearch, doResolveClaimIds, doResolveUris } from 'redux/actions/claims';
|
||||||
import { doFetchUserMemberships } from 'redux/actions/user';
|
import { doFetchUserMemberships } from 'redux/actions/user';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import * as SETTINGS from 'constants/settings';
|
||||||
import { MATURE_TAGS } from 'constants/tags';
|
import { MATURE_TAGS } from 'constants/tags';
|
||||||
|
@ -35,6 +40,7 @@ const select = (state, props) => {
|
||||||
return {
|
return {
|
||||||
claimSearchResults: selectClaimSearchByQuery(state)[searchKey],
|
claimSearchResults: selectClaimSearchByQuery(state)[searchKey],
|
||||||
claimsByUri: selectClaimsByUri(state),
|
claimsByUri: selectClaimsByUri(state),
|
||||||
|
claimsById: selectById(state),
|
||||||
fetchingClaimSearch: selectFetchingClaimSearchByQuery(state)[searchKey],
|
fetchingClaimSearch: selectFetchingClaimSearchByQuery(state)[searchKey],
|
||||||
showNsfw,
|
showNsfw,
|
||||||
hideReposts,
|
hideReposts,
|
||||||
|
@ -47,6 +53,8 @@ const perform = {
|
||||||
doClaimSearch,
|
doClaimSearch,
|
||||||
doFetchViewCount,
|
doFetchViewCount,
|
||||||
doFetchUserMemberships,
|
doFetchUserMemberships,
|
||||||
|
doResolveClaimIds,
|
||||||
|
doResolveUris,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withRouter(connect(select, perform)(ClaimListDiscover));
|
export default withRouter(connect(select, perform)(ClaimListDiscover));
|
||||||
|
|
|
@ -4,6 +4,7 @@ import React from 'react';
|
||||||
import ClaimPreviewTile from 'component/claimPreviewTile';
|
import ClaimPreviewTile from 'component/claimPreviewTile';
|
||||||
import useFetchViewCount from 'effects/use-fetch-view-count';
|
import useFetchViewCount from 'effects/use-fetch-view-count';
|
||||||
import useLastVisibleItem from 'effects/use-last-visible-item';
|
import useLastVisibleItem from 'effects/use-last-visible-item';
|
||||||
|
import useResolvePins from 'effects/use-resolve-pins';
|
||||||
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
||||||
|
|
||||||
function urisEqual(prev: ?Array<string>, next: ?Array<string>) {
|
function urisEqual(prev: ?Array<string>, next: ?Array<string>) {
|
||||||
|
@ -25,7 +26,7 @@ function urisEqual(prev: ?Array<string>, next: ?Array<string>) {
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
prefixUris?: Array<string>,
|
prefixUris?: Array<string>,
|
||||||
pinUrls?: Array<string>,
|
pins?: { urls?: Array<string>, claimIds?: Array<string>, onlyPinForOrder?: string },
|
||||||
uris: Array<string>,
|
uris: Array<string>,
|
||||||
injectedItem?: { node: Node, index?: number, replace?: boolean },
|
injectedItem?: { node: Node, index?: number, replace?: boolean },
|
||||||
showNoSourceClaims?: boolean,
|
showNoSourceClaims?: boolean,
|
||||||
|
@ -51,6 +52,7 @@ type Props = {
|
||||||
location: { search: string },
|
location: { search: string },
|
||||||
claimSearchResults: Array<string>,
|
claimSearchResults: Array<string>,
|
||||||
claimsByUri: { [string]: any },
|
claimsByUri: { [string]: any },
|
||||||
|
claimsById: { [string]: any },
|
||||||
fetchingClaimSearch: boolean,
|
fetchingClaimSearch: boolean,
|
||||||
showNsfw: boolean,
|
showNsfw: boolean,
|
||||||
hideReposts: boolean,
|
hideReposts: boolean,
|
||||||
|
@ -59,6 +61,8 @@ type Props = {
|
||||||
doClaimSearch: ({}) => void,
|
doClaimSearch: ({}) => void,
|
||||||
doFetchViewCount: (claimIdCsv: string) => void,
|
doFetchViewCount: (claimIdCsv: string) => void,
|
||||||
doFetchUserMemberships: (claimIdCsv: string) => void,
|
doFetchUserMemberships: (claimIdCsv: string) => void,
|
||||||
|
doResolveClaimIds: (Array<string>) => Promise<any>,
|
||||||
|
doResolveUris: (Array<string>, boolean) => Promise<any>,
|
||||||
};
|
};
|
||||||
|
|
||||||
function ClaimTilesDiscover(props: Props) {
|
function ClaimTilesDiscover(props: Props) {
|
||||||
|
@ -66,12 +70,13 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
doClaimSearch,
|
doClaimSearch,
|
||||||
claimSearchResults,
|
claimSearchResults,
|
||||||
claimsByUri,
|
claimsByUri,
|
||||||
|
claimsById,
|
||||||
fetchViewCount,
|
fetchViewCount,
|
||||||
fetchingClaimSearch,
|
fetchingClaimSearch,
|
||||||
hasNoSource,
|
hasNoSource,
|
||||||
// forceShowReposts = false,
|
// forceShowReposts = false,
|
||||||
renderProperties,
|
renderProperties,
|
||||||
pinUrls,
|
pins,
|
||||||
prefixUris,
|
prefixUris,
|
||||||
injectedItem,
|
injectedItem,
|
||||||
showNoSourceClaims,
|
showNoSourceClaims,
|
||||||
|
@ -79,6 +84,8 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
pageSize = 8,
|
pageSize = 8,
|
||||||
optionsStringified,
|
optionsStringified,
|
||||||
doFetchUserMemberships,
|
doFetchUserMemberships,
|
||||||
|
doResolveClaimIds,
|
||||||
|
doResolveUris,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const listRef = React.useRef();
|
const listRef = React.useRef();
|
||||||
|
@ -87,21 +94,15 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
const prevUris = React.useRef();
|
const prevUris = React.useRef();
|
||||||
const claimSearchUris = claimSearchResults || [];
|
const claimSearchUris = claimSearchResults || [];
|
||||||
const isUnfetchedClaimSearch = claimSearchResults === undefined;
|
const isUnfetchedClaimSearch = claimSearchResults === undefined;
|
||||||
|
const resolvedPinUris = useResolvePins({ pins, claimsById, doResolveClaimIds, doResolveUris });
|
||||||
|
|
||||||
const shouldPerformSearch = !fetchingClaimSearch && claimSearchUris.length === 0;
|
const shouldPerformSearch = !fetchingClaimSearch && claimSearchUris.length === 0;
|
||||||
|
|
||||||
const uris = (prefixUris || []).concat(claimSearchUris);
|
const uris = (prefixUris || []).concat(claimSearchUris);
|
||||||
if (prefixUris && prefixUris.length) uris.splice(prefixUris.length * -1, prefixUris.length);
|
if (prefixUris && prefixUris.length) uris.splice(prefixUris.length * -1, prefixUris.length);
|
||||||
|
|
||||||
if (pinUrls && uris && uris.length > 2 && window.location.pathname === '/') {
|
if (window.location.pathname === '/') {
|
||||||
pinUrls.forEach((pin) => {
|
injectPinUrls(uris, pins, resolvedPinUris);
|
||||||
if (uris.indexOf(pin) !== -1) {
|
|
||||||
uris.splice(uris.indexOf(pin), 1);
|
|
||||||
} else {
|
|
||||||
uris.pop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
uris.splice(2, 0, ...pinUrls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uris.length > 0 && uris.length < pageSize && shouldPerformSearch) {
|
if (uris.length > 0 && uris.length < pageSize && shouldPerformSearch) {
|
||||||
|
@ -117,11 +118,31 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function injectPinUrls(uris, pins, resolvedPinUris) {
|
||||||
|
if (!pins || !uris || uris.length <= 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedPinUris) {
|
||||||
|
resolvedPinUris.forEach((pin) => {
|
||||||
|
if (uris.includes(pin)) {
|
||||||
|
uris.splice(uris.indexOf(pin), 1);
|
||||||
|
} else {
|
||||||
|
uris.pop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
uris.splice(2, 0, ...resolvedPinUris);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
useFetchViewCount(fetchViewCount, uris, claimsByUri, doFetchViewCount);
|
useFetchViewCount(fetchViewCount, uris, claimsByUri, doFetchViewCount);
|
||||||
|
|
||||||
useGetUserMemberships(true, uris, claimsByUri, doFetchUserMemberships);
|
useGetUserMemberships(true, uris, claimsByUri, doFetchUserMemberships);
|
||||||
|
|
||||||
// Run `doClaimSearch`
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (shouldPerformSearch) {
|
if (shouldPerformSearch) {
|
||||||
const searchOptions = JSON.parse(optionsStringified);
|
const searchOptions = JSON.parse(optionsStringified);
|
||||||
|
@ -129,6 +150,9 @@ function ClaimTilesDiscover(props: Props) {
|
||||||
}
|
}
|
||||||
}, [doClaimSearch, shouldPerformSearch, optionsStringified]);
|
}, [doClaimSearch, shouldPerformSearch, optionsStringified]);
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul ref={listRef} className="claim-grid">
|
<ul ref={listRef} className="claim-grid">
|
||||||
{finalUris && finalUris.length
|
{finalUris && finalUris.length
|
||||||
|
|
|
@ -174,7 +174,9 @@ function SideNavigation(props: Props) {
|
||||||
|
|
||||||
const isLargeScreen = useIsLargeScreen();
|
const isLargeScreen = useIsLargeScreen();
|
||||||
|
|
||||||
const EXTRA_SIDEBAR_LINKS = GetLinksData(homepageData, isLargeScreen).map(({ pinnedUrls, ...theRest }) => theRest);
|
const EXTRA_SIDEBAR_LINKS = GetLinksData(homepageData, isLargeScreen).map(
|
||||||
|
({ pinnedUrls, pinnedClaimIds, ...theRest }) => theRest
|
||||||
|
);
|
||||||
|
|
||||||
const MOBILE_LINKS: Array<SideNavLink> = [
|
const MOBILE_LINKS: Array<SideNavLink> = [
|
||||||
{
|
{
|
||||||
|
|
51
ui/effects/use-resolve-pins.js
Normal file
51
ui/effects/use-resolve-pins.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import useFetched from 'effects/use-fetched';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
pins?: { urls?: Array<string>, claimIds?: Array<string>, onlyPinForOrder?: string },
|
||||||
|
claimsById: { [string]: Claim },
|
||||||
|
doResolveClaimIds: (Array<string>) => Promise<any>,
|
||||||
|
doResolveUris: (Array<string>, boolean) => Promise<any>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useResolvePins(props: Props) {
|
||||||
|
const { pins, claimsById, doResolveClaimIds, doResolveUris } = props;
|
||||||
|
|
||||||
|
const [resolvedPinUris, setResolvedPinUris] = React.useState(pins ? undefined : null);
|
||||||
|
const [resolvingPinUris, setResolvingPinUris] = React.useState(false);
|
||||||
|
const hasResolvedPinUris = useFetched(resolvingPinUris);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (resolvedPinUris === undefined && pins && !resolvingPinUris) {
|
||||||
|
if (pins.urls) {
|
||||||
|
doResolveUris(pins.urls, true).finally(() => setResolvedPinUris(pins.urls));
|
||||||
|
} else if (pins.claimIds) {
|
||||||
|
// setResolvingPinUris is only needed for claim_search.
|
||||||
|
// doResolveUris uses selectResolvingUris internally to prevent double call.
|
||||||
|
setResolvingPinUris(true);
|
||||||
|
|
||||||
|
// We can't use .then() here to grab the `claim_search` uris directly,
|
||||||
|
// because we skip those that are already resolved. Instead, we mark a
|
||||||
|
// flag here, then populate the array in the other effect below in the
|
||||||
|
// next render cycle (redux would be updated by then). Pretty dumb.
|
||||||
|
// $FlowFixMe: already checked for null `pins`, but flow can't see it when there's code above it? Wow.
|
||||||
|
doResolveClaimIds(pins.claimIds).finally(() => setResolvingPinUris(false));
|
||||||
|
} else {
|
||||||
|
setResolvedPinUris(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [resolvedPinUris, pins, doResolveUris, doResolveClaimIds, resolvingPinUris]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (hasResolvedPinUris) {
|
||||||
|
if (pins && pins.claimIds) {
|
||||||
|
setResolvedPinUris(pins.claimIds.map<string>((id) => claimsById[id]?.canonical_url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only do this over a false->true->false transition for hasResolvedPinUris.
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [hasResolvedPinUris]);
|
||||||
|
|
||||||
|
return resolvedPinUris;
|
||||||
|
}
|
|
@ -128,9 +128,10 @@ function DiscoverPage(props: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPins(routeProps) {
|
function getPins(routeProps) {
|
||||||
if (routeProps && routeProps.pinnedUrls) {
|
if (routeProps && (routeProps.pinnedUrls || routeProps.pinnedClaimIds)) {
|
||||||
return {
|
return {
|
||||||
urls: routeProps.pinnedUrls,
|
urls: routeProps.pinnedUrls,
|
||||||
|
claimIds: routeProps.pinnedClaimIds,
|
||||||
onlyPinForOrder: CS.ORDER_BY_TRENDING,
|
onlyPinForOrder: CS.ORDER_BY_TRENDING,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ function HomePage(props: Props) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function getRowElements(id, title, route, link, icon, help, options, index, pinUrls) {
|
function getRowElements(id, title, route, link, icon, help, options, index, pinUrls, pinnedClaimIds) {
|
||||||
const tilePlaceholder = (
|
const tilePlaceholder = (
|
||||||
<ul className="claim-grid">
|
<ul className="claim-grid">
|
||||||
{new Array(options.pageSize || 8).fill(1).map((x, i) => (
|
{new Array(options.pageSize || 8).fill(1).map((x, i) => (
|
||||||
|
@ -161,7 +161,7 @@ function HomePage(props: Props) {
|
||||||
showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS}
|
showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS}
|
||||||
hasSource
|
hasSource
|
||||||
prefixUris={getLivestreamUris(activeLivestreams, options.channelIds)}
|
prefixUris={getLivestreamUris(activeLivestreams, options.channelIds)}
|
||||||
pinUrls={pinUrls}
|
pins={{ urls: pinUrls, claimIds: pinnedClaimIds }}
|
||||||
injectedItem={
|
injectedItem={
|
||||||
index === 0 && {
|
index === 0 && {
|
||||||
node: <Ads small type="video" tileLayout />,
|
node: <Ads small type="video" tileLayout />,
|
||||||
|
@ -249,9 +249,11 @@ function HomePage(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sortedRowData.map(({ id, title, route, link, icon, help, pinnedUrls: pinUrls, options = {} }, index) => {
|
{sortedRowData.map(
|
||||||
return getRowElements(id, title, route, link, icon, help, options, index, pinUrls);
|
({ id, title, route, link, icon, help, pinnedUrls: pinUrls, pinnedClaimIds, options = {} }, index) => {
|
||||||
})}
|
return getRowElements(id, title, route, link, icon, help, options, index, pinUrls, pinnedClaimIds);
|
||||||
|
}
|
||||||
|
)}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ export type HomepageCat = {
|
||||||
order?: string,
|
order?: string,
|
||||||
tags?: Array<string>,
|
tags?: Array<string>,
|
||||||
pinnedUrls?: Array<string>,
|
pinnedUrls?: Array<string>,
|
||||||
|
pinnedClaimIds?: Array<string>, // pinnedUrls takes precedence
|
||||||
mixIn?: Array<string>,
|
mixIn?: Array<string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,6 +90,7 @@ export const getHomepageRowForCat = (key: string, cat: HomepageCat) => {
|
||||||
icon: cat.icon || '', // some default
|
icon: cat.icon || '', // some default
|
||||||
title: cat.label,
|
title: cat.label,
|
||||||
pinnedUrls: cat.pinnedUrls,
|
pinnedUrls: cat.pinnedUrls,
|
||||||
|
pinnedClaimIds: cat.pinnedClaimIds,
|
||||||
options: {
|
options: {
|
||||||
claimType: cat.claimType || ['stream', 'repost'],
|
claimType: cat.claimType || ['stream', 'repost'],
|
||||||
channelIds: cat.channelIds,
|
channelIds: cat.channelIds,
|
||||||
|
|
Loading…
Add table
Reference in a new issue