diff --git a/package-lock.json b/package-lock.json index ad6333f..17a27a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "no-copy-frontend", "version": "0.40.0", "dependencies": { + "@a2seven/yoo-checkout": "^1.1.4", "@react-input/mask": "^2.0.4", "@tailwindcss/postcss": "^4.1.17", "@tanstack/match-sorter-utils": "^8.19.4", @@ -41,6 +42,20 @@ "typescript": "^5" } }, + "node_modules/@a2seven/yoo-checkout": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@a2seven/yoo-checkout/-/yoo-checkout-1.1.4.tgz", + "integrity": "sha512-Xn8E6fJKVUpSqTTEgigoi0Woyvmc1/UuHukwpQUTEtxD2l4skTEeqPlhd0J4xum6lQ/0eGzeJP+/MgpkE9Ak9g==", + "license": "MIT", + "dependencies": { + "@types/axios": "^0.14.0", + "axios": "^0.21.1", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -2314,6 +2329,16 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/axios": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.4.tgz", + "integrity": "sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==", + "deprecated": "This is a stub types definition. axios provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "axios": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", @@ -3289,6 +3314,15 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -4654,6 +4688,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -7858,6 +7912,15 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validator": { "version": "13.15.26", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", diff --git a/package.json b/package.json index 5a7f0f3..ec17154 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "no-copy-frontend", - "version": "0.40.0", + "version": "0.41.0", "private": true, "scripts": { "dev": "next dev -p 2999", @@ -9,6 +9,7 @@ "lint": "eslint" }, "dependencies": { + "@a2seven/yoo-checkout": "^1.1.4", "@react-input/mask": "^2.0.4", "@tailwindcss/postcss": "^4.1.17", "@tanstack/match-sorter-utils": "^8.19.4", diff --git a/src/app/actions/yooKassa.ts b/src/app/actions/yooKassa.ts new file mode 100644 index 0000000..c76bedc --- /dev/null +++ b/src/app/actions/yooKassa.ts @@ -0,0 +1,43 @@ +'use server' + +import { YooCheckout, ICreatePayment } from '@a2seven/yoo-checkout'; +import { getSessionData } from '@/app/actions/session'; + +const checkout = new YooCheckout({ shopId: '1276731', secretKey: 'test_0Yns_0NHV5GJf6ypJ5HC4NSfnLO8SJkw-1PwrVWsDl4' }); + +const idempotenceKey = '02347fc4-a1f0-49db-807e-f0d67c2ed5a5'; + +export async function yooKasaCreatePayment(amount: number, tariff: string) { + console.log(amount); + console.log(tariff); + /* return true; */ + + const userEmail = await getSessionData('email'); + + const createPayload: ICreatePayment = { + amount: { + value: amount.toLocaleString(), + currency: 'RUB' + }, + payment_method_data: { + type: 'bank_card' + }, + confirmation: { + type: 'redirect', + return_url: 'test' + }, + metadata: { + userId: userEmail, + tariff: tariff + } + }; + + try { + const payment = await checkout.createPayment(createPayload, Date.now().toLocaleString()); + console.log(payment); + return payment?.confirmation.confirmation_url; + /* return payment; */ + } catch (error) { + console.error(error); + } +} diff --git a/src/app/styles/pages-styles.scss b/src/app/styles/pages-styles.scss index eebb307..01e7535 100644 --- a/src/app/styles/pages-styles.scss +++ b/src/app/styles/pages-styles.scss @@ -3942,4 +3942,111 @@ animation: spin 1s linear infinite; } } +} + +.modal-window-confirm-payment { + background: white; + border-radius: 20px; + max-width: 480px; + margin: 20px; + text-align: center; + position: relative; + + &-title { + color: #1e293b; + margin-bottom: 12px; + font-size: 24px; + } + + &-tariff { + color: #1e293b; + margin-bottom: 8px; + font-size: 20px; + } + + &-description { + color: #64748b; + margin-bottom: 12px; + font-size: 16px; + } + + &-price { + background: #f8fafc; + padding: 12px; + border-radius: 10px; + margin-bottom: 30px; + + div { + &:first-child { + font-size: 26px; + font-weight: 700; + color: #6366f1; + } + + &:last-child { + color: #64748b; + font-size: 16px; + } + } + } + + .btn-primary { + width: 100%; + padding: 12px 18px; + border: none; + border-radius: 12px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + overflow: hidden; + + &.btn-confirm { + background: linear-gradient(135deg, #6366f1, #8b5cf6); + color: white; + } + + &.btn-cancel { + background: transparent; + border: 2px solid #6366f1; + color: #6366f1; + } + + &.btn-confirm:disabled, + .btn-cancel:disabled { + opacity: 0.6; + cursor: not-allowed; + pointer-events: none; + } + + .btn-loading { + position: relative; + /* Можно добавить анимацию загрузки */ + } + + .btn-loading::after { + content: ''; + position: absolute; + width: 16px; + height: 16px; + top: 50%; + right: 10px; + transform: translateY(-50%); + border: 2px solid transparent; + border-top-color: #ffffff; + border-radius: 50%; + animation: button-loading-spinner 1s ease infinite; + } + + @keyframes button-loading-spinner { + from { + transform: translateY(-50%) rotate(0turn); + } + + to { + transform: translateY(-50%) rotate(1turn); + } + } + } } \ No newline at end of file diff --git a/src/app/ui/payment/payment-tab-tariffs.tsx b/src/app/ui/payment/payment-tab-tariffs.tsx index 94faf8b..01335b2 100644 --- a/src/app/ui/payment/payment-tab-tariffs.tsx +++ b/src/app/ui/payment/payment-tab-tariffs.tsx @@ -4,8 +4,12 @@ import { fetchTariffs } from '@/app/actions/action'; import { useQuery } from '@tanstack/react-query'; import { convertBytes } from '@/app/lib/convertBytes'; import { useTranslations } from 'next-intl'; +import { yooKasaCreatePayment } from '@/app/actions/yooKassa'; +import { useState, ReactNode } from 'react'; +import ModalWindow from '@/app/components/ModalWindow'; export default function PaymentTabTariffs() { + const t = useTranslations('Global'); const { data: userData, isLoading, @@ -18,48 +22,128 @@ export default function PaymentTabTariffs() { } }); + const [openWindow, setOpenWindow] = useState(false); + const [selectedTariff, setSelectedTariff] = useState<{ + value: number; + tariff: string; + tokens: number; + } | null>(null); + const [isProcessing, setIsProcessing] = useState(false); - const t = useTranslations('Global'); + async function createPayment(value: number, tariff: string) { + if (isProcessing) return; - return ( -
-
-
- - +
-
+ ); + } - {userData?.map(((item: { - id: number, - name: string, - price: number, - tokens: number, - maxFilesCount: number, - diskSize: number - }) => { - return ( -
+ return ( + <> + + + + +
+
+
+ + +
+
+
+ {userData?.map((item: { + id: number; + name: string; + price: number; + tokens: number; + maxFilesCount: number; + diskSize: number; + }) => ( +
🚀

- { - t.has(item.name) ? t(item.name) : item.name - } + {t.has(item.name) ? t(item.name) : item.name}

-
- {item.price} -
+
{item.price}
в месяц
-
- {item.tokens} токенов включено
+
{item.tokens} токенов включено
  • @@ -83,10 +167,18 @@ export default function PaymentTabTariffs() { API доступ
+
+ +
- ) - }))} + ))} +
-
- ) + + ); } \ No newline at end of file diff --git a/src/app/ui/payment/secure-payments.tsx b/src/app/ui/payment/secure-payments.tsx index d5ff9ff..2bd2eaa 100644 --- a/src/app/ui/payment/secure-payments.tsx +++ b/src/app/ui/payment/secure-payments.tsx @@ -8,9 +8,11 @@ export default function SecurePayments() { return (

- 🔒 Безопасные платежи + Безопасные платежи

-
+