diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx index 5558060c..1d47aad9 100644 --- a/src/pages/onboarding/Onboarding.tsx +++ b/src/pages/onboarding/Onboarding.tsx @@ -298,6 +298,7 @@ export function OnboardingPage() { setdebridToken={usePreferencesStore((s) => s.setdebridToken)} debridService={usePreferencesStore((s) => s.debridService)} setdebridService={usePreferencesStore((s) => s.setdebridService)} + mode="onboarding" /> diff --git a/src/pages/parts/settings/ConnectionsPart.tsx b/src/pages/parts/settings/ConnectionsPart.tsx index fc3ae9f0..28b229a7 100644 --- a/src/pages/parts/settings/ConnectionsPart.tsx +++ b/src/pages/parts/settings/ConnectionsPart.tsx @@ -25,6 +25,7 @@ import { SetupPart, Status, testFebboxKey, + testTorboxToken, testdebridToken, } from "@/pages/parts/settings/SetupPart"; import { conf } from "@/setup/config"; @@ -55,6 +56,8 @@ interface DebridProps { setdebridToken: (value: string | null) => void; debridService: string; setdebridService: (value: string) => void; + // eslint-disable-next-line react/no-unused-prop-types + mode?: "onboarding" | "settings"; } function ProxyEdit({ @@ -255,14 +258,14 @@ export function FebboxSetup({ const exampleModal = useModal("febbox-example"); // Initialize expansion state for onboarding mode - const [isExpanded, setIsExpanded] = useState( + const [isFebboxExpanded, setIsFebboxExpanded] = useState( mode === "onboarding" && febboxKey !== null && febboxKey !== "", ); // Expand when key is set in onboarding mode useEffect(() => { if (mode === "onboarding" && febboxKey && febboxKey.length > 0) { - setIsExpanded(true); + setIsFebboxExpanded(true); } }, [febboxKey, mode]); @@ -296,14 +299,14 @@ export function FebboxSetup({ }, [febboxKey]); // Toggle handler based on mode - const toggleExpanded = () => { + const toggleFebboxExpanded = () => { if (mode === "onboarding") { // Onboarding mode: expand/collapse, preserve key - if (isExpanded) { + if (isFebboxExpanded) { setFebboxKey(""); - setIsExpanded(false); + setIsFebboxExpanded(false); } else { - setIsExpanded(true); + setIsFebboxExpanded(true); } } else { // Settings mode: enable/disable @@ -312,7 +315,8 @@ export function FebboxSetup({ }; // Determine if content is visible - const isVisible = mode === "onboarding" ? isExpanded : febboxKey !== null; + const isFebboxVisible = + mode === "onboarding" ? isFebboxExpanded : febboxKey !== null; if (conf().ALLOW_FEBBOX_KEY) { return ( @@ -329,14 +333,14 @@ export function FebboxSetup({
- {isVisible ? ( + {isFebboxVisible ? ( <> @@ -463,9 +467,15 @@ export function FebboxSetup({ } } -async function getdebridTokenStatus(debridToken: string | null) { +async function getdebridTokenStatus( + debridToken: string | null, + debridService: string, +) { if (debridToken) { - const status: Status = await testdebridToken(debridToken); + const status: Status = + debridService === "torbox" + ? await testTorboxToken(debridToken) + : await testdebridToken(debridToken); return status; } return "unset"; @@ -476,11 +486,24 @@ export function DebridEdit({ setdebridToken, debridService, setdebridService, + mode = "settings", }: DebridProps) { const { t } = useTranslation(); const user = useAuthStore(); const preferences = usePreferencesStore(); + // Initialize expansion state for onboarding mode + const [isDebridExpanded, setIsDebridExpanded] = useState( + mode === "onboarding" && debridToken !== null && debridToken !== "", + ); + + // Expand when key is set in onboarding mode + useEffect(() => { + if (mode === "onboarding" && debridToken && debridToken.length > 0) { + setIsDebridExpanded(true); + } + }, [debridToken, mode]); + // Enable Real Debrid token when account is loaded and we have a token useEffect(() => { if (user.account && debridToken === null && preferences.debridToken) { @@ -488,6 +511,26 @@ export function DebridEdit({ } }, [user.account, debridToken, preferences.debridToken, setdebridToken]); + // Determine if content is visible + const isDebridVisible = + mode === "onboarding" ? isDebridExpanded : debridToken !== null; + + // Toggle handler based on mode + const toggleDebridExpanded = () => { + if (mode === "onboarding") { + // Onboarding mode: expand/collapse, preserve key + if (isDebridExpanded) { + setdebridToken(""); + setIsDebridExpanded(false); + } else { + setIsDebridExpanded(true); + } + } else { + // Settings mode: enable/disable + setdebridToken(debridToken === null ? "" : null); + } + }; + const [status, setStatus] = useState("unset"); const statusMap: Record = { error: "error", @@ -499,11 +542,11 @@ export function DebridEdit({ useEffect(() => { const checkTokenStatus = async () => { - const result = await getdebridTokenStatus(debridToken); + const result = await getdebridTokenStatus(debridToken, debridService); setStatus(result); }; checkTokenStatus(); - }, [debridToken]); + }, [debridToken, debridService]); if (conf().ALLOW_DEBRID_KEY) { return ( @@ -518,59 +561,66 @@ export function DebridEdit({
- setdebridToken(debridToken === null ? "" : null)} - enabled={debridToken !== null} - /> +
- -

{t("debrid.tokenLabel")}

-
-
- - { - setdebridToken(newToken); - }} - value={debridToken ?? ""} - placeholder="ABC123..." - passwordToggleable - className="flex-grow" - /> -
-
- setdebridService(item.id)} - direction="up" - /> -
-
- {status === "error" && ( -

{t("debrid.status.failure")}

- )} - {status === "api_down" && ( -

{t("debrid.status.api_down")}

- )} - {status === "invalid_token" && ( -

- {t("debrid.status.invalid_token")} -

- )} + {isDebridVisible ? ( + <> + +

+ {t("debrid.tokenLabel")} +

+
+
+ + { + setdebridToken(newToken); + }} + value={debridToken ?? ""} + placeholder="ABC123..." + passwordToggleable + className="flex-grow" + /> +
+
+ setdebridService(item.id)} + direction="up" + /> +
+
+ {status === "error" && ( +

+ {t("debrid.status.failure")} +

+ )} + {status === "api_down" && ( +

+ {t("debrid.status.api_down")} +

+ )} + {status === "invalid_token" && ( +

+ {t("debrid.status.invalid_token")} +

+ )} + + ) : null} ); } @@ -606,6 +656,7 @@ export function ConnectionsPart( setdebridToken={props.setdebridToken} debridService={props.debridService} setdebridService={props.setdebridService} + mode="settings" /> diff --git a/src/pages/parts/settings/SetupPart.tsx b/src/pages/parts/settings/SetupPart.tsx index 7860f681..0dd9ca3c 100644 --- a/src/pages/parts/settings/SetupPart.tsx +++ b/src/pages/parts/settings/SetupPart.tsx @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import classNames from "classnames"; +import { FetchError } from "ofetch"; import { ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; @@ -174,12 +175,32 @@ export async function testdebridToken( console.log("RD response did not indicate premium status"); attempts += 1; - if (attempts === maxAttempts) { + if (attempts === maxAttempts || data?.error_code === 8) { return "invalid_token"; } await sleep(3000); } catch (error) { console.error("RD API error:", error); + + // Check if it's a FetchError with error_code 8 (bad_token) + if (error instanceof FetchError) { + try { + const errorData = error.data; + if (errorData?.error_code === 8) { + console.log("RD token is invalid (error_code 8)"); + return "invalid_token"; + } + } catch (parseError) { + console.error("Failed to parse RD error response:", parseError); + } + + // For other HTTP errors (like 500, 502, etc.), treat as API down + if (error.statusCode && error.statusCode >= 500) { + console.log(`RD API down (status ${error.statusCode})`); + return "api_down"; + } + } + attempts += 1; if (attempts === maxAttempts) { return "api_down"; @@ -206,6 +227,7 @@ function useIsSetup() { const proxyUrls = useAuthStore((s) => s.proxySet); const febboxKey = usePreferencesStore((s) => s.febboxKey); const debridToken = usePreferencesStore((s) => s.debridToken); + const debridService = usePreferencesStore((s) => s.debridService); const { loading, value } = useAsync(async (): Promise => { const extensionStatus: Status = (await isExtensionActive()) ? "success" @@ -221,7 +243,10 @@ function useIsSetup() { } const febboxKeyStatus: Status = await testFebboxKey(febboxKey); - const debridTokenStatus: Status = await testdebridToken(debridToken); + const debridTokenStatus: Status = + debridService === "torbox" + ? await testTorboxToken(debridToken) + : await testdebridToken(debridToken); return { extension: extensionStatus, @@ -232,7 +257,7 @@ function useIsSetup() { }), debridTokenTest: debridTokenStatus, }; - }, [proxyUrls, febboxKey, debridToken]); + }, [proxyUrls, febboxKey, debridToken, debridService]); let globalState: Status = "unset"; if (