Premium modal: Various fixes (#4045)
This commit is contained in:
parent
3ef2fa7680
commit
76629db59f
@ -1,6 +1,6 @@
|
|||||||
import type { FC } from '../../../lib/teact/teact';
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
import React, {
|
import React, {
|
||||||
memo, useCallback, useEffect, useRef, useState,
|
memo, useCallback, useEffect, useMemo, useRef, useState,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import type { ApiPremiumPromo } from '../../../api/types';
|
import type { ApiPremiumPromo } from '../../../api/types';
|
||||||
@ -127,21 +127,23 @@ const LIMITS_DESCRIPTIONS: Record<ApiLimitTypeWithoutUpload, string> = {
|
|||||||
const BORDER_THRESHOLD = 20;
|
const BORDER_THRESHOLD = 20;
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
onBack: VoidFunction;
|
|
||||||
initialSection: string;
|
initialSection: string;
|
||||||
promo: ApiPremiumPromo;
|
promo: ApiPremiumPromo;
|
||||||
onClickSubscribe: (startParam?: string) => void;
|
|
||||||
isPremium?: boolean;
|
isPremium?: boolean;
|
||||||
limits?: NonNullable<GlobalState['appConfig']>['limits'];
|
limits?: NonNullable<GlobalState['appConfig']>['limits'];
|
||||||
|
premiumPromoOrder?: string[];
|
||||||
|
onBack: VoidFunction;
|
||||||
|
onClickSubscribe: (startParam?: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PremiumFeatureModal: FC<OwnProps> = ({
|
const PremiumFeatureModal: FC<OwnProps> = ({
|
||||||
promo,
|
promo,
|
||||||
initialSection,
|
initialSection,
|
||||||
onBack,
|
|
||||||
onClickSubscribe,
|
|
||||||
isPremium,
|
isPremium,
|
||||||
limits,
|
limits,
|
||||||
|
premiumPromoOrder,
|
||||||
|
onBack,
|
||||||
|
onClickSubscribe,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
@ -155,6 +157,11 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const prevInitialSection = usePrevious(initialSection);
|
const prevInitialSection = usePrevious(initialSection);
|
||||||
|
|
||||||
|
const filteredSections = useMemo(() => {
|
||||||
|
if (!premiumPromoOrder) return PREMIUM_FEATURE_SECTIONS;
|
||||||
|
return premiumPromoOrder.filter((section) => PREMIUM_FEATURE_SECTIONS.includes(section));
|
||||||
|
}, [premiumPromoOrder]);
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
onClickSubscribe(initialSection);
|
onClickSubscribe(initialSection);
|
||||||
}
|
}
|
||||||
@ -192,12 +199,12 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
|||||||
const scrollContainer = scrollContainerRef.current;
|
const scrollContainer = scrollContainerRef.current;
|
||||||
if (!scrollContainer || (prevInitialSection === initialSection)) return;
|
if (!scrollContainer || (prevInitialSection === initialSection)) return;
|
||||||
|
|
||||||
const index = PREMIUM_FEATURE_SECTIONS.indexOf(initialSection);
|
const index = filteredSections.indexOf(initialSection);
|
||||||
setCurrentSlideIndex(index);
|
setCurrentSlideIndex(index);
|
||||||
startScrolling();
|
startScrolling();
|
||||||
animateHorizontalScroll(scrollContainer, scrollContainer.clientWidth * index, 0)
|
animateHorizontalScroll(scrollContainer, scrollContainer.clientWidth * index, 0)
|
||||||
.then(stopScrolling);
|
.then(stopScrolling);
|
||||||
}, [currentSlideIndex, initialSection, prevInitialSection, startScrolling, stopScrolling]);
|
}, [currentSlideIndex, filteredSections, initialSection, prevInitialSection]);
|
||||||
|
|
||||||
const handleSelectSlide = useCallback(async (index: number) => {
|
const handleSelectSlide = useCallback(async (index: number) => {
|
||||||
const scrollContainer = scrollContainerRef.current;
|
const scrollContainer = scrollContainerRef.current;
|
||||||
@ -208,7 +215,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
|||||||
startScrolling();
|
startScrolling();
|
||||||
await animateHorizontalScroll(scrollContainer, scrollContainer.clientWidth * index, 800);
|
await animateHorizontalScroll(scrollContainer, scrollContainer.clientWidth * index, 800);
|
||||||
stopScrolling();
|
stopScrolling();
|
||||||
}, [startScrolling, stopScrolling]);
|
}, []);
|
||||||
|
|
||||||
// TODO Support all subscription options
|
// TODO Support all subscription options
|
||||||
const month = promo.options.find((option) => option.months === 1)!;
|
const month = promo.options.find((option) => option.months === 1)!;
|
||||||
@ -230,7 +237,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
|||||||
|
|
||||||
<div className={buildClassName(styles.content, 'no-scrollbar')} onScroll={handleScroll} ref={scrollContainerRef}>
|
<div className={buildClassName(styles.content, 'no-scrollbar')} onScroll={handleScroll} ref={scrollContainerRef}>
|
||||||
|
|
||||||
{PREMIUM_FEATURE_SECTIONS.map((section, index) => {
|
{filteredSections.map((section, index) => {
|
||||||
if (section === 'double_limits') {
|
if (section === 'double_limits') {
|
||||||
return (
|
return (
|
||||||
<div className={buildClassName(styles.slide, styles.limits)}>
|
<div className={buildClassName(styles.slide, styles.limits)}>
|
||||||
|
|||||||
@ -372,6 +372,7 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
onClickSubscribe={handleClickWithStartParam}
|
onClickSubscribe={handleClickWithStartParam}
|
||||||
isPremium={isPremium}
|
isPremium={isPremium}
|
||||||
limits={limits}
|
limits={limits}
|
||||||
|
premiumPromoOrder={premiumPromoOrder}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { FC } from '../../../../lib/teact/teact';
|
import type { FC } from '../../../../lib/teact/teact';
|
||||||
import React, {
|
import React, {
|
||||||
memo, useCallback, useEffect, useRef, useState,
|
memo, useEffect, useRef, useState,
|
||||||
} from '../../../../lib/teact/teact';
|
} from '../../../../lib/teact/teact';
|
||||||
import { withGlobal } from '../../../../global';
|
import { withGlobal } from '../../../../global';
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ import type { GlobalState } from '../../../../global/types';
|
|||||||
import cycleRestrict from '../../../../util/cycleRestrict';
|
import cycleRestrict from '../../../../util/cycleRestrict';
|
||||||
|
|
||||||
import useFlag from '../../../../hooks/useFlag';
|
import useFlag from '../../../../hooks/useFlag';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
import useMedia from '../../../../hooks/useMedia';
|
import useMedia from '../../../../hooks/useMedia';
|
||||||
|
|
||||||
import AnimatedSticker from '../../../common/AnimatedSticker';
|
import AnimatedSticker from '../../../common/AnimatedSticker';
|
||||||
@ -36,7 +37,7 @@ const AnimatedCircleSticker: FC<{
|
|||||||
index: number;
|
index: number;
|
||||||
maxLength: number;
|
maxLength: number;
|
||||||
onClick: (index: number) => void;
|
onClick: (index: number) => void;
|
||||||
onEnded: NoneToVoidFunction;
|
onEnded: (index: number) => void;
|
||||||
canPlay: boolean;
|
canPlay: boolean;
|
||||||
}> = ({
|
}> = ({
|
||||||
size, realIndex, canPlay,
|
size, realIndex, canPlay,
|
||||||
@ -60,14 +61,14 @@ const AnimatedCircleSticker: FC<{
|
|||||||
const x = Math.cos(angle) * width - circleSize * 2.8;
|
const x = Math.cos(angle) * width - circleSize * 2.8;
|
||||||
const y = Math.sin(angle) * height;
|
const y = Math.sin(angle) * height;
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useLastCallback(() => {
|
||||||
onClick(realIndex);
|
onClick(realIndex);
|
||||||
}, [onClick, realIndex]);
|
});
|
||||||
|
|
||||||
const handleEnded = useCallback(() => {
|
const handleEnded = useLastCallback(() => {
|
||||||
inanimate();
|
inanimate();
|
||||||
onEnded();
|
onEnded(realIndex);
|
||||||
}, [inanimate, onEnded]);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isActivated) {
|
if (isActivated) {
|
||||||
@ -112,15 +113,20 @@ const PremiumFeaturePreviewStickers: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const renderedStickers = stickers?.slice(0, MAX_EMOJIS);
|
const renderedStickers = stickers?.slice(0, MAX_EMOJIS);
|
||||||
|
|
||||||
const handleClick = useCallback((i: number) => {
|
const handleClick = useLastCallback((i: number) => {
|
||||||
setOffset(-i);
|
setOffset(-i);
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
|
const handleEnded = useLastCallback((i: number) => {
|
||||||
|
const displayIndex = cycleRestrict(renderedStickers.length, i + offset);
|
||||||
|
if (displayIndex !== 0) return;
|
||||||
|
|
||||||
const handleEnded = useCallback(() => {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setOffset((current) => cycleRestrict(renderedStickers.length, current + 1));
|
setOffset((current) => {
|
||||||
|
return cycleRestrict(renderedStickers.length, current + 1);
|
||||||
|
});
|
||||||
}, ENDED_DELAY);
|
}, ENDED_DELAY);
|
||||||
}, [renderedStickers.length]);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = containerRef.current;
|
const container = containerRef.current;
|
||||||
@ -134,11 +140,11 @@ const PremiumFeaturePreviewStickers: FC<OwnProps & StateProps> = ({
|
|||||||
className={styles.root}
|
className={styles.root}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
>
|
>
|
||||||
{Boolean(size) && renderedStickers?.map((l, i) => {
|
{Boolean(size) && renderedStickers?.map((sticker, i) => {
|
||||||
return (
|
return (
|
||||||
<AnimatedCircleSticker
|
<AnimatedCircleSticker
|
||||||
size={size}
|
size={size}
|
||||||
sticker={l}
|
sticker={sticker}
|
||||||
realIndex={i}
|
realIndex={i}
|
||||||
index={(i + offset + renderedStickers.length) % renderedStickers.length}
|
index={(i + offset + renderedStickers.length) % renderedStickers.length}
|
||||||
maxLength={renderedStickers.length}
|
maxLength={renderedStickers.length}
|
||||||
|
|||||||
@ -30,10 +30,11 @@
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
border-top: 0.0625rem solid transparent;
|
border-top: 0.0625rem solid transparent;
|
||||||
transition: 0.2s ease-in-out border-color;
|
transition: 0.2s ease-in-out border-color;
|
||||||
|
margin-inline: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile {
|
.mobile {
|
||||||
padding: 1rem 1rem 1rem 2rem;
|
padding: 1rem 0rem 1rem 1rem;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,15 +88,17 @@ const MediaAreaSuggestedReaction = ({
|
|||||||
<div
|
<div
|
||||||
className={buildClassName(styles.background, isFlipped && styles.flipped)}
|
className={buildClassName(styles.background, isFlipped && styles.flipped)}
|
||||||
/>
|
/>
|
||||||
<ReactionAnimatedEmoji
|
{Boolean(customEmojiSize) && (
|
||||||
className={buildClassName(styles.reaction, shouldDisplayCount && styles.withCount)}
|
<ReactionAnimatedEmoji
|
||||||
reaction={reaction}
|
className={buildClassName(styles.reaction, shouldDisplayCount && styles.withCount)}
|
||||||
containerId={containerId}
|
reaction={reaction}
|
||||||
size={customEmojiSize}
|
containerId={containerId}
|
||||||
effectSize={customEmojiSize * EFFECT_SIZE_MULTIPLIER}
|
size={customEmojiSize}
|
||||||
shouldPause={isPreview}
|
effectSize={customEmojiSize * EFFECT_SIZE_MULTIPLIER}
|
||||||
shouldLoop={!isPreview}
|
shouldPause={isPreview}
|
||||||
/>
|
shouldLoop={!isPreview}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{shouldDisplayCount && (
|
{shouldDisplayCount && (
|
||||||
<span className={styles.reactionCount}>{reactionCount}</span>
|
<span className={styles.reactionCount}>{reactionCount}</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user