diff --git a/backend/sellers/views.py b/backend/sellers/views.py index 22c00fdd..41be93a7 100644 --- a/backend/sellers/views.py +++ b/backend/sellers/views.py @@ -295,21 +295,14 @@ class SellerProductApproveView(APIView): permission_classes = [IsAuthenticated] def post(self, request, pk, product_id): - seller = SupplierProfile.objects.filter(pk=pk).first() - if not seller: - return Response({"detail": "Seller not found."}, status=status.HTTP_404_NOT_FOUND) - - product = Product.objects.filter( - models.Q(supplier_id=seller.id) | models.Q(supplier_id=seller.user_id), - pk=product_id - ).first() + product = Product.objects.filter(pk=product_id).first() if not product: return Response({"detail": "Product not found."}, status=status.HTTP_404_NOT_FOUND) product.status = "approved" product.is_active = True product.rejection_reason = None - product.save() + product.save(using="product_db") return Response({ "message": f"Product '{product.title}' has been approved and published to website.", @@ -322,21 +315,14 @@ class SellerProductRejectView(APIView): def post(self, request, pk, product_id): reason = request.data.get("reason", "Product does not comply with catalogue quality or listing policies.") - seller = SupplierProfile.objects.filter(pk=pk).first() - if not seller: - return Response({"detail": "Seller not found."}, status=status.HTTP_404_NOT_FOUND) - - product = Product.objects.filter( - models.Q(supplier_id=seller.id) | models.Q(supplier_id=seller.user_id), - pk=product_id - ).first() + product = Product.objects.filter(pk=product_id).first() if not product: return Response({"detail": "Product not found."}, status=status.HTTP_404_NOT_FOUND) product.status = "rejected" product.is_active = False product.rejection_reason = reason - product.save() + product.save(using="product_db") return Response({ "message": f"Product '{product.title}' was rejected.", @@ -349,27 +335,13 @@ class SellerProductDetailView(APIView): permission_classes = [IsAuthenticated] def get(self, request, pk, product_id): - seller = SupplierProfile.objects.filter(pk=pk).first() - if not seller: - return Response({"detail": "Seller not found."}, status=status.HTTP_404_NOT_FOUND) - - product = Product.objects.filter( - models.Q(supplier_id=seller.id) | models.Q(supplier_id=seller.user_id), - pk=product_id - ).first() + product = Product.objects.filter(pk=product_id).first() if not product: return Response({"detail": "Product not found."}, status=status.HTTP_404_NOT_FOUND) return Response(ProductSerializer(product).data) def patch(self, request, pk, product_id): - seller = SupplierProfile.objects.filter(pk=pk).first() - if not seller: - return Response({"detail": "Seller not found."}, status=status.HTTP_404_NOT_FOUND) - - product = Product.objects.filter( - models.Q(supplier_id=seller.id) | models.Q(supplier_id=seller.user_id), - pk=product_id - ).first() + product = Product.objects.filter(pk=product_id).first() if not product: return Response({"detail": "Product not found."}, status=status.HTTP_404_NOT_FOUND) @@ -397,13 +369,14 @@ class SellerProductDetailView(APIView): "image", "shipping_profile", "package_weight", + "processing_days", ] for field in updatable_fields: if field in request.data: setattr(product, field, request.data[field]) - product.save() + product.save(using="product_db") return Response({ "message": f"Product '{product.title}' content updated successfully.", "product": ProductSerializer(product).data @@ -414,23 +387,17 @@ class SellerProductToggleView(APIView): permission_classes = [IsAuthenticated] def post(self, request, pk, product_id): - seller = SupplierProfile.objects.filter(pk=pk).first() - if not seller: - return Response({"detail": "Seller not found."}, status=status.HTTP_404_NOT_FOUND) - - product = Product.objects.filter( - models.Q(supplier_id=seller.id) | models.Q(supplier_id=seller.user_id), - pk=product_id - ).first() + product = Product.objects.filter(pk=product_id).first() if not product: return Response({"detail": "Product not found."}, status=status.HTTP_404_NOT_FOUND) if "is_active" in request.data: - product.is_active = bool(request.data["is_active"]) + val = request.data["is_active"] + product.is_active = val in [True, "true", "True", 1, "1"] if "status" in request.data: product.status = request.data["status"] - product.save() + product.save(using="product_db") return Response({ "message": f"Product '{product.title}' updated.", "product": ProductSerializer(product).data diff --git a/frontend/src/routes/(app)/sellers/[id]/+page.server.js b/frontend/src/routes/(app)/sellers/[id]/+page.server.js index f6882064..5218c6ae 100644 --- a/frontend/src/routes/(app)/sellers/[id]/+page.server.js +++ b/frontend/src/routes/(app)/sellers/[id]/+page.server.js @@ -131,12 +131,12 @@ export const actions = { const data = await request.formData(); const product_id = data.get('product_id'); try { - await apiRequest( + const res = await apiRequest( `/sellers/${params.id}/products/${product_id}/approve/`, { method: 'POST' }, { cookies } ); - return { success: true, message: 'Product approved and published to website' }; + return { success: true, message: 'Product approved and published to website', product: res.product }; } catch (err) { return fail(400, { error: err.message || 'Failed to approve product' }); } @@ -147,12 +147,12 @@ export const actions = { const product_id = data.get('product_id'); const reason = data.get('reason') || 'Product does not comply with catalogue quality standards.'; try { - await apiRequest( + const res = await apiRequest( `/sellers/${params.id}/products/${product_id}/reject/`, { method: 'POST', body: { reason: String(reason) } }, { cookies } ); - return { success: true, message: 'Product rejected' }; + return { success: true, message: 'Product rejected', product: res.product }; } catch (err) { return fail(400, { error: err.message || 'Failed to reject product' }); } @@ -175,12 +175,12 @@ export const actions = { } } try { - await apiRequest( + const res = await apiRequest( `/sellers/${params.id}/products/${product_id}/`, { method: 'PATCH', body: payload }, { cookies } ); - return { success: true, message: 'Product content updated successfully in website catalogue' }; + return { success: true, message: 'Product content updated successfully in website catalogue', product: res.product }; } catch (err) { return fail(400, { error: err.message || 'Failed to update product content' }); } diff --git a/frontend/src/routes/(app)/sellers/[id]/+page.svelte b/frontend/src/routes/(app)/sellers/[id]/+page.svelte index 4c9bc217..a1053db5 100644 --- a/frontend/src/routes/(app)/sellers/[id]/+page.svelte +++ b/frontend/src/routes/(app)/sellers/[id]/+page.svelte @@ -43,6 +43,22 @@ let activeTab = $state('overview'); let productFilter = $state('all'); // 'all', 'individual', 'bulk', 'pending', 'approved', 'rejected', 'batches' let failedProductImgs = $state(new Set()); + let localProducts = $state(/** @type {any[]} */ ([])); + + $effect(() => { + if (data.products) { + localProducts = [...data.products]; + } + }); + + $effect(() => { + if (form?.product) { + const idx = localProducts.findIndex((p) => p.id === form.product.id); + if (idx !== -1) { + localProducts[idx] = { ...localProducts[idx], ...form.product }; + } + } + }); // Modals state let showRejectModal = $state(false); @@ -154,14 +170,15 @@ } // Filtered products derived state - let filteredProducts = $derived(() => { - if (productFilter === 'all') return products; - if (productFilter === 'individual') return products.filter((p) => p.upload_source !== 'bulk'); - if (productFilter === 'bulk') return products.filter((p) => p.upload_source === 'bulk'); - if (productFilter === 'pending') return products.filter((p) => p.status === 'pending'); - if (productFilter === 'approved') return products.filter((p) => p.status === 'approved'); - if (productFilter === 'rejected') return products.filter((p) => p.status === 'rejected'); - return products; + let filteredProducts = $derived.by(() => { + const list = localProducts.length > 0 ? localProducts : products; + if (productFilter === 'all') return list; + if (productFilter === 'individual') return list.filter((p) => p.upload_source !== 'bulk'); + if (productFilter === 'bulk') return list.filter((p) => p.upload_source === 'bulk'); + if (productFilter === 'pending') return list.filter((p) => p.status === 'pending'); + if (productFilter === 'approved') return list.filter((p) => p.status === 'approved'); + if (productFilter === 'rejected') return list.filter((p) => p.status === 'rejected'); + return list; }); @@ -637,7 +654,7 @@
- {#each filteredProducts() as p (p.id)} + {#each filteredProducts as p (p.id)}