Compare commits
6 Commits
372f84d1b1
...
dd62962de8
| Author | SHA1 | Date |
|---|---|---|
|
|
dd62962de8 | |
|
|
3e9564d7b9 | |
|
|
7f7dde7b28 | |
|
|
fc6fb5003e | |
|
|
1d22ac2173 | |
|
|
7705908484 |
|
|
@ -0,0 +1 @@
|
|||
VITE_API_BASE_URL=https://my-public-node-1.projscale.dev/api/v1
|
||||
|
|
@ -2,3 +2,4 @@
|
|||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
.env
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
"@tonconnect/ui-react": "^2.0.2",
|
||||
"@vkruglikov/react-telegram-web-app": "^2.1.9",
|
||||
"axios": "^1.6.7",
|
||||
"buffer": "^6.0.3",
|
||||
"clsx": "^2.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
@ -2054,6 +2055,26 @@
|
|||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"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/big-integer": {
|
||||
"version": "1.6.52",
|
||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
||||
|
|
@ -2139,6 +2160,30 @@
|
|||
"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": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
|
|
@ -3621,6 +3666,26 @@
|
|||
"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": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"@tonconnect/ui-react": "^2.0.2",
|
||||
"@vkruglikov/react-telegram-web-app": "^2.1.9",
|
||||
"axios": "^1.6.7",
|
||||
"buffer": "^6.0.3",
|
||||
"clsx": "^2.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import "~/app/styles/globals.css";
|
||||
import '~/shared/libs/buffer';
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useExpand, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||
|
|
|
|||
|
|
@ -26,18 +26,26 @@
|
|||
/*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 */
|
||||
-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 */
|
||||
border-radius: 9999px;
|
||||
/* Rounded-full track */
|
||||
outline: none;
|
||||
/* Remove outline */
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
|
|
@ -45,45 +53,64 @@
|
|||
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 */
|
||||
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 */
|
||||
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 */
|
||||
-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 */
|
||||
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-transparent text-gray placeholder:text-gray outline-none w-full h-8;
|
||||
@apply border border-white py-[20px] !important;
|
||||
@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
|
||||
|
|
@ -94,7 +121,7 @@
|
|||
|
||||
/* 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 rounded mr-1;
|
||||
@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
|
||||
|
|
@ -105,7 +132,7 @@
|
|||
}
|
||||
|
||||
.ReactTags__selected .ReactTags__remove {
|
||||
@apply ml-1 text-gray hover:text-white cursor-pointer;
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useHapticFeedback } from "@vkruglikov/react-telegram-web-app";
|
||||
import { Replace } from "~/shared/ui/icons/replace";
|
||||
|
||||
import { XMark } from "~/shared/ui/icons/x-mark.tsx";
|
||||
|
||||
|
|
@ -36,8 +37,8 @@ export const CoverButton = ({ src, onClick }: CoverButtonProps) => {
|
|||
}
|
||||
>
|
||||
<div />
|
||||
<div className={"flex gap-2 text-sm"}>Удалить</div>
|
||||
<XMark />
|
||||
<div className={"flex gap-2 text-sm"}>Изменить</div>
|
||||
<Replace />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import { useRootStore } from "~/shared/stores/root";
|
|||
import { Checkbox } from "~/shared/ui/checkbox";
|
||||
import { AudioPlayer } from "~/shared/ui/audio-player";
|
||||
import { HashtagInput } from "~/shared/ui/hashtag-input";
|
||||
import { XMark } from "~/shared/ui/icons/x-mark";
|
||||
import { Replace } from "~/shared/ui/icons/replace";
|
||||
|
||||
type DataStepProps = {
|
||||
nextStep(): void;
|
||||
|
|
@ -57,6 +59,12 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
|
|||
})();
|
||||
};
|
||||
|
||||
const handleFileReset = () => {
|
||||
rootStore.setFile(null);
|
||||
rootStore.setFileSrc('');
|
||||
rootStore.setFileType('');
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={"mt-4 px-4 pb-8"}>
|
||||
<div className={"mb-[30px] flex flex-col text-sm"}>
|
||||
|
|
@ -88,6 +96,7 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
|
|||
</FormLabel>
|
||||
|
||||
<FormLabel label={"Файл"}>
|
||||
{!rootStore.fileSrc && <>
|
||||
<HiddenFileInput
|
||||
id={"file"}
|
||||
shouldProcess={false}
|
||||
|
|
@ -99,7 +108,8 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
|
|||
}}
|
||||
/>
|
||||
|
||||
{!rootStore.fileSrc && <FileButton htmlFor={"file"} />}
|
||||
<FileButton htmlFor={"file"} />
|
||||
</>}
|
||||
|
||||
{rootStore.fileSrc && (
|
||||
<div
|
||||
|
|
@ -118,6 +128,16 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
|
|||
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>
|
||||
)}
|
||||
</FormLabel>
|
||||
|
|
@ -136,13 +156,7 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
|
|||
|
||||
{rootStore.allowCover && (
|
||||
<FormLabel label={"Обложка"}>
|
||||
<HiddenFileInput
|
||||
id={"cover"}
|
||||
accept={"image/*"}
|
||||
onChange={(cover) => {
|
||||
rootStore.setCover(cover);
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
{rootStore.cover ? (
|
||||
<CoverButton
|
||||
|
|
@ -152,7 +166,16 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
|
|||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<HiddenFileInput
|
||||
id={"cover"}
|
||||
accept={"image/*"}
|
||||
onChange={(cover) => {
|
||||
rootStore.setCover(cover);
|
||||
}}
|
||||
/>
|
||||
<FileButton htmlFor={"cover"} />
|
||||
</>
|
||||
)}
|
||||
</FormLabel>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||
content: fileUploadResult.content_id_v1,
|
||||
image: coverUploadResult.content_id_v1,
|
||||
price: String(rootStore.price * 10 ** 9),
|
||||
|
||||
hashtags: rootStore.hashtags,
|
||||
royaltyParams: rootStore.royalty.map((member) => ({
|
||||
...member,
|
||||
value: member.value * 100,
|
||||
|
|
@ -151,6 +151,24 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => {
|
|||
</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={"Цена"}>
|
||||
<div
|
||||
className={
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import { Button } from "~/shared/ui/button";
|
|||
import { useRootStore } from "~/shared/stores/root";
|
||||
import { BackButton } from "~/shared/ui/back-button";
|
||||
|
||||
const MIN_PRICE = 0.07;
|
||||
const MIN_RESALE_PRICE = 0.07;
|
||||
const MIN_PRICE = 0.15;
|
||||
const MIN_RESALE_PRICE = 0.15;
|
||||
|
||||
const RECOMMENDED_PRICE = 0.15;
|
||||
// const RECOMMENDED_PRICE = 0.15;
|
||||
// const RECOMMENDED_RESALE_PRICE = 0.15;
|
||||
|
||||
type PriceStepProps = {
|
||||
|
|
@ -25,9 +25,9 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||
|
||||
const formSchema = useMemo(() => {
|
||||
const parsePrice = (value: unknown) => {
|
||||
if (typeof value === "string") {
|
||||
// Replace commas with dots and parse the value
|
||||
const parsedValue = parseFloat(value.replace(",", "."));
|
||||
if (typeof value === "string" || typeof value === "number") {
|
||||
const stringValue = value.toString().replace(",", ".");
|
||||
const parsedValue = parseFloat(stringValue);
|
||||
return isNaN(parsedValue) ? undefined : parsedValue;
|
||||
}
|
||||
return undefined;
|
||||
|
|
@ -37,10 +37,10 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||
return z.object({
|
||||
price: z.preprocess(
|
||||
parsePrice,
|
||||
z.number().min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`)
|
||||
z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`)
|
||||
),
|
||||
resaleLicensePrice: z
|
||||
.preprocess(parsePrice, z.number().min(MIN_RESALE_PRICE, `Цена копии должна быть минимум ${MIN_RESALE_PRICE} TON.`))
|
||||
.preprocess(parsePrice, z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_RESALE_PRICE, `Цена копии должна быть минимум ${MIN_RESALE_PRICE} TON.`))
|
||||
.optional(),
|
||||
});
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||
return z.object({
|
||||
price: z.preprocess(
|
||||
parsePrice,
|
||||
z.number().min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`)
|
||||
z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`)
|
||||
),
|
||||
});
|
||||
}, [rootStore.allowResale]);
|
||||
|
|
@ -59,9 +59,9 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||
resolver: zodResolver(formSchema),
|
||||
mode: "onChange",
|
||||
defaultValues: {
|
||||
price: rootStore.price,
|
||||
price: rootStore.price || MIN_PRICE,
|
||||
//@ts-expect-error Fix typings
|
||||
resaleLicensePrice: rootStore?.licenseResalePrice,
|
||||
resaleLicensePrice: rootStore?.licenseResalePrice || MIN_RESALE_PRICE,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -98,12 +98,21 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
|
|||
<FormLabel label={"Цена продажи TON"}>
|
||||
<div className={"my-2 flex flex-col gap-1.5"}>
|
||||
<p className={"text-xs"}>Минимальная стоимость {MIN_PRICE} TON.</p>
|
||||
<p className={"text-xs"}>Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.</p>
|
||||
{/* <p className={"text-xs"}>Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.</p> */}
|
||||
</div>
|
||||
<Input
|
||||
error={form.formState.errors?.price}
|
||||
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>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,17 +12,30 @@ import { ConfirmModal } from "~/pages/root/steps/royalty-step/components/confirm
|
|||
import { useRootStore } from "~/shared/stores/root";
|
||||
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 = {
|
||||
prevStep(): 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) => {
|
||||
const [impactOccurred] = useHapticFeedback();
|
||||
|
||||
const [isDeleteAllOpen, setDeleteAllOpen] = useState(false);
|
||||
const [isSpreadOpen, setSpreadOpen] = useState(false);
|
||||
const [addressErrors, setAddressErrors] = useState<Record<number, FieldError | undefined>>({});
|
||||
|
||||
const { royalty, setRoyalty, isPercentHintOpen, setPercentHintOpen } =
|
||||
useRootStore();
|
||||
|
|
@ -42,12 +55,24 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||
};
|
||||
|
||||
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) =>
|
||||
i === index ? { ...member, address } : member,
|
||||
i === index ? { ...member, address } : member
|
||||
);
|
||||
setRoyalty(newRoyalty);
|
||||
};
|
||||
|
||||
|
||||
const handlePercentChange = (index: number, value: string) => {
|
||||
const percentNumber = parseInt(value, 10) || 0;
|
||||
const newRoyalty = royalty.map((royalty, i) =>
|
||||
|
|
@ -67,20 +92,28 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||
|
||||
const isValid = useMemo(() => {
|
||||
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]);
|
||||
|
||||
const [tonConnectUI] = useTonConnectUI();
|
||||
|
||||
// Устанавливаем адрес из tonConnectUI.account при загрузке страницы
|
||||
useEffect(() => {
|
||||
console.log('tonconnectUI', tonConnectUI)
|
||||
if (tonConnectUI.account) {
|
||||
setRoyalty([{ address: tonConnectUI.account.address, value: 100 }]);
|
||||
if (!tonConnectUI.account) return;
|
||||
|
||||
if (royalty.length === 0) {
|
||||
// First initialization with 100%
|
||||
setRoyalty([{
|
||||
address: Address.parse(tonConnectUI.account.address).toString({
|
||||
bounceable: true,
|
||||
urlSafe: true,
|
||||
testOnly: false,
|
||||
}),
|
||||
value: 100
|
||||
}]);
|
||||
}
|
||||
}, [tonConnectUI.account, setRoyalty]);
|
||||
}, [tonConnectUI.account, setRoyalty, royalty]);
|
||||
|
||||
return (
|
||||
<section className={"mt-4 px-4 pb-8"}>
|
||||
|
|
@ -128,7 +161,7 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||
<section className={"flex flex-col gap-1.5"}>
|
||||
{royalty.map((member, index) => (
|
||||
<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%]"}>
|
||||
<FormLabel
|
||||
labelClassName={"flex"}
|
||||
|
|
@ -145,6 +178,7 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => {
|
|||
value={member.address}
|
||||
onChange={(e) => handleWalletChange(index, e.target.value)}
|
||||
placeholder={"[ Введите адрес криптокошелька TON ]"}
|
||||
error={addressErrors[index]}
|
||||
/>
|
||||
</FormLabel>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,8 +23,13 @@ export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
|
|||
await auth.mutateAsync();
|
||||
nextStep();
|
||||
} else {
|
||||
try {
|
||||
await tonConnectUI.openModal();
|
||||
await auth.mutateAsync();
|
||||
nextStep();
|
||||
} catch (error) {
|
||||
console.error('Failed to connect or authenticate:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export const ViewContentPage = () => {
|
|||
|
||||
|
||||
return (
|
||||
<main className={"flex w-full flex-col gap-[50px] px-4"}>
|
||||
<main className={"min-h-screen flex w-full flex-col gap-[50px] px-4 "}>
|
||||
{content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && (
|
||||
<div className={"mt-[30px] h-[314px] w-full"}>
|
||||
<img
|
||||
|
|
@ -111,9 +111,10 @@ export const ViewContentPage = () => {
|
|||
</p>
|
||||
</section>
|
||||
|
||||
<div className="mt-auto pb-2">
|
||||
{!haveLicense && <Button
|
||||
onClick={handleBuyContent}
|
||||
className={"mb-4 mt-[30px] h-[48px]"}
|
||||
className={"mb-4 h-[48px]"}
|
||||
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
|
||||
includeArrows={true}
|
||||
/>
|
||||
|
|
@ -123,9 +124,10 @@ export const ViewContentPage = () => {
|
|||
onClick={() => {
|
||||
WebApp.openTelegramLink(`https://t.me/MY_UploaderRobot`);
|
||||
}}
|
||||
className={"mb-4 mt-[-20px] h-[48px] bg-darkred"}
|
||||
className={"h-[48px] bg-darkred"}
|
||||
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 = (
|
||||
sections: ({
|
||||
|
|
@ -9,15 +13,24 @@ export const useSteps = (
|
|||
prevStep(): void;
|
||||
}) => ReactNode[],
|
||||
) => {
|
||||
|
||||
const [tonConnectUI] = useTonConnectUI();
|
||||
|
||||
const [step, setStep] = useState(0);
|
||||
|
||||
const nextStep = () => {
|
||||
return setStep((s) => s + 1);
|
||||
};
|
||||
// If connection is lost, reset the step
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
if (!tonConnectUI.connected && step !== 0) {
|
||||
setStep(0);
|
||||
}
|
||||
}, CHECK_INTERVAL);
|
||||
|
||||
const prevStep = () => {
|
||||
return setStep((s) => s - 1);
|
||||
};
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const nextStep = () => setStep((s) => s + 1);
|
||||
const prevStep = () => setStep((s) => s - 1);
|
||||
|
||||
const ActiveSection = useMemo(() => {
|
||||
return sections({ nextStep, prevStep })[step];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
import { Buffer } from 'buffer';
|
||||
globalThis.Buffer = Buffer;
|
||||
|
|
@ -13,80 +13,103 @@ export const useAuth = () => {
|
|||
const [tonConnectUI] = useTonConnectUI();
|
||||
const interval = useRef<ReturnType<typeof setInterval> | undefined>();
|
||||
|
||||
return useMutation(["auth"], async () => {
|
||||
clearInterval(interval.current);
|
||||
|
||||
if (!wallet) {
|
||||
localStorage.removeItem(sessionStorageKey);
|
||||
|
||||
const refreshPayload = async () => {
|
||||
tonConnectUI.setConnectRequestParameters({ state: "loading" });
|
||||
|
||||
const value = await request
|
||||
.post<{
|
||||
auth_v1_token: string;
|
||||
}>("/auth.twa", {
|
||||
twa_data: WebApp.initData,
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error("Error in authentication request: ", error);
|
||||
throw new Error("Failed to authenticate.");
|
||||
});
|
||||
if (!value) {
|
||||
tonConnectUI.setConnectRequestParameters(null);
|
||||
} else {
|
||||
tonConnectUI.setConnectRequestParameters({
|
||||
state: "ready",
|
||||
value: {
|
||||
tonProof: value?.data?.auth_v1_token,
|
||||
},
|
||||
});
|
||||
const waitForWalletProof = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => reject(new Error("Timeout waiting for proof")), 30000);
|
||||
const checkProof = setInterval(() => {
|
||||
const currentWallet = tonConnectUI.wallet;
|
||||
if (
|
||||
currentWallet?.connectItems?.tonProof &&
|
||||
!("error" in currentWallet.connectItems.tonProof)
|
||||
) {
|
||||
clearInterval(checkProof);
|
||||
clearTimeout(timeout);
|
||||
resolve(currentWallet.connectItems.tonProof.proof);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
|
||||
void refreshPayload();
|
||||
setInterval(refreshPayload, payloadTTLMS);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
wallet.connectItems?.tonProof &&
|
||||
!("error" in wallet.connectItems.tonProof)
|
||||
) {
|
||||
const tonProof = wallet.connectItems.tonProof.proof;
|
||||
|
||||
console.log("DEBUG TON-PROOF", tonProof);
|
||||
|
||||
request
|
||||
.post<{
|
||||
const makeAuthRequest = async (params: {
|
||||
twa_data: string;
|
||||
ton_proof?: {
|
||||
account: any;
|
||||
ton_proof: any;
|
||||
};
|
||||
}) => {
|
||||
const res = await request.post<{
|
||||
connected_wallet: null | {
|
||||
version: string;
|
||||
address: string;
|
||||
ton_balance: string;
|
||||
};
|
||||
auth_v1_token: string;
|
||||
}>("/auth.twa", {
|
||||
}>("/auth.twa", params);
|
||||
|
||||
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"], async () => {
|
||||
clearInterval(interval.current);
|
||||
console.log("DEBUG: Starting auth flow");
|
||||
|
||||
// Case 1: Not connected - need to connect and get proof
|
||||
if (!tonConnectUI.connected) {
|
||||
console.log("DEBUG: No wallet connection, starting flow");
|
||||
localStorage.removeItem(sessionStorageKey);
|
||||
|
||||
const refreshPayload = async () => {
|
||||
tonConnectUI.setConnectRequestParameters({ state: "loading" });
|
||||
const value = await request.post<{ auth_v1_token: string }>("/auth.twa", {
|
||||
twa_data: WebApp.initData,
|
||||
});
|
||||
|
||||
if (value?.data?.auth_v1_token) {
|
||||
tonConnectUI.setConnectRequestParameters({
|
||||
state: "ready",
|
||||
value: { tonProof: value.data.auth_v1_token },
|
||||
});
|
||||
} else {
|
||||
tonConnectUI.setConnectRequestParameters(null);
|
||||
}
|
||||
};
|
||||
|
||||
await refreshPayload();
|
||||
interval.current = setInterval(refreshPayload, payloadTTLMS);
|
||||
|
||||
const tonProof = await waitForWalletProof();
|
||||
console.log("DEBUG: Got initial proof", tonProof);
|
||||
|
||||
return makeAuthRequest({
|
||||
twa_data: WebApp.initData,
|
||||
ton_proof: {
|
||||
account: tonConnectUI.wallet!.account,
|
||||
ton_proof: tonProof,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Case 2: Connected with proof - use it
|
||||
if (wallet?.connectItems?.tonProof && !("error" in wallet.connectItems.tonProof)) {
|
||||
console.log("DEBUG: Using existing proof");
|
||||
return makeAuthRequest({
|
||||
twa_data: WebApp.initData,
|
||||
ton_proof: {
|
||||
account: wallet.account,
|
||||
ton_proof: tonProof,
|
||||
ton_proof: wallet.connectItems.tonProof.proof,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data?.auth_v1_token) {
|
||||
localStorage.setItem(sessionStorageKey, res?.data?.auth_v1_token);
|
||||
} else {
|
||||
alert("Please try another wallet");
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error("Error in authentication request: ", error);
|
||||
throw new Error("Failed to authenticate.");
|
||||
});
|
||||
} else {
|
||||
void tonConnectUI.disconnect();
|
||||
localStorage.removeItem(sessionStorageKey)
|
||||
}
|
||||
|
||||
// Case 3: Connected without proof - already authenticated
|
||||
console.log("DEBUG: Connected without proof, proceeding without it");
|
||||
return makeAuthRequest({
|
||||
twa_data: WebApp.initData,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
@ -8,6 +8,7 @@ type UseCreateNewContentPayload = {
|
|||
content: string;
|
||||
image: string;
|
||||
description: string;
|
||||
hashtags: string[];
|
||||
price: string;
|
||||
resaleLicensePrice: string; // nanoTON bignum (default = 0)
|
||||
allowResale: boolean;
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ export const useUploadFile = () => {
|
|||
}>("/storage", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
Authorization: localStorage.getItem('auth_v1_token') ?? ""
|
||||
Authorization: localStorage.getItem('auth_v1_token') || ""
|
||||
},
|
||||
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const percentCompleted = Math.round(
|
||||
(progressEvent.loaded * 100) / (progressEvent?.total as number) ??
|
||||
(progressEvent.loaded * 100) / (progressEvent?.total as number) ||
|
||||
0,
|
||||
);
|
||||
setUploadProgress(percentCompleted);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ type RootStore = {
|
|||
setAuthor: (author: string) => void;
|
||||
|
||||
file: File | null;
|
||||
setFile: (file: File) => void;
|
||||
setFile: (file: File | null) => void;
|
||||
|
||||
fileType: string;
|
||||
setFileType: (type: string) => void;
|
||||
|
|
@ -77,10 +77,10 @@ export const useRootStore = create<RootStore>((set) => ({
|
|||
authors: [],
|
||||
setAuthors: (authors) => set({ authors }),
|
||||
|
||||
royalty: [{ address: "", value: 100 }],
|
||||
royalty: [],
|
||||
setRoyalty: (royalty) => set({ royalty }),
|
||||
|
||||
price: 0,
|
||||
price: 0.15,
|
||||
setPrice: (price: number) => set({ price }),
|
||||
|
||||
allowResale: false,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useState } from "react";
|
||||
import { WithContext as ReactTags } from "react-tag-input";
|
||||
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();
|
||||
|
|
@ -9,9 +8,7 @@ export const HashtagInput = () => {
|
|||
// English comment: local state as string[] for simplicity
|
||||
const [tags, setTags] = useState<string[]>(hashtags);
|
||||
|
||||
const KeyCodes = { comma: 188, enter: 13 };
|
||||
const delimiters = [KeyCodes.comma, KeyCodes.enter];
|
||||
|
||||
const separators = [SEPARATORS.ENTER, SEPARATORS.COMMA]
|
||||
const handleDelete = (i: number) => {
|
||||
const newTags = tags.filter((_, index) => index !== i);
|
||||
setTags(newTags);
|
||||
|
|
@ -20,20 +17,47 @@ export const HashtagInput = () => {
|
|||
|
||||
// English comment: pass "any" to the function
|
||||
const handleAddition = (newTag: any) => {
|
||||
// English comment: newTag might be { id, text, ... } from react-tag-input
|
||||
const updatedTags = [...tags, newTag?.text || newTag?.id || ""];
|
||||
// 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}
|
||||
delimiters={delimiters as any}
|
||||
separators={separators as any}
|
||||
handleDelete={handleDelete as any}
|
||||
handleAddition={handleAddition as any}
|
||||
allowDragDrop={false}
|
||||
placeholder="[ enter a hashtag ]"
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
|
@ -4,4 +4,19 @@ import TSPaths from "vite-tsconfig-paths";
|
|||
|
||||
export default defineConfig({
|
||||
plugins: [react(), TSPaths()],
|
||||
define: {
|
||||
global: 'globalThis',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
buffer: 'buffer/',
|
||||
}
|
||||
},
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
define: {
|
||||
global: 'globalThis'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
35
yarn.lock
35
yarn.lock
|
|
@ -225,10 +225,10 @@
|
|||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@esbuild/darwin-arm64@0.19.12":
|
||||
"@esbuild/win32-x64@0.19.12":
|
||||
version "0.19.12"
|
||||
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz"
|
||||
integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz"
|
||||
integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||
version "4.4.0"
|
||||
|
|
@ -381,10 +381,10 @@
|
|||
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz"
|
||||
integrity sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.12.0":
|
||||
"@rollup/rollup-win32-x64-msvc@4.12.0":
|
||||
version "4.12.0"
|
||||
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz"
|
||||
integrity sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==
|
||||
resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz"
|
||||
integrity sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==
|
||||
|
||||
"@ton/core@^0.59.1":
|
||||
version "0.59.1"
|
||||
|
|
@ -860,6 +860,11 @@ balanced-match@^1.0.0:
|
|||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||
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==
|
||||
|
||||
big-integer@^1.6.16:
|
||||
version "1.6.52"
|
||||
resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz"
|
||||
|
|
@ -916,6 +921,14 @@ browserslist@^4.22.2, browserslist@^4.23.0, "browserslist@>= 4.21.0":
|
|||
node-releases "^2.0.14"
|
||||
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:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
|
||||
|
|
@ -1569,11 +1582,6 @@ fs.realpath@^1.0.0:
|
|||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
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:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||
|
|
@ -1764,6 +1772,11 @@ hoist-non-react-statics@^3.3.2:
|
|||
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:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
|
||||
|
|
|
|||
Loading…
Reference in New Issue