The product management system provides full CRUD operations through the AdminContext and modal-based forms. All operations interact with a MockAPI backend.
API Configuration
The admin panel connects to MockAPI for product data:
const apiUrl = "https://681cdce3f74de1d219ae0bdb.mockapi.io/tiendatobe/productos"
Reference: /workspace/source/src/context/AdminContext.jsx:12
Product Data Structure
Products contain the following fields:
Auto-generated product identifier
Product price (must be greater than 0)
Product description (minimum 10 characters)
Adding Products
Click the “Abrir panel agregar producto” button to open the FormularioProducto modal:
< button className = "btn-inicio" onClick = { () => setOpen ( true ) } >
Abrir panel agregar producto
</ button >
Reference: /workspace/source/src/layout/Admin.jsx:61
The add form includes validation rules:
const validarFormulario = () => {
const nuevosErrores = {};
if ( ! producto . nombre . trim ())
nuevosErrores . nombre = 'El nombre es obligatorio.' ;
if ( ! producto . precio || producto . precio <= 0 )
nuevosErrores . precio = 'El precio debe ser mayor a 0.' ;
if ( ! producto . descripcion . trim () || producto . descripcion . length < 10 )
nuevosErrores . descripcion = 'La descripción debe tener al menos 10 caracteres.' ;
setErrores ( nuevosErrores );
return Object . keys ( nuevosErrores ). length === 0 ;
};
Reference: /workspace/source/src/components/FormularioProducto.jsx:17-25
API Call: POST Request
When the form is submitted, the agregarProducto function sends a POST request:
const agregarProducto = async ( producto ) => {
try {
const respuesta = await fetch ( apiUrl , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json'
},
body: JSON . stringify ( producto )
})
if ( ! respuesta . ok ) {
throw new Error ( 'Error al agregar producto' )
}
const data = await respuesta . json ()
Swal . fire ({
title: "Realizado!" ,
text: "Producto agregado correctamente!" ,
icon: "success"
});
cargarProductos ()
} catch ( error ) {
console . log ( error . message );
}
}
Reference: /workspace/source/src/context/AdminContext.jsx:30-54
After adding a product, cargarProductos() is called to refresh the product list.
Editing Products
Click the “Editar” button on any product card:
< button className = "editButton" onClick = { () => {
setOpenEditor ( true )
setSeleccionado ( product )
} } >
Editar
</ button >
Reference: /workspace/source/src/layout/Admin.jsx:50-53
This opens the FormularioEdicion modal with the selected product data pre-filled.
The edit form (FormularioEdicion) includes all product fields:
ID (read-only)
Nombre (text input)
Precio (number input, min: 0)
Stock (number input)
Imagen (text input for URL)
Categoría (text input)
Descripción (textarea)
Reference: /workspace/source/src/components/FormularioEdicion.jsx:35-124
API Call: PUT Request
The actualizarProducto function sends a PUT request:
const actualizarProducto = async ( producto ) => {
try {
const respuesta = await fetch ( ` ${ apiUrl } / ${ producto . id } ` , {
method: 'PUT' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( producto ),
});
if ( ! respuesta . ok ) throw Error ( 'Error al actualizar el producto' );
const data = await respuesta . json ();
Swal . fire ({
title: "Realizado!" ,
text: "Producto actualizado correctamente!" ,
icon: "success"
});
setOpenEditor ( false );
setSeleccionado ( null );
cargarProductos ();
} catch ( error ) {
console . log ( error . message );
}
};
Reference: /workspace/source/src/context/AdminContext.jsx:101-126
Deleting Products
Triggering Delete
Click the “Eliminar” button on any product card:
< button className = "deleteButton" onClick = { () => eliminarProducto ( product . id ) } >
Eliminar
</ button >
Reference: /workspace/source/src/layout/Admin.jsx:54
Confirmation Dialog
Before deleting, a SweetAlert2 confirmation dialog appears:
const result = await Swal . fire ({
title: '¿Estás seguro de eliminar el producto?' ,
icon: 'warning' ,
showCancelButton: true ,
confirmButtonText: 'Sí, eliminar' ,
cancelButtonText: 'Cancelar' ,
});
Reference: /workspace/source/src/context/AdminContext.jsx:70-76
API Call: DELETE Request
If confirmed, a DELETE request is sent:
if ( result . isConfirmed ) {
try {
const respuesta = await fetch (
`https://681cdce3f74de1d219ae0bdb.mockapi.io/tiendatobe/productos/ ${ id } ` ,
{
method: 'DELETE' ,
}
);
if ( ! respuesta . ok ) throw new Error ( 'Error al eliminar' );
Swal . fire ({
title: "Realizado!" ,
text: "Producto eliminado correctamente!" ,
icon: "success" ,
});
cargarProductos ();
} catch ( error ) {
Swal . fire ({
title: "Error!" ,
text: "Hubo un problema al eliminar el producto!" ,
icon: "error"
});
}
}
Reference: /workspace/source/src/context/AdminContext.jsx:78-99
Loading Products
Products are loaded automatically when the AdminContext mounts:
useEffect (() => {
fetch ( apiUrl )
. then (( response ) => response . json ())
. then (( data ) => {
setTimeout (() => {
setProductos ( data );
setLoading ( false );
}, 2000 );
})
. catch (( error ) => {
console . error ( "Error fetching data:" , error );
setError ( true );
setLoading ( false );
});
}, []);
Reference: /workspace/source/src/context/AdminContext.jsx:14-28
A 2-second delay is added to simulate loading time and show the loading state.
Reload Function
After any CRUD operation, products are reloaded:
const cargarProductos = async () => {
try {
const res = await fetch ( apiUrl )
const data = await res . json ()
setProductos ( data )
} catch ( error ) {
console . log ( 'Error al cargar productos ' , error )
}
}
Reference: /workspace/source/src/context/AdminContext.jsx:56-64
User Feedback
All operations use SweetAlert2 for user feedback:
Success Shown after successful add, edit, or delete
Error Shown when operations fail
Warning Shown before delete confirmation