diff --git a/.env b/.env
new file mode 100644
index 0000000..c1948b4
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+VITE_API_BASE_URL=https://my-public-node-1.projscale.dev/api/v1
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 2324b9b..689d7c9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 6dd29bb..f4b588b 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/app/index.tsx b/src/app/index.tsx
index 4833d7a..6c66e95 100644
--- a/src/app/index.tsx
+++ b/src/app/index.tsx
@@ -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";
diff --git a/src/app/styles/globals.css b/src/app/styles/globals.css
index bbf4d90..ea8f082 100644
--- a/src/app/styles/globals.css
+++ b/src/app/styles/globals.css
@@ -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 */
- );
- border-radius: 9999px; /* Rounded-full track */
- outline: none; /* Remove outline */
+ -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;
}
@@ -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 */
- );
- border-radius: 9999px; /* Rounded-full track */
- outline: none; /* Remove outline */
+ -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-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,11 +132,11 @@
}
.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
'cursor-pointer' so it looks clickable
*/
}
-}
+}
\ No newline at end of file
diff --git a/src/pages/root/steps/data-step/components/cover-button/index.tsx b/src/pages/root/steps/data-step/components/cover-button/index.tsx
index 2b3d339..e0b9aa1 100644
--- a/src/pages/root/steps/data-step/components/cover-button/index.tsx
+++ b/src/pages/root/steps/data-step/components/cover-button/index.tsx
@@ -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) => {
}
>
- Удалить
-
+ Изменить
+
);
diff --git a/src/pages/root/steps/data-step/index.tsx b/src/pages/root/steps/data-step/index.tsx
index 2878be1..c467205 100644
--- a/src/pages/root/steps/data-step/index.tsx
+++ b/src/pages/root/steps/data-step/index.tsx
@@ -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,119 +59,140 @@ export const DataStep = ({ nextStep }: DataStepProps) => {
})();
};
+ const handleFileReset = () => {
+ rootStore.setFile(null);
+ rootStore.setFileSrc('');
+ rootStore.setFileType('');
+ }
+
return (
-
-
-
/Заполните информацию о контенте
-
- 1/5
-
+
+
+
/Заполните информацию о контенте
+
+ 1/5
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
+ {!rootStore.fileSrc && <>
{
- rootStore.setFile(file);
- rootStore.setFileSrc(URL.createObjectURL(file));
- rootStore.setFileType(file.type); // Save the file type for conditional rendering
- }}
+ id={"file"}
+ shouldProcess={false}
+ accept={"video/mp4,video/x-m4v,video/*,audio/mp3,audio/*"}
+ onChange={(file) => {
+ rootStore.setFile(file);
+ rootStore.setFileSrc(URL.createObjectURL(file));
+ rootStore.setFileType(file.type); // Save the file type for conditional rendering
+ }}
/>
- {!rootStore.fileSrc && }
+
+ >}
- {rootStore.fileSrc && (
-
- {rootStore.fileType?.startsWith("audio") ? (
-
- ) : (
-
- )}
-
- )}
-
-
-
-
rootStore.setAllowCover(!rootStore.allowCover)}
- checked={rootStore.allowCover}
- />
+ {rootStore.fileSrc && (
+
+ {rootStore.fileType?.startsWith("audio") ? (
+
+ ) : (
+
+ )}
+
+ >
+
+
Изменить выбор
+
+
+
+ )}
+
- {rootStore.allowCover && (
-
- {
- rootStore.setCover(cover);
- }}
- />
-
- {rootStore.cover ? (
- {
- rootStore.setCover(null);
- }}
- />
- ) : (
-
- )}
-
- )}
-
-
-
-
+
+
+
+
);
};
diff --git a/src/pages/root/steps/presubmit-step/index.tsx b/src/pages/root/steps/presubmit-step/index.tsx
index db44819..c9d986c 100644
--- a/src/pages/root/steps/presubmit-step/index.tsx
+++ b/src/pages/root/steps/presubmit-step/index.tsx
@@ -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) => {
)}
+ {rootStore.author && (
+
+
+ {rootStore.hashtags.map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+
+ )}
+
{
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,13 +98,22 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => {
Минимальная стоимость {MIN_PRICE} TON.
-
Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.
+ {/*
Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.
*/}
+ 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, '');
+ }
+ }
+ })}
+ />