diff --git a/backend/handlers/item_handlers.go b/backend/handlers/item_handlers.go index 2dc9317..e950181 100644 --- a/backend/handlers/item_handlers.go +++ b/backend/handlers/item_handlers.go @@ -73,6 +73,8 @@ func UpdateItem(c *gin.Context) { UnitType: input.UnitType, City: input.City, Price: input.Price, + Category: input.Category, + Stock: input.Stock, }) c.JSON(http.StatusOK, item) @@ -156,14 +158,14 @@ func UploadItemAvatar(c *gin.Context) { resized := imaging.Resize(img, 1200, 0, imaging.Lanczos) uniqueName := uuid.New().String() + ".jpg" - dstPath := filepath.Join("./uploads/items", uniqueName) + dstPath := filepath.Join("./uploads/items/", uniqueName) if err := imaging.Save(resized, dstPath, imaging.JPEGQuality(82)); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Не удалось сохранить фотографию"}) return } - item.AvatarURL = "/uploads/items" + uniqueName + item.AvatarURL = uniqueName database.DB.Save(&item) c.JSON(http.StatusOK, gin.H{"avatar_url": item.AvatarURL}) diff --git a/backend/main.go b/backend/main.go index d6f7d0d..3aefb7d 100644 --- a/backend/main.go +++ b/backend/main.go @@ -41,7 +41,7 @@ func main() { api.POST("/login", handlers.Login) protected := api.Group("/") api.GET("/items/:id", handlers.GetItem) - api.GET("/items/", handlers.GetAllItems) + api.GET("/items", handlers.GetAllItems) api.GET("/getCategories", handlers.GetCategories) api.POST("/register", handlers.Register) protected.Use(middleware.AuthRequired()) @@ -66,6 +66,7 @@ func main() { admin.POST("/register", handlers.RegisterAdmin) admin.GET("/orders", handlers.GetAllOrders) admin.PATCH("/orders/:id", handlers.UpdateOrderStatus) + admin.PATCH("/items/:id/avatar", handlers.UploadItemAvatar) } } diff --git a/backend/uploads/items/748f6329-3806-4dd0-82ec-dabfa7445552.jpg b/backend/uploads/items/748f6329-3806-4dd0-82ec-dabfa7445552.jpg new file mode 100644 index 0000000..18c7366 Binary files /dev/null and b/backend/uploads/items/748f6329-3806-4dd0-82ec-dabfa7445552.jpg differ diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 7e06556..04a084e 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -42,11 +42,19 @@ export const getAllCategories = () => axios.get(`${API_URL}/getCategories`); export const getCart = () => axios.get(`${API_URL}/cart/`); export const addToCart = (data) => axios.post(`${API_URL}/cart/`, data); export const updateCartItem = (id, data) => - axios.post(`${API_URL}/cart/${id}`, data); + axios.patch(`${API_URL}/cart/${id}`, data); export const removeFromCart = (id) => axios.delete(`${API_URL}/cart/${id}`); export const createOrder = (data) => axios.post(`${API_URL}/orders/`, data); export const getUserOrders = () => axios.get(`${API_URL}/orders`); export const getOrder = (id) => axios.get(`${API_URL}/orders/${id}`); -export const updateProfile = () => axios.patch(`${API_URL}/profile`); +export const updateProfile = (data) => axios.patch(`${API_URL}/profile`); export const getUserInfo = () => axios.get(`${API_URL}/profile`); + +export const uploadItemAvatar = (id, file) => { + const formData = new FormData(); + formData.append("avatar", file); + return axios.patch(`${API_URL}/admin/items/${id}/avatar`, formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); +}; diff --git a/frontend/src/components/AdminItems.jsx b/frontend/src/components/AdminItems.jsx index fcf463d..cfe078f 100644 --- a/frontend/src/components/AdminItems.jsx +++ b/frontend/src/components/AdminItems.jsx @@ -1,9 +1,152 @@ import { useState, useEffect } from "react"; -import { getAllItems, deleteItem } from "../api/index"; +import { + getAllItems, + deleteItem, + addItem, + updateItem, + uploadItemAvatar, +} from "../api/index"; + +function ItemFormModal({ item, onClose, onSaved }) { + const isEdit = !!item; + const [form, setForm] = useState({ + name: item?.name || "", + category: item?.category || "", + city: item?.city || "", + price: item?.price || "", + stock: item?.stock || "", + unit: item?.unit || "кг", + unit_type: item?.unit_type || "weight", + }); + const [file, setFile] = useState(null); + const [saving, setSaving] = useState(false); + + const handleChange = (field) => (e) => + setForm({ ...form, [field]: e.target.value }); + + const handleSubmit = async () => { + setSaving(true); + try { + // числовые поля привести к числам + const payload = { + ...form, + price: Number(form.price), + stock: Number(form.stock), + }; + + let itemId; + if (isEdit) { + await updateItem(item.id, payload); + itemId = item.id; + } else { + const res = await addItem(payload); + itemId = res.data.id; + } + + // если выбран файл — загрузить картинку + if (file) { + await uploadItemAvatar(itemId, file); + } + + onSaved(); + } catch { + alert("Не удалось сохранить товар"); + } finally { + setSaving(false); + } + }; + + return ( +
Загрузка...
; return (