From f25b438324f390c192d804eda786188aefaeb830 Mon Sep 17 00:00:00 2001 From: iasssy Date: Mon, 4 Nov 2024 00:26:10 -0500 Subject: [PATCH 1/2] added price and quantity --- src/components/Dashboard/ManageItems.tsx | 168 ++++++++++++++++++----- 1 file changed, 134 insertions(+), 34 deletions(-) diff --git a/src/components/Dashboard/ManageItems.tsx b/src/components/Dashboard/ManageItems.tsx index 1b6b967..0706e12 100644 --- a/src/components/Dashboard/ManageItems.tsx +++ b/src/components/Dashboard/ManageItems.tsx @@ -25,17 +25,28 @@ export default function ManageItems() { name: string; description: string; image_url: string; + quantity: number; + price: number; } const [items, setItems] = useState([]); const { isLoggedIn, authToken } = useLoginStore.getState(); const apiUrl = import.meta.env.VITE_API_URL; const schema = yup.object().shape({ name: yup.string().required('Store name is required'), + price: yup + .number() + .required('Price is required') + .positive('Price must be positive'), }); const [formValues, setFormValues] = useState({ name: '', description: '', + image_url: '', + quantity: 0, + price: 0, }); + + const [imageFile, setImageFile] = useState(null); const [success, setSuccess] = useState(null); const [error, setError] = useState<{ [key: string]: string | null }>({}); useEffect(() => { @@ -73,11 +84,40 @@ export default function ManageItems() { event.preventDefault(); try { await schema.validate(formValues, { abortEarly: false }); - await axios.post(`${apiUrl}/api/stores/items`, formValues, { - headers: { - Authorization: `Bearer ${authToken}`, + const formData = new FormData(); + formData.append('name', formValues.name); + formData.append('description', formValues.description); + formData.append('quantity', formValues.quantity.toString()); + + if (imageFile) { + formData.append('file', imageFile); + } + const uploadResponse = imageFile + ? await axios.post(`${apiUrl}/api/files/upload`, formData, { + headers: { + Authorization: `Bearer ${authToken}`, + 'Content-Type': 'multipart/form-data', + }, + }) + : null; + + const imageUrl = uploadResponse ? uploadResponse.data.url : null; + + await axios.post( + `${apiUrl}/api/stores/items`, + { + name: formValues.name, + description: formValues.description, + image_url: imageUrl, + price: formValues.price, + quantity: formValues.quantity, }, - }); + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); setSuccess('Item created successfully! Close the window'); setError({}); @@ -97,29 +137,36 @@ export default function ManageItems() { setError({ general: messageError }); } }; - const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; - setFormValues((prev) => ({ ...prev, [name]: value })); - setError((prev) => ({ ...prev, [name]: null })); + + setFormValues((prev) => ({ + ...prev, + [name]: (name === 'price' || name === 'quantity') && value === '' ? 0 : value, + })); + + setError((prev) => ({ + ...prev, + [name]: null, + })); }; return ( Manage Items {isLoggedIn ? ( <> - + + + + + + + + + - From 14f7d97864576ab18c8c1b335d691b4b50027c42 Mon Sep 17 00:00:00 2001 From: iasssy Date: Mon, 4 Nov 2024 02:08:19 -0500 Subject: [PATCH 2/2] updated manage items with the same form to create and edit --- src/components/Dashboard/ManageItems.tsx | 203 ++++++++++++++++++----- 1 file changed, 165 insertions(+), 38 deletions(-) diff --git a/src/components/Dashboard/ManageItems.tsx b/src/components/Dashboard/ManageItems.tsx index 0706e12..5ffd0db 100644 --- a/src/components/Dashboard/ManageItems.tsx +++ b/src/components/Dashboard/ManageItems.tsx @@ -49,8 +49,12 @@ export default function ManageItems() { const [imageFile, setImageFile] = useState(null); const [success, setSuccess] = useState(null); const [error, setError] = useState<{ [key: string]: string | null }>({}); - useEffect(() => { - const fetchItemsData = async () => { + const [open, setOpen] = useState(false); + const [isEditMode, setIsEditMode] = useState(false); + const [itemToEdit, setItemToEdit] = useState(null); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [itemToDelete, setItemToDelete] = useState(null); +const fetchItemsData = async () => { try { const response = await axios.get(`${apiUrl}/api/stores/items`, { headers: { @@ -64,21 +68,87 @@ export default function ManageItems() { console.error('Error fetching store data', err); } }; + useEffect(() => { + fetchItemsData(); }, [apiUrl, authToken]); - - const [open, setOpen] = useState(false); const openCreateItemDialog = () => { - setSuccess(''); - setError({}); + resetForm(); setOpen(true); }; const closeCreateItemDialog = () => { + resetForm(); setOpen(false); }; - const handleEdit = () => {}; // TODO: handleEdit - const handleDelete = () => {}; // TODO: handleDelete + const handleEdit = (item: Item) => { + setItemToEdit(item); + setFormValues({ + name: item.name, + description: item.description, + image_url: item.image_url, + quantity: item.quantity, + price: item.price, + }); + setIsEditMode(true); + setOpen(true); + }; + + + const openDeleteDialog = (item: Item) => { + setItemToDelete(item); + setDeleteDialogOpen(true); + }; + + const closeDeleteDialog = () => { + setDeleteDialogOpen(false); + setItemToDelete(null); + }; + + const handleDelete = async () => { + if (itemToDelete) { + try { + await axios.delete( + `${apiUrl}/api/stores/items/${itemToDelete.item_id}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); + setItems((prevItems) => + prevItems.filter( + (item) => item.item_id !== itemToDelete.item_id + ) + ); + setSuccess('Item deleted successfully!'); + } catch (err) { + console.error('Error deleting item', err); + setError({ + general: 'An error occurred while deleting the item.', + }); + } finally { + closeDeleteDialog(); + } + } + }; + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + + setFormValues((prev) => ({ + ...prev, + [name]: + (name === 'price' || name === 'quantity') && value === '' + ? 0 + : value, + })); + + setError((prev) => ({ + ...prev, + [name]: null, + })); + }; const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); @@ -92,6 +162,7 @@ export default function ManageItems() { if (imageFile) { formData.append('file', imageFile); } + const uploadResponse = imageFile ? await axios.post(`${apiUrl}/api/files/upload`, formData, { headers: { @@ -103,26 +174,55 @@ export default function ManageItems() { const imageUrl = uploadResponse ? uploadResponse.data.url : null; - await axios.post( - `${apiUrl}/api/stores/items`, - { - name: formValues.name, - description: formValues.description, + if (isEditMode && itemToEdit) { + // Update existing item + await axios.put( + `${apiUrl}/api/stores/items/${itemToEdit.item_id}`, + { + name: formValues.name, + description: formValues.description, + image_url: imageUrl, + price: formValues.price, + quantity: formValues.quantity, + }, + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); + + setItems((prevItems) => + prevItems.map((item) => + item.item_id === itemToEdit.item_id + ? { ...item, ...formValues, image_url: imageUrl || item.image_url} + : item + ) + ); + + setSuccess('Item updated successfully!'); + } else { + // Create new item + await axios.post( + `${apiUrl}/api/stores/items`, + { + ...formValues, image_url: imageUrl, - price: formValues.price, - quantity: formValues.quantity, - }, - { - headers: { - Authorization: `Bearer ${authToken}`, }, - } - ); + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); + resetForm(); + setSuccess('Item created successfully! Close the window'); + fetchItemsData(); + } - setSuccess('Item created successfully! Close the window'); setError({}); } catch (err) { - let messageError = 'An error occurred while creating an item.'; + let messageError = 'An error occurred while saving the item.'; if (axios.isAxiosError(err)) { messageError = err.response?.data?.message || 'An error occurred.'; @@ -135,20 +235,23 @@ export default function ManageItems() { return; } setError({ general: messageError }); + } finally { + closeCreateItemDialog(); + setIsEditMode(false); + setItemToEdit(null); } }; - const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - - setFormValues((prev) => ({ - ...prev, - [name]: (name === 'price' || name === 'quantity') && value === '' ? 0 : value, - })); - - setError((prev) => ({ - ...prev, - [name]: null, - })); + const resetForm = () => { + setFormValues({ + name: '', + description: '', + image_url: '', + quantity: 0, + price: 0, + }); + setImageFile(null); + setSuccess(null); + setError({}); }; return ( @@ -167,6 +270,7 @@ export default function ManageItems() { @@ -233,7 +344,9 @@ export default function ManageItems() { onSubmit: handleSubmit, }} > - Create an item + + {isEditMode ? 'Edit item' : 'Create an item'} + {error.general && ( @@ -335,6 +448,20 @@ export default function ManageItems() { + + Delete Item + + + Are you sure you want to delete this item? + + + + + + + ) : ( 'Please log in'