753 lines
27 KiB
HTML
753 lines
27 KiB
HTML
{{ define "content" }}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>{{.Title}}</title>
|
|
<link
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
|
|
rel="stylesheet"
|
|
/>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
</head>
|
|
<body class="bg-gray-50">
|
|
<div class="min-h-screen w-full flex flex-col">
|
|
<!-- Header -->
|
|
<div class="bg-white border-b border-gray-200 w-full">
|
|
<div class="px-8 py-6">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-8 h-8 bg-purple-600 flex items-center justify-center rounded"
|
|
>
|
|
<i class="fas fa-brain text-white text-sm"></i>
|
|
</div>
|
|
<span class="text-xl font-semibold text-gray-900"
|
|
>Smart Reports & Analytics</span
|
|
>
|
|
</div>
|
|
<div class="flex items-center gap-4">
|
|
{{if .SmartQuery}}
|
|
<button
|
|
onclick="exportResults()"
|
|
class="px-6 py-2.5 bg-green-600 text-white text-sm font-medium rounded hover:bg-green-700 transition-colors"
|
|
>
|
|
<i class="fas fa-download mr-2"></i>Export Results
|
|
</button>
|
|
{{end}}
|
|
<button
|
|
onclick="clearQuery()"
|
|
class="px-6 py-2.5 border border-gray-300 text-gray-700 text-sm font-medium rounded hover:bg-gray-50 transition-colors"
|
|
>
|
|
<i class="fas fa-eraser mr-2"></i>Clear
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Smart Search Interface -->
|
|
<div class="bg-white w-full border-b border-gray-200">
|
|
<div class="px-8 py-8">
|
|
<div class="max-w-4xl mx-auto">
|
|
<h2 class="text-2xl font-bold text-gray-900 mb-2">
|
|
Ask About Your Data
|
|
</h2>
|
|
<p class="text-gray-600 mb-8">
|
|
Use natural language to query across users, polls, appointments,
|
|
addresses, and teams
|
|
</p>
|
|
|
|
<form method="GET" action="/smart-reports" class="mb-8">
|
|
<div class="relative">
|
|
<div
|
|
class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"
|
|
>
|
|
<i class="fas fa-magic text-purple-400"></i>
|
|
</div>
|
|
<input
|
|
type="text"
|
|
name="smart_query"
|
|
value="{{.SmartQuery}}"
|
|
placeholder="e.g., 'volunteers who went to Main Street' or 'donations by team 5'"
|
|
class="w-full pl-10 pr-4 py-4 text-lg border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
|
|
autocomplete="off"
|
|
/>
|
|
</div>
|
|
<div class="flex justify-between items-center mt-4">
|
|
<button
|
|
type="submit"
|
|
class="px-8 py-3 bg-purple-600 text-white font-semibold rounded-lg hover:bg-purple-700 transition-colors"
|
|
>
|
|
<i class="fas fa-search mr-2"></i>Search
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onclick="toggleExamples()"
|
|
class="text-purple-600 hover:text-purple-800 text-sm font-medium"
|
|
>
|
|
<i class="fas fa-lightbulb mr-1"></i>Show Examples
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Query Examples -->
|
|
<div id="queryExamples" class="hidden">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
|
Example Queries
|
|
</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
|
{{range .QueryExamples}}
|
|
<div
|
|
class="p-4 bg-gray-50 rounded-lg border border-gray-200 hover:bg-gray-100 transition-colors cursor-pointer"
|
|
onclick="useExample('{{.}}')"
|
|
>
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-sm text-gray-700">{{.}}</span>
|
|
<i class="fas fa-arrow-right text-purple-500 text-xs"></i>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Results Section -->
|
|
{{if .Result}} {{if .Result.Error}}
|
|
<div class="bg-white w-full">
|
|
<div class="px-8 py-6">
|
|
<div class="bg-red-50 border border-red-200 rounded-lg p-6">
|
|
<div class="flex items-center">
|
|
<div
|
|
class="w-8 h-8 bg-red-100 rounded-full flex items-center justify-center"
|
|
>
|
|
<i class="fas fa-exclamation-triangle text-red-600 text-sm"></i>
|
|
</div>
|
|
<div class="ml-4">
|
|
<h3 class="text-lg font-semibold text-red-800">Query Error</h3>
|
|
<p class="text-red-700 mt-2">{{.Result.Error}}</p>
|
|
{{if .Result.Query}}
|
|
<details class="mt-4">
|
|
<summary class="text-sm text-red-600 cursor-pointer">
|
|
Show Generated SQL
|
|
</summary>
|
|
<pre
|
|
class="mt-2 p-3 bg-red-100 text-red-800 text-xs rounded overflow-x-auto"
|
|
>
|
|
{{.Result.Query}}</pre
|
|
>
|
|
</details>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{else}}
|
|
<!-- Successful Results -->
|
|
<div class="bg-white w-full">
|
|
<div class="px-8 py-6">
|
|
<div class="flex items-center justify-between mb-6">
|
|
<h3 class="text-lg font-semibold text-gray-900">
|
|
Query Results ({{.Result.Count}} records found)
|
|
</h3>
|
|
<div class="flex items-center gap-4">
|
|
<button
|
|
onclick="toggleQueryDetails()"
|
|
class="text-sm text-gray-500 hover:text-gray-700"
|
|
>
|
|
<i class="fas fa-code mr-1"></i>Show SQL
|
|
</button>
|
|
<button
|
|
onclick="exportResults()"
|
|
class="px-4 py-2 bg-green-600 text-white text-sm rounded hover:bg-green-700 transition-colors"
|
|
>
|
|
<i class="fas fa-download mr-1"></i>Export CSV
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Query Details (Hidden by default) -->
|
|
<div
|
|
id="queryDetails"
|
|
class="hidden mb-6 p-4 bg-gray-50 rounded-lg border"
|
|
>
|
|
<h4 class="text-sm font-semibold text-gray-700 mb-2">
|
|
Generated SQL Query:
|
|
</h4>
|
|
<pre class="text-xs text-gray-600 overflow-x-auto">
|
|
{{.Result.Query}}</pre
|
|
>
|
|
</div>
|
|
|
|
<!-- Results Table -->
|
|
{{if gt .Result.Count 0}}
|
|
<div class="overflow-x-auto rounded-lg border border-gray-200">
|
|
<table class="w-full">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
{{range .Result.Columns}}
|
|
<th
|
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider border-b border-gray-200"
|
|
>
|
|
{{formatColumnName .}}
|
|
</th>
|
|
{{end}}
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
{{range .Result.Rows}}
|
|
<tr class="hover:bg-gray-50 transition-colors">
|
|
{{range .}}
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
|
{{.}}
|
|
</td>
|
|
{{end}}
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else}}
|
|
<div class="text-center py-12">
|
|
<div
|
|
class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4"
|
|
>
|
|
<i class="fas fa-search text-gray-400 text-xl"></i>
|
|
</div>
|
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
|
No Results Found
|
|
</h3>
|
|
<p class="text-gray-500">
|
|
Try adjusting your query or check the examples below
|
|
</p>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}} {{end}}
|
|
|
|
<!-- Query Builder Assistant -->
|
|
<div class="bg-white w-full border-t border-gray-200">
|
|
<div class="px-8 py-6">
|
|
<div class="max-w-4xl mx-auto">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-6">
|
|
Smart Query Builder
|
|
</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<!-- Common Queries -->
|
|
<div class="space-y-4">
|
|
<h4 class="font-medium text-gray-900">
|
|
User & Volunteer Queries
|
|
</h4>
|
|
<div class="space-y-2">
|
|
<button
|
|
onclick="useSmartQuery('volunteers who went to')"
|
|
class="w-full text-left p-3 bg-blue-50 text-blue-800 rounded border hover:bg-blue-100 transition-colors"
|
|
>
|
|
<i class="fas fa-user-friends mr-2"></i>Volunteers who went
|
|
to...
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('users with role admin')"
|
|
class="w-full text-left p-3 bg-blue-50 text-blue-800 rounded border hover:bg-blue-100 transition-colors"
|
|
>
|
|
<i class="fas fa-user-shield mr-2"></i>Users by role
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('volunteer activity by month')"
|
|
class="w-full text-left p-3 bg-blue-50 text-blue-800 rounded border hover:bg-blue-100 transition-colors"
|
|
>
|
|
<i class="fas fa-chart-line mr-2"></i>Volunteer activity
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Poll & Donation Queries -->
|
|
<div class="space-y-4">
|
|
<h4 class="font-medium text-gray-900">
|
|
Poll & Donation Queries
|
|
</h4>
|
|
<div class="space-y-2">
|
|
<button
|
|
onclick="useSmartQuery('poll responses for')"
|
|
class="w-full text-left p-3 bg-green-50 text-green-800 rounded border hover:bg-green-100 transition-colors"
|
|
>
|
|
<i class="fas fa-poll mr-2"></i>Poll responses for address
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('donations by volunteer')"
|
|
class="w-full text-left p-3 bg-green-50 text-green-800 rounded border hover:bg-green-100 transition-colors"
|
|
>
|
|
<i class="fas fa-donate mr-2"></i>Donations by volunteer
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('active polls created after 2024-01-01')"
|
|
class="w-full text-left p-3 bg-green-50 text-green-800 rounded border hover:bg-green-100 transition-colors"
|
|
>
|
|
<i class="fas fa-calendar-check mr-2"></i>Active polls by
|
|
date
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Team & Address Queries -->
|
|
<div class="space-y-4">
|
|
<h4 class="font-medium text-gray-900">
|
|
Team & Address Queries
|
|
</h4>
|
|
<div class="space-y-2">
|
|
<button
|
|
onclick="useSmartQuery('team with most appointments')"
|
|
class="w-full text-left p-3 bg-purple-50 text-purple-800 rounded border hover:bg-purple-100 transition-colors"
|
|
>
|
|
<i class="fas fa-users mr-2"></i>Top performing teams
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('visited addresses')"
|
|
class="w-full text-left p-3 bg-purple-50 text-purple-800 rounded border hover:bg-purple-100 transition-colors"
|
|
>
|
|
<i class="fas fa-map-marked-alt mr-2"></i>Visited addresses
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('money made by team')"
|
|
class="w-full text-left p-3 bg-purple-50 text-purple-800 rounded border hover:bg-purple-100 transition-colors"
|
|
>
|
|
<i class="fas fa-dollar-sign mr-2"></i>Team earnings
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Query Syntax Help -->
|
|
<div class="mt-8 p-6 bg-gray-50 rounded-lg border border-gray-200">
|
|
<h4 class="font-semibold text-gray-900 mb-4">
|
|
<i class="fas fa-info-circle text-blue-500 mr-2"></i>Smart Query
|
|
Syntax Guide
|
|
</h4>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 text-sm">
|
|
<div>
|
|
<h5 class="font-medium text-gray-800 mb-2">
|
|
Entity Keywords:
|
|
</h5>
|
|
<ul class="space-y-1 text-gray-600">
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>volunteer, user, admin</code
|
|
>
|
|
- User data
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded">poll, polls</code>
|
|
- Poll data
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>address, addresses</code
|
|
>
|
|
- Address data
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>appointment, appointments</code
|
|
>
|
|
- Appointment data
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded">team, teams</code>
|
|
- Team data
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h5 class="font-medium text-gray-800 mb-2">
|
|
Action Keywords:
|
|
</h5>
|
|
<ul class="space-y-1 text-gray-600">
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>went to, visited</code
|
|
>
|
|
- Filter by visits
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>donated, money, amount</code
|
|
>
|
|
- Financial data
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>active, inactive</code
|
|
>
|
|
- Status filters
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>most, highest, top</code
|
|
>
|
|
- Ranking queries
|
|
</li>
|
|
<li>
|
|
<code class="bg-gray-200 px-1 rounded"
|
|
>from DATE, after DATE</code
|
|
>
|
|
- Date filters
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Live Query Suggestions -->
|
|
<div class="bg-white w-full border-t border-gray-200">
|
|
<div class="px-8 py-6">
|
|
<div class="max-w-4xl mx-auto">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
|
Popular Analysis Questions
|
|
</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
<div
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-purple-300 transition-colors cursor-pointer"
|
|
onclick="useSmartQuery('which volunteer went to most addresses')"
|
|
>
|
|
<h5 class="font-medium text-gray-900 mb-2">
|
|
Top Performing Volunteers
|
|
</h5>
|
|
<p class="text-sm text-gray-600">
|
|
Find volunteers with most address visits
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-purple-300 transition-colors cursor-pointer"
|
|
onclick="useSmartQuery('poll responses of visited addresses')"
|
|
>
|
|
<h5 class="font-medium text-gray-900 mb-2">
|
|
Visited Address Polls
|
|
</h5>
|
|
<p class="text-sm text-gray-600">
|
|
Polls from addresses that were visited
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-purple-300 transition-colors cursor-pointer"
|
|
onclick="useSmartQuery('donations filtered by volunteer Sarah')"
|
|
>
|
|
<h5 class="font-medium text-gray-900 mb-2">
|
|
Volunteer Donations
|
|
</h5>
|
|
<p class="text-sm text-gray-600">
|
|
Total donations by specific volunteer
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-purple-300 transition-colors cursor-pointer"
|
|
onclick="useSmartQuery('team that did most appointments')"
|
|
>
|
|
<h5 class="font-medium text-gray-900 mb-2">Most Active Team</h5>
|
|
<p class="text-sm text-gray-600">
|
|
Team with highest appointment count
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-purple-300 transition-colors cursor-pointer"
|
|
onclick="useSmartQuery('people in team 1')"
|
|
>
|
|
<h5 class="font-medium text-gray-900 mb-2">Team Members</h5>
|
|
<p class="text-sm text-gray-600">
|
|
View all members of a specific team
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="p-4 border border-gray-200 rounded-lg hover:border-purple-300 transition-colors cursor-pointer"
|
|
onclick="useSmartQuery('unvisited addresses with polls')"
|
|
>
|
|
<h5 class="font-medium text-gray-900 mb-2">
|
|
Missed Opportunities
|
|
</h5>
|
|
<p class="text-sm text-gray-600">
|
|
Addresses with polls but no visits
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Queries History -->
|
|
<div class="bg-gray-50 w-full border-t border-gray-200">
|
|
<div class="px-8 py-6">
|
|
<div class="max-w-4xl mx-auto">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
|
Quick Actions
|
|
</h3>
|
|
<div class="flex flex-wrap gap-3">
|
|
<button
|
|
onclick="useSmartQuery('all users created today')"
|
|
class="px-4 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded hover:bg-gray-50 transition-colors"
|
|
>
|
|
Today's Users
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('donations over 50')"
|
|
class="px-4 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded hover:bg-gray-50 transition-colors"
|
|
>
|
|
High Donations
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('appointments this week')"
|
|
class="px-4 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded hover:bg-gray-50 transition-colors"
|
|
>
|
|
This Week's Appointments
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('inactive polls with donations')"
|
|
class="px-4 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded hover:bg-gray-50 transition-colors"
|
|
>
|
|
Inactive Paid Polls
|
|
</button>
|
|
<button
|
|
onclick="useSmartQuery('teams created this month')"
|
|
class="px-4 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded hover:bg-gray-50 transition-colors"
|
|
>
|
|
New Teams
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Toggle query examples
|
|
function toggleExamples() {
|
|
const examples = document.getElementById("queryExamples");
|
|
examples.classList.toggle("hidden");
|
|
}
|
|
|
|
// Use example query
|
|
function useExample(query) {
|
|
document.querySelector('input[name="smart_query"]').value = query;
|
|
}
|
|
|
|
// Use smart query (for buttons)
|
|
function useSmartQuery(query) {
|
|
document.querySelector('input[name="smart_query"]').value = query;
|
|
document.querySelector("form").submit();
|
|
}
|
|
|
|
// Toggle query details
|
|
function toggleQueryDetails() {
|
|
const details = document.getElementById("queryDetails");
|
|
details.classList.toggle("hidden");
|
|
}
|
|
|
|
// Export results
|
|
function exportResults() {
|
|
const query = encodeURIComponent(
|
|
document.querySelector('input[name="smart_query"]').value
|
|
);
|
|
window.location.href = `/smart-reports/export?smart_query=${query}`;
|
|
}
|
|
|
|
// Clear query
|
|
function clearQuery() {
|
|
window.location.href = "/smart-reports";
|
|
}
|
|
|
|
// Format column names for display
|
|
function formatColumnName(name) {
|
|
return name.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
|
|
}
|
|
|
|
// Auto-complete functionality
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const input = document.querySelector('input[name="smart_query"]');
|
|
const suggestions = [
|
|
"volunteers who went to",
|
|
"poll responses for address",
|
|
"donations by volunteer",
|
|
"team with most appointments",
|
|
"people in team",
|
|
"money made by team",
|
|
"visited addresses",
|
|
"active polls",
|
|
"appointments for",
|
|
"users with role",
|
|
"polls with donations over",
|
|
"addresses visited by",
|
|
"team leads with more than",
|
|
"donations per address",
|
|
"unvisited addresses with polls",
|
|
];
|
|
|
|
// Simple autocomplete
|
|
input.addEventListener("input", function () {
|
|
const value = this.value.toLowerCase();
|
|
// You could implement autocomplete dropdown here
|
|
console.log("Typing:", value);
|
|
});
|
|
|
|
// Submit on Enter
|
|
input.addEventListener("keypress", function (e) {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
this.form.submit();
|
|
}
|
|
});
|
|
|
|
// Focus on load
|
|
input.focus();
|
|
});
|
|
|
|
// Real-time query validation
|
|
function validateQuery(query) {
|
|
const keywords = [
|
|
"volunteer",
|
|
"user",
|
|
"poll",
|
|
"address",
|
|
"appointment",
|
|
"team",
|
|
"donation",
|
|
];
|
|
const hasKeyword = keywords.some((keyword) =>
|
|
query.toLowerCase().includes(keyword)
|
|
);
|
|
|
|
if (!hasKeyword) {
|
|
return {
|
|
valid: false,
|
|
message:
|
|
"Query should include at least one entity (volunteer, poll, address, etc.)",
|
|
};
|
|
}
|
|
|
|
return { valid: true };
|
|
}
|
|
|
|
// Query suggestions based on context
|
|
function getContextualSuggestions(partialQuery) {
|
|
const suggestions = [];
|
|
const query = partialQuery.toLowerCase();
|
|
|
|
if (query.includes("volunteer")) {
|
|
suggestions.push("volunteers who went to Main Street");
|
|
suggestions.push("volunteers with most donations");
|
|
suggestions.push("volunteer activity by month");
|
|
}
|
|
|
|
if (query.includes("team")) {
|
|
suggestions.push("team with most appointments");
|
|
suggestions.push("people in team 1");
|
|
suggestions.push("money made by team 2");
|
|
}
|
|
|
|
if (query.includes("address")) {
|
|
suggestions.push("addresses visited by volunteer John");
|
|
suggestions.push("poll responses for 123 Oak Street");
|
|
suggestions.push("unvisited addresses with polls");
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
// Keyboard shortcuts
|
|
document.addEventListener("keydown", function (e) {
|
|
// Ctrl/Cmd + Enter to submit
|
|
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
|
|
document.querySelector("form").submit();
|
|
}
|
|
|
|
// Escape to clear
|
|
if (e.key === "Escape") {
|
|
clearQuery();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
/* Enhanced styling for smart interface */
|
|
.smart-query-input:focus {
|
|
box-shadow: 0 0 0 3px rgba(147, 51, 234, 0.1);
|
|
border-color: #9333ea;
|
|
}
|
|
|
|
/* Syntax highlighting for code examples */
|
|
code {
|
|
background-color: #f3f4f6;
|
|
padding: 2px 4px;
|
|
border-radius: 3px;
|
|
font-family: "Courier New", monospace;
|
|
font-size: 0.875em;
|
|
}
|
|
|
|
/* Hover effects for query buttons */
|
|
.query-button:hover {
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
/* Loading animation */
|
|
.loading {
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
/* Results table styling */
|
|
.results-table th {
|
|
position: sticky;
|
|
top: 0;
|
|
background: white;
|
|
z-index: 10;
|
|
}
|
|
|
|
/* Print styles */
|
|
@media print {
|
|
.no-print {
|
|
display: none !important;
|
|
}
|
|
body {
|
|
background: white !important;
|
|
}
|
|
.border-gray-200 {
|
|
border-color: #000 !important;
|
|
}
|
|
}
|
|
|
|
/* Mobile responsive adjustments */
|
|
@media (max-width: 768px) {
|
|
.px-8 {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
.overflow-x-auto {
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
}
|
|
</style>
|
|
</body>
|
|
</html>
|
|
{{ end }}
|