132 lines
4.1 KiB
TypeScript

import type { FC } from '../../../lib/teact/teact';
import React, { memo, useRef } from '../../../lib/teact/teact';
import type { ApiMessage } from '../../../api/types';
import type { ISettings } from '../../../types';
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
import { requestMutation } from '../../../lib/fasterdom/fasterdom';
import { getMessageInvoice, getWebDocumentHash } from '../../../global/helpers';
import buildStyle from '../../../util/buildStyle';
import { formatCurrency } from '../../../util/formatCurrency';
import renderText from '../../common/helpers/renderText';
import getCustomAppendixBg from './helpers/getCustomAppendixBg';
import useLayoutEffectWithPrevDeps from '../../../hooks/useLayoutEffectWithPrevDeps';
import useMedia from '../../../hooks/useMedia';
import useOldLang from '../../../hooks/useOldLang';
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
import Skeleton from '../../ui/placeholder/Skeleton';
import './Invoice.scss';
type OwnProps = {
message: ApiMessage;
shouldAffectAppendix?: boolean;
isInSelectMode?: boolean;
isSelected?: boolean;
theme: ISettings['theme'];
forcedWidth?: number;
};
const Invoice: FC<OwnProps> = ({
message,
shouldAffectAppendix,
isInSelectMode,
isSelected,
theme,
forcedWidth,
}) => {
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null);
const lang = useOldLang();
const invoice = getMessageInvoice(message);
const {
title,
text,
amount,
currency,
isTest,
photo,
} = invoice!;
const photoUrl = useMedia(getWebDocumentHash(photo));
const withBlurredBackground = Boolean(forcedWidth);
const blurredBackgroundRef = useBlurredMediaThumbRef(photoUrl, !withBlurredBackground);
const messageId = message.id;
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
if (!shouldAffectAppendix) {
if (prevShouldAffectAppendix) {
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
}
return;
}
if (photoUrl) {
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
getCustomAppendixBg(photoUrl, false, messageId, isSelected, theme).then((appendixBg) => {
requestMutation(() => {
contentEl.style.setProperty('--appendix-bg', appendixBg);
contentEl.setAttribute(CUSTOM_APPENDIX_ATTRIBUTE, '');
});
});
}
}, [shouldAffectAppendix, photoUrl, isInSelectMode, isSelected, theme, messageId]);
const width = forcedWidth || photo?.dimensions?.width;
const style = buildStyle(
photo?.dimensions && `width: ${width}px`,
photo?.dimensions && `aspect-ratio: ${photo.dimensions.width} / ${photo.dimensions.height}`,
Boolean(!photo?.dimensions && forcedWidth) && `width: ${forcedWidth}px`,
);
return (
<div
ref={ref}
className="Invoice"
>
{title && (
<p className="title">{renderText(title)}</p>
)}
{text && (
<div>{renderText(text, ['emoji', 'br'])}</div>
)}
<div className={`description ${photo ? 'has-image' : ''}`}>
{Boolean(photo) && (
<div className="invoice-image-container">
{withBlurredBackground && <canvas ref={blurredBackgroundRef} className="thumbnail blurred-bg" />}
{photoUrl && (
<img
className="invoice-image"
src={photoUrl}
alt=""
style={style}
crossOrigin="anonymous"
draggable={false}
/>
)}
{!photoUrl && photo && (
<Skeleton
width={width}
height={photo.dimensions?.height}
forceAspectRatio
/>
)}
</div>
)}
<p className="description-text">
{formatCurrency(amount, currency, lang.code, { iconClassName: 'invoice-currency-icon' })}
{isTest && <span className="test-invoice">{lang('PaymentTestInvoice')}</span>}
</p>
</div>
</div>
);
};
export default memo(Invoice);