feat: add bw themes
ci-front / build (push) Successful in 2m26s

This commit is contained in:
2026-04-03 21:49:39 +03:00
parent cc23cc2a1e
commit 88fb7a1888
9 changed files with 642 additions and 235 deletions
+130
View File
@@ -0,0 +1,130 @@
import React, { useState, useEffect } from "react";
import { useNavigate, Link } from "react-router-dom";
import { FiUser, FiLock, FiLogIn } from "react-icons/fi";
import { useAuthStore } from "@/modules/auth/store/useAuthStore";
export const AuthPage: React.FC = () => {
const navigate = useNavigate();
const { login, isLoading, error, clearError, token } = useAuthStore();
const [formData, setFormData] = useState({
login: "",
password: "",
});
useEffect(() => {
if (token) {
navigate("/dashboard");
}
}, [token, navigate]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await login(formData);
navigate("/dashboard");
} catch (err) {
// Error is handled by store
}
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
if (error) clearError();
};
return (
<div className="pt-[25%] flex items-center justify-center bg-white dark:bg-black transition-colors duration-200">
<div className="w-full max-w-md px-8">
{/* Card */}
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg shadow-xl p-8 border border-gray-200 dark:border-gray-800">
{/* Header */}
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-2">
Welcome Back
</h1>
<p className="text-gray-600 dark:text-gray-400">
Sign in to your account
</p>
</div>
{/* Error Message */}
{error && (
<div className="mb-4 p-3 bg-red-100 dark:bg-red-900/20 border border-red-400 dark:border-red-800 rounded text-red-700 dark:text-red-400 text-sm">
{error}
</div>
)}
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Login
</label>
<div className="relative">
<FiUser className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500" />
<input
type="text"
name="login"
value={formData.login}
onChange={handleChange}
required
className="w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="Enter your login"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Password
</label>
<div className="relative">
<FiLock className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500" />
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
required
className="w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="Enter your password"
/>
</div>
</div>
<button
type="submit"
disabled={isLoading}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg hover:bg-gray-800 dark:hover:bg-gray-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed font-medium"
>
{isLoading ? (
"Signing in..."
) : (
<>
<FiLogIn />
Sign In
</>
)}
</button>
</form>
{/* Footer */}
<div className="mt-6 text-center">
<p className="text-sm text-gray-600 dark:text-gray-400">
Don't have an account?{" "}
<Link
to="/register"
className="text-gray-900 dark:text-white hover:underline font-medium"
>
Sign up
</Link>
</p>
</div>
</div>
</div>
</div>
);
};
+203
View File
@@ -0,0 +1,203 @@
import React, { useState, useEffect } from "react";
import { useNavigate, Link } from "react-router-dom";
import { FiUser, FiLock, FiUserPlus, FiMail } from "react-icons/fi";
import { useAuthStore } from "@/modules/auth/store/useAuthStore";
export const RegisterPage: React.FC = () => {
const navigate = useNavigate();
const { register, isLoading, error, clearError, token } = useAuthStore();
const [formData, setFormData] = useState({
login: "",
password: "",
confirmPassword: "",
firstName: "",
lastName: "",
});
const [passwordError, setPasswordError] = useState<string | null>(null);
useEffect(() => {
if (token) {
navigate("/dashboard");
}
}, [token, navigate]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (formData.password !== formData.confirmPassword) {
setPasswordError("Passwords do not match");
return;
}
setPasswordError(null);
try {
await register({
login: formData.login,
password: formData.password,
firstName: formData.firstName,
lastName: formData.lastName,
});
navigate("/dashboard");
} catch (err) {
// Error is handled by store
}
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
if (error) clearError();
if (passwordError) setPasswordError(null);
};
return (
<div className="min-h-screen flex items-center justify-center bg-white dark:bg-black transition-colors duration-200">
<div className="w-full max-w-md px-8">
{/* Card */}
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg shadow-xl p-8 border border-gray-200 dark:border-gray-800">
{/* Header */}
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-2">
Create Account
</h1>
<p className="text-gray-600 dark:text-gray-400">
Sign up to get started
</p>
</div>
{/* Error Message */}
{error && (
<div className="mb-4 p-3 bg-red-100 dark:bg-red-900/20 border border-red-400 dark:border-red-800 rounded text-red-700 dark:text-red-400 text-sm">
{error}
</div>
)}
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
First Name
</label>
<input
type="text"
name="firstName"
value={formData.firstName}
onChange={handleChange}
required
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="John"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Last Name
</label>
<input
type="text"
name="lastName"
value={formData.lastName}
onChange={handleChange}
required
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="Doe"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Login
</label>
<div className="relative">
<FiUser className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500" />
<input
type="text"
name="login"
value={formData.login}
onChange={handleChange}
required
className="w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="Choose a login"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Password
</label>
<div className="relative">
<FiLock className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500" />
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
required
className="w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="Create a password"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Confirm Password
</label>
<div className="relative">
<FiLock className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500" />
<input
type="password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
required
className="w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-gray-500 dark:focus:ring-gray-400 transition-colors"
placeholder="Confirm your password"
/>
</div>
{passwordError && (
<p className="mt-1 text-sm text-red-600 dark:text-red-400">
{passwordError}
</p>
)}
</div>
<button
type="submit"
disabled={isLoading}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg hover:bg-gray-800 dark:hover:bg-gray-100 transition-colors disabled:opacity-50 disabled:cursor-not-allowed font-medium"
>
{isLoading ? (
"Creating account..."
) : (
<>
<FiUserPlus />
Sign Up
</>
)}
</button>
</form>
{/* Footer */}
<div className="mt-6 text-center">
<p className="text-sm text-gray-600 dark:text-gray-400">
Already have an account?{" "}
<Link
to="/auth"
className="text-gray-900 dark:text-white hover:underline font-medium"
>
Sign in
</Link>
</p>
</div>
</div>
</div>
</div>
);
};