Skip to content

Commit 7b57a26

Browse files
authored
Merge pull request #23 from ZatoBox/fix/hover-and-product-owner
Fix/hover and product owner
2 parents 9b1715f + f6db328 commit 7b57a26

12 files changed

Lines changed: 460 additions & 166 deletions

File tree

backend/zato-csm-backend/repositories/product_repositories.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,8 @@ def delete_product(self, product_id: int):
113113
if not product:
114114
raise HTTPException(status_code=404, detail="Product not found")
115115
return product
116+
117+
def find_by_creator(self, creator_id: int):
118+
with self._get_cursor() as cursor:
119+
cursor.execute("SELECT * FROM products WHERE creator_id=%s", (creator_id,))
120+
return cursor.fetchall()

backend/zato-csm-backend/routes/auth.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,11 @@ def update_profile(
147147
if not current_user.get("admin"):
148148
raise HTTPException(status_code=403, detail="Acess denied")
149149
return auth_service.update_profile(user_id, updates)
150+
151+
152+
@router.get("/check-email")
153+
def check_email(email: str, db=Depends(get_db_connection)):
154+
with db.cursor() as cursor:
155+
cursor.execute("SELECT id FROM users WHERE email=%s", (email,))
156+
row = cursor.fetchone()
157+
return {"exists": bool(row)}

backend/zato-csm-backend/routes/inventory.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ def get_inventory(
2121
return {"success": True, "inventory": inventory}
2222

2323

24+
@router.get("/user")
25+
def get_user_inventory(
26+
user=Depends(get_current_user), inventory_service=Depends(_get_inventory_service)
27+
):
28+
inventory = inventory_service.get_inventory_by_user(user["id"])
29+
return {"success": True, "inventory": inventory}
30+
31+
2432
@router.put("/{product_id}")
2533
def update_inventory(
2634
product_id: int,

backend/zato-csm-backend/services/inventory_service.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ def get_inventory(self):
2323
for p in products
2424
]
2525

26+
def get_inventory_by_user(self, user_id: int):
27+
products = self.product_repo.find_by_creator(user_id)
28+
return [
29+
{
30+
"id": p["id"],
31+
"productId": p["id"],
32+
"quantity": p["stock"],
33+
"minStock": p.get("min_stock", 0),
34+
"lastUpdated": p.get("last_updated", datetime.now().isoformat() + "Z"),
35+
}
36+
for p in products
37+
]
38+
2639
def update_stock(self, product_id: int, quantity: int, user_timezone: str = "UTC"):
2740
if quantity < 0:
2841
raise HTTPException(status_code=400, detail="Quantity cannot be negative")

frontend/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function App() {
6666
<div className='p-8'>
6767
<h1 className='text-2xl font-bold'>POS Integration</h1>
6868
<p className='mt-4'>
69-
POS system integration module is active and ready to use.
69+
POS system integration module is currently under development. This feature will allow you to connect ZatoBox with your existing POS system for seamless inventory management and sales tracking.
7070
</p>
7171
</div>
7272
}

frontend/src/components/InventoryPage.tsx

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
Package,
99
ChevronDown,
1010
} from 'lucide-react';
11-
import { productsAPI } from '../services/api';
11+
import { productsAPI, inventoryAPI } from '../services/api';
1212
import type { Product } from '../services/api';
1313
import { useAuth } from '../contexts/AuthContext';
1414

@@ -27,7 +27,7 @@ const InventoryPage: React.FC = () => {
2727

2828
// Fetch products from backend
2929
useEffect(() => {
30-
const fetchProducts = async () => {
30+
const fetchInventory = async () => {
3131
if (!isAuthenticated) {
3232
setError('You must log in to view inventory');
3333
setLoading(false);
@@ -36,21 +36,60 @@ const InventoryPage: React.FC = () => {
3636

3737
try {
3838
setLoading(true);
39-
const response = await productsAPI.getAll();
40-
if (response.success) {
41-
setInventoryItems(response.products);
42-
} else {
43-
setError('Error loading products');
39+
const response = await inventoryAPI.getUserInventory();
40+
41+
if (!response.success) {
42+
setError('Error loading inventory');
43+
return;
4444
}
45+
46+
const mappedProducts: Product[] = response.inventory.map((item) => {
47+
const anyItem = item as unknown as Record<string, unknown>;
48+
49+
// If backend returns an embedded product object
50+
if (anyItem.product && typeof anyItem.product === 'object') {
51+
return anyItem.product as Product;
52+
}
53+
54+
// If inventory item already contains product-like fields
55+
if (anyItem.name || anyItem.price !== undefined) {
56+
return {
57+
id: (anyItem.product_id as number) ?? (anyItem.id as number) ?? 0,
58+
name:
59+
(anyItem.name as string) ??
60+
`Product ${
61+
(anyItem.product_id as number) ?? (anyItem.id as number) ?? ''
62+
}`,
63+
description: (anyItem.description as string) ?? null,
64+
price: Number(anyItem.price ?? 0),
65+
stock: Number(anyItem.quantity ?? 0),
66+
category: (anyItem.category as string) ?? null,
67+
status: (anyItem.status as 'active' | 'inactive') ?? 'inactive',
68+
} as Product;
69+
}
70+
71+
// Fallback minimal product constructed from inventory item
72+
return {
73+
id: (anyItem.product_id as number) ?? (anyItem.id as number) ?? 0,
74+
name: `Product ${
75+
(anyItem.product_id as number) ?? (anyItem.id as number) ?? ''
76+
}`,
77+
price: 0,
78+
stock: Number(anyItem.quantity ?? 0),
79+
} as Product;
80+
});
81+
82+
setInventoryItems(mappedProducts);
83+
setError(null);
4584
} catch (err) {
46-
console.error('Error fetching products:', err);
47-
setError('Error loading products');
85+
console.error('Error fetching inventory:', err);
86+
setError('Error loading inventory');
4887
} finally {
4988
setLoading(false);
5089
}
5190
};
5291

53-
fetchProducts();
92+
fetchInventory();
5493
}, [isAuthenticated]);
5594

5695
const categories = [

frontend/src/components/OCRResultPage.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,27 @@ const OCRResultPage: React.FC = () => {
2121
});
2222
const [systemStatus, setSystemStatus] = useState<any>(null);
2323

24+
const maintenanceMode = true;
25+
26+
if (maintenanceMode) {
27+
return (
28+
<div className='flex items-center justify-center min-h-screen p-4'>
29+
<div className='w-full max-w-2xl p-8 text-center bg-white rounded-lg shadow-lg'>
30+
<h1 className='mb-4 text-2xl font-bold'>In maintenance</h1>
31+
<p className='mb-6 text-text-secondary'>
32+
The OCR feature is temporarily unavailable.
33+
</p>
34+
<button
35+
disabled
36+
className='px-6 py-3 font-medium text-white bg-gray-400 rounded-lg cursor-not-allowed'
37+
>
38+
In maintenance
39+
</button>
40+
</div>
41+
</div>
42+
);
43+
}
44+
2445
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
2546
if (e.target.files && e.target.files[0]) {
2647
setFile(e.target.files[0]);

0 commit comments

Comments
 (0)