diff --git a/src/i18n/de.json b/src/i18n/de.json index fb28b5b..5167529 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -19,7 +19,9 @@ "displayName": "Anzeigename", "noAccount": "Noch kein Konto?", "hasAccount": "Bereits ein Konto?", - "orContinueWith": "Oder weiter mit" + "orContinueWith": "Oder weiter mit", + "loginSubtitle": "Melde dich bei deinem Konto an", + "registerSubtitle": "Erstelle ein neues Konto" }, "categories": { "title": "Kategorien", diff --git a/src/i18n/en.json b/src/i18n/en.json index 5209970..642fd5a 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -19,7 +19,9 @@ "displayName": "Display Name", "noAccount": "Don't have an account?", "hasAccount": "Already have an account?", - "orContinueWith": "Or continue with" + "orContinueWith": "Or continue with", + "loginSubtitle": "Sign in to your account", + "registerSubtitle": "Create a new account" }, "categories": { "title": "Categories", diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx new file mode 100644 index 0000000..75935e4 --- /dev/null +++ b/src/pages/LoginPage.tsx @@ -0,0 +1,118 @@ +import { useState } from "react" +import { Link, useNavigate } from "react-router-dom" +import { useTranslation } from "react-i18next" +import { useAuth } from "@/hooks/useAuth" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Separator } from "@/components/ui/separator" + +export default function LoginPage() { + const { t } = useTranslation() + const { signIn, signInWithOAuth } = useAuth() + const navigate = useNavigate() + const [email, setEmail] = useState("") + const [password, setPassword] = useState("") + const [error, setError] = useState("") + const [loading, setLoading] = useState(false) + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault() + setError("") + setLoading(true) + try { + await signIn(email, password) + navigate("/") + } catch (err) { + setError(err instanceof Error ? err.message : t("common.error")) + } finally { + setLoading(false) + } + } + + return ( +
+ + + + {t("app.title")} +

{t("auth.loginSubtitle")}

+
+ +
+
+ + setEmail(e.target.value)} + required + autoComplete="email" + /> +
+
+ + setPassword(e.target.value)} + required + autoComplete="current-password" + /> +
+ {error && ( +

{error}

+ )} + +
+ +
+
+ + + {t("auth.orContinueWith")} + +
+
+ + +
+
+ +

+ {t("auth.noAccount")}{" "} + + {t("auth.register")} + +

+
+
+
+ ) +}