Files
popa-launcher/src/renderer/components/BonusShopItem.tsx
2025-12-14 21:14:59 +05:00

310 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/renderer/components/BonusShopItem.tsx
import React from 'react';
import {
Card,
CardContent,
Box,
Typography,
Button,
CardMedia,
Divider,
} from '@mui/material';
import CoinsDisplay from './CoinsDisplay';
export interface BonusShopItemProps {
id: string;
name: string;
description?: string;
level: number;
effectValue: number;
nextEffectValue?: number;
// цена покупки и улучшения
price?: number;
upgradePrice: number;
canUpgrade: boolean;
mode?: 'buy' | 'upgrade';
isActive?: boolean;
isPermanent?: boolean;
imageUrl?: string;
disabled?: boolean;
onBuy?: () => void;
onUpgrade?: () => void;
onToggleActive?: () => void;
}
export const BonusShopItem: React.FC<BonusShopItemProps> = ({
name,
description,
level,
effectValue,
nextEffectValue,
price,
upgradePrice,
canUpgrade,
mode,
isActive = true,
isPermanent = false,
imageUrl,
disabled,
onBuy,
onUpgrade,
onToggleActive,
}) => {
const isBuyMode = mode === 'buy' || level === 0;
const buttonText = isBuyMode
? 'Купить'
: canUpgrade
? 'Улучшить'
: 'Макс. уровень';
const displayedPrice = isBuyMode ? (price ?? upgradePrice) : upgradePrice;
const buttonDisabled =
disabled ||
(isBuyMode
? !onBuy || displayedPrice === undefined
: !canUpgrade || !onUpgrade);
const handlePrimaryClick = () => {
if (buttonDisabled) return;
if (isBuyMode && onBuy) onBuy();
else if (!isBuyMode && onUpgrade) onUpgrade();
};
return (
<Card
sx={{
position: 'relative',
width: '100%',
maxWidth: 220,
height: 440,
display: 'flex',
flexDirection: 'column',
background: 'rgba(20,20,20,0.9)',
borderRadius: '2.5vw',
border: '1px solid rgba(255,255,255,0.08)',
boxShadow: '0 10px 40px rgba(0,0,0,0.8)',
overflow: 'hidden',
transition: 'transform 0.35s ease, box-shadow 0.35s ease',
'&:hover': {
transform: 'scale(1.01)',
boxShadow: '0 10px 20px rgba(242,113,33,0.1)',
},
}}
>
{/* Градиентный свет сверху — как в ShopItem */}
<Box
sx={{
position: 'absolute',
inset: 0,
pointerEvents: 'none',
background:
'radial-gradient(circle at top, rgba(242,113,33,0.25), transparent 60%)',
}}
/>
{imageUrl && (
<Box sx={{ position: 'relative', p: 1.5, pb: 0 }}>
<Box
sx={{
borderRadius: '1.8vw',
overflow: 'hidden',
border: '1px solid rgba(255,255,255,0.12)',
background:
'linear-gradient(135deg, rgba(40,40,40,0.9), rgba(15,15,15,0.9))',
}}
>
<CardMedia
component="img"
image={imageUrl}
alt={name}
sx={{
width: '100%',
height: 160,
objectFit: 'cover',
}}
/>
</Box>
</Box>
)}
<CardContent
sx={{
flexGrow: 1,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
pt: 2,
pb: 2,
}}
>
<Box>
{/* Имя бонуса — градиентом как у ShopItem */}
<Typography
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '1rem',
mb: 0.5,
backgroundImage:
'linear-gradient(136deg, rgb(242,113,33), rgb(233,64,87), rgb(138,35,135))',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
{name}
</Typography>
<Typography
sx={{
color: 'rgba(255,255,255,0.7)',
fontSize: '0.7rem',
mb: 0.8,
}}
>
Уровень: {level}
{isPermanent && ' • Постоянный'}
</Typography>
{description && (
<Typography
sx={{
color: 'rgba(255,255,255,0.75)',
fontSize: '0.7rem',
mb: 1.2,
minHeight: 40,
}}
>
{description}
</Typography>
)}
<Box sx={{ mb: 1 }}>
<Typography
sx={{ color: 'rgba(255,255,255,0.8)', fontSize: '0.8rem' }}
>
Текущий эффект:{' '}
<Box component="b" sx={{ fontWeight: 600 }}>
{effectValue.toLocaleString('ru-RU')}
</Box>
</Typography>
{typeof nextEffectValue === 'number' &&
!isBuyMode &&
canUpgrade && (
<Typography
sx={{
color: 'rgba(255,255,255,0.8)',
fontSize: '0.8rem',
mt: 0.4,
}}
>
Следующий уровень:{' '}
<Box component="b" sx={{ fontWeight: 600 }}>
{nextEffectValue.toLocaleString('ru-RU')}
</Box>
</Typography>
)}
</Box>
<Typography
sx={{
fontSize: '0.78rem',
mb: 1,
color: isActive
? 'rgba(0, 200, 140, 0.9)'
: 'rgba(255, 180, 80, 0.9)',
}}
>
{isActive ? 'Бонус активен' : 'Бонус не активен'}
</Typography>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 1,
}}
>
<Typography
sx={{ color: 'rgba(255,255,255,0.8)', fontSize: '0.85rem' }}
>
{isBuyMode ? 'Цена покупки' : 'Цена улучшения'}
</Typography>
{displayedPrice !== undefined && (
<CoinsDisplay
value={displayedPrice}
size="small"
autoUpdate={false}
showTooltip={true}
/>
)}
</Box>
<Divider sx={{background: 'rgba(160, 160, 160, 0.3)', borderRadius: '2vw'}}/>
{!isBuyMode && onToggleActive && (
<Typography
onClick={onToggleActive}
sx={{
mt: '1vw',
fontFamily: 'Benzin-Bold',
fontSize: '1vw',
textTransform: 'uppercase',
letterSpacing: '0.08em',
cursor: 'pointer',
backgroundImage:
'linear-gradient(71deg, #F27121 0%, #E940CD 60%, #8A2387 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
textShadow: '0 0 15px rgba(0,0,0,0.9)',
'&:hover': {
opacity: 1,
},
}}
>
{isActive ? 'Выключить' : 'Включить'}
</Typography>
)}
</Box>
{/* Кнопка в стиле Registration / ShopItem */}
<Button
variant="contained"
fullWidth
disabled={buttonDisabled}
onClick={handlePrimaryClick}
sx={{
mt: 2,
transition: 'transform 0.3s ease, opacity 0.2s ease',
background: buttonDisabled
? 'linear-gradient(71deg, #555 0%, #666 70%, #444 100%)'
: 'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
fontFamily: 'Benzin-Bold',
borderRadius: '2.5vw',
fontSize: '0.85rem',
color: '#fff',
opacity: buttonDisabled ? 0.6 : 1,
'&:hover': {
transform: buttonDisabled ? 'none' : 'scale(1.05)',
},
}}
>
{buttonText}
</Button>
</CardContent>
</Card>
);
};
export default BonusShopItem;