1
1
mirror of https://github.com/neosubhamoy/pytubepp-helper.git synced 2026-02-04 11:22:22 +05:30
Files
pytubepp-helper/src/pages/settings.tsx

207 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import clsx from "clsx";
import { z } from "zod";
import { useState, useEffect, useRef } from "react";
import { Link } from "react-router-dom";
import { invoke } from "@tauri-apps/api/tauri";
import { getVersion } from "@tauri-apps/api/app";
import { Button } from "@/components/ui/button";
import { ArrowLeft, Github, Globe, History, Save } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Config, PlatformInfo } from "@/types";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useToast } from "@/hooks/use-toast";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { getPlatformInfo } from "@/lib/platform-utils";
const DEFAULT_PORT = 3030;
const settingsFormSchema = z.object({
port: z.number().min(3000, { message: "Port must be greater than 3000" }).max(3999, { message: "Port must be less than 3999" }),
})
export default function SettingsPage() {
const { toast } = useToast();
const [platformInfo, setPlatformInfo] = useState<PlatformInfo | null>(null);
const [appConfig, setAppConfig] = useState<Config | null>(null);
const [appVersion, setAppVersion] = useState<string | null>(null);
const [isFormDirty, setIsFormDirty] = useState(false);
const saveButtonRef = useRef<HTMLButtonElement>(null);
const settingsForm = useForm<z.infer<typeof settingsFormSchema>>({
resolver: zodResolver(settingsFormSchema),
defaultValues: {
port: DEFAULT_PORT,
},
});
useEffect(() => {
const subscription = settingsForm.watch((value) => {
if (appConfig) {
setIsFormDirty(value.port !== appConfig.port);
}
});
return () => subscription.unsubscribe();
}, [settingsForm, appConfig]);
useEffect(() => {
const getConfig = async () => {
const config: Config = await invoke("get_config");
if (config) {
setAppConfig(config);
settingsForm.reset({ port: config.port });
}
}
getConfig().catch(console.error);
}, [settingsForm]);
useEffect(() => {
getPlatformInfo().then(setPlatformInfo).catch(console.error);
const getAppVersion = async () => {
const version = await getVersion();
setAppVersion(version);
}
getAppVersion().catch(console.error);
}, [])
const updateConfig = async () => {
try {
const updatedConfig: Config = await invoke("update_config", {
newConfig: {
port: Number(settingsForm.getValues().port)
}
});
setAppConfig(updatedConfig);
setIsFormDirty(false);
toast({
title: "Settings updated"
});
} catch (error) {
console.error("Failed to update config:", error);
toast({
title: "Failed to update settings",
variant: "destructive"
});
}
}
const resetConfig = async () => {
try {
const config: Config = await invoke("reset_config");
setAppConfig(config);
settingsForm.reset({ port: config.port });
setIsFormDirty(false);
toast({
title: "Using default settings"
});
} catch (error) {
console.error("Failed to reset config:", error);
toast({
title: "Failed to reset settings",
variant: "destructive"
});
}
}
const isUsingDefaultConfig = appConfig?.port === DEFAULT_PORT;
return (
<div className="container">
<div className={clsx("topbar flex justify-between items-center mt-5", !platformInfo?.isWindows && "mx-3")}>
<div className="flex items-center">
<Link to="/">
<ArrowLeft className="w-5 h-5 mr-3"/>
</Link>
<h1 className="text-xl font-bold">Settings</h1>
</div>
<div className="flex items-center">
<Tooltip>
<TooltipTrigger>
<Button
className="ml-3"
variant="outline"
size="icon"
onClick={() => resetConfig()}
disabled={isUsingDefaultConfig}
>
<History className="w-5 h-5"/>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{isUsingDefaultConfig ? "using default settings" : "reset to default"}</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<Button
className="ml-3"
size="icon"
onClick={() => saveButtonRef.current?.click()}
disabled={!isFormDirty}
>
<Save className="w-5 h-5"/>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{isFormDirty ? "save changes" : "no changes to save"}</p>
</TooltipContent>
</Tooltip>
</div>
</div>
<div className={clsx("mt-5", !platformInfo?.isWindows && "mx-3")}>
<div className="flex flex-col min-h-[55vh]">
<Form {...settingsForm}>
<form onSubmit={settingsForm.handleSubmit(updateConfig)}>
<FormField
control={settingsForm.control}
name="port"
render={({ field }) => (
<FormItem>
<FormLabel>Port</FormLabel>
<FormControl>
<Input
type="text"
{...field}
onChange={(e) => {
const value = e.target.value;
field.onChange(value ? Number(value) : DEFAULT_PORT);
}}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
}
}}
/>
</FormControl>
<FormDescription>
The port to use for the websocket server
</FormDescription>
<FormMessage/>
</FormItem>
)}
/>
<Button className="hidden" ref={saveButtonRef} type="submit">Save</Button>
</form>
</Form>
</div>
<div className="flex justify-between items-center border-t border-muted-foreground/50 pt-2">
<div className="flex flex-col">
<p>PytubePP Helper <span className="text-muted-foreground">|</span> <span className="text-sm text-muted-foreground">v{appVersion}-beta</span></p>
<p className="text-xs text-muted-foreground">© {new Date().getFullYear()} - <a href="https://github.com/neosubhamoy/pytubepp-helper/blob/main/LICENSE" target="_blank">MIT License</a> - Made with by <a href="https://neosubhamoy.com" target="_blank">Subhamoy</a></p>
</div>
<div className="flex flex-col">
<div className="flex justify-center items-center gap-2">
<a href="https://pytubepp.neosubhamoy.com" target="_blank" title="website">
<Globe className="w-4 h-4 text-muted-foreground"/>
</a>
<a href="https://github.com/neosubhamoy/pytubepp-helper" target="_blank" title="github">
<Github className="w-4 h-4 text-muted-foreground"/>
</a>
</div>
</div>
</div>
</div>
</div>
);
}