PremiumMainModal: Render all subscription options (#4129)
This commit is contained in:
parent
d2b834d1a6
commit
3e96262038
@ -194,7 +194,7 @@ function buildApiPremiumSubscriptionOption(option: GramJs.PremiumSubscriptionOpt
|
|||||||
isCurrent: current,
|
isCurrent: current,
|
||||||
canPurchaseUpgrade,
|
canPurchaseUpgrade,
|
||||||
currency,
|
currency,
|
||||||
amount: amount.toString(),
|
amount: amount.toJSNumber(),
|
||||||
botUrl,
|
botUrl,
|
||||||
months,
|
months,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -75,7 +75,7 @@ export interface ApiPremiumSubscriptionOption {
|
|||||||
canPurchaseUpgrade?: boolean;
|
canPurchaseUpgrade?: boolean;
|
||||||
months: number;
|
months: number;
|
||||||
currency: string;
|
currency: string;
|
||||||
amount: string;
|
amount: number;
|
||||||
botUrl: string;
|
botUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import Avatar from '../../common/Avatar';
|
|||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
import Link from '../../ui/Link';
|
import Link from '../../ui/Link';
|
||||||
import Modal from '../../ui/Modal';
|
import Modal from '../../ui/Modal';
|
||||||
import GiftOption from './GiftOption';
|
import PremiumSubscriptionOption from './PremiumSubscriptionOption';
|
||||||
|
|
||||||
import styles from './GiftPremiumModal.module.scss';
|
import styles from './GiftPremiumModal.module.scss';
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ const GiftPremiumModal: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
<div className={styles.options}>
|
<div className={styles.options}>
|
||||||
{renderedGifts?.map((gift) => (
|
{renderedGifts?.map((gift) => (
|
||||||
<GiftOption
|
<PremiumSubscriptionOption
|
||||||
key={gift.amount}
|
key={gift.amount}
|
||||||
option={gift}
|
option={gift}
|
||||||
fullMonthlyAmount={fullMonthlyAmount}
|
fullMonthlyAmount={fullMonthlyAmount}
|
||||||
|
|||||||
@ -168,3 +168,11 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subscriptionOptions {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscriptionOption {
|
||||||
|
margin: 0.8125rem;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import React, {
|
|||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiPremiumPromo, ApiSticker, ApiStickerSet, ApiUser,
|
ApiPremiumPromo, ApiPremiumSubscriptionOption, ApiSticker, ApiStickerSet, ApiUser,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { GlobalState } from '../../../global/types';
|
import type { GlobalState } from '../../../global/types';
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ import PremiumFeatureModal, {
|
|||||||
PREMIUM_FEATURE_SECTIONS,
|
PREMIUM_FEATURE_SECTIONS,
|
||||||
PREMIUM_FEATURE_TITLES,
|
PREMIUM_FEATURE_TITLES,
|
||||||
} from './PremiumFeatureModal';
|
} from './PremiumFeatureModal';
|
||||||
|
import PremiumSubscriptionOption from './PremiumSubscriptionOption';
|
||||||
|
|
||||||
import styles from './PremiumMainModal.module.scss';
|
import styles from './PremiumMainModal.module.scss';
|
||||||
|
|
||||||
@ -133,6 +134,7 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
const [isHeaderHidden, setHeaderHidden] = useState(true);
|
const [isHeaderHidden, setHeaderHidden] = useState(true);
|
||||||
const [currentSection, setCurrentSection] = useState<string | undefined>(initialSection);
|
const [currentSection, setCurrentSection] = useState<string | undefined>(initialSection);
|
||||||
|
const [selectedSubscriptionOption, setSubscriptionOption] = useState<ApiPremiumSubscriptionOption>();
|
||||||
|
|
||||||
const handleOpen = useCallback((section: string | undefined) => {
|
const handleOpen = useCallback((section: string | undefined) => {
|
||||||
return () => {
|
return () => {
|
||||||
@ -146,7 +148,7 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
setHeaderHidden(scrollTop <= 150);
|
setHeaderHidden(scrollTop <= 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClickWithStartParam(startParam?: string) {
|
const handleClickWithStartParam = useLastCallback((startParam?: string) => {
|
||||||
const dialog = dialogRef.current;
|
const dialog = dialogRef.current;
|
||||||
if (!dialog) return;
|
if (!dialog) return;
|
||||||
|
|
||||||
@ -160,12 +162,21 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
closePremiumModal();
|
closePremiumModal();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const handleClick = useLastCallback(() => {
|
|
||||||
handleClickWithStartParam();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
if (selectedSubscriptionOption) {
|
||||||
|
handleClickWithStartParam(String(selectedSubscriptionOption.months));
|
||||||
|
} else {
|
||||||
|
handleClickWithStartParam();
|
||||||
|
}
|
||||||
|
}, [selectedSubscriptionOption, handleClickWithStartParam]);
|
||||||
|
|
||||||
|
const handleChangeSubscriptionOption = useCallback((months: number) => {
|
||||||
|
const foundOption = promo?.options.find((option) => option.months === months);
|
||||||
|
setSubscriptionOption(foundOption);
|
||||||
|
}, [promo]);
|
||||||
|
|
||||||
const showConfetti = useCallback(() => {
|
const showConfetti = useCallback(() => {
|
||||||
const dialog = dialogRef.current;
|
const dialog = dialogRef.current;
|
||||||
if (!dialog) return;
|
if (!dialog) return;
|
||||||
@ -206,6 +217,11 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
}, [loadStickers, fromUserStatusEmoji, fromUserStatusSet]);
|
}, [loadStickers, fromUserStatusEmoji, fromUserStatusSet]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const [defaultOption] = promo?.options ?? [];
|
||||||
|
setSubscriptionOption(defaultOption);
|
||||||
|
}, [promo]);
|
||||||
|
|
||||||
const handleOpenStatusSet = useLastCallback(() => {
|
const handleOpenStatusSet = useLastCallback(() => {
|
||||||
if (!fromUserStatusSet) return;
|
if (!fromUserStatusSet) return;
|
||||||
|
|
||||||
@ -231,10 +247,15 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
return [renderText(first), link, renderText(second)];
|
return [renderText(first), link, renderText(second)];
|
||||||
}, [fromUser, fromUserStatusSet, lang]);
|
}, [fromUser, fromUserStatusSet, lang]);
|
||||||
|
|
||||||
if (!promo || (fromUserStatusEmoji && !fromUserStatusSet)) return undefined;
|
const fullMonthlyAmount = useMemo(() => {
|
||||||
|
const monthOption = promo?.options.find((option) => option.months === 1);
|
||||||
|
if (!monthOption) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return Number(monthOption.amount);
|
||||||
|
}, [promo]);
|
||||||
|
|
||||||
// TODO Support all subscription options
|
if (!promo || (fromUserStatusEmoji && !fromUserStatusSet)) return undefined;
|
||||||
const month = promo.options.find((option) => option.months === 1)!;
|
|
||||||
|
|
||||||
function getHeaderText() {
|
function getHeaderText() {
|
||||||
if (isGift) {
|
if (isGift) {
|
||||||
@ -279,6 +300,24 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderSubscriptionOptions() {
|
||||||
|
return (
|
||||||
|
<div className={styles.subscriptionOptions}>
|
||||||
|
{promo?.options
|
||||||
|
.map((option) => (
|
||||||
|
<PremiumSubscriptionOption
|
||||||
|
className={styles.subscriptionOption}
|
||||||
|
key={option.amount}
|
||||||
|
option={option}
|
||||||
|
onChange={handleChangeSubscriptionOption}
|
||||||
|
fullMonthlyAmount={fullMonthlyAmount}
|
||||||
|
checked={selectedSubscriptionOption?.months === option.months}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className={styles.root}
|
className={styles.root}
|
||||||
@ -319,12 +358,12 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
<div className={styles.description}>
|
<div className={styles.description}>
|
||||||
{renderText(getHeaderDescription(), ['simple_markdown', 'emoji'])}
|
{renderText(getHeaderDescription(), ['simple_markdown', 'emoji'])}
|
||||||
</div>
|
</div>
|
||||||
|
{!isPremium && renderSubscriptionOptions()}
|
||||||
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
|
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
|
||||||
<h2 className={styles.premiumHeaderText}>
|
<h2 className={styles.premiumHeaderText}>
|
||||||
{lang('TelegramPremium')}
|
{lang('TelegramPremium')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={buildClassName(styles.list, isPremium && styles.noButton)}>
|
<div className={buildClassName(styles.list, isPremium && styles.noButton)}>
|
||||||
{filteredSections.map((section, index) => {
|
{filteredSections.map((section, index) => {
|
||||||
return (
|
return (
|
||||||
@ -355,10 +394,15 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
{renderFooterText()}
|
{renderFooterText()}
|
||||||
</div>
|
</div>
|
||||||
{!isPremium && (
|
{!isPremium && selectedSubscriptionOption && (
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
<Button className={styles.button} isShiny withPremiumGradient onClick={handleClick}>
|
<Button className={styles.button} isShiny withPremiumGradient onClick={handleClick}>
|
||||||
{lang('SubscribeToPremium', formatCurrency(Number(month.amount), month.currency, lang.code))}
|
{lang('SubscribeToPremium',
|
||||||
|
formatCurrency(
|
||||||
|
selectedSubscriptionOption.amount,
|
||||||
|
selectedSubscriptionOption.currency,
|
||||||
|
lang.code,
|
||||||
|
))}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,24 +2,27 @@ import type { ChangeEvent } from 'react';
|
|||||||
import type { FC } from '../../../lib/teact/teact';
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
import React, { memo, useCallback, useMemo } from '../../../lib/teact/teact';
|
import React, { memo, useCallback, useMemo } from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import type { ApiPremiumGiftOption } from '../../../api/types';
|
|
||||||
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { formatCurrency } from '../../../util/formatCurrency';
|
import { formatCurrency } from '../../../util/formatCurrency';
|
||||||
|
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
|
|
||||||
import styles from './GiftOption.module.scss';
|
import styles from './PremiumSubscriptionOption.module.scss';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
option: ApiPremiumGiftOption;
|
option: {
|
||||||
|
months: number;
|
||||||
|
currency: string;
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
checked?: boolean;
|
checked?: boolean;
|
||||||
fullMonthlyAmount?: number;
|
fullMonthlyAmount?: number;
|
||||||
|
className?: string;
|
||||||
onChange: (month: number) => void;
|
onChange: (month: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const GiftOption: FC<OwnProps> = ({
|
const PremiumSubscriptionOption: FC<OwnProps> = ({
|
||||||
option, checked, fullMonthlyAmount, onChange,
|
option, checked, fullMonthlyAmount, onChange, className,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
@ -39,7 +42,14 @@ const GiftOption: FC<OwnProps> = ({
|
|||||||
}, [months, onChange]);
|
}, [months, onChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label className={buildClassName(styles.wrapper, checked && styles.active)} dir={lang.isRtl ? 'rtl' : undefined}>
|
<label
|
||||||
|
className={buildClassName(
|
||||||
|
styles.wrapper,
|
||||||
|
checked && styles.active,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
dir={lang.isRtl ? 'rtl' : undefined}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className={styles.input}
|
className={styles.input}
|
||||||
type="radio"
|
type="radio"
|
||||||
@ -62,4 +72,4 @@ const GiftOption: FC<OwnProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(GiftOption);
|
export default memo(PremiumSubscriptionOption);
|
||||||
@ -407,7 +407,7 @@ addActionHandler('openGiftPremiumModal', async (global, actions, payload): Promi
|
|||||||
isOpen: true,
|
isOpen: true,
|
||||||
forUserId,
|
forUserId,
|
||||||
monthlyCurrency: month.currency,
|
monthlyCurrency: month.currency,
|
||||||
monthlyAmount: month.amount,
|
monthlyAmount: String(month.amount),
|
||||||
},
|
},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user