import React from "react";
import { cn } from "~/lib/utils";
import { Eye, EyeOff, AlertCircle, CheckCircle2 } from "lucide-react";
import { Input } from "./input";
import { Label } from "./label";
interface BaseFieldProps {
label?: string;
error?: string;
helper?: string;
required?: boolean;
className?: string;
containerClassName?: string;
}
interface TextFieldProps extends BaseFieldProps {
id: string;
type?: "text" | "email" | "tel" | "url";
value: string;
onChange: (value: string) => void;
placeholder?: string;
disabled?: boolean;
autoComplete?: string;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
maxLength?: number;
minLength?: number;
}
export function TextField({
id,
label,
type = "text",
value,
onChange,
placeholder,
error,
helper,
required,
disabled,
autoComplete,
leftIcon,
rightIcon,
maxLength,
minLength,
className,
containerClassName,
}: TextFieldProps) {
const hasError = !!error;
const hasSuccess = !hasError && value.length > 0;
return (
{label && (
)}
{leftIcon && (
{leftIcon}
)}
onChange(e.target.value)}
placeholder={placeholder}
disabled={disabled}
autoComplete={autoComplete}
maxLength={maxLength}
minLength={minLength}
className={cn(
"w-full h-12 px-4 font-persian text-right transition-all duration-200",
leftIcon && "pr-10",
(rightIcon || hasError || hasSuccess) && "pl-10",
hasError &&
"border-destructive focus:border-destructive focus:ring-destructive/20",
hasSuccess &&
"border-green-500 focus:border-green-500 focus:ring-green-500/20",
className,
)}
/>
{(rightIcon || hasError || hasSuccess) && (
{hasError ? (
) : hasSuccess ? (
) : (
rightIcon && (
{rightIcon}
)
)}
)}
{error && (
{error}
)}
{helper && !error && (
{helper}
)}
{maxLength && (
{value.length}/{maxLength}
)}
);
}
interface PasswordFieldProps extends BaseFieldProps {
id: string;
value: string;
onChange: (value: string) => void;
placeholder?: string;
disabled?: boolean;
autoComplete?: string;
showStrength?: boolean;
minLength?: number;
}
export function PasswordField({
id,
label,
value,
onChange,
placeholder,
error,
helper,
required,
disabled,
autoComplete = "current-password",
showStrength = false,
minLength,
className,
containerClassName,
}: PasswordFieldProps) {
const [showPassword, setShowPassword] = React.useState(false);
const hasError = !!error;
const getPasswordStrength = (
password: string,
): {
score: number;
text: string;
color: string;
} => {
if (!password) return { score: 0, text: "", color: "" };
let score = 0;
if (password.length >= 8) score++;
if (/[a-z]/.test(password)) score++;
if (/[A-Z]/.test(password)) score++;
if (/[0-9]/.test(password)) score++;
if (/[^a-zA-Z0-9]/.test(password)) score++;
const strength = [
{ text: "بسیار ضعیف", color: "text-red-500" },
{ text: "ضعیف", color: "text-orange-500" },
{ text: "متوسط", color: "text-yellow-500" },
{ text: "قوی", color: "text-blue-500" },
{ text: "بسیار قوی", color: "text-green-500" },
];
return {
score,
text: strength[Math.min(score, 4)].text,
color: strength[Math.min(score, 4)].color,
};
};
const strength = showStrength ? getPasswordStrength(value) : null;
return (
{label && (
)}
onChange(e.target.value)}
placeholder={placeholder}
disabled={disabled}
autoComplete={autoComplete}
minLength={minLength}
className={cn(
"w-full h-12 px-4 pl-10 font-persian text-right transition-all duration-200",
hasError &&
"border-destructive focus:border-destructive focus:ring-destructive/20",
className,
)}
/>
{showStrength && value && (
قدرت رمز عبور:
{strength?.text}
{[1, 2, 3, 4, 5].map((step) => (
))}
)}
{error && (
{error}
)}
{helper && !error && (
{helper}
)}
);
}
interface CheckboxFieldProps extends BaseFieldProps {
id: string;
checked: boolean;
onChange: (checked: boolean) => void;
disabled?: boolean;
size?: "sm" | "md" | "lg";
}
export function CheckboxField({
id,
label,
checked,
onChange,
error,
helper,
required,
disabled,
size = "md",
className,
containerClassName,
}: CheckboxFieldProps) {
const sizes = {
sm: "w-3 h-3",
md: "w-4 h-4",
lg: "w-5 h-5",
};
return (
onChange(e.target.checked)}
disabled={disabled}
className={cn(
sizes[size],
"text-[var(--color-login-primary)] bg-background border-input rounded focus:ring-[var(--color-login-primary)] focus:ring-2 accent-[var(--color-login-primary)] transition-all duration-200",
disabled && "opacity-50 cursor-not-allowed",
error && "border-destructive focus:ring-destructive",
className,
)}
/>
{label && (
)}
{error && (
{error}
)}
{helper && !error && (
{helper}
)}
);
}
interface FieldGroupProps {
children: React.ReactNode;
className?: string;
}
export function FieldGroup({ children, className }: FieldGroupProps) {
return {children}
;
}
interface FormActionsProps {
children: React.ReactNode;
className?: string;
}
export function FormActions({ children, className }: FormActionsProps) {
return (
{children}
);
}