This commit is contained in:
you 2024-07-25 11:59:35 +03:00
parent cbb3a5f1b6
commit 06d4c96c44
5 changed files with 490 additions and 271 deletions

Binary file not shown.

11
package-lock.json generated
View File

@ -20,6 +20,7 @@
"@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-terser": "^0.4.0",
"@zerodevx/svelte-toast": "^0.9.5",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"rollup": "^3.15.0", "rollup": "^3.15.0",
@ -277,6 +278,16 @@
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"dev": true "dev": true
}, },
"node_modules/@zerodevx/svelte-toast": {
"version": "0.9.5",
"resolved": "https://registry.npmjs.org/@zerodevx/svelte-toast/-/svelte-toast-0.9.5.tgz",
"integrity": "sha512-JLeB/oRdJfT+dz9A5bgd3Z7TuQnBQbeUtXrGIrNWMGqWbabpepBF2KxtWVhL2qtxpRqhae2f6NAOzH7xs4jUSw==",
"dev": true,
"license": "ISC",
"peerDependencies": {
"svelte": "^3.57.0 || ^4.0.0"
}
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.11.3", "version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",

View File

@ -12,6 +12,7 @@
"@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-terser": "^0.4.0",
"@zerodevx/svelte-toast": "^0.9.5",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"rollup": "^3.15.0", "rollup": "^3.15.0",

View File

@ -1,7 +1,9 @@
<script> <script>
import TailwindCss from "./TailwindCSS/TailwindCSS.svelte"; import TailwindCss from "./TailwindCSS/TailwindCSS.svelte";
import DepositPage from "./Pages/DepositPage.svelte"; import DepositPage from "./Pages/DepositPage.svelte";
import {SvelteToast} from "@zerodevx/svelte-toast";
</script> </script>
<TailwindCss /> <TailwindCss />
<DepositPage /> <DepositPage />
<SvelteToast />

View File

@ -1,6 +1,57 @@
<script> <script>
import { jwtDecode } from "jwt-decode";
import { Turnstile } from "svelte-turnstile"; import { Turnstile } from "svelte-turnstile";
import Mbank from "../banks/mbank.svelte"; import Mbank from "../banks/mbank.svelte";
import axios from "axios";
import { sayError, sayInfo } from "../lib/toaster";
import LoadingSpinner from "../lib/loadingSpinner.svelte";
const apiBase = "https://24paymentgateway.ru/api/v1/";
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
/**
* hpp:
1) GET: /api/v1/getPaymentMethods
2) GET: /api/v1/getRequisites
3) GET: /api/v1/getOrderStatus
4) POST: /api/v1/loadDisputeReceipt
5) POST: /api/v1/createDispute
5) POST: /api/v1/choosePaymentMethod
6) POST: /api/v1/cancelOrder
*/
let tokenURL = "";
let orderID = "";
let invalidURL = true;
async function getTokenFromURL() {
const queryString = window.location.search;
// console.log(queryString);
// await delay(5000);
const urlParams = new URLSearchParams(queryString);
tokenURL = urlParams.get("token");
// console.log(urlParams.get("token"));
}
getTokenFromURL();
function validateJWT(token) {
try {
let t = jwtDecode(token);
orderID = t["order_id"];
console.log(t);
invalidURL = false;
} catch (error) {
invalidURL = true;
// console.log(error);
}
}
$: tokenURL, validateJWT(tokenURL);
$: invalidURL,
(() => {
if (!invalidURL) {
getPaymentMethods();
}
})();
let selectedBank = ""; let selectedBank = "";
let depositTimeLeft = 60; //seconds let depositTimeLeft = 60; //seconds
@ -15,70 +66,70 @@
let randomCard = "2200 2080 1111 1111"; let randomCard = "2200 2080 1111 1111";
let cardHolder = "Андрей Витальевич В."; let cardHolder = "Андрей Витальевич В.";
function randomRequstIdGenerator() { // function randomRequstIdGenerator() {
randomRequestId = // randomRequestId =
Math.floor(Math.random() * (999999999 - 111111111 + 1)) + 111111111; // Math.floor(Math.random() * (999999999 - 111111111 + 1)) + 111111111;
} // }
randomRequstIdGenerator(); // randomRequstIdGenerator();
function genRandomCard() { // function genRandomCard() {
let r = [1234]; // let r = [1234];
for (let i = 0; i < 3; i++) { // for (let i = 0; i < 3; i++) {
r.push(Math.floor(Math.random() * (8888 - 1111 + 1)) + 1111); // r.push(Math.floor(Math.random() * (8888 - 1111 + 1)) + 1111);
} // }
return r.join(" "); // return r.join(" ");
} // }
function startTimer() { // function startTimer() {
endTime = Math.floor(Math.random() * (58 - 57 + 1)) + 57; // endTime = Math.floor(Math.random() * (58 - 57 + 1)) + 57;
timerInterval = setInterval(() => { // timerInterval = setInterval(() => {
depositTimeLeft--; // depositTimeLeft--;
if (depositTimeLeft === endTime) { // if (depositTimeLeft === endTime) {
clearInterval(timerInterval); // clearInterval(timerInterval);
depositTimeLeft = 0; // depositTimeLeft = 0;
showReqs = true; // showReqs = true;
showBankSelection = false; // showBankSelection = false;
randomCard = genRandomCard(); // randomCard = genRandomCard();
startTotalTimer(); // startTotalTimer();
requestingReqs = false; // requestingReqs = false;
return; // return;
} // }
if (depositTimeLeft < 0) { // if (depositTimeLeft < 0) {
clearInterval(timerInterval); // clearInterval(timerInterval);
depositTimeLeft = 0; // depositTimeLeft = 0;
return; // return;
} // }
}, 1000); // }, 1000);
} // }
function stopTimer() { // function stopTimer() {
clearInterval(timerInterval); // clearInterval(timerInterval);
depositTimeLeft = 60; // depositTimeLeft = 60;
} // }
function startTotalTimer() { // function startTotalTimer() {
// endTime = Math.floor(Math.random() * (58 - 47 + 1)) + 47; // // endTime = Math.floor(Math.random() * (58 - 47 + 1)) + 47;
timerInterval = setInterval(() => { // timerInterval = setInterval(() => {
totalDepositTimeLeft--; // totalDepositTimeLeft--;
if (totalDepositTimeLeft < 0) { // if (totalDepositTimeLeft < 0) {
clearInterval(totalTimerInterval); // clearInterval(totalTimerInterval);
totalDepositTimeLeft = 0; // totalDepositTimeLeft = 0;
return; // return;
} // }
}, 1000); // }, 1000);
} // }
function stopTotalTimer() { // function stopTotalTimer() {
clearInterval(totalTimerInterval); // clearInterval(totalTimerInterval);
totalDepositTimeLeft = 600; // totalDepositTimeLeft = 600;
} // }
let captchaVerified = false; let captchaVerified = false;
let captchaValue = undefined; let captchaValue = undefined;
let checkCaptchaInterval = setInterval(() => { let checkCaptchaInterval = setInterval(() => {
const form = document.getElementById( const form = document.getElementById(
"8d895e75b7a0def7699e6c4d7cd54c51d9844775bd5fd5e8e3d34748" "8d895e75b7a0def7699e6c4d7cd54c51d9844775bd5fd5e8e3d34748",
); );
const captchaInput = form.querySelector("input"); const captchaInput = form.querySelector("input");
if (captchaInput.value !== "") { if (captchaInput.value !== "") {
@ -94,20 +145,179 @@
let loadedFile = ""; let loadedFile = "";
let showBankSelection = true; let showBankSelection = false;
let showHelpSection = false; let showHelpSection = false;
let showComplete = false; let showComplete = false;
let showLoadingScreen = false; let showLoadingScreen = false;
let disableGetReqBtn = false;
let paymentMethods = [];
async function getPaymentMethods() {
try {
let result = await axios.get(apiBase + "getPaymentMethods", {
headers: {
Authorization: "Bearer " + tokenURL,
"Content-Type": "application/json",
},
});
paymentMethods = result.data.data;
showBankSelection = true;
} catch (error) {
sayError("Не удалось получить доступные банки. Ошибка #8787");
}
}
// getPaymentMethods();
let requisites = [];
async function getRequisites() {
requestingReqs = true;
disableGetReqBtn = true;
await delay(2000);
let result = await axios.post(
apiBase + "getRequisites",
{
bank_id: selectedBank,
},
{
headers: {
Authorization: "Bearer " + tokenURL,
"Content-Type": "application/json",
},
},
);
requestingReqs = false;
requisites = result.data;
console.log(result);
showReqs = true;
}
// getRequisites();
let orderStatus;
async function getOrderStatus() {
let result = await axios.get(apiBase + "getOrderStatus", {
headers: {
Authorization: "Bearer " + "jwt",
"Content-Type": "application/json",
},
});
console.log(result);
}
// getOrderStatus();
async function loadReceipt() {
let result = await axios.post(
apiBase + "loadDisputeReceipt",
{
//data form
},
{
headers: {
Authorization: "Bearer " + "jwt",
"Content-Type": "application/json",
},
},
);
console.log(result);
}
async function createDispute() {
let result = await axios.post(
apiBase + "createDispute",
{
//data
},
{
headers: {
Authorization: "Bearer " + "jwt",
"Content-Type": "application/json",
},
},
);
console.log(result);
}
async function choosePaymentMethod() {
let result = await axios.post(
apiBase + "choosePaymentMethod",
{
//data
},
{
headers: {
Authorization: "Bearer " + "jwt",
"Content-Type": "application/json",
},
},
);
console.log(result);
}
async function cancelOrder() {
let result = await axios.post(
apiBase + "cancelOrder",
{
//data
},
{
headers: {
Authorization: "Bearer " + "jwt",
"Content-Type": "application/json",
},
},
);
console.log(result);
}
async function copyToClipboard() {
try {
await navigator.clipboard.writeText(requisites.requisite[1]);
sayInfo('Скопировано!');
} catch (err) {
console.error('Failed to copy: ', err);
}
}
</script> </script>
<div {#if invalidURL}
<div
class="fixed inset-0 bg-slate-950 w-full min-h-screen overflow-auto flex flex-col justify-center items-center gap-4 p-8 text-white"
>
<div class="flex justify-center items-center gap-4">
<svg
class="animate-spin h-12 w-12 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
></circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
</div>
</div>
{:else}
<div
class="fixed inset-0 bg-slate-950 w-full min-h-screen overflow-auto flex flex-col items-center gap-4 p-8 text-white" class="fixed inset-0 bg-slate-950 w-full min-h-screen overflow-auto flex flex-col items-center gap-4 p-8 text-white"
> >
<div class="flex flex-col flex-shrink-0 gap-8"> <div class="flex flex-col flex-shrink-0 gap-8">
<div <div
class="w-full flex h-16 justify-center items-center bg-slate-900 rounded-3xl flex-shrink-0" class="w-full flex h-16 justify-center items-center bg-slate-900 rounded-3xl flex-shrink-0"
> >
<p class="text-xl flex-shrink-0">Заявка №{randomRequestId}</p> <p class="text-sm flex-shrink-0">Заявка {orderID}</p>
</div> </div>
<div class="flex flex-col w-full gap-16"> <div class="flex flex-col w-full gap-16">
<div class="flex w-full"> <div class="flex w-full">
@ -142,68 +352,54 @@
</div> </div>
<div class="flex flex-col w-full gap-8"> <div class="flex flex-col w-full gap-8">
{#if showBankSelection} {#if showBankSelection}
<p class="text-3xl font-bold">Выберите банк</p> <p class="text-3xl font-bold">Выбор банка</p>
{#each paymentMethods as pm}
<div class="flex"> <div class="flex">
<button <button
on:click={() => { on:click={() => {
selectedBank = "sber"; selectedBank = pm["bank_id"];
}} }}
class={"w-full rounded-3xl flex items-center justify-center gap-8 ring-2 py-4 px-4 " + class={"w-full rounded-3xl flex items-center justify-center gap-8 ring-2 py-4 px-4 " +
(selectedBank === "sber" (selectedBank === pm["bank_id"]
? "ring-indigo-600 bg-slate-900 cursor-default" ? "ring-indigo-600 bg-slate-900 cursor-default"
: "ring-slate-600 hover:ring-slate-300")} : "ring-slate-600 hover:ring-slate-300")}
> >
<div class="bg-transparent flex-shrink-0"> <div
<Mbank /> class="bg-transparent flex-shrink-0 flex justify-center items-center max-w-[200px] max-h-[70px]"
>
{@html pm["icon"]}
</div> </div>
<!-- <div class="w-full flex justify-center items-center pr-16">
<p class="text-xl">МБАНК</p>
</div> -->
</button> </button>
</div> </div>
{/each}
{:else}
<LoadingSpinner />
{/if} {/if}
<div class={"w-full justify-center " + (!showBankSelection ? "hidden":"hidden")}> <div
class={"w-full justify-center " +
(!showBankSelection ? "hidden" : "hidden")}
>
<form id="8d895e75b7a0def7699e6c4d7cd54c51d9844775bd5fd5e8e3d34748"> <form id="8d895e75b7a0def7699e6c4d7cd54c51d9844775bd5fd5e8e3d34748">
<Turnstile siteKey="0x4AAAAAAAdVbiLiWPGwxHjN" /> <Turnstile siteKey="0x4AAAAAAAdVbiLiWPGwxHjN" />
</form> </form>
</div> </div>
{#if selectedBank === "sber" && captchaVerified} {#if selectedBank !== "" && captchaVerified}
{#if !showHelpSection} {#if !showHelpSection}
<button <button
disabled={disableGetReqBtn}
on:click={() => { on:click={() => {
if (requestingReqs || showReqs) {
showAlertQuit = true; getRequisites();
} else {
requestingReqs = true;
showReqs = false;
depositTimeLeft = 60;
startTimer();
}
}} }}
class={(requestingReqs || showReqs class={"bg-indigo-800 hover:bg-indigo-700 ring-transparent disabled:bg-transparent disabled:text-gray-600 disabled:ring-2 disabled:ring-inset disabled:ring-gray-600" +
? "bg-slate-950 ring-indigo-800 hover:bg-slate-900"
: "bg-indigo-800 hover:bg-indigo-700 ring-transparent") +
" w-full font-semibold text-xl flex gap-1 justify-center items-center text-center p-4 rounded-3xl transition-all duration-75 ring-2 ring-inset focus:outline-none focus:ring-inset focus:ring-1 focus:ring-white"} " w-full font-semibold text-xl flex gap-1 justify-center items-center text-center p-4 rounded-3xl transition-all duration-75 ring-2 ring-inset focus:outline-none focus:ring-inset focus:ring-1 focus:ring-white"}
> >
{requestingReqs || showReqs ? "Отмена" : "Запросить реквизиты"} {"Запросить реквизиты"}
</button> </button>
{/if} {/if}
{#if requestingReqs} {#if requestingReqs}
<div class="flex justify-center items-center w-full"> <LoadingSpinner />
<p>
Реквизиты появятся не позже, чем через {Math.floor(
depositTimeLeft / 60
).toLocaleString("en-US", {
minimumIntegerDigits: 2,
useGrouping: false,
}) +
":" +
Math.floor(depositTimeLeft % 60).toLocaleString("en-US", {
minimumIntegerDigits: 2,
useGrouping: false,
})}
</p>
</div>
{/if} {/if}
{#if showReqs} {#if showReqs}
{#if !showHelpSection} {#if !showHelpSection}
@ -211,8 +407,11 @@
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<p class="text-lg">Номер карты для перевода</p> <p class="text-lg">Номер карты для перевода</p>
<div class="flex gap-4 justify-center items-center"> <div class="flex gap-4 justify-center items-center">
<p class="text-4xl font-bold">{randomCard}</p> <p class="text-2xl font-bold">{requisites.requisite[1]}</p>
<button <button
on:click={()=>{
copyToClipboard();
}}
class="relative w-11 h-10 p-2 rounded-full bg-indigo-900 group hover:bg-indigo-800" class="relative w-11 h-10 p-2 rounded-full bg-indigo-900 group hover:bg-indigo-800"
> >
<div <div
@ -223,27 +422,16 @@
></div> ></div>
</button> </button>
</div> </div>
<p class="text-lg">Получатель: {cardHolder}</p> <p class="text-lg">Получатель: {requisites.requisite[0]}</p>
<p class="text-lg mt-4"> <p class="text-lg mt-4">
Время на оплату {Math.floor( Время на оплату
totalDepositTimeLeft / 60
).toLocaleString("en-US", {
minimumIntegerDigits: 2,
useGrouping: false,
}) +
":" +
Math.floor(totalDepositTimeLeft % 60).toLocaleString(
"en-US",
{
minimumIntegerDigits: 2,
useGrouping: false,
}
)}
</p> </p>
</div> </div>
</div> </div>
<button <button
on:click={() => {showLoadingScreen = true}} on:click={() => {
showLoadingScreen = true;
}}
disabled={showHelpSection} disabled={showHelpSection}
class={(false class={(false
? "bg-slate-950 ring-indigo-800 hover:bg-slate-900" ? "bg-slate-950 ring-indigo-800 hover:bg-slate-900"
@ -254,9 +442,12 @@
</button> </button>
{/if} {/if}
{#if !showHelpSection} {#if !showHelpSection}
<button on:click={()=>{ <button
on:click={() => {
showHelpSection = true; showHelpSection = true;
}} class="underline text-blue-500 hover:text-blue-400"> }}
class="underline text-blue-500 hover:text-blue-400"
>
Возникли трудности? Возникли трудности?
</button> </button>
{/if} {/if}
@ -264,33 +455,43 @@
<p class="p-8 bg-slate-900 text-xl rounded-3xl"> <p class="p-8 bg-slate-900 text-xl rounded-3xl">
Загрузите чек, чтобы мы могли подтвердить перевод Загрузите чек, чтобы мы могли подтвердить перевод
</p> </p>
<button on:click={()=>{ <button
document.getElementById('loaded-file').click(); on:click={() => {
document.getElementById("loaded-file").click();
}} }}
class={"bg-indigo-800 hover:bg-indigo-700 ring-transparent" + class={"bg-indigo-800 hover:bg-indigo-700 ring-transparent" +
" w-full font-semibold text-xl flex gap-1 justify-center items-center text-center p-4 rounded-3xl transition-all duration-75 ring-2 ring-inset focus:outline-none focus:ring-inset focus:ring-1 focus:ring-white"} " w-full font-semibold text-xl flex gap-1 justify-center items-center text-center p-4 rounded-3xl transition-all duration-75 ring-2 ring-inset focus:outline-none focus:ring-inset focus:ring-1 focus:ring-white"}
>Загрузить чек</button> >Загрузить чек</button
>
<p class="text-xl font-semibold">Загружен файл: {loadedFile}</p> <p class="text-xl font-semibold">Загружен файл: {loadedFile}</p>
<button on:click={()=>{ <button
on:click={() => {
// window.open("https://www.google.com", "__blank"); // window.open("https://www.google.com", "__blank");
showLoadingScreen = true; showLoadingScreen = true;
}} }}
disabled={loadedFile === ""} disabled={loadedFile === ""}
class={"bg-green-800 hover:bg-green-700 ring-transparent" + class={"bg-green-800 hover:bg-green-700 ring-transparent" +
" w-full font-semibold text-xl flex gap-1 disabled:bg-slate-950 disabled:ring-2 disabled:ring-inset disabled:ring-red-800 justify-center items-center text-center p-4 rounded-3xl transition-all duration-75 ring-2 ring-inset focus:outline-none focus:ring-inset focus:ring-1 focus:ring-white"} " w-full font-semibold text-xl flex gap-1 disabled:bg-slate-950 disabled:ring-2 disabled:ring-inset disabled:ring-red-800 justify-center items-center text-center p-4 rounded-3xl transition-all duration-75 ring-2 ring-inset focus:outline-none focus:ring-inset focus:ring-1 focus:ring-white"}
>Отправить</button> >Отправить</button
>
{/if} {/if}
<input on:change={(e)=>{ <input
on:change={(e) => {
loadedFile = e.target.files[0].name; loadedFile = e.target.files[0].name;
}} id="loaded-file" type="file" hidden accept=".png, .jpg, .jpeg, .pdf"> }}
id="loaded-file"
type="file"
hidden
accept=".png, .jpg, .jpeg, .pdf"
/>
{/if} {/if}
{/if} {/if}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{#if showAlertQuit} {#if showAlertQuit}
<div <div
class="fixed bg-slate-950 inset-0 w-full h-full bg-opacity-70 flex justify-center items-center text-white" class="fixed bg-slate-950 inset-0 w-full h-full bg-opacity-70 flex justify-center items-center text-white"
> >
@ -328,16 +529,20 @@
</div> </div>
</div> </div>
</div> </div>
{/if} {/if}
{#if showLoadingScreen} {#if showLoadingScreen}
<div class="fixed inset-0 bg-black flex flex-col justify-center items-center"> <div
class="fixed inset-0 bg-black flex flex-col justify-center items-center"
>
<div class="relative w-10 h-10"> <div class="relative w-10 h-10">
<div class="absolute bg-indigo-600 animate-ping w-10 h-10 rounded-full"> <div
</div> class="absolute bg-indigo-600 animate-ping w-10 h-10 rounded-full"
></div>
<div class="bg-indigo-600 w-10 h-10 rounded-full"></div> <div class="bg-indigo-600 w-10 h-10 rounded-full"></div>
</div> </div>
<p class="text-white text-2xl mt-8">Ваш платёж обрабатывается</p> <p class="text-white text-2xl mt-8">Ваш платёж обрабатывается</p>
<p class="text-white opacity-50 text-xl">Это не займет много времени</p> <p class="text-white opacity-50 text-xl">Это не займет много времени</p>
</div> </div>
{/if}
{/if} {/if}