import { useEffect, useState } from 'react'
import ItemCard from '../../components/ItemCard/ItemCard.jsx'
import {
inventoryApi,
locationsApi,
searchApi,
} from '../../api/client.js'
import { useAuth } from '../../context/AuthContext.jsx'
import {
filterInventoryItems,
formatAmount,
formatDate,
getExpiryStatus,
} from '../../utils/searchUtils.js'
import { getPaginatedResults } from '../../utils/paginationUtils.js'
import './SearchPage.css'
function ExpiryBadge({ expiryDate }) {
const status = getExpiryStatus(expiryDate)
const badgeClass = status.status === 'Expired'
? 'expiry-expired'
: (status.status === 'Soon' || status.status === 'Today')
? 'expiry-soon'
: 'expiry-fresh'
return (
{formatDate(expiryDate) || 'No expiry date'}
)
}
function SearchPage() {
const { isAuthenticated } = useAuth()
const [searchName, setSearchName] = useState('')
const [locationId, setLocationId] = useState('')
const [minAmount, setMinAmount] = useState('0')
const [maxAmount, setMaxAmount] = useState('999')
const [minExpiryDate, setMinExpiryDate] = useState('')
const [maxExpiryDate, setMaxExpiryDate] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(15)
const [locations, setLocations] = useState([])
const [matchingLocations, setMatchingLocations] = useState([])
const [results, setResults] = useState([])
const [loading, setLoading] = useState(false)
const [errorMessage, setErrorMessage] = useState('')
useEffect(() => {
let cancelled = false
async function loadInitialData() {
if (!isAuthenticated) {
setLocations([])
setMatchingLocations([])
setResults([])
setErrorMessage('')
return
}
setLoading(true)
setErrorMessage('')
try {
const [nextLocations, nextItems] = await Promise.all([
locationsApi.getLocations(),
inventoryApi.getInventoryItems(),
])
if (!cancelled) {
setLocations(nextLocations)
setMatchingLocations([])
setResults(nextItems)
}
} catch (error) {
if (!cancelled) {
setErrorMessage(error.message)
}
} finally {
if (!cancelled) {
setLoading(false)
}
}
}
loadInitialData()
return () => {
cancelled = true
}
}, [isAuthenticated])
async function performSearch() {
const parsedMinAmount = minAmount === '' ? 0 : Number(minAmount)
const parsedMaxAmount = maxAmount === '' ? Infinity : Number(maxAmount)
const safeMinAmount = Number.isFinite(parsedMinAmount) ? parsedMinAmount : 0
const safeMaxAmount = maxAmount === '' || !Number.isFinite(parsedMaxAmount) ? Infinity : parsedMaxAmount
if (minExpiryDate && maxExpiryDate && minExpiryDate > maxExpiryDate) {
alert('Start date cannot be after end date')
return
}
if (safeMinAmount > safeMaxAmount) {
alert('Minimum amount cannot be greater than maximum amount')
return
}
setLoading(true)
setErrorMessage('')
try {
const trimmedQuery = searchName.trim()
const [nextItems, nextMatchingLocations] = trimmedQuery
? await Promise.all([
searchApi.searchItems(trimmedQuery),
searchApi.searchLocations(trimmedQuery),
])
: await Promise.all([
inventoryApi.getInventoryItems(),
Promise.resolve([]),
])
const filteredItems = filterInventoryItems(nextItems, {
locationId,
minAmount: safeMinAmount,
maxAmount: safeMaxAmount,
minExpiryDate,
maxExpiryDate,
})
setCurrentPage(1)
setResults(filteredItems)
setMatchingLocations(nextMatchingLocations)
} catch (error) {
setErrorMessage(error.message)
} finally {
setLoading(false)
}
}
async function resetForm() {
setSearchName('')
setLocationId('')
setMinAmount('0')
setMaxAmount('999')
setMinExpiryDate('')
setMaxExpiryDate('')
setCurrentPage(1)
setPageSize(15)
setMatchingLocations([])
setErrorMessage('')
if (!isAuthenticated) {
setResults([])
return
}
setLoading(true)
try {
const [nextLocations, nextItems] = await Promise.all([
locationsApi.getLocations(),
inventoryApi.getInventoryItems(),
])
setLocations(nextLocations)
setResults(nextItems)
} catch (error) {
setErrorMessage(error.message)
} finally {
setLoading(false)
}
}
const paginationData = getPaginatedResults(results, currentPage, pageSize)
return (
<>
Search Inventory
{!isAuthenticated ? (
Sign in on the dashboard before using the protected item and location search endpoints.
) : (
<>
{errorMessage && {errorMessage}
}
{loading && Searching the API...
}
setSearchName(event.target.value)}
onKeyDown={event => {
if (event.key === 'Enter') {
event.preventDefault()
performSearch()
}
}}
/>
{searchName.trim() && (
Matching Locations
{matchingLocations.length === 0 ? (
No locations matched that query.
) : (
{matchingLocations.map(location => (
{location.name}
{location.description || 'No description provided.'}
))}
)}
)}
{results.length === 0
? 'No results'
: `Found ${results.length} item${results.length !== 1 ? 's' : ''} (showing ${paginationData.startIndex}-${paginationData.endIndex})`
}
Page {paginationData.currentPage} of {paginationData.totalPages}
{results.length === 0 ? (
No items found matching your search criteria.
) : (
{paginationData.items.map(item => (
))}
)}
>
)}
>
)
}
export default SearchPage