101 lines
4.1 KiB
Go
101 lines
4.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"dealroom/templates"
|
|
)
|
|
|
|
func (h *Handler) handleAnalytics(w http.ResponseWriter, r *http.Request) {
|
|
profile := getProfile(r.Context())
|
|
dealID := r.URL.Query().Get("deal_id")
|
|
|
|
deals := h.getDeals(profile)
|
|
|
|
var dealCount, fileCount, requestCount, fulfilledCount int
|
|
|
|
if dealID != "" {
|
|
h.db.QueryRow("SELECT COUNT(*) FROM deals WHERE id = ? AND organization_id = ? AND is_archived = 0", dealID, profile.OrganizationID).Scan(&dealCount)
|
|
h.db.QueryRow("SELECT COUNT(*) FROM files WHERE deal_id = ?", dealID).Scan(&fileCount)
|
|
h.db.QueryRow("SELECT COUNT(*) FROM diligence_requests WHERE deal_id = ?", dealID).Scan(&requestCount)
|
|
h.db.QueryRow("SELECT COUNT(*) FROM diligence_requests WHERE deal_id = ? AND atlas_status = 'fulfilled'", dealID).Scan(&fulfilledCount)
|
|
} else {
|
|
h.db.QueryRow("SELECT COUNT(*) FROM deals WHERE organization_id = ? AND is_archived = 0", profile.OrganizationID).Scan(&dealCount)
|
|
h.db.QueryRow("SELECT COUNT(*) FROM files f JOIN deals d ON f.deal_id = d.id WHERE d.organization_id = ?", profile.OrganizationID).Scan(&fileCount)
|
|
h.db.QueryRow("SELECT COUNT(*) FROM diligence_requests r JOIN deals d ON r.deal_id = d.id WHERE d.organization_id = ?", profile.OrganizationID).Scan(&requestCount)
|
|
h.db.QueryRow("SELECT COUNT(*) FROM diligence_requests r JOIN deals d ON r.deal_id = d.id WHERE d.organization_id = ? AND r.atlas_status = 'fulfilled'", profile.OrganizationID).Scan(&fulfilledCount)
|
|
}
|
|
|
|
completionPct := 0
|
|
if requestCount > 0 {
|
|
completionPct = (fulfilledCount * 100) / requestCount
|
|
}
|
|
|
|
stats := &templates.AnalyticsStats{
|
|
DealCount: dealCount,
|
|
FileCount: fileCount,
|
|
RequestCount: requestCount,
|
|
CompletionPct: completionPct,
|
|
}
|
|
|
|
templates.AnalyticsPage(profile, stats, deals, dealID).Render(r.Context(), w)
|
|
}
|
|
|
|
func (h *Handler) handleAnalyticsBuyers(w http.ResponseWriter, r *http.Request) {
|
|
dealID := r.URL.Query().Get("deal_id")
|
|
if dealID == "" {
|
|
w.Write([]byte(`<p class="text-sm text-gray-500">Select a deal to see buyer activity.</p>`))
|
|
return
|
|
}
|
|
|
|
rows, err := h.db.Query(`
|
|
SELECT COALESCE(buyer_group, 'Unknown') as bg,
|
|
COUNT(CASE WHEN activity_type = 'download' THEN 1 END) as downloads,
|
|
MAX(created_at) as last_access,
|
|
SUM(COALESCE(time_spent_seconds, 0)) as total_time,
|
|
COUNT(CASE WHEN activity_type = 'view' THEN 1 END) as views
|
|
FROM deal_activity WHERE deal_id = ? AND COALESCE(buyer_group, '') != ''
|
|
GROUP BY COALESCE(buyer_group, 'Unknown')
|
|
ORDER BY last_access DESC`, dealID)
|
|
if err != nil {
|
|
http.Error(w, "Error", 500)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
html := `<table class="w-full"><thead><tr class="border-b border-gray-800">
|
|
<th class="text-left px-4 py-2 text-xs font-medium text-gray-500 uppercase">Buyer Group</th>
|
|
<th class="text-left px-4 py-2 text-xs font-medium text-gray-500 uppercase">Downloads</th>
|
|
<th class="text-left px-4 py-2 text-xs font-medium text-gray-500 uppercase">Last Accessed</th>
|
|
<th class="text-left px-4 py-2 text-xs font-medium text-gray-500 uppercase">Total Time</th>
|
|
<th class="text-left px-4 py-2 text-xs font-medium text-gray-500 uppercase">Files Viewed</th>
|
|
</tr></thead><tbody class="divide-y divide-gray-800/50">`
|
|
|
|
hasRows := false
|
|
for rows.Next() {
|
|
hasRows = true
|
|
var bg, lastAccess string
|
|
var downloads, totalTime, views int
|
|
rows.Scan(&bg, &downloads, &lastAccess, &totalTime, &views)
|
|
timeStr := fmt.Sprintf("%dm", totalTime/60)
|
|
if totalTime < 60 {
|
|
timeStr = fmt.Sprintf("%ds", totalTime)
|
|
}
|
|
html += fmt.Sprintf(`<tr class="hover:bg-gray-800/30">
|
|
<td class="px-4 py-2 text-sm font-medium text-teal-400">%s</td>
|
|
<td class="px-4 py-2 text-sm text-gray-400">%d</td>
|
|
<td class="px-4 py-2 text-xs text-gray-500">%s</td>
|
|
<td class="px-4 py-2 text-sm text-gray-400">%s</td>
|
|
<td class="px-4 py-2 text-sm text-gray-400">%d</td>
|
|
</tr>`, bg, downloads, lastAccess, timeStr, views)
|
|
}
|
|
if !hasRows {
|
|
html += `<tr><td colspan="5" class="px-4 py-4 text-center text-gray-600 text-sm">No buyer activity recorded yet.</td></tr>`
|
|
}
|
|
|
|
html += `</tbody></table>`
|
|
w.Write([]byte(html))
|
|
}
|