From d2578b206acb37ac87117e24077876624725f896 Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Thu, 19 Feb 2026 17:28:51 +0100 Subject: [PATCH] implemented admin custom image upload on flavor detail page --- backend/api/serializers.py | 5 +++- frontend/src/pages/flavors/FlavorDetail.tsx | 29 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/backend/api/serializers.py b/backend/api/serializers.py index 91affe4..14193b2 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -75,7 +75,10 @@ class FlavorSerializer(serializers.ModelSerializer): class Meta: model = Flavor - fields = ['id', 'name', 'category', 'category_name', 'category_slug', 'description', 'average_rating', 'followed_average_rating', 'user_rating', 'ratings', 'image_url', 'is_available', 'is_legacy', 'shop_url'] + fields = ['id', 'name', 'category', 'category_name', 'category_slug', 'description', 'average_rating', 'followed_average_rating', 'user_rating', 'ratings', 'image_url', 'image', 'is_available', 'is_legacy', 'shop_url'] + extra_kwargs = { + 'image': {'write_only': True} + } def get_image_url(self, obj): if obj.image: diff --git a/frontend/src/pages/flavors/FlavorDetail.tsx b/frontend/src/pages/flavors/FlavorDetail.tsx index 44b7160..71f4bd3 100644 --- a/frontend/src/pages/flavors/FlavorDetail.tsx +++ b/frontend/src/pages/flavors/FlavorDetail.tsx @@ -86,6 +86,7 @@ const FlavorDetail: React.FC = ({ adminMode }) => { // Product Edit state (Admin) const [isAdminEditing, setIsAdminEditing] = useState(false); + const [uploadingImage, setUploadingImage] = useState(false); const [editFlavorData, setEditFlavorData] = useState({ name: '', description: '', @@ -148,6 +149,26 @@ const FlavorDetail: React.FC = ({ adminMode }) => { } }; + const handleImageUpload = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + const formData = new FormData(); + formData.append('image', file); + + try { + setUploadingImage(true); + await api.patch(`flavors/${id}/`, formData, { + headers: { 'Content-Type': 'multipart/form-data' } + }); + fetchFlavor(); + } catch (err) { + alert('Image upload failed'); + } finally { + setUploadingImage(false); + } + }; + const handleRatingSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!newScore) { @@ -337,6 +358,14 @@ const FlavorDetail: React.FC = ({ adminMode }) => { value={editFlavorData.shop_url} onChange={(e) => setEditFlavorData({...editFlavorData, shop_url: e.target.value})} /> + + + + + setEditFlavorData({...editFlavorData, is_available: e.target.checked})} />} label="In Stock"