Refactor some components/callbacks

This commit is contained in:
Lim Chee Aun 2023-10-27 14:15:03 +08:00
parent c022e2fd00
commit 6dd6e0e77c
2 changed files with 315 additions and 310 deletions

View file

@ -347,151 +347,15 @@ function Timeline({
{!!items.length ? (
<>
<ul class="timeline">
{items.map((status) => {
const { id: statusID, reblog, items, type, _pinned } = status;
const actualStatusID = reblog?.id || statusID;
const url = instance
? `/${instance}/s/${actualStatusID}`
: `/s/${actualStatusID}`;
let title = '';
if (type === 'boosts') {
title = `${items.length} Boosts`;
} else if (type === 'pinned') {
title = 'Pinned posts';
}
const isCarousel = type === 'boosts' || type === 'pinned';
if (items) {
if (isCarousel) {
// Here, we don't hide filtered posts, but we sort them last
items.sort((a, b) => {
if (a._filtered && !b._filtered) {
return 1;
}
if (!a._filtered && b._filtered) {
return -1;
}
return 0;
});
return (
<li
key={`timeline-${statusID}`}
class="timeline-item-carousel"
>
<StatusCarousel
title={title}
class={`${type}-carousel`}
>
{items.map((item) => {
const { id: statusID, reblog } = item;
const actualStatusID = reblog?.id || statusID;
const url = instance
? `/${instance}/s/${actualStatusID}`
: `/s/${actualStatusID}`;
return (
<li key={statusID}>
<Link
class="status-carousel-link timeline-item-alt"
to={url}
>
{useItemID ? (
<Status
statusID={statusID}
instance={instance}
size="s"
contentTextWeight
allowFilters={allowFilters}
/>
) : (
<Status
status={item}
instance={instance}
size="s"
contentTextWeight
allowFilters={allowFilters}
/>
)}
</Link>
</li>
);
})}
</StatusCarousel>
</li>
);
}
const manyItems = items.length > 3;
return items.map((item, i) => {
const { id: statusID, _differentAuthor } = item;
const url = instance
? `/${instance}/s/${statusID}`
: `/s/${statusID}`;
const isMiddle = i > 0 && i < items.length - 1;
const isSpoiler = item.sensitive && !!item.spoilerText;
const showCompact =
(!_differentAuthor && isSpoiler && i > 0) ||
(manyItems &&
isMiddle &&
(type === 'thread' ||
(type === 'conversation' &&
!_differentAuthor &&
!items[i - 1]._differentAuthor &&
!items[i + 1]._differentAuthor)));
return (
<li
key={`timeline-${statusID}`}
class={`timeline-item-container timeline-item-container-type-${type} timeline-item-container-${
i === 0
? 'start'
: i === items.length - 1
? 'end'
: 'middle'
} ${
_differentAuthor ? 'timeline-item-diff-author' : ''
}`}
>
<Link class="status-link timeline-item" to={url}>
{showCompact ? (
<TimelineStatusCompact
status={item}
instance={instance}
/>
) : useItemID ? (
<Status
statusID={statusID}
instance={instance}
allowFilters={allowFilters}
/>
) : (
<Status
status={item}
instance={instance}
allowFilters={allowFilters}
/>
)}
</Link>
</li>
);
});
}
return (
<li key={`timeline-${statusID + _pinned}`}>
<Link class="status-link timeline-item" to={url}>
{useItemID ? (
<Status
statusID={statusID}
instance={instance}
allowFilters={allowFilters}
/>
) : (
<Status
status={status}
instance={instance}
allowFilters={allowFilters}
/>
)}
</Link>
</li>
);
})}
{items.map((status) => (
<TimelineItem
status={status}
instance={instance}
useItemID={useItemID}
allowFilters={allowFilters}
key={status.id + status?._pinned}
/>
))}
{showMore && uiState === 'loading' && (
<>
<li
@ -562,6 +426,132 @@ function Timeline({
);
}
function TimelineItem({ status, instance, useItemID, allowFilters }) {
const { id: statusID, reblog, items, type, _pinned } = status;
const actualStatusID = reblog?.id || statusID;
const url = instance
? `/${instance}/s/${actualStatusID}`
: `/s/${actualStatusID}`;
let title = '';
if (type === 'boosts') {
title = `${items.length} Boosts`;
} else if (type === 'pinned') {
title = 'Pinned posts';
}
const isCarousel = type === 'boosts' || type === 'pinned';
if (items) {
if (isCarousel) {
// Here, we don't hide filtered posts, but we sort them last
items.sort((a, b) => {
if (a._filtered && !b._filtered) {
return 1;
}
if (!a._filtered && b._filtered) {
return -1;
}
return 0;
});
return (
<li key={`timeline-${statusID}`} class="timeline-item-carousel">
<StatusCarousel title={title} class={`${type}-carousel`}>
{items.map((item) => {
const { id: statusID, reblog } = item;
const actualStatusID = reblog?.id || statusID;
const url = instance
? `/${instance}/s/${actualStatusID}`
: `/s/${actualStatusID}`;
return (
<li key={statusID}>
<Link class="status-carousel-link timeline-item-alt" to={url}>
{useItemID ? (
<Status
statusID={statusID}
instance={instance}
size="s"
contentTextWeight
allowFilters={allowFilters}
/>
) : (
<Status
status={item}
instance={instance}
size="s"
contentTextWeight
allowFilters={allowFilters}
/>
)}
</Link>
</li>
);
})}
</StatusCarousel>
</li>
);
}
const manyItems = items.length > 3;
return items.map((item, i) => {
const { id: statusID, _differentAuthor } = item;
const url = instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`;
const isMiddle = i > 0 && i < items.length - 1;
const isSpoiler = item.sensitive && !!item.spoilerText;
const showCompact =
(!_differentAuthor && isSpoiler && i > 0) ||
(manyItems &&
isMiddle &&
(type === 'thread' ||
(type === 'conversation' &&
!_differentAuthor &&
!items[i - 1]._differentAuthor &&
!items[i + 1]._differentAuthor)));
return (
<li
key={`timeline-${statusID}`}
class={`timeline-item-container timeline-item-container-type-${type} timeline-item-container-${
i === 0 ? 'start' : i === items.length - 1 ? 'end' : 'middle'
} ${_differentAuthor ? 'timeline-item-diff-author' : ''}`}
>
<Link class="status-link timeline-item" to={url}>
{showCompact ? (
<TimelineStatusCompact status={item} instance={instance} />
) : useItemID ? (
<Status
statusID={statusID}
instance={instance}
allowFilters={allowFilters}
/>
) : (
<Status
status={item}
instance={instance}
allowFilters={allowFilters}
/>
)}
</Link>
</li>
);
});
}
return (
<li key={`timeline-${statusID + _pinned}`}>
<Link class="status-link timeline-item" to={url}>
{useItemID ? (
<Status
statusID={statusID}
instance={instance}
allowFilters={allowFilters}
/>
) : (
<Status
status={status}
instance={instance}
allowFilters={allowFilters}
/>
)}
</Link>
</li>
);
}
function StatusCarousel({ title, class: className, children }) {
const carouselRef = useRef();
const { reachStart, reachEnd, init } = useScroll({

View file

@ -657,139 +657,142 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
resetScrollPosition(status.id);
}, []);
const renderStatus = (status) => {
const {
id: statusID,
ancestor,
isThread,
descendant,
thread,
replies,
repliesCount,
weight,
} = status;
const isHero = statusID === id;
// const StatusParent = useCallback(
// (props) =>
// isThread || thread || ancestor ? (
// <Link
// class="status-link"
// to={
// instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`
// }
// onClick={() => {
// resetScrollPosition(statusID);
// }}
// {...props}
// />
// ) : (
// <div class="status-focus" tabIndex={0} {...props} />
// ),
// [isThread, thread],
// );
return (
<li
key={statusID}
ref={isHero ? heroStatusRef : null}
class={`${ancestor ? 'ancestor' : ''} ${
descendant ? 'descendant' : ''
} ${thread ? 'thread' : ''} ${isHero ? 'hero' : ''}`}
>
{isHero ? (
<>
<InView
threshold={0.1}
onChange={onView}
class="status-focus"
tabIndex={0}
const renderStatus = useCallback(
(status) => {
const {
id: statusID,
ancestor,
isThread,
descendant,
thread,
replies,
repliesCount,
weight,
} = status;
const isHero = statusID === id;
// const StatusParent = useCallback(
// (props) =>
// isThread || thread || ancestor ? (
// <Link
// class="status-link"
// to={
// instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`
// }
// onClick={() => {
// resetScrollPosition(statusID);
// }}
// {...props}
// />
// ) : (
// <div class="status-focus" tabIndex={0} {...props} />
// ),
// [isThread, thread],
// );
return (
<li
key={statusID}
ref={isHero ? heroStatusRef : null}
class={`${ancestor ? 'ancestor' : ''} ${
descendant ? 'descendant' : ''
} ${thread ? 'thread' : ''} ${isHero ? 'hero' : ''}`}
>
{isHero ? (
<>
<InView
threshold={0.1}
onChange={onView}
class="status-focus"
tabIndex={0}
>
<Status
statusID={statusID}
instance={instance}
withinContext
size="l"
enableTranslate
forceTranslate={translate}
/>
</InView>
{uiState !== 'loading' && !authenticated ? (
<div class="post-status-banner">
<p>
You're not logged in. Interactions (reply, boost, etc) are
not possible.
</p>
<Link to="/login" class="button">
Log in
</Link>
</div>
) : (
!sameInstance && (
<div class="post-status-banner">
<p>
This post is from another instance (<b>{instance}</b>).
Interactions (reply, boost, etc) are not possible.
</p>
<button
type="button"
disabled={uiState === 'loading'}
onClick={() => {
setUIState('loading');
(async () => {
try {
const results = await currentMasto.v2.search.fetch({
q: heroStatus.url,
type: 'statuses',
resolve: true,
limit: 1,
});
if (results.statuses.length) {
const status = results.statuses[0];
location.hash = currentInstance
? `/${currentInstance}/s/${status.id}`
: `/s/${status.id}`;
} else {
throw new Error('No results');
}
} catch (e) {
setUIState('default');
alert('Error: ' + e);
console.error(e);
}
})();
}}
>
<Icon icon="transfer" /> Switch to my instance to enable
interactions
</button>
</div>
)
)}
</>
) : (
// <StatusParent>
<Link
class="status-link"
to={instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`}
onClick={() => {
resetScrollPosition(statusID);
}}
>
<Status
statusID={statusID}
instance={instance}
withinContext
size="l"
size={thread || ancestor ? 'm' : 's'}
enableTranslate
forceTranslate={translate}
onMediaClick={handleMediaClick}
onStatusLinkClick={handleStatusLinkClick}
/>
</InView>
{uiState !== 'loading' && !authenticated ? (
<div class="post-status-banner">
<p>
You're not logged in. Interactions (reply, boost, etc) are not
possible.
</p>
<Link to="/login" class="button">
Log in
</Link>
</div>
) : (
!sameInstance && (
<div class="post-status-banner">
<p>
This post is from another instance (<b>{instance}</b>).
Interactions (reply, boost, etc) are not possible.
</p>
<button
type="button"
disabled={uiState === 'loading'}
onClick={() => {
setUIState('loading');
(async () => {
try {
const results = await currentMasto.v2.search.fetch({
q: heroStatus.url,
type: 'statuses',
resolve: true,
limit: 1,
});
if (results.statuses.length) {
const status = results.statuses[0];
location.hash = currentInstance
? `/${currentInstance}/s/${status.id}`
: `/s/${status.id}`;
} else {
throw new Error('No results');
}
} catch (e) {
setUIState('default');
alert('Error: ' + e);
console.error(e);
}
})();
}}
>
<Icon icon="transfer" /> Switch to my instance to enable
interactions
</button>
{ancestor && isThread && repliesCount > 1 && (
<div class="replies-link">
<Icon icon="comment" />{' '}
<span title={repliesCount}>
{shortenNumber(repliesCount)}
</span>
</div>
)
)}
</>
) : (
// <StatusParent>
<Link
class="status-link"
to={instance ? `/${instance}/s/${statusID}` : `/s/${statusID}`}
onClick={() => {
resetScrollPosition(statusID);
}}
>
<Status
statusID={statusID}
instance={instance}
withinContext
size={thread || ancestor ? 'm' : 's'}
enableTranslate
onMediaClick={handleMediaClick}
onStatusLinkClick={handleStatusLinkClick}
/>
{ancestor && isThread && repliesCount > 1 && (
<div class="replies-link">
<Icon icon="comment" />{' '}
<span title={repliesCount}>{shortenNumber(repliesCount)}</span>
</div>
)}{' '}
{/* {replies?.length > LIMIT && (
)}{' '}
{/* {replies?.length > LIMIT && (
<div class="replies-link">
<Icon icon="comment" />{' '}
<span title={replies.length}>
@ -797,48 +800,60 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
</span>
</div>
)} */}
{/* </StatusParent> */}
</Link>
)}
{descendant && replies?.length > 0 && (
<SubComments
instance={instance}
replies={replies}
hasParentThread={thread}
level={1}
accWeight={weight}
openAll={totalDescendants.current < SUBCOMMENTS_OPEN_ALL_LIMIT}
/>
)}
{uiState === 'loading' &&
isHero &&
!!heroStatus?.repliesCount &&
!hasDescendants && (
<div class="status-loading">
<Loader />
</div>
{/* </StatusParent> */}
</Link>
)}
{uiState === 'error' &&
isHero &&
!!heroStatus?.repliesCount &&
!hasDescendants && (
<div class="status-error">
Unable to load replies.
<br />
<button
type="button"
class="plain"
onClick={() => {
states.reloadStatusPage++;
}}
>
Try again
</button>
</div>
{descendant && replies?.length > 0 && (
<SubComments
instance={instance}
replies={replies}
hasParentThread={thread}
level={1}
accWeight={weight}
openAll={totalDescendants.current < SUBCOMMENTS_OPEN_ALL_LIMIT}
/>
)}
</li>
);
};
{uiState === 'loading' &&
isHero &&
!!heroStatus?.repliesCount &&
!hasDescendants && (
<div class="status-loading">
<Loader />
</div>
)}
{uiState === 'error' &&
isHero &&
!!heroStatus?.repliesCount &&
!hasDescendants && (
<div class="status-error">
Unable to load replies.
<br />
<button
type="button"
class="plain"
onClick={() => {
states.reloadStatusPage++;
}}
>
Try again
</button>
</div>
)}
</li>
);
},
[
id,
instance,
uiState,
authenticated,
sameInstance,
translate,
handleMediaClick,
handleStatusLinkClick,
hasDescendants,
],
);
return (
<div