import { memo, useEffect, useMemo, useState } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiStarsRating, ApiUser } from '../../../api/types'; import type { TabState } from '../../../global/types'; import { getPeerTitle } from '../../../global/helpers/peers'; import { selectUser, selectUserFullInfo } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import { formatShortDuration } from '../../../util/dates/oldDateFormat'; import { getNextArrowReplacement } from '../../../util/localization/format'; import { getServerTime } from '../../../util/serverTime'; import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import PremiumProgress, { type AnimationDirection } from '../../common/PremiumProgress'; import Button from '../../ui/Button'; import Transition from '../../ui/Transition'; import TableAboutModal, { type TableAboutData } from '../common/TableAboutModal'; import styles from './ProfileRatingModal.module.scss'; export type OwnProps = { modal: TabState['profileRatingModal']; }; type StateProps = { user?: ApiUser; currentUserId?: string; starsRating?: ApiStarsRating; pendingRating?: ApiStarsRating; pendingRatingDate?: number; }; const ProfileRatingModal = ({ modal, user, currentUserId, starsRating, pendingRating, pendingRatingDate, }: OwnProps & StateProps) => { const { closeProfileRatingModal, } = getActions(); const lang = useLang(); const isOpen = Boolean(modal); const renderingUser = useCurrentOrPrev(user); const renderingStarsRating = useCurrentOrPrev(starsRating); const renderingPendingRating = useCurrentOrPrev(pendingRating); const renderingPendingRatingDate = useCurrentOrPrev(pendingRatingDate); const [showFutureRating, setShowFutureRating] = useState(false); const handleClose = useLastCallback(() => { closeProfileRatingModal(); }); useEffect(() => { if (!isOpen) { setShowFutureRating(false); } }, [isOpen]); const handleShowFuture = useLastCallback(() => { setShowFutureRating(true); }); const handleShowCurrent = useLastCallback(() => { setShowFutureRating(false); }); const renderBadge = (type: 'added' | 'deducted') => { const isAdded = type === 'added'; const badgeText = isAdded ? lang('RatingBadgeAdded') : lang('RatingBadgeDeducted'); const badgeClass = isAdded ? styles.badgeAdded : styles.badgeDeducted; return ( {badgeText} ); }; const header = useMemo(() => { if (!renderingUser || !renderingStarsRating) return undefined; const rating = showFutureRating && renderingPendingRating ? renderingPendingRating : renderingStarsRating; const currentStars = rating.stars; const currentLevelStars = rating.currentLevelStars; const nextLevelStars = rating.nextLevelStars; const currentLevel = rating.level; const nextLevel = currentLevel + 1; const isNegative = currentLevel < 0; const pendingLevel = !showFutureRating && renderingPendingRating ? renderingPendingRating.level : renderingStarsRating.level; let levelProgress = 0; if (!nextLevelStars) { levelProgress = 1; } else if (nextLevelStars > currentLevelStars) { levelProgress = Math.max(0.03, (currentStars - currentLevelStars) / (nextLevelStars - currentLevelStars)); } else { levelProgress = 1; } const progress = isNegative ? 0.5 : Math.max(0, Math.min(1, levelProgress)); const waitTime = renderingPendingRatingDate ? renderingPendingRatingDate - getServerTime() : 0; const pendingPoints = renderingPendingRating ? renderingPendingRating.stars - renderingStarsRating.stars : 0; const shouldShowPreview = renderingPendingRating && renderingPendingRatingDate; const renderPreviewDescription = () => { if (!shouldShowPreview) return undefined; return ( {showFutureRating ? (

{lang('DescriptionFutureRating', { time: formatShortDuration(lang, waitTime), points: Math.abs(pendingPoints), link: ( {lang('LinkDescriptionRatingBack', undefined, { withNodes: true, specialReplacement: getNextArrowReplacement() })} ), }, { pluralValue: Math.abs(pendingPoints), withNodes: true, })}

) : (

{lang('DescriptionPendingRating', { time: formatShortDuration(lang, waitTime), points: Math.abs(pendingPoints), link: ( {lang('LinkDescriptionRatingPreview', undefined, { withNodes: true, specialReplacement: getNextArrowReplacement() })} ), }, { pluralValue: Math.abs(pendingPoints), withNodes: true, })}

)}
); }; let animationDirection: AnimationDirection = 'none'; if (currentLevel >= 0 && pendingLevel >= 0 && currentLevel !== pendingLevel) { animationDirection = currentLevel > pendingLevel ? 'forward' : 'backward'; } if (currentLevel < 0 && pendingLevel < 0 && currentLevel !== pendingLevel) { animationDirection = currentLevel < pendingLevel ? 'backward' : 'forward'; } const userFallbackText = lang('ActionFallbackUser'); return (
= 0} isNegative={currentLevel < 0} animationDirection={animationDirection} className={buildClassName(styles.ratingProgress, shouldShowPreview && styles.withPreview)} /> {renderPreviewDescription()}
{lang('TitleRating')}

{renderingUser?.id === currentUserId ? lang('RatingYourReflectsActivity') : lang('RatingReflectsActivity', { name: getPeerTitle(lang, renderingUser) || userFallbackText }, { withMarkdown: true, withNodes: true })}

); }, [renderingUser, currentUserId, renderingStarsRating, renderingPendingRating, renderingPendingRatingDate, showFutureRating, lang, handleShowFuture, handleShowCurrent]); const listItemData = [ ['closed-gift', lang('RatingGiftsFromTelegram'), ( {renderBadge('added')} {lang('RatingGiftsFromTelegramDesc')} )], ['user-stars', lang('RatingGiftsAndPostsFromUsers'), ( {renderBadge('added')} {lang('RatingGiftsAndPostsFromUsersDesc')} )], ['stars-refund', lang('RatingRefundsAndConversions'), ( {renderBadge('deducted')} {lang('RatingRefundsAndConversionsDesc')} )], ] satisfies TableAboutData; const footer = useMemo(() => { return (
); }, [lang, handleClose]); return ( ); }; export default memo(withGlobal( (global, { modal }): Complete => { const currentUserId = global.currentUserId; const user = modal?.userId ? selectUser(global, modal.userId) : undefined; const userFullInfo = modal?.userId ? selectUserFullInfo(global, modal.userId) : undefined; const starsRating = userFullInfo?.starsRating; const pendingRating = userFullInfo?.starsMyPendingRating; const pendingRatingDate = userFullInfo?.starsMyPendingRatingDate; return { user, currentUserId, starsRating, pendingRating, pendingRatingDate, }; }, )(ProfileRatingModal));