add febbox token example modal

This commit is contained in:
Pas 2025-07-27 21:25:51 -07:00
parent 5e7a8cc228
commit 084078d75a
3 changed files with 276 additions and 204 deletions

View file

@ -1105,6 +1105,14 @@
"4": "4. Copy the 'ui' cookie's value.",
"5": "5. Close the tab, but do NOT logout!",
"warning": "(Do not share this token!)"
},
"tokenLabel": "Token",
"tokenExample": {
"button": "(Example)",
"title": "Example Token",
"description": "This is what a Febbox UI token looks like:",
"warning": "Don't try to use, it's fake.",
"close": "Got it"
}
},
"status": {

View file

@ -62,6 +62,7 @@ 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(
@ -108,116 +109,148 @@ export function FEDAPISetup() {
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="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">
{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" />
<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&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;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 />
</>
)}
</div>
{showVideo && (
<>
<div className="relative pt-[56.25%] mt-2">
<iframe
src="https://player.vimeo.com/video/1059834885?h=c3ab398d42&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;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" />
<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>
<br />
<Trans i18nKey="fedapi.setup.step.5" />
<Divider marginClass="my-6 px-8 box-content -mx-8" />
<p className="text-white font-bold mb-3">
{t("fedapi.setup.tokenLabel")}
</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("settings.connections.febbox.tokenLabel", "Token")}
</p>
<div className="flex items-center w-full">
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
<AuthInputBox
onChange={(newToken) => {
setFebboxKey(newToken);
}}
value={febboxKey ?? ""}
placeholder="eyABCdE..."
passwordToggleable
className="flex-grow"
/>
</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>
<div className="flex items-center w-full">
<StatusCircle
type={statusMap[status]}
className="mx-2 mr-4"
/>
<AuthInputBox
onChange={(newToken) => {
setFebboxKey(newToken);
}}
value={febboxKey ?? ""}
placeholder="eyJ0eXAi..."
passwordToggleable
className="flex-grow"
/>
</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>
</>
);
}
}

View file

@ -11,6 +11,7 @@ import { Button } from "@/components/buttons/Button";
import { Toggle } from "@/components/buttons/Toggle";
import { Icon, Icons } from "@/components/Icon";
import { SettingsCard } from "@/components/layout/SettingsCard";
import { Modal, ModalCard, useModal } from "@/components/overlays/Modal";
import {
StatusCircle,
StatusCircleProps,
@ -18,7 +19,7 @@ import {
import { MwLink } from "@/components/text/Link";
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
import { Divider } from "@/components/utils/Divider";
import { Heading1 } from "@/components/utils/Text";
import { Heading1, Heading2, Paragraph } from "@/components/utils/Text";
import {
SetupPart,
Status,
@ -238,6 +239,7 @@ function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
const [showVideo, setShowVideo] = useState(false);
const user = useAuthStore();
const preferences = usePreferencesStore();
const exampleModal = useModal("febbox-example-settings");
// Enable febbox token when account is loaded and we have a token
useEffect(() => {
@ -265,111 +267,140 @@ function FebboxKeyEdit({ febboxKey, setFebboxKey }: FebboxKeyProps) {
if (conf().ALLOW_FEBBOX_KEY) {
return (
<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={() => setFebboxKey((s) => (s === null ? "" : null))}
enabled={febboxKey !== null}
/>
</div>
</div>
{febboxKey !== null ? (
<>
<Divider marginClass="my-6 px-8 box-content -mx-8" />
<>
<SettingsCard>
<div className="flex justify-between items-center gap-4">
<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&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;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" />
<br />
<Trans i18nKey="fedapi.setup.step.5" />
<p className="text-white font-bold mb-3">
{t("fedapi.onboarding.title")}
</p>
<p className="text-type-danger mt-2">
<Trans i18nKey="fedapi.setup.step.warning" />
<p className="max-w-[30rem] font-medium">
<Trans i18nKey="fedapi.onboarding.description" />
</p>
</div>
<Divider marginClass="my-6 px-8 box-content -mx-8" />
<p className="text-white font-bold mb-3">
{t("settings.connections.febbox.tokenLabel", "Token")}
</p>
<div className="flex items-center w-full">
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
<AuthInputBox
onChange={(newToken) => {
setFebboxKey(newToken);
}}
value={febboxKey ?? ""}
placeholder="eyABCdE..."
passwordToggleable
className="flex-grow"
<div>
<Toggle
onClick={() => setFebboxKey((s) => (s === null ? "" : null))}
enabled={febboxKey !== null}
/>
</div>
{status === "error" && (
<p className="text-type-danger mt-4">
{t("fedapi.status.failure")}
</div>
{febboxKey !== null ? (
<>
<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&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;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">
{t("settings.connections.febbox.tokenLabel", "Token")}
</p>
)}
{status === "api_down" && (
<p className="text-type-danger mt-4">
{t("fedapi.status.api_down")}
</p>
)}
{status === "invalid_token" && (
<p className="text-type-danger mt-4">
{t("fedapi.status.invalid_token")}
</p>
)}
</>
) : null}
</SettingsCard>
<div className="flex items-center w-full">
<StatusCircle type={statusMap[status]} className="mx-2 mr-4" />
<AuthInputBox
onChange={(newToken) => {
setFebboxKey(newToken);
}}
value={febboxKey ?? ""}
placeholder="eyJ0eXAi..."
passwordToggleable
className="flex-grow"
/>
</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")}
</p>
)}
{status === "invalid_token" && (
<p className="text-type-danger mt-4">
{t("fedapi.status.invalid_token")}
</p>
)}
</>
) : null}
</SettingsCard>
<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>
</>
);
}
}