724 lines
28 KiB
HTML
724 lines
28 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ _("Survey Instances")}} - PX360{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.border-left-primary {
|
|
border-left: 4px solid var(--hh-primary) !important;
|
|
}
|
|
.border-left-success {
|
|
border-left: 4px solid var(--hh-success) !important;
|
|
}
|
|
.border-left-warning {
|
|
border-left: 4px solid var(--hh-warning) !important;
|
|
}
|
|
.border-left-danger {
|
|
border-left: 4px solid var(--hh-accent) !important;
|
|
}
|
|
.border-left-info {
|
|
border-left: 4px solid var(--hh-primary-light) !important;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h2 class="mb-1">
|
|
<i class="bi bi-clipboard-data text-info me-2"></i>
|
|
{{ _("Survey Instances")}}
|
|
</h2>
|
|
<p class="text-muted mb-0">{{ _("Monitor survey responses and scores")}}</p>
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#filtersModal">
|
|
<i class="bi bi-funnel me-1"></i> {% trans "Filters" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Enhanced Statistics Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-primary">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Total Surveys" %}</div>
|
|
<div class="stat-value">{{ stats.total }}</div>
|
|
<div class="stat-trend text-muted">
|
|
<i class="bi bi-clipboard-data"></i> {% trans "All surveys" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-info">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Opened" %}</div>
|
|
<div class="stat-value">{{ stats.opened }}</div>
|
|
<div class="stat-trend text-info">
|
|
<i class="bi bi-eye"></i> {{ stats.open_rate }}% {% trans "open rate" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-success">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Completed" %}</div>
|
|
<div class="stat-value">{{ stats.completed }}</div>
|
|
<div class="stat-trend text-success">
|
|
<i class="bi bi-check-circle"></i> {{ stats.response_rate }}% {% trans "response rate" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-danger">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Negative" %}</div>
|
|
<div class="stat-value text-danger">{{ stats.negative }}</div>
|
|
<div class="stat-trend text-danger">
|
|
<i class="bi bi-exclamation-triangle"></i> {% trans "Need attention" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Secondary Statistics Row -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-warning">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "In Progress" %}</div>
|
|
<div class="stat-value">{{ stats.in_progress }}</div>
|
|
<div class="stat-trend text-warning">
|
|
<i class="bi bi-hourglass-split"></i> {% trans "Started but not completed" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-secondary">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Viewed" %}</div>
|
|
<div class="stat-value">{{ stats.viewed }}</div>
|
|
<div class="stat-trend text-secondary">
|
|
<i class="bi bi-eye"></i> {% trans "Opened but not started" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-danger">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Abandoned" %}</div>
|
|
<div class="stat-value">{{ stats.abandoned }}</div>
|
|
<div class="stat-trend text-danger">
|
|
<i class="bi bi-x-circle"></i> {% trans "Left incomplete" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-card border-left-success">
|
|
<div class="card-body">
|
|
<div class="stat-label">{% trans "Avg Completion Time" %}</div>
|
|
<div class="stat-value">{{ stats.avg_completion_time }}s</div>
|
|
<div class="stat-trend text-success">
|
|
<i class="bi bi-clock"></i> {% trans "Average time to complete" %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row -->
|
|
<div class="row mb-4">
|
|
<!-- Engagement Funnel Chart -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-funnel text-info me-2"></i>
|
|
{% trans "Engagement Funnel" %}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="engagementFunnelChart" style="min-height: 250px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Completion Time Distribution -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-clock-history text-success me-2"></i>
|
|
{% trans "Completion Time" %}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="completionTimeChart" style="min-height: 250px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Device Type Distribution -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-device text-primary me-2"></i>
|
|
{% trans "Device Types" %}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="deviceTypeChart" style="min-height: 250px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Secondary Charts Row -->
|
|
<div class="row mb-4">
|
|
<!-- Score Distribution Chart -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-bar-chart text-info me-2"></i>
|
|
{% trans "Score Distribution" %}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="scoreDistributionChart" style="min-height: 250px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Survey Type Distribution -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-pie-chart text-success me-2"></i>
|
|
{% trans "Survey Types" %}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="surveyTypeChart" style="min-height: 250px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Survey Trend -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-graph-up text-primary me-2"></i>
|
|
{% trans "30-Day Trend" %}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="surveyTrendChart" style="min-height: 250px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Surveys Table -->
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h6 class="card-title mb-0">
|
|
<i class="bi bi-table me-2"></i>
|
|
{% trans "Survey List" %}
|
|
</h6>
|
|
<div class="text-muted">
|
|
<small>{% trans "Showing" %} {{ page_obj.start_index }}-{% trans "end" %} {{ page_obj.end_index }} {% trans "of" %} {{ page_obj.paginator.count }}</small>
|
|
</div>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>{% trans "Patient" %}</th>
|
|
<th>{% trans "Survey Template" %}</th>
|
|
<th>{% trans "Type" %}</th>
|
|
<th>{% trans "Status" %}</th>
|
|
<th>{% trans "Score" %}</th>
|
|
<th>{% trans "Sent" %}</th>
|
|
<th>{% trans "Completed" %}</th>
|
|
<th>{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for survey in surveys %}
|
|
<tr onclick="window.location='{% url 'surveys:instance_detail' survey.id %}'" style="cursor: pointer;">
|
|
<td>
|
|
<strong>{{ survey.patient.get_full_name }}</strong><br>
|
|
<small class="text-muted">MRN: {{ survey.patient.mrn }}</small>
|
|
</td>
|
|
<td>
|
|
<div class="fw-semibold">{{ survey.survey_template.name }}</div>
|
|
{% if survey.survey_template.hospital %}
|
|
<small class="text-muted">{{ survey.survey_template.hospital.name }}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<span class="badge badge-soft-primary">{{ survey.survey_template.get_survey_type_display }}</span>
|
|
</td>
|
|
<td>
|
|
{% if survey.status == 'completed' %}
|
|
<span class="badge bg-success">{{ survey.get_status_display }}</span>
|
|
{% elif survey.status == 'sent' %}
|
|
<span class="badge bg-warning">{{ survey.get_status_display }}</span>
|
|
{% elif survey.status == 'active' %}
|
|
<span class="badge bg-info">{{ survey.get_status_display }}</span>
|
|
{% elif survey.status == 'cancelled' %}
|
|
<span class="badge bg-danger">{{ survey.get_status_display }}</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">{{ survey.get_status_display }}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if survey.total_score %}
|
|
<div class="d-flex align-items-center">
|
|
<strong class="{% if survey.is_negative %}text-danger{% else %}text-success{% endif %} me-2">
|
|
{{ survey.total_score|floatformat:1 }}/5.0
|
|
</strong>
|
|
{% if survey.is_negative %}
|
|
<i class="bi bi-exclamation-circle text-danger" title="{% trans 'Negative survey' %}"></i>
|
|
{% endif %}
|
|
</div>
|
|
{% else %}
|
|
<span class="text-muted">-</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if survey.sent_at %}
|
|
<small>{{ survey.sent_at|date:"M d, Y H:i" }}</small>
|
|
{% else %}
|
|
<span class="text-muted">-</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if survey.completed_at %}
|
|
<small>{{ survey.completed_at|date:"M d, Y H:i" }}</small>
|
|
{% else %}
|
|
<span class="text-muted">-</span>
|
|
{% endif %}
|
|
</td>
|
|
<td onclick="event.stopPropagation();">
|
|
<a href="{% url 'surveys:instance_detail' survey.id %}"
|
|
class="btn btn-sm btn-outline-primary"
|
|
title="{% trans 'View details' %}">
|
|
<i class="bi bi-eye"></i>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="8" class="text-center py-5">
|
|
<i class="bi bi-inbox" style="font-size: 3rem; color: #ccc;"></i>
|
|
<p class="text-muted mt-3">{{ _("No surveys found")}}</p>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% if page_obj.has_other_pages %}
|
|
<nav aria-label="Surveys pagination" class="mt-4">
|
|
<ul class="pagination justify-content-center">
|
|
{% if page_obj.has_previous %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
|
|
<i class="bi bi-chevron-left"></i>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% for num in page_obj.paginator.page_range %}
|
|
{% if page_obj.number == num %}
|
|
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ num }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
|
|
{{ num }}
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if page_obj.has_next %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
|
|
<i class="bi bi-chevron-right"></i>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Filters Modal -->
|
|
<div class="modal fade" id="filtersModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
<i class="bi bi-funnel me-2"></i>{% trans "Filter Surveys" %}
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form method="get" id="filtersForm">
|
|
<div class="mb-3">
|
|
<label class="form-label">{% trans "Status" %}</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">{% trans "All Statuses" %}</option>
|
|
<option value="sent" {% if filters.status == 'sent' %}selected{% endif %}>{% trans "Sent" %}</option>
|
|
<option value="completed" {% if filters.status == 'completed' %}selected{% endif %}>{% trans "Completed" %}</option>
|
|
<option value="pending" {% if filters.status == 'pending' %}selected{% endif %}>{% trans "Pending" %}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">{% trans "Survey Type" %}</label>
|
|
<select name="survey_type" class="form-select">
|
|
<option value="">{% trans "All Types" %}</option>
|
|
<option value="stage" {% if filters.survey_type == 'stage' %}selected{% endif %}>{% trans "Journey Stage" %}</option>
|
|
<option value="complaint_resolution" {% if filters.survey_type == 'complaint_resolution' %}selected{% endif %}>{% trans "Complaint Resolution" %}</option>
|
|
<option value="general" {% if filters.survey_type == 'general' %}selected{% endif %}>{% trans "General" %}</option>
|
|
<option value="nps" {% if filters.survey_type == 'nps' %}selected{% endif %}>{% trans "NPS" %}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">{% trans "Hospital" %}</label>
|
|
<select name="hospital" class="form-select">
|
|
<option value="">{% trans "All Hospitals" %}</option>
|
|
{% for hospital in hospitals %}
|
|
<option value="{{ hospital.id }}" {% if filters.hospital|add:"0" == hospital.id %}selected{% endif %}>
|
|
{{ hospital.name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">
|
|
<input type="checkbox" name="is_negative" value="true" {% if filters.is_negative == 'true' %}checked{% endif %}>
|
|
{% trans "Negative Surveys Only" %}
|
|
</label>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">{% trans "Date From" %}</label>
|
|
<input type="date" name="date_from" class="form-control" value="{{ filters.date_from }}">
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">{% trans "Date To" %}</label>
|
|
<input type="date" name="date_to" class="form-control" value="{{ filters.date_to }}">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">{% trans "Search" %}</label>
|
|
<input type="text" name="search" class="form-control" placeholder="MRN, Name, Encounter" value="{{ filters.search }}">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<a href="{% url 'surveys:instance_list' %}" class="btn btn-secondary">{% trans "Clear" %}</a>
|
|
<button type="submit" form="filtersForm" class="btn btn-primary">
|
|
<i class="bi bi-check me-1"></i>{% trans "Apply Filters" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
// Parse JSON data from server
|
|
const engagementFunnelData = {{ engagement_funnel_json|safe }};
|
|
const completionTimeData = {{ completion_time_distribution_json|safe }};
|
|
const deviceDistributionData = {{ device_distribution_json|safe }};
|
|
const scoreDistributionData = {{ score_distribution_json|safe }};
|
|
const surveyTypesData = {{ survey_types_json|safe }};
|
|
const trendLabels = {{ trend_labels_json|safe }};
|
|
const trendSent = {{ trend_sent_json|safe }};
|
|
const trendCompleted = {{ trend_completed_json|safe }};
|
|
|
|
// Helper function to check if data is valid
|
|
function hasData(data) {
|
|
return data && data.length > 0 && data.some(item => item.count > 0);
|
|
}
|
|
|
|
// Engagement Funnel Chart (Horizontal Bar)
|
|
if (hasData(engagementFunnelData)) {
|
|
const engagementFunnelOptions = {
|
|
series: [{
|
|
name: 'Surveys',
|
|
data: engagementFunnelData.map(item => item.count)
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 250,
|
|
toolbar: { show: false }
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
borderRadius: 4,
|
|
horizontal: true,
|
|
barHeight: '50%',
|
|
dataLabels: { position: 'top' }
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: true,
|
|
formatter: function (value) {
|
|
return value;
|
|
},
|
|
style: { colors: ['#333'] }
|
|
},
|
|
xaxis: {
|
|
categories: engagementFunnelData.map(item => item.stage),
|
|
labels: { style: { colors: ['#90a4ae'] } }
|
|
},
|
|
yaxis: { labels: { style: { colors: ['#607d8b'] } } },
|
|
colors: ['#0097a7', '#26a69a', '#f9a825', '#1a237e', '#c62828'],
|
|
tooltip: {
|
|
y: {
|
|
formatter: function (value, { seriesIndex, dataPointIndex }) {
|
|
return value + " surveys (" + engagementFunnelData[dataPointIndex].percentage + "%)";
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const engagementFunnelChart = new ApexCharts(document.querySelector("#engagementFunnelChart"), engagementFunnelOptions);
|
|
engagementFunnelChart.render();
|
|
}
|
|
|
|
// Completion Time Distribution Chart (Vertical Bar)
|
|
if (hasData(completionTimeData)) {
|
|
const completionTimeOptions = {
|
|
series: [{
|
|
name: 'Surveys',
|
|
data: completionTimeData.map(item => item.count)
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 250,
|
|
toolbar: { show: false }
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
borderRadius: 4,
|
|
horizontal: false,
|
|
columnWidth: '60%',
|
|
}
|
|
},
|
|
dataLabels: { enabled: false },
|
|
xaxis: {
|
|
categories: completionTimeData.map(item => item.range),
|
|
labels: { style: { colors: ['#90a4ae'] } }
|
|
},
|
|
yaxis: { labels: { style: { colors: ['#90a4ae'] } } },
|
|
colors: ['#0097a7', '#26a69a', '#f9a825', '#c62828', '#1a237e'],
|
|
tooltip: {
|
|
y: {
|
|
formatter: function (value) {
|
|
return value + " surveys";
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const completionTimeChart = new ApexCharts(document.querySelector("#completionTimeChart"), completionTimeOptions);
|
|
completionTimeChart.render();
|
|
}
|
|
|
|
// Device Type Donut Chart
|
|
if (hasData(deviceDistributionData)) {
|
|
const deviceTypeOptions = {
|
|
series: deviceDistributionData.map(item => item.count),
|
|
chart: {
|
|
type: 'donut',
|
|
height: 250,
|
|
toolbar: { show: false }
|
|
},
|
|
labels: deviceDistributionData.map(item => item.name),
|
|
colors: ['#0097a7', '#26a69a', '#f9a825'],
|
|
plotOptions: {
|
|
pie: {
|
|
donut: {
|
|
size: '70%'
|
|
}
|
|
}
|
|
},
|
|
dataLabels: { enabled: false },
|
|
legend: {
|
|
position: 'bottom',
|
|
fontSize: '12px',
|
|
labels: { colors: ['#607d8b'] }
|
|
},
|
|
tooltip: {
|
|
y: {
|
|
formatter: function (value, { seriesIndex, dataPointIndex }) {
|
|
return value + ' surveys (' + deviceDistributionData[dataPointIndex].percentage + '%)';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const deviceTypeChart = new ApexCharts(document.querySelector("#deviceTypeChart"), deviceTypeOptions);
|
|
deviceTypeChart.render();
|
|
}
|
|
|
|
// Score Distribution Bar Chart (Vertical Bar)
|
|
if (hasData(scoreDistributionData)) {
|
|
const scoreDistributionOptions = {
|
|
series: [{
|
|
name: 'Surveys',
|
|
data: scoreDistributionData.map(item => item.count)
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 250,
|
|
toolbar: { show: false }
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
borderRadius: 4,
|
|
horizontal: false,
|
|
columnWidth: '60%',
|
|
}
|
|
},
|
|
dataLabels: { enabled: false },
|
|
xaxis: {
|
|
categories: scoreDistributionData.map(item => item.range),
|
|
labels: { style: { colors: ['#90a4ae'] } }
|
|
},
|
|
yaxis: { labels: { style: { colors: ['#90a4ae'] } } },
|
|
colors: ['#0097a7', '#26a69a', '#f9a825', '#c62828'],
|
|
tooltip: {
|
|
y: {
|
|
formatter: function (value) {
|
|
return value + " surveys";
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const scoreDistributionChart = new ApexCharts(document.querySelector("#scoreDistributionChart"), scoreDistributionOptions);
|
|
scoreDistributionChart.render();
|
|
}
|
|
|
|
// Survey Type Donut Chart
|
|
if (hasData(surveyTypesData)) {
|
|
const surveyTypeOptions = {
|
|
series: surveyTypesData.map(item => item.count),
|
|
chart: {
|
|
type: 'donut',
|
|
height: 250,
|
|
toolbar: { show: false }
|
|
},
|
|
labels: surveyTypesData.map(item => item.name),
|
|
colors: ['#0097a7', '#26a69a', '#f9a825', '#1a237e'],
|
|
plotOptions: {
|
|
pie: {
|
|
donut: {
|
|
size: '70%'
|
|
}
|
|
}
|
|
},
|
|
dataLabels: { enabled: false },
|
|
legend: {
|
|
position: 'bottom',
|
|
fontSize: '12px',
|
|
labels: { colors: ['#607d8b'] }
|
|
},
|
|
tooltip: {
|
|
y: {
|
|
formatter: function (value, { seriesIndex, dataPointIndex }) {
|
|
return value + ' surveys (' + surveyTypesData[dataPointIndex].percentage + '%)';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const surveyTypeChart = new ApexCharts(document.querySelector("#surveyTypeChart"), surveyTypeOptions);
|
|
surveyTypeChart.render();
|
|
}
|
|
|
|
// Survey Trend Line Chart
|
|
if (trendLabels.length > 0 && trendSent.length > 0) {
|
|
const surveyTrendOptions = {
|
|
series: [
|
|
{
|
|
name: '{% trans "Sent" %}',
|
|
data: trendSent
|
|
},
|
|
{
|
|
name: '{% trans "Completed" %}',
|
|
data: trendCompleted
|
|
}
|
|
],
|
|
chart: {
|
|
type: 'line',
|
|
height: 250,
|
|
toolbar: { show: false }
|
|
},
|
|
stroke: {
|
|
curve: 'smooth',
|
|
width: 2
|
|
},
|
|
xaxis: {
|
|
categories: trendLabels,
|
|
labels: {
|
|
rotate: -45,
|
|
style: { colors: ['#90a4ae'] }
|
|
}
|
|
},
|
|
yaxis: { labels: { style: { colors: ['#90a4ae'] } } },
|
|
colors: ['#0097a7', '#26a69a'],
|
|
dataLabels: { enabled: false },
|
|
legend: {
|
|
position: 'top',
|
|
horizontalAlign: 'right',
|
|
labels: { colors: ['#607d8b'] }
|
|
},
|
|
tooltip: {
|
|
y: {
|
|
formatter: function (value) {
|
|
return value + " surveys";
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const surveyTrendChart = new ApexCharts(document.querySelector("#surveyTrendChart"), surveyTrendOptions);
|
|
surveyTrendChart.render();
|
|
}
|
|
</script>
|
|
{% endblock %}
|