Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions backend/controllers/patientController.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,18 @@ const getAllPatients = async (req, res) => {
l.risk_score, l.risk_category, l.top_factors,
l.confidence_low, l.confidence_medium, l.confidence_high,
l.low_confidence,
prev.risk_category AS previous_risk_category
prev.risk_category AS previous_risk_category,
(
SELECT JSON_ARRAYAGG(s.risk_score)
FROM (
SELECT risk_score, visit_date
FROM visits
WHERE patient_id = p.patient_id
AND risk_score IS NOT NULL
ORDER BY visit_date ASC
LIMIT 5
) s
) AS sparkline
Comment thread
deshanekanayaka marked this conversation as resolved.
FROM patients p
INNER JOIN latest l ON p.patient_id = l.patient_id
LEFT JOIN previous prev ON p.patient_id = prev.patient_id
Expand All @@ -208,6 +219,12 @@ const getAllPatients = async (req, res) => {
const patients = rows.map((row) => {
parseTopFactors(row);

// Parse sparkline: MySQL returns JSON_ARRAYAGG result as a string
if (typeof row.sparkline === 'string') {
try { row.sparkline = JSON.parse(row.sparkline); } catch { row.sparkline = []; }
}
if (!Array.isArray(row.sparkline)) row.sparkline = [];

let trend = 'stable';
if (row.previous_risk_category) {
const curr = riskOrder[row.risk_category] ?? -1;
Expand Down Expand Up @@ -511,4 +528,4 @@ const createVisit = async (req, res) => {
}
};

export { createPatient, getAllPatients, getPatientById, updatePatient, deletePatient, createVisit };
export { createPatient, getAllPatients, getPatientById, updatePatient, deletePatient, createVisit };
6 changes: 6 additions & 0 deletions backend/logs/error.log
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@
{"level":"error","message":"Error fetching patients: Unknown column 'v.risk_score' in 'order clause'","timestamp":"2026-06-03T21:07:33.971Z"}
{"code":"ER_BAD_FIELD_ERROR","errno":1054,"level":"error","message":"Analytics query error: Unknown column 'age' in 'field list'","sql":"SELECT\n CASE\n WHEN age BETWEEN 20 AND 29 THEN '20-29'\n WHEN age BETWEEN 30 AND 39 THEN '30-39'\n WHEN age BETWEEN 40 AND 49 THEN '40-49'\n WHEN age BETWEEN 50 AND 59 THEN '50-59'\n WHEN age BETWEEN 60 AND 69 THEN '60-69'\n -- Catches all patients aged 70 and older\n WHEN age >= 70 THEN '70+'\n -- Fallback for ages outside the expected range\n ELSE 'Other'\n END AS age_group,\n -- Included so the chart can stack bars by severity\n risk_category,\n COUNT(*) AS count\n FROM patients\n -- Scopes results to only this clinician's patients\n WHERE clerk_id = 'user_3EY91m497QY2YDIvkDsJnaIiKdw'\n -- One row per unique age group and risk level pair\n GROUP BY age_group, risk_category\n ORDER BY age_group","sqlMessage":"Unknown column 'age' in 'field list'","sqlState":"42S22","stack":"Error: Unknown column 'age' in 'field list'\n at PromisePool.query (/Users/deshan/Documents/diacify/backend/node_modules/mysql2/lib/promise/pool.js:36:22)\n at query (file:///Users/deshan/Documents/diacify/backend/config/database.js:46:36)\n at getAnalytics (file:///Users/deshan/Documents/diacify/backend/controllers/analyticsController.js:16:39)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:149:13)\n at Route.dispatch (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:119:3)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at /Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:284:15\n at router.process_params (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:346:12)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:280:10)"}
{"code":"ER_BAD_FIELD_ERROR","errno":1054,"level":"error","message":"Analytics query error: Unknown column 'age' in 'field list'","sql":"SELECT\n CASE\n WHEN age BETWEEN 20 AND 29 THEN '20-29'\n WHEN age BETWEEN 30 AND 39 THEN '30-39'\n WHEN age BETWEEN 40 AND 49 THEN '40-49'\n WHEN age BETWEEN 50 AND 59 THEN '50-59'\n WHEN age BETWEEN 60 AND 69 THEN '60-69'\n -- Catches all patients aged 70 and older\n WHEN age >= 70 THEN '70+'\n -- Fallback for ages outside the expected range\n ELSE 'Other'\n END AS age_group,\n -- Included so the chart can stack bars by severity\n risk_category,\n COUNT(*) AS count\n FROM patients\n -- Scopes results to only this clinician's patients\n WHERE clerk_id = 'user_3EY91m497QY2YDIvkDsJnaIiKdw'\n -- One row per unique age group and risk level pair\n GROUP BY age_group, risk_category\n ORDER BY age_group","sqlMessage":"Unknown column 'age' in 'field list'","sqlState":"42S22","stack":"Error: Unknown column 'age' in 'field list'\n at PromisePool.query (/Users/deshan/Documents/diacify/backend/node_modules/mysql2/lib/promise/pool.js:36:22)\n at query (file:///Users/deshan/Documents/diacify/backend/config/database.js:46:36)\n at getAnalytics (file:///Users/deshan/Documents/diacify/backend/controllers/analyticsController.js:16:39)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:149:13)\n at Route.dispatch (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:119:3)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at /Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:284:15\n at router.process_params (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:346:12)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:280:10)"}
{"level":"error","message":"Error fetching patients: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ORDER BY s.visit_date ASC)\n FROM (\n SELECT risk_score, visit' at line 27","timestamp":"2026-06-04T19:41:37.526Z"}
{"level":"error","message":"Error fetching patients: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ORDER BY s.visit_date ASC)\n FROM (\n SELECT risk_score, visit' at line 27","timestamp":"2026-06-04T19:41:37.531Z"}
{"level":"error","message":"Error fetching patients: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ORDER BY s.visit_date ASC)\n FROM (\n SELECT risk_score, visit' at line 27","timestamp":"2026-06-04T19:41:54.828Z"}
{"level":"error","message":"Error fetching patients: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ORDER BY s.visit_date ASC)\n FROM (\n SELECT risk_score, visit' at line 27","timestamp":"2026-06-04T19:41:54.832Z"}
{"code":"ER_BAD_FIELD_ERROR","errno":1054,"level":"error","message":"Analytics query error: Unknown column 'age' in 'field list'","sql":"SELECT\n CASE\n WHEN age BETWEEN 20 AND 29 THEN '20-29'\n WHEN age BETWEEN 30 AND 39 THEN '30-39'\n WHEN age BETWEEN 40 AND 49 THEN '40-49'\n WHEN age BETWEEN 50 AND 59 THEN '50-59'\n WHEN age BETWEEN 60 AND 69 THEN '60-69'\n -- Catches all patients aged 70 and older\n WHEN age >= 70 THEN '70+'\n -- Fallback for ages outside the expected range\n ELSE 'Other'\n END AS age_group,\n -- Included so the chart can stack bars by severity\n risk_category,\n COUNT(*) AS count\n FROM patients\n -- Scopes results to only this clinician's patients\n WHERE clerk_id = 'user_3EY91m497QY2YDIvkDsJnaIiKdw'\n -- One row per unique age group and risk level pair\n GROUP BY age_group, risk_category\n ORDER BY age_group","sqlMessage":"Unknown column 'age' in 'field list'","sqlState":"42S22","stack":"Error: Unknown column 'age' in 'field list'\n at PromisePool.query (/Users/deshan/Documents/diacify/backend/node_modules/mysql2/lib/promise/pool.js:36:22)\n at query (file:///Users/deshan/Documents/diacify/backend/config/database.js:46:36)\n at getAnalytics (file:///Users/deshan/Documents/diacify/backend/controllers/analyticsController.js:16:39)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:149:13)\n at Route.dispatch (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:119:3)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at /Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:284:15\n at router.process_params (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:346:12)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:280:10)"}
{"code":"ER_BAD_FIELD_ERROR","errno":1054,"level":"error","message":"Analytics query error: Unknown column 'age' in 'field list'","sql":"SELECT\n CASE\n WHEN age BETWEEN 20 AND 29 THEN '20-29'\n WHEN age BETWEEN 30 AND 39 THEN '30-39'\n WHEN age BETWEEN 40 AND 49 THEN '40-49'\n WHEN age BETWEEN 50 AND 59 THEN '50-59'\n WHEN age BETWEEN 60 AND 69 THEN '60-69'\n -- Catches all patients aged 70 and older\n WHEN age >= 70 THEN '70+'\n -- Fallback for ages outside the expected range\n ELSE 'Other'\n END AS age_group,\n -- Included so the chart can stack bars by severity\n risk_category,\n COUNT(*) AS count\n FROM patients\n -- Scopes results to only this clinician's patients\n WHERE clerk_id = 'user_3EY91m497QY2YDIvkDsJnaIiKdw'\n -- One row per unique age group and risk level pair\n GROUP BY age_group, risk_category\n ORDER BY age_group","sqlMessage":"Unknown column 'age' in 'field list'","sqlState":"42S22","stack":"Error: Unknown column 'age' in 'field list'\n at PromisePool.query (/Users/deshan/Documents/diacify/backend/node_modules/mysql2/lib/promise/pool.js:36:22)\n at query (file:///Users/deshan/Documents/diacify/backend/config/database.js:46:36)\n at getAnalytics (file:///Users/deshan/Documents/diacify/backend/controllers/analyticsController.js:16:39)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:149:13)\n at Route.dispatch (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/route.js:119:3)\n at Layer.handle [as handle_request] (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/layer.js:95:5)\n at /Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:284:15\n at router.process_params (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:346:12)\n at next (/Users/deshan/Documents/diacify/backend/node_modules/express/lib/router/index.js:280:10)"}
26 changes: 12 additions & 14 deletions frontend/src/components/PriorityTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,17 @@ const PriorityTable = ({ patients = [], loading, error, onRefresh }) => {

const riskCategory = (rc) => (rc || '').toLowerCase();

const formatDate = (iso) => {
if (!iso) return '—';
const d = new Date(iso);
if (isNaN(d.getTime())) return '—';
const dd = String(d.getDate()).padStart(2, '0');
const mm = String(d.getMonth() + 1).padStart(2, '0');
const yyyy = d.getFullYear();
return `${dd}/${mm}/${yyyy}`;
};
const formatDate = (iso) => {
if (!iso) return '—';
const d = new Date(iso);
if (isNaN(d.getTime())) return '—';
const dd = String(d.getDate()).padStart(2, '0');
const mm = String(d.getMonth() + 1).padStart(2, '0');
const yyyy = d.getFullYear();
return `${dd}/${mm}/${yyyy}`;
};

const riskTextClass = (cat) => riskColorClass(cat === 'high' || cat === 'medium' || cat === 'low' ? cat : 'low').text;
const riskTextClass = (cat) => riskColorClass(cat === 'high' || cat === 'medium' || cat === 'low' ? cat : 'low').text;

return (
<>
Expand Down Expand Up @@ -205,14 +205,13 @@ const PriorityTable = ({ patients = [], loading, error, onRefresh }) => {
{!loading && !error && (
<div className="p-2">
<Table>
{/* item 6 */}
<TableHeader>
<TableRow>
<TableHead className="w-35 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3">PATIENT ID</TableHead>
<TableHead className="w-20 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3">AGE</TableHead>
<TableHead className="w-25 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3">SEX</TableHead>
<TableHead className="w-40 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3">LAST VISIT</TableHead>
<TableHead className="w-50 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3">RISK SCORE</TableHead>
<TableHead className="w-50 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3 text-left">RISK SCORE</TableHead>
<TableHead className="w-30 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3">RISK</TableHead>
<TableHead className="w-20 bg-gray-50 text-xs font-bold text-gray-600 uppercase tracking-wider border-b border-gray-200 px-4 py-3 text-right pr-4">ACTIONS</TableHead>
</TableRow>
Expand Down Expand Up @@ -251,7 +250,6 @@ const PriorityTable = ({ patients = [], loading, error, onRefresh }) => {
<EllipsisVertical className="h-5 w-5" />
</button>
</DropdownMenuTrigger>
{/* item 12 */}
<DropdownMenuContent
align="end"
sideOffset={4}
Expand Down Expand Up @@ -324,4 +322,4 @@ const PriorityTable = ({ patients = [], loading, error, onRefresh }) => {
);
};

export default PriorityTable;
export default PriorityTable;
Loading