Phase 5 frontend - #14
Merged
Merged
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed data correctness and UI-state bugs (month bucketing across years, negative progress width, duplicated velocity labels, and a detail-loading race) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds the Phase 5 “real data” wiring for the frontend approvals and analytics experience, replacing mock-driven UI components with API-backed pages/cards and extending backend analytics to support the new charts.
Changes:
- Introduces an employee-only “My Approvals” page that lists submitted expenses and expands to show approval timeline/stepper details.
- Updates analytics dashboard + chart components to consume backend-provided datasets (risk trend, approval rate, monthly velocity, turnaround time).
- Extends backend analytics queries/controllers and adds an authorization check to protect expense approval-status visibility for employees.
File summaries
| File | Description |
|---|---|
| frontend/src/pages/MyApprovalsPage.jsx | New page to list employee expenses and fetch/display approval status timeline per expense. |
| frontend/src/pages/AnalyticsPage.jsx | Wires analytics API response fields into chart components via props. |
| frontend/src/features/expense/components/RecentSpendingCards.jsx | Replaces mock recent spending with live /expenses data and basic loading/empty states. |
| frontend/src/features/analytics/components/TurnaroundTimeCard.jsx | Switches from mock to prop-driven turnaround time display. |
| frontend/src/features/analytics/components/SpendByCategoryChart.jsx | Switches from mock to prop-driven category spend pie chart with empty-state. |
| frontend/src/features/analytics/components/RiskScoreTrendChart.jsx | Switches from mock to prop-driven risk trend line chart with empty-state. |
| frontend/src/features/analytics/components/MonthlyVelocityChart.jsx | Switches from mock to prop-driven velocity bar chart with empty-state. |
| frontend/src/features/analytics/components/ApprovalRateChart.jsx | Switches from mock to prop-driven approval rate bar chart with empty-state. |
| frontend/src/components/layout/AppLayout.jsx | Adds “My Approvals” navigation entry for employees. |
| frontend/src/app/router.jsx | Adds protected route for /my-approvals (employee-only). |
| frontend/src/api/expenseService.js | Adds getApprovalStatus() API helper and normalizes formatting. |
| backend/src/modules/expenses/expenses.controller.js | Prevents employees from viewing approval status of other users’ expenses. |
| backend/src/modules/analytics/analytics.model.js | Adds model methods for new analytics datasets. |
| backend/src/modules/analytics/analytics.controller.js | Extends analytics summary endpoint to return new datasets. |
| backend/src/db/queries/analytics/analytics.queries.js | Adds SQL queries for turnaround time, risk trend, approval rate, and monthly velocity. |
Review details
Suppressed comments (1)
backend/src/db/queries/analytics/analytics.queries.js:39
- This query also buckets by month name/month number only, which will merge results across years and sort incorrectly for multi-year datasets. Group/order by date_trunc('month', submitted_at) instead and format the label from that date.
approvalRate: `
SELECT
TO_CHAR(submitted_at, 'Mon') AS month,
EXTRACT(MONTH FROM submitted_at) AS month_num,
COUNT(*) FILTER (WHERE status = 'approved') AS approved,
- Files reviewed: 15/15 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+23
to
+34
| riskTrend: ` | ||
| SELECT | ||
| TO_CHAR(submitted_at, 'Mon') AS month, | ||
| EXTRACT(MONTH FROM submitted_at) AS month_num, | ||
| COUNT(*) FILTER (WHERE converted_amount < 1000) AS low, | ||
| COUNT(*) FILTER (WHERE converted_amount >= 1000 AND converted_amount < 5000) AS medium, | ||
| COUNT(*) FILTER (WHERE converted_amount >= 5000) AS high | ||
| FROM expenses | ||
| WHERE company_id = $1 | ||
| GROUP BY month, month_num | ||
| ORDER BY month_num | ||
| `, |
Comment on lines
+4
to
+7
| const chartData = data.map((item) => ({ | ||
| day: item.day, | ||
| amount: Number(item.amount || 0), | ||
| })); |
Comment on lines
33
to
35
| className="h-full bg-gradient-to-r from-neon to-forest-500 rounded-full transition-all duration-1000" | ||
| style={{ width: `${(1 - averageDays / 7) * 100}%` }} | ||
| style={{ width: `${Math.min((1 - days / 7) * 100, 100)}%` }} | ||
| /> |
Comment on lines
+33
to
+35
| }) | ||
| .catch(() => {}) | ||
| .finally(() => active && setLoading(false)); |
Comment on lines
+71
to
+75
| if (!detailCache[id]) { | ||
| setDetailLoading(true); | ||
| try { | ||
| const detail = await getApprovalStatus(id); | ||
| setDetailCache((prev) => ({ ...prev, [id]: detail })); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.