diff --git a/web/.eslintrc.cjs b/web/.eslintrc.cjs index 883537d0f..ab64df676 100644 --- a/web/.eslintrc.cjs +++ b/web/.eslintrc.cjs @@ -43,6 +43,14 @@ module.exports = { "error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, ], + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], "no-console": "error", "prettier/prettier": [ "warn", diff --git a/web/login.html b/web/login.html new file mode 100644 index 000000000..39ca78c3c --- /dev/null +++ b/web/login.html @@ -0,0 +1,36 @@ + + + + + + + Frigate + + + + + + + + + + +
+ + + + diff --git a/web/src/LoginPage.tsx b/web/src/LoginPage.tsx new file mode 100644 index 000000000..8b1b1decd --- /dev/null +++ b/web/src/LoginPage.tsx @@ -0,0 +1,22 @@ +import { UserAuthForm } from "@/components/AuthForm"; +import Logo from "./components/Logo"; +import { ThemeProvider } from "./context/theme-provider"; + +function LoginPage() { + return ( + +
+
+
+
+ +
+ +
+
+
+
+ ); +} + +export default LoginPage; diff --git a/web/src/components/AuthForm.tsx b/web/src/components/AuthForm.tsx new file mode 100644 index 000000000..113ebf508 --- /dev/null +++ b/web/src/components/AuthForm.tsx @@ -0,0 +1,114 @@ +"use client"; + +import * as React from "react"; + +import { cn } from "@/lib/utils"; +import { Input } from "./ui/input"; +import { Button } from "./ui/button"; +import ActivityIndicator from "./indicators/activity-indicator"; +import axios from "axios"; +import { Toaster } from "./ui/sonner"; +import { toast } from "sonner"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, +} from "@/components/ui/form"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +interface UserAuthFormProps extends React.HTMLAttributes {} + +export function UserAuthForm({ className, ...props }: UserAuthFormProps) { + const [isLoading, setIsLoading] = React.useState(false); + + const formSchema = z.object({ + user: z.string(), + password: z.string(), + }); + + const form = useForm>({ + resolver: zodResolver(formSchema), + mode: "onChange", + defaultValues: { + user: "", + password: "", + }, + }); + + const onSubmit = async (values: z.infer) => { + setIsLoading(true); + try { + await axios.post( + "/api/login", + { + user: values.user, + password: values.password, + }, + { + headers: { + "X-CSRF-TOKEN": 1, + }, + }, + ); + window.location.href = "/"; + } catch (error) { + toast.error("Login failed", { + position: "top-center", + }); + setIsLoading(false); + } + }; + + return ( +
+
+ + ( + + User + + + + + )} + /> + ( + + Password + + + + + )} + /> +
+ +
+ + + +
+ ); +} diff --git a/web/src/login.tsx b/web/src/login.tsx new file mode 100644 index 000000000..23ff71e3e --- /dev/null +++ b/web/src/login.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import LoginPage from "./LoginPage.tsx"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + , +);