mirror of
https://github.com/p-stream/p-stream.git
synced 2026-08-17 12:54:12 +00:00
fix febbox input not fitting on mobile
This commit is contained in:
parent
a807dec9d0
commit
b20b183545
2 changed files with 86 additions and 235 deletions
|
|
@ -18,7 +18,6 @@ import {
|
|||
StatusCircle,
|
||||
StatusCircleProps,
|
||||
} from "@/components/player/internals/StatusCircle";
|
||||
import { MwLink } from "@/components/text/Link";
|
||||
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||
import { Divider } from "@/components/utils/Divider";
|
||||
import { Ol } from "@/components/utils/Ol";
|
||||
|
|
@ -44,215 +43,8 @@ import { conf } from "@/setup/config";
|
|||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
import { getProxyUrls } from "@/utils/proxyUrls";
|
||||
|
||||
import { RegionSelectorPart } from "../parts/settings/RegionSelectorPart";
|
||||
import {
|
||||
Status,
|
||||
testFebboxKey,
|
||||
testRealDebridKey,
|
||||
} from "../parts/settings/SetupPart";
|
||||
|
||||
async function getFebboxKeyStatus(febboxKey: string | null) {
|
||||
if (febboxKey) {
|
||||
const status: Status = await testFebboxKey(febboxKey);
|
||||
return status;
|
||||
}
|
||||
return "unset";
|
||||
}
|
||||
|
||||
export function FEDAPISetup() {
|
||||
const { t } = useTranslation();
|
||||
const febboxKey = usePreferencesStore((s) => s.febboxKey);
|
||||
const setFebboxKey = usePreferencesStore((s) => s.setFebboxKey);
|
||||
const exampleModal = useModal("febbox-example");
|
||||
|
||||
// Initialize isExpanded based on whether febboxKey has a value
|
||||
const [isExpanded, setIsExpanded] = useState(
|
||||
febboxKey !== null && febboxKey !== "",
|
||||
);
|
||||
|
||||
// Add a separate effect to set the initial state
|
||||
useEffect(() => {
|
||||
// If we have a valid key, make sure the section is expanded
|
||||
if (febboxKey && febboxKey.length > 0) {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
}, [febboxKey]);
|
||||
|
||||
const [status, setStatus] = useState<Status>("unset");
|
||||
const statusMap: Record<Status, StatusCircleProps["type"]> = {
|
||||
error: "error",
|
||||
success: "success",
|
||||
unset: "noresult",
|
||||
api_down: "error",
|
||||
invalid_token: "error",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const checkTokenStatus = async () => {
|
||||
const result = await getFebboxKeyStatus(febboxKey);
|
||||
setStatus(result);
|
||||
};
|
||||
checkTokenStatus();
|
||||
}, [febboxKey]);
|
||||
|
||||
// Toggle handler that preserves the key
|
||||
const toggleExpanded = () => {
|
||||
if (isExpanded) {
|
||||
// Store the key temporarily instead of setting to null
|
||||
setFebboxKey("");
|
||||
setIsExpanded(false);
|
||||
} else {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
};
|
||||
|
||||
const [showVideo, setShowVideo] = useState(false);
|
||||
|
||||
if (conf().ALLOW_FEBBOX_KEY) {
|
||||
return (
|
||||
<>
|
||||
<div className="mt-6">
|
||||
<SettingsCard>
|
||||
<div className="flex justify-between items-center gap-4">
|
||||
<div className="my-3">
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("fedapi.onboarding.title")}
|
||||
</p>
|
||||
<p className="max-w-[30rem] font-medium">
|
||||
<Trans i18nKey="fedapi.onboarding.description" />
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle onClick={toggleExpanded} enabled={isExpanded} />
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded ? (
|
||||
<>
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
|
||||
<div className="my-3">
|
||||
<p className="max-w-[30rem] font-medium">
|
||||
{t("fedapi.setup.title")}
|
||||
<br />
|
||||
<div
|
||||
onClick={() => setShowVideo(!showVideo)}
|
||||
className="flex items-center justify-between p-1 px-2 my-2 w-fit border border-type-secondary rounded-lg cursor-pointer text-type-secondary hover:text-white transition-colors duration-200"
|
||||
>
|
||||
<span className="text-sm">
|
||||
{showVideo
|
||||
? t("fedapi.setup.hideVideo")
|
||||
: t("fedapi.setup.showVideo")}
|
||||
</span>
|
||||
{showVideo ? (
|
||||
<Icon icon={Icons.CHEVRON_UP} className="pl-1" />
|
||||
) : (
|
||||
<Icon icon={Icons.CHEVRON_DOWN} className="pl-1" />
|
||||
)}
|
||||
</div>
|
||||
{showVideo && (
|
||||
<>
|
||||
<div className="relative pt-[56.25%] mt-2">
|
||||
<iframe
|
||||
src="https://player.vimeo.com/video/1059834885?h=c3ab398d42&badge=0&autopause=0&player_id=0&app_id=58479"
|
||||
allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media"
|
||||
className="absolute top-0 left-0 w-full h-full border border-type-secondary rounded-lg bg-black"
|
||||
title="P-Stream FED API Setup Tutorial"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
</>
|
||||
)}
|
||||
<Trans i18nKey="fedapi.setup.step.1">
|
||||
<MwLink url="https://febbox.com" />
|
||||
</Trans>
|
||||
<br />
|
||||
<Trans i18nKey="fedapi.setup.step.2" />
|
||||
<br />
|
||||
<Trans i18nKey="fedapi.setup.step.3" />
|
||||
<br />
|
||||
<Trans i18nKey="fedapi.setup.step.4" />{" "}
|
||||
<button
|
||||
type="button"
|
||||
onClick={exampleModal.show}
|
||||
className="text-type-link hover:text-type-linkHover"
|
||||
>
|
||||
<Trans i18nKey="fedapi.setup.tokenExample.button" />
|
||||
</button>
|
||||
<br />
|
||||
<Trans i18nKey="fedapi.setup.step.5" />
|
||||
</p>
|
||||
<p className="text-type-danger mt-2">
|
||||
<Trans i18nKey="fedapi.setup.step.warning" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
<p className="text-white font-bold mb-3">
|
||||
{t("fedapi.setup.tokenLabel")}
|
||||
</p>
|
||||
<div className="flex items-center w-full gap-4">
|
||||
<StatusCircle type={statusMap[status]} className="mx-2" />
|
||||
<AuthInputBox
|
||||
onChange={(newToken) => {
|
||||
setFebboxKey(newToken);
|
||||
}}
|
||||
value={febboxKey ?? ""}
|
||||
placeholder="eyJ0eXAi..."
|
||||
passwordToggleable
|
||||
className="flex-grow"
|
||||
/>
|
||||
<RegionSelectorPart />
|
||||
</div>
|
||||
{status === "error" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t("fedapi.status.failure")}
|
||||
</p>
|
||||
)}
|
||||
{status === "api_down" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t(
|
||||
"fedapi.status.api_down",
|
||||
"Febbox API is currently unavailable. Please try again later.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{status === "invalid_token" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
{t(
|
||||
"fedapi.status.invalid_token",
|
||||
"Invalid token. Please check your Febbox UI token.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</SettingsCard>
|
||||
</div>
|
||||
<Modal id={exampleModal.id}>
|
||||
<ModalCard>
|
||||
<Heading2 className="!mt-0 !mb-4 !text-2xl">
|
||||
{t("fedapi.setup.tokenExample.title")}
|
||||
</Heading2>
|
||||
<Paragraph className="!mt-1 !mb-6">
|
||||
{t("fedapi.setup.tokenExample.description")}
|
||||
</Paragraph>
|
||||
<div className="bg-authentication-inputBg p-4 rounded-lg mb-6 font-mono text-sm break-all">
|
||||
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3NDc1MTI2MTksIm5iZiI6MTc0NzUxMjYxOSwiZXhwIjoxNzc4NjE2NjM5LCJkYXRhIjp7InVpZCI6NTI1NTc3LCsudujeI6IjE4NTQ4NmEwMzBjMGNlMWJjY2IzYWJjMjI2OTYwYzQ4dhdhs.qkuTF2aVPu54S0RFJS_ca7rlHuGz_Fe6kWkBydYQoCg
|
||||
</div>
|
||||
<Paragraph className="!mt-1 !mb-6 text-type-danger">
|
||||
{t("fedapi.setup.tokenExample.warning")}
|
||||
</Paragraph>
|
||||
<div className="flex justify-end">
|
||||
<Button theme="secondary" onClick={exampleModal.hide}>
|
||||
{t("fedapi.setup.tokenExample.close")}
|
||||
</Button>
|
||||
</div>
|
||||
</ModalCard>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
import { FebboxSetup } from "../parts/settings/ConnectionsPart";
|
||||
import { Status, testRealDebridKey } from "../parts/settings/SetupPart";
|
||||
|
||||
async function getRealDebridKeyStatus(realDebridKey: string | null) {
|
||||
if (realDebridKey) {
|
||||
|
|
@ -628,7 +420,13 @@ export function OnboardingPage() {
|
|||
</div>
|
||||
|
||||
{/* <RealDebridSetup /> */}
|
||||
<FEDAPISetup />
|
||||
<div className="mt-6">
|
||||
<FebboxSetup
|
||||
febboxKey={usePreferencesStore((s) => s.febboxKey)}
|
||||
setFebboxKey={usePreferencesStore((s) => s.setFebboxKey)}
|
||||
mode="onboarding"
|
||||
/>
|
||||
</div>
|
||||
</BiggerCenterContainer>
|
||||
</MinimalPageLayout>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ interface BackendEditProps {
|
|||
|
||||
interface FebboxKeyProps {
|
||||
febboxKey: string | null;
|
||||
setFebboxKey: Dispatch<SetStateAction<string | null>>;
|
||||
setFebboxKey: (value: string | null) => void;
|
||||
}
|
||||
|
||||
interface RealDebridKeyProps {
|
||||
|
|
@ -236,19 +236,44 @@ async function getFebboxKeyStatus(febboxKey: string | null) {
|
|||
return "unset";
|
||||
}
|
||||
|
||||
function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
|
||||
interface FebboxSetupProps extends FebboxKeyProps {
|
||||
mode: "onboarding" | "settings";
|
||||
}
|
||||
|
||||
export function FebboxSetup({
|
||||
febboxKey,
|
||||
setFebboxKey,
|
||||
mode,
|
||||
}: FebboxSetupProps) {
|
||||
const { t } = useTranslation();
|
||||
const [showVideo, setShowVideo] = useState(false);
|
||||
const user = useAuthStore();
|
||||
const preferences = usePreferencesStore();
|
||||
const exampleModal = useModal("febbox-example-settings");
|
||||
const exampleModal = useModal("febbox-example");
|
||||
|
||||
// Enable febbox token when account is loaded and we have a token
|
||||
// Initialize expansion state for onboarding mode
|
||||
const [isExpanded, setIsExpanded] = useState(
|
||||
mode === "onboarding" && febboxKey !== null && febboxKey !== "",
|
||||
);
|
||||
|
||||
// Expand when key is set in onboarding mode
|
||||
useEffect(() => {
|
||||
if (user.account && febboxKey === null && preferences.febboxKey) {
|
||||
if (mode === "onboarding" && febboxKey && febboxKey.length > 0) {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
}, [febboxKey, mode]);
|
||||
|
||||
// Enable febbox token when account is loaded in settings mode
|
||||
useEffect(() => {
|
||||
if (
|
||||
mode === "settings" &&
|
||||
user.account &&
|
||||
febboxKey === null &&
|
||||
preferences.febboxKey
|
||||
) {
|
||||
setFebboxKey(preferences.febboxKey);
|
||||
}
|
||||
}, [user.account, febboxKey, preferences.febboxKey, setFebboxKey]);
|
||||
}, [user.account, febboxKey, preferences.febboxKey, setFebboxKey, mode]);
|
||||
|
||||
const [status, setStatus] = useState<Status>("unset");
|
||||
const statusMap: Record<Status, StatusCircleProps["type"]> = {
|
||||
|
|
@ -267,6 +292,25 @@ function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
|
|||
checkTokenStatus();
|
||||
}, [febboxKey]);
|
||||
|
||||
// Toggle handler based on mode
|
||||
const toggleExpanded = () => {
|
||||
if (mode === "onboarding") {
|
||||
// Onboarding mode: expand/collapse, preserve key
|
||||
if (isExpanded) {
|
||||
setFebboxKey("");
|
||||
setIsExpanded(false);
|
||||
} else {
|
||||
setIsExpanded(true);
|
||||
}
|
||||
} else {
|
||||
// Settings mode: enable/disable
|
||||
setFebboxKey(febboxKey === null ? "" : null);
|
||||
}
|
||||
};
|
||||
|
||||
// Determine if content is visible
|
||||
const isVisible = mode === "onboarding" ? isExpanded : febboxKey !== null;
|
||||
|
||||
if (conf().ALLOW_FEBBOX_KEY) {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -282,12 +326,14 @@ function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
|
|||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
onClick={() => setFebboxKey((s) => (s === null ? "" : null))}
|
||||
enabled={febboxKey !== null}
|
||||
onClick={toggleExpanded}
|
||||
enabled={
|
||||
mode === "onboarding" ? isExpanded : febboxKey !== null
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{febboxKey !== null ? (
|
||||
{isVisible ? (
|
||||
<>
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
|
||||
|
|
@ -348,21 +394,27 @@ function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
|
|||
</div>
|
||||
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
<p className="text-white font-bold">
|
||||
{t("settings.connections.febbox.tokenLabel", "Token")}
|
||||
<p className="text-white font-bold mb-3">
|
||||
{mode === "settings"
|
||||
? t("settings.connections.febbox.tokenLabel", "Token")
|
||||
: t("fedapi.setup.tokenLabel")}
|
||||
</p>
|
||||
<div className="flex items-center w-full gap-4">
|
||||
<StatusCircle type={statusMap[status]} className="mx-2" />
|
||||
<AuthInputBox
|
||||
onChange={(newToken) => {
|
||||
setFebboxKey(newToken);
|
||||
}}
|
||||
value={febboxKey ?? ""}
|
||||
placeholder="eyJ0eXAi..."
|
||||
passwordToggleable
|
||||
className="flex-grow"
|
||||
/>
|
||||
<RegionSelectorPart />
|
||||
<div className="flex md:flex-row flex-col items-center w-full gap-4">
|
||||
<div className="flex items-center w-full">
|
||||
<StatusCircle type={statusMap[status]} className="mx-2" />
|
||||
<AuthInputBox
|
||||
onChange={(newToken) => {
|
||||
setFebboxKey(newToken);
|
||||
}}
|
||||
value={febboxKey ?? ""}
|
||||
placeholder="eyJ0eXAi..."
|
||||
passwordToggleable
|
||||
className="flex-grow"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<RegionSelectorPart />
|
||||
</div>
|
||||
</div>
|
||||
{status === "error" && (
|
||||
<p className="text-type-danger mt-4">
|
||||
|
|
@ -546,9 +598,10 @@ export function ConnectionsPart(
|
|||
realDebridKey={props.realDebridKey}
|
||||
setRealDebridKey={props.setRealDebridKey}
|
||||
/>
|
||||
<FebboxKeyEdit
|
||||
<FebboxSetup
|
||||
febboxKey={props.febboxKey}
|
||||
setFebboxKey={props.setFebboxKey}
|
||||
mode="settings"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue