From 77059084846b6ccc0048bcf03c440ee22fe95cc4 Mon Sep 17 00:00:00 2001 From: Verticool Date: Sat, 1 Feb 2025 19:17:40 +0600 Subject: [PATCH 1/5] tg buttons /viewContent, tags, validation address form and more /uploadContent --- .env | 1 + .gitignore | 1 + package-lock.json | 65 +++++++++++ package.json | 1 + src/app/index.tsx | 1 + src/app/styles/globals.css | 105 +++++++++++------- src/pages/root/steps/presubmit-step/index.tsx | 20 +++- src/pages/root/steps/price-step/index.tsx | 37 +++--- src/pages/root/steps/royalty-step/index.tsx | 52 +++++++-- src/pages/view-content/index.tsx | 43 ++++++- src/shared/libs/buffer/index.ts | 2 + src/shared/services/content/index.ts | 1 + src/shared/stores/root/index.ts | 2 +- src/shared/ui/hashtag-input/index.tsx | 42 +++++-- vite.config.ts | 17 ++- yarn.lock | 35 ++++-- 16 files changed, 336 insertions(+), 89 deletions(-) create mode 100644 .env create mode 100644 src/shared/libs/buffer/index.ts 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/.gitignore b/.gitignore index a71e418..948dfab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules .DS_Store dist +.env \ 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/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, ''); + } + } + })} + />
+ + )} +
- {rootStore.allowCover && ( - - { - rootStore.setCover(cover); - }} - /> - - {rootStore.cover ? ( - { - rootStore.setCover(null); - }} - /> - ) : ( - - )} - - )} - - - - ); diff --git a/src/pages/root/steps/data-step/index.tsx b/src/pages/root/steps/data-step/index.tsx index a601b98..c467205 100644 --- a/src/pages/root/steps/data-step/index.tsx +++ b/src/pages/root/steps/data-step/index.tsx @@ -15,6 +15,7 @@ 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; @@ -95,18 +96,20 @@ export const DataStep = ({ nextStep }: DataStepProps) => { - { - rootStore.setFile(file); - rootStore.setFileSrc(URL.createObjectURL(file)); - rootStore.setFileType(file.type); // Save the file type for conditional rendering - }} - /> + {!rootStore.fileSrc && <> + { + rootStore.setFile(file); + rootStore.setFileSrc(URL.createObjectURL(file)); + rootStore.setFileType(file.type); // Save the file type for conditional rendering + }} + /> - {!rootStore.fileSrc && } + + } {rootStore.fileSrc && (
{
)} @@ -151,13 +156,7 @@ export const DataStep = ({ nextStep }: DataStepProps) => { {rootStore.allowCover && ( - { - rootStore.setCover(cover); - }} - /> + {rootStore.cover ? ( { }} /> ) : ( - + <> + { + rootStore.setCover(cover); + }} + /> + + )} )} diff --git a/src/shared/ui/icons/replace.tsx b/src/shared/ui/icons/replace.tsx new file mode 100644 index 0000000..c256953 --- /dev/null +++ b/src/shared/ui/icons/replace.tsx @@ -0,0 +1,9 @@ +export const Replace = () => { + return ( + + + + + + ); +}; From 3e9564d7b919b2535885da73399b22ddee33f102 Mon Sep 17 00:00:00 2001 From: Verticool Date: Mon, 3 Feb 2025 11:04:15 +0600 Subject: [PATCH 5/5] auth flow fix, validation for auth in steps /uploadContnt --- src/pages/root/steps/welcome-step/index.tsx | 23 ++-- src/pages/view-content/index.tsx | 89 ++++--------- src/shared/hooks/use-steps/index.ts | 33 +++-- src/shared/services/auth/index.ts | 139 ++++++++++++-------- src/shared/stores/root/index.ts | 2 +- 5 files changed, 147 insertions(+), 139 deletions(-) diff --git a/src/pages/root/steps/welcome-step/index.tsx b/src/pages/root/steps/welcome-step/index.tsx index 72172e3..80243d2 100644 --- a/src/pages/root/steps/welcome-step/index.tsx +++ b/src/pages/root/steps/welcome-step/index.tsx @@ -11,22 +11,27 @@ type WelcomeStepProps = { export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => { const [tonConnectUI] = useTonConnectUI(); const [isLoaded, setLoaded] = useState(false); - + console.log("💩💩💩 enter WelcomeStep"); const auth = useAuth(); console.log("💩💩💩 after useAuth"); - - const handleNextClick = async () => { - if (tonConnectUI.connected) { - await auth.mutateAsync(); - nextStep(); - } else { + +const handleNextClick = async () => { + if (tonConnectUI.connected) { + await auth.mutateAsync(); + nextStep(); + } else { + try { await tonConnectUI.openModal(); await auth.mutateAsync(); + nextStep(); + } catch (error) { + console.error('Failed to connect or authenticate:', error); } - }; + } +}; // useEffect(() => { // const first = setTimeout(async () => { @@ -104,4 +109,4 @@ export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => { /> ); -}; +}; \ No newline at end of file diff --git a/src/pages/view-content/index.tsx b/src/pages/view-content/index.tsx index 5a07966..877d5a6 100644 --- a/src/pages/view-content/index.tsx +++ b/src/pages/view-content/index.tsx @@ -2,6 +2,7 @@ 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} from "react"; @@ -71,54 +72,18 @@ export const ViewContentPage = () => { }, []); - useEffect(() => { - const mainButton = WebApp.MainButton; - const secondaryButton = WebApp.SecondaryButton; - - try { - // Set main button color - mainButton.color = '#e40615'; - mainButton.textColor = '#FFFFFF'; - - // Set secondary button color - secondaryButton.color = '#363636'; - secondaryButton.textColor = '#FFFFFF'; - if (!haveLicense) { - mainButton.text = `Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`; - mainButton.show(); - mainButton.onClick(handleBuyContent); - } else { - mainButton.hide(); - } - - secondaryButton.text = 'Загрузить свой контент'; - secondaryButton.show(); - secondaryButton.onClick(() => { - WebApp.openTelegramLink('https://t.me/MY_UploaderRobot'); - }); - - return () => { - mainButton.hide(); - mainButton.offClick(handleBuyContent); - secondaryButton.hide(); - secondaryButton.offClick(); - }; - } catch (error) { - console.error('Error setting up Telegram WebApp buttons:', error); - } - }, [content, haveLicense, WebApp, handleBuyContent]); - + return ( -
- {content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && ( -
- {"content_image"} -
- )} +
+ {content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && ( +
+ {"content_image"} +
+ )} {content?.data?.content_type.startsWith("audio") ? ( @@ -146,21 +111,23 @@ export const ViewContentPage = () => {

- {/* {!haveLicense &&
); }; diff --git a/src/shared/hooks/use-steps/index.ts b/src/shared/hooks/use-steps/index.ts index 7f632e4..311f069 100644 --- a/src/shared/hooks/use-steps/index.ts +++ b/src/shared/hooks/use-steps/index.ts @@ -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); - }; - - const prevStep = () => { - 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); + + return () => clearInterval(interval); + }, []); + + const nextStep = () => setStep((s) => s + 1); + const prevStep = () => setStep((s) => s - 1); const ActiveSection = useMemo(() => { return sections({ nextStep, prevStep })[step]; @@ -28,4 +41,4 @@ export const useSteps = ( setStep, step, }; -}; +}; \ No newline at end of file diff --git a/src/shared/services/auth/index.ts b/src/shared/services/auth/index.ts index 0f6d859..fd0a308 100644 --- a/src/shared/services/auth/index.ts +++ b/src/shared/services/auth/index.ts @@ -13,80 +13,103 @@ export const useAuth = () => { const [tonConnectUI] = useTonConnectUI(); const interval = useRef | undefined>(); + 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); + }); + }; + + 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", 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"); - if (!wallet) { + // 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, - }) - .catch((error: any) => { - console.error("Error in authentication request: ", error); - throw new Error("Failed to authenticate."); - }); - if (!value) { - tonConnectUI.setConnectRequestParameters(null); - } else { + 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, - }, + value: { tonProof: value.data.auth_v1_token }, }); + } else { + tonConnectUI.setConnectRequestParameters(null); } }; - void refreshPayload(); - setInterval(refreshPayload, payloadTTLMS); + await refreshPayload(); + interval.current = setInterval(refreshPayload, payloadTTLMS); - return; + 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, + }, + }); } - if ( - wallet.connectItems?.tonProof && - !("error" in wallet.connectItems.tonProof) - ) { - const tonProof = wallet.connectItems.tonProof.proof; - - console.log("DEBUG TON-PROOF", tonProof); - - request - .post<{ - connected_wallet: null | { - version: string; - address: string; - ton_balance: string; - }; - auth_v1_token: string; - }>("/auth.twa", { - twa_data: WebApp.initData, - ton_proof: { - account: wallet.account, - ton_proof: tonProof, - }, - }) - .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 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: wallet.connectItems.tonProof.proof, + }, + }); } + + // Case 3: Connected without proof - already authenticated + console.log("DEBUG: Connected without proof, proceeding without it"); + return makeAuthRequest({ + twa_data: WebApp.initData, + }); }); }; \ No newline at end of file diff --git a/src/shared/stores/root/index.ts b/src/shared/stores/root/index.ts index 038e113..376d717 100644 --- a/src/shared/stores/root/index.ts +++ b/src/shared/stores/root/index.ts @@ -77,7 +77,7 @@ export const useRootStore = create((set) => ({ authors: [], setAuthors: (authors) => set({ authors }), - royalty: [{ address: "", value: 100 }], + royalty: [], setRoyalty: (royalty) => set({ royalty }), price: 0.15,