Integrated stock reduction logic and branding updates
This commit is contained in:
@@ -40,6 +40,7 @@ public class OrderController {
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate,
|
||||
@RequestParam(required = false) String status,
|
||||
@RequestParam(required = false) String paymentType,
|
||||
@RequestParam(required = false) String orderType,
|
||||
@RequestParam(required = false) String search,
|
||||
@RequestParam(defaultValue = "false") boolean archived,
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@@ -66,6 +67,9 @@ public class OrderController {
|
||||
if (paymentType != null && !paymentType.isEmpty()) {
|
||||
predicates.add(cb.equal(root.get("paymentMethod"), paymentType));
|
||||
}
|
||||
if (orderType != null && !orderType.isEmpty()) {
|
||||
predicates.add(cb.equal(root.get("orderType"), orderType));
|
||||
}
|
||||
if (search != null && !search.isEmpty()) {
|
||||
String searchLower = "%" + search.toLowerCase() + "%";
|
||||
Join<Order, User> userJoin = root.join("user", JoinType.LEFT);
|
||||
@@ -110,10 +114,11 @@ public class OrderController {
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Map<String, Object>> placeOrder(@RequestBody Order order) {
|
||||
try {
|
||||
// Link items to the order for bidirectional relationship
|
||||
if (order.getItems() != null) {
|
||||
for (OrderItem item : order.getItems()) {
|
||||
System.out.println("🛒 RECEIVED ITEM: " + item.getProductName() + " | StallID: " + item.getStallId() + " | StallName: " + item.getStallName());
|
||||
System.out.println("🛒 RECEIVED ITEM: " + item.getProductName());
|
||||
item.setOrder(order);
|
||||
}
|
||||
}
|
||||
@@ -152,11 +157,18 @@ public class OrderController {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("success", true);
|
||||
response.put("orderNumber", savedOrder.getOrderNumber()); // Secure ID for QR
|
||||
response.put("displayOrderId", savedOrder.getDisplayOrderId()); // Sequential ID (#001)
|
||||
response.put("orderNumber", savedOrder.getOrderNumber());
|
||||
response.put("displayOrderId", savedOrder.getDisplayOrderId());
|
||||
response.put("message", "Order placed successfully");
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Map<String, Object> errorResponse = new HashMap<>();
|
||||
errorResponse.put("success", false);
|
||||
errorResponse.put("error", e.getMessage());
|
||||
return ResponseEntity.status(500).body(errorResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/user/{userId}")
|
||||
|
||||
@@ -16,6 +16,16 @@ public class ProductController {
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
|
||||
@GetMapping("/categories")
|
||||
public List<String> getAllCategories() {
|
||||
return productRepository.findAll().stream()
|
||||
.map(Product::getCategory)
|
||||
.filter(c -> c != null && !c.isEmpty())
|
||||
.distinct()
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public org.springframework.data.domain.Page<Product> getAllProducts(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
|
||||
@@ -41,6 +41,9 @@ public class Order {
|
||||
@Column(nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String orderType = "STORE_ORDER"; // STORE_ORDER, QR_ORDER, MY_ORDER, etc.
|
||||
|
||||
@Column(name = "is_archived", nullable = false)
|
||||
private boolean isArchived = false;
|
||||
|
||||
@@ -97,6 +100,9 @@ public class Order {
|
||||
public boolean isArchived() { return isArchived; }
|
||||
public void setArchived(boolean archived) { isArchived = archived; }
|
||||
|
||||
public String getOrderType() { return orderType; }
|
||||
public void setOrderType(String orderType) { this.orderType = orderType; }
|
||||
|
||||
public List<OrderItem> getItems() { return items; }
|
||||
public void setItems(List<OrderItem> items) { this.items = items; }
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@ const BaseMenu = () => {
|
||||
setShowProductsModal(true);
|
||||
setProductsLoading(true);
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8080/api/products/category/${encodeURIComponent(baseItem.name)}`);
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/products/category/${encodeURIComponent(baseItem.name)}`);
|
||||
const data = await response.json();
|
||||
setAssociatedProducts(data);
|
||||
} catch (error) {
|
||||
@@ -88,9 +89,10 @@ const BaseMenu = () => {
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const host = window.location.hostname;
|
||||
const url = editingItem
|
||||
? `http://localhost:8080/api/base-items/${editingItem.id}`
|
||||
: 'http://localhost:8080/api/base-items';
|
||||
? `http://${host}:8080/api/base-items/${editingItem.id}`
|
||||
: `http://${host}:8080/api/base-items`;
|
||||
const method = editingItem ? 'PUT' : 'POST';
|
||||
|
||||
try {
|
||||
@@ -119,7 +121,8 @@ const BaseMenu = () => {
|
||||
|
||||
const handleToggleActive = async (item: BaseItem) => {
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8080/api/base-items/${item.id}`, {
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/base-items/${item.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...item, active: !item.active }),
|
||||
@@ -200,7 +203,7 @@ const BaseMenu = () => {
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : items.filter(item => item.name.toLowerCase().includes(searchTerm.toLowerCase())).length === 0 ? (
|
||||
) : items.filter(item => (item.name || '').toLowerCase().includes((searchTerm || '').toLowerCase())).length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={6} className="px-6 py-12 text-center text-[#64748b]">
|
||||
<p className="text-lg font-medium mb-1">No items found</p>
|
||||
@@ -209,7 +212,7 @@ const BaseMenu = () => {
|
||||
</tr>
|
||||
) : (
|
||||
items
|
||||
.filter(item => item.name.toLowerCase().includes(searchTerm.toLowerCase()))
|
||||
.filter(item => (item.name || '').toLowerCase().includes((searchTerm || '').toLowerCase()))
|
||||
.map((item) => (
|
||||
<tr key={item.id} className="hover:bg-gray-50/50 transition-all group">
|
||||
<td className="px-6 py-4 text-sm font-medium text-[#64748b]">#{item.id}</td>
|
||||
|
||||
@@ -74,8 +74,9 @@ const Bills: React.FC = () => {
|
||||
};
|
||||
|
||||
const filteredOrders = orders.filter(order => {
|
||||
const matchesSearch = order.purchaseId.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
order.referenceId?.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const search = (searchTerm || '').toLowerCase();
|
||||
const matchesSearch = (order.purchaseId || '').toLowerCase().includes(search) ||
|
||||
(order.referenceId || '').toLowerCase().includes(search);
|
||||
const matchesStatus = statusFilter === 'All' || order.status === statusFilter;
|
||||
return matchesSearch && matchesStatus;
|
||||
});
|
||||
|
||||
@@ -146,10 +146,12 @@ const Customers: React.FC = () => {
|
||||
return name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
|
||||
};
|
||||
|
||||
const filteredUsers = users.filter(user =>
|
||||
user.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
user.mobileNumber?.includes(searchTerm)
|
||||
);
|
||||
const filteredCustomers = customers.filter(user => {
|
||||
const search = (searchTerm || '').toLowerCase();
|
||||
const name = (user.name || '').toLowerCase();
|
||||
return name.includes(search) ||
|
||||
(user.mobileNumber || '').includes(searchTerm);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -43,13 +43,13 @@ const Login = () => {
|
||||
const user = await response.json();
|
||||
|
||||
// Strict Role Validation
|
||||
if (user.role.toLowerCase() !== role) {
|
||||
alert(`Access Denied: You are trying to login as ${role.toUpperCase()}, but your credentials belong to a ${user.role.toUpperCase()} account.`);
|
||||
if ((user.role || '').toLowerCase() !== (role || '').toLowerCase()) {
|
||||
alert(`Access Denied: You are trying to login as ${(role || '').toUpperCase()}, but your credentials belong to a ${(user.role || '').toUpperCase()} account.`);
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.setItem('isLoggedIn', 'true');
|
||||
sessionStorage.setItem('userRole', user.role.toLowerCase());
|
||||
sessionStorage.setItem('userRole', (user.role || '').toLowerCase());
|
||||
sessionStorage.setItem('userPermissions', JSON.stringify(user.permissions || []));
|
||||
navigate('/store-dashboard');
|
||||
} else {
|
||||
|
||||
@@ -193,7 +193,11 @@ const Managers = () => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-[#e2e8f0]">
|
||||
{managers.filter(m => m.name.toLowerCase().includes(searchQuery.toLowerCase()) || m.email.toLowerCase().includes(searchQuery.toLowerCase())).map((manager) => (
|
||||
{managers.filter(m => {
|
||||
const query = (searchQuery || '').toLowerCase();
|
||||
return (m.name || '').toLowerCase().includes(query) ||
|
||||
(m.email || '').toLowerCase().includes(query);
|
||||
}).map((manager) => (
|
||||
<tr key={manager.id} className="hover:bg-gray-50/50 transition-colors">
|
||||
<td className="px-6 py-5">
|
||||
<div className="flex items-center gap-3">
|
||||
|
||||
@@ -82,10 +82,12 @@ const Orders: React.FC = () => {
|
||||
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
const response = await fetch(`http://${window.location.hostname}:8080/api/products`);
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/products`);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setAllProducts(data);
|
||||
// Handle both Array and Page object responses for robustness
|
||||
setAllProducts(Array.isArray(data) ? data : (data.content || []));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching products:', error);
|
||||
@@ -233,10 +235,11 @@ const Orders: React.FC = () => {
|
||||
};
|
||||
|
||||
const filteredProducts = useMemo(() => {
|
||||
if (!editSearchQuery.trim()) return [];
|
||||
const query = (editSearchQuery || '').trim().toLowerCase();
|
||||
if (!query) return [];
|
||||
return allProducts.filter(p =>
|
||||
p.name.toLowerCase().includes(editSearchQuery.toLowerCase()) ||
|
||||
p.category.toLowerCase().includes(editSearchQuery.toLowerCase())
|
||||
(p.name || '').toLowerCase().includes(query) ||
|
||||
(p.category || '').toLowerCase().includes(query)
|
||||
).slice(0, 5); // Limit results
|
||||
}, [allProducts, editSearchQuery]);
|
||||
|
||||
@@ -246,7 +249,7 @@ const Orders: React.FC = () => {
|
||||
};
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status.toUpperCase()) {
|
||||
switch ((status || '').toUpperCase()) {
|
||||
case 'COMPLETED': return 'bg-emerald-50 text-emerald-600 border-emerald-100';
|
||||
case 'PAID': return 'bg-indigo-50 text-indigo-600 border-indigo-100';
|
||||
case 'PENDING': return 'bg-amber-50 text-amber-600 border-amber-100';
|
||||
|
||||
@@ -117,15 +117,21 @@ const Products = () => {
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/products?page=${currentPage}&size=${pageSize}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data && data.content) {
|
||||
setProducts(data.content);
|
||||
setTotalElements(data.totalElements);
|
||||
} else if (Array.isArray(data)) {
|
||||
setProducts(data);
|
||||
setTotalElements(data.length);
|
||||
} else {
|
||||
setProducts([]);
|
||||
setTotalElements(0);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching products:', error);
|
||||
setProducts([]);
|
||||
setTotalElements(0);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -133,17 +139,26 @@ const Products = () => {
|
||||
|
||||
const fetchBaseItems = async () => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:8080/api/base-items');
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/base-items`);
|
||||
const data = await response.json();
|
||||
if (data && data.content) {
|
||||
setBaseItems(data.content);
|
||||
} else if (Array.isArray(data)) {
|
||||
setBaseItems(data);
|
||||
} else {
|
||||
setBaseItems([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching base items:', error);
|
||||
setBaseItems([]);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAllStalls = async () => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:8080/api/stalls');
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/stalls`);
|
||||
const data = await response.json();
|
||||
setAllStalls(data);
|
||||
} catch (error) {
|
||||
@@ -153,9 +168,10 @@ const Products = () => {
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const host = window.location.hostname;
|
||||
const url = editingProduct
|
||||
? `http://localhost:8080/api/products/${editingProduct.id}`
|
||||
: 'http://localhost:8080/api/products';
|
||||
? `http://${host}:8080/api/products/${editingProduct.id}`
|
||||
: `http://${host}:8080/api/products`;
|
||||
const method = editingProduct ? 'PUT' : 'POST';
|
||||
|
||||
try {
|
||||
@@ -168,6 +184,7 @@ const Products = () => {
|
||||
setShowModal(false);
|
||||
setEditingProduct(null);
|
||||
setFormData(emptyProduct);
|
||||
setSearchTerm(''); // Clear search term to ensure updated product is visible
|
||||
fetchProducts();
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -187,7 +204,8 @@ const Products = () => {
|
||||
|
||||
const handleToggleActive = async (product: Product) => {
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8080/api/products/${product.id}`, {
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/products/${product.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...product, active: !product.active }),
|
||||
@@ -203,7 +221,8 @@ const Products = () => {
|
||||
|
||||
const handleToggleStock = async (product: Product) => {
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8080/api/products/${product.id}/toggle-stock`, {
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/products/${product.id}/toggle-stock`, {
|
||||
method: 'PATCH',
|
||||
});
|
||||
if (response.ok) {
|
||||
@@ -218,7 +237,8 @@ const Products = () => {
|
||||
const handleDelete = async (product: Product) => {
|
||||
if (!window.confirm(`Are you sure you want to delete ${product.name}?`)) return;
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8080/api/products/${product.id}`, {
|
||||
const host = window.location.hostname;
|
||||
const response = await fetch(`http://${host}:8080/api/products/${product.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (response.ok) {
|
||||
@@ -303,9 +323,21 @@ const Products = () => {
|
||||
<tbody className="divide-y divide-[#e2e8f0]">
|
||||
{loading ? (
|
||||
<tr><td colSpan={6} className="px-6 py-12 text-center text-[#64748b]"><RefreshCw className="animate-spin inline mr-2" />Loading...</td></tr>
|
||||
) : products.filter(p => p.name.toLowerCase().includes(searchTerm.toLowerCase()) || p.category.toLowerCase().includes(searchTerm.toLowerCase())).length === 0 ? (
|
||||
) : products.filter(p => {
|
||||
if (!p) return false;
|
||||
const search = (searchTerm || '').toLowerCase();
|
||||
const name = (p.name || '').toLowerCase();
|
||||
const category = (p.category || '').toLowerCase();
|
||||
return name.includes(search) || category.includes(search);
|
||||
}).length === 0 ? (
|
||||
<tr><td colSpan={6} className="px-6 py-12 text-center text-[#64748b]">No products found</td></tr>
|
||||
) : products.filter(p => p.name.toLowerCase().includes(searchTerm.toLowerCase()) || p.category.toLowerCase().includes(searchTerm.toLowerCase())).map((product) => (
|
||||
) : products.filter(p => {
|
||||
if (!p) return false;
|
||||
const search = (searchTerm || '').toLowerCase();
|
||||
const name = (p.name || '').toLowerCase();
|
||||
const category = (p.category || '').toLowerCase();
|
||||
return name.includes(search) || category.includes(search);
|
||||
}).map((product) => (
|
||||
<tr key={product.id} className="hover:bg-gray-50/50 transition-all">
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -327,9 +359,9 @@ const Products = () => {
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{(() => {
|
||||
// Combine direct stalls with stalls that have this product's category in their baseItems
|
||||
const directStalls = product.stalls || [];
|
||||
const indirectStalls = allStalls.filter(s =>
|
||||
s.baseItems?.some(bi => bi.name.toLowerCase() === product.category?.toLowerCase())
|
||||
const directStalls = (product && product.stalls) || [];
|
||||
const indirectStalls = (allStalls || []).filter(s =>
|
||||
s.baseItems?.some(bi => bi.name?.toLowerCase() === product.category?.toLowerCase())
|
||||
).map(s => ({ id: s.id, name: s.name }));
|
||||
|
||||
// Unique stalls by ID
|
||||
|
||||
@@ -161,7 +161,7 @@ const PurchaseAnalytics = () => {
|
||||
};
|
||||
|
||||
const filteredAnalytics = analytics.filter(item => {
|
||||
const matchesSearch = item.product.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const matchesSearch = (item.product || '').toLowerCase().includes((searchTerm || '').toLowerCase());
|
||||
const matchesFilter = filterType === 'all' || item.trend === filterType;
|
||||
return matchesSearch && matchesFilter;
|
||||
});
|
||||
|
||||
@@ -258,7 +258,7 @@ const Purchases: React.FC = () => {
|
||||
<Loader2 className="animate-spin inline-block mr-2" /> Loading records...
|
||||
</td>
|
||||
</tr>
|
||||
) : orders.filter(o => o.purchaseId.toLowerCase().includes(searchTerm.toLowerCase())).map((order) => (
|
||||
) : orders.filter(o => (o.purchaseId || '').toLowerCase().includes((searchTerm || '').toLowerCase())).map((order) => (
|
||||
<tr key={order.id} className="hover:bg-gray-50/50 transition-all font-medium">
|
||||
<td className="px-6 py-4 text-sm font-bold text-[#231651]">{order.purchaseId}</td>
|
||||
<td className="px-6 py-4 text-sm text-[#64748b]">{new Date(order.date).toLocaleDateString()}</td>
|
||||
|
||||
@@ -109,10 +109,11 @@ const Staff = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredStaff = staffList.filter(s =>
|
||||
s.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
s.email.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
const filteredStaff = staff.filter(s => {
|
||||
const query = (searchQuery || '').toLowerCase();
|
||||
return (s.name || '').toLowerCase().includes(query) ||
|
||||
(s.email || '').toLowerCase().includes(query);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 bg-[#f8fafc] min-h-screen font-inter">
|
||||
|
||||
@@ -198,8 +198,15 @@ const Stalls: React.FC = () => {
|
||||
fetch(`http://${host}:8080/api/base-items`)
|
||||
]);
|
||||
|
||||
if (prodRes.ok) setAllProducts(await prodRes.json());
|
||||
if (baseRes.ok) setAllBaseItems(await baseRes.json());
|
||||
if (prodRes.ok) {
|
||||
const data = await prodRes.json();
|
||||
// Handle both Array and Page object responses for robustness
|
||||
setAllProducts(Array.isArray(data) ? data : (data.content || []));
|
||||
}
|
||||
if (baseRes.ok) {
|
||||
const data = await baseRes.json();
|
||||
setAllBaseItems(Array.isArray(data) ? data : (data.content || []));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching available items:', error);
|
||||
}
|
||||
@@ -234,10 +241,11 @@ const Stalls: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredStalls = stalls.filter(s =>
|
||||
s.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
s.description.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
const filteredStalls = stalls.filter(s => {
|
||||
const query = (searchQuery || '').toLowerCase();
|
||||
return (s.name || '').toLowerCase().includes(query) ||
|
||||
(s.description || '').toLowerCase().includes(query);
|
||||
});
|
||||
|
||||
const isStallOpen = (stall: Stall) => {
|
||||
if (stall.temporarilyClosed) return false;
|
||||
@@ -618,7 +626,7 @@ const Stalls: React.FC = () => {
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
|
||||
{activeTab === 'products' ? (
|
||||
allProducts
|
||||
.filter(p => p.name.toLowerCase().includes(itemSearchQuery.toLowerCase()))
|
||||
.filter(p => (p.name || '').toLowerCase().includes((itemSearchQuery || '').toLowerCase()))
|
||||
.map(product => {
|
||||
const isSelected = tempProductIds.includes(product.id);
|
||||
return (
|
||||
@@ -644,7 +652,7 @@ const Stalls: React.FC = () => {
|
||||
})
|
||||
) : (
|
||||
allBaseItems
|
||||
.filter(b => b.name.toLowerCase().includes(itemSearchQuery.toLowerCase()))
|
||||
.filter(b => (b.name || '').toLowerCase().includes((itemSearchQuery || '').toLowerCase()))
|
||||
.map(baseItem => {
|
||||
const isSelected = tempBaseItemIds.includes(baseItem.id);
|
||||
return (
|
||||
|
||||
@@ -60,11 +60,11 @@ const Terminals = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredTerminals = terminals.filter(t =>
|
||||
t.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
t.location.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
const filteredTerminals = terminals.filter(t => {
|
||||
const query = (searchQuery || '').toLowerCase();
|
||||
return (t.name || '').toLowerCase().includes(query) ||
|
||||
(t.location || '').toLowerCase().includes(query);
|
||||
});
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto space-y-8 font-inter">
|
||||
{/* Header Section */}
|
||||
|
||||
@@ -134,10 +134,13 @@ const Vendors: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredVendors = vendors.filter(v =>
|
||||
v.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
v.companyName?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
const filteredVendors = vendors.filter(v => {
|
||||
if (!v) return false;
|
||||
const search = (searchTerm || '').toLowerCase();
|
||||
const name = (v.name || '').toLowerCase();
|
||||
const company = (v.companyName || '').toLowerCase();
|
||||
return name.includes(search) || company.includes(search);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user