curl --request GET \
--url https://api.example.com/api/stats/expiry-trends \
--header 'Authorization: <authorization>'{
"date": "<string>",
"expiring": 123,
"consumed": 123,
"wasted_cost": 123
}Retrieve detailed expiry trends with consumption patterns and waste cost estimates
curl --request GET \
--url https://api.example.com/api/stats/expiry-trends \
--header 'Authorization: <authorization>'{
"date": "<string>",
"expiring": 123,
"consumed": 123,
"wasted_cost": 123
}Bearer YOUR_ACCESS_TOKENYYYY-MM-DD format[
{
"date": "2026-03-01",
"expiring": 10,
"consumed": 6,
"wasted_cost": 200.0
},
{
"date": "2026-03-02",
"expiring": 8,
"consumed": 5,
"wasted_cost": 150.0
},
{
"date": "2026-03-03",
"expiring": 15,
"consumed": 9,
"wasted_cost": 300.0
}
]
[]
{
"detail": "Authorization header missing or invalid."
}
curl -X GET "https://api.expireeye.com/api/stats/expiry-trends" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const accessToken = "your-jwt-token";
fetch("https://api.expireeye.com/api/stats/expiry-trends", {
method: "GET",
headers: {
"Authorization": `Bearer ${accessToken}`,
},
})
.then(response => response.json())
.then(data => {
const totalExpiring = data.reduce((sum, item) => sum + item.expiring, 0);
const totalConsumed = data.reduce((sum, item) => sum + item.consumed, 0);
const totalWasteCost = data.reduce((sum, item) => sum + item.wasted_cost, 0);
console.log(`Total expiring: ${totalExpiring}`);
console.log(`Total consumed: ${totalConsumed}`);
console.log(`Total waste cost: $${totalWasteCost}`);
console.log(`Consumption rate: ${((totalConsumed / totalExpiring) * 100).toFixed(1)}%`);
})
.catch(error => console.error("Error:", error));
import requests
from datetime import datetime
access_token = "your-jwt-token"
url = "https://api.expireeye.com/api/stats/expiry-trends"
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
if data:
total_expiring = sum(item["expiring"] for item in data)
total_consumed = sum(item["consumed"] for item in data)
total_waste_cost = sum(item["wasted_cost"] for item in data)
consumption_rate = (total_consumed / total_expiring * 100) if total_expiring > 0 else 0
print(f"Total expiring items: {total_expiring}")
print(f"Total consumed: {total_consumed}")
print(f"Consumption rate: {consumption_rate:.1f}%")
print(f"Total waste cost: ${total_waste_cost:.2f}")
# Find worst day
worst_day = max(data, key=lambda x: x["wasted_cost"])
print(f"\nWorst waste day: {worst_day['date']}")
print(f"Waste cost on that day: ${worst_day['wasted_cost']:.2f}")
else:
print("No expiry trend data available")
else:
print(f"Error: {response.status_code}")
import { useEffect, useState } from 'react';
import {
LineChart,
Line,
BarChart,
Bar,
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
ComposedChart,
} from 'recharts';
import axios from 'axios';
interface ExpiryTrendItem {
date: string;
expiring: number;
consumed: number;
wasted_cost: number;
}
function ExpiryTrendsChart({ accessToken }: { accessToken: string }) {
const [data, setData] = useState<ExpiryTrendItem[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
axios
.get<ExpiryTrendItem[]>('https://api.expireeye.com/api/stats/expiry-trends', {
headers: { Authorization: `Bearer ${accessToken}` },
})
.then(response => {
setData(response.data);
})
.finally(() => setLoading(false));
}, [accessToken]);
if (loading) return <div>Loading trends...</div>;
if (data.length === 0) return <div>No trend data available</div>;
return (
<div className="space-y-8">
{/* Combined Chart: Bars (expiring) + Line (consumed) + Area (waste cost) */}
<div>
<h3 className="text-lg font-semibold mb-4">Expiry Trends Overview</h3>
<ResponsiveContainer width="100%" height={400}>
<ComposedChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis yAxisId="left" />
<YAxis yAxisId="right" orientation="right" />
<Tooltip />
<Legend />
<Bar yAxisId="left" dataKey="expiring" fill="#8884d8" name="Expiring Items" />
<Line
yAxisId="left"
type="monotone"
dataKey="consumed"
stroke="#82ca9d"
name="Consumed Before Expiry"
/>
<Area
yAxisId="right"
type="monotone"
dataKey="wasted_cost"
fill="#ff6b6b"
stroke="#ff6b6b"
fillOpacity={0.3}
name="Waste Cost ($)"
/>
</ComposedChart>
</ResponsiveContainer>
</div>
{/* Summary Statistics */}
<div className="grid grid-cols-4 gap-4">
<div className="bg-white p-4 rounded-lg shadow">
<p className="text-sm text-gray-600">Total Expiring</p>
<p className="text-2xl font-bold">
{data.reduce((sum, item) => sum + item.expiring, 0)}
</p>
</div>
<div className="bg-white p-4 rounded-lg shadow">
<p className="text-sm text-gray-600">Total Consumed</p>
<p className="text-2xl font-bold text-green-600">
{data.reduce((sum, item) => sum + item.consumed, 0)}
</p>
</div>
<div className="bg-white p-4 rounded-lg shadow">
<p className="text-sm text-gray-600">Consumption Rate</p>
<p className="text-2xl font-bold text-blue-600">
{(
(data.reduce((sum, item) => sum + item.consumed, 0) /
data.reduce((sum, item) => sum + item.expiring, 0)) *
100
).toFixed(1)}
%
</p>
</div>
<div className="bg-white p-4 rounded-lg shadow">
<p className="text-sm text-gray-600">Total Waste Cost</p>
<p className="text-2xl font-bold text-red-600">
${data.reduce((sum, item) => sum + item.wasted_cost, 0).toFixed(2)}
</p>
</div>
</div>
</div>
);
}
expired items × $50 (fixed mock cost per item)consumed field is a simulated estimate based on a random uniform distribution (0.4 to 0.8). In a production environment, this should be replaced with actual consumption tracking data.wasted_cost uses a fixed mock value of $50 per item. Implement actual cost tracking by storing purchase prices or average market values for more accurate waste cost calculations.