Story: Display forwards count in channels (#4092)

This commit is contained in:
Alexander Zinchuk 2023-12-12 12:34:36 +01:00
parent b4291a1505
commit 2edd680802
6 changed files with 73 additions and 38 deletions

View File

@ -68,6 +68,7 @@ export function buildApiStory(peerId: string, story: GramJs.TypeStoryItem): ApiT
...(closeFriends && { isForCloseFriends: true }),
...(noforwards && { noForwards: true }),
...(views?.viewsCount && { viewsCount: views.viewsCount }),
...(views?.forwardsCount && { forwardsCount: views.forwardsCount }),
...(views?.reactionsCount && { reactionsCount: views.reactionsCount }),
...(views?.reactions && { reactions: views.reactions.map(buildReactionCount) }),
...(views?.recentViewers && {

View File

@ -19,6 +19,7 @@ export interface ApiStory {
isOut?: true;
noForwards?: boolean;
viewsCount?: number;
forwardsCount?: number;
reactionsCount?: number;
reactions?: ApiReactionCount[];
recentViewerIds?: string[];

View File

@ -53,10 +53,17 @@
font-size: 1.25rem;
}
.channelReaction {
.footerItem {
display: flex;
align-items: center;
padding-inline-end: 0.5rem;
&:last-child {
padding-inline-end: 0.5rem;
}
& + & {
margin-inline-end: 0.5rem;
}
}
.views {

View File

@ -32,7 +32,7 @@ const StoryFooter = ({
const lang = useLang();
const {
viewsCount, reactionsCount, isOut, peerId, id: storyId, sentReaction,
viewsCount, forwardsCount, reactionsCount, isOut, peerId, id: storyId, sentReaction,
} = story;
const isChannel = !isUserId(peerId);
@ -121,37 +121,54 @@ const StoryFooter = ({
round
onClick={handleForwardClick}
ariaLabel={lang('Forward')}
className={styles.footerItem}
>
<Icon name="forward" />
</Button>
)}
{isChannel && (
<div className={styles.channelReaction}>
<Button
round
className={styles.reactionButton}
color="translucent"
size="smaller"
onClick={handleLikeStory}
ariaLabel={lang('AccDescrLike')}
>
{sentReaction && (
<ReactionAnimatedEmoji
key={'documentId' in sentReaction ? sentReaction.documentId : sentReaction.emoticon}
containerId={containerId}
reaction={sentReaction}
withEffectOnly={isSentStoryReactionHeart}
/>
)}
{(!sentReaction || isSentStoryReactionHeart) && (
<Icon
name={isSentStoryReactionHeart ? 'heart' : 'heart-outline'}
className={buildClassName(isSentStoryReactionHeart && styles.reactionHeart)}
/>
)}
</Button>
{Boolean(reactionsCount) && (<span>{reactionsCount}</span>)}
</div>
<>
{Boolean(forwardsCount) && (
<div className={styles.footerItem}>
<Button
round
color="translucent"
size="smaller"
nonInteractive
ariaLabel={lang('PublicShares')}
>
<Icon name="loop" />
</Button>
<span>{forwardsCount}</span>
</div>
)}
<div className={styles.footerItem}>
<Button
round
className={styles.reactionButton}
color="translucent"
size="smaller"
onClick={handleLikeStory}
ariaLabel={lang('AccDescrLike')}
>
{sentReaction && (
<ReactionAnimatedEmoji
key={'documentId' in sentReaction ? sentReaction.documentId : sentReaction.emoticon}
containerId={containerId}
reaction={sentReaction}
withEffectOnly={isSentStoryReactionHeart}
/>
)}
{(!sentReaction || isSentStoryReactionHeart) && (
<Icon
name={isSentStoryReactionHeart ? 'heart' : 'heart-outline'}
className={buildClassName(isSentStoryReactionHeart && styles.reactionHeart)}
/>
)}
</Button>
{Boolean(reactionsCount) && (<span>{reactionsCount}</span>)}
</div>
</>
)}
</div>
);

View File

@ -55,8 +55,12 @@
}
&.disabled {
opacity: 0.5 !important;
cursor: var(--custom-cursor, default);
&:not(.non-interactive) {
opacity: 0.5 !important;
}
&:not(.click-allowed) {
pointer-events: none;
}

View File

@ -36,6 +36,7 @@ export type OwnProps = {
href?: string;
download?: string;
disabled?: boolean;
nonInteractive?: boolean;
allowDisabledClick?: boolean;
noFastClick?: boolean;
ripple?: boolean;
@ -91,6 +92,7 @@ const Button: FC<OwnProps> = ({
href,
download,
disabled,
nonInteractive,
allowDisabledClick,
noFastClick = color === 'danger',
ripple,
@ -110,6 +112,8 @@ const Button: FC<OwnProps> = ({
const [isClicked, setIsClicked] = useState(false);
const isNotInteractive = disabled || nonInteractive;
const fullClassName = buildClassName(
'Button',
className,
@ -118,7 +122,8 @@ const Button: FC<OwnProps> = ({
round && 'round',
pill && 'pill',
fluid && 'fluid',
disabled && 'disabled',
isNotInteractive && 'disabled',
nonInteractive && 'non-interactive',
allowDisabledClick && 'click-allowed',
isText && 'text',
isLoading && 'loading',
@ -132,7 +137,7 @@ const Button: FC<OwnProps> = ({
);
const handleClick = useLastCallback((e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
if ((allowDisabledClick || !disabled) && onClick) {
if ((allowDisabledClick || !isNotInteractive) && onClick) {
onClick(e);
}
@ -147,7 +152,7 @@ const Button: FC<OwnProps> = ({
const handleMouseDown = useLastCallback((e: ReactMouseEvent<HTMLButtonElement>) => {
if (!noPreventDefault) e.preventDefault();
if ((allowDisabledClick || !disabled) && onMouseDown) {
if ((allowDisabledClick || !isNotInteractive) && onMouseDown) {
onMouseDown(e);
}
@ -173,7 +178,7 @@ const Button: FC<OwnProps> = ({
onTransitionEnd={onTransitionEnd}
>
{children}
{!disabled && ripple && (
{!isNotInteractive && ripple && (
<RippleEffect />
)}
</a>
@ -190,10 +195,10 @@ const Button: FC<OwnProps> = ({
onContextMenu={onContextMenu}
onMouseDown={handleMouseDown}
onMouseUp={onMouseUp}
onMouseEnter={onMouseEnter && !disabled ? onMouseEnter : undefined}
onMouseLeave={onMouseLeave && !disabled ? onMouseLeave : undefined}
onMouseEnter={onMouseEnter && !isNotInteractive ? onMouseEnter : undefined}
onMouseLeave={onMouseLeave && !isNotInteractive ? onMouseLeave : undefined}
onTransitionEnd={onTransitionEnd}
onFocus={onFocus && !disabled ? onFocus : undefined}
onFocus={onFocus && !isNotInteractive ? onFocus : undefined}
aria-label={ariaLabel}
aria-controls={ariaControls}
aria-haspopup={hasPopup}
@ -208,7 +213,7 @@ const Button: FC<OwnProps> = ({
<Spinner color={isText ? 'blue' : 'white'} />
</div>
) : children}
{!disabled && ripple && (
{!isNotInteractive && ripple && (
<RippleEffect />
)}
</button>