dga_feedback-2.0.0/templates/feedback-admin.html.twig

templates/feedback-admin.html.twig
{#
/**
 * @file
 * Template for the DGA Feedback admin submissions page.
 *
 * Available variables:
 * - overall_stats: Overall statistics (yes_percentage, total_count)
 * - usefulness_distribution: Array of yes/no counts
 * - url_statistics: Array of statistics grouped by URL
 * - unique_url_count: Total count of unique URLs
 * - submissions: Array of submission data
 * - total_count: Total number of submissions
 * - current_page: Current page number
 * - limit: Items per page
 * - filters: Current filter values
 * - sort_by: Current sort field
 * - sort_direction: Current sort direction (ASC/DESC)
 * - url_stats_limit: Limit for URL statistics
 * - url_stats_order_by: Order field for URL statistics
 * - url_stats_order_direction: Order direction for URL statistics
 * - top_feedback_page: Top feedback page statistics
 * - most_feedback_page: Most feedback page statistics
 * - recent_activity: Recent activity (7 days, 30 days)
 * - useful_percentage: Percentage of useful feedback (yes)
 * - user_type_stats: Statistics by user type (anonymous vs authenticated)
 */
#}

<div class="dga-feedback-admin-wrapper">
	<div
		class="dga-feedback-admin">
		{# Overall Statistics Section #}
		<div class="dga-feedback-stats-section">
			<div class="section-header">
				<h2 class="section-title">{{ 'Overall Statistics'|t }}</h2>
				{% if filters is not empty %}
					<div class="stats-note">
						<span class="note-icon">ℹ️</span>
						<span class="note-text">{{ 'Showing all-time statistics (not filtered)'|t }}</span>
					</div>
				{% endif %}
			</div>
			<div
				class="stats-grid">
				{# Primary Stats - Large Cards #}
				<div class="stat-card stat-card-primary stat-card-large">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/chart.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'Total Submissions'|t }}</div>
						<div class="stat-value">{{ overall_stats.total_count|number_format }}</div>
						<div class="stat-trend">
							<span class="trend-text">{{ recent_activity.last_7_days.count|default(0) }}
								{{ 'in last 7 days'|t }}</span>
						</div>
					</div>
				</div>

				<div class="stat-card stat-card-success stat-card-large">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/positive.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'Useful Percentage'|t }}</div>
						<div class="stat-value">{{ overall_stats.yes_percentage|number_format(1) }}%</div>
						<div class="stat-progress">
							<div class="progress-bar">
								<div class="progress-fill" style="width: {{ overall_stats.yes_percentage }}%"></div>
							</div>
							<span class="progress-text">{{ overall_stats.yes_percentage|round }}%
								{{ 'said Yes'|t }}</span>
						</div>
					</div>
				</div>

				<div class="stat-card stat-card-info stat-card-large">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/page.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'Total Pages'|t }}</div>
						<div class="stat-value">{{ unique_url_count|number_format }}</div>
						<div class="stat-subtitle">{{ 'Pages with feedback'|t }}</div>
					</div>
				</div>

				<div class="stat-card stat-card-warning stat-card-large">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/average.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'Average per Page'|t }}</div>
						<div class="stat-value">{{ unique_url_count > 0 ? (overall_stats.total_count / unique_url_count)|number_format(1) : '0.0' }}</div>
						<div class="stat-subtitle">{{ 'Submissions per page'|t }}</div>
					</div>
				</div>

				{# Advanced Stats - Medium Cards #}
				<div class="stat-card stat-card-advanced stat-card-positive">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/positive.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'Yes Responses'|t }}</div>
						<div class="stat-value">{{ usefulness_distribution.yes|number_format }}</div>
						<div class="stat-gauge">
							<div class="gauge-bar">
								{% set yes_percentage = overall_stats.total_count > 0 ? (usefulness_distribution.yes / overall_stats.total_count * 100)|round : 0 %}
								<div class="gauge-fill gauge-positive" style="width: {{ yes_percentage }}%"></div>
							</div>
							<span class="gauge-label">{{ 'Useful'|t }}</span>
						</div>
					</div>
				</div>

				<div class="stat-card stat-card-advanced stat-card-negative">
					<div class="icon cancel">
						<img src="/modules/custom/dga_feedback/images/icons/cancel.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'No Responses'|t }}</div>
						<div class="stat-value">{{ usefulness_distribution.no|number_format }}</div>
						<div class="stat-gauge">
							<div class="gauge-bar">
								{% set no_percentage = overall_stats.total_count > 0 ? (usefulness_distribution.no / overall_stats.total_count * 100)|round : 0 %}
								<div class="gauge-fill gauge-negative" style="width: {{ no_percentage }}%"></div>
							</div>
							<span class="gauge-label">{{ 'Not Useful'|t }}</span>
						</div>
					</div>
				</div>

				<div class="stat-card stat-card-advanced stat-card-recent">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/clock.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'Last 7 Days'|t }}</div>
						<div class="stat-value">{{ recent_activity.last_7_days.count|default(0)|number_format }}</div>
						<div class="stat-subtitle">
							{% if recent_activity.last_7_days.count > 0 %}
								{{ recent_activity.last_7_days.useful_percentage|default(0)|number_format(1) }}%
								{{ 'useful'|t }}
							{% else %}
								{{ 'No recent activity'|t }}
							{% endif %}
						</div>
					</div>
				</div>

				{% if top_feedback_page %}
					<div class="stat-card stat-card-advanced stat-card-top-rated">
						<div class="icon">
							<img src="/modules/custom/dga_feedback/images/icons/top-rated.svg" alt="average-icon">
						</div>
						<div class="stat-content">
							<div class="stat-label">{{ 'Most Useful Page'|t }}</div>
							<div class="stat-value">{{ top_feedback_page.yes_percentage|number_format(1) }}%</div>
							<div class="stat-url">
								<a href="{{ top_feedback_page.url }}" target="_blank" class="url-link-small" title="{{ top_feedback_page.url }}">
									{{ top_feedback_page.url|length > 30 ? top_feedback_page.url|slice(0, 30) ~ '...' : top_feedback_page.url }}
								</a>
								<span class="url-count">{{ top_feedback_page.count }}
									{{ 'submissions'|t }}</span>
							</div>
						</div>
					</div>
				{% endif %}

				{% if most_feedback_page %}
					<div class="stat-card stat-card-advanced stat-card-most-reviewed">
						<div class="icon">
							<img src="/modules/custom/dga_feedback/images/icons/fire.svg" alt="average-icon">
						</div>
						<div class="stat-content">
							<div class="stat-label">{{ 'Most Feedback'|t }}</div>
							<div class="stat-value">{{ most_feedback_page.count|number_format }}</div>
							<div class="stat-url">
								<a href="{{ most_feedback_page.url }}" target="_blank" class="url-link-small" title="{{ most_feedback_page.url }}">
									{{ most_feedback_page.url|length > 30 ? most_feedback_page.url|slice(0, 30) ~ '...' : most_feedback_page.url }}
								</a>
								<span class="url-count">{{ most_feedback_page.yes_percentage|number_format(1) }}%
									{{ 'useful'|t }}</span>
							</div>
						</div>
					</div>
				{% endif %}

				<div class="stat-card stat-card-advanced stat-card-users">
					<div class="icon">
						<img src="/modules/custom/dga_feedback/images/icons/people.svg" alt="average-icon">
					</div>
					<div class="stat-content">
						<div class="stat-label">{{ 'User Type'|t }}</div>
						<div class="stat-value-split">
							<div class="split-item">
								<span class="split-label">{{ 'Anonymous'|t }}</span>
								<span class="split-value">{{ user_type_stats.anonymous|default(0)|number_format }}</span>
							</div>
							<div class="split-item">
								<span class="split-label">{{ 'Authenticated'|t }}</span>
								<span class="split-value">{{ user_type_stats.authenticated|default(0)|number_format }}</span>
							</div>
						</div>
						<div class="stat-chart-mini">
							{% set total_users = user_type_stats.anonymous|default(0) + user_type_stats.authenticated|default(0) %}
							{% if total_users > 0 %}
								{% set anon_percent = (user_type_stats.anonymous|default(0) / total_users * 100)|round %}
								{% set auth_percent = (user_type_stats.authenticated|default(0) / total_users * 100)|round %}
								<div class="mini-bar">
									<div class="mini-bar-segment mini-bar-anon" style="width: {{ anon_percent }}%"></div>
									<div class="mini-bar-segment mini-bar-auth" style="width: {{ auth_percent }}%"></div>
								</div>
							{% endif %}
						</div>
					</div>
				</div>
			</div>
		</div>

		{# Filters Section #}
		<div class="dga-feedback-filters-section">
			<div class="section-header">
				<h2 class="section-title">{{ 'Filters & Search'|t }}</h2>
				<button type="button" class="button button-secondary" id="toggle-filters" aria-expanded="true">
					<span class="toggle-text">{{ 'Hide Filters'|t }}</span>
				</button>
			</div>
			<div class="filters-content" id="filters-content">
				<form method="get" action="" class="filters-form" id="feedback-filters-form">
					<div class="filters-grid">
						<div class="filter-group">
							<label for="filter-url" class="filter-label">{{ 'URL'|t }}</label>
							<input type="text" id="filter-url" name="url" value="{{ filters.url|default('') }}" placeholder="{{ 'Filter by URL...'|t }}" class="form-text">
						</div>
						<div class="filter-group">
							<label for="filter-is-useful" class="filter-label">{{ 'Useful'|t }}</label>
							<select id="filter-is-useful" name="is_useful" class="form-select">
								<option value="">{{ 'All'|t }}</option>
								<option value="yes" {% if filters.is_useful == 'yes' %} selected {% endif %}>{{ 'Yes'|t }}</option>
								<option value="no" {% if filters.is_useful == 'no' %} selected {% endif %}>{{ 'No'|t }}</option>
							</select>
						</div>
						<div class="filter-group">
							<label for="filter-entity-type" class="filter-label">{{ 'Entity Type'|t }}</label>
							<input type="text" id="filter-entity-type" name="entity_type" value="{{ filters.entity_type|default('') }}" placeholder="{{ 'e.g., node'|t }}" class="form-text">
						</div>
						<div class="filter-group">
							<label for="filter-entity-id" class="filter-label">{{ 'Entity ID'|t }}</label>
							<input type="number" id="filter-entity-id" name="entity_id" value="{{ filters.entity_id|default('') }}" placeholder="{{ 'e.g., 123'|t }}" class="form-text">
						</div>
						<div class="filter-group">
							<label for="filter-date-from" class="filter-label">{{ 'Date From'|t }}</label>
							<input type="date" id="filter-date-from" name="date_from" value="{% if filters.date_from %}{{ filters.date_from|date('Y-m-d', 'UTC') }}{% endif %}" class="form-date">
						</div>
						<div class="filter-group">
							<label for="filter-date-to" class="filter-label">{{ 'Date To'|t }}</label>
							<input type="date" id="filter-date-to" name="date_to" value="{% if filters.date_to %}{{ filters.date_to|date('Y-m-d', 'UTC') }}{% endif %}" class="form-date">
						</div>
					</div>
					<div class="filters-actions">
						<button type="submit" class="button button-primary">{{ 'Apply Filters'|t }}</button>
						<a href="?" class="button button-secondary">{{ 'Clear Filters'|t }}</a>
					</div>
				</form>
			</div>
		</div>

		{# Submissions Table Section #}
		<div class="dga-feedback-submissions-section">
			<div class="section-header">
				<h2 class="section-title">{{ 'All Submissions'|t }}
					<span class="submissions-count">({{ total_count|number_format }})</span>
				</h2>
			</div>

			{% if submissions is empty %}
				<div class="empty-state">
					<p class="empty-message">{{ 'No submissions found.'|t }}</p>
				</div>
			{% else %}
				{# Bulk Operations #}
				<div class="bulk-operations-wrapper" id="bulk-operations-wrapper" style="display: none;">
					<div class="bulk-operations">
						<div class="bulk-operations-info">
							<span class="bulk-operations-count" id="bulk-operations-count">0</span>
							<span class="bulk-operations-text">{{ 'selected'|t }}</span>
						</div>
						<div class="bulk-operations-actions">
							<select id="bulk-action-select" class="form-select">
								<option value="">{{ '- Select action -'|t }}</option>
								<option value="delete">{{ 'Delete selected'|t }}</option>
							</select>
							<button type="button" id="bulk-action-submit" class="button button--primary" disabled>{{ 'Apply to selected items'|t }}</button>
						</div>
					</div>
				</div>

				<div class="table-wrapper">
					<table class="submissions-table sticky-enabled" id="submissions-table">
						<thead>
							<tr>
								<th class="select-all">
									<input type="checkbox" id="select-all-checkbox" class="form-checkbox" title="{{ 'Select all rows in this table'|t }}"/>
								</th>
								<th class="sortable" data-sort="id">
									{{ 'ID'|t }}
									{% if sort_by == 'id' %}
										<span class="sort-indicator">{{ sort_direction == 'ASC' ? '↑' : '↓' }}</span>
									{% endif %}
								</th>
								<th class="sortable" data-sort="is_useful">
									{{ 'Useful'|t }}
									{% if sort_by == 'is_useful' %}
										<span class="sort-indicator">{{ sort_direction == 'ASC' ? '↑' : '↓' }}</span>
									{% endif %}
								</th>
								<th>{{ 'Reasons'|t }}</th>
								<th>{{ 'Feedback'|t }}</th>
								<th>{{ 'Gender'|t }}</th>
								<th class="sortable" data-sort="url">
									{{ 'URL'|t }}
									{% if sort_by == 'url' %}
										<span class="sort-indicator">{{ sort_direction == 'ASC' ? '↑' : '↓' }}</span>
									{% endif %}
								</th>
								<th class="sortable" data-sort="user_id">
									{{ 'User'|t }}
									{% if sort_by == 'user_id' %}
										<span class="sort-indicator">{{ sort_direction == 'ASC' ? '↑' : '↓' }}</span>
									{% endif %}
								</th>
								<th class="sortable" data-sort="created">
									{{ 'Submitted'|t }}
									{% if sort_by == 'created' %}
										<span class="sort-indicator">{{ sort_direction == 'ASC' ? '↑' : '↓' }}</span>
									{% endif %}
								</th>
								<th>{{ 'Operations'|t }}</th>
							</tr>
						</thead>
						<tbody>
							{% for submission in submissions %}
								<tr>
									<td class="select-checkbox">
										<input type="checkbox" name="submissions[]" value="{{ submission.id|default(0) }}" class="form-checkbox submission-checkbox"/>
									</td>
									<td class="cell-id">{{ submission.id|default(0) }}</td>
									<td class="cell-useful">
										{% if submission.is_useful == 'yes' %}
											<span class="useful-display useful-yes">
												{{ 'Yes'|t }}</span>
										{% else %}
											<span class="useful-display useful-no">
												{{ 'No'|t }}</span>
										{% endif %}
									</td>
									<td class="cell-reasons">
										{% if submission.reasons %}
											<ul class="reasons-list">
												{% for reason in submission.reasons %}
													<li>{{ reason|striptags|escape|t }}</li>
												{% endfor %}
											</ul>
										{% else %}
											<em class="no-reasons">{{ 'None'|t }}</em>
										{% endif %}
									</td>
									<td class="cell-feedback">
										{% if submission.feedback %}
											<div class="feedback-text" title="{{ submission.feedback|striptags|escape }}">
												{{ submission.feedback|striptags|escape|length > 80 ? submission.feedback|striptags|escape|slice(0, 80) ~ '...' : submission.feedback|striptags|escape }}
											</div>
										{% else %}
											<em class="no-feedback">{{ 'No feedback'|t }}</em>
										{% endif %}
									</td>
									<td class="cell-gender">
										{% if submission.gender == 'male' %}
											{{ 'Male'|t }}
										{% elseif submission.gender == 'female' %}
											{{ 'Female'|t }}
										{% else %}
											{{ submission.gender|default('—')|capitalize }}
										{% endif %}
									</td>
									<td class="cell-url">
										<a href="{{ submission.url|default('/') }}" target="_blank" class="url-link" title="{{ submission.url|default('/') }}">
											{{ submission.url|default('/')|length > 40 ? submission.url|default('/')|slice(0, 40) ~ '...' : submission.url|default('/') }}
										</a>
									</td>
									<td class="cell-user">
										{% if submission.user_id and submission.user_id is not null %}
											{{ 'User'|t }}
											#{{ submission.user_id }}
										{% else %}
											<span class="anonymous-badge">{{ 'Anonymous'|t }}</span>
										{% endif %}
									</td>
									<td class="cell-date">{{ submission.created_formatted|default('') }}</td>
									<td class="cell-operations">
										<div class="dropbutton-wrapper dropbutton-multiple">
											<div class="dropbutton-widget">
												<ul class="dropbutton">
													<li class="dropbutton-action">
														<a href="{{ path('dga_feedback.admin.edit', {'id': submission.id}) }}">{{ 'Edit'|t }}</a>
													</li>
													<li class="dropbutton-toggle">
														<button type="button" class="dropbutton__toggle" aria-label="{{ 'List additional actions'|t }}" aria-expanded="false">
															<span class="dropbutton__arrow">
																<span class="visually-hidden">{{ 'List additional actions'|t }}</span>
															</span>
														</button>
													</li>
												</ul>
												<ul class="dropbutton dropbutton-multiple dropbutton-secondary">
													<li class="dropbutton-action">
														<a href="{{ path('dga_feedback.admin.delete', {'id': submission.id}) }}">{{ 'Delete'|t }}</a>
													</li>
												</ul>
											</div>
										</div>
									</td>
								</tr>
							{% endfor %}
						</tbody>
					</table>
				</div>

				{# Pagination #}
				{% if total_count > limit %}
					<div class="pager-wrapper">
						{{ pager }}
					</div>
				{% endif %}
			{% endif %}
		</div>
	</div>
</div>

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc