Add frontend input validation for User username and Product name

This commit is contained in:
continuist 2025-06-24 23:21:16 -04:00
parent 9de4f0b64c
commit 9956c22cce
2 changed files with 99 additions and 10 deletions

View file

@ -40,6 +40,10 @@ export default function ProductsPage() {
name: '', name: '',
description: '', description: '',
}); });
const [errors, setErrors] = useState({
name: '',
description: '',
});
useEffect(() => { useEffect(() => {
loadProducts(); loadProducts();
@ -54,8 +58,29 @@ export default function ProductsPage() {
} }
}; };
const validateForm = () => {
const newErrors = {
name: '',
description: '',
};
// Product name cannot be empty
if (!formData.name.trim()) {
newErrors.name = 'Product name is required';
}
// Description can be empty, no validation needed
setErrors(newErrors);
return !newErrors.name;
};
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (!validateForm()) {
return;
}
try { try {
if (editingProduct) { if (editingProduct) {
await productApi.update(editingProduct.id, formData); await productApi.update(editingProduct.id, formData);
@ -65,6 +90,7 @@ export default function ProductsPage() {
setIsDialogOpen(false); setIsDialogOpen(false);
setEditingProduct(null); setEditingProduct(null);
setFormData({ name: '', description: '' }); setFormData({ name: '', description: '' });
setErrors({ name: '', description: '' });
loadProducts(); loadProducts();
} catch (error) { } catch (error) {
console.error('Error saving product:', error); console.error('Error saving product:', error);
@ -77,6 +103,7 @@ export default function ProductsPage() {
name: product.name, name: product.name,
description: product.description, description: product.description,
}); });
setErrors({ name: '', description: '' });
setIsDialogOpen(true); setIsDialogOpen(true);
}; };
@ -91,6 +118,14 @@ export default function ProductsPage() {
} }
}; };
const handleInputChange = (field: 'name' | 'description', value: string) => {
setFormData({ ...formData, [field]: value });
// Clear error when user starts typing
if (errors[field]) {
setErrors({ ...errors, [field]: '' });
}
};
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
@ -100,6 +135,7 @@ export default function ProductsPage() {
<Button onClick={() => { <Button onClick={() => {
setEditingProduct(null); setEditingProduct(null);
setFormData({ name: '', description: '' }); setFormData({ name: '', description: '' });
setErrors({ name: '', description: '' });
}}> }}>
Add Product Add Product
</Button> </Button>
@ -110,21 +146,23 @@ export default function ProductsPage() {
</DialogHeader> </DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="name">Name</Label> <Label htmlFor="name">Name *</Label>
<Input <Input
id="name" id="name"
value={formData.name} value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })} onChange={(e) => handleInputChange('name', e.target.value)}
required className={errors.name ? 'border-red-500' : ''}
/> />
{errors.name && (
<p className="text-red-500 text-sm">{errors.name}</p>
)}
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="description">Description</Label> <Label htmlFor="description">Description</Label>
<Input <Input
id="description" id="description"
value={formData.description} value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })} onChange={(e) => handleInputChange('description', e.target.value)}
required
/> />
</div> </div>
<Button type="submit">{editingProduct ? 'Update' : 'Create'}</Button> <Button type="submit">{editingProduct ? 'Update' : 'Create'}</Button>

View file

@ -40,6 +40,10 @@ export default function UsersPage() {
username: '', username: '',
email: '', email: '',
}); });
const [errors, setErrors] = useState({
username: '',
email: '',
});
useEffect(() => { useEffect(() => {
loadUsers(); loadUsers();
@ -54,8 +58,38 @@ export default function UsersPage() {
} }
}; };
const validateForm = () => {
const newErrors = {
username: '',
email: '',
};
// Username cannot be empty
if (!formData.username.trim()) {
newErrors.username = 'Username is required';
}
// Email can be empty, but if provided, should be valid
if (formData.email.trim() && !isValidEmail(formData.email)) {
newErrors.email = 'Please enter a valid email address';
}
setErrors(newErrors);
return !newErrors.username && !newErrors.email;
};
const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (!validateForm()) {
return;
}
try { try {
if (editingUser) { if (editingUser) {
await userApi.update(editingUser.id, formData); await userApi.update(editingUser.id, formData);
@ -65,6 +99,7 @@ export default function UsersPage() {
setIsDialogOpen(false); setIsDialogOpen(false);
setEditingUser(null); setEditingUser(null);
setFormData({ username: '', email: '' }); setFormData({ username: '', email: '' });
setErrors({ username: '', email: '' });
loadUsers(); loadUsers();
} catch (error) { } catch (error) {
console.error('Error saving user:', error); console.error('Error saving user:', error);
@ -74,6 +109,7 @@ export default function UsersPage() {
const handleEdit = (user: User) => { const handleEdit = (user: User) => {
setEditingUser(user); setEditingUser(user);
setFormData({ username: user.username, email: user.email }); setFormData({ username: user.username, email: user.email });
setErrors({ username: '', email: '' });
setIsDialogOpen(true); setIsDialogOpen(true);
}; };
@ -88,6 +124,14 @@ export default function UsersPage() {
} }
}; };
const handleInputChange = (field: 'username' | 'email', value: string) => {
setFormData({ ...formData, [field]: value });
// Clear error when user starts typing
if (errors[field]) {
setErrors({ ...errors, [field]: '' });
}
};
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
@ -97,6 +141,7 @@ export default function UsersPage() {
<Button onClick={() => { <Button onClick={() => {
setEditingUser(null); setEditingUser(null);
setFormData({ username: '', email: '' }); setFormData({ username: '', email: '' });
setErrors({ username: '', email: '' });
}}> }}>
Add User Add User
</Button> </Button>
@ -107,13 +152,16 @@ export default function UsersPage() {
</DialogHeader> </DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="username">Username</Label> <Label htmlFor="username">Username *</Label>
<Input <Input
id="username" id="username"
value={formData.username} value={formData.username}
onChange={(e) => setFormData({ ...formData, username: e.target.value })} onChange={(e) => handleInputChange('username', e.target.value)}
required className={errors.username ? 'border-red-500' : ''}
/> />
{errors.username && (
<p className="text-red-500 text-sm">{errors.username}</p>
)}
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="email">Email</Label> <Label htmlFor="email">Email</Label>
@ -121,9 +169,12 @@ export default function UsersPage() {
id="email" id="email"
type="email" type="email"
value={formData.email} value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })} onChange={(e) => handleInputChange('email', e.target.value)}
required className={errors.email ? 'border-red-500' : ''}
/> />
{errors.email && (
<p className="text-red-500 text-sm">{errors.email}</p>
)}
</div> </div>
<Button type="submit">{editingUser ? 'Update' : 'Create'}</Button> <Button type="submit">{editingUser ? 'Update' : 'Create'}</Button>
</form> </form>