tahamajs/IE / Projects /front /src /components /genui /FormComponent.tsx
tahamajs's picture
download
raw
3.5 kB
// src/components/genui/FormComponent.tsx
import { useState } from "react";
import { Send, Loader2 } from "lucide-react";
interface FormField {
id: string;
label: string;
type: "text" | "email" | "textarea" | "select";
options?: string[];
required?: boolean;
}
interface FormComponentProps {
title?: string;
fields?: FormField[];
onSubmit?: (data: Record<string, any>) => void;
submitLabel?: string;
}
const DEFAULT_FIELDS: FormField[] = [
{ id: "name", label: "Name", type: "text", required: true },
{ id: "email", label: "Email", type: "email", required: true },
{ id: "message", label: "Message", type: "textarea" },
];
export function FormComponent({
title = "Contact Form",
fields = DEFAULT_FIELDS,
onSubmit,
submitLabel = "Submit",
}: FormComponentProps) {
const [values, setValues] = useState<Record<string, any>>({});
const [submitting, setSubmitting] = useState(false);
const handleChange = (id: string, value: any) => {
setValues((prev) => ({ ...prev, [id]: value }));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSubmitting(true);
try {
await onSubmit?.(values);
} finally {
setSubmitting(false);
}
};
return (
<div className="bg-white dark:bg-gray-800 rounded-xl p-6 shadow">
<h3 className="text-lg font-semibold mb-4">{title}</h3>
<form onSubmit={handleSubmit} className="space-y-4">
{fields.map((field) => (
<div key={field.id}>
<label htmlFor={field.id} className="block text-sm font-medium mb-1">
{field.label} {field.required && <span className="text-red-500">*</span>}
</label>
{field.type === "textarea" ? (
<textarea
id={field.id}
value={values[field.id] || ""}
onChange={(e) => handleChange(field.id, e.target.value)}
className="input w-full"
rows={3}
title={field.label}
placeholder={`Enter ${field.label.toLowerCase()}`}
/>
) : field.type === "select" ? (
<select
id={field.id}
value={values[field.id] || ""}
onChange={(e) => handleChange(field.id, e.target.value)}
className="input w-full"
title={field.label}
>
<option value="">Select...</option>
{field.options?.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
) : (
<input
type={field.type}
id={field.id}
value={values[field.id] || ""}
onChange={(e) => handleChange(field.id, e.target.value)}
className="input w-full"
title={field.label}
placeholder={`Enter ${field.label.toLowerCase()}`}
/>
)}
</div>
))}
<button
type="submit"
disabled={submitting}
className="btn btn-primary w-full gap-1"
title="Submit form"
>
{submitting ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<Send className="w-4 h-4" />
)}
{submitting ? "Submitting..." : submitLabel}
</button>
</form>
</div>
);
}

Xet Storage Details

Size:
3.5 kB
·
Xet hash:
b6faf21f0048be867f27a1f0d1936532903d097b52e14fb26a6efbc16d450f03

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.