inogen/app/components/auth/login-form.tsx

224 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from "react";
import { useAuth } from "~/contexts/auth-context";
import toast from "react-hot-toast";
import { Button } from "~/components/ui/button";
import {
TextField,
PasswordField,
CheckboxField,
FieldGroup,
} from "~/components/ui/form-field";
import { ErrorAlert, ConnectionError } from "~/components/ui/error-alert";
import { InogenLogo } from "~/components/ui/brand-logo";
import {
LoginLayout,
LoginContent,
LoginSidebar,
LoginHeader,
LoginBranding,
LoginFormContainer,
} from "./login-layout";
import { Loader2, User, Lock } from "lucide-react";
interface LoginFormProps {
onSuccess?: () => void;
}
interface FormData {
username: string;
password: string;
rememberMe: boolean;
}
interface ValidationErrors {
username?: string;
password?: string;
general?: string;
}
export function LoginForm({ onSuccess }: LoginFormProps) {
const [formData, setFormData] = useState<FormData>({
username: "",
password: "",
rememberMe: false,
});
const [errors, setErrors] = useState<ValidationErrors>({});
const [isConnectionError, setIsConnectionError] = useState(false);
const { login, isLoading } = useAuth();
const updateField = (field: keyof FormData, value: string | boolean) => {
setFormData((prev) => ({ ...prev, [field]: value }));
// Clear field-specific errors when user starts typing
if (errors[field as keyof ValidationErrors]) {
setErrors((prev) => ({ ...prev, [field]: undefined }));
}
};
const validateForm = (): ValidationErrors => {
const newErrors: ValidationErrors = {};
if (!formData.username.trim()) {
newErrors.username = "نام کاربری الزامی است";
} else if (formData.username.length < 3) {
newErrors.username = "نام کاربری باید حداقل ۳ کاراکتر باشد";
}
if (!formData.password) {
newErrors.password = "کلمه عبور الزامی است";
} else if (formData.password.length < 4) {
newErrors.password = "کلمه عبور باید حداقل ۴ کاراکتر باشد";
}
return newErrors;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Clear previous errors
setErrors({});
setIsConnectionError(false);
// Validate form
const validationErrors = validateForm();
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
const firstError = Object.values(validationErrors)[0];
toast.error(firstError);
return;
}
try {
const success = await login(formData.username, formData.password);
if (success) {
toast.success("ورود موفقیت‌آمیز بود!");
onSuccess?.();
} else {
const errorMessage = "نام کاربری یا رمز عبور اشتباه است";
setErrors({ general: errorMessage });
toast.error(errorMessage);
}
} catch (err: any) {
console.error("Login error:", err);
// Check if it's a connection error
if (err?.code === "NETWORK_ERROR" || err?.message?.includes("fetch")) {
setIsConnectionError(true);
} else {
const errorMessage = err?.message || "خطا در برقراری ارتباط با سرور";
setErrors({ general: errorMessage });
toast.error(errorMessage);
}
}
};
const handleRetry = () => {
setIsConnectionError(false);
setErrors({});
};
return (
<LoginLayout>
{/* Left Side - Login Form */}
<LoginContent>
<LoginHeader
title="ورود"
subtitle="داشبورد مدیریت فناوری و نوآوری"
description="لطفا نام کاربری و پسورد خود را در قسمت خواسته شده وارد فرمایید"
/>
<LoginFormContainer onSubmit={handleSubmit}>
<FieldGroup>
{/* Connection Error */}
{isConnectionError && <ConnectionError onRetry={handleRetry} />}
{/* General Error */}
{errors.general && (
<ErrorAlert
message={errors.general}
variant="error"
onRetry={() => setErrors({ general: undefined })}
dismissible
onDismiss={() => setErrors({ general: undefined })}
/>
)}
{/* Username Field */}
<TextField
id="username"
label=""
type="text"
value={formData.username}
onChange={(value) => updateField("username", value)}
error={errors.username}
placeholder="نام کاربری"
disabled={isLoading}
autoComplete="username"
required
leftIcon={<User className="h-4 w-4" />}
/>
{/* Password Field */}
<PasswordField
id="password"
label=""
value={formData.password}
onChange={(value) => updateField("password", value)}
error={errors.password}
placeholder="کلمه عبور"
disabled={isLoading}
autoComplete="current-password"
required
minLength={4}
/>
{/* Remember Me Checkbox */}
<div className="flex justify-end">
<CheckboxField
id="remember"
label="همیشه متصل بمان"
checked={formData.rememberMe}
onChange={(checked) => updateField("rememberMe", checked)}
disabled={isLoading}
size="md"
/>
</div>
{/* Login Button */}
<Button
type="submit"
disabled={isLoading || isConnectionError}
size="lg"
className="w-full font-persian bg-[var(--color-login-primary)] hover:bg-[var(--color-login-primary)]/90 text-slate-800 text-base font-semibold"
>
{isLoading ? (
<>
<Loader2 className="h-4 w-4 animate-spin ml-2" />
در حال ورود...
</>
) : (
"ورود"
)}
</Button>
{/* Additional Links */}
</FieldGroup>
</LoginFormContainer>
</LoginContent>
{/* Right Side - Branding */}
<LoginSidebar>
<LoginBranding
brandName="پتروشیمی بندر امام"
engSub="Inception by Fara"
companyName="توسعه‌یافته توسط شرکت رهپویان دانش و فناوری فرا"
logo={<img src="/brand2.svg"/>}
/>
</LoginSidebar>
</LoginLayout>
);
}