# Survey Charts Fix - Complete Summary ## Problem Identified The survey response list page had empty charts showing no data, even though survey data existed in the database. ### Root Causes 1. **ApexCharts Series Structure Error** - Bar charts (Engagement Funnel, Completion Time, Score Distribution) had incorrect series structure - They used simple arrays: `series: [18, 2, 7, 6, 29]` - ApexCharts bar charts require: `series: [{name: 'Surveys', data: [18, 2, 7, 6, 29]}]` - This triggered the error: "It is a possibility that you may have not included 'data' property in series" 2. **Messy Django Template Loops in JavaScript** - All chart data was generated using `{% for %}` loops inside JavaScript code - This made the code hard to maintain and debug - Example of old code: ```javascript series: [{% for item in engagement_funnel %}{{ item.count }}{% if not forloop.last %},{% endif %}{% endfor %}] ``` 3. **No Safety Checks for Empty Data** - Charts would try to render even with no data - This caused errors when viewing as users with limited access ## Solution Implemented ### 1. Refactored View to Serialize Data to JSON **File:** `apps/surveys/ui_views.py` Changed from passing multiple arrays to passing JSON-serialized data: ```python # Old way (removed) context = { 'engagement_funnel': engagement_funnel, 'completion_time_distribution': completion_time_distribution, 'device_distribution': device_distribution, 'score_distribution': score_distribution, 'survey_type_labels': survey_type_labels, 'survey_type_counts': survey_type_counts, 'trend_labels': trend_labels, 'trend_sent': trend_sent, 'trend_completed': trend_completed, } # New way import json context = { 'engagement_funnel_json': json.dumps(engagement_funnel), 'completion_time_distribution_json': json.dumps(completion_time_distribution), 'device_distribution_json': json.dumps(device_distribution), 'score_distribution_json': json.dumps(score_distribution), 'survey_types_json': json.dumps(survey_types), 'trend_labels_json': json.dumps(trend_labels), 'trend_sent_json': json.dumps(trend_sent), 'trend_completed_json': json.dumps(trend_completed), } ``` **Benefits:** - Clean separation of concerns - Data is computed once in Python, not multiple times in template - JSON is validated before reaching the browser - Easier to debug (can log JSON in browser console) ### 2. Fixed Bar Chart Series Structure **File:** `templates/surveys/instance_list.html` Fixed all three bar charts to use correct `{name, data}` format: ```javascript // Old (BROKEN) const engagementFunnelOptions = { series: [{% for item in engagement_funnel %}{{ item.count }}{% if not forloop.last %},{% endif %}{% endfor %}], // ... }; // New (FIXED) const engagementFunnelOptions = { series: [{ name: 'Surveys', data: engagementFunnelData.map(item => item.count) }], // ... }; ``` This was applied to: - Engagement Funnel Chart (horizontal bar) - Completion Time Distribution Chart (vertical bar) - Score Distribution Chart (vertical bar) ### 3. Removed All Django Template Loops from JavaScript **Before (messy):** ```javascript series: [{% for item in engagement_funnel %}{{ item.count }}{% if not forloop.last %},{% endif %}{% endfor %}], categories: [{% for item in engagement_funnel %}'{{ item.stage }}'{% if not forloop.last %},{% endif %}{% endfor %}], ``` **After (clean):** ```javascript // Parse JSON data from server const engagementFunnelData = {{ engagement_funnel_json|safe }}; series: [{ name: 'Surveys', data: engagementFunnelData.map(item => item.count) }], categories: engagementFunnelData.map(item => item.stage), ``` **Benefits:** - Pure JavaScript, no Django template syntax - Modern JavaScript array methods (map, filter, etc.) - Much easier to read and maintain - Better IDE support and IntelliSense - Can easily debug in browser console ### 4. Added Safety Checks for Empty Data ```javascript // Helper function to check if data is valid function hasData(data) { return data && data.length > 0 && data.some(item => item.count > 0); } // Only render chart if data exists if (hasData(engagementFunnelData)) { const engagementFunnelOptions = { /* ... */ }; const engagementFunnelChart = new ApexCharts(...); engagementFunnelChart.render(); } ``` **Benefits:** - Prevents errors when viewing as limited users - Charts won't render empty when no data is available - Clean user experience - chart containers simply remain empty ### 5. Fixed Tooltip Formatters Updated all tooltip formatters to use the new JSON data structure: ```javascript // Old tooltip: { y: { formatter: function (value, { series, seriesIndex, dataPointIndex, w }) { var percentages = [{% for item in engagement_funnel %}{{ item.percentage }}{% if not forloop.last %},{% endif %}{% endfor %}]; return value + " surveys (" + percentages[seriesIndex] + "%)"; } } } // New tooltip: { y: { formatter: function (value, { seriesIndex, dataPointIndex }) { return value + " surveys (" + engagementFunnelData[dataPointIndex].percentage + "%)"; } } } ``` ## Charts Fixed 1. ✅ **Engagement Funnel Chart** (Horizontal Bar) - Shows survey progression from sent to completed - Fixed series structure - Clean JSON data 2. ✅ **Completion Time Distribution Chart** (Vertical Bar) - Shows how long users take to complete surveys - Fixed series structure - Clean JSON data 3. ✅ **Device Type Distribution Chart** (Donut) - Shows which devices users use to complete surveys - Already had correct structure - Clean JSON data 4. ✅ **Score Distribution Chart** (Vertical Bar) - Shows distribution of survey scores - Fixed series structure - Clean JSON data 5. ✅ **Survey Types Chart** (Donut) - Shows breakdown by survey type - Already had correct structure - Clean JSON data 6. ✅ **30-Day Trend Chart** (Line) - Shows sent vs completed surveys over time - Already had correct structure - Clean JSON data ## Testing Instructions ### 1. Access the Survey List Page Navigate to: `http://localhost:8000/surveys/instances/` ### 2. Verify Charts Display All six charts should display with actual data: - Engagement Funnel (top left) - Completion Time (top center) - Device Types (top right) - Score Distribution (bottom left) - Survey Types (bottom center) - 30-Day Trend (bottom right) ### 3. Check Browser Console Open browser DevTools (F12) and check console for: - No ApexCharts errors - No JavaScript errors - JSON data objects logged (if you add console.log) ### 4. Test with Different User Roles Test as: - PX Admin (should see all surveys) - Hospital Admin (should see hospital's surveys only) - Hospital User (should see hospital's surveys only) ### 5. Test with Filters Apply different filters to ensure charts update correctly: - Status filter - Survey type filter - Hospital filter - Date range filter ## Files Modified 1. **apps/surveys/ui_views.py** - Refactored to serialize all chart data to JSON - Removed separate arrays for labels and counts - Added JSON serialization using `json.dumps()` 2. **templates/surveys/instance_list.html** - Removed all `{% for %}` loops from JavaScript - Fixed bar chart series structure to `{name, data}` format - Added `hasData()` helper function for safety checks - Updated all chart configurations to use JSON data - Fixed tooltip formatters to use data from JSON objects ## Technical Details ### JSON Data Structure Each chart receives clean JSON arrays of objects: ```json [ { "range": "1-2", "count": 15, "percentage": 25.5 }, { "range": "2-3", "count": 20, "percentage": 34.0 } ] ``` ### ApexCharts Requirements **Bar Charts (vertical/horizontal):** ```javascript { series: [{ name: 'Series Name', data: [value1, value2, value3, ...] }], xaxis: { categories: ['label1', 'label2', 'label3', ...] } } ``` **Donut/Pie Charts:** ```javascript { series: [value1, value2, value3, ...], labels: ['label1', 'label2', 'label3', ...] } ``` **Line Charts:** ```javascript { series: [ { name: 'Series 1', data: [value1, value2, value3, ...] }, { name: 'Series 2', data: [value1, value2, value3, ...] } ], xaxis: { categories: ['label1', 'label2', 'label3', ...] } } ``` ## Benefits of This Fix 1. **No More Empty Charts** - Charts display correctly with actual data 2. **Cleaner Code** - No Django template syntax in JavaScript 3. **Better Maintainability** - Easy to understand and modify 4. **Better Performance** - Data computed once, not multiple times 5. **Better Debugging** - Can inspect JSON in browser console 6. **Safer** - Charts won't crash with empty data 7. **Modern Practices** - Uses modern JavaScript array methods 8. **IDE Friendly** - Better IntelliSense and error detection ## Next Steps 1. Test the survey list page at `http://localhost:8000/surveys/instances/` 2. Verify all six charts display correctly 3. Check browser console for any errors 4. Test with different user roles and filters 5. Review the code changes if desired ## Rollback Plan (if needed) If issues arise, the fix can be easily rolled back by reverting the two modified files: ```bash git checkout HEAD -- apps/surveys/ui_views.py templates/surveys/instance_list.html ``` However, the old code had the charts not working at all, so rolling back would break the charts again.