add AI voice assistant, chat widget, inventory and pharmacy pages with API services

This commit is contained in:
2026-09-18 10:39:03 +05:30
parent a343bb0dfc
commit 6c43b92671
7 changed files with 123 additions and 29 deletions
+58 -8
View File
@@ -1,4 +1,5 @@
import { useState, useEffect, useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { Search, AlertCircle, Package, Layers, Plus, X, ChevronDown } from 'lucide-react';
import { createColumnHelper } from '@tanstack/react-table';
import { Table } from '../components/Table';
@@ -73,6 +74,8 @@ const columns = [
];
const Pharmacy = () => {
const location = useLocation();
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(25);
const [inventory, setInventory] = useState<PharmacyItem[]>([]);
@@ -246,18 +249,52 @@ const Pharmacy = () => {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('action') === 'dispense') {
setIsDispenseModalOpen(true);
// Clean up URL after opening
window.history.replaceState({}, '', '/pharmacy');
}
}, []);
// Filter inventory based on search query
// Listen for external search triggers (e.g., Voice Assistant or Chat Widget)
useEffect(() => {
const handleSearchEvent = (e: any) => {
if (typeof e.detail === 'string') {
setSearchQuery(e.detail);
}
};
window.addEventListener('setPharmacySearch', handleSearchEvent);
window.addEventListener('setSearchQuery', handleSearchEvent);
return () => {
window.removeEventListener('setPharmacySearch', handleSearchEvent);
window.removeEventListener('setSearchQuery', handleSearchEvent);
};
}, []);
// Automatically sync search query when navigating with ?search=query
useEffect(() => {
const params = new URLSearchParams(location.search);
const searchParam = params.get('search');
if (searchParam !== null) {
setSearchQuery(searchParam);
}
}, [location.search]);
// Filter inventory based on search query with smart matching
const filteredInventory = useMemo(() => {
return inventory.filter(item =>
item.medicine.toLowerCase().includes(searchQuery.toLowerCase()) ||
item.subtitle.toLowerCase().includes(searchQuery.toLowerCase()) ||
item.manufacture.toLowerCase().includes(searchQuery.toLowerCase())
);
if (!searchQuery.trim()) return inventory;
const cleanSearch = searchQuery.trim().toLowerCase();
const compactSearch = cleanSearch.replace(/[\s\-_]+/g, '');
return inventory.filter(item => {
const med = item.medicine.toLowerCase();
const sub = item.subtitle.toLowerCase();
const mfr = item.manufacture.toLowerCase();
const compactMed = med.replace(/[\s\-_]+/g, '');
return med.includes(cleanSearch) ||
sub.includes(cleanSearch) ||
mfr.includes(cleanSearch) ||
compactMed.includes(compactSearch);
});
}, [inventory, searchQuery]);
// Reset pagination when search changes
@@ -337,8 +374,21 @@ const Pharmacy = () => {
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search medicines, OTC, or prescriptions..."
className="w-full py-3 bg-slate-50 border border-slate-200 hover:border-slate-300 hover:bg-slate-100/50 rounded-xl focus:bg-white focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 shadow-sm placeholder:text-slate-400 transition-all text-slate-800"
style={{ height: '46px', paddingLeft: '44px', paddingRight: '16px', fontSize: '15px' }}
style={{ height: '46px', paddingLeft: '44px', paddingRight: searchQuery ? '40px' : '16px', fontSize: '15px' }}
/>
{searchQuery && (
<button
onClick={() => {
setSearchQuery('');
navigate('/pharmacy', { replace: true });
}}
className="absolute inset-y-0 right-0 flex items-center pr-3 text-slate-400 hover:text-slate-600 transition-colors"
title="Clear search"
type="button"
>
<X size={18} />
</button>
)}
</div>