TelegramPWA/src/components/main/premium/StarsGiftModal.tsx

228 lines
6.3 KiB
TypeScript

import type { FC } from '../../../lib/teact/teact';
import React, {
memo, useEffect, useMemo, useRef,
useState,
} from '../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../global';
import type {
ApiStarTopupOption, ApiUser,
} from '../../../api/types';
import { getSenderTitle } from '../../../global/helpers';
import {
selectTabState, selectUser,
} from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { formatCurrencyAsString } from '../../../util/formatCurrency';
import renderText from '../../common/helpers/renderText';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';
import Avatar from '../../common/Avatar';
import SafeLink from '../../common/SafeLink';
import StarTopupOptionList from '../../modals/stars/StarTopupOptionList';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
import styles from './StarsGiftModal.module.scss';
import StarLogo from '../../../assets/icons/StarLogo.svg';
import StarsBackground from '../../../assets/stars-bg.png';
export type OwnProps = {
isOpen?: boolean;
};
type StateProps = {
isCompleted?: boolean;
starsGiftOptions?: ApiStarTopupOption[] | undefined;
forUserId?: string;
user?: ApiUser;
};
const StarsGiftModal: FC<OwnProps & StateProps> = ({
isOpen,
isCompleted,
starsGiftOptions,
forUserId,
user,
}) => {
// eslint-disable-next-line no-null/no-null
const dialogRef = useRef<HTMLDivElement>(null);
const {
closeStarsGiftModal, openInvoice, requestConfetti,
} = getActions();
const oldLang = useOldLang();
const [selectedOption, setSelectedOption] = useState<ApiStarTopupOption | undefined>();
const [isHeaderHidden, setHeaderHidden] = useState(true);
useEffect(() => {
if (!isOpen) {
setHeaderHidden(true);
}
}, [isOpen]);
const showConfetti = useLastCallback(() => {
const dialog = dialogRef.current;
if (!dialog) return;
if (isOpen) {
const {
top, left, width, height,
} = dialog.querySelector('.modal-content')!.getBoundingClientRect();
requestConfetti({
top,
left,
width,
height,
withStars: true,
});
}
});
useEffect(() => {
if (isCompleted) {
showConfetti();
}
}, [isCompleted, showConfetti]);
const handleClick = useLastCallback((option: ApiStarTopupOption) => {
setSelectedOption(option);
if (user) {
openInvoice({
type: 'starsgift',
userId: forUserId!,
stars: option.stars,
currency: option.currency,
amount: option.amount,
});
} else {
openInvoice({
type: 'stars',
stars: option.stars,
currency: option.currency,
amount: option.amount,
});
}
});
function handleScroll(e: React.UIEvent<HTMLDivElement>) {
const { scrollTop } = e.currentTarget;
setHeaderHidden(scrollTop <= 150);
}
const handleClose = useLastCallback(() => {
closeStarsGiftModal();
});
function renderGiftTitle() {
if (isCompleted) {
return user ? renderText(oldLang('Notification.StarsGift.SentYou',
formatCurrencyAsString(selectedOption!.amount, selectedOption!.currency, oldLang.code)), ['simple_markdown'])
: renderText(oldLang('StarsAcquiredInfo', selectedOption?.stars), ['simple_markdown']);
}
return user ? oldLang('GiftStarsTitle') : oldLang('Star.List.GetStars');
}
function renderStarOptionList() {
return (
<StarTopupOptionList
options={starsGiftOptions}
onClick={handleClick}
/>
);
}
const bottomText = useMemo(() => {
if (!isOpen) return undefined;
const text = oldLang('lng_credits_summary_options_about');
const parts = text.split('{link}');
return [
parts[0],
<SafeLink url={oldLang('StarsTOSLink')} text={oldLang('lng_credits_summary_options_about_link')} />,
parts[1],
];
}, [isOpen, oldLang]);
return (
<Modal
className={buildClassName(styles.modalDialog, styles.root)}
dialogRef={dialogRef}
onClose={handleClose}
isOpen={isOpen}
>
<div className={styles.main} onScroll={handleScroll}>
<Button
round
size="smaller"
className={styles.closeButton}
color="translucent"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => closeStarsGiftModal()}
ariaLabel={oldLang('Close')}
>
<i className="icon icon-close" />
</Button>
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
<h2 className={styles.starHeaderText}>
{user ? oldLang('GiftStarsTitle') : oldLang('Star.List.GetStars')}
</h2>
</div>
<div className={styles.headerInfo}>
{user ? (
<>
<Avatar
size="huge"
peer={user}
className={styles.avatar}
/>
<img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
</>
) : (
<>
<img className={styles.logo} src={StarLogo} alt="" draggable={false} />
<img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
</>
)}
</div>
<h2 className={buildClassName(styles.headerText, styles.center)}>
{renderGiftTitle()}
</h2>
<p className={styles.description}>
{user ? renderText(
oldLang('ActionGiftStarsSubtitle', getSenderTitle(oldLang, user)), ['simple_markdown'],
) : oldLang('Stars.Purchase.GetStarsInfo')}
</p>
<div className={styles.section}>
{renderStarOptionList()}
<div className={styles.secondaryInfo}>
{bottomText}
</div>
</div>
</div>
</Modal>
);
};
export default memo(withGlobal<OwnProps>((global): StateProps => {
const {
starsGiftOptions, forUserId, isCompleted,
} = selectTabState(global).starsGiftModal || {};
const user = forUserId ? selectUser(getGlobal(), forUserId) : undefined;
return {
isCompleted,
starsGiftOptions,
forUserId,
user,
};
})(StarsGiftModal));