brands-in-shops feature implemented

This commit is contained in:
2025-05-27 23:41:04 +02:00
parent 7037be370e
commit 2846bcbb1c
9 changed files with 559 additions and 36 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Shop, Product, ShoppingEventCreate, ProductInEvent, ShoppingEvent } from '../types';
import { shopApi, productApi, shoppingEventApi } from '../services/api';
import { Shop, Product, ShoppingEventCreate, ProductInEvent, ShoppingEvent, BrandInShop } from '../types';
import { shopApi, productApi, shoppingEventApi, brandInShopApi } from '../services/api';
interface AddShoppingEventModalProps {
isOpen: boolean;
@@ -17,6 +17,7 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
}) => {
const [shops, setShops] = useState<Shop[]>([]);
const [products, setProducts] = useState<Product[]>([]);
const [shopBrands, setShopBrands] = useState<BrandInShop[]>([]);
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState('');
@@ -160,6 +161,30 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
}
};
const fetchShopBrands = async (shopId: number) => {
if (shopId === 0) {
setShopBrands([]);
return;
}
try {
const response = await brandInShopApi.getByShop(shopId);
setShopBrands(response.data);
} catch (error) {
console.error('Error fetching shop brands:', error);
setShopBrands([]);
}
};
// Effect to load shop brands when shop selection changes
useEffect(() => {
if (formData.shop_id > 0) {
fetchShopBrands(formData.shop_id);
} else {
setShopBrands([]);
}
}, [formData.shop_id]);
const addProductToEvent = () => {
if (newProductItem.product_id > 0 && newProductItem.amount > 0 && newProductItem.price >= 0) {
setSelectedProducts([...selectedProducts, { ...newProductItem }]);
@@ -224,6 +249,23 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
return `${product.name}${organicEmoji} ${weightInfo}`;
};
// Filter products based on selected shop's brands
const getFilteredProducts = () => {
// If no shop is selected or shop has no brands, show all products
if (formData.shop_id === 0 || shopBrands.length === 0) {
return products;
}
// Get brand IDs available in the selected shop
const availableBrandIds = shopBrands.map(sb => sb.brand_id);
// Filter products to only show those with brands available in the shop
// Also include products without brands (brand_id is null/undefined)
return products.filter(product =>
!product.brand_id || availableBrandIds.includes(product.brand_id)
);
};
if (!isOpen) return null;
return (
@@ -306,7 +348,7 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
>
<option value={0}>Select a product</option>
{Object.entries(
products.reduce((groups, product) => {
getFilteredProducts().reduce((groups, product) => {
const category = product.grocery.category.name;
if (!groups[category]) {
groups[category] = [];
@@ -329,6 +371,14 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
</optgroup>
))}
</select>
{formData.shop_id > 0 && (
<p className="text-xs text-gray-500 mt-1">
{shopBrands.length === 0
? `Showing all ${products.length} products (no brand restrictions for this shop)`
: `Showing ${getFilteredProducts().length} of ${products.length} products (filtered by shop's available brands)`
}
</p>
)}
</div>
<div className="w-24">
<label className="block text-xs font-medium text-gray-700 mb-1">