This commit is contained in:
Jake Kasper
2025-09-04 09:01:54 -05:00
parent 6d20918bb7
commit c9729130fe
2 changed files with 45 additions and 22 deletions

View File

@@ -1174,36 +1174,59 @@ router.get('/stats', async (req, res, next) => {
try {
const { year = new Date().getFullYear() } = req.query;
const statsQuery = `
// Compute plan stats and log stats without FULL JOIN to satisfy Postgres
const combinedStatsQuery = `
WITH log_stats AS (
SELECT
COUNT(DISTINCT al.id) as total_applications,
COUNT(DISTINCT ap.id) as total_plans,
COUNT(DISTINCT CASE WHEN ap.status = 'completed' THEN ap.id END) as completed_plans,
COUNT(DISTINCT CASE WHEN ap.status = 'planned' THEN ap.id END) as planned_applications,
COALESCE(SUM(al.area_covered), 0) as total_area_treated,
COALESCE(AVG(al.average_speed), 0) as avg_application_speed
FROM application_logs al
FULL OUTER JOIN application_plans ap ON al.plan_id = ap.id OR ap.user_id = $1
WHERE EXTRACT(YEAR FROM COALESCE(al.application_date, ap.planned_date)) = $2
AND (al.user_id = $1 OR ap.user_id = $1)
COUNT(*)::int AS total_applications,
COALESCE(SUM(area_covered), 0)::float AS total_area_treated,
COALESCE(AVG(average_speed), 0)::float AS avg_application_speed
FROM application_logs
WHERE user_id = $1
AND EXTRACT(YEAR FROM application_date) = $2
),
plan_stats AS (
SELECT
COUNT(*)::int AS total_plans,
COUNT(*) FILTER (WHERE status = 'completed')::int AS completed_plans,
COUNT(*) FILTER (WHERE status = 'planned')::int AS planned_applications
FROM application_plans
WHERE user_id = $1
AND EXTRACT(YEAR FROM planned_date) = $2
)
SELECT
ls.total_applications,
ps.total_plans,
ps.completed_plans,
ps.planned_applications,
ls.total_area_treated,
ls.avg_application_speed
FROM log_stats ls
CROSS JOIN plan_stats ps;
`;
const statsResult = await pool.query(statsQuery, [req.user.id, year]);
const stats = statsResult.rows[0];
const statsResult = await pool.query(combinedStatsQuery, [req.user.id, year]);
const stats = statsResult.rows[0] || {
total_applications: 0,
total_plans: 0,
completed_plans: 0,
planned_applications: 0,
total_area_treated: 0,
avg_application_speed: 0,
};
// Get monthly breakdown
// Monthly breakdown from logs
const monthlyQuery = `
SELECT
EXTRACT(MONTH FROM al.application_date) as month,
COUNT(*) as applications,
COALESCE(SUM(al.area_covered), 0) as area_covered
EXTRACT(MONTH FROM al.application_date) AS month,
COUNT(*) AS applications,
COALESCE(SUM(al.area_covered), 0) AS area_covered
FROM application_logs al
WHERE al.user_id = $1
AND EXTRACT(YEAR FROM al.application_date) = $2
GROUP BY EXTRACT(MONTH FROM al.application_date)
ORDER BY month
`;
const monthlyResult = await pool.query(monthlyQuery, [req.user.id, year]);
res.json({
@@ -1216,8 +1239,8 @@ router.get('/stats', async (req, res, next) => {
plannedApplications: parseInt(stats.planned_applications) || 0,
totalAreaTreated: parseFloat(stats.total_area_treated) || 0,
avgApplicationSpeed: parseFloat(stats.avg_application_speed) || 0,
completionRate: stats.total_plans > 0 ?
Math.round((stats.completed_plans / stats.total_plans) * 100) : 0
completionRate: (parseInt(stats.total_plans) || 0) > 0 ?
Math.round((parseInt(stats.completed_plans) / parseInt(stats.total_plans)) * 100) : 0
},
monthlyBreakdown: monthlyResult.rows.map(row => ({
month: parseInt(row.month),

View File

@@ -140,8 +140,8 @@ const Dashboard = () => {
const appLogs = (appLogsRes.data?.data?.logs || []).map(l => ({
id: `app-${l.id}`,
type: 'application',
title: `${l.productNames?.length ? 'Applied ' + l.productNames.join(', ') : 'Application'} on ${l.section_names || 'section'}`,
property: l.property_name,
title: `Application on ${l.sectionName || 'section'}`,
property: l.propertyName,
date: l.applicationDate || l.createdAt,
status: 'completed'
}));