mirror of
https://github.com/sussy-code/smov.git
synced 2026-03-11 17:55:35 +00:00
Update Direct page, add migrate button, and clean up
This commit is contained in:
parent
718acfd76a
commit
c48602a9fc
5 changed files with 174 additions and 72 deletions
|
|
@ -217,6 +217,24 @@
|
|||
"action": "Download data"
|
||||
}
|
||||
}
|
||||
},
|
||||
"direct": {
|
||||
"title": "Direct migration",
|
||||
"description": "Enter the destination backend URL to migrate your current account data to a new backend. This keeps your passphrase the same!",
|
||||
"backendLabel": "Destination Backend URL",
|
||||
"recaptchaLabel": "ReCaptcha Key (Optional)",
|
||||
"toggleLable": "Needs ReCaptcha?",
|
||||
"loginRequired": "You must be logged in to migrate your data! Please go back and login to continue.",
|
||||
"status": {
|
||||
"error": "Failed to migrate your data. 😿",
|
||||
"success": "Your data has been migrated successfully! 🎉"
|
||||
},
|
||||
"button": {
|
||||
"migrate": "Migrate",
|
||||
"processing": "Processing...",
|
||||
"home": "Go home",
|
||||
"login": "Continue to login"
|
||||
}
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
|
|
@ -596,7 +614,11 @@
|
|||
"server": {
|
||||
"description": "If you would like to connect to a custom backend to store your data, enable this and provide the URL. <0>Instructions.</0>",
|
||||
"label": "Custom server",
|
||||
"urlLabel": "Custom server URL"
|
||||
"urlLabel": "Custom server URL",
|
||||
"migration": {
|
||||
"description": "<0>Migrate my data</0> to a new server. ",
|
||||
"link": "Migrate my data"
|
||||
}
|
||||
},
|
||||
"setup": {
|
||||
"doSetup": "Do setup",
|
||||
|
|
|
|||
|
|
@ -86,12 +86,12 @@ export function useMigration() {
|
|||
};
|
||||
|
||||
const migrate = useCallback(
|
||||
async (backendUrl: string, recaptchaToken: string) => {
|
||||
async (backendUrl: string, recaptchaToken?: string) => {
|
||||
if (!currentAccount) return;
|
||||
|
||||
const { challenge } = await getRegisterChallengeToken(
|
||||
backendUrl,
|
||||
recaptchaToken,
|
||||
recaptchaToken || undefined, // Pass undefined if token is not provided
|
||||
);
|
||||
const keys = await keysFromSeed(base64ToBuffer(currentAccount.seed));
|
||||
const signature = await signChallenge(keys, challenge);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,139 @@
|
|||
import { useCallback, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { SettingsCard } from "@/components/layout/SettingsCard";
|
||||
import { CenterContainer } from "@/components/layout/ThinContainer";
|
||||
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||
import { Divider } from "@/components/utils/Divider";
|
||||
import { Heading2, Paragraph } from "@/components/utils/Text";
|
||||
import { useAuth } from "@/hooks/auth/useAuth";
|
||||
import { useMigration } from "@/hooks/auth/useMigration";
|
||||
import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
|
||||
import { PageTitle } from "@/pages/parts/util/PageTitle";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
export function MigrationDirectPage() {
|
||||
const { t } = useTranslation();
|
||||
const user = useAuthStore();
|
||||
const { logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const { migrate } = useMigration();
|
||||
const [backendUrl, setBackendUrl] = useState("");
|
||||
const [status, setStatus] = useState<
|
||||
"idle" | "success" | "error" | "processing"
|
||||
>("idle");
|
||||
const updateBackendUrl = useAuthStore((state) => state.setBackendUrl);
|
||||
|
||||
const handleMigration = useCallback(async () => {
|
||||
if (!backendUrl) {
|
||||
// eslint-disable-next-line no-alert
|
||||
alert("Please provide a Backend URL.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setStatus("processing");
|
||||
const account = await migrate(backendUrl);
|
||||
if (account) {
|
||||
setStatus("success");
|
||||
await logout();
|
||||
updateBackendUrl(backendUrl);
|
||||
} else {
|
||||
setStatus("error");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error during migration:", error);
|
||||
setStatus("error");
|
||||
}
|
||||
}, [backendUrl, migrate, updateBackendUrl, logout]);
|
||||
|
||||
const continueButton = () => {
|
||||
if (status === "success") {
|
||||
navigate("/login");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MinimalPageLayout>
|
||||
<PageTitle subpage k="global.pages.migration" />
|
||||
<CenterContainer>Hi</CenterContainer>
|
||||
<CenterContainer>
|
||||
{user.account ? (
|
||||
<div>
|
||||
<Heading2 className="!text-4xl">
|
||||
{" "}
|
||||
{t("migration.direct.title")}
|
||||
</Heading2>
|
||||
<div className="space-y-6 max-w-3xl mx-auto">
|
||||
<Paragraph className="text-lg max-w-md">
|
||||
{t("migration.direct.description")}
|
||||
</Paragraph>
|
||||
<SettingsCard>
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="font-bold text-white">
|
||||
{t("migration.direct.backendLabel")}
|
||||
</p>
|
||||
</div>
|
||||
{backendUrl !== null && (
|
||||
<>
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
<AuthInputBox
|
||||
placeholder="https://"
|
||||
value={backendUrl ?? ""}
|
||||
onChange={setBackendUrl}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</SettingsCard>
|
||||
|
||||
<div className="text-center">
|
||||
{status !== "success" && (
|
||||
<Button theme="purple" onClick={handleMigration}>
|
||||
{status === "processing"
|
||||
? t("migration.direct.button.processing")
|
||||
: t("migration.direct.button.migrate")}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{status === "success" && (
|
||||
<div>
|
||||
<Button
|
||||
theme="purple"
|
||||
className="mt-4"
|
||||
onClick={continueButton}
|
||||
>
|
||||
{t("migration.direct.button.login")}
|
||||
</Button>
|
||||
<p className="text-green-600 mt-4">
|
||||
{t("migration.direct.status.success")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === "error" && (
|
||||
<p className="text-red-600 mt-4">
|
||||
{t("migration.direct.status.error")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center text-center mb-8">
|
||||
<Paragraph className="max-w-[320px] text-md">
|
||||
{t("migration.direct.loginRequired")}
|
||||
</Paragraph>
|
||||
<Button
|
||||
theme="purple"
|
||||
className="mt-4"
|
||||
onClick={() => navigate("/")}
|
||||
>
|
||||
{t("migration.direct.button.home")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</CenterContainer>
|
||||
</MinimalPageLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
|||
import { Divider } from "@/components/utils/Divider";
|
||||
import { Heading1 } from "@/components/utils/Text";
|
||||
// import { SetupPart } from "@/pages/parts/settings/SetupPart";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
interface ProxyEditProps {
|
||||
proxyUrls: string[] | null;
|
||||
|
|
@ -116,6 +117,7 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {
|
|||
|
||||
function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
|
||||
const { t } = useTranslation();
|
||||
const user = useAuthStore();
|
||||
return (
|
||||
<SettingsCard>
|
||||
<div className="flex justify-between items-center gap-4">
|
||||
|
|
@ -130,6 +132,18 @@ function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
|
|||
</MwLink>
|
||||
</Trans>
|
||||
</p>
|
||||
{user.account && (
|
||||
<div>
|
||||
<br />
|
||||
<p className="max-w-[20rem] font-medium">
|
||||
<Trans i18nKey="settings.connections.server.migration.description">
|
||||
<MwLink to="/migration">
|
||||
{t("settings.connections.server.migration.link")}
|
||||
</MwLink>
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
|
|
|
|||
|
|
@ -148,6 +148,13 @@ function App() {
|
|||
element={<OnboardingExtensionPage />}
|
||||
/>
|
||||
<Route path="/onboarding/proxy" element={<OnboardingProxyPage />} />
|
||||
|
||||
<Route path="/migration" element={<MigrationDirectPage />} />
|
||||
{/* Migration pages - awaiting import and export fixes
|
||||
<Route path="/migration" element={<MigrationPage />} />
|
||||
<Route path="/migration/direct" element={<MigrationDirectPage />} />
|
||||
*/}
|
||||
|
||||
{shouldHaveDmcaPage() ? (
|
||||
<Route path="/dmca" element={<DmcaPage />} />
|
||||
) : null}
|
||||
|
|
@ -180,74 +187,6 @@ function App() {
|
|||
{showDowntime && (
|
||||
<MaintenancePage onHomeButtonClick={handleButtonClick} />
|
||||
)}
|
||||
<Routes>
|
||||
{/* functional routes */}
|
||||
<Route path="/s/:query" element={<QuickSearch />} />
|
||||
<Route path="/search/:type" element={<Navigate to="/browse" />} />
|
||||
<Route path="/search/:type/:query?" element={<QueryView />} />
|
||||
|
||||
{/* pages */}
|
||||
<Route
|
||||
path="/media/:media"
|
||||
element={
|
||||
<LegacyUrlView>
|
||||
<Suspense fallback={null}>
|
||||
<PlayerView />
|
||||
</Suspense>
|
||||
</LegacyUrlView>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/media/:media/:season/:episode"
|
||||
element={
|
||||
<LegacyUrlView>
|
||||
<Suspense fallback={null}>
|
||||
<PlayerView />
|
||||
</Suspense>
|
||||
</LegacyUrlView>
|
||||
}
|
||||
/>
|
||||
<Route path="/browse/:query?" element={<HomePage />} />
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
<Route path="/onboarding" element={<OnboardingPage />} />
|
||||
<Route
|
||||
path="/onboarding/extension"
|
||||
element={<OnboardingExtensionPage />}
|
||||
/>
|
||||
<Route path="/onboarding/proxy" element={<OnboardingProxyPage />} />
|
||||
|
||||
<Route path="/migration" element={<MigrationPage />} />
|
||||
<Route path="/migration/direct" element={<MigrationDirectPage />} />
|
||||
|
||||
{shouldHaveDmcaPage() ? (
|
||||
<Route path="/dmca" element={<DmcaPage />} />
|
||||
) : null}
|
||||
|
||||
{/* Settings page */}
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<Suspense fallback={null}>
|
||||
<SettingsPage />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* admin routes */}
|
||||
<Route path="/admin" element={<AdminPage />} />
|
||||
|
||||
{/* other */}
|
||||
<Route path="/dev" element={<DeveloperPage />} />
|
||||
<Route path="/dev/video" element={<VideoTesterView />} />
|
||||
{/* developer routes that can abuse workers are disabled in production */}
|
||||
{process.env.NODE_ENV === "development" ? (
|
||||
<Route path="/dev/test" element={<TestView />} />
|
||||
) : null}
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue