Management: Fix layout in management boost list (#4645)

This commit is contained in:
Alexander Zinchuk 2024-06-12 18:11:18 +02:00
parent 1997008ba5
commit 86ddd5bf0b
4 changed files with 89 additions and 42 deletions

View File

@ -12,17 +12,13 @@
}
.badgeContainer {
--min-shift: calc(10% + var(--digits-count, 1) * 0.4ch);
--max-shift: calc(85% - var(--digits-count, 1) * 0.4ch);
--shift-x: calc(clamp(var(--min-shift), var(--percent), var(--max-shift)) - 50%);
display: flex;
justify-content: center;
position: absolute;
top: -1.5rem;
left: 0;
right: 0;
transform: translate(var(--shift-x), -20px);
transform: translate(calc(var(--shift-x) * 100% - 50%), -20px);
transition: transform 0.2s ease-in-out;
animation: slide-in 0.5s ease-in-out;
}
@ -33,7 +29,7 @@
}
to {
transform: translate(var(--shift-x), -20px);
transform: translate(calc(var(--shift-x) * 100% - 50%), -20px);
}
}
@ -75,7 +71,7 @@
.floating-badge-triangle {
display: inline-block;
position: absolute;
bottom: -5px;
bottom: -4px;
left: calc(var(--tail-position, 0.5) * 100%);
transform: translateX(-50%);
}

View File

@ -1,5 +1,7 @@
import type { FC } from '../../lib/teact/teact';
import React, { memo } from '../../lib/teact/teact';
import React, {
memo, useEffect, useRef, useState,
} from '../../lib/teact/teact';
import type { IconName } from '../../types/icons';
@ -7,6 +9,7 @@ import buildClassName from '../../util/buildClassName';
import buildStyle from '../../util/buildStyle';
import useLang from '../../hooks/useLang';
import useResizeObserver from '../../hooks/useResizeObserver';
import Icon from './Icon';
@ -21,8 +24,6 @@ type OwnProps = {
className?: string;
};
const PROGRESS_LOCK = 0.1;
const LimitPreview: FC<OwnProps> = ({
leftText,
rightText,
@ -32,15 +33,48 @@ const LimitPreview: FC<OwnProps> = ({
className,
}) => {
const lang = useLang();
// eslint-disable-next-line no-null/no-null
const floatingBadgeRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const parentContainerRef = useRef<HTMLDivElement>(null);
const [shiftX, setShiftX] = useState(0);
const [tailPosition, setTailPosition] = useState(0);
const updateBadgePosition = () => {
if (floatingBadgeRef.current && parentContainerRef.current && progress !== undefined) {
const badgeWidth = floatingBadgeRef.current.offsetWidth;
const parentWidth = parentContainerRef.current.offsetWidth;
const minShift = badgeWidth / 2;
const maxShift = parentWidth - badgeWidth / 2;
const currentShift = progress * parentWidth;
const safeShift = Math.max(minShift, Math.min(currentShift, maxShift));
setShiftX(safeShift / parentWidth);
let newTailPosition;
if (currentShift < minShift) {
newTailPosition = (progress * parentWidth) / (minShift * 2);
} else if (currentShift > maxShift) {
const progressMapped = (progress - (maxShift / parentWidth)) / (1 - maxShift / parentWidth);
newTailPosition = 0.5 + (progressMapped * 0.4);
} else {
newTailPosition = 0.5;
}
setTailPosition(newTailPosition);
}
};
useEffect(updateBadgePosition, [progress]);
useResizeObserver(parentContainerRef, updateBadgePosition);
const hasFloatingBadge = Boolean(floatingBadgeIcon || floatingBadgeText);
const isProgressFull = Boolean(progress) && progress > 0.99;
const digitsCount = floatingBadgeText?.length;
const tailPosition = progress && (progress < PROGRESS_LOCK ? 0 : progress > 1 - PROGRESS_LOCK ? 1 : 0.5);
return (
<div
ref={parentContainerRef}
className={buildClassName(
styles.root,
hasFloatingBadge && styles.withBadge,
@ -49,13 +83,13 @@ const LimitPreview: FC<OwnProps> = ({
style={buildStyle(
progress !== undefined && `--progress: ${progress}`,
tailPosition !== undefined && `--tail-position: ${tailPosition}`,
digitsCount !== undefined && `--digits-count: ${digitsCount}`,
`--shift-x: ${shiftX}`,
)}
>
{hasFloatingBadge && (
<div className={styles.badgeContainer}>
<div className={styles.floatingBadgeWrapper}>
<div className={styles.floatingBadge}>
<div className={styles.floatingBadge} ref={floatingBadgeRef}>
{floatingBadgeIcon && <Icon name={floatingBadgeIcon} className={styles.floatingBadgeIcon} />}
{floatingBadgeText && (
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>

View File

@ -44,7 +44,7 @@
.status {
display: flex;
align-items: center;
gap: 1rem;
gap: 0.5rem;
justify-content: space-between;
width: 100%;
}
@ -111,3 +111,8 @@
.giveawayButton {
margin-bottom: 0.5rem;
}
.giveawayIcon {
width: 2.75rem;
height: 2.75rem;
}

View File

@ -177,7 +177,7 @@ const BoostStatistics = ({
>
<Icon name="gift" className={styles.floatingBadgeIcon} />
<div className={styles.floatingBadgeValue}>{lang(boost.isFromGiveaway
? 'lng_prizes_results_link' : 'BoostingGift')}
? 'BoostingGiveaway' : 'BoostingGift')}
</div>
</div>
</div>
@ -218,11 +218,13 @@ const BoostStatistics = ({
);
});
const handleGiveawayClick = useLastCallback(() => {
const handleGiveawayClick = useLastCallback((e) => {
e.preventDefault();
openGiveawayModal({ chatId });
});
const handleLoadMore = useLastCallback(() => {
const handleLoadMore = useLastCallback((e) => {
e.preventDefault();
loadMoreBoosters({ isGifts: tabType === 'giftedBoostList' });
});
@ -243,7 +245,7 @@ const BoostStatistics = ({
}
return (
<div className={styles.content}>
<div className={styles.section}>
{listToRender?.map((boost) => renderBoostList(boost))}
</div>
);
@ -278,7 +280,11 @@ const BoostStatistics = ({
>
<div className={buildClassName(styles.status, 'status-clickable')}>
<div>
<img src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]} alt="Giveaway" />
<img
src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]}
className={styles.giveawayIcon}
alt={lang('Giveaway')}
/>
</div>
<div className={styles.info}>
<h3>
@ -303,13 +309,12 @@ const BoostStatistics = ({
<p className="text-muted hint" key="links-hint">{lang('BoostingSelectPaidGiveaway')}</p>
</div>
)}
<div className={styles.section}>
<div>
{shouldDisplayGiftList ? (
<div
className={styles.boostSection}
className={buildClassName(styles.boostSection, styles.content)}
>
<Transition
key={activeKey}
ref={transitionRef}
name={lang.isRtl ? 'slideOptimizedRtl' : 'slideOptimized'}
activeKey={activeKey}
@ -322,7 +327,7 @@ const BoostStatistics = ({
<TabList big activeTab={renderingActiveTab} tabs={tabs} onSwitchTab={setActiveTab} />
</div>
) : (
<>
<div className={styles.section}>
<h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}>
{lang('BoostingBoostsCount', boostStatistics?.boosts?.count)}
</h4>
@ -331,28 +336,35 @@ const BoostStatistics = ({
</div>
)}
{boostStatistics?.boosts?.list?.map((boost) => renderBoostList(boost))}
</>
)}
{Boolean(boostersToLoadCount) && (
<ListItem
key="load-more"
className={styles.showMore}
disabled={boostStatistics?.isLoadingBoosters}
onClick={handleLoadMore}
>
{boostStatistics?.isLoadingBoosters ? (
<Spinner className={styles.loadMoreSpinner} />
) : (
<Icon name="down" className={styles.down} />
)}
{lang('ShowVotes', boostersToLoadCount, 'i')}
</ListItem>
</div>
)}
<div className={styles.section}>
{Boolean(boostersToLoadCount) && (
<ListItem
key="load-more"
className={styles.showMore}
disabled={boostStatistics?.isLoadingBoosters}
onClick={handleLoadMore}
>
{boostStatistics?.isLoadingBoosters ? (
<Spinner className={styles.loadMoreSpinner} />
) : (
<Icon name="down" className={styles.down} />
)}
{lang('ShowVotes', boostersToLoadCount, 'i')}
</ListItem>
)}
</div>
</div>
<LinkField className={styles.section} link={status!.boostUrl} withShare title={lang('LinkForBoosting')} />
{isGiveawayAvailable && (
<div className={styles.section}>
<ListItem icon="gift" ripple onClick={handleGiveawayClick} className={styles.giveawayButton}>
<ListItem
key="load-more"
icon="gift"
onClick={handleGiveawayClick}
className={styles.giveawayButton}
>
{lang('BoostingGetBoostsViaGifts')}
</ListItem>
<p className="text-muted hint" key="links-hint">{lang(