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 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { fetchTariffs, fetchTokensBundle } from '@/app/actions/action';
|
||||
import {useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { convertBytes } from '@/app/lib/convertBytes';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { yooKasaCreatePayment } from '@/app/actions/yooKassa';
|
||||
@@ -54,6 +54,7 @@ export default function PaymentTubBuyTokens() {
|
||||
const [showWidget, setShowWidget] = useState<boolean>(false);
|
||||
const [yooMoneyConfig, setYooMoneyConfig] = useState<YooMoneyCheckoutWidgetConfig | null>(null);
|
||||
const queryClient = useQueryClient();
|
||||
const [selectedTokenPackage, setSelectedTokenPackage] = useState<Tariff | null>(null);
|
||||
|
||||
async function createPayment(value: number, tokensBundle: number) {
|
||||
if (isProcessing) return;
|
||||
@@ -175,50 +176,69 @@ export default function PaymentTubBuyTokens() {
|
||||
setShowWidget(false);
|
||||
}
|
||||
|
||||
function selectHandler(item: Tariff) {
|
||||
console.log(item);
|
||||
setSelectedTokenPackage(item);
|
||||
console.log(selectedTokenPackage);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModalWindow state={openWindow} callBack={closeModal}>
|
||||
<PaymentConfirmationModal />
|
||||
</ModalWindow>
|
||||
<div className="tab-content">
|
||||
<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="tab-content block-wrapper">
|
||||
<div className="subscription-grid">
|
||||
{tokensPaymentData?.map((item: {
|
||||
id: number;
|
||||
name: string;
|
||||
price: number;
|
||||
tokens: number;
|
||||
maxFilesCount: number;
|
||||
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>
|
||||
{tokensPaymentData?.map((item: Tariff) => (
|
||||
<div
|
||||
className={`token-package ${selectedTokenPackage?.id === item.id ? 'selected' : ''}`}
|
||||
key={item.id}
|
||||
onClick={(() => {
|
||||
selectHandler(item);
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className="token-package-amount"
|
||||
>
|
||||
{item.tokens ?? 0}
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={() => openPaymentWindow(item.price, item.name, item.tokens, item.id)}
|
||||
>
|
||||
{t('buy')}
|
||||
</button>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
{/* Модальное окно с виджетом */}
|
||||
|
||||
@@ -294,7 +294,9 @@
|
||||
"there-are-not-enough-funds-to-protect-file": "There are not enough funds to protect file. {count} tokens required",
|
||||
"duplicate-files": "Duplicate files",
|
||||
"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": {
|
||||
"and": "and",
|
||||
|
||||
@@ -294,7 +294,9 @@
|
||||
"there-are-not-enough-funds-to-protect-file": "Для защиты файла недостаточно средств. Необходимо {count} токен(ов/а)",
|
||||
"duplicate-files": "Дубликаты файлов",
|
||||
"monitoring-is-not-supported": "Мониторинг не поддерживается",
|
||||
"frequently-asked-questions": "Часто задаваемые вопросы"
|
||||
"frequently-asked-questions": "Часто задаваемые вопросы",
|
||||
"select-a-token-package": "Выберите пакет токенов",
|
||||
"package-selected-tokens-price": "Выбран пакет: {tokens} токенов за {price}₽"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "и",
|
||||
|
||||
Reference in New Issue
Block a user