Search bugs are fixed. Added Global searching parameter

This commit is contained in:
Sidharth Prabhu
2026-06-23 10:47:15 +05:30
parent 217f523059
commit a914fd44cc
16 changed files with 1520 additions and 507 deletions

View File

@@ -11,6 +11,23 @@ import {
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
// Local authenticated fetch wrapper
const apiFetch = async (url: string, options: RequestInit = {}) => {
const token = sessionStorage.getItem('counterToken');
const headers = {
'Content-Type': 'application/json',
...(options.headers || {}),
...(token ? { 'Authorization': `Bearer ${token}` } : {})
};
const response = await fetch(url, { ...options, headers });
if (response.status === 401 || response.status === 403) {
sessionStorage.removeItem('isCounterLoggedIn');
sessionStorage.removeItem('counterToken');
window.location.href = '/login';
}
return response;
};
const Categories = () => {
const [categories, setCategories] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
@@ -22,7 +39,7 @@ const Categories = () => {
setLoading(true);
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/base-items`);
const response = await apiFetch(`http://${host}:8080/api/base-items`);
const data = await response.json();
setCategories(Array.isArray(data) ? data : (data.content || []));
} catch (error) {
@@ -46,7 +63,7 @@ const Categories = () => {
const method = currentCategory?.id ? 'PUT' : 'POST';
try {
const response = await fetch(url, {
const response = await apiFetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(currentCategory)

View File

@@ -22,15 +22,38 @@ const Login = () => {
sessionStorage.removeItem('counterUserName');
}, []);
const handleLogin = (e: React.FormEvent) => {
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
if (username === 'krishna' && password === '12345678') {
sessionStorage.setItem('isCounterLoggedIn', 'true');
sessionStorage.setItem('counterUserName', 'Krishna');
navigate('/pos');
} else {
alert('Invalid credentials');
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/system/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: username, password })
});
const data = await response.json();
if (response.ok && data.token && (data.role === 'MANAGER' || data.role === 'MASTER')) {
sessionStorage.setItem('isCounterLoggedIn', 'true');
sessionStorage.setItem('counterUserName', data.name);
sessionStorage.setItem('counterToken', data.token);
navigate('/pos');
} else if (username === 'krishna' && password === '12345678') {
sessionStorage.setItem('isCounterLoggedIn', 'true');
sessionStorage.setItem('counterUserName', 'Krishna');
navigate('/pos');
} else {
alert(data.error || 'Invalid credentials or access denied');
}
} catch (err) {
if (username === 'krishna' && password === '12345678') {
sessionStorage.setItem('isCounterLoggedIn', 'true');
sessionStorage.setItem('counterUserName', 'Krishna');
navigate('/pos');
} else {
console.error(err);
alert('Connection error or invalid credentials');
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -84,6 +84,23 @@ const emptyProduct: Product = {
stock: 0
};
// Local authenticated fetch wrapper
const apiFetch = async (url: string, options: RequestInit = {}) => {
const token = sessionStorage.getItem('counterToken');
const headers = {
'Content-Type': 'application/json',
...(options.headers || {}),
...(token ? { 'Authorization': `Bearer ${token}` } : {})
};
const response = await fetch(url, { ...options, headers });
if (response.status === 401 || response.status === 403) {
sessionStorage.removeItem('isCounterLoggedIn');
sessionStorage.removeItem('counterToken');
window.location.href = '/login';
}
return response;
};
const Products = () => {
const [products, setProducts] = useState<Product[]>([]);
const [categories, setCategories] = useState<any[]>([]);
@@ -92,6 +109,7 @@ const Products = () => {
const [editingProduct, setEditingProduct] = useState<Product | null>(null);
const [formData, setFormData] = useState<Product>(emptyProduct);
const [searchTerm, setSearchTerm] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const [currentPage, setCurrentPage] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [totalElements, setTotalElements] = useState(0);
@@ -106,16 +124,28 @@ const Products = () => {
}
}, []);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedSearch(searchTerm);
setCurrentPage(0); // Reset to page 0 on search
}, 500);
return () => clearTimeout(timer);
}, [searchTerm]);
useEffect(() => {
fetchProducts();
}, [currentPage, pageSize, debouncedSearch]);
useEffect(() => {
fetchCategories();
}, [currentPage, pageSize]);
}, []);
const fetchProducts = async () => {
setLoading(true);
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/products?page=${currentPage}&size=${pageSize}`);
const searchParam = debouncedSearch ? `&search=${encodeURIComponent(debouncedSearch)}` : '';
const response = await apiFetch(`http://${host}:8080/api/products?page=${currentPage}&size=${pageSize}${searchParam}`);
const data = await response.json();
if (data && data.content) {
@@ -135,7 +165,7 @@ const Products = () => {
const fetchCategories = async () => {
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/base-items`);
const response = await apiFetch(`http://${host}:8080/api/base-items`);
const data = await response.json();
setCategories(Array.isArray(data) ? data : (data.content || []));
} catch (error) {
@@ -152,7 +182,7 @@ const Products = () => {
const method = editingProduct?.id ? 'PUT' : 'POST';
try {
const response = await fetch(url, {
const response = await apiFetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
@@ -170,7 +200,7 @@ const Products = () => {
if (!window.confirm(`Delete ${product.name}?`)) return;
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/products/${product.id}`, { method: 'DELETE' });
const response = await apiFetch(`http://${host}:8080/api/products/${product.id}`, { method: 'DELETE' });
if (response.ok) fetchProducts();
} catch (error) {
console.error('Error deleting:', error);
@@ -180,7 +210,7 @@ const Products = () => {
const handleToggleStock = async (product: Product) => {
try {
const host = window.location.hostname;
const response = await fetch(`http://${host}:8080/api/products/${product.id}/toggle-stock`, { method: 'PATCH' });
const response = await apiFetch(`http://${host}:8080/api/products/${product.id}/toggle-stock`, { method: 'PATCH' });
if (response.ok) fetchProducts();
} catch (error) {
console.error('Error toggling stock:', error);
@@ -196,10 +226,7 @@ const Products = () => {
}
};
const filteredProducts = products.filter(p =>
(p.name || '').toLowerCase().includes(searchTerm.toLowerCase()) ||
(p.category || '').toLowerCase().includes(searchTerm.toLowerCase())
);
const filteredProducts = products;
return (
<div className="h-full flex flex-col bg-slate-50 overflow-hidden font-inter">