viewcontent fix

This commit is contained in:
root 2025-10-20 15:32:32 +00:00
parent 3b31c4e6cb
commit 61b50df864
1 changed files with 92 additions and 44 deletions

View File

@ -52,9 +52,22 @@ export const ViewContentPage = () => {
}
}, [statusState]);
const haveLicense = useMemo(() => (
content?.data?.have_licenses?.includes('listen') ||
content?.data?.have_licenses?.includes('resale')
), [content]);
const contentMime = content?.data?.content_mime ?? null;
const contentKind = content?.data?.display_options?.content_kind ?? null;
const mediaUrl = content?.data?.display_options?.content_url ?? null;
const isAudio = Boolean(content?.data?.content_type?.startsWith('audio'));
const isReady = Boolean(mediaUrl);
const isAudio = contentKind === 'audio' || Boolean(content?.data?.content_type?.startsWith('audio'));
const isVideo = contentKind === 'video' || Boolean(content?.data?.content_type?.startsWith('video'));
const isBinary = contentKind === 'binary' || (!isAudio && !isVideo);
const hasInlinePlayer = Boolean(mediaUrl) && (isAudio || isVideo);
const binaryDownloadReady = Boolean(mediaUrl) && isBinary;
const isReadyState = statusState === "ready";
const previewAvailable = Boolean(content?.data?.display_options?.has_preview);
const coverImage = content?.data?.display_options?.metadata?.image ?? null;
const metadataName = content?.data?.display_options?.metadata?.name;
const contentTitle = metadataName || content?.data?.encrypted?.title || 'Контент';
const processingDetails = useMemo(() => {
@ -67,6 +80,10 @@ export const ViewContentPage = () => {
};
}, [conversionState, statusMessage, uploadState]);
const canDownload = Boolean(mediaUrl) && haveLicense && ((content?.data?.downloadable ?? false) || isBinary);
const binaryAwaitingAccess = isBinary && !binaryDownloadReady;
const isFailed = statusState === "failed";
const handleBuyContentTON = useCallback(async () => {
if (!contentId) {
console.error('No content identifier available for purchase');
@ -185,11 +202,6 @@ export const ViewContentPage = () => {
}
}, [content, refetchContent]);
const haveLicense = useMemo(() => (
content?.data?.have_licenses?.includes('listen') ||
content?.data?.have_licenses?.includes('resale')
), [content]);
const hadLicenseRef = useRef<boolean>(haveLicense);
useEffect(() => {
@ -230,11 +242,15 @@ export const ViewContentPage = () => {
const handleDwnldContent = async () => {
try {
const fileUrl = content?.data?.display_options?.content_url;
if (!fileUrl) {
return;
}
const fileName = content?.data?.display_options?.metadata?.name || 'content';
const fileFormat = content?.data?.content_ext || '.raw';
const rawExt = content?.data?.content_ext ?? 'bin';
const normalizedExt = rawExt.replace(/^\.+/, '');
await WebApp.downloadFile({
url: fileUrl,
file_name: fileName + '.' + fileFormat,
file_name: `${fileName}.${normalizedExt}`,
});
} catch (error) {
console.error('Error downloading content:', error);
@ -242,23 +258,28 @@ export const ViewContentPage = () => {
};
return (
<main className={'min-h-screen flex w-full flex-col gap-[50px] px-4 '}>
<main className={'min-h-screen flex w-full flex-col gap-[40px] px-4 '}>
{isCongratsModal && <CongratsModal onConfirm={handleConfirmCongrats} />}
{isErrorModal && <ErrorModal onConfirm={handleErrorModal} />}
{isReady && isAudio &&
content?.data?.display_options?.metadata?.image && (
<div className={'mt-[30px] h-[314px] w-full'}>
{coverImage && (
<div className="mt-[30px] flex w-full justify-center">
<div className="relative aspect-square w-full max-w-[320px] rounded-3xl border border-slate-900/60 bg-transparent">
<div className="absolute inset-0 flex items-center justify-center overflow-hidden">
<img
alt={'content_image'}
className={'h-full w-full object-cover object-center'}
src={content?.data?.display_options?.metadata?.image}
alt={'content cover'}
className={'max-h-full max-w-full object-contain'}
src={coverImage}
loading="lazy"
/>
</div>
</div>
</div>
)}
{isReady ? (
{isReadyState ? (
<>
{isAudio ? (
{hasInlinePlayer && (
isAudio ? (
<AudioPlayer src={mediaUrl ?? ''} />
) : (
<ReactPlayer
@ -274,8 +295,19 @@ export const ViewContentPage = () => {
},
},
}}
url={mediaUrl}
url={mediaUrl ?? ''}
light={coverImage || undefined}
/>
)
)}
{binaryDownloadReady && (
<div className="rounded-2xl border border-slate-800 bg-slate-950/70 px-6 py-5 shadow-inner shadow-black/20">
<h2 className="text-base font-semibold text-slate-100">Файл готов к скачиванию</h2>
<p className="mt-2 text-sm text-slate-300">
{contentMime ? `Тип файла: ${contentMime}` : 'Скачайте оригинальные данные на устройство.'}
</p>
</div>
)}
<section className={'flex flex-col'}>
@ -285,26 +317,40 @@ export const ViewContentPage = () => {
</p>
</section>
{binaryAwaitingAccess && (
<div className="rounded-2xl border border-slate-800 bg-slate-950/70 px-6 py-5 text-sm text-slate-300">
<h2 className="text-base font-semibold text-slate-100">Предпросмотр недоступен</h2>
<p className="mt-2">
Этот файл нельзя открыть в браузере. Получите доступ, чтобы скачать оригинал на устройство.
</p>
{!previewAvailable && (
<p className="mt-2 text-xs text-slate-500">
Предпросмотр не формируется для бинарных данных.
</p>
)}
</div>
)}
<div className="mt-auto pb-2">
{content?.data?.downloadable && (
{canDownload && (
<Button
onClick={() => handleDwnldContent()}
className={'h-[48px] mb-4'}
label={`Скачать контент`}
label={`Скачать ${isBinary ? 'файл' : 'контент'}`}
/>
)}
{!haveLicense && (
<div className="flex flex-row gap-4">
<div className="flex gap-4 pb-2">
<Button
onClick={handleBuyContentTON}
className={'mb-4 h-[48px] px-2'}
className={'mb-4 h-[48px] px-2 flex-1 min-w-[140px] w-auto'}
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
includeArrows={content?.data?.invoice ? false : true}
/>
{content?.data?.invoice && (
<Button
onClick={handleBuyContentStars}
className={'mb-4 h-[48px] px-2'}
className={'mb-4 h-[48px] px-2 flex-1 min-w-[140px] w-auto'}
label={`Купить за ${content?.data?.invoice?.amount} ⭐️`}
/>
)}
@ -332,10 +378,12 @@ export const ViewContentPage = () => {
<div className="flex flex-1 flex-col items-center justify-center py-16">
<div className="max-w-md rounded-2xl border border-slate-800 bg-slate-950/70 px-6 py-8 text-center shadow-lg shadow-black/30">
<h1 className="text-lg font-semibold text-slate-100">
Контент скоро будет здесь
{isFailed ? 'Не удалось подготовить контент' : 'Контент скоро будет здесь'}
</h1>
<p className="mt-3 text-sm text-slate-300">
Мы уже обрабатываем загруженный файл и обновим страницу автоматически, как только появится доступ к полному контенту.
{isFailed
? 'При обработке файла произошла ошибка. Попробуйте обновить страницу или повторно загрузить контент.'
: 'Мы уже обрабатываем загруженный файл и обновим страницу автоматически, как только появится доступ к полному контенту.'}
</p>
{statusMessage && (
<p className="mt-4 text-[12px] text-slate-500">