auth flow fix, validation for auth in steps /uploadContnt
This commit is contained in:
parent
7705908484
commit
3e9564d7b9
|
|
@ -23,8 +23,13 @@ export const WelcomeStep = ({ nextStep }: WelcomeStepProps) => {
|
||||||
await auth.mutateAsync();
|
await auth.mutateAsync();
|
||||||
nextStep();
|
nextStep();
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
await tonConnectUI.openModal();
|
await tonConnectUI.openModal();
|
||||||
await auth.mutateAsync();
|
await auth.mutateAsync();
|
||||||
|
nextStep();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to connect or authenticate:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import ReactPlayer from "react-player/lazy";
|
||||||
import { useTonConnectUI } from "@tonconnect/ui-react";
|
import { useTonConnectUI } from "@tonconnect/ui-react";
|
||||||
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
|
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||||
|
|
||||||
|
import { Button } from "~/shared/ui/button";
|
||||||
import { usePurchaseContent, useViewContent } from "~/shared/services/content";
|
import { usePurchaseContent, useViewContent } from "~/shared/services/content";
|
||||||
import { fromNanoTON } from "~/shared/utils";
|
import { fromNanoTON } from "~/shared/utils";
|
||||||
import {useCallback, useEffect, useMemo} from "react";
|
import {useCallback, useEffect, useMemo} from "react";
|
||||||
|
|
@ -71,45 +72,9 @@ 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 (
|
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 && (
|
{content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && (
|
||||||
<div className={"mt-[30px] h-[314px] w-full"}>
|
<div className={"mt-[30px] h-[314px] w-full"}>
|
||||||
<img
|
<img
|
||||||
|
|
@ -146,9 +111,10 @@ export const ViewContentPage = () => {
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* {!haveLicense && <Button
|
<div className="mt-auto pb-2">
|
||||||
|
{!haveLicense && <Button
|
||||||
onClick={handleBuyContent}
|
onClick={handleBuyContent}
|
||||||
className={"mb-4 mt-[30px] h-[48px]"}
|
className={"mb-4 h-[48px]"}
|
||||||
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
|
label={`Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`}
|
||||||
includeArrows={true}
|
includeArrows={true}
|
||||||
/>
|
/>
|
||||||
|
|
@ -158,9 +124,10 @@ export const ViewContentPage = () => {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
WebApp.openTelegramLink(`https://t.me/MY_UploaderRobot`);
|
WebApp.openTelegramLink(`https://t.me/MY_UploaderRobot`);
|
||||||
}}
|
}}
|
||||||
className={"mb-4 mt-[-20px] h-[48px] bg-darkred"}
|
className={"h-[48px] bg-darkred"}
|
||||||
label={`Загрузить свой контент`}
|
label={`Загрузить свой контент`}
|
||||||
/> */}
|
/>
|
||||||
|
</div>
|
||||||
</main>
|
</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];
|
||||||
|
|
|
||||||
|
|
@ -13,80 +13,103 @@ export const useAuth = () => {
|
||||||
const [tonConnectUI] = useTonConnectUI();
|
const [tonConnectUI] = useTonConnectUI();
|
||||||
const interval = useRef<ReturnType<typeof setInterval> | undefined>();
|
const interval = useRef<ReturnType<typeof setInterval> | undefined>();
|
||||||
|
|
||||||
return useMutation(["auth"], async () => {
|
const waitForWalletProof = async () => {
|
||||||
clearInterval(interval.current);
|
return new Promise((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => reject(new Error("Timeout waiting for proof")), 30000);
|
||||||
if (!wallet) {
|
const checkProof = setInterval(() => {
|
||||||
localStorage.removeItem(sessionStorageKey);
|
const currentWallet = tonConnectUI.wallet;
|
||||||
|
if (
|
||||||
const refreshPayload = async () => {
|
currentWallet?.connectItems?.tonProof &&
|
||||||
tonConnectUI.setConnectRequestParameters({ state: "loading" });
|
!("error" in currentWallet.connectItems.tonProof)
|
||||||
|
) {
|
||||||
const value = await request
|
clearInterval(checkProof);
|
||||||
.post<{
|
clearTimeout(timeout);
|
||||||
auth_v1_token: string;
|
resolve(currentWallet.connectItems.tonProof.proof);
|
||||||
}>("/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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
void refreshPayload();
|
const makeAuthRequest = async (params: {
|
||||||
setInterval(refreshPayload, payloadTTLMS);
|
twa_data: string;
|
||||||
|
ton_proof?: {
|
||||||
return;
|
account: any;
|
||||||
}
|
ton_proof: any;
|
||||||
|
};
|
||||||
if (
|
}) => {
|
||||||
wallet.connectItems?.tonProof &&
|
const res = await request.post<{
|
||||||
!("error" in wallet.connectItems.tonProof)
|
|
||||||
) {
|
|
||||||
const tonProof = wallet.connectItems.tonProof.proof;
|
|
||||||
|
|
||||||
console.log("DEBUG TON-PROOF", tonProof);
|
|
||||||
|
|
||||||
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);
|
||||||
|
} 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,
|
twa_data: WebApp.initData,
|
||||||
ton_proof: {
|
ton_proof: {
|
||||||
account: wallet.account,
|
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,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -77,7 +77,7 @@ 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.15,
|
price: 0.15,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue