Skip to content

Commit

Permalink
feat: debrid token input component
Browse files Browse the repository at this point in the history
  • Loading branch information
zamitto committed Jan 12, 2025
1 parent b1dde44 commit 8761302
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 14 deletions.
3 changes: 2 additions & 1 deletion src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@
"launch_minimized": "Launch Hydra minimized",
"disable_nsfw_alert": "Disable NSFW alert",
"seed_after_download_complete": "Seed after download complete",
"show_hidden_achievement_description": "Show hidden achievements description before unlocking them"
"show_hidden_achievement_description": "Show hidden achievements description before unlocking them",
"debrid_services": "Debrid Services"
},
"notifications": {
"download_complete": "Download complete",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/pt-BR/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@
"launch_minimized": "Iniciar o Hydra minimizado",
"disable_nsfw_alert": "Desativar alerta de conteúdo inapropriado",
"seed_after_download_complete": "Semear após a conclusão do download",
"show_hidden_achievement_description": "Mostrar descrição de conquistas ocultas antes de debloqueá-las"
"show_hidden_achievement_description": "Mostrar descrição de conquistas ocultas antes de debloqueá-las",
"debrid_services": "Serviços Debrid"
},
"notifications": {
"download_complete": "Download concluído",
Expand Down
186 changes: 186 additions & 0 deletions src/renderer/src/pages/settings/settings-debrid-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { useContext, useEffect, useMemo, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
import * as styles from "./settings-debrid.css";
import { useAppSelector, useToast } from "@renderer/hooks";
import { SPACING_UNIT } from "@renderer/theme.css";
import { settingsContext } from "@renderer/context";
import { DebridServices } from "@types";

const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
const TORBOX_API_TOKEN_URL = "https://torbox.app/settings";

Check failure on line 11 in src/renderer/src/pages/settings/settings-debrid-input.tsx

View workflow job for this annotation

GitHub Actions / lint

'TORBOX_API_TOKEN_URL' is declared but its value is never read.

interface SettingsDebridForm {
useRealDebrid: boolean;
realDebridApiToken: string | null;
useTorBox: boolean;
torBoxApiToken: string | null;
}

export interface SettingsDebridProps {
service: DebridServices;
form: SettingsDebridForm;
setForm: (SettingsDebridForm) => void;
}

export function SettingsDebridInput({
service,
form,
setForm,
}: SettingsDebridProps) {
const userPreferences = useAppSelector(
(state) => state.userPreferences.value
);

const { updateUserPreferences } = useContext(settingsContext);

const [isLoading, setIsLoading] = useState(false);

const { showSuccessToast, showErrorToast } = useToast();

const { t } = useTranslation("settings");

useEffect(() => {
if (userPreferences) {
setForm({
useRealDebrid: Boolean(userPreferences.realDebridApiToken),
realDebridApiToken: userPreferences.realDebridApiToken ?? null,
useTorBox: Boolean(userPreferences.torBoxApiToken),
torBoxApiToken: userPreferences.torBoxApiToken ?? null,
});
}
}, [userPreferences]);

const handleFormSubmit: React.FormEventHandler<HTMLFormElement> = async (
event
) => {
setIsLoading(true);
event.preventDefault();

try {
if (form.useRealDebrid) {
const user = await window.electron.authenticateRealDebrid(
form.realDebridApiToken!
);

if (user.type === "free") {
showErrorToast(
t("real_debrid_free_account_error", { username: user.username })
);

return;
} else {
showSuccessToast(
t("real_debrid_linked_message", { username: user.username })
);
}
} else {
showSuccessToast(t("changes_saved"));
}

updateUserPreferences({
realDebridApiToken: form.useRealDebrid ? form.realDebridApiToken : null,
});
} catch (err) {
showErrorToast(t("real_debrid_invalid_token"));
} finally {
setIsLoading(false);
}
};

const useDebridService = useMemo(() => {
if (service === "RealDebrid") {
return form.useRealDebrid;
}

if (service === "TorBox") {
return form.useTorBox;
}

return false;
}, [form, service]);

const debridApiToken = useMemo(() => {
if (service === "RealDebrid") {
return form.realDebridApiToken;
}

if (service === "TorBox") {
return form.torBoxApiToken;
}

return null;
}, [form, service]);

const onChangeCheckbox = () => {
if (service === "RealDebrid") {
setForm((prev) => ({
...prev,
useRealDebrid: !form.useRealDebrid,
}));
}

if (service === "TorBox") {
setForm((prev) => ({
...prev,
useTorBox: !form.useTorBox,
}));
}
};

const onChangeInput = (event: React.ChangeEvent<HTMLInputElement>) => {
if (service === "RealDebrid") {
setForm((prev) => ({
...prev,
realDebridApiToken: event.target.value,
}));
}

if (service === "TorBox") {
setForm((prev) => ({
...prev,
torBoxApiToken: event.target.value,
}));
}
};

const isButtonDisabled =
(form.useRealDebrid && !form.realDebridApiToken) || isLoading;

return (
<form className={styles.form} onSubmit={handleFormSubmit}>
<CheckboxField
label={t("enable_real_debrid")}
checked={useDebridService}
onChange={onChangeCheckbox}
/>

{useDebridService && (
<TextField
label={t("real_debrid_api_token")}
value={debridApiToken ?? ""}
type="password"
onChange={onChangeInput}
placeholder="API Token"
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
rightContent={
<Button
type="submit"
style={{
alignSelf: "flex-end",
}}
disabled={isButtonDisabled}
>
{t("save")}
</Button>
}
hint={
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
<Link to={REAL_DEBRID_API_TOKEN_URL} />
</Trans>
}
/>
)}
</form>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import { useContext, useEffect, useState } from "react";
import { Trans, useTranslation } from "react-i18next";

import { Button, CheckboxField, Link, TextField } from "@renderer/components";
import * as styles from "./settings-real-debrid.css";
import * as styles from "./settings-debrid.css";

import { useAppSelector, useToast } from "@renderer/hooks";

import { SPACING_UNIT } from "@renderer/theme.css";
import { settingsContext } from "@renderer/context";

const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
const TORBOX_API_TOKEN_URL = "https://torbox.app/settings";

export function SettingsRealDebrid() {
export function SettingsDebrid() {
const userPreferences = useAppSelector(
(state) => state.userPreferences.value
);
Expand All @@ -22,6 +23,8 @@ export function SettingsRealDebrid() {
const [form, setForm] = useState({
useRealDebrid: false,
realDebridApiToken: null as string | null,
useTorBox: false,
torBoxApiToken: null as string | null,
});

const { showSuccessToast, showErrorToast } = useToast();
Expand All @@ -33,6 +36,8 @@ export function SettingsRealDebrid() {
setForm({
useRealDebrid: Boolean(userPreferences.realDebridApiToken),
realDebridApiToken: userPreferences.realDebridApiToken ?? null,
useTorBox: Boolean(userPreferences.torBoxApiToken),
torBoxApiToken: userPreferences.torBoxApiToken ?? null,
});
}
}, [userPreferences]);
Expand Down Expand Up @@ -102,6 +107,17 @@ export function SettingsRealDebrid() {
}
placeholder="API Token"
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
rightContent={
<Button
type="submit"
style={{
alignSelf: "flex-end",
}}
disabled={isButtonDisabled}
>
{t("save")}
</Button>
}
hint={
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
<Link to={REAL_DEBRID_API_TOKEN_URL} />
Expand All @@ -110,13 +126,45 @@ export function SettingsRealDebrid() {
/>
)}

<Button
type="submit"
style={{ alignSelf: "flex-end", marginTop: `${SPACING_UNIT * 2}px` }}
disabled={isButtonDisabled}
>
{t("save_changes")}
</Button>
<CheckboxField
label={t("enable_torbox")}
checked={form.useTorBox}
onChange={() =>
setForm((prev) => ({
...prev,
useTorBox: !form.useTorBox,
}))
}
/>

{form.useTorBox && (
<TextField
label={t("real_debrid_api_token")}
value={form.torBoxApiToken ?? ""}
type="password"
onChange={(event) =>
setForm({ ...form, torBoxApiToken: event.target.value })
}
placeholder="API Token"
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
rightContent={
<Button
type="submit"
style={{
alignSelf: "flex-end",
}}
disabled={isButtonDisabled}
>
{t("save")}
</Button>
}
hint={
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
<Link to={TORBOX_API_TOKEN_URL} />
</Trans>
}
/>
)}
</form>
);
}
6 changes: 3 additions & 3 deletions src/renderer/src/pages/settings/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button } from "@renderer/components";

import * as styles from "./settings.css";
import { useTranslation } from "react-i18next";
import { SettingsRealDebrid } from "./settings-real-debrid";
import { SettingsDebrid } from "./settings-debrid";
import { SettingsGeneral } from "./settings-general";
import { SettingsBehavior } from "./settings-behavior";

Expand All @@ -25,7 +25,7 @@ export default function Settings() {
t("general"),
t("behavior"),
t("download_sources"),
"Real-Debrid",
t("debrid_services"),
];

if (userDetails) return [...categories, t("privacy")];
Expand All @@ -50,7 +50,7 @@ export default function Settings() {
}

if (currentCategoryIndex === 3) {
return <SettingsRealDebrid />;
return <SettingsDebrid />;
}

return <SettingsPrivacy />;
Expand Down
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export type HydraCloudFeature =
| "backup"
| "achievements-points";

export type DebridServices = "RealDebrid" | "TorBox";

export interface GameRepack {
id: number;
title: string;
Expand Down

0 comments on commit 8761302

Please sign in to comment.