74 lines
1.7 KiB
TypeScript
74 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import React, { ChangeEvent } from 'react';
|
|
|
|
interface FormFieldProps {
|
|
label: string;
|
|
name: string;
|
|
type?: 'text' | 'email' | 'password' | 'tel' | 'number' | 'date';
|
|
value: string | number;
|
|
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
|
onBlur?: (e: ChangeEvent<HTMLInputElement>) => void;
|
|
error?: string;
|
|
touched?: boolean;
|
|
placeholder?: string;
|
|
required?: boolean;
|
|
disabled?: boolean;
|
|
className?: string;
|
|
autoComplete?: string;
|
|
}
|
|
|
|
/**
|
|
* Composant de champ de formulaire réutilisable
|
|
*/
|
|
export default function FormField({
|
|
label,
|
|
name,
|
|
type = 'text',
|
|
value,
|
|
onChange,
|
|
onBlur,
|
|
error,
|
|
touched,
|
|
placeholder,
|
|
required = false,
|
|
disabled = false,
|
|
className = '',
|
|
autoComplete,
|
|
}: FormFieldProps) {
|
|
const showError = touched && error;
|
|
|
|
return (
|
|
<div className={`mb-4 ${className}`}>
|
|
<label
|
|
htmlFor={name}
|
|
className="block text-sm font-medium text-gray-700 mb-2"
|
|
>
|
|
{label}
|
|
{required && <span className="text-red-500 ml-1">*</span>}
|
|
</label>
|
|
<input
|
|
id={name}
|
|
name={name}
|
|
type={type}
|
|
value={value}
|
|
onChange={onChange}
|
|
onBlur={onBlur}
|
|
placeholder={placeholder}
|
|
disabled={disabled}
|
|
required={required}
|
|
autoComplete={autoComplete}
|
|
className={`
|
|
w-full px-4 py-2 border rounded-lg
|
|
focus:outline-none focus:ring-2 focus:ring-primary-500
|
|
disabled:bg-gray-100 disabled:cursor-not-allowed
|
|
${showError ? 'border-red-500' : 'border-gray-300'}
|
|
`}
|
|
/>
|
|
{showError && (
|
|
<p className="mt-1 text-sm text-red-500">{error}</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|