Compare commits
72
Commits
v0.2
...
tgFullscreen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9dcc6860f4 | ||
|
|
1b96d049c7 | ||
|
|
46f3b22ec9 | ||
|
|
7d8096be4c | ||
|
|
2351ee51eb | ||
|
|
5f4b13d7ba | ||
|
|
0b1dc23cc6 | ||
|
|
2274cb4a4a | ||
|
|
060785a11a | ||
|
|
4645093029 | ||
|
|
1c1ee5df16 | ||
|
|
7cb7a7d73a | ||
|
|
0bc77e44f8 | ||
|
|
d10065cfcc | ||
|
|
d42f6eb9e8 | ||
|
|
f675a4ca49 | ||
|
|
9aee5f10d2 | ||
|
|
add9cb471e | ||
|
|
a58c73c112 | ||
|
|
90d629876b | ||
|
|
e34e65b337 | ||
|
|
fc8e8cba5e | ||
|
|
b952a76ccb | ||
|
|
f1decf7448 | ||
|
|
e7d5acc155 | ||
|
|
dd62962de8 | ||
|
|
3e9564d7b9 | ||
|
|
7f7dde7b28 | ||
|
|
fc6fb5003e | ||
|
|
1d22ac2173 | ||
|
|
7705908484 | ||
|
|
372f84d1b1 | ||
|
|
9c2a415886 | ||
|
|
0fc292829f | ||
|
|
691dea4bc8 | ||
|
|
578c82f6dd | ||
|
|
881ff70a1c | ||
|
|
58d2d3aa17 | ||
|
|
9c4851d35f | ||
|
|
a81aee843f | ||
|
|
778db1ce9c | ||
|
|
39fef5cb2a | ||
|
|
ed33936e4f | ||
|
|
9d2b4c158f | ||
|
|
71284b722c | ||
|
|
a9111959cd | ||
|
|
e4f3ddb6cd | ||
|
|
d298c58e08 | ||
|
|
0531e60222 | ||
|
|
9cef81a3c1 | ||
|
|
1e7e773cb1 | ||
|
|
2440fdf61a | ||
|
|
0ecc2b4a3c | ||
|
|
c5c36cb078 | ||
|
|
b03533dea6 | ||
|
|
939de83654 | ||
|
|
bf99462835 | ||
|
|
afc1670ac0 | ||
|
|
1b79b15a31 | ||
|
|
99c9f00110 | ||
|
|
6d5f73e90e | ||
|
|
f875a6afc0 | ||
|
|
08dc809e9d | ||
|
|
b4ceaa387a | ||
|
|
72ad5b3a21 | ||
|
|
419eed81e6 | ||
|
|
195ee714e9 | ||
|
|
6d37b74706 | ||
|
|
35c9a6704d | ||
|
|
54275d997b | ||
|
|
8c217ab321 | ||
|
|
5c3500d17c |
No files matched your search
@@ -1,3 +1,5 @@
|
|||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
dist
|
||||||
|
.env*
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"printWidth": 100,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
# React + TypeScript + Vite
|
# React + TypeScript + Vite
|
||||||
|
|
||||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
Currently, two official plugins are available:
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
|
|||||||
+20
-2
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link href="/vite.svg" rel="icon" type="image/svg+xml" />
|
<link href="/favicon.png" rel="icon" type="image/png">
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
|
|
||||||
<meta
|
<meta
|
||||||
@@ -14,9 +14,27 @@
|
|||||||
|
|
||||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||||
|
|
||||||
<title>MyMusic</title>
|
<title>MY</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Yandex.Metrika counter -->
|
||||||
|
<script type="text/javascript" >
|
||||||
|
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||||
|
m[i].l=1*new Date();
|
||||||
|
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
||||||
|
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
||||||
|
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
||||||
|
|
||||||
|
ym(99984890, "init", {
|
||||||
|
clickmap:true,
|
||||||
|
trackLinks:true,
|
||||||
|
accurateTrackBounce:true,
|
||||||
|
webvisor:true
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<noscript><div><img src="https://mc.yandex.ru/watch/99984890" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
||||||
|
<!-- /Yandex.Metrika counter -->
|
||||||
|
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script src="/src/entry.tsx" type="module"></script>
|
<script src="/src/entry.tsx" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Generated
+670
-7
@@ -9,8 +9,13 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.3.4",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
|
"@sentry/react": "^9.1.0",
|
||||||
|
"@telegram-apps/sdk": "^3.5.1",
|
||||||
|
"@ton/core": "^0.59.1",
|
||||||
|
"@tonconnect/ui-react": "^2.0.2",
|
||||||
"@vkruglikov/react-telegram-web-app": "^2.1.9",
|
"@vkruglikov/react-telegram-web-app": "^2.1.9",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -18,6 +23,7 @@
|
|||||||
"react-player": "^2.15.1",
|
"react-player": "^2.15.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.22.2",
|
"react-router-dom": "^6.22.2",
|
||||||
|
"react-tag-input": "^6.10.3",
|
||||||
"tailwind-merge": "^2.2.1",
|
"tailwind-merge": "^2.2.1",
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
@@ -1108,6 +1114,27 @@
|
|||||||
"url": "https://opencollective.com/unts"
|
"url": "https://opencollective.com/unts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-dnd/asap": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/invariant": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/shallowequal": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@remix-run/router": {
|
"node_modules/@remix-run/router": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz",
|
||||||
@@ -1285,6 +1312,324 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@sentry-internal/browser-utils": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-S1uT+kkFlstWpwnaBTIJSwwAID8PS3aA0fIidOjNezeoUE5gOvpsjDATo9q+sl6FbGWynxMz6EnYSrq/5tuaBQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "9.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/feedback": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-jTDCqkqH3QDC8m9WO4mB06hqnBRsl3p7ozoh0E774UvNB6blOEZjShhSGMMEy5jbbJajPWsOivCofUtFAwbfGw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/core": "9.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-E2xrUoms90qvm0BVOuaZ8QfkMoTUEgoIW/35uOeaqNcL7uOIj8c5cSEQQKit2Dr7CL6W+Ci5c6Khdyd5C0NL5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/browser-utils": "9.1.0",
|
||||||
|
"@sentry/core": "9.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry-internal/replay-canvas": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-gxredVe+mOgfNqDJ3dTLiRON3FK1rZ8d0LHp7TICK/umLkWFkuso0DbNeyKU+3XCEjCr9VM7ZRqTDMzmY6zyVg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/replay": "9.1.0",
|
||||||
|
"@sentry/core": "9.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/browser": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-G55e5j77DqRW3LkalJLAjRRfuyKrjHaKTnwIYXa6ycO+Q1+l14pEUxu+eK5Abu2rtSdViwRSb5/G6a/miSUlYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry-internal/browser-utils": "9.1.0",
|
||||||
|
"@sentry-internal/feedback": "9.1.0",
|
||||||
|
"@sentry-internal/replay": "9.1.0",
|
||||||
|
"@sentry-internal/replay-canvas": "9.1.0",
|
||||||
|
"@sentry/core": "9.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/core": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-djWEzSBpMgqdF3GQuxO+kXCUX+Mgq42G4Uah/HSUBvPDHKipMmyWlutGRoFyVPPOnCDgpHu3wCt83wbpEyVmDw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@sentry/react": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-aP2sXHH+erbomuzU762ktg340IGDh8zD7ueuqwBwGu98fhCpTYsLXiS85I29tUvPLljwNU9puLPmxbgW4iZ2tQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sentry/browser": "9.1.0",
|
||||||
|
"@sentry/core": "9.1.0",
|
||||||
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.14.0 || 17.x || 18.x || 19.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/bridge": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/bridge/-/bridge-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-Lp/vhspF7okK8zXvSWWirunKXOPE6Gr11o9VBne4VmKG/yHRhEW7Pf07ncPtXLLzI6wW8+VYc3khsHPABJymEw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@telegram-apps/signals": "^1.1.1",
|
||||||
|
"@telegram-apps/toolkit": "^2.0.0",
|
||||||
|
"@telegram-apps/transformers": "^2.2.0",
|
||||||
|
"@telegram-apps/types": "^2.0.0",
|
||||||
|
"better-promises": "^0.4.0",
|
||||||
|
"error-kid": "^0.0.4",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
|
"valibot": "1.0.0-beta.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/navigation": {
|
||||||
|
"version": "1.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/navigation/-/navigation-1.0.13.tgz",
|
||||||
|
"integrity": "sha512-TsUueB5LQp77GQHoMa93nq26Uw7GJjrFCPbyseMVU7aBBxAc+8CV2IYytRwcVp5sv/q7ThK5X4JaKn2V1yBHDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@telegram-apps/bridge": "^1.9.2",
|
||||||
|
"@telegram-apps/signals": "^1.1.1",
|
||||||
|
"@telegram-apps/toolkit": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/navigation/node_modules/@telegram-apps/bridge": {
|
||||||
|
"version": "1.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/bridge/-/bridge-1.9.2.tgz",
|
||||||
|
"integrity": "sha512-SJLcNWLXhbbZr9MiqFH/g2ceuitSJKMxUIZysK4zUNyTUNuonrQG80Q/yrO+XiNbKUj8WdDNM86NBARhuyyinQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@telegram-apps/signals": "^1.1.1",
|
||||||
|
"@telegram-apps/toolkit": "^1.1.1",
|
||||||
|
"@telegram-apps/transformers": "^1.2.2",
|
||||||
|
"@telegram-apps/types": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/navigation/node_modules/@telegram-apps/toolkit": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/toolkit/-/toolkit-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-+vhKx6ngfvjyTE6Xagl3z1TPVbfx5s7xAkcYzCdHYUo6T60jLIqLgyZMcI1UPoIAMuMu1pHoO+p8QNCj/+tFmw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/navigation/node_modules/@telegram-apps/transformers": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/transformers/-/transformers-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-vvMwXckd1D7Ozc0h66PSUwF5QLrRV9HlGJFFeBuUex8QEk5mSPtsJkLiqB8aBbwuFDa91+TUSM/CxqPZO/e9YQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@telegram-apps/toolkit": "^1.1.1",
|
||||||
|
"@telegram-apps/types": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/navigation/node_modules/@telegram-apps/types": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/types/-/types-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-so4HLh7clur0YyMthi9KVIgWoGpZdXlFOuQjk3+Q5NAvJZ11nAheBSwPlGw/Ko92+zwvrSBE/lQyN2+p17RP+w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/sdk": {
|
||||||
|
"version": "3.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/sdk/-/sdk-3.5.1.tgz",
|
||||||
|
"integrity": "sha512-m/ynpSozXsqq6Kfb6M9fm8SD6x/+jqvTFT59FuuOBvC+G8eMd0F+fvZdr6Pj0I6IL9M67nrfm92JpTu/aVNEjw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@telegram-apps/bridge": "^2.4.0",
|
||||||
|
"@telegram-apps/navigation": "^1.0.13",
|
||||||
|
"@telegram-apps/signals": "^1.1.1",
|
||||||
|
"@telegram-apps/toolkit": "^2.0.0",
|
||||||
|
"@telegram-apps/transformers": "^2.2.0",
|
||||||
|
"@telegram-apps/types": "^2.0.0",
|
||||||
|
"better-promises": "^0.4.0",
|
||||||
|
"error-kid": "^0.0.4",
|
||||||
|
"valibot": "1.0.0-beta.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/signals": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/signals/-/signals-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-vz37r8lemGpPzDiBRfqpXYBynzmy3SFnY6zfHsTZABTYYt0b0WQZyU5mFDqqqugGhka78Gy11xmr9csgy4YgGA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/toolkit": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/toolkit/-/toolkit-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-1GKTLBNme1Phu/gFvgS9NWPq+LhPfzSIfnwhcF9I/6tCdufrLRcVaSMRiK9R4VDYD6iZUyj+a2l250qWAxxjQQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/transformers": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/transformers/-/transformers-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-wqXXOukhEjZKhzdq5vG1LkxWL11DApbmUKzk+3nA/ki3TLyD3awVTOXbpoNdOwFl2xliIooYcsUOEl4WCyyLGw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@telegram-apps/toolkit": "^2.0.0",
|
||||||
|
"@telegram-apps/types": "^2.0.0",
|
||||||
|
"valibot": "1.0.0-beta.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@telegram-apps/types": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@telegram-apps/types/-/types-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-yF499FJK82a2IDNDAQdrmVH3sgFZl/QFNdVZKgWpgtunIVJ1fres5wi9+4aUBRVIdQwZOZZqB/AOvYYuYXsq3Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@ton/core": {
|
||||||
|
"version": "0.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ton/core/-/core-0.59.1.tgz",
|
||||||
|
"integrity": "sha512-SxFBAvutYJaIllTkv82vbHTJhJI6NxzqUhi499CDEjJEZ9i6i9lHJiK2df4dlLAb/4SiWX6+QUzESkK4DEdnCw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"symbol.inspect": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@ton/crypto": ">=3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ton/crypto": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ton/crypto/-/crypto-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-/A6CYGgA/H36OZ9BbTaGerKtzWp50rg67ZCH2oIjV1NcrBaCK9Z343M+CxedvM7Haf3f/Ee9EhxyeTp0GKMUpA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@ton/crypto-primitives": "2.1.0",
|
||||||
|
"jssha": "3.2.0",
|
||||||
|
"tweetnacl": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ton/crypto-primitives": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ton/crypto-primitives/-/crypto-primitives-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-PQesoyPgqyI6vzYtCXw4/ZzevePc4VGcJtFwf08v10OevVJHVfW238KBdpj1kEDQkxWLeuNHEpTECNFKnP6tow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"jssha": "3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ton/crypto-primitives/node_modules/jssha": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ton/crypto/node_modules/jssha": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tonconnect/isomorphic-eventsource": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tonconnect/isomorphic-eventsource/-/isomorphic-eventsource-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-B4UoIjPi0QkvIzZH5fV3BQLWrqSYABdrzZQSI9sJA9aA+iC0ohOzFwVVGXanlxeDAy1bcvPbb29f6sVUk0UnnQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"eventsource": "^2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tonconnect/isomorphic-fetch": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tonconnect/isomorphic-fetch/-/isomorphic-fetch-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-jIg5nTrDwnite4fXao3dD83eCpTvInTjZon/rZZrIftIegh4XxyVb5G2mpMqXrVGk1e8SVXm3Kj5OtfMplQs0w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"node-fetch": "^2.6.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tonconnect/protocol": {
|
||||||
|
"version": "2.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tonconnect/protocol/-/protocol-2.2.6.tgz",
|
||||||
|
"integrity": "sha512-kyoDz5EqgsycYP+A+JbVsAUYHNT059BCrK+m0pqxykMODwpziuSAXfwAZmHcg8v7NB9VKYbdFY55xKeXOuEd0w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": "^1.0.3",
|
||||||
|
"tweetnacl-util": "^0.15.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tonconnect/sdk": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tonconnect/sdk/-/sdk-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-dJipe0Cw43p/7o3Pa6Y6h0QMDtY2V2YKzwdCqcYvmyCYadBNmvA+8ScH9QK5GpkngRJnYaWq+321lAaQTFpUwA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tonconnect/isomorphic-eventsource": "^0.0.2",
|
||||||
|
"@tonconnect/isomorphic-fetch": "^0.0.3",
|
||||||
|
"@tonconnect/protocol": "^2.2.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tonconnect/ui": {
|
||||||
|
"version": "2.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tonconnect/ui/-/ui-2.0.11.tgz",
|
||||||
|
"integrity": "sha512-5TOhfEDeyY8R9oyEGavLU+DRmDW3wSGyxVshWhHisi8597cZIuG39HHNbP05WJBBjmVm/Kh/bhcHtfx7lQp/Ig==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tonconnect/sdk": "3.0.6",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
|
"csstype": "^3.1.1",
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"ua-parser-js": "^1.0.35"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tonconnect/ui-react": {
|
||||||
|
"version": "2.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tonconnect/ui-react/-/ui-react-2.0.11.tgz",
|
||||||
|
"integrity": "sha512-h8E4zlbdNBJCAPgg6+O5ZkVDZh8mvnc82VRmhInSPLFAr6qDZbE+qSjRVm4lkuN1N/m24lhkDXFCFjvJ9CgCow==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tonconnect/ui": "2.0.11"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=17.0.0",
|
||||||
|
"react-dom": ">=17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||||
@@ -1344,11 +1689,26 @@
|
|||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash": {
|
||||||
|
"version": "4.17.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz",
|
||||||
|
"integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/lodash-es": {
|
||||||
|
"version": "4.17.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||||
|
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/lodash": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.11.24",
|
"version": "20.11.24",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz",
|
||||||
"integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==",
|
"integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
@@ -1916,6 +2276,35 @@
|
|||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/better-promises": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/better-promises/-/better-promises-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-AcKkTUSd4o1vMf41eBbHW1NkY7vrXeNI6etitGdQE54WFXsF2wkfonrKA06Za7lViRNyT/cMvj5z+DScqhYW8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"error-kid": "^0.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/big-integer": {
|
"node_modules/big-integer": {
|
||||||
"version": "1.6.52",
|
"version": "1.6.52",
|
||||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
||||||
@@ -2001,6 +2390,30 @@
|
|||||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||||
@@ -2108,6 +2521,12 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
|
||||||
@@ -2191,8 +2610,7 @@
|
|||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||||
"devOptional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
@@ -2296,6 +2714,18 @@
|
|||||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/dnd-core": {
|
||||||
|
"version": "14.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-14.0.1.tgz",
|
||||||
|
"integrity": "sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@react-dnd/asap": "^4.0.0",
|
||||||
|
"@react-dnd/invariant": "^2.0.0",
|
||||||
|
"redux": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/doctrine": {
|
"node_modules/doctrine": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||||
@@ -2326,6 +2756,12 @@
|
|||||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/error-kid": {
|
||||||
|
"version": "0.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/error-kid/-/error-kid-0.0.4.tgz",
|
||||||
|
"integrity": "sha512-x+yQhY56SorLMnX6kOf+z3JCv2QBurcWEDcIjgxYtVr4fGeCfAtOdZOCyWttkHHDFPtL2PqnaRUmphbmALJd9w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/es-abstract": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.22.5",
|
"version": "1.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz",
|
||||||
@@ -2957,11 +3393,19 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eventsource": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/fast-diff": {
|
"node_modules/fast-diff": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
@@ -3448,6 +3892,35 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hoist-non-react-statics": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"react-is": "^16.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||||
@@ -3928,6 +4401,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@@ -4047,6 +4526,12 @@
|
|||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mitt": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@@ -4096,6 +4581,26 @@
|
|||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"encoding": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"encoding": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.14",
|
"version": "2.0.14",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||||
@@ -4712,6 +5217,47 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-dnd": {
|
||||||
|
"version": "14.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-14.0.5.tgz",
|
||||||
|
"integrity": "sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@react-dnd/invariant": "^2.0.0",
|
||||||
|
"@react-dnd/shallowequal": "^2.0.0",
|
||||||
|
"dnd-core": "14.0.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/hoist-non-react-statics": ">= 3.3.1",
|
||||||
|
"@types/node": ">= 12",
|
||||||
|
"@types/react": ">= 16",
|
||||||
|
"react": ">= 16.14"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/hoist-non-react-statics": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-dnd-html5-backend": {
|
||||||
|
"version": "14.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz",
|
||||||
|
"integrity": "sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"dnd-core": "14.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
@@ -4828,6 +5374,33 @@
|
|||||||
"react-dom": ">=16.8"
|
"react-dom": ">=16.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-tag-input": {
|
||||||
|
"version": "6.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-tag-input/-/react-tag-input-6.10.3.tgz",
|
||||||
|
"integrity": "sha512-IVneBnT0/7N8FktHsFUA2UVDvcwLSJoWDTdEm/Ei/r5O6iBABaVw1RMh6SlG+P7oummvzSY6EBjGCXr/Ntq8rQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"classnames": "~2.3.1",
|
||||||
|
"lodash-es": "^4.17.21"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/ad1992"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dnd": "^14.0.2",
|
||||||
|
"react-dnd-html5-backend": "^14.0.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-tag-input/node_modules/classnames": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-1inzZmicIFcmUya7PGtUQeXtcF7zZpPnxtQoYOrz0uiOBGlLFa4ik4361seYL2JCcRDIyfdFHiwQolESFlw+Og==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@@ -4849,6 +5422,16 @@
|
|||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redux": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
@@ -5383,6 +5966,12 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/symbol.inspect": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/symbol.inspect/-/symbol.inspect-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-YQSL4duoHmLhsTD1Pw8RW6TZ5MaTX5rXJnqacJottr2P2LZBF/Yvrc3ku4NUpMOm8aM0KOCqM+UAkMA5HWQCzQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/synckit": {
|
"node_modules/synckit": {
|
||||||
"version": "0.8.8",
|
"version": "0.8.8",
|
||||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
|
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
|
||||||
@@ -5496,6 +6085,12 @@
|
|||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ts-api-utils": {
|
"node_modules/ts-api-utils": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz",
|
||||||
@@ -5564,6 +6159,18 @@
|
|||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
|
"node_modules/tweetnacl-util": {
|
||||||
|
"version": "0.15.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz",
|
||||||
|
"integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
@@ -5665,7 +6272,7 @@
|
|||||||
"version": "5.3.3",
|
"version": "5.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||||
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -5674,6 +6281,32 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ua-parser-js": {
|
||||||
|
"version": "1.0.40",
|
||||||
|
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz",
|
||||||
|
"integrity": "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ua-parser-js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paypal",
|
||||||
|
"url": "https://paypal.me/faisalman"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/faisalman"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"ua-parser-js": "script/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unbox-primitive": {
|
"node_modules/unbox-primitive": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
|
||||||
@@ -5693,7 +6326,7 @@
|
|||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
"dev": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/unload": {
|
"node_modules/unload": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
@@ -5757,6 +6390,20 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/valibot": {
|
||||||
|
"version": "1.0.0-beta.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.14.tgz",
|
||||||
|
"integrity": "sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=5"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.1.4",
|
"version": "5.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz",
|
||||||
@@ -5831,6 +6478,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
@@ -11,8 +11,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.3.4",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
|
"@sentry/react": "^9.1.0",
|
||||||
|
"@telegram-apps/sdk": "^3.5.1",
|
||||||
|
"@ton/core": "^0.59.1",
|
||||||
|
"@tonconnect/ui-react": "^2.0.2",
|
||||||
"@vkruglikov/react-telegram-web-app": "^2.1.9",
|
"@vkruglikov/react-telegram-web-app": "^2.1.9",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -20,6 +25,7 @@
|
|||||||
"react-player": "^2.15.1",
|
"react-player": "^2.15.1",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.22.2",
|
"react-router-dom": "^6.22.2",
|
||||||
|
"react-tag-input": "^6.10.3",
|
||||||
"tailwind-merge": "^2.2.1",
|
"tailwind-merge": "^2.2.1",
|
||||||
"zod": "^3.22.4",
|
"zod": "^3.22.4",
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
+12
-8
@@ -1,26 +1,30 @@
|
|||||||
import "~/app/styles/globals.css";
|
import '~/app/styles/globals.css';
|
||||||
|
import '~/shared/libs/buffer';
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from 'react';
|
||||||
import { useExpand, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
import { useExpand, useWebApp } from '@vkruglikov/react-telegram-web-app';
|
||||||
|
|
||||||
import { Providers } from "~/app/providers";
|
|
||||||
import { AppRouter } from "~/app/router";
|
|
||||||
|
|
||||||
|
import { Providers } from '~/app/providers';
|
||||||
|
import { AppRouter } from '~/app/router';
|
||||||
|
import { Notification } from '~/shared/ui/notification';
|
||||||
|
import { init } from '@telegram-apps/sdk';
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
const WebApp = useWebApp();
|
const WebApp = useWebApp();
|
||||||
const [, expand] = useExpand();
|
const [, expand] = useExpand();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
init();
|
||||||
WebApp.enableClosingConfirmation();
|
WebApp.enableClosingConfirmation();
|
||||||
expand();
|
expand();
|
||||||
|
|
||||||
WebApp.setHeaderColor("#1d1d1b");
|
WebApp.setHeaderColor('#1d1d1b');
|
||||||
WebApp.setBackgroundColor("#1d1d1b");
|
WebApp.setBackgroundColor('#1d1d1b');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Providers>
|
<Providers>
|
||||||
<AppRouter />
|
<AppRouter />
|
||||||
|
<Notification />
|
||||||
</Providers>
|
</Providers>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { QueryClientProvider } from "react-query";
|
import { QueryClientProvider } from "react-query";
|
||||||
import { WebAppProvider } from "@vkruglikov/react-telegram-web-app";
|
import { WebAppProvider } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
import { TonConnectUIProvider } from "@tonconnect/ui-react";
|
||||||
|
|
||||||
import { queryClient } from "~/shared/libs";
|
import { queryClient } from "~/shared/libs";
|
||||||
|
|
||||||
@@ -11,9 +12,15 @@ type ProvidersProps = {
|
|||||||
export const Providers = ({ children }: ProvidersProps) => {
|
export const Providers = ({ children }: ProvidersProps) => {
|
||||||
return (
|
return (
|
||||||
<WebAppProvider options={{ smoothButtonsTransition: true }}>
|
<WebAppProvider options={{ smoothButtonsTransition: true }}>
|
||||||
|
<TonConnectUIProvider
|
||||||
|
manifestUrl={
|
||||||
|
"https://my-public-node-1.projscale.dev/api/tonconnect-manifest.json"
|
||||||
|
}
|
||||||
|
>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<main className="antialiased">{children}</main>
|
<main className="antialiased">{children}</main>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
</TonConnectUIProvider>
|
||||||
</WebAppProvider>
|
</WebAppProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
export const Routes = {
|
export const Routes = {
|
||||||
Root: "/uploadContent",
|
Root: "/uploadContent",
|
||||||
|
ViewContent: "/viewContent",
|
||||||
|
SentryCheck: "/sentryCheck",
|
||||||
};
|
};
|
||||||
@@ -2,9 +2,33 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
|||||||
|
|
||||||
import { Routes } from "~/app/router/constants";
|
import { Routes } from "~/app/router/constants";
|
||||||
import { RootPage } from "~/pages/root";
|
import { RootPage } from "~/pages/root";
|
||||||
|
import { ViewContentPage } from "~/pages/view-content";
|
||||||
|
import { ProtectedLayout } from "./protected-layout";
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
|
{
|
||||||
|
element: <ProtectedLayout />,
|
||||||
|
children: [
|
||||||
{ path: Routes.Root, element: <RootPage /> },
|
{ path: Routes.Root, element: <RootPage /> },
|
||||||
|
{ path: Routes.ViewContent, element: <ViewContentPage /> },
|
||||||
|
{
|
||||||
|
path: Routes.SentryCheck,
|
||||||
|
element: (
|
||||||
|
<div className="flex h-screen items-center justify-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-primary border bg-red-900 p-2"
|
||||||
|
onClick={() => {
|
||||||
|
throw new Error("Sentry Test Error");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sentry Test Error
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const AppRouter = () => {
|
export const AppRouter = () => {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
import { useAuthTwa } from '~/shared/services/authTwa';
|
||||||
|
|
||||||
|
export const ProtectedLayout = () => {
|
||||||
|
const auth = useAuthTwa();
|
||||||
|
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
void auth.mutateAsync().finally(() => {
|
||||||
|
setIsInitialLoad(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isInitialLoad || auth.isLoading) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Outlet />;
|
||||||
|
};
|
||||||
@@ -22,4 +22,121 @@
|
|||||||
a {
|
a {
|
||||||
@apply transition-all active:opacity-60;
|
@apply transition-all active:opacity-60;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Input Range*/
|
||||||
|
/* Custom styles for the range input */
|
||||||
|
input[type="range"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
/* Remove default appearance */
|
||||||
|
width: 100%;
|
||||||
|
/* Full width */
|
||||||
|
height: 2px;
|
||||||
|
/* Track height */
|
||||||
|
background: linear-gradient(to right,
|
||||||
|
white 0%,
|
||||||
|
/* Start color of passed track */
|
||||||
|
white var(--value-percentage, 0%),
|
||||||
|
/* End color of passed track */
|
||||||
|
gray var(--value-percentage, 0%),
|
||||||
|
/* Start color of remaining track */
|
||||||
|
gray 100%
|
||||||
|
/* End color of remaining track */
|
||||||
|
);
|
||||||
|
border-radius: 9999px;
|
||||||
|
/* Rounded-full track */
|
||||||
|
outline: none;
|
||||||
|
/* Remove outline */
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the thumb (toggle) */
|
||||||
|
input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 9px;
|
||||||
|
/* Thumb width */
|
||||||
|
height: 9px;
|
||||||
|
/* Thumb height */
|
||||||
|
background: #fff;
|
||||||
|
/* Thumb color (blue-500) */
|
||||||
|
border-radius: 9999px;
|
||||||
|
/* Rounded-full thumb */
|
||||||
|
cursor: pointer;
|
||||||
|
/* Pointer cursor on hover */
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For Firefox */
|
||||||
|
input[type="range"]::-moz-range-thumb {
|
||||||
|
appearance: none;
|
||||||
|
width: 9px;
|
||||||
|
/* Thumb width */
|
||||||
|
height: 9px;
|
||||||
|
/* Thumb height */
|
||||||
|
background: #fff;
|
||||||
|
/* Thumb color (blue-500) */
|
||||||
|
border-radius: 9999px;
|
||||||
|
/* Rounded-full thumb */
|
||||||
|
cursor: pointer;
|
||||||
|
/* Pointer cursor on hover */
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="range"]::-moz-range-track {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
/* Remove default appearance */
|
||||||
|
width: 100%;
|
||||||
|
/* Full width */
|
||||||
|
height: 2px;
|
||||||
|
/* Track height */
|
||||||
|
background: linear-gradient(to right,
|
||||||
|
white 0%,
|
||||||
|
/* Start color of passed track */
|
||||||
|
white var(--value-percentage, 0%),
|
||||||
|
/* End color of passed track */
|
||||||
|
gray var(--value-percentage, 0%),
|
||||||
|
/* Start color of remaining track */
|
||||||
|
gray 100%
|
||||||
|
/* End color of remaining track */
|
||||||
|
);
|
||||||
|
border-radius: 9999px;
|
||||||
|
/* Rounded-full track */
|
||||||
|
outline: none;
|
||||||
|
/* Remove outline */
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* English comment: override react-tag-input classes */
|
||||||
|
.ReactTags__tagInputField {
|
||||||
|
@apply bg-[#2B2B2B] outline-none w-full h-8 text-sm !important;
|
||||||
|
@apply border border-white px-[10px] py-[18px] !important;
|
||||||
|
@apply whitespace-pre !important;
|
||||||
|
/* English comment:
|
||||||
|
'bg-transparent' to blend with your dark background
|
||||||
|
'text-white' to have white text
|
||||||
|
'placeholder:text-gray-400' to see the placeholder text in a lighter gray
|
||||||
|
'outline-none' to remove default borders
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* English comment: style for the tag itself when it's rendered */
|
||||||
|
.ReactTags__selected .ReactTags__tag {
|
||||||
|
@apply bg-[#363636] text-white text-sm inline-flex items-center px-2 py-1 mb-2 rounded mr-1 !important;
|
||||||
|
/* English comment:
|
||||||
|
'bg-[#363636]' to have a dark gray background
|
||||||
|
'text-white' keeps the text white
|
||||||
|
'text-sm' smaller text
|
||||||
|
'inline-flex items-center' for better alignment
|
||||||
|
'px-2 py-1 rounded mr-1' for spacing and rounding
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.ReactTags__selected .ReactTags__remove {
|
||||||
|
@apply ml-1 text-gray hover:text-white cursor-pointer !important;
|
||||||
|
/* English comment:
|
||||||
|
'ml-1' a small margin to separate the 'x' or close symbol
|
||||||
|
'text-gray-400' by default, and change to white on hover
|
||||||
|
'cursor-pointer' so it looks clickable
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import './shared/services/sentry/index.ts';
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
-1
@@ -1,7 +1,12 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_API_BASE_URL: string;
|
readonly VITE_SENTRY_DSN: string
|
||||||
|
readonly VITE_API_BASE_URL: string
|
||||||
|
readonly VITE_API_BASE_STORAGE_URL: string
|
||||||
|
readonly MODE: 'development' | 'production'
|
||||||
|
readonly PROD: boolean
|
||||||
|
readonly DEV: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { WelcomeStep } from "./steps/welcome-step";
|
|
||||||
import { DataStep } from "./steps/data-step";
|
import { DataStep } from "./steps/data-step";
|
||||||
import { RoyaltyStep } from "./steps/royalty-step";
|
import { RoyaltyStep } from "./steps/royalty-step";
|
||||||
import { PresubmitStep } from "./steps/presubmit-step";
|
import { PresubmitStep } from "./steps/presubmit-step";
|
||||||
|
|
||||||
import { useSteps } from "~/shared/hooks/use-steps";
|
import { useSteps } from "~/shared/hooks/use-steps";
|
||||||
import { PriceStep } from "~/pages/root/steps/price-step";
|
import { PriceStep } from "~/pages/root/steps/price-step";
|
||||||
|
import { WelcomeStep } from "~/pages/root/steps/welcome-step";
|
||||||
|
|
||||||
export const RootPage = () => {
|
export const RootPage = () => {
|
||||||
const { ActiveSection } = useSteps(({ nextStep, prevStep }) => {
|
const { ActiveSection } = useSteps(({ nextStep, prevStep }) => {
|
||||||
return [
|
return [
|
||||||
<WelcomeStep nextStep={nextStep} />,
|
<WelcomeStep nextStep={nextStep} />,
|
||||||
<DataStep prevStep={prevStep} nextStep={nextStep} />,
|
<DataStep nextStep={nextStep} />,
|
||||||
// <AuthorsStep prevStep={prevStep} nextStep={nextStep} />,
|
// <AuthorsStep prevStep={prevStep} nextStep={nextStep} />,
|
||||||
<RoyaltyStep prevStep={prevStep} nextStep={nextStep} />,
|
<RoyaltyStep prevStep={prevStep} nextStep={nextStep} />,
|
||||||
<PriceStep prevStep={prevStep} nextStep={nextStep} />,
|
<PriceStep prevStep={prevStep} nextStep={nextStep} />,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useHapticFeedback } from "@vkruglikov/react-telegram-web-app";
|
import { useHapticFeedback } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
import { Replace } from "~/shared/ui/icons/replace";
|
||||||
import { XMark } from "~/shared/ui/icons/x-mark.tsx";
|
|
||||||
|
|
||||||
type CoverButtonProps = {
|
type CoverButtonProps = {
|
||||||
src: string;
|
src: string;
|
||||||
@@ -36,8 +35,8 @@ export const CoverButton = ({ src, onClick }: CoverButtonProps) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div />
|
<div />
|
||||||
<div className={"flex gap-2 text-sm"}>Удалить</div>
|
<div className={"flex gap-2 text-sm"}>Изменить</div>
|
||||||
<XMark />
|
<Replace />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { useHapticFeedback, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Button } from "~/shared/ui/button";
|
||||||
|
|
||||||
|
type DisclaimerModalProps = {
|
||||||
|
onConfirm(): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DisclaimerModal = ({
|
||||||
|
onConfirm,
|
||||||
|
}: DisclaimerModalProps) => {
|
||||||
|
const [impactOccurred] = useHapticFeedback();
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
useEffect(() => {
|
||||||
|
// Отключаем вертикальные свайпы при монтировании компонента
|
||||||
|
if (WebApp && WebApp.disableVerticalSwipes) {
|
||||||
|
WebApp.disableVerticalSwipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Включаем вертикальные свайпы обратно при размонтировании
|
||||||
|
return () => {
|
||||||
|
if (WebApp && WebApp.enableVerticalSwipes) {
|
||||||
|
WebApp.enableVerticalSwipes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClick = (fn: () => void) => {
|
||||||
|
impactOccurred("light");
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"fixed left-0 top-0 z-30 flex h-full w-full items-center justify-center bg-black/80 px-[15px]"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={"flex flex-col max-h-[80vh] w-[85vw] max-w-md"}>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"border border-white bg-[#1D1D1B] px-[15px] py-[16px] text-start flex flex-col gap-12 h-full overflow-y-auto"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col gap-6">
|
||||||
|
<p className="mt-2">
|
||||||
|
Внимание!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
MY снимает с себя ответственность за правомерность загрузки контента пользователем.
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
<span className="tracking-[.25em] w-full">
|
||||||
|
Сервис исходит из личной
|
||||||
|
</span>
|
||||||
|
ответственности пользователя перед законом и третьими лицами. MY категорически не приемлет любые виды пиратства, но признает за Пользователем право принятия самостоятельных решений.
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
<span className="tracking-[.25em] w-full">
|
||||||
|
Перед загрузкой контента
|
||||||
|
</span>
|
||||||
|
необходимо убедиться, что первые 30 секунд контента, которые будут использоваться для превью, не содержат материалов, нарушающих возрастное ограничение 18+
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={"mt-[20px] sticky bottom-0"}
|
||||||
|
label={"Принять и продолжить"}
|
||||||
|
includeArrows={false}
|
||||||
|
onClick={() => handleClick(onConfirm)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMemo } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -12,19 +12,23 @@ import { CoverButton } from "~/pages/root/steps/data-step/components/cover-butto
|
|||||||
import { HiddenFileInput } from "~/shared/ui/hidden-file-input";
|
import { HiddenFileInput } from "~/shared/ui/hidden-file-input";
|
||||||
import { useRootStore } from "~/shared/stores/root";
|
import { useRootStore } from "~/shared/stores/root";
|
||||||
import { Checkbox } from "~/shared/ui/checkbox";
|
import { Checkbox } from "~/shared/ui/checkbox";
|
||||||
import { BackButton } from "~/shared/ui/back-button";
|
import { AudioPlayer } from "~/shared/ui/audio-player";
|
||||||
|
import { HashtagInput } from "~/shared/ui/hashtag-input";
|
||||||
|
import { Replace } from "~/shared/ui/icons/replace";
|
||||||
|
import { DisclaimerModal } from "./components/disclaimer-modal";
|
||||||
|
|
||||||
type DataStepProps = {
|
type DataStepProps = {
|
||||||
prevStep(): void;
|
|
||||||
nextStep(): void;
|
nextStep(): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
export const DataStep = ({ nextStep }: DataStepProps) => {
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
const [disclaimerAccepted, setDisclaimerAccepted] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
const formSchema = useMemo(() => {
|
const formSchema = useMemo(() => {
|
||||||
return z.object({
|
return z.object({
|
||||||
name: z.string().min(1),
|
name: z.string().min(1, "Обязательное поле"),
|
||||||
author: z.string().optional(),
|
author: z.string().optional(),
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -57,9 +61,33 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
})();
|
})();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFileReset = () => {
|
||||||
|
rootStore.setFile(null);
|
||||||
|
rootStore.setFileSrc('');
|
||||||
|
rootStore.setFileType('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const storedValue = localStorage.getItem('disclaimerAccepted');
|
||||||
|
if (storedValue === 'true') {
|
||||||
|
setDisclaimerAccepted(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleConfirmDisclaimer = () => {
|
||||||
|
setDisclaimerAccepted(true);
|
||||||
|
localStorage.setItem('disclaimerAccepted', 'true');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={"mt-4 px-4 pb-8"}>
|
<section className={"mt-4 px-4 pb-8"}>
|
||||||
<BackButton onClick={prevStep} />
|
|
||||||
|
{(rootStore.fileSrc && !disclaimerAccepted) &&
|
||||||
|
(<DisclaimerModal
|
||||||
|
onConfirm={() => {
|
||||||
|
handleConfirmDisclaimer()}}
|
||||||
|
/>)}
|
||||||
|
|
||||||
<div className={"mb-[30px] flex flex-col text-sm"}>
|
<div className={"mb-[30px] flex flex-col text-sm"}>
|
||||||
<span className={"ml-4"}>/Заполните информацию о контенте</span>
|
<span className={"ml-4"}>/Заполните информацию о контенте</span>
|
||||||
@@ -72,6 +100,7 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
<FormLabel label={"Название"}>
|
<FormLabel label={"Название"}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={"[ Введите название ]"}
|
placeholder={"[ Введите название ]"}
|
||||||
|
error={form.formState.errors?.name}
|
||||||
{...form.register("name")}
|
{...form.register("name")}
|
||||||
/>
|
/>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
@@ -79,11 +108,17 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
<FormLabel label={"Имя автора/исполнителя"}>
|
<FormLabel label={"Имя автора/исполнителя"}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={"[ введите имя автора/исполнителя ]"}
|
placeholder={"[ введите имя автора/исполнителя ]"}
|
||||||
|
error={form.formState.errors?.author}
|
||||||
{...form.register("author")}
|
{...form.register("author")}
|
||||||
/>
|
/>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormLabel label={"Хэштеги"}>
|
||||||
|
<HashtagInput />
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormLabel label={"Файл"}>
|
<FormLabel label={"Файл"}>
|
||||||
|
{!rootStore.fileSrc && <>
|
||||||
<HiddenFileInput
|
<HiddenFileInput
|
||||||
id={"file"}
|
id={"file"}
|
||||||
shouldProcess={false}
|
shouldProcess={false}
|
||||||
@@ -91,10 +126,12 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
onChange={(file) => {
|
onChange={(file) => {
|
||||||
rootStore.setFile(file);
|
rootStore.setFile(file);
|
||||||
rootStore.setFileSrc(URL.createObjectURL(file));
|
rootStore.setFileSrc(URL.createObjectURL(file));
|
||||||
|
rootStore.setFileType(file.type); // Save the file type for conditional rendering
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!rootStore.fileSrc && <FileButton htmlFor={"file"} />}
|
<FileButton htmlFor={"file"} />
|
||||||
|
</>}
|
||||||
|
|
||||||
{rootStore.fileSrc && (
|
{rootStore.fileSrc && (
|
||||||
<div
|
<div
|
||||||
@@ -102,17 +139,42 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
"w-full border border-white bg-[#2B2B2B] px-[10px] py-[8px] text-sm"
|
"w-full border border-white bg-[#2B2B2B] px-[10px] py-[8px] text-sm"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{rootStore.fileType?.startsWith("audio") ? (
|
||||||
|
<AudioPlayer src={rootStore.fileSrc} />
|
||||||
|
) : (
|
||||||
<ReactPlayer
|
<ReactPlayer
|
||||||
playsinline={true}
|
playsinline={true}
|
||||||
controls={true}
|
controls={true}
|
||||||
width={"100%"}
|
width="100%"
|
||||||
|
config={{ file: { attributes: { playsInline: true } } }}
|
||||||
url={rootStore.fileSrc}
|
url={rootStore.fileSrc}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={handleFileReset}
|
||||||
|
className={
|
||||||
|
"flex w-full items-center justify-between gap-1 border border-white px-[10px] py-[8px]"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
<div className={"flex gap-2 text-sm"}>Изменить выбор</div>
|
||||||
|
<Replace />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<div className={"flex flex-col gap-2"}>
|
<div className={"flex flex-col gap-2"}>
|
||||||
|
<FormLabel
|
||||||
|
label={"Разрешить скачивание"}
|
||||||
|
labelClassName={"flex"}
|
||||||
|
formLabelAddon={
|
||||||
|
<Checkbox
|
||||||
|
onClick={() => rootStore.setAllowDwnld(!rootStore.allowDwnld)}
|
||||||
|
checked={rootStore.allowDwnld}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<FormLabel
|
<FormLabel
|
||||||
label={"Разрешить обложку"}
|
label={"Разрешить обложку"}
|
||||||
labelClassName={"flex"}
|
labelClassName={"flex"}
|
||||||
@@ -126,13 +188,7 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
|
|
||||||
{rootStore.allowCover && (
|
{rootStore.allowCover && (
|
||||||
<FormLabel label={"Обложка"}>
|
<FormLabel label={"Обложка"}>
|
||||||
<HiddenFileInput
|
|
||||||
id={"cover"}
|
|
||||||
accept={"image/*"}
|
|
||||||
onChange={(cover) => {
|
|
||||||
rootStore.setCover(cover);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{rootStore.cover ? (
|
{rootStore.cover ? (
|
||||||
<CoverButton
|
<CoverButton
|
||||||
@@ -142,7 +198,16 @@ export const DataStep = ({ nextStep, prevStep }: DataStepProps) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
|
<HiddenFileInput
|
||||||
|
id={"cover"}
|
||||||
|
accept={"image/*"}
|
||||||
|
onChange={(cover) => {
|
||||||
|
rootStore.setCover(cover);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<FileButton htmlFor={"cover"} />
|
<FileButton htmlFor={"cover"} />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { useHapticFeedback, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Button } from "~/shared/ui/button";
|
||||||
|
|
||||||
|
type ErrorUploadProps = {
|
||||||
|
onConfirm(): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ErrorUploadModal = ({
|
||||||
|
onConfirm,
|
||||||
|
}: ErrorUploadProps) => {
|
||||||
|
const [impactOccurred] = useHapticFeedback();
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
useEffect(() => {
|
||||||
|
// Отключаем вертикальные свайпы при монтировании компонента
|
||||||
|
if (WebApp && WebApp.disableVerticalSwipes) {
|
||||||
|
WebApp.disableVerticalSwipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Включаем вертикальные свайпы обратно при размонтировании
|
||||||
|
return () => {
|
||||||
|
if (WebApp && WebApp.enableVerticalSwipes) {
|
||||||
|
WebApp.enableVerticalSwipes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClick = (fn: () => void) => {
|
||||||
|
impactOccurred("light");
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"fixed left-0 top-0 z-30 flex h-full w-full items-center justify-center bg-black/80 px-[15px]"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={"flex flex-col max-h-[80vh] w-[85vw] max-w-md"}>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"border border-white bg-[#1D1D1B] px-[15px] py-[16px] text-start flex flex-col gap-12 h-full overflow-y-auto"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col gap-6">
|
||||||
|
<p className="mt-2">
|
||||||
|
Внимание!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Произошла ошибка при загрузке видео.
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
<span className="tracking-[.25em] w-full">
|
||||||
|
Загрузка не завершена
|
||||||
|
</span>
|
||||||
|
из-за технических проблем или превышения допустимых ограничений. Вы можете попробовать загрузить файл ещё раз или выбрать другой файл.
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
<span className="tracking-[.25em] w-full">
|
||||||
|
Если проблема повторяется
|
||||||
|
</span>
|
||||||
|
обратитесь в техническую поддержку сервиса MY, предоставив подробную информацию о загружаемом файле и возникшей ошибке.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={"mt-[20px] sticky bottom-0"}
|
||||||
|
label={"Понятно"}
|
||||||
|
includeArrows={false}
|
||||||
|
onClick={() => handleClick(onConfirm)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
useHapticFeedback,
|
useHapticFeedback,
|
||||||
useWebApp,
|
useWebApp,
|
||||||
} from "@vkruglikov/react-telegram-web-app";
|
} from "@vkruglikov/react-telegram-web-app";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ReactPlayer from "react-player/lazy";
|
import ReactPlayer from "react-player/lazy";
|
||||||
|
|
||||||
import { Button } from "~/shared/ui/button";
|
import { Button } from "~/shared/ui/button";
|
||||||
@@ -12,6 +12,10 @@ import { useUploadFile } from "~/shared/services/file";
|
|||||||
import { Progress } from "~/shared/ui/progress";
|
import { Progress } from "~/shared/ui/progress";
|
||||||
import { useCreateNewContent } from "~/shared/services/content";
|
import { useCreateNewContent } from "~/shared/services/content";
|
||||||
import { BackButton } from "~/shared/ui/back-button";
|
import { BackButton } from "~/shared/ui/back-button";
|
||||||
|
import { useTonConnectUI } from "@tonconnect/ui-react";
|
||||||
|
import { ErrorUploadModal } from "./components/error-upload-modal";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type PresubmitStepProps = {
|
type PresubmitStepProps = {
|
||||||
prevStep(): void;
|
prevStep(): void;
|
||||||
@@ -20,6 +24,8 @@ type PresubmitStepProps = {
|
|||||||
export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
||||||
const WebApp = useWebApp();
|
const WebApp = useWebApp();
|
||||||
|
|
||||||
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
|
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
const [impactOccurred] = useHapticFeedback();
|
const [impactOccurred] = useHapticFeedback();
|
||||||
|
|
||||||
@@ -30,6 +36,20 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||||||
|
|
||||||
const createContent = useCreateNewContent();
|
const createContent = useCreateNewContent();
|
||||||
|
|
||||||
|
const [isErrorUploadModal, setIsErrorUploadModal] = useState(false);
|
||||||
|
|
||||||
|
const handleErrorUploadModal = () => {
|
||||||
|
setIsErrorUploadModal(false);
|
||||||
|
uploadFile.resetUploadError();
|
||||||
|
uploadCover.resetUploadError();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (uploadFile.uploadError || uploadCover.uploadError) {
|
||||||
|
setIsErrorUploadModal(true);
|
||||||
|
}
|
||||||
|
}, [uploadFile.uploadError, uploadCover.uploadError]);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
let coverUploadResult = { content_id_v1: "" };
|
let coverUploadResult = { content_id_v1: "" };
|
||||||
@@ -44,7 +64,7 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await createContent.mutateAsync({
|
const createContentResponse = await createContent.mutateAsync({
|
||||||
title: rootStore.name,
|
title: rootStore.name,
|
||||||
|
|
||||||
// Это для одного автора
|
// Это для одного автора
|
||||||
@@ -55,11 +75,11 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||||||
// Откомментировать при условии того что вы принимаете много авторов
|
// Откомментировать при условии того что вы принимаете много авторов
|
||||||
// следует отметить что вы должны еще откомментровать AuthorsStep в RootPage
|
// следует отметить что вы должны еще откомментровать AuthorsStep в RootPage
|
||||||
// authors: rootStore.authors,
|
// authors: rootStore.authors,
|
||||||
|
downloadable: rootStore.allowDwnld,
|
||||||
content: fileUploadResult.content_id_v1,
|
content: fileUploadResult.content_id_v1,
|
||||||
image: coverUploadResult.content_id_v1,
|
image: coverUploadResult.content_id_v1,
|
||||||
price: String(rootStore.price * 10 ** 9),
|
price: String(rootStore.price * 10 ** 9),
|
||||||
|
hashtags: rootStore.hashtags,
|
||||||
royaltyParams: rootStore.royalty.map((member) => ({
|
royaltyParams: rootStore.royalty.map((member) => ({
|
||||||
...member,
|
...member,
|
||||||
value: member.value * 100,
|
value: member.value * 100,
|
||||||
@@ -78,15 +98,48 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||||||
: { allowResale: false, resaleLicensePrice: "0" }),
|
: { allowResale: false, resaleLicensePrice: "0" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (createContentResponse.data) {
|
||||||
|
if (createContentResponse.data.address != "free") {
|
||||||
|
const transactionResponse = await tonConnectUI.sendTransaction({
|
||||||
|
validUntil: Math.floor(Date.now() / 1000) + 120,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
amount: createContentResponse.data.amount,
|
||||||
|
address: createContentResponse.data.address,
|
||||||
|
payload: createContentResponse.data.payload,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
if (transactionResponse.boc) {
|
||||||
WebApp.close();
|
WebApp.close();
|
||||||
} catch (error) {
|
} else {
|
||||||
|
console.error("Transaction failed:", transactionResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WebApp.close();
|
||||||
|
// @ts-expect-error Type issues
|
||||||
|
} catch (error: never) {
|
||||||
|
|
||||||
|
|
||||||
console.error("An error occurred during the submission process:", error);
|
console.error("An error occurred during the submission process:", error);
|
||||||
alert(`Возникла ошибка, ${JSON.stringify(error)}`);
|
|
||||||
|
if (error?.status === 400) {
|
||||||
|
alert(
|
||||||
|
"Введенные данные неверные, проверьте правильность введенных данных.",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={"mt-4 px-4 pb-8"}>
|
<section className={"mt-4 px-4 pb-8"}>
|
||||||
|
{isErrorUploadModal && (
|
||||||
|
<ErrorUploadModal
|
||||||
|
onConfirm={() => {
|
||||||
|
handleErrorUploadModal()}}
|
||||||
|
/>)}
|
||||||
<BackButton onClick={prevStep} />
|
<BackButton onClick={prevStep} />
|
||||||
|
|
||||||
<div className={"mb-[30px] flex flex-col text-sm"}>
|
<div className={"mb-[30px] flex flex-col text-sm"}>
|
||||||
@@ -119,6 +172,24 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||||||
</FormLabel>
|
</FormLabel>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{rootStore.author && (
|
||||||
|
<FormLabel label={"Теги"}>
|
||||||
|
<div
|
||||||
|
className="flex flex-wrap gap-1">
|
||||||
|
{rootStore.hashtags.map((tag, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={
|
||||||
|
"bg-[#363636] text-white text-sm inline-flex items-center px-2 py-1 rounded mr-1"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</FormLabel>
|
||||||
|
)}
|
||||||
|
|
||||||
<FormLabel label={"Цена"}>
|
<FormLabel label={"Цена"}>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
@@ -151,7 +222,8 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||||||
<ReactPlayer
|
<ReactPlayer
|
||||||
playsinline={true}
|
playsinline={true}
|
||||||
controls={true}
|
controls={true}
|
||||||
width={"100%"}
|
width="100%"
|
||||||
|
config={{ file: { attributes: { playsInline: true } } }}
|
||||||
url={rootStore.fileSrc}
|
url={rootStore.fileSrc}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import { Button } from "~/shared/ui/button";
|
|||||||
import { useRootStore } from "~/shared/stores/root";
|
import { useRootStore } from "~/shared/stores/root";
|
||||||
import { BackButton } from "~/shared/ui/back-button";
|
import { BackButton } from "~/shared/ui/back-button";
|
||||||
|
|
||||||
const MIN_PRICE = 0.07;
|
const MIN_PRICE = 0.15;
|
||||||
const MIN_RESALE_PRICE = 0.07;
|
const MIN_RESALE_PRICE = 0.15;
|
||||||
|
|
||||||
const RECOMMENDED_PRICE = 0.15;
|
// const RECOMMENDED_PRICE = 0.15;
|
||||||
// const RECOMMENDED_RESALE_PRICE = 0.15;
|
// const RECOMMENDED_RESALE_PRICE = 0.15;
|
||||||
|
|
||||||
type PriceStepProps = {
|
type PriceStepProps = {
|
||||||
@@ -24,48 +24,31 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
|
||||||
const formSchema = useMemo(() => {
|
const formSchema = useMemo(() => {
|
||||||
|
const parsePrice = (value: unknown) => {
|
||||||
|
if (typeof value === "string" || typeof value === "number") {
|
||||||
|
const stringValue = value.toString().replace(",", ".");
|
||||||
|
const parsedValue = parseFloat(stringValue);
|
||||||
|
return isNaN(parsedValue) ? undefined : parsedValue;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
if (rootStore.allowResale) {
|
if (rootStore.allowResale) {
|
||||||
return z.object({
|
return z.object({
|
||||||
price: z.preprocess(
|
price: z.preprocess(
|
||||||
(value) => {
|
parsePrice,
|
||||||
const parsed = parseFloat(value as string);
|
z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`)
|
||||||
|
|
||||||
return isNaN(parsed) ? undefined : parsed;
|
|
||||||
},
|
|
||||||
z
|
|
||||||
.number()
|
|
||||||
.min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
resaleLicensePrice: z
|
resaleLicensePrice: z
|
||||||
.preprocess(
|
.preprocess(parsePrice, z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_RESALE_PRICE, `Цена копии должна быть минимум ${MIN_RESALE_PRICE} TON.`))
|
||||||
(value) => {
|
|
||||||
if (value === undefined || value === "" || value === 0)
|
|
||||||
return undefined;
|
|
||||||
|
|
||||||
const parsed = parseFloat(value as string);
|
|
||||||
return isNaN(parsed) ? undefined : parsed;
|
|
||||||
},
|
|
||||||
|
|
||||||
z
|
|
||||||
.number()
|
|
||||||
.min(
|
|
||||||
MIN_RESALE_PRICE,
|
|
||||||
`Цена копии должна быть минимум ${MIN_RESALE_PRICE} TON.`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return z.object({
|
return z.object({
|
||||||
price: z.preprocess(
|
price: z.preprocess(
|
||||||
(value) => {
|
parsePrice,
|
||||||
const parsed = parseFloat(value as string);
|
z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`)
|
||||||
|
|
||||||
return isNaN(parsed) ? undefined : parsed;
|
|
||||||
},
|
|
||||||
z.number().min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`),
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}, [rootStore.allowResale]);
|
}, [rootStore.allowResale]);
|
||||||
@@ -75,12 +58,10 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||||||
const form = useForm<FormValues>({
|
const form = useForm<FormValues>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
|
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
price: rootStore.price,
|
price: rootStore.price || MIN_PRICE,
|
||||||
|
|
||||||
//@ts-expect-error Fix typings
|
//@ts-expect-error Fix typings
|
||||||
resaleLicensePrice: rootStore?.licenseResalePrice,
|
resaleLicensePrice: rootStore?.licenseResalePrice || MIN_RESALE_PRICE,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -92,13 +73,11 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||||||
form.handleSubmit(async (values: FormValues) => {
|
form.handleSubmit(async (values: FormValues) => {
|
||||||
try {
|
try {
|
||||||
rootStore.setPrice(values.price);
|
rootStore.setPrice(values.price);
|
||||||
|
|
||||||
//@ts-expect-error Fix typings
|
//@ts-expect-error Fix typings
|
||||||
if (values?.resaleLicensePrice) {
|
if (values?.resaleLicensePrice) {
|
||||||
//@ts-expect-error Fix typings
|
//@ts-expect-error Fix typings
|
||||||
rootStore.setLicenseResalePrice(values?.resaleLicensePrice);
|
rootStore.setLicenseResalePrice(values?.resaleLicensePrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
nextStep();
|
nextStep();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error: ", error);
|
console.error("Error: ", error);
|
||||||
@@ -109,72 +88,34 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||||||
return (
|
return (
|
||||||
<section className={"mt-4 px-4 pb-8"}>
|
<section className={"mt-4 px-4 pb-8"}>
|
||||||
<BackButton onClick={prevStep} />
|
<BackButton onClick={prevStep} />
|
||||||
|
|
||||||
<div className={"mb-[30px] flex flex-col text-sm"}>
|
<div className={"mb-[30px] flex flex-col text-sm"}>
|
||||||
<span className={"ml-4"}>/Укажите цену</span>
|
<span className={"ml-4"}>/Укажите цену</span>
|
||||||
<div>
|
<div>
|
||||||
4/<span className={"text-[#7B7B7B]"}>5</span>
|
4/<span className={"text-[#7B7B7B]"}>5</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={"flex flex-col gap-[20px]"}>
|
<div className={"flex flex-col gap-[20px]"}>
|
||||||
<FormLabel label={"Цена TON"}>
|
<FormLabel label={"Цена продажи TON"}>
|
||||||
<div className={"my-2 flex flex-col gap-1.5"}>
|
<div className={"my-2 flex flex-col gap-1.5"}>
|
||||||
<p className={"text-xs"}>Минимальная стоимость {MIN_PRICE} TON.</p>
|
<p className={"text-xs"}>Минимальная стоимость {MIN_PRICE} TON.</p>
|
||||||
<p className={"text-xs"}>
|
{/* <p className={"text-xs"}>Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.</p> */}
|
||||||
Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
error={form.formState.errors?.price}
|
error={form.formState.errors?.price}
|
||||||
placeholder={"[ Введите цену ]"}
|
placeholder={"[ Введите цену ]"}
|
||||||
{...form.register("price")}
|
inputMode="decimal"
|
||||||
|
pattern="[0-9]*[.,]?[0-9]*"
|
||||||
|
{...form.register("price", {
|
||||||
|
onChange: (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
if (!/^\d*[.,]?\d*$/.test(value)) {
|
||||||
|
e.target.value = value.replace(/[^\d.,]/g, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
{/*<div className={"flex flex-col gap-2"}>*/}
|
|
||||||
{/* <FormLabel*/}
|
|
||||||
{/* labelClassName={"flex"}*/}
|
|
||||||
{/* label={"Разрешить копии"}*/}
|
|
||||||
{/* formLabelAddon={*/}
|
|
||||||
{/* <Checkbox*/}
|
|
||||||
{/* checked={rootStore.allowResale}*/}
|
|
||||||
{/* onClick={() => {*/}
|
|
||||||
{/* rootStore.setAllowResale(!rootStore.allowResale);*/}
|
|
||||||
{/* }}*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* }*/}
|
|
||||||
{/* />*/}
|
|
||||||
|
|
||||||
{/* {rootStore.allowResale && (*/}
|
|
||||||
{/* <FormLabel label={"Цена копии TON"}>*/}
|
|
||||||
{/* <div className={"my-2 flex flex-col gap-1.5"}>*/}
|
|
||||||
{/* <p className={"text-xs"}>*/}
|
|
||||||
{/* Это цена, по которой пользователи будут покупать и*/}
|
|
||||||
{/* перепродавать ваш контент.*/}
|
|
||||||
{/* </p>*/}
|
|
||||||
|
|
||||||
{/* <p className={"text-xs"}>*/}
|
|
||||||
{/* Минимальная стоимость {MIN_RESALE_PRICE} TON.*/}
|
|
||||||
{/* </p>*/}
|
|
||||||
{/* <p className={"text-xs"}>*/}
|
|
||||||
{/* Рекомендуемая стоимость {RECOMMENDED_RESALE_PRICE} TON.*/}
|
|
||||||
{/* </p>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
|
|
||||||
{/* <Input*/}
|
|
||||||
{/* //@ts-expect-error Fix typings*/}
|
|
||||||
{/* error={form.formState.errors?.resaleLicensePrice}*/}
|
|
||||||
{/* placeholder={"[ Введите цену копии ]"}*/}
|
|
||||||
{/* //@ts-expect-error Fix typings*/}
|
|
||||||
{/* {...form.register("resaleLicensePrice")}*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* </FormLabel>*/}
|
|
||||||
{/* )}*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className={"mt-[30px]"}
|
className={"mt-[30px]"}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useHapticFeedback } from "@vkruglikov/react-telegram-web-app";
|
import { useHapticFeedback } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
|
||||||
import { Input } from "~/shared/ui/input";
|
import { Input } from "~/shared/ui/input";
|
||||||
@@ -11,17 +11,31 @@ import { Spread } from "~/shared/ui/icons/spread.tsx";
|
|||||||
import { ConfirmModal } from "~/pages/root/steps/royalty-step/components/confirm-modal";
|
import { ConfirmModal } from "~/pages/root/steps/royalty-step/components/confirm-modal";
|
||||||
import { useRootStore } from "~/shared/stores/root";
|
import { useRootStore } from "~/shared/stores/root";
|
||||||
import { BackButton } from "~/shared/ui/back-button";
|
import { BackButton } from "~/shared/ui/back-button";
|
||||||
|
import { useTonConnectUI } from "@tonconnect/ui-react";
|
||||||
|
import { Address } from "@ton/core";
|
||||||
|
import { FieldError } from "react-hook-form";
|
||||||
|
|
||||||
type RoyaltyStepProps = {
|
type RoyaltyStepProps = {
|
||||||
prevStep(): void;
|
prevStep(): void;
|
||||||
nextStep(): void;
|
nextStep(): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isValidTonAddress = (address: string): boolean => {
|
||||||
|
try {
|
||||||
|
if (!address) return false;
|
||||||
|
Address.parse(address);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
||||||
const [impactOccurred] = useHapticFeedback();
|
const [impactOccurred] = useHapticFeedback();
|
||||||
|
|
||||||
const [isDeleteAllOpen, setDeleteAllOpen] = useState(false);
|
const [isDeleteAllOpen, setDeleteAllOpen] = useState(false);
|
||||||
const [isSpreadOpen, setSpreadOpen] = useState(false);
|
const [isSpreadOpen, setSpreadOpen] = useState(false);
|
||||||
|
const [addressErrors, setAddressErrors] = useState<Record<number, FieldError | undefined>>({});
|
||||||
|
|
||||||
const { royalty, setRoyalty, isPercentHintOpen, setPercentHintOpen } =
|
const { royalty, setRoyalty, isPercentHintOpen, setPercentHintOpen } =
|
||||||
useRootStore();
|
useRootStore();
|
||||||
@@ -41,12 +55,24 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleWalletChange = (index: number, address: string) => {
|
const handleWalletChange = (index: number, address: string) => {
|
||||||
|
const isValid = isValidTonAddress(address);
|
||||||
|
setAddressErrors({
|
||||||
|
...addressErrors,
|
||||||
|
[index]: !isValid
|
||||||
|
? {
|
||||||
|
type: 'validation',
|
||||||
|
message: 'Неверный адрес TON'
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
});
|
||||||
|
|
||||||
const newRoyalty = royalty.map((member, i) =>
|
const newRoyalty = royalty.map((member, i) =>
|
||||||
i === index ? { ...member, address } : member,
|
i === index ? { ...member, address } : member
|
||||||
);
|
);
|
||||||
setRoyalty(newRoyalty);
|
setRoyalty(newRoyalty);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handlePercentChange = (index: number, value: string) => {
|
const handlePercentChange = (index: number, value: string) => {
|
||||||
const percentNumber = parseInt(value, 10) || 0;
|
const percentNumber = parseInt(value, 10) || 0;
|
||||||
const newRoyalty = royalty.map((royalty, i) =>
|
const newRoyalty = royalty.map((royalty, i) =>
|
||||||
@@ -66,11 +92,29 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||||||
|
|
||||||
const isValid = useMemo(() => {
|
const isValid = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
royalty.every((member) => member.address && member.value >= 0) &&
|
royalty.every((member) => isValidTonAddress(member.address) && member.value >= 0) &&
|
||||||
royalty.reduce((acc, curr) => acc + curr.value, 0) === 100
|
royalty.reduce((acc, curr) => acc + curr.value, 0) === 100
|
||||||
);
|
);
|
||||||
}, [royalty]);
|
}, [royalty]);
|
||||||
|
|
||||||
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
|
// Устанавливаем адрес из tonConnectUI.account при загрузке страницы
|
||||||
|
useEffect(() => {
|
||||||
|
if (!tonConnectUI.account) return;
|
||||||
|
|
||||||
|
if (royalty.length === 0) {
|
||||||
|
// First initialization with 100%
|
||||||
|
setRoyalty([{
|
||||||
|
address: Address.parse(tonConnectUI.account.address).toString({
|
||||||
|
bounceable: false,
|
||||||
|
urlSafe: true,
|
||||||
|
testOnly: false,
|
||||||
|
}),
|
||||||
|
value: 100
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}, [tonConnectUI.account, setRoyalty, royalty]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={"mt-4 px-4 pb-8"}>
|
<section className={"mt-4 px-4 pb-8"}>
|
||||||
{isPercentHintOpen && (
|
{isPercentHintOpen && (
|
||||||
@@ -117,7 +161,7 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||||||
<section className={"flex flex-col gap-1.5"}>
|
<section className={"flex flex-col gap-1.5"}>
|
||||||
{royalty.map((member, index) => (
|
{royalty.map((member, index) => (
|
||||||
<div key={index} className={"flex flex-col gap-[20px]"}>
|
<div key={index} className={"flex flex-col gap-[20px]"}>
|
||||||
<div className={"flex w-full items-center gap-1"}>
|
<div className={"flex w-full items-start gap-1"}>
|
||||||
<div className={"w-[83%]"}>
|
<div className={"w-[83%]"}>
|
||||||
<FormLabel
|
<FormLabel
|
||||||
labelClassName={"flex"}
|
labelClassName={"flex"}
|
||||||
@@ -134,6 +178,7 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||||||
value={member.address}
|
value={member.address}
|
||||||
onChange={(e) => handleWalletChange(index, e.target.value)}
|
onChange={(e) => handleWalletChange(index, e.target.value)}
|
||||||
placeholder={"[ Введите адрес криптокошелька TON ]"}
|
placeholder={"[ Введите адрес криптокошелька TON ]"}
|
||||||
|
error={addressErrors[index]}
|
||||||
/>
|
/>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,21 +1,123 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTonConnectUI } from "@tonconnect/ui-react";
|
||||||
|
|
||||||
import { Button } from "~/shared/ui/button";
|
import { Button } from "~/shared/ui/button";
|
||||||
import { useAuth } from "~/shared/services/auth";
|
import { useAuth } from "~/shared/services/auth";
|
||||||
|
import { Address } from "@ton/core";
|
||||||
|
|
||||||
type WelcomeStepProps = {
|
type WelcomeStepProps = {
|
||||||
nextStep(): void;
|
nextStep(): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
|
export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
|
||||||
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
|
const [isLoaded, setLoaded] = useState(false);
|
||||||
|
const [isConnected, setIsConnected] = useState(tonConnectUI.connected);
|
||||||
|
const [address, setAddress] = useState('');
|
||||||
|
console.log("💩💩💩 enter WelcomeStep");
|
||||||
|
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
|
|
||||||
|
console.log("💩💩💩 after useAuth");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem('disclaimerAccepted', 'false');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = tonConnectUI.onStatusChange((wallet) => {
|
||||||
|
setIsConnected(!!wallet);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, [tonConnectUI]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(tonConnectUI.account){
|
||||||
|
setAddress(Address.parse(tonConnectUI.account?.address).toString({
|
||||||
|
bounceable: false,
|
||||||
|
urlSafe: true,
|
||||||
|
testOnly: false,
|
||||||
|
}),)
|
||||||
|
}
|
||||||
|
}, [tonConnectUI.account]);
|
||||||
|
|
||||||
const handleNextClick = async () => {
|
const handleNextClick = async () => {
|
||||||
const res = await auth.mutateAsync();
|
if (tonConnectUI.connected) {
|
||||||
sessionStorage.setItem("auth_v1_token", res.data.auth_v1_token);
|
await auth.mutateAsync();
|
||||||
nextStep();
|
nextStep();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await tonConnectUI.openModal();
|
||||||
|
await auth.mutateAsync();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to connect or authenticate:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDisconnect = async () => {
|
||||||
|
if (isConnected){
|
||||||
|
try {
|
||||||
|
await tonConnectUI.disconnect();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to disconnect:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// useEffect(() => {
|
||||||
|
// const first = setTimeout(async () => {
|
||||||
|
// console.log("💩💩💩 call auth");
|
||||||
|
// await auth.mutateAsync();
|
||||||
|
// }, 1000);
|
||||||
|
//
|
||||||
|
// const second = setTimeout(() => {
|
||||||
|
// setLoaded(true);
|
||||||
|
//
|
||||||
|
// if (tonConnectUI.connected) {
|
||||||
|
// nextStep();
|
||||||
|
// }
|
||||||
|
// }, 4000);
|
||||||
|
//
|
||||||
|
// return () => {
|
||||||
|
// clearTimeout(first);
|
||||||
|
// clearTimeout(second);
|
||||||
|
// };
|
||||||
|
// }, [tonConnectUI.connected]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setLoaded(true)
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!isLoaded) {
|
||||||
return (
|
return (
|
||||||
<section className={"mt-4 px-4"}>
|
<section
|
||||||
|
className={"relative flex h-[100vh] items-center justify-center"}
|
||||||
|
>
|
||||||
|
<img alt={"splash"} className={"mb-20 w-[50%]"} src={"/splash.gif"} />
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={"mt-4 flex flex-col justify-between min-h-[calc(100vh-32px)] px-4"}>
|
||||||
|
<div className="flex items-center justify-center overflow-hidden w-[100%] h-[400px]">
|
||||||
|
<img
|
||||||
|
alt={"splash"}
|
||||||
|
className={"w-[50%] shrink-0"}
|
||||||
|
src={"/splash.gif"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"flex flex-col mt-4"}>
|
||||||
<div className={"flex gap-2 text-sm"}>
|
<div className={"flex gap-2 text-sm"}>
|
||||||
<span>/ Добро пожаловать в MY</span>
|
<span>/ Добро пожаловать в MY</span>
|
||||||
|
|
||||||
@@ -26,20 +128,54 @@ export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{isConnected ?
|
||||||
|
<>
|
||||||
<div className={"mt-2"}>
|
<div className={"mt-2"}>
|
||||||
<p className={"text-sm"}>
|
<p className={"text-sm"}>
|
||||||
децентрализованную систему монетизации контента. для продолжения
|
Вы зарегистрированы под кошельком: <br/>
|
||||||
необходимо подключить криптокошелек TON
|
<span className={"font-bold"}>{address}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
<Button
|
<Button
|
||||||
label={"Подключить криптокошелёк TON"}
|
|
||||||
className={"mt-[30px]"}
|
className={"mt-[30px]"}
|
||||||
|
label={"Продолжить"}
|
||||||
|
includeArrows={false}
|
||||||
|
isLoading={auth.isLoading}
|
||||||
|
onClick={handleNextClick}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className={"mt-[20px] bg-inherit"}
|
||||||
|
label={"Изменить кошелек"}
|
||||||
|
includeArrows={false}
|
||||||
|
isLoading={false}
|
||||||
|
onClick={handleDisconnect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<>
|
||||||
|
<div className={"mt-2"}>
|
||||||
|
<p className={"text-sm"}>
|
||||||
|
Здесь вы можете загрузить свой контент. <br/> Для продолжения подключите кошелек.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className={"mt-2"}>
|
||||||
|
<p className={"text-sm"}>
|
||||||
|
Не волнуйтесь. Вы сможете поменять свой выбор в любой момент.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={"mt-[30px]"}
|
||||||
|
label={"Подключить криптокошелёк TON"}
|
||||||
includeArrows={true}
|
includeArrows={true}
|
||||||
isLoading={auth.isLoading}
|
isLoading={auth.isLoading}
|
||||||
onClick={handleNextClick}
|
onClick={handleNextClick}
|
||||||
/>
|
/>
|
||||||
|
</>}
|
||||||
|
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { useHapticFeedback, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Button } from "~/shared/ui/button";
|
||||||
|
|
||||||
|
type CongratsModalProps = {
|
||||||
|
onConfirm(): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CongratsModal = ({
|
||||||
|
onConfirm,
|
||||||
|
}: CongratsModalProps) => {
|
||||||
|
const [impactOccurred] = useHapticFeedback();
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
|
||||||
|
const handleClick = (fn: () => void) => {
|
||||||
|
impactOccurred("light");
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
// Отключаем вертикальные свайпы при монтировании компонента
|
||||||
|
if (WebApp && WebApp.disableVerticalSwipes) {
|
||||||
|
WebApp.disableVerticalSwipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Включаем вертикальные свайпы обратно при размонтировании
|
||||||
|
return () => {
|
||||||
|
if (WebApp && WebApp.enableVerticalSwipes) {
|
||||||
|
WebApp.enableVerticalSwipes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"fixed left-0 top-0 z-30 flex h-full w-full items-center justify-center bg-black/80 px-[15px]"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={"flex flex-col max-h-[80vh] w-[85vw] max-w-md"}>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"border border-white bg-[#1D1D1B] px-[15px] py-[16px] text-start flex flex-col gap-6 h-full overflow-y-auto"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className="mt-4">
|
||||||
|
<span className="text-xl">🎉</span>
|
||||||
|
<span className="px-1 font-bold">Поздравляем с покупкой!</span>
|
||||||
|
<span className="text-xl">🎉</span>
|
||||||
|
</p>
|
||||||
|
<p className="">
|
||||||
|
Ваш контент уже в пути! В ближайшее время в чат-боте <strong>MY Player</strong> вам придёт сообщение с доступом к купленному материалу. В этом чат-боте будет храниться весь ваш приобретённый контент.
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
<strong className="w-full">Теперь вы можете самостоятельно осуществить продажу купленного контента.</strong>
|
||||||
|
<span>
|
||||||
|
Перешлите сообщение из чата My-Player друзьям или опубликуйте в своём Telegram-канале. Каждый, кто купит контент по вашей ссылке, принесёт вам доход, а автору — заслуженное вознаграждение.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
Спасибо, что выбираете MY!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={"mt-[20px]"}
|
||||||
|
label={"Ок"}
|
||||||
|
includeArrows={false}
|
||||||
|
onClick={() => handleClick(onConfirm)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { useHapticFeedback, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Button } from "~/shared/ui/button";
|
||||||
|
|
||||||
|
type ErrorModalProps = {
|
||||||
|
onConfirm(): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ErrorModal = ({
|
||||||
|
onConfirm,
|
||||||
|
}: ErrorModalProps) => {
|
||||||
|
const [impactOccurred] = useHapticFeedback();
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
|
||||||
|
const handleClick = (fn: () => void) => {
|
||||||
|
impactOccurred("light");
|
||||||
|
fn();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Отключаем вертикальные свайпы при монтировании компонента
|
||||||
|
if (WebApp && WebApp.disableVerticalSwipes) {
|
||||||
|
WebApp.disableVerticalSwipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Включаем вертикальные свайпы обратно при размонтировании
|
||||||
|
return () => {
|
||||||
|
if (WebApp && WebApp.enableVerticalSwipes) {
|
||||||
|
WebApp.enableVerticalSwipes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"fixed left-0 top-0 z-30 flex h-full w-full items-center justify-center bg-black/80 px-[15px]"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={"flex flex-col max-h-[80vh] w-[85vw] max-w-md"}>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"border border-white bg-[#1D1D1B] px-[15px] py-[16px] text-start flex flex-col gap-6 h-full overflow-y-auto"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className="mt-4">
|
||||||
|
<span className="font-bold">Ошибка запроса транзакции</span>
|
||||||
|
</p>
|
||||||
|
<p className="">
|
||||||
|
Не удалось отправить запрос на выполнение транзакции.
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
<span>
|
||||||
|
Попробуйте переподключить кошелек и повторить попытку. Если ошибка сохраняется, попробуйте запросить транзакцию еще раз.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p className="flex flex-col">
|
||||||
|
Если проблема не исчезает, убедитесь, что ваш кошелек работает корректно, или свяжитесь с поддержкой.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={"mt-[20px]"}
|
||||||
|
label={"Ок"}
|
||||||
|
includeArrows={false}
|
||||||
|
onClick={() => handleClick(onConfirm)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
import ReactPlayer from 'react-player/lazy';
|
||||||
|
import { useTonConnectUI } from '@tonconnect/ui-react';
|
||||||
|
import { useWebApp } from '@vkruglikov/react-telegram-web-app';
|
||||||
|
import { Button } from '~/shared/ui/button';
|
||||||
|
import { usePurchaseContent, useViewContent } from '~/shared/services/content';
|
||||||
|
import { fromNanoTON } from '~/shared/utils';
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { AudioPlayer } from '~/shared/ui/audio-player';
|
||||||
|
import { useAuth } from '~/shared/services/auth';
|
||||||
|
import { CongratsModal } from './components/congrats-modal';
|
||||||
|
import { ErrorModal } from './components/error-modal';
|
||||||
|
import { useRootStore } from '~/shared/stores/root';
|
||||||
|
import { useTgFullscreen } from '~/shared/hooks/use-tgfullscreen';
|
||||||
|
type InvoiceStatus = 'paid' | 'failed' | 'cancelled' | 'pending';
|
||||||
|
|
||||||
|
// Add type for invoice event
|
||||||
|
interface InvoiceEvent {
|
||||||
|
url: string;
|
||||||
|
status: InvoiceStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ViewContentPage = () => {
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
const { addNotification } = useRootStore();
|
||||||
|
const { data: content, refetch: refetchContent } = useViewContent(
|
||||||
|
WebApp.initDataUnsafe?.start_param
|
||||||
|
);
|
||||||
|
|
||||||
|
const { mutateAsync: purchaseContent } = usePurchaseContent();
|
||||||
|
|
||||||
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
|
|
||||||
|
const { isFullscreen, toggleFullscreen } = useTgFullscreen();
|
||||||
|
|
||||||
|
const auth = useAuth();
|
||||||
|
const [isCongratsModal, setIsCongratsModal] = useState(false);
|
||||||
|
const [isErrorModal, setIsErrorModal] = useState(false);
|
||||||
|
|
||||||
|
const handleBuyContentTON = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
// Helper function to wait for wallet connection
|
||||||
|
const waitForConnection = async (timeoutMs = 30000, intervalMs = 500) => {
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
while (Date.now() - startTime < timeoutMs) {
|
||||||
|
if (tonConnectUI.connected) {
|
||||||
|
addNotification('Кошелек подключен', 'success');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
||||||
|
}
|
||||||
|
addNotification('Время ожидания подключения кошелька истекло', 'warning');
|
||||||
|
return false; // Timed out
|
||||||
|
};
|
||||||
|
|
||||||
|
// If not connected, start connection process
|
||||||
|
if (!tonConnectUI.connected) {
|
||||||
|
console.log('DEBUG: Wallet not connected, opening modal');
|
||||||
|
|
||||||
|
// Open connection modal
|
||||||
|
await tonConnectUI.openModal();
|
||||||
|
|
||||||
|
// Wait for connection
|
||||||
|
const connected = await waitForConnection();
|
||||||
|
if (!connected) {
|
||||||
|
console.log('DEBUG: Connection timed out or was cancelled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('DEBUG: Connection successful, authenticating');
|
||||||
|
await auth.mutateAsync();
|
||||||
|
} else {
|
||||||
|
// Already connected, just authenticate
|
||||||
|
await auth.mutateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proceed with purchase
|
||||||
|
console.log('DEBUG: Proceeding with purchase');
|
||||||
|
const contentResponse = await purchaseContent({
|
||||||
|
content_address: WebApp.initDataUnsafe?.start_param,
|
||||||
|
license_type: 'resale',
|
||||||
|
});
|
||||||
|
|
||||||
|
const transactionResponse = await tonConnectUI.sendTransaction({
|
||||||
|
validUntil: Math.floor(Date.now() / 1000) + 86400, // 24 hours
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
amount: contentResponse.data.amount,
|
||||||
|
address: contentResponse.data.address,
|
||||||
|
payload: contentResponse.data.payload,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (transactionResponse.boc) {
|
||||||
|
void refetchContent();
|
||||||
|
setIsCongratsModal(true);
|
||||||
|
console.log(transactionResponse.boc, 'PURCHASED');
|
||||||
|
} else {
|
||||||
|
setIsErrorModal(true);
|
||||||
|
console.error('Transaction failed:', transactionResponse);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setIsErrorModal(true);
|
||||||
|
console.error('Error handling Ton Connect subscription:', error);
|
||||||
|
}
|
||||||
|
}, [auth, purchaseContent, refetchContent, tonConnectUI, WebApp.initDataUnsafe?.start_param]);
|
||||||
|
|
||||||
|
const handleBuyContentStars = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
if (!content?.data?.invoice.url) {
|
||||||
|
console.error('No invoice URL available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listener for invoice closing with typed event
|
||||||
|
const handleInvoiceClosed = (event: InvoiceEvent) => {
|
||||||
|
if (event.url === content.data.invoice.url) {
|
||||||
|
if (event.status === 'paid') {
|
||||||
|
void refetchContent();
|
||||||
|
setIsCongratsModal(true);
|
||||||
|
} else if (event.status === 'failed' || event.status === 'cancelled') {
|
||||||
|
// setIsErrorModal(true); // Turn on if need in error modal. Update text in it to match both way of payment errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WebApp.onEvent('invoiceClosed', handleInvoiceClosed);
|
||||||
|
|
||||||
|
await WebApp.openInvoice(content.data.invoice.url, (status: InvoiceStatus) => {
|
||||||
|
console.log('Invoice status:', status);
|
||||||
|
if (status === 'paid') {
|
||||||
|
void refetchContent();
|
||||||
|
setIsCongratsModal(true);
|
||||||
|
} else if (status === 'failed' || status === 'cancelled') {
|
||||||
|
// setIsErrorModal(true); // Turn on if need in error modal. Update text in it to match both way of payment errors
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
WebApp.offEvent('invoiceClosed', handleInvoiceClosed);
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Payment failed:', error);
|
||||||
|
// setIsErrorModal(true); // Turn on if need in error modal. Update text in it to match both way of payment errors
|
||||||
|
}
|
||||||
|
}, [content, refetchContent]);
|
||||||
|
|
||||||
|
const haveLicense = useMemo(() => {
|
||||||
|
document.title = content?.data?.display_options?.metadata?.name;
|
||||||
|
return (
|
||||||
|
content?.data?.have_licenses?.includes('listen') ||
|
||||||
|
content?.data?.have_licenses?.includes('resale')
|
||||||
|
);
|
||||||
|
}, [content]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
void refetchContent();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleConfirmCongrats = () => {
|
||||||
|
setIsCongratsModal(!isCongratsModal);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleErrorModal = () => {
|
||||||
|
setIsErrorModal(!isErrorModal);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDwnldContent = async () => {
|
||||||
|
try {
|
||||||
|
const fileUrl = content?.data?.display_options?.content_url;
|
||||||
|
const fileName = content?.data?.display_options?.metadata?.name || 'content';
|
||||||
|
const fileFormat = content?.data?.content_ext || '.raw';
|
||||||
|
await WebApp.downloadFile({
|
||||||
|
url: fileUrl,
|
||||||
|
file_name: fileName + '.' + fileFormat,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading content:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className={'min-h-screen flex w-full flex-col gap-[50px] px-4 '}>
|
||||||
|
{isCongratsModal && <CongratsModal onConfirm={handleConfirmCongrats} />}
|
||||||
|
{isErrorModal && <ErrorModal onConfirm={handleErrorModal} />}
|
||||||
|
<div
|
||||||
|
className={`${isFullscreen ? 'left-[50%] translate-x-[-50%] fixed top-11 lg:top-2' : 'left-4 absolute top-2'} z-50`}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
onClick={toggleFullscreen}
|
||||||
|
className="bg-primary bg-opacity-80 w-8 h-8 flex items-center justify-center rounded-full text-white"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M2 6V2H6M8 2H12V6M12 8V12H8M6 12H2V8"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="mt-[50px]">
|
||||||
|
{content?.data?.content_type.startsWith('audio') &&
|
||||||
|
content?.data?.display_options?.metadata?.image && (
|
||||||
|
<div className={'mt-[30px] h-[314px] w-full'}>
|
||||||
|
<img
|
||||||
|
alt={'content_image'}
|
||||||
|
className={'h-full w-full object-cover object-center'}
|
||||||
|
src={content?.data?.display_options?.metadata?.image}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{content?.data?.content_type.startsWith('audio') ? (
|
||||||
|
<AudioPlayer src={content?.data?.display_options?.content_url} />
|
||||||
|
) : (
|
||||||
|
<div className="w-full video-container">
|
||||||
|
<ReactPlayer
|
||||||
|
playsinline={true}
|
||||||
|
controls={true}
|
||||||
|
width="100%"
|
||||||
|
height="auto"
|
||||||
|
className="react-player"
|
||||||
|
allowFullScreen={true}
|
||||||
|
url={content?.data?.display_options?.content_url}
|
||||||
|
config={{
|
||||||
|
file: {
|
||||||
|
attributes: {
|
||||||
|
playsInline: true,
|
||||||
|
autoPlay: true,
|
||||||
|
poster:
|
||||||
|
content?.data?.display_options?.metadata?.image ||
|
||||||
|
undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<section className={'flex flex-col'}>
|
||||||
|
<h1 className={'text-[20px] font-bold'}>
|
||||||
|
{content?.data?.display_options?.metadata?.name}
|
||||||
|
</h1>
|
||||||
|
{/*<h2>Russian</h2>*/}
|
||||||
|
{/*<h2>2022</h2>*/}
|
||||||
|
<p className={'mt-2 text-[12px]'}>
|
||||||
|
{content?.data?.display_options?.metadata?.description}
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<div className="mt-auto pb-2">
|
||||||
|
{content?.data?.downloadable && (
|
||||||
|
<Button
|
||||||
|
onClick={() => handleDwnldContent()}
|
||||||
|
className={'h-[48px] mb-4'}
|
||||||
|
label={`Скачать контент`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!haveLicense && (
|
||||||
|
<div className="flex flex-row gap-4">
|
||||||
|
<Button
|
||||||
|
onClick={handleBuyContentTON}
|
||||||
|
className={'mb-4 h-[48px] px-2'}
|
||||||
|
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
|
||||||
|
includeArrows={content?.data?.invoice ? false : true}
|
||||||
|
/>
|
||||||
|
{content?.data?.invoice && (
|
||||||
|
<Button
|
||||||
|
onClick={handleBuyContentStars}
|
||||||
|
className={'mb-4 h-[48px] px-2'}
|
||||||
|
label={`Купить за ${content?.data?.invoice?.amount} ⭐️`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
WebApp.openTelegramLink(`https://t.me/MY_UploaderRobot`);
|
||||||
|
}}
|
||||||
|
className={'h-[48px] bg-darkred'}
|
||||||
|
label={`Загрузить свой контент`}
|
||||||
|
/>
|
||||||
|
{tonConnectUI.connected && (
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
tonConnectUI.disconnect();
|
||||||
|
}}
|
||||||
|
className={'h-[48px] bg-darkred mt-4'}
|
||||||
|
label={`Отключить кошелек`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
import { ReactNode, useMemo, useState } from "react";
|
import { useTonConnectUI } from "@tonconnect/ui-react";
|
||||||
|
import { ReactNode, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
|
const CHECK_INTERVAL = 20000;
|
||||||
|
|
||||||
|
|
||||||
export const useSteps = (
|
export const useSteps = (
|
||||||
sections: ({
|
sections: ({
|
||||||
@@ -9,15 +13,24 @@ export const useSteps = (
|
|||||||
prevStep(): void;
|
prevStep(): void;
|
||||||
}) => ReactNode[],
|
}) => ReactNode[],
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
|
|
||||||
const [step, setStep] = useState(0);
|
const [step, setStep] = useState(0);
|
||||||
|
|
||||||
const nextStep = () => {
|
// If connection is lost, reset the step
|
||||||
return setStep((s) => s + 1);
|
useEffect(() => {
|
||||||
};
|
const interval = setInterval(() => {
|
||||||
|
if (!tonConnectUI.connected && step !== 0) {
|
||||||
|
setStep(0);
|
||||||
|
}
|
||||||
|
}, CHECK_INTERVAL);
|
||||||
|
|
||||||
const prevStep = () => {
|
return () => clearInterval(interval);
|
||||||
return setStep((s) => s - 1);
|
}, []);
|
||||||
};
|
|
||||||
|
const nextStep = () => setStep((s) => s + 1);
|
||||||
|
const prevStep = () => setStep((s) => s - 1);
|
||||||
|
|
||||||
const ActiveSection = useMemo(() => {
|
const ActiveSection = useMemo(() => {
|
||||||
return sections({ nextStep, prevStep })[step];
|
return sections({ nextStep, prevStep })[step];
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { useState, useCallback, useEffect } from 'react';
|
||||||
|
import { useWebApp } from '@vkruglikov/react-telegram-web-app';
|
||||||
|
import { viewport } from '@telegram-apps/sdk';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for managing Telegram WebApp fullscreen state
|
||||||
|
* @returns {Object} Object containing isFullscreen state and toggleFullscreen function
|
||||||
|
*/
|
||||||
|
export const useTgFullscreen = () => {
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
|
// Initialize viewport once on mount
|
||||||
|
useEffect(() => {
|
||||||
|
// Mount viewport if available
|
||||||
|
if (viewport.mount.isAvailable() && !viewport.isMounted()) {
|
||||||
|
viewport.mount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check current fullscreen state
|
||||||
|
if (viewport.isFullscreen && typeof viewport.isFullscreen === 'function') {
|
||||||
|
setIsFullscreen(viewport.isFullscreen());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the WebApp event system for tracking changes
|
||||||
|
const handleViewportChanged = () => {
|
||||||
|
if (WebApp.isExpanded) {
|
||||||
|
setIsFullscreen(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
WebApp.onEvent('viewportChanged', handleViewportChanged);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not add viewportChanged event listener:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
try {
|
||||||
|
WebApp.offEvent('viewportChanged', handleViewportChanged);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not remove viewportChanged event listener:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [WebApp]);
|
||||||
|
|
||||||
|
const toggleFullscreen = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
if (!isFullscreen) {
|
||||||
|
// Try to enter fullscreen
|
||||||
|
if (viewport.requestFullscreen && viewport.requestFullscreen.isAvailable()) {
|
||||||
|
await viewport.requestFullscreen();
|
||||||
|
setIsFullscreen(true);
|
||||||
|
} else if (viewport.expand && viewport.expand.isAvailable()) {
|
||||||
|
viewport.expand();
|
||||||
|
setIsFullscreen(true);
|
||||||
|
} else {
|
||||||
|
WebApp.expand();
|
||||||
|
setIsFullscreen(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to exit fullscreen
|
||||||
|
if (viewport.exitFullscreen && viewport.exitFullscreen.isAvailable()) {
|
||||||
|
await viewport.exitFullscreen();
|
||||||
|
setIsFullscreen(false);
|
||||||
|
} else {
|
||||||
|
setIsFullscreen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error toggling fullscreen:', error);
|
||||||
|
|
||||||
|
if (!isFullscreen) {
|
||||||
|
try {
|
||||||
|
WebApp.expand();
|
||||||
|
setIsFullscreen(true);
|
||||||
|
} catch {
|
||||||
|
console.error('All fullscreen methods failed');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsFullscreen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [WebApp, isFullscreen]);
|
||||||
|
|
||||||
|
return { isFullscreen, toggleFullscreen };
|
||||||
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import { Buffer } from 'buffer';
|
||||||
|
globalThis.Buffer = Buffer;
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
|
|
||||||
export const APP_API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string;
|
export const APP_API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
|
||||||
export const request = axios.create({
|
export const request = axios.create({
|
||||||
baseURL: APP_API_BASE_URL,
|
baseURL: APP_API_BASE_URL,
|
||||||
});
|
});
|
||||||
|
|
||||||
request.interceptors.request.use((config) => {
|
request.interceptors.request.use((config) => {
|
||||||
const auth_v1_token = sessionStorage.getItem("auth_v1_token");
|
const auth_v1_token = localStorage.getItem('auth_v1_token');
|
||||||
|
|
||||||
if (auth_v1_token) {
|
if (auth_v1_token) {
|
||||||
config.headers.Authorization = auth_v1_token;
|
config.headers.Authorization = auth_v1_token;
|
||||||
|
|||||||
@@ -1,22 +1,311 @@
|
|||||||
import { useMutation } from "react-query";
|
import { useRef, useEffect } from 'react';
|
||||||
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
|
import { useTonConnectUI } from '@tonconnect/ui-react';
|
||||||
|
import { useMutation } from 'react-query';
|
||||||
|
import { request } from '~/shared/libs';
|
||||||
|
import { useWebApp } from '@vkruglikov/react-telegram-web-app';
|
||||||
|
|
||||||
import { request } from "~/shared/libs";
|
const sessionStorageKey = 'auth_v1_token';
|
||||||
|
const tonProofStorageKey = 'stored_ton_proof';
|
||||||
|
const payloadTTLMS = 1000 * 60 * 20;
|
||||||
|
|
||||||
export const useAuth = () => {
|
export const useAuth = () => {
|
||||||
const WebApp = useWebApp();
|
const WebApp = useWebApp();
|
||||||
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
|
const interval = useRef<ReturnType<typeof setInterval> | undefined>();
|
||||||
|
|
||||||
return useMutation(["auth"], () => {
|
// Store ton_proof when it becomes available
|
||||||
return request.post<{
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
tonConnectUI.wallet?.connectItems?.tonProof &&
|
||||||
|
!('error' in tonConnectUI.wallet.connectItems.tonProof) &&
|
||||||
|
tonConnectUI.wallet.account
|
||||||
|
) {
|
||||||
|
console.log('DEBUG: Storing ton_proof for future use');
|
||||||
|
localStorage.setItem(
|
||||||
|
tonProofStorageKey,
|
||||||
|
JSON.stringify({
|
||||||
|
timestamp: Date.now(),
|
||||||
|
account: tonConnectUI.wallet.account,
|
||||||
|
proof: tonConnectUI.wallet.connectItems.tonProof.proof,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [tonConnectUI.wallet?.connectItems?.tonProof, tonConnectUI.wallet?.account]);
|
||||||
|
|
||||||
|
const makeAuthRequest = async (params: {
|
||||||
|
twa_data: string;
|
||||||
|
ton_proof?: {
|
||||||
|
account: any;
|
||||||
|
ton_proof: any;
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
try {
|
||||||
|
const res = await request.post<{
|
||||||
connected_wallet: null | {
|
connected_wallet: null | {
|
||||||
version: string;
|
version: string;
|
||||||
address: string;
|
address: string;
|
||||||
ton_balance: string;
|
ton_balance: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
auth_v1_token: string;
|
auth_v1_token: string;
|
||||||
}>("/auth.twa", {
|
}>('/auth.twa', params);
|
||||||
|
|
||||||
|
if (res?.data?.auth_v1_token) {
|
||||||
|
localStorage.setItem(sessionStorageKey, res.data.auth_v1_token);
|
||||||
|
|
||||||
|
// If we sent a proof, it was accepted, so keep record of that
|
||||||
|
if (params.ton_proof) {
|
||||||
|
console.log('DEBUG: Auth with proof successful');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('Failed to get auth token');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} catch (error) {
|
||||||
|
// If we were using ton_proof and it failed, clear stored proof
|
||||||
|
if (params.ton_proof) {
|
||||||
|
console.log('DEBUG: Auth with proof failed, clearing stored proof');
|
||||||
|
localStorage.removeItem(tonProofStorageKey);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeSelectWalletRequest = async (params: { wallet_address: string }) => {
|
||||||
|
try {
|
||||||
|
const res = await request.post('/auth.selectWallet', params);
|
||||||
|
return res;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Check for 404 error (wallet not found or invalid)
|
||||||
|
if (error.response?.status === 404) {
|
||||||
|
console.log('DEBUG: Wallet selection failed with 404, disconnecting');
|
||||||
|
await tonConnectUI.disconnect();
|
||||||
|
localStorage.removeItem(sessionStorageKey);
|
||||||
|
localStorage.removeItem(tonProofStorageKey);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to prepare the connection parameters with proof requirements
|
||||||
|
const prepareConnectParams = async () => {
|
||||||
|
console.log('DEBUG: Preparing connect parameters');
|
||||||
|
|
||||||
|
// Set to loading state first
|
||||||
|
tonConnectUI.setConnectRequestParameters({ state: 'loading' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the payload/token from backend
|
||||||
|
const value = await request.post<{ auth_v1_token: string }>('/auth.twa', {
|
||||||
twa_data: WebApp.initData,
|
twa_data: WebApp.initData,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (value?.data?.auth_v1_token) {
|
||||||
|
console.log('DEBUG: Got token for connect params');
|
||||||
|
|
||||||
|
// Set the parameters to ready with tonProof requirement
|
||||||
|
tonConnectUI.setConnectRequestParameters({
|
||||||
|
state: 'ready',
|
||||||
|
value: { tonProof: value.data.auth_v1_token },
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.log('DEBUG: No token received for connect params');
|
||||||
|
tonConnectUI.setConnectRequestParameters(null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('DEBUG: Error preparing connect params:', error);
|
||||||
|
tonConnectUI.setConnectRequestParameters(null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to check if connection is capable of transactions
|
||||||
|
const isConnectionValid = () => {
|
||||||
|
if (!tonConnectUI.connected || !tonConnectUI.wallet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return useMutation(['auth'], async () => {
|
||||||
|
clearInterval(interval.current);
|
||||||
|
let authResult;
|
||||||
|
console.log('DEBUG: Starting auth flow');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Case 1: Not connected - need to connect and get proof
|
||||||
|
if (!tonConnectUI.connected) {
|
||||||
|
console.log('DEBUG: No wallet connection, starting flow');
|
||||||
|
localStorage.removeItem(sessionStorageKey);
|
||||||
|
|
||||||
|
// Prepare connection parameters (this sets up the proof requirement)
|
||||||
|
const prepared = await prepareConnectParams();
|
||||||
|
|
||||||
|
if (!prepared) {
|
||||||
|
throw new Error('Failed to prepare connection parameters');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start periodic refresh of the payload
|
||||||
|
interval.current = setInterval(prepareConnectParams, payloadTTLMS);
|
||||||
|
|
||||||
|
// Open the modal - this will not resolve until connection or cancellation
|
||||||
|
await tonConnectUI.openModal();
|
||||||
|
|
||||||
|
// Check if connection was successful
|
||||||
|
if (!tonConnectUI.connected) {
|
||||||
|
console.log('DEBUG: Connection cancelled or failed');
|
||||||
|
throw new Error('Wallet connection cancelled or failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have a proof after connection
|
||||||
|
if (
|
||||||
|
tonConnectUI.wallet?.connectItems?.tonProof &&
|
||||||
|
!('error' in tonConnectUI.wallet.connectItems.tonProof)
|
||||||
|
) {
|
||||||
|
console.log('DEBUG: Got proof after connection');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try auth with the proof
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
ton_proof: {
|
||||||
|
account: tonConnectUI.wallet.account,
|
||||||
|
ton_proof: tonConnectUI.wallet.connectItems.tonProof.proof,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// If auth with proof fails, throw the error
|
||||||
|
console.error('DEBUG: Auth with fresh proof failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('DEBUG: No proof available after connection');
|
||||||
|
// If we can't get proof but we're connected, try auth without it
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Case 2: Already connected - try to use stored proof first
|
||||||
|
console.log('DEBUG: Already connected');
|
||||||
|
|
||||||
|
// Check if we have a valid stored proof
|
||||||
|
const storedProofData = localStorage.getItem(tonProofStorageKey);
|
||||||
|
if (storedProofData) {
|
||||||
|
try {
|
||||||
|
const proofData = JSON.parse(storedProofData);
|
||||||
|
|
||||||
|
// Check if the proof matches current wallet and is not too old
|
||||||
|
if (tonConnectUI.wallet?.account?.address === proofData.account.address) {
|
||||||
|
console.log('DEBUG: Using stored proof');
|
||||||
|
|
||||||
|
// Try auth with stored proof but ignore errors
|
||||||
|
try {
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
ton_proof: {
|
||||||
|
account: proofData.account,
|
||||||
|
ton_proof: proofData.proof,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// If successful, remove stored proof as it's been used
|
||||||
|
localStorage.removeItem(tonProofStorageKey);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
'DEBUG: Auth with stored proof failed, proceeding without it'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fall back to auth without proof
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('DEBUG: Stored proof address mismatch');
|
||||||
|
localStorage.removeItem(tonProofStorageKey);
|
||||||
|
|
||||||
|
// Auth without proof
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('DEBUG: Error parsing stored proof:', error);
|
||||||
|
localStorage.removeItem(tonProofStorageKey);
|
||||||
|
|
||||||
|
// Auth without proof
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No stored proof, check if we have a live proof
|
||||||
|
if (
|
||||||
|
tonConnectUI.wallet?.connectItems?.tonProof &&
|
||||||
|
!('error' in tonConnectUI.wallet.connectItems.tonProof)
|
||||||
|
) {
|
||||||
|
console.log('DEBUG: Using live proof from wallet');
|
||||||
|
try {
|
||||||
|
// Try auth with the live proof
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
ton_proof: {
|
||||||
|
account: tonConnectUI.wallet.account,
|
||||||
|
ton_proof: tonConnectUI.wallet.connectItems.tonProof.proof,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
'DEBUG: Auth with live proof failed, proceeding without it'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fall back to auth without proof
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Connected without proof - already authenticated
|
||||||
|
console.log('DEBUG: Connected without proof, proceeding without it');
|
||||||
|
authResult = await makeAuthRequest({
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always try to select wallet after auth (this validates the connection)
|
||||||
|
if (tonConnectUI.wallet?.account?.address) {
|
||||||
|
console.log('DEBUG: Selecting wallet', tonConnectUI.wallet.account.address);
|
||||||
|
try {
|
||||||
|
await makeSelectWalletRequest({
|
||||||
|
wallet_address: tonConnectUI.wallet.account.address,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Additional validation check
|
||||||
|
if (!isConnectionValid()) {
|
||||||
|
console.log('DEBUG: Connection validation failed, disconnecting');
|
||||||
|
await tonConnectUI.disconnect();
|
||||||
|
localStorage.removeItem(sessionStorageKey);
|
||||||
|
localStorage.removeItem(tonProofStorageKey);
|
||||||
|
throw new Error('Connection validation failed');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Errors from makeSelectWalletRequest are already handled
|
||||||
|
console.error('DEBUG: Wallet selection failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return authResult;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('DEBUG: Auth flow failed:', error);
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
clearInterval(interval.current);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { useMutation } from "react-query";
|
||||||
|
import { request } from "~/shared/libs";
|
||||||
|
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
|
||||||
|
const sessionStorageKey = "auth_v1_token";
|
||||||
|
|
||||||
|
export const useAuthTwa = () => {
|
||||||
|
const WebApp = useWebApp();
|
||||||
|
|
||||||
|
const makeAuthRequest = async () => {
|
||||||
|
const res = await request.post<{
|
||||||
|
auth_v1_token: string;
|
||||||
|
}>("/auth.twa", {
|
||||||
|
twa_data: WebApp.initData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res?.data?.auth_v1_token) {
|
||||||
|
localStorage.setItem(sessionStorageKey, res.data.auth_v1_token);
|
||||||
|
} else {
|
||||||
|
throw new Error("Failed to get auth token");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
return useMutation(["auth"], makeAuthRequest);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMutation } from "react-query";
|
import { useMutation, useQuery } from "react-query";
|
||||||
|
|
||||||
import { request } from "~/shared/libs";
|
import { request } from "~/shared/libs";
|
||||||
import { Royalty } from "~/shared/stores/root";
|
import { Royalty } from "~/shared/stores/root";
|
||||||
@@ -8,11 +8,13 @@ type UseCreateNewContentPayload = {
|
|||||||
content: string;
|
content: string;
|
||||||
image: string;
|
image: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
hashtags: string[];
|
||||||
price: string;
|
price: string;
|
||||||
resaleLicensePrice: string; // nanoTON bignum (default = 0)
|
resaleLicensePrice: string; // nanoTON bignum (default = 0)
|
||||||
allowResale: boolean;
|
allowResale: boolean;
|
||||||
authors: string[];
|
authors: string[];
|
||||||
royaltyParams: Royalty[];
|
royaltyParams: Royalty[];
|
||||||
|
downloadable: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useCreateNewContent = () => {
|
export const useCreateNewContent = () => {
|
||||||
@@ -20,19 +22,61 @@ export const useCreateNewContent = () => {
|
|||||||
["create-new-content"],
|
["create-new-content"],
|
||||||
(payload: UseCreateNewContentPayload) => {
|
(payload: UseCreateNewContentPayload) => {
|
||||||
return request.post<{
|
return request.post<{
|
||||||
message: string;
|
address: string;
|
||||||
}>("/blockchain.sendNewContentMessage", payload);
|
amount: string;
|
||||||
|
payload: string;
|
||||||
|
}>("/blockchain.sendNewContentMessage", payload, {
|
||||||
|
headers: {
|
||||||
|
Authorization: localStorage.getItem('auth_v1_token') ?? ""
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// export const usePurchaseContent = () => {
|
||||||
|
// return useMutation(
|
||||||
|
// ["purchase-content"],
|
||||||
|
// (payload: { content_address: string; price: string }) => {
|
||||||
|
// return request.post<{
|
||||||
|
// message: string;
|
||||||
|
// }>("/blockchain.sendPurchaseContentMessage", payload);
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const useViewContent = (contentId: string) => {
|
||||||
|
return useQuery(["view", "content", contentId], () => {
|
||||||
|
return request.get(`/content.view/${contentId}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: localStorage.getItem('auth_v1_token') ?? ""
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const usePurchaseContent = () => {
|
export const usePurchaseContent = () => {
|
||||||
return useMutation(
|
return useMutation(
|
||||||
["purchase-content"],
|
["purchase", "content"],
|
||||||
(payload: { content_address: string; price: string }) => {
|
({
|
||||||
|
content_address,
|
||||||
|
license_type,
|
||||||
|
}: {
|
||||||
|
content_address: string;
|
||||||
|
license_type: "listen" | "resale";
|
||||||
|
}) => {
|
||||||
return request.post<{
|
return request.post<{
|
||||||
message: string;
|
address: string;
|
||||||
}>("/blockchain.sendPurchaseContentMessage", payload);
|
amount: string;
|
||||||
|
payload: string;
|
||||||
|
}>("/blockchain.sendPurchaseContentMessage", {
|
||||||
|
content_address,
|
||||||
|
license_type,
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
Authorization: localStorage.getItem('auth_v1_token') ?? ""
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1,45 +1,201 @@
|
|||||||
import { useMutation } from "react-query";
|
import { useMutation } from "react-query";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { request } from "~/shared/libs";
|
import { request } from "~/shared/libs";
|
||||||
|
|
||||||
|
const STORAGE_API_URL = import.meta.env.VITE_API_BASE_STORAGE_URL;
|
||||||
|
const MAX_CHUNK_SIZE = 80 * 1024 * 1024; // 80 MB
|
||||||
|
|
||||||
export const useUploadFile = () => {
|
export const useUploadFile = () => {
|
||||||
const [uploadProgress, setUploadProgress] = useState(0);
|
const [uploadProgress, setUploadProgress] = useState(0);
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
|
const [uploadError, setUploadError] = useState<Error | null>(null);
|
||||||
|
|
||||||
const mutation = useMutation(["upload-file"], (file: File) => {
|
const mutation = useMutation(["upload-file"], async (file: File) => {
|
||||||
|
console.log(`Начинаем загрузку файла: ${file.name} (${file.size} байт)`);
|
||||||
setIsUploading(true);
|
setIsUploading(true);
|
||||||
|
setUploadProgress(0);
|
||||||
|
setUploadError(null); // Сбрасываем ошибку перед началом новой загрузки
|
||||||
|
|
||||||
const formData = new FormData();
|
try {
|
||||||
formData.append("file", file);
|
// Для маленьких файлов используем обычную загрузку, но с теми же заголовками
|
||||||
|
if (file.size <= MAX_CHUNK_SIZE) {
|
||||||
|
console.log("Используем обычную загрузку (файл <= MAX_CHUNK_SIZE)");
|
||||||
|
|
||||||
return request
|
// Подготавливаем заголовки - такие же, как для чанковой загрузки
|
||||||
.post<{
|
const headers: Record<string, string> = {
|
||||||
content_sha256: string;
|
"X-File-Name": btoa(unescape(encodeURIComponent(file.name))), // Имя файла в base64
|
||||||
content_id_v1: string;
|
"X-Chunk-Start": "0", // Начинаем с позиции 0
|
||||||
content_url: string;
|
"Content-Type": file.type || "application/octet-stream",
|
||||||
}>("/storage", formData, {
|
"X-Last-Chunk": "1" // Это единственный и последний чанк
|
||||||
headers: {
|
};
|
||||||
"Content-Type": "multipart/form-data",
|
|
||||||
},
|
|
||||||
|
|
||||||
|
// Добавляем заголовок авторизации
|
||||||
|
const authToken = localStorage.getItem('auth_v1_token');
|
||||||
|
if (authToken) {
|
||||||
|
headers["Authorization"] = authToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Заголовки запроса:", headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await request.post<{
|
||||||
|
upload_id?: string;
|
||||||
|
content_sha256?: string;
|
||||||
|
content_id?: string;
|
||||||
|
content_id_v1?: string;
|
||||||
|
content_url?: string;
|
||||||
|
}>("", file, { // Отправляем файл напрямую вместо FormData
|
||||||
|
baseURL: STORAGE_API_URL,
|
||||||
|
headers,
|
||||||
onUploadProgress: (progressEvent) => {
|
onUploadProgress: (progressEvent) => {
|
||||||
const percentCompleted = Math.round(
|
const percentCompleted = Math.round(
|
||||||
(progressEvent.loaded * 100) / (progressEvent?.total as number) ??
|
(progressEvent.loaded * 100) / (progressEvent?.total as number || file.size)
|
||||||
0,
|
|
||||||
);
|
);
|
||||||
setUploadProgress(percentCompleted);
|
setUploadProgress(Math.min(99, percentCompleted));
|
||||||
},
|
},
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
setIsUploading(false);
|
|
||||||
return response.data;
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setIsUploading(false);
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ...mutation, uploadProgress, isUploading };
|
console.log("Ответ на обычную загрузку:", response.data);
|
||||||
|
setUploadProgress(100);
|
||||||
|
|
||||||
|
return {
|
||||||
|
content_sha256: response.data.content_sha256 || "",
|
||||||
|
content_id_v1: response.data.content_id_v1 || response.data.content_id || "",
|
||||||
|
content_url: response.data.content_url || ""
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Ошибка при обычной загрузке:", error);
|
||||||
|
setUploadError(error instanceof Error ? error : new Error('Ошибка при загрузке файла'));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для больших файлов используем чанковую загрузку
|
||||||
|
console.log("Используем чанкированную загрузку (файл > MAX_CHUNK_SIZE)");
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
let uploadId: string | null = null;
|
||||||
|
let chunkNumber = 0;
|
||||||
|
|
||||||
|
// Загружаем файл по чанкам
|
||||||
|
while (offset < file.size) {
|
||||||
|
chunkNumber++;
|
||||||
|
const chunkEnd = Math.min(offset + MAX_CHUNK_SIZE, file.size);
|
||||||
|
const chunk = file.slice(offset, chunkEnd);
|
||||||
|
console.log(`Загрузка чанка #${chunkNumber} начиная с байта ${offset}`);
|
||||||
|
|
||||||
|
// Определяем, является ли текущий чанк последним
|
||||||
|
const isLastChunk = chunkEnd === file.size;
|
||||||
|
|
||||||
|
// Подготавливаем заголовки
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
"X-File-Name": btoa(unescape(encodeURIComponent(file.name))), // Имя файла в base64
|
||||||
|
"X-Chunk-Start": offset.toString(),
|
||||||
|
"Content-Type": file.type || "application/octet-stream"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Добавляем маркер последнего чанка, если это последний чанк
|
||||||
|
if (isLastChunk) {
|
||||||
|
headers["X-Last-Chunk"] = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем заголовок авторизации
|
||||||
|
const authToken = localStorage.getItem('auth_v1_token');
|
||||||
|
if (authToken) {
|
||||||
|
headers["Authorization"] = authToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если есть uploadId, добавляем его в заголовки
|
||||||
|
if (uploadId) {
|
||||||
|
headers["X-Upload-ID"] = uploadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Заголовки запроса:", headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await request.post<{
|
||||||
|
upload_id?: string;
|
||||||
|
current_size?: number;
|
||||||
|
content_id?: string;
|
||||||
|
content_sha256?: string;
|
||||||
|
content_id_v1?: string;
|
||||||
|
content_url?: string;
|
||||||
|
}>("", chunk, {
|
||||||
|
baseURL: STORAGE_API_URL,
|
||||||
|
headers,
|
||||||
|
onUploadProgress: (progressEvent) => {
|
||||||
|
// Прогресс загрузки текущего чанка
|
||||||
|
const overallProgress = offset + progressEvent.loaded;
|
||||||
|
const percentCompleted = Math.round((overallProgress / file.size) * 100);
|
||||||
|
setUploadProgress(Math.min(99, percentCompleted));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Ответ на чанк #${chunkNumber}:`, response.data);
|
||||||
|
|
||||||
|
// Сохраняем uploadId из первого ответа, если не установлен
|
||||||
|
if (!uploadId && response.data.upload_id) {
|
||||||
|
uploadId = response.data.upload_id;
|
||||||
|
console.log("Получен upload_id:", uploadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка на наличие content_id
|
||||||
|
if (response.data.content_id) {
|
||||||
|
console.log("Загрузка завершена. ID файла:", response.data.content_id);
|
||||||
|
setUploadProgress(100);
|
||||||
|
|
||||||
|
return {
|
||||||
|
content_sha256: response.data.content_sha256 || "",
|
||||||
|
content_id_v1: response.data.content_id_v1 || response.data.content_id || "",
|
||||||
|
content_url: response.data.content_url || ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем смещение на основе ответа сервера
|
||||||
|
if (response.data.current_size !== undefined) {
|
||||||
|
offset = response.data.current_size;
|
||||||
|
console.log(`Сервер сообщает current_size: ${offset}`);
|
||||||
|
} else {
|
||||||
|
console.warn("Неожиданный ответ от сервера, отсутствует current_size");
|
||||||
|
const error = new Error("Missing current_size in response");
|
||||||
|
setUploadError(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`Ошибка при загрузке чанка #${chunkNumber}:`, error);
|
||||||
|
if (error.response) {
|
||||||
|
console.error("Ответ сервера:", error.response.status, error.response.data);
|
||||||
|
}
|
||||||
|
setUploadError(error instanceof Error ? error : new Error(`Ошибка при загрузке чанка #${chunkNumber}`));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = new Error("Ошибка загрузки файла: все чанки загружены, но content_id не получен");
|
||||||
|
console.error(error.message);
|
||||||
|
setUploadError(error);
|
||||||
|
throw error;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("Ошибка при загрузке:", error);
|
||||||
|
if (error.response) {
|
||||||
|
console.error("Ответ сервера:", error.response.status, error.response.data);
|
||||||
|
}
|
||||||
|
setUploadError(error instanceof Error ? error : new Error("Неизвестная ошибка при загрузке"));
|
||||||
|
setIsUploading(false);
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
setIsUploading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Сбросить ошибку
|
||||||
|
const resetUploadError = () => setUploadError(null);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...mutation,
|
||||||
|
uploadProgress,
|
||||||
|
isUploading,
|
||||||
|
uploadError,
|
||||||
|
resetUploadError
|
||||||
|
};
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import * as Sentry from "@sentry/react";
|
||||||
|
import {
|
||||||
|
createRoutesFromChildren,
|
||||||
|
matchRoutes,
|
||||||
|
useLocation,
|
||||||
|
useNavigationType,
|
||||||
|
} from "react-router-dom";
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: import.meta.env.VITE_SENTRY_DSN,
|
||||||
|
integrations: [
|
||||||
|
// See docs for support of different versions of variation of react router
|
||||||
|
// https://docs.sentry.io/platforms/javascript/guides/react/configuration/integrations/react-router/
|
||||||
|
Sentry.reactRouterV6BrowserTracingIntegration({
|
||||||
|
useEffect,
|
||||||
|
useLocation,
|
||||||
|
useNavigationType,
|
||||||
|
createRoutesFromChildren,
|
||||||
|
matchRoutes,
|
||||||
|
}),
|
||||||
|
Sentry.replayIntegration(),
|
||||||
|
],
|
||||||
|
enabled: import.meta.env.PROD, // Only enable in production
|
||||||
|
environment: import.meta.env.MODE, // Set the environment
|
||||||
|
// Set tracesSampleRate to 1.0 to capture 100%
|
||||||
|
// of transactions for tracing.
|
||||||
|
// Learn more at
|
||||||
|
// https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
|
||||||
|
tracesSampleRate: 1,
|
||||||
|
|
||||||
|
// Set `tracePropagationTargets` to control for which URLs trace propagation should be enabled
|
||||||
|
tracePropagationTargets: [
|
||||||
|
// /^\//,
|
||||||
|
// new RegExp(`^${import.meta.env.VITE_API_BASE_URL}`),
|
||||||
|
],
|
||||||
|
// Capture Replay for 10% of all sessions,
|
||||||
|
// plus for 100% of sessions with an error
|
||||||
|
// Learn more at
|
||||||
|
// https://docs.sentry.io/platforms/javascript/session-replay/configuration/#general-integration-configuration
|
||||||
|
replaysSessionSampleRate: 0,
|
||||||
|
replaysOnErrorSampleRate: 0,
|
||||||
|
});
|
||||||
@@ -1,10 +1,19 @@
|
|||||||
import { create } from "zustand";
|
import { create } from 'zustand';
|
||||||
|
|
||||||
export type Royalty = {
|
export type Royalty = {
|
||||||
address: string;
|
address: string;
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NotificationType = 'success' | 'danger' | 'warning' | 'info';
|
||||||
|
|
||||||
|
interface Notification {
|
||||||
|
id: string;
|
||||||
|
message: string;
|
||||||
|
type: NotificationType;
|
||||||
|
createdAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
type RootStore = {
|
type RootStore = {
|
||||||
name: string;
|
name: string;
|
||||||
setName: (name: string) => void;
|
setName: (name: string) => void;
|
||||||
@@ -13,7 +22,10 @@ type RootStore = {
|
|||||||
setAuthor: (author: string) => void;
|
setAuthor: (author: string) => void;
|
||||||
|
|
||||||
file: File | null;
|
file: File | null;
|
||||||
setFile: (file: File) => void;
|
setFile: (file: File | null) => void;
|
||||||
|
|
||||||
|
fileType: string;
|
||||||
|
setFileType: (type: string) => void;
|
||||||
|
|
||||||
fileSrc: string;
|
fileSrc: string;
|
||||||
setFileSrc: (fileSrc: string) => void;
|
setFileSrc: (fileSrc: string) => void;
|
||||||
@@ -21,6 +33,9 @@ type RootStore = {
|
|||||||
allowCover: boolean;
|
allowCover: boolean;
|
||||||
setAllowCover: (allowCover: boolean) => void;
|
setAllowCover: (allowCover: boolean) => void;
|
||||||
|
|
||||||
|
allowDwnld: boolean;
|
||||||
|
setAllowDwnld: (allowDwnld: boolean) => void;
|
||||||
|
|
||||||
cover: File | null;
|
cover: File | null;
|
||||||
setCover: (cover: File | null) => void;
|
setCover: (cover: File | null) => void;
|
||||||
|
|
||||||
@@ -41,24 +56,37 @@ type RootStore = {
|
|||||||
|
|
||||||
licenseResalePrice: number;
|
licenseResalePrice: number;
|
||||||
setLicenseResalePrice: (licenseResalePrice: number) => void;
|
setLicenseResalePrice: (licenseResalePrice: number) => void;
|
||||||
|
|
||||||
|
hashtags: string[];
|
||||||
|
setHashtags: (hashtags: string[]) => void;
|
||||||
|
|
||||||
|
notifications: Notification[];
|
||||||
|
addNotification: (message: string, type: NotificationType) => void;
|
||||||
|
removeNotification: (id: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useRootStore = create<RootStore>((set) => ({
|
export const useRootStore = create<RootStore>((set) => ({
|
||||||
name: "",
|
name: '',
|
||||||
setName: (name) => set({ name }),
|
setName: (name) => set({ name }),
|
||||||
|
|
||||||
author: "",
|
author: '',
|
||||||
setAuthor: (author) => set({ author }),
|
setAuthor: (author) => set({ author }),
|
||||||
|
|
||||||
file: null,
|
file: null,
|
||||||
setFile: (file) => set({ file }),
|
setFile: (file) => set({ file }),
|
||||||
|
|
||||||
fileSrc: "",
|
fileType: '',
|
||||||
|
setFileType: (fileType) => set({ fileType }),
|
||||||
|
|
||||||
|
fileSrc: '',
|
||||||
setFileSrc: (fileSrc) => set({ fileSrc }),
|
setFileSrc: (fileSrc) => set({ fileSrc }),
|
||||||
|
|
||||||
allowCover: false,
|
allowCover: false,
|
||||||
setAllowCover: (allowCover) => set({ allowCover }),
|
setAllowCover: (allowCover) => set({ allowCover }),
|
||||||
|
|
||||||
|
allowDwnld: false,
|
||||||
|
setAllowDwnld: (allowDwnld) => set({ allowDwnld }),
|
||||||
|
|
||||||
cover: null,
|
cover: null,
|
||||||
setCover: (cover) => set({ cover }),
|
setCover: (cover) => set({ cover }),
|
||||||
|
|
||||||
@@ -68,10 +96,10 @@ export const useRootStore = create<RootStore>((set) => ({
|
|||||||
authors: [],
|
authors: [],
|
||||||
setAuthors: (authors) => set({ authors }),
|
setAuthors: (authors) => set({ authors }),
|
||||||
|
|
||||||
royalty: [{ address: "", value: 100 }],
|
royalty: [],
|
||||||
setRoyalty: (royalty) => set({ royalty }),
|
setRoyalty: (royalty) => set({ royalty }),
|
||||||
|
|
||||||
price: 0,
|
price: 0.15,
|
||||||
setPrice: (price: number) => set({ price }),
|
setPrice: (price: number) => set({ price }),
|
||||||
|
|
||||||
allowResale: false,
|
allowResale: false,
|
||||||
@@ -79,4 +107,29 @@ export const useRootStore = create<RootStore>((set) => ({
|
|||||||
|
|
||||||
licenseResalePrice: 0,
|
licenseResalePrice: 0,
|
||||||
setLicenseResalePrice: (licenseResalePrice) => set({ licenseResalePrice }),
|
setLicenseResalePrice: (licenseResalePrice) => set({ licenseResalePrice }),
|
||||||
|
|
||||||
|
hashtags: [],
|
||||||
|
setHashtags: (hashtags: string[]) => set({ hashtags }),
|
||||||
|
|
||||||
|
notifications: [],
|
||||||
|
|
||||||
|
addNotification: (message: string, type: NotificationType = 'info') => {
|
||||||
|
const id = Date.now().toString();
|
||||||
|
const notification = {
|
||||||
|
id,
|
||||||
|
message,
|
||||||
|
type,
|
||||||
|
createdAt: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
set((state) => ({
|
||||||
|
notifications: [...state.notifications, notification],
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
removeNotification: (id: string) => {
|
||||||
|
set((state) => ({
|
||||||
|
notifications: state.notifications.filter((notification) => notification.id !== id),
|
||||||
|
}));
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import { FC, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
interface AudioPlayerProps {
|
||||||
|
src: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AudioPlayer: FC<AudioPlayerProps> = ({ src }) => {
|
||||||
|
const [isPlaying, setIsPlaying] = useState<boolean>(false);
|
||||||
|
const [currentTime, setCurrentTime] = useState<number>(0);
|
||||||
|
const [duration, setDuration] = useState<number>(0);
|
||||||
|
const audioRef = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const rangeRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const audio = audioRef.current;
|
||||||
|
|
||||||
|
if (!audio) return;
|
||||||
|
|
||||||
|
const handleLoadedMetadata = () => {
|
||||||
|
setDuration(audio.duration);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTimeUpdate = () => {
|
||||||
|
setCurrentTime(audio.currentTime);
|
||||||
|
updateRangeBackground(audio.currentTime);
|
||||||
|
};
|
||||||
|
|
||||||
|
audio.addEventListener("loadedmetadata", handleLoadedMetadata);
|
||||||
|
audio.addEventListener("timeupdate", handleTimeUpdate);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
audio.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
||||||
|
audio.removeEventListener("timeupdate", handleTimeUpdate);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const togglePlayPause = () => {
|
||||||
|
const audio = audioRef.current;
|
||||||
|
if (!audio) return;
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
audio.pause();
|
||||||
|
} else {
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
setIsPlaying(!isPlaying);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const audio = audioRef.current;
|
||||||
|
if (!audio) return;
|
||||||
|
|
||||||
|
const newTime = parseFloat(e.target.value);
|
||||||
|
audio.currentTime = newTime;
|
||||||
|
setCurrentTime(newTime);
|
||||||
|
updateRangeBackground(newTime);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatTime = (time: number): string => {
|
||||||
|
const minutes = Math.floor(time / 60);
|
||||||
|
const seconds = Math.floor(time % 60);
|
||||||
|
return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRangeBackground = (currentTime: number) => {
|
||||||
|
if (rangeRef.current) {
|
||||||
|
const percentage = (currentTime / duration) * 100;
|
||||||
|
rangeRef.current.style.setProperty(
|
||||||
|
"--value-percentage",
|
||||||
|
`${percentage}%`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center space-x-4">
|
||||||
|
<audio ref={audioRef} autoPlay={true} src={src} />
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={togglePlayPause}
|
||||||
|
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white text-gray focus:outline-none"
|
||||||
|
>
|
||||||
|
{isPlaying ? (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
className="size-6"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M6.75 5.25a.75.75 0 0 1 .75-.75H9a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H7.5a.75.75 0 0 1-.75-.75V5.25Zm7.5 0A.75.75 0 0 1 15 4.5h1.5a.75.75 0 0 1 .75.75v13.5a.75.75 0 0 1-.75.75H15a.75.75 0 0 1-.75-.75V5.25Z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
className="size-6"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.347c1.295.712 1.295 2.573 0 3.286L7.28 19.99c-1.25.687-2.779-.217-2.779-1.643V5.653Z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className={"flex w-full flex-col gap-2"}>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
ref={rangeRef}
|
||||||
|
min="0"
|
||||||
|
max={duration}
|
||||||
|
value={currentTime}
|
||||||
|
onChange={handleSliderChange}
|
||||||
|
className="flex-grow"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between text-xs">
|
||||||
|
<span>{formatTime(currentTime)}</span>
|
||||||
|
<span>{formatTime(duration)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { WithContext as ReactTags, SEPARATORS } from "react-tag-input";
|
||||||
|
import { useRootStore } from "~/shared/stores/root";
|
||||||
|
// English comment: no extra Tag interface, just cast to any
|
||||||
|
export const HashtagInput = () => {
|
||||||
|
const { hashtags, setHashtags } = useRootStore();
|
||||||
|
|
||||||
|
// English comment: local state as string[] for simplicity
|
||||||
|
const [tags, setTags] = useState<string[]>(hashtags);
|
||||||
|
|
||||||
|
const separators = [SEPARATORS.ENTER, SEPARATORS.COMMA]
|
||||||
|
const handleDelete = (i: number) => {
|
||||||
|
const newTags = tags.filter((_, index) => index !== i);
|
||||||
|
setTags(newTags);
|
||||||
|
setHashtags(newTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
// English comment: pass "any" to the function
|
||||||
|
const handleAddition = (newTag: any) => {
|
||||||
|
// Clean up text from commas and trim whitespace
|
||||||
|
const text = newTag?.text || newTag?.id || "";
|
||||||
|
const cleanText = text.replace(/,/g, '').trim();
|
||||||
|
|
||||||
|
// Skip empty tags
|
||||||
|
if (!cleanText) return;
|
||||||
|
|
||||||
|
const updatedTags = [...tags, cleanText];
|
||||||
|
setTags(updatedTags);
|
||||||
|
setHashtags(updatedTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simulate Enter keypress for Android
|
||||||
|
const enterEvent = new KeyboardEvent('keydown', {
|
||||||
|
key: 'Enter',
|
||||||
|
code: 'Enter',
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
which: 13,
|
||||||
|
keyCode: 13,
|
||||||
|
});
|
||||||
|
const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (e.key === 'Unidentified') {
|
||||||
|
const lastChar = e.currentTarget.value.slice(-1);
|
||||||
|
if (lastChar === ',') {
|
||||||
|
e.currentTarget.dispatchEvent(enterEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReactTags
|
||||||
|
tags={tags.map((t) => ({ id: t, text: t })) as any}
|
||||||
|
separators={separators as any}
|
||||||
|
handleDelete={handleDelete as any}
|
||||||
|
handleAddition={handleAddition as any}
|
||||||
|
allowDragDrop={false}
|
||||||
|
placeholder="[ введите тэги через запятую ]"
|
||||||
|
inputProps={{
|
||||||
|
onKeyUp: handleKeyUp as any
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export const Replace = () => {
|
||||||
|
return (
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="1">
|
||||||
|
<path d="M15.75 6.01C15.9293 6.01 16.0939 6.07292 16.2229 6.17788C17.3108 7.09184 18.0024 8.46516 18.0024 10C18.0024 12.6888 15.8801 14.8818 13.2193 14.9954L13.0024 15H8.56057L9.78032 16.2197C10.0466 16.4859 10.0708 16.9026 9.85294 17.1962L9.78032 17.2803C9.51406 17.5466 9.09739 17.5708 8.80378 17.3529L8.71966 17.2803L6.21966 14.7803C5.9534 14.5141 5.92919 14.0974 6.14704 13.8038L6.21966 13.7197L8.71966 11.2197C9.01256 10.9268 9.48743 10.9268 9.78032 11.2197C10.0466 11.4859 10.0708 11.9026 9.85294 12.1962L9.78032 12.2803L8.56057 13.5H13.0024C14.871 13.5 16.3975 12.0357 16.4972 10.192L16.5024 10C16.5024 8.91885 16.0122 7.95219 15.2419 7.31017C15.0935 7.17538 15 6.97861 15 6.76C15 6.34579 15.3358 6.01 15.75 6.01ZM10.2197 2.71967C10.4859 2.4534 10.9026 2.4292 11.1962 2.64705L11.2803 2.71967L13.7803 5.21967L13.8529 5.30379C14.0466 5.56478 14.049 5.92299 13.8601 6.18638L13.7803 6.28033L11.2803 8.78033L11.1962 8.85295C10.9352 9.0466 10.577 9.04899 10.3136 8.86012L10.2197 8.78033L10.147 8.69621C9.9534 8.43522 9.951 8.07701 10.1399 7.81362L10.2197 7.71967L11.4386 6.5H6.99757C5.12901 6.5 3.60245 7.96428 3.50275 9.80796L3.49757 10C3.49757 11.0831 3.98958 12.0514 4.7623 12.6934C4.9085 12.8289 4.99999 13.0238 4.99999 13.24C4.99999 13.6542 4.66421 13.99 4.24999 13.99C4.05871 13.99 3.88415 13.9184 3.75166 13.8005C2.67865 12.8872 1.99757 11.5232 1.99757 10C1.99757 7.31124 4.11988 5.11818 6.78068 5.00462L6.99757 5H11.4386L10.2197 3.78033L10.147 3.69621C9.92919 3.4026 9.9534 2.98594 10.2197 2.71967Z" fill="white" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useRootStore } from '~/shared/stores/root';
|
||||||
|
|
||||||
|
interface AnimatedNotification {
|
||||||
|
id: string;
|
||||||
|
message: string;
|
||||||
|
type: 'success' | 'danger' | 'warning' | 'info';
|
||||||
|
isExiting: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Notification = () => {
|
||||||
|
const { notifications, removeNotification } = useRootStore();
|
||||||
|
const [animatedNotifications, setAnimatedNotifications] = useState<AnimatedNotification[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentIds = animatedNotifications.map((n) => n.id);
|
||||||
|
const newNotifications = notifications
|
||||||
|
.filter((n) => !currentIds.includes(n.id))
|
||||||
|
.map((n) => ({ ...n, isExiting: false }));
|
||||||
|
|
||||||
|
if (newNotifications.length > 0) {
|
||||||
|
newNotifications.forEach((notification) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
handleRemove(notification.id);
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
|
||||||
|
setAnimatedNotifications((prev) => [...prev, ...newNotifications]);
|
||||||
|
}
|
||||||
|
}, [notifications]);
|
||||||
|
|
||||||
|
// Функция для начала анимации удаления
|
||||||
|
const handleRemove = (id: string) => {
|
||||||
|
setAnimatedNotifications((prev) =>
|
||||||
|
prev.map((n) => (n.id === id ? { ...n, isExiting: true } : n))
|
||||||
|
);
|
||||||
|
setTimeout(() => {
|
||||||
|
setAnimatedNotifications((prev) => prev.filter((n) => n.id !== id));
|
||||||
|
removeNotification(id);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-x-0 top-2 z-50 flex flex-col items-center gap-2 pointer-events-none">
|
||||||
|
{animatedNotifications.map((notification) => (
|
||||||
|
<div
|
||||||
|
key={notification.id}
|
||||||
|
onClick={() => handleRemove(notification.id)}
|
||||||
|
className={`
|
||||||
|
p-2 rounded shadow-md relative transition-all duration-300 max-w-sm
|
||||||
|
transform origin-top pointer-events-auto cursor-pointer
|
||||||
|
${notification.isExiting ? 'animate-fade-out' : 'animate-slide-in-top'}
|
||||||
|
${getNotificationClass(notification.type)}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div className="text-center">{notification.message}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getNotificationClass = (type: 'success' | 'danger' | 'warning' | 'info'): string => {
|
||||||
|
const baseStyle = 'border border-white bg-opacity-70 backdrop-blur-sm';
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'success':
|
||||||
|
return `${baseStyle} bg-primary text-white`;
|
||||||
|
case 'danger':
|
||||||
|
return `${baseStyle} bg-primary text-white`;
|
||||||
|
case 'warning':
|
||||||
|
return `${baseStyle} bg-primary text-white`;
|
||||||
|
case 'info':
|
||||||
|
default:
|
||||||
|
return `${baseStyle} bg-primary text-white`;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -17,3 +17,5 @@ export const processFile = async (file: File) => {
|
|||||||
|
|
||||||
export const getIndexArray = (len: number) =>
|
export const getIndexArray = (len: number) =>
|
||||||
new Array(len).fill("").map((_, i) => i);
|
new Array(len).fill("").map((_, i) => i);
|
||||||
|
|
||||||
|
export const fromNanoTON = (amount: string) => Number(amount) / 10 ** 9;
|
||||||
+23
-3
@@ -1,11 +1,31 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
gray: "#1d1d1b",
|
gray: '#1d1d1b',
|
||||||
primary: "#e40615",
|
primary: '#e40615',
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
'slide-in-top': {
|
||||||
|
'0%': {
|
||||||
|
transform: 'translateY(-1rem)',
|
||||||
|
opacity: '0',
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
transform: 'translateY(0)',
|
||||||
|
opacity: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'fade-out': {
|
||||||
|
'0%': { opacity: '1' },
|
||||||
|
'100%': { opacity: '0' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
'slide-in-top': 'slide-in-top 0.3s ease-out forwards',
|
||||||
|
'fade-out': 'fade-out 0.3s ease-out forwards',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"rewrites": [{ "source": "/(.*)", "destination": "/" }]
|
||||||
|
}
|
||||||
@@ -4,4 +4,19 @@ import TSPaths from "vite-tsconfig-paths";
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), TSPaths()],
|
plugins: [react(), TSPaths()],
|
||||||
|
define: {
|
||||||
|
global: 'globalThis',
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
buffer: 'buffer/',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
esbuildOptions: {
|
||||||
|
define: {
|
||||||
|
global: 'globalThis'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.22.5"
|
"@babel/helper-plugin-utils" "^7.22.5"
|
||||||
|
|
||||||
"@babel/runtime@^7.23.7", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2":
|
"@babel/runtime@^7.23.7", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.9.2":
|
||||||
version "7.24.0"
|
version "7.24.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz"
|
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz"
|
||||||
integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==
|
integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==
|
||||||
@@ -225,10 +225,10 @@
|
|||||||
"@babel/helper-validator-identifier" "^7.22.20"
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@esbuild/darwin-arm64@0.19.12":
|
"@esbuild/win32-x64@0.19.12":
|
||||||
version "0.19.12"
|
version "0.19.12"
|
||||||
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz"
|
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz"
|
||||||
integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==
|
integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==
|
||||||
|
|
||||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
@@ -361,15 +361,247 @@
|
|||||||
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz"
|
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz"
|
||||||
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
|
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
|
||||||
|
|
||||||
|
"@react-dnd/asap@^4.0.0":
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz"
|
||||||
|
integrity sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==
|
||||||
|
|
||||||
|
"@react-dnd/invariant@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz"
|
||||||
|
integrity sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==
|
||||||
|
|
||||||
|
"@react-dnd/shallowequal@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz"
|
||||||
|
integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==
|
||||||
|
|
||||||
"@remix-run/router@1.15.2":
|
"@remix-run/router@1.15.2":
|
||||||
version "1.15.2"
|
version "1.15.2"
|
||||||
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz"
|
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz"
|
||||||
integrity sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==
|
integrity sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==
|
||||||
|
|
||||||
"@rollup/rollup-darwin-arm64@4.12.0":
|
"@rollup/rollup-win32-x64-msvc@4.12.0":
|
||||||
version "4.12.0"
|
version "4.12.0"
|
||||||
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz"
|
resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz"
|
||||||
integrity sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==
|
integrity sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==
|
||||||
|
|
||||||
|
"@sentry-internal/browser-utils@9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.1.0.tgz"
|
||||||
|
integrity sha512-S1uT+kkFlstWpwnaBTIJSwwAID8PS3aA0fIidOjNezeoUE5gOvpsjDATo9q+sl6FbGWynxMz6EnYSrq/5tuaBQ==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/core" "9.1.0"
|
||||||
|
|
||||||
|
"@sentry-internal/feedback@9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.1.0.tgz"
|
||||||
|
integrity sha512-jTDCqkqH3QDC8m9WO4mB06hqnBRsl3p7ozoh0E774UvNB6blOEZjShhSGMMEy5jbbJajPWsOivCofUtFAwbfGw==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/core" "9.1.0"
|
||||||
|
|
||||||
|
"@sentry-internal/replay-canvas@9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.1.0.tgz"
|
||||||
|
integrity sha512-gxredVe+mOgfNqDJ3dTLiRON3FK1rZ8d0LHp7TICK/umLkWFkuso0DbNeyKU+3XCEjCr9VM7ZRqTDMzmY6zyVg==
|
||||||
|
dependencies:
|
||||||
|
"@sentry-internal/replay" "9.1.0"
|
||||||
|
"@sentry/core" "9.1.0"
|
||||||
|
|
||||||
|
"@sentry-internal/replay@9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.1.0.tgz"
|
||||||
|
integrity sha512-E2xrUoms90qvm0BVOuaZ8QfkMoTUEgoIW/35uOeaqNcL7uOIj8c5cSEQQKit2Dr7CL6W+Ci5c6Khdyd5C0NL5w==
|
||||||
|
dependencies:
|
||||||
|
"@sentry-internal/browser-utils" "9.1.0"
|
||||||
|
"@sentry/core" "9.1.0"
|
||||||
|
|
||||||
|
"@sentry/browser@9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry/browser/-/browser-9.1.0.tgz"
|
||||||
|
integrity sha512-G55e5j77DqRW3LkalJLAjRRfuyKrjHaKTnwIYXa6ycO+Q1+l14pEUxu+eK5Abu2rtSdViwRSb5/G6a/miSUlYA==
|
||||||
|
dependencies:
|
||||||
|
"@sentry-internal/browser-utils" "9.1.0"
|
||||||
|
"@sentry-internal/feedback" "9.1.0"
|
||||||
|
"@sentry-internal/replay" "9.1.0"
|
||||||
|
"@sentry-internal/replay-canvas" "9.1.0"
|
||||||
|
"@sentry/core" "9.1.0"
|
||||||
|
|
||||||
|
"@sentry/core@9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry/core/-/core-9.1.0.tgz"
|
||||||
|
integrity sha512-djWEzSBpMgqdF3GQuxO+kXCUX+Mgq42G4Uah/HSUBvPDHKipMmyWlutGRoFyVPPOnCDgpHu3wCt83wbpEyVmDw==
|
||||||
|
|
||||||
|
"@sentry/react@^9.1.0":
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@sentry/react/-/react-9.1.0.tgz"
|
||||||
|
integrity sha512-aP2sXHH+erbomuzU762ktg340IGDh8zD7ueuqwBwGu98fhCpTYsLXiS85I29tUvPLljwNU9puLPmxbgW4iZ2tQ==
|
||||||
|
dependencies:
|
||||||
|
"@sentry/browser" "9.1.0"
|
||||||
|
"@sentry/core" "9.1.0"
|
||||||
|
hoist-non-react-statics "^3.3.2"
|
||||||
|
|
||||||
|
"@telegram-apps/bridge@^1.9.2":
|
||||||
|
version "1.9.2"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/bridge/-/bridge-1.9.2.tgz"
|
||||||
|
integrity sha512-SJLcNWLXhbbZr9MiqFH/g2ceuitSJKMxUIZysK4zUNyTUNuonrQG80Q/yrO+XiNbKUj8WdDNM86NBARhuyyinQ==
|
||||||
|
dependencies:
|
||||||
|
"@telegram-apps/signals" "^1.1.1"
|
||||||
|
"@telegram-apps/toolkit" "^1.1.1"
|
||||||
|
"@telegram-apps/transformers" "^1.2.2"
|
||||||
|
"@telegram-apps/types" "^1.2.1"
|
||||||
|
|
||||||
|
"@telegram-apps/bridge@^2.4.0":
|
||||||
|
version "2.4.0"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/bridge/-/bridge-2.4.0.tgz"
|
||||||
|
integrity sha512-Lp/vhspF7okK8zXvSWWirunKXOPE6Gr11o9VBne4VmKG/yHRhEW7Pf07ncPtXLLzI6wW8+VYc3khsHPABJymEw==
|
||||||
|
dependencies:
|
||||||
|
"@telegram-apps/signals" "^1.1.1"
|
||||||
|
"@telegram-apps/toolkit" "^2.0.0"
|
||||||
|
"@telegram-apps/transformers" "^2.2.0"
|
||||||
|
"@telegram-apps/types" "^2.0.0"
|
||||||
|
better-promises "^0.4.0"
|
||||||
|
error-kid "^0.0.4"
|
||||||
|
mitt "^3.0.1"
|
||||||
|
valibot "1.0.0-beta.14"
|
||||||
|
|
||||||
|
"@telegram-apps/navigation@^1.0.13":
|
||||||
|
version "1.0.13"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/navigation/-/navigation-1.0.13.tgz"
|
||||||
|
integrity sha512-TsUueB5LQp77GQHoMa93nq26Uw7GJjrFCPbyseMVU7aBBxAc+8CV2IYytRwcVp5sv/q7ThK5X4JaKn2V1yBHDQ==
|
||||||
|
dependencies:
|
||||||
|
"@telegram-apps/bridge" "^1.9.2"
|
||||||
|
"@telegram-apps/signals" "^1.1.1"
|
||||||
|
"@telegram-apps/toolkit" "^1.1.1"
|
||||||
|
|
||||||
|
"@telegram-apps/sdk@^3.5.1":
|
||||||
|
version "3.5.1"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/sdk/-/sdk-3.5.1.tgz"
|
||||||
|
integrity sha512-m/ynpSozXsqq6Kfb6M9fm8SD6x/+jqvTFT59FuuOBvC+G8eMd0F+fvZdr6Pj0I6IL9M67nrfm92JpTu/aVNEjw==
|
||||||
|
dependencies:
|
||||||
|
"@telegram-apps/bridge" "^2.4.0"
|
||||||
|
"@telegram-apps/navigation" "^1.0.13"
|
||||||
|
"@telegram-apps/signals" "^1.1.1"
|
||||||
|
"@telegram-apps/toolkit" "^2.0.0"
|
||||||
|
"@telegram-apps/transformers" "^2.2.0"
|
||||||
|
"@telegram-apps/types" "^2.0.0"
|
||||||
|
better-promises "^0.4.0"
|
||||||
|
error-kid "^0.0.4"
|
||||||
|
valibot "1.0.0-beta.14"
|
||||||
|
|
||||||
|
"@telegram-apps/signals@^1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/signals/-/signals-1.1.1.tgz"
|
||||||
|
integrity sha512-vz37r8lemGpPzDiBRfqpXYBynzmy3SFnY6zfHsTZABTYYt0b0WQZyU5mFDqqqugGhka78Gy11xmr9csgy4YgGA==
|
||||||
|
|
||||||
|
"@telegram-apps/toolkit@^1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/toolkit/-/toolkit-1.1.1.tgz"
|
||||||
|
integrity sha512-+vhKx6ngfvjyTE6Xagl3z1TPVbfx5s7xAkcYzCdHYUo6T60jLIqLgyZMcI1UPoIAMuMu1pHoO+p8QNCj/+tFmw==
|
||||||
|
|
||||||
|
"@telegram-apps/toolkit@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/toolkit/-/toolkit-2.0.0.tgz"
|
||||||
|
integrity sha512-1GKTLBNme1Phu/gFvgS9NWPq+LhPfzSIfnwhcF9I/6tCdufrLRcVaSMRiK9R4VDYD6iZUyj+a2l250qWAxxjQQ==
|
||||||
|
|
||||||
|
"@telegram-apps/transformers@^1.2.2":
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/transformers/-/transformers-1.2.2.tgz"
|
||||||
|
integrity sha512-vvMwXckd1D7Ozc0h66PSUwF5QLrRV9HlGJFFeBuUex8QEk5mSPtsJkLiqB8aBbwuFDa91+TUSM/CxqPZO/e9YQ==
|
||||||
|
dependencies:
|
||||||
|
"@telegram-apps/toolkit" "^1.1.1"
|
||||||
|
"@telegram-apps/types" "^1.2.1"
|
||||||
|
|
||||||
|
"@telegram-apps/transformers@^2.2.0":
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/transformers/-/transformers-2.2.0.tgz"
|
||||||
|
integrity sha512-wqXXOukhEjZKhzdq5vG1LkxWL11DApbmUKzk+3nA/ki3TLyD3awVTOXbpoNdOwFl2xliIooYcsUOEl4WCyyLGw==
|
||||||
|
dependencies:
|
||||||
|
"@telegram-apps/toolkit" "^2.0.0"
|
||||||
|
"@telegram-apps/types" "^2.0.0"
|
||||||
|
valibot "1.0.0-beta.14"
|
||||||
|
|
||||||
|
"@telegram-apps/types@^1.2.1":
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/types/-/types-1.2.1.tgz"
|
||||||
|
integrity sha512-so4HLh7clur0YyMthi9KVIgWoGpZdXlFOuQjk3+Q5NAvJZ11nAheBSwPlGw/Ko92+zwvrSBE/lQyN2+p17RP+w==
|
||||||
|
|
||||||
|
"@telegram-apps/types@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@telegram-apps/types/-/types-2.0.0.tgz"
|
||||||
|
integrity sha512-yF499FJK82a2IDNDAQdrmVH3sgFZl/QFNdVZKgWpgtunIVJ1fres5wi9+4aUBRVIdQwZOZZqB/AOvYYuYXsq3Q==
|
||||||
|
|
||||||
|
"@ton/core@^0.59.1":
|
||||||
|
version "0.59.1"
|
||||||
|
resolved "https://registry.npmjs.org/@ton/core/-/core-0.59.1.tgz"
|
||||||
|
integrity sha512-SxFBAvutYJaIllTkv82vbHTJhJI6NxzqUhi499CDEjJEZ9i6i9lHJiK2df4dlLAb/4SiWX6+QUzESkK4DEdnCw==
|
||||||
|
dependencies:
|
||||||
|
symbol.inspect "1.0.1"
|
||||||
|
|
||||||
|
"@ton/crypto-primitives@2.1.0":
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@ton/crypto-primitives/-/crypto-primitives-2.1.0.tgz"
|
||||||
|
integrity sha512-PQesoyPgqyI6vzYtCXw4/ZzevePc4VGcJtFwf08v10OevVJHVfW238KBdpj1kEDQkxWLeuNHEpTECNFKnP6tow==
|
||||||
|
dependencies:
|
||||||
|
jssha "3.2.0"
|
||||||
|
|
||||||
|
"@ton/crypto@>=3.2.0":
|
||||||
|
version "3.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/@ton/crypto/-/crypto-3.3.0.tgz"
|
||||||
|
integrity sha512-/A6CYGgA/H36OZ9BbTaGerKtzWp50rg67ZCH2oIjV1NcrBaCK9Z343M+CxedvM7Haf3f/Ee9EhxyeTp0GKMUpA==
|
||||||
|
dependencies:
|
||||||
|
"@ton/crypto-primitives" "2.1.0"
|
||||||
|
jssha "3.2.0"
|
||||||
|
tweetnacl "1.0.3"
|
||||||
|
|
||||||
|
"@tonconnect/isomorphic-eventsource@^0.0.2":
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.npmjs.org/@tonconnect/isomorphic-eventsource/-/isomorphic-eventsource-0.0.2.tgz"
|
||||||
|
integrity sha512-B4UoIjPi0QkvIzZH5fV3BQLWrqSYABdrzZQSI9sJA9aA+iC0ohOzFwVVGXanlxeDAy1bcvPbb29f6sVUk0UnnQ==
|
||||||
|
dependencies:
|
||||||
|
eventsource "^2.0.2"
|
||||||
|
|
||||||
|
"@tonconnect/isomorphic-fetch@^0.0.3":
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/@tonconnect/isomorphic-fetch/-/isomorphic-fetch-0.0.3.tgz"
|
||||||
|
integrity sha512-jIg5nTrDwnite4fXao3dD83eCpTvInTjZon/rZZrIftIegh4XxyVb5G2mpMqXrVGk1e8SVXm3Kj5OtfMplQs0w==
|
||||||
|
dependencies:
|
||||||
|
node-fetch "^2.6.9"
|
||||||
|
|
||||||
|
"@tonconnect/protocol@^2.2.6":
|
||||||
|
version "2.2.6"
|
||||||
|
resolved "https://registry.npmjs.org/@tonconnect/protocol/-/protocol-2.2.6.tgz"
|
||||||
|
integrity sha512-kyoDz5EqgsycYP+A+JbVsAUYHNT059BCrK+m0pqxykMODwpziuSAXfwAZmHcg8v7NB9VKYbdFY55xKeXOuEd0w==
|
||||||
|
dependencies:
|
||||||
|
tweetnacl "^1.0.3"
|
||||||
|
tweetnacl-util "^0.15.1"
|
||||||
|
|
||||||
|
"@tonconnect/sdk@3.0.6":
|
||||||
|
version "3.0.6"
|
||||||
|
resolved "https://registry.npmjs.org/@tonconnect/sdk/-/sdk-3.0.6.tgz"
|
||||||
|
integrity sha512-dJipe0Cw43p/7o3Pa6Y6h0QMDtY2V2YKzwdCqcYvmyCYadBNmvA+8ScH9QK5GpkngRJnYaWq+321lAaQTFpUwA==
|
||||||
|
dependencies:
|
||||||
|
"@tonconnect/isomorphic-eventsource" "^0.0.2"
|
||||||
|
"@tonconnect/isomorphic-fetch" "^0.0.3"
|
||||||
|
"@tonconnect/protocol" "^2.2.6"
|
||||||
|
|
||||||
|
"@tonconnect/ui-react@^2.0.2":
|
||||||
|
version "2.0.11"
|
||||||
|
resolved "https://registry.npmjs.org/@tonconnect/ui-react/-/ui-react-2.0.11.tgz"
|
||||||
|
integrity sha512-h8E4zlbdNBJCAPgg6+O5ZkVDZh8mvnc82VRmhInSPLFAr6qDZbE+qSjRVm4lkuN1N/m24lhkDXFCFjvJ9CgCow==
|
||||||
|
dependencies:
|
||||||
|
"@tonconnect/ui" "2.0.11"
|
||||||
|
|
||||||
|
"@tonconnect/ui@2.0.11":
|
||||||
|
version "2.0.11"
|
||||||
|
resolved "https://registry.npmjs.org/@tonconnect/ui/-/ui-2.0.11.tgz"
|
||||||
|
integrity sha512-5TOhfEDeyY8R9oyEGavLU+DRmDW3wSGyxVshWhHisi8597cZIuG39HHNbP05WJBBjmVm/Kh/bhcHtfx7lQp/Ig==
|
||||||
|
dependencies:
|
||||||
|
"@tonconnect/sdk" "3.0.6"
|
||||||
|
classnames "^2.3.2"
|
||||||
|
csstype "^3.1.1"
|
||||||
|
deepmerge "^4.2.2"
|
||||||
|
ua-parser-js "^1.0.35"
|
||||||
|
|
||||||
"@types/babel__core@^7.20.5":
|
"@types/babel__core@^7.20.5":
|
||||||
version "7.20.5"
|
version "7.20.5"
|
||||||
@@ -419,7 +651,19 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
|
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
|
||||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||||
|
|
||||||
"@types/node@^18.0.0 || >=20.0.0", "@types/node@^20.11.24":
|
"@types/lodash-es@^4.17.12":
|
||||||
|
version "4.17.12"
|
||||||
|
resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz"
|
||||||
|
integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
|
"@types/lodash@*":
|
||||||
|
version "4.17.15"
|
||||||
|
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz"
|
||||||
|
integrity sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==
|
||||||
|
|
||||||
|
"@types/node@^18.0.0 || >=20.0.0", "@types/node@^20.11.24", "@types/node@>= 12":
|
||||||
version "20.11.24"
|
version "20.11.24"
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz"
|
||||||
integrity sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==
|
integrity sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==
|
||||||
@@ -438,7 +682,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^18.2.56", "@types/react@>=16.8":
|
"@types/react@*", "@types/react@^18.2.56", "@types/react@>= 16", "@types/react@>=16.8":
|
||||||
version "18.2.61"
|
version "18.2.61"
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-18.2.61.tgz"
|
resolved "https://registry.npmjs.org/@types/react/-/react-18.2.61.tgz"
|
||||||
integrity sha512-NURTN0qNnJa7O/k4XUkEW2yfygA+NxS0V5h1+kp9jPwhzZy95q3ADoGMP0+JypMhrZBTTgjKAUlTctde1zzeQA==
|
integrity sha512-NURTN0qNnJa7O/k4XUkEW2yfygA+NxS0V5h1+kp9jPwhzZy95q3ADoGMP0+JypMhrZBTTgjKAUlTctde1zzeQA==
|
||||||
@@ -761,6 +1005,18 @@ balanced-match@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||||
|
|
||||||
|
base64-js@^1.3.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
|
||||||
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
|
better-promises@^0.4.0:
|
||||||
|
version "0.4.0"
|
||||||
|
resolved "https://registry.npmjs.org/better-promises/-/better-promises-0.4.0.tgz"
|
||||||
|
integrity sha512-AcKkTUSd4o1vMf41eBbHW1NkY7vrXeNI6etitGdQE54WFXsF2wkfonrKA06Za7lViRNyT/cMvj5z+DScqhYW8A==
|
||||||
|
dependencies:
|
||||||
|
error-kid "^0.0.4"
|
||||||
|
|
||||||
big-integer@^1.6.16:
|
big-integer@^1.6.16:
|
||||||
version "1.6.52"
|
version "1.6.52"
|
||||||
resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz"
|
resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz"
|
||||||
@@ -817,6 +1073,14 @@ browserslist@^4.22.2, browserslist@^4.23.0, "browserslist@>= 4.21.0":
|
|||||||
node-releases "^2.0.14"
|
node-releases "^2.0.14"
|
||||||
update-browserslist-db "^1.0.13"
|
update-browserslist-db "^1.0.13"
|
||||||
|
|
||||||
|
buffer@^6.0.3:
|
||||||
|
version "6.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
|
||||||
|
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
|
||||||
|
dependencies:
|
||||||
|
base64-js "^1.3.1"
|
||||||
|
ieee754 "^1.2.1"
|
||||||
|
|
||||||
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
|
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
|
||||||
@@ -875,6 +1139,16 @@ chokidar@^3.5.3:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
classnames@^2.3.2:
|
||||||
|
version "2.5.1"
|
||||||
|
resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz"
|
||||||
|
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
|
||||||
|
|
||||||
|
classnames@~2.3.1:
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.3.tgz"
|
||||||
|
integrity sha512-1inzZmicIFcmUya7PGtUQeXtcF7zZpPnxtQoYOrz0uiOBGlLFa4ik4361seYL2JCcRDIyfdFHiwQolESFlw+Og==
|
||||||
|
|
||||||
clsx@^2.1.0:
|
clsx@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz"
|
||||||
@@ -940,7 +1214,7 @@ cssesc@^3.0.0:
|
|||||||
resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
|
resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
|
||||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||||
|
|
||||||
csstype@^3.0.2:
|
csstype@^3.0.2, csstype@^3.1.1:
|
||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
|
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
|
||||||
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
|
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
|
||||||
@@ -964,7 +1238,7 @@ deep-is@^0.1.3:
|
|||||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
||||||
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||||
|
|
||||||
deepmerge@^4.0.0:
|
deepmerge@^4.0.0, deepmerge@^4.2.2:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz"
|
resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz"
|
||||||
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
|
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
|
||||||
@@ -1014,6 +1288,15 @@ dlv@^1.1.3:
|
|||||||
resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz"
|
resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz"
|
||||||
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
|
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
|
||||||
|
|
||||||
|
dnd-core@14.0.1:
|
||||||
|
version "14.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/dnd-core/-/dnd-core-14.0.1.tgz"
|
||||||
|
integrity sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A==
|
||||||
|
dependencies:
|
||||||
|
"@react-dnd/asap" "^4.0.0"
|
||||||
|
"@react-dnd/invariant" "^2.0.0"
|
||||||
|
redux "^4.1.1"
|
||||||
|
|
||||||
doctrine@^2.1.0:
|
doctrine@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz"
|
||||||
@@ -1048,6 +1331,11 @@ emoji-regex@^9.2.2:
|
|||||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
|
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
|
||||||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
||||||
|
|
||||||
|
error-kid@^0.0.4:
|
||||||
|
version "0.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/error-kid/-/error-kid-0.0.4.tgz"
|
||||||
|
integrity sha512-x+yQhY56SorLMnX6kOf+z3JCv2QBurcWEDcIjgxYtVr4fGeCfAtOdZOCyWttkHHDFPtL2PqnaRUmphbmALJd9w==
|
||||||
|
|
||||||
es-abstract@^1.22.1, es-abstract@^1.22.3:
|
es-abstract@^1.22.1, es-abstract@^1.22.3:
|
||||||
version "1.22.5"
|
version "1.22.5"
|
||||||
resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz"
|
resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz"
|
||||||
@@ -1333,6 +1621,11 @@ esutils@^2.0.2:
|
|||||||
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
|
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
|
||||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||||
|
|
||||||
|
eventsource@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz"
|
||||||
|
integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==
|
||||||
|
|
||||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
|
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
|
||||||
@@ -1446,11 +1739,6 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
fsevents@~2.3.2, fsevents@~2.3.3:
|
|
||||||
version "2.3.3"
|
|
||||||
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
|
|
||||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
|
||||||
|
|
||||||
function-bind@^1.1.2:
|
function-bind@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||||
@@ -1634,6 +1922,18 @@ hasown@^2.0.0, hasown@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind "^1.1.2"
|
function-bind "^1.1.2"
|
||||||
|
|
||||||
|
hoist-non-react-statics@^3.3.2:
|
||||||
|
version "3.3.2"
|
||||||
|
resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz"
|
||||||
|
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||||
|
dependencies:
|
||||||
|
react-is "^16.7.0"
|
||||||
|
|
||||||
|
ieee754@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
|
||||||
|
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
|
|
||||||
ignore@^5.2.0, ignore@^5.2.4:
|
ignore@^5.2.0, ignore@^5.2.4:
|
||||||
version "5.3.1"
|
version "5.3.1"
|
||||||
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
|
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
|
||||||
@@ -1878,6 +2178,11 @@ json5@^2.2.3:
|
|||||||
resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
|
resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
|
||||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||||
|
|
||||||
|
jssha@3.2.0:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz"
|
||||||
|
integrity sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q==
|
||||||
|
|
||||||
keyv@^4.5.3:
|
keyv@^4.5.3:
|
||||||
version "4.5.4"
|
version "4.5.4"
|
||||||
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
|
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
|
||||||
@@ -1920,6 +2225,11 @@ locate-path@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^5.0.0"
|
p-locate "^5.0.0"
|
||||||
|
|
||||||
|
lodash-es@^4.17.21:
|
||||||
|
version "4.17.21"
|
||||||
|
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
|
||||||
|
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||||
|
|
||||||
lodash.merge@^4.6.2:
|
lodash.merge@^4.6.2:
|
||||||
version "4.6.2"
|
version "4.6.2"
|
||||||
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
|
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
|
||||||
@@ -2032,6 +2342,11 @@ minimist@^1.2.0, minimist@^1.2.6:
|
|||||||
resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz"
|
resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz"
|
||||||
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
|
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
|
||||||
|
|
||||||
|
mitt@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz"
|
||||||
|
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
|
||||||
|
|
||||||
ms@^2.1.1, ms@2.1.2:
|
ms@^2.1.1, ms@2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||||
@@ -2063,6 +2378,13 @@ natural-compare@^1.4.0:
|
|||||||
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
|
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
|
||||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||||
|
|
||||||
|
node-fetch@^2.6.9:
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"
|
||||||
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-releases@^2.0.14:
|
node-releases@^2.0.14:
|
||||||
version "2.0.14"
|
version "2.0.14"
|
||||||
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz"
|
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz"
|
||||||
@@ -2339,7 +2661,25 @@ queue-microtask@^1.2.2:
|
|||||||
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
|
|
||||||
react-dom@^18, react-dom@^18.2.0, react-dom@>=16.8:
|
react-dnd-html5-backend@^14.0.0:
|
||||||
|
version "14.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz"
|
||||||
|
integrity sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw==
|
||||||
|
dependencies:
|
||||||
|
dnd-core "14.0.1"
|
||||||
|
|
||||||
|
react-dnd@^14.0.2:
|
||||||
|
version "14.0.5"
|
||||||
|
resolved "https://registry.npmjs.org/react-dnd/-/react-dnd-14.0.5.tgz"
|
||||||
|
integrity sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A==
|
||||||
|
dependencies:
|
||||||
|
"@react-dnd/invariant" "^2.0.0"
|
||||||
|
"@react-dnd/shallowequal" "^2.0.0"
|
||||||
|
dnd-core "14.0.1"
|
||||||
|
fast-deep-equal "^3.1.3"
|
||||||
|
hoist-non-react-statics "^3.3.2"
|
||||||
|
|
||||||
|
react-dom@^18, react-dom@^18.2.0, react-dom@>=16.8, react-dom@>=17.0.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
|
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
|
||||||
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
|
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
|
||||||
@@ -2357,7 +2697,7 @@ react-hook-form@^7.0.0, react-hook-form@^7.51.0:
|
|||||||
resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.0.tgz"
|
resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.0.tgz"
|
||||||
integrity sha512-BggOy5j58RdhdMzzRUHGOYhSz1oeylFAv6jUSG86OvCIvlAvS7KvnRY7yoAf2pfEiPN7BesnR0xx73nEk3qIiw==
|
integrity sha512-BggOy5j58RdhdMzzRUHGOYhSz1oeylFAv6jUSG86OvCIvlAvS7KvnRY7yoAf2pfEiPN7BesnR0xx73nEk3qIiw==
|
||||||
|
|
||||||
react-is@^16.13.1:
|
react-is@^16.13.1, react-is@^16.7.0:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
@@ -2402,7 +2742,16 @@ react-router@6.22.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@remix-run/router" "1.15.2"
|
"@remix-run/router" "1.15.2"
|
||||||
|
|
||||||
"react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17.0.0 || ^18.0.0", react@^18, react@^18.2.0, react@>=16.6.0, react@>=16.8:
|
react-tag-input@^6.10.3:
|
||||||
|
version "6.10.3"
|
||||||
|
resolved "https://registry.npmjs.org/react-tag-input/-/react-tag-input-6.10.3.tgz"
|
||||||
|
integrity sha512-IVneBnT0/7N8FktHsFUA2UVDvcwLSJoWDTdEm/Ei/r5O6iBABaVw1RMh6SlG+P7oummvzSY6EBjGCXr/Ntq8rQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash-es" "^4.17.12"
|
||||||
|
classnames "~2.3.1"
|
||||||
|
lodash-es "^4.17.21"
|
||||||
|
|
||||||
|
"react@^16.14.0 || 17.x || 18.x || 19.x", "react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17.0.0 || ^18.0.0", react@^18, react@^18.2.0, "react@>= 16.14", react@>=16.6.0, react@>=16.8, react@>=17.0.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
|
||||||
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||||
@@ -2423,6 +2772,13 @@ readdirp@~3.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.2.1"
|
picomatch "^2.2.1"
|
||||||
|
|
||||||
|
redux@^4.1.1:
|
||||||
|
version "4.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
|
||||||
|
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.9.2"
|
||||||
|
|
||||||
regenerator-runtime@^0.14.0:
|
regenerator-runtime@^0.14.0:
|
||||||
version "0.14.1"
|
version "0.14.1"
|
||||||
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
|
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
|
||||||
@@ -2712,6 +3068,11 @@ supports-preserve-symlinks-flag@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
|
||||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||||
|
|
||||||
|
symbol.inspect@1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/symbol.inspect/-/symbol.inspect-1.0.1.tgz"
|
||||||
|
integrity sha512-YQSL4duoHmLhsTD1Pw8RW6TZ5MaTX5rXJnqacJottr2P2LZBF/Yvrc3ku4NUpMOm8aM0KOCqM+UAkMA5HWQCzQ==
|
||||||
|
|
||||||
synckit@^0.8.6:
|
synckit@^0.8.6:
|
||||||
version "0.8.8"
|
version "0.8.8"
|
||||||
resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz"
|
resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz"
|
||||||
@@ -2786,6 +3147,11 @@ to-regex-range@^5.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-number "^7.0.0"
|
is-number "^7.0.0"
|
||||||
|
|
||||||
|
tr46@~0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
|
||||||
|
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||||
|
|
||||||
ts-api-utils@^1.0.1:
|
ts-api-utils@^1.0.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz"
|
resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz"
|
||||||
@@ -2816,6 +3182,16 @@ tslib@^2.6.2:
|
|||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
|
||||||
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||||
|
|
||||||
|
tweetnacl-util@^0.15.1:
|
||||||
|
version "0.15.1"
|
||||||
|
resolved "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz"
|
||||||
|
integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==
|
||||||
|
|
||||||
|
tweetnacl@^1.0.3, tweetnacl@1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz"
|
||||||
|
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
|
||||||
|
|
||||||
type-check@^0.4.0, type-check@~0.4.0:
|
type-check@^0.4.0, type-check@~0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
|
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
|
||||||
@@ -2872,11 +3248,16 @@ typed-array-length@^1.0.5:
|
|||||||
is-typed-array "^1.1.13"
|
is-typed-array "^1.1.13"
|
||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
|
|
||||||
typescript@^5.0.0, typescript@^5.2.2, typescript@>=4.2.0:
|
typescript@^5.0.0, typescript@^5.2.2, typescript@>=4.2.0, typescript@>=5:
|
||||||
version "5.3.3"
|
version "5.3.3"
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz"
|
||||||
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
||||||
|
|
||||||
|
ua-parser-js@^1.0.35:
|
||||||
|
version "1.0.40"
|
||||||
|
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz"
|
||||||
|
integrity sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==
|
||||||
|
|
||||||
unbox-primitive@^1.0.2:
|
unbox-primitive@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz"
|
||||||
@@ -2925,6 +3306,11 @@ util-deprecate@^1.0.2:
|
|||||||
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||||
|
|
||||||
|
valibot@1.0.0-beta.14:
|
||||||
|
version "1.0.0-beta.14"
|
||||||
|
resolved "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.14.tgz"
|
||||||
|
integrity sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==
|
||||||
|
|
||||||
vite-tsconfig-paths@^4.3.1:
|
vite-tsconfig-paths@^4.3.1:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.1.tgz"
|
resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.1.tgz"
|
||||||
@@ -2945,6 +3331,19 @@ vite@*, "vite@^4.2.0 || ^5.0.0", vite@^5.1.4:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.3"
|
fsevents "~2.3.3"
|
||||||
|
|
||||||
|
webidl-conversions@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
|
||||||
|
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
|
||||||
|
|
||||||
|
whatwg-url@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"
|
||||||
|
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
|
||||||
|
dependencies:
|
||||||
|
tr46 "~0.0.3"
|
||||||
|
webidl-conversions "^3.0.0"
|
||||||
|
|
||||||
which-boxed-primitive@^1.0.2:
|
which-boxed-primitive@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
|
||||||
|
|||||||
Reference in new issue
Block a user