auth flow fix, validation for auth in steps /uploadContnt

This commit is contained in:
Verticool 2025-02-03 11:04:15 +06:00
parent 7705908484
commit 3e9564d7b9
5 changed files with 147 additions and 139 deletions

View File

@ -18,15 +18,20 @@ export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
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 () => {

View File

@ -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 (
<main className={"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
alt={"content_image"}
className={"h-full w-full object-cover object-center"}
src={content?.data?.display_options?.metadata?.image}
/>
</div>
)}
<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
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} />
@ -146,21 +111,23 @@ export const ViewContentPage = () => {
</p>
</section>
{/* {!haveLicense && <Button
onClick={handleBuyContent}
className={"mb-4 mt-[30px] h-[48px]"}
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
includeArrows={true}
/>
}
<div className="mt-auto pb-2">
{!haveLicense && <Button
onClick={handleBuyContent}
className={"mb-4 h-[48px]"}
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
includeArrows={true}
/>
}
<Button
onClick={() => {
WebApp.openTelegramLink(`https://t.me/MY_UploaderRobot`);
}}
className={"mb-4 mt-[-20px] h-[48px] bg-darkred"}
label={`Загрузить свой контент`}
/> */}
<Button
onClick={() => {
WebApp.openTelegramLink(`https://t.me/MY_UploaderRobot`);
}}
className={"h-[48px] bg-darkred"}
label={`Загрузить свой контент`}
/>
</div>
</main>
);
};

View File

@ -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];

View File

@ -13,80 +13,103 @@ export const useAuth = () => {
const [tonConnectUI] = useTonConnectUI();
const interval = useRef<ReturnType<typeof setInterval> | 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,
});
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 {
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,
});
});
};

View File

@ -77,7 +77,7 @@ export const useRootStore = create<RootStore>((set) => ({
authors: [],
setAuthors: (authors) => set({ authors }),
royalty: [{ address: "", value: 100 }],
royalty: [],
setRoyalty: (royalty) => set({ royalty }),
price: 0.15,