Add frontend input validation for User username and Product name
This commit is contained in:
parent
9de4f0b64c
commit
9956c22cce
2 changed files with 99 additions and 10 deletions
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Reference in a new issue