redisign tokens paytment
This commit is contained in:
@@ -298,6 +298,97 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.token-package {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 2px solid #e2e8f0;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-4px) scale(1.02);
|
||||||
|
border-color: #6366f1;
|
||||||
|
box-shadow: 0 12px 30px rgba(99, 102, 241, 0.2);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.1), transparent);
|
||||||
|
transition: left 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border-color: #10b981;
|
||||||
|
background: linear-gradient(135deg, #f0fdf4, #dcfce7);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-package-amount {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1e293b;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-package-text {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #64748b;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-package-price {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 600;
|
||||||
|
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-package-detail {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-button {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 280px;
|
||||||
|
padding: 12px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-token-info {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.secure-payments-wrapper {
|
.secure-payments-wrapper {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export default function PaymentTubBuyTokens() {
|
|||||||
const [showWidget, setShowWidget] = useState<boolean>(false);
|
const [showWidget, setShowWidget] = useState<boolean>(false);
|
||||||
const [yooMoneyConfig, setYooMoneyConfig] = useState<YooMoneyCheckoutWidgetConfig | null>(null);
|
const [yooMoneyConfig, setYooMoneyConfig] = useState<YooMoneyCheckoutWidgetConfig | null>(null);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const [selectedTokenPackage, setSelectedTokenPackage] = useState<Tariff | null>(null);
|
||||||
|
|
||||||
async function createPayment(value: number, tokensBundle: number) {
|
async function createPayment(value: number, tokensBundle: number) {
|
||||||
if (isProcessing) return;
|
if (isProcessing) return;
|
||||||
@@ -175,50 +176,69 @@ export default function PaymentTubBuyTokens() {
|
|||||||
setShowWidget(false);
|
setShowWidget(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectHandler(item: Tariff) {
|
||||||
|
console.log(item);
|
||||||
|
setSelectedTokenPackage(item);
|
||||||
|
console.log(selectedTokenPackage);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ModalWindow state={openWindow} callBack={closeModal}>
|
<ModalWindow state={openWindow} callBack={closeModal}>
|
||||||
<PaymentConfirmationModal />
|
<PaymentConfirmationModal />
|
||||||
</ModalWindow>
|
</ModalWindow>
|
||||||
<div className="tab-content">
|
<div className="tab-content block-wrapper">
|
||||||
<div className="billing-toggle" style={{ display: 'none' }}>
|
|
||||||
<div>
|
|
||||||
<button className="billing-btn active">💳 Помесячно</button>
|
|
||||||
<button className="billing-btn">
|
|
||||||
🔥 Годовая
|
|
||||||
<span>ВЫГОДНО</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="subscription-grid">
|
<div className="subscription-grid">
|
||||||
{tokensPaymentData?.map((item: {
|
{tokensPaymentData?.map((item: Tariff) => (
|
||||||
id: number;
|
<div
|
||||||
name: string;
|
className={`token-package ${selectedTokenPackage?.id === item.id ? 'selected' : ''}`}
|
||||||
price: number;
|
key={item.id}
|
||||||
tokens: number;
|
onClick={(() => {
|
||||||
maxFilesCount: number;
|
selectHandler(item);
|
||||||
diskSize: number;
|
})}
|
||||||
}) => (
|
|
||||||
<div className="plan-card animate-card" key={item.id}>
|
|
||||||
<div className="plan-header">
|
|
||||||
<div className="plan-price">{item.price ?? 0} ₽</div>
|
|
||||||
<div className="plan-tokens header">
|
|
||||||
{item.tokens ?? 0}
|
|
||||||
<br />
|
|
||||||
токенов
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={() => openPaymentWindow(item.price, item.name, item.tokens, item.id)}
|
|
||||||
>
|
>
|
||||||
{t('buy')}
|
<div
|
||||||
</button>
|
className="token-package-amount"
|
||||||
|
>
|
||||||
|
{item.tokens ?? 0}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="token-package-text"
|
||||||
|
>
|
||||||
|
{t('tokens')}
|
||||||
|
</div>
|
||||||
|
<div className="token-package-price">{item.price ?? 0} ₽</div>
|
||||||
|
<div className="token-package-detail">
|
||||||
|
~{Math.ceil((item.price / item.tokens) * 10) / 10 }₽ за токен
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
className="plan-button btn-primary"
|
||||||
|
onClick={() => {
|
||||||
|
if (selectedTokenPackage) {
|
||||||
|
openPaymentWindow(selectedTokenPackage.price, selectedTokenPackage.name, selectedTokenPackage.tokens, selectedTokenPackage.id)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={selectedTokenPackage ? false : true}
|
||||||
|
>
|
||||||
|
{selectedTokenPackage ? `Купить за ${selectedTokenPackage.price}₽` : t('select-a-token-package')}
|
||||||
|
</button>
|
||||||
|
{selectedTokenPackage && (
|
||||||
|
<div
|
||||||
|
className="selected-token-info"
|
||||||
|
>
|
||||||
|
{t('package-selected-tokens-price', {
|
||||||
|
tokens: selectedTokenPackage.tokens,
|
||||||
|
price: selectedTokenPackage.price
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Модальное окно с виджетом */}
|
{/* Модальное окно с виджетом */}
|
||||||
|
|||||||
@@ -294,7 +294,9 @@
|
|||||||
"there-are-not-enough-funds-to-protect-file": "There are not enough funds to protect file. {count} tokens required",
|
"there-are-not-enough-funds-to-protect-file": "There are not enough funds to protect file. {count} tokens required",
|
||||||
"duplicate-files": "Duplicate files",
|
"duplicate-files": "Duplicate files",
|
||||||
"monitoring-is-not-supported": "Monitoring is not supported",
|
"monitoring-is-not-supported": "Monitoring is not supported",
|
||||||
"frequently-asked-questions": "Frequently Asked Questions"
|
"frequently-asked-questions": "Frequently Asked Questions",
|
||||||
|
"select-a-token-package": "Select a token package",
|
||||||
|
"package-selected-tokens-price": "Package selected: {tokens} tokens for {price}₽"
|
||||||
},
|
},
|
||||||
"Login-register-form": {
|
"Login-register-form": {
|
||||||
"and": "and",
|
"and": "and",
|
||||||
|
|||||||
@@ -294,7 +294,9 @@
|
|||||||
"there-are-not-enough-funds-to-protect-file": "Для защиты файла недостаточно средств. Необходимо {count} токен(ов/а)",
|
"there-are-not-enough-funds-to-protect-file": "Для защиты файла недостаточно средств. Необходимо {count} токен(ов/а)",
|
||||||
"duplicate-files": "Дубликаты файлов",
|
"duplicate-files": "Дубликаты файлов",
|
||||||
"monitoring-is-not-supported": "Мониторинг не поддерживается",
|
"monitoring-is-not-supported": "Мониторинг не поддерживается",
|
||||||
"frequently-asked-questions": "Часто задаваемые вопросы"
|
"frequently-asked-questions": "Часто задаваемые вопросы",
|
||||||
|
"select-a-token-package": "Выберите пакет токенов",
|
||||||
|
"package-selected-tokens-price": "Выбран пакет: {tokens} токенов за {price}₽"
|
||||||
},
|
},
|
||||||
"Login-register-form": {
|
"Login-register-form": {
|
||||||
"and": "и",
|
"and": "и",
|
||||||
|
|||||||
Reference in New Issue
Block a user