feat: normalize email login and improve theme handling
Normalize email input by stripping whitespace and converting to lowercase in login endpoint, remove EmailStr validation in favor of plain string type, move dark mode class toggle from Layout to App component for better initialization, add theme toggle button to login page, and set dark mode as default theme when no preference is stored
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
||||
|
||||
import { Layout } from "./components/Layout";
|
||||
@@ -7,10 +8,17 @@ import { FirewallPreview } from "./pages/FirewallPreview";
|
||||
import { ListPage } from "./pages/ListPage";
|
||||
import { Login } from "./pages/Login";
|
||||
import { PolicyDesigner } from "./pages/PolicyDesigner";
|
||||
import { useTheme } from "./stores/theme";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export function App() {
|
||||
const dark = useTheme((state) => state.dark);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.classList.toggle("dark", dark);
|
||||
}, [dark]);
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
@@ -38,4 +46,3 @@ export function App() {
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,10 +45,6 @@ export function Layout() {
|
||||
const navigate = useNavigate();
|
||||
const { dark, toggle } = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.classList.toggle("dark", dark);
|
||||
}, [dark]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!token()) navigate("/login");
|
||||
}, [navigate]);
|
||||
@@ -96,4 +92,3 @@ export function Layout() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { FormEvent, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ShieldCheck } from "lucide-react";
|
||||
import { Moon, ShieldCheck, Sun } from "lucide-react";
|
||||
|
||||
import { login } from "../api/client";
|
||||
import { useTheme } from "../stores/theme";
|
||||
|
||||
export function Login() {
|
||||
const navigate = useNavigate();
|
||||
const [email, setEmail] = useState("admin@nexafabric.local");
|
||||
const [password, setPassword] = useState("ChangeMe_UseEnvInstead");
|
||||
const [error, setError] = useState("");
|
||||
const { dark, toggle } = useTheme();
|
||||
|
||||
async function submit(event: FormEvent) {
|
||||
event.preventDefault();
|
||||
@@ -23,6 +25,14 @@ export function Login() {
|
||||
|
||||
return (
|
||||
<div className="grid min-h-screen place-items-center bg-canvas px-4">
|
||||
<button
|
||||
className="fixed right-4 top-4 rounded-md border border-border bg-panel p-2 text-slate-700 hover:bg-slate-100 dark:text-slate-200 dark:hover:bg-slate-800"
|
||||
onClick={toggle}
|
||||
type="button"
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
{dark ? <Sun size={18} /> : <Moon size={18} />}
|
||||
</button>
|
||||
<form onSubmit={submit} className="w-full max-w-sm rounded-md border border-border bg-panel p-6 shadow-sm">
|
||||
<div className="mb-6 flex items-center gap-3">
|
||||
<div className="rounded-md bg-accent p-2 text-white">
|
||||
@@ -47,4 +57,3 @@ export function Login() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ type ThemeState = {
|
||||
toggle: () => void;
|
||||
};
|
||||
|
||||
const storedTheme = localStorage.getItem("nexafabric.theme");
|
||||
|
||||
export const useTheme = create<ThemeState>((set) => ({
|
||||
dark: localStorage.getItem("nexafabric.theme") === "dark",
|
||||
dark: storedTheme ? storedTheme === "dark" : true,
|
||||
toggle: () =>
|
||||
set((state) => {
|
||||
const dark = !state.dark;
|
||||
@@ -14,4 +16,3 @@ export const useTheme = create<ThemeState>((set) => ({
|
||||
return { dark };
|
||||
}),
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user