Parcourir la source

Dashboard: click an outcome count to list its businesses; method split in daily activity tooltip

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
master
Daniel Covington il y a 2 semaines
Parent
révision
0797024437
7 fichiers modifiés avec 42 ajouts et 11 suppressions
  1. +1
    -1
      app/controllers/BusinessesController.asp
  2. +1
    -1
      app/controllers/ExportController.asp
  3. +1
    -1
      app/lib/lib.BusinessHelpers.asp
  4. +13
    -1
      app/repositories/BusinessRepository.asp
  5. +17
    -5
      app/repositories/StatsRepository.asp
  6. +7
    -0
      app/views/Businesses/index.asp
  7. +2
    -2
      app/views/Dashboard/index.asp

+ 1
- 1
app/controllers/BusinessesController.asp Voir le fichier

@@ -32,7 +32,7 @@ Class BusinessesController_Class
Dim f, k, page, pageCount, result, rows, total, industries, areas, sort, dir, firstRow, lastRow Dim f, k, page, pageCount, result, rows, total, industries, areas, sort, dir, firstRow, lastRow


Set f = CreateObject("Scripting.Dictionary") Set f = CreateObject("Scripting.Dictionary")
For Each k In Array("q", "industry", "area", "status", "show", "contacted", "phone", "sort", "dir")
For Each k In Array("q", "industry", "area", "status", "show", "contacted", "phone", "outcome", "sort", "dir")
f(k) = Trim(CStr(Request.QueryString(k))) f(k) = Trim(CStr(Request.QueryString(k)))
Next Next
f("q") = Left(f("q"), 100) f("q") = Left(f("q"), 100)


+ 1
- 1
app/controllers/ExportController.asp Voir le fichier

@@ -31,7 +31,7 @@ Class ExportController_Class
Dim f, k, rs, line, n, fileName, areaNames, bizAreas Dim f, k, rs, line, n, fileName, areaNames, bizAreas


Set f = CreateObject("Scripting.Dictionary") Set f = CreateObject("Scripting.Dictionary")
For Each k In Array("q", "industry", "area", "status", "show", "contacted", "phone", "sort", "dir")
For Each k In Array("q", "industry", "area", "status", "show", "contacted", "phone", "outcome", "sort", "dir")
f(k) = Trim(CStr(Request.QueryString(k))) f(k) = Trim(CStr(Request.QueryString(k)))
Next Next
f("q") = Left(f("q"), 100) f("q") = Left(f("q"), 100)


+ 1
- 1
app/lib/lib.BusinessHelpers.asp Voir le fichier

@@ -87,7 +87,7 @@ End Function
Function Businesses_QS(f, page, sort, dir) Function Businesses_QS(f, page, sort, dir)
Dim k, s Dim k, s
s = "" s = ""
For Each k In Array("q", "industry", "area", "status", "show", "contacted", "phone")
For Each k In Array("q", "industry", "area", "status", "show", "contacted", "phone", "outcome")
If f.Exists(k) Then If f.Exists(k) Then
If Len(f(k)) > 0 Then s = s & "&" & k & "=" & Server.URLEncode(f(k)) If Len(f(k)) > 0 Then s = s & "&" & k & "=" & Server.URLEncode(f(k))
End If End If


+ 13
- 1
app/repositories/BusinessRepository.asp Voir le fichier

@@ -12,6 +12,7 @@
' show "" = everyone, "prospects", "customers" ' show "" = everyone, "prospects", "customers"
' contacted "never" = only businesses with no contact yet ' contacted "never" = only businesses with no contact yet
' phone "1" = only businesses with a phone number ' phone "1" = only businesses with a phone number
' outcome an outcome key (or "none") = businesses with a contact logged with that outcome in the last 30 days
' sort name | city | industry | area | status | last_contacted | next_action | added (default name) ' sort name | city | industry | area | status | last_contacted | next_action | added (default name)
' area sorts by each business's alphabetically first area; businesses with none sort first ' area sorts by each business's alphabetically first area; businesses with none sort first
' dir asc | desc ' dir asc | desc
@@ -343,7 +344,7 @@ Class BusinessRepository_Class
End Sub End Sub


Private Sub BuildWhere(f) Private Sub BuildWhere(f)
Dim terms, t, d, q, n, frag, ind, ar, st
Dim terms, t, d, q, n, frag, ind, ar, st, oc
m_where = "1=1" m_where = "1=1"
Set m_params = CreateObject("Scripting.Dictionary") Set m_params = CreateObject("Scripting.Dictionary")


@@ -406,6 +407,17 @@ Class BusinessRepository_Class


If Val_(f, "contacted") = "never" Then m_where = m_where & " AND b.last_contacted_at IS NULL" If Val_(f, "contacted") = "never" Then m_where = m_where & " AND b.last_contacted_at IS NULL"
If Val_(f, "phone") = "1" Then m_where = m_where & " AND b.phone_digits IS NOT NULL" If Val_(f, "phone") = "1" Then m_where = m_where & " AND b.phone_digits IS NOT NULL"

' Businesses with a contact logged in the last 30 days with this outcome (same window as the dashboard).
' "none" = contacts logged without an outcome. Inlined from a whitelist, not a ? marker (see area above).
oc = Val_(f, "outcome")
If oc = "none" Then
m_where = m_where & " AND EXISTS (SELECT x.id FROM interactions x WHERE x.business_id = b.id " & _
"AND x.contacted_at >= DateAdd('d', -29, Date()) AND (x.outcome IS NULL OR x.outcome = ''))"
ElseIf Businesses_IsKey(Businesses_Outcomes(), oc) Then
m_where = m_where & " AND EXISTS (SELECT x.id FROM interactions x WHERE x.business_id = b.id " & _
"AND x.contacted_at >= DateAdd('d', -29, Date()) AND x.outcome = '" & oc & "')"
End If
End Sub End Sub


' FROM clause for the list and export: the business, its industry, and fa.first_area (its alphabetically first ' FROM clause for the list and export: the business, its industry, and fa.first_area (its alphabetically first


+ 17
- 5
app/repositories/StatsRepository.asp Voir le fichier

@@ -46,13 +46,21 @@ Class StatsRepository_Class
Set ActivityCounts = d Set ActivityCounts = d
End Function End Function


' Contacts per day for the last `days` days, oldest first: list of Array(date, count) including zero days
' Contacts per day for the last `days` days, oldest first: list of Array(date, count, methods) including zero days.
' methods is a Dictionary of method key -> count for that day.
Public Function DailyActivity(days) Public Function DailyActivity(days)
Dim rs, counts, list, i, dt, key
Dim rs, counts, byMethod, list, i, dt, key, m
Set counts = CreateObject("Scripting.Dictionary") Set counts = CreateObject("Scripting.Dictionary")
Set rs = Db_Query("SELECT contacted_at, COUNT(*) FROM interactions WHERE contacted_at >= DateAdd('d', " & CLng(1 - days) & ", Date()) GROUP BY contacted_at", Array())
Set byMethod = CreateObject("Scripting.Dictionary")
Set rs = Db_Query("SELECT contacted_at, method, COUNT(*) FROM interactions WHERE contacted_at >= DateAdd('d', " & CLng(1 - days) & ", Date()) GROUP BY contacted_at, method", Array())
Do While Not rs.EOF Do While Not rs.EOF
If Not IsNull(rs(0)) Then counts(CStr(CLng(CDate(rs(0))))) = CLng(rs(1))
If Not IsNull(rs(0)) Then
key = CStr(CLng(CDate(rs(0))))
counts(key) = N(counts(key)) + CLng(rs(2))
If Not byMethod.Exists(key) Then Set byMethod(key) = CreateObject("Scripting.Dictionary")
m = rs(1) & ""
byMethod(key)(m) = N(byMethod(key)(m)) + CLng(rs(2))
End If
rs.MoveNext rs.MoveNext
Loop Loop
rs.Close rs.Close
@@ -60,7 +68,11 @@ Class StatsRepository_Class
For i = days - 1 To 0 Step -1 For i = days - 1 To 0 Step -1
dt = Date - i dt = Date - i
key = CStr(CLng(dt)) key = CStr(CLng(dt))
If counts.Exists(key) Then list.Add list.Count, Array(dt, counts(key)) Else list.Add list.Count, Array(dt, 0)
If counts.Exists(key) Then
list.Add list.Count, Array(dt, counts(key), byMethod(key))
Else
list.Add list.Count, Array(dt, 0, CreateObject("Scripting.Dictionary"))
End If
Next Next
Set DailyActivity = list Set DailyActivity = list
End Function End Function


+ 7
- 0
app/views/Businesses/index.asp Voir le fichier

@@ -66,6 +66,13 @@
</div> </div>
</div> </div>
</div> </div>
<% If Len(f("outcome")) > 0 Then %>
<input type="hidden" name="outcome" value="<%= H(f("outcome")) %>" />
<div class="mt-2 small">
<span class="badge text-bg-primary">Outcome: <% If f("outcome") = "none" Then Response.Write "(no outcome)" Else Response.Write H(Businesses_Label(Businesses_Outcomes(), f("outcome"))) %> &middot; last 30 days</span>
<a href="/businesses" class="ms-1">clear</a>
</div>
<% End If %>
<div class="mt-2"> <div class="mt-2">
<button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-search"></i> Search</button> <button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-search"></i> Search</button>
<a href="/businesses" class="btn btn-link btn-sm">Reset</a> <a href="/businesses" class="btn btn-link btn-sm">Reset</a>


+ 2
- 2
app/views/Dashboard/index.asp Voir le fichier

@@ -88,7 +88,7 @@ tiles = Array( _
dd = daily(di) dd = daily(di)
barPct = Round(dd(1) * 100 / maxDaily, 0) barPct = Round(dd(1) * 100 / maxDaily, 0)
If dd(1) > 0 And barPct < 6 Then barPct = 6 %> If dd(1) > 0 And barPct < 6 Then barPct = 6 %>
<div class="flex-fill d-flex flex-column justify-content-end align-items-center h-100" title="<%= Date_Fmt(dd(0)) %>: <%= dd(1) %>">
<div class="flex-fill d-flex flex-column justify-content-end align-items-center h-100" title="<%= Date_Fmt(dd(0)) %>: <%= dd(1) %> total&#10;<% For mi = 0 To UBound(Businesses_Methods()) %><%= H(Businesses_Methods()(mi)(1)) %>: <% If dd(2).Exists(Businesses_Methods()(mi)(0)) Then Response.Write dd(2)(Businesses_Methods()(mi)(0)) Else Response.Write 0 %><% If mi < UBound(Businesses_Methods()) Then Response.Write "&#10;" %><% Next %>">
<div class="small text-muted" style="font-size: .7rem;"><% If dd(1) > 0 Then Response.Write dd(1) %></div> <div class="small text-muted" style="font-size: .7rem;"><% If dd(1) > 0 Then Response.Write dd(1) %></div>
<div class="w-100 rounded-top <% If dd(0) = Date Then Response.Write "bg-primary" Else Response.Write "bg-primary-subtle" %>" style="height: <%= barPct %>%; min-height: <% If dd(1) > 0 Then Response.Write "2px" Else Response.Write "1px" %>;<% If dd(1) = 0 Then Response.Write " background:#dee2e6;" %>"></div> <div class="w-100 rounded-top <% If dd(0) = Date Then Response.Write "bg-primary" Else Response.Write "bg-primary-subtle" %>" style="height: <%= barPct %>%; min-height: <% If dd(1) > 0 Then Response.Write "2px" Else Response.Write "1px" %>;<% If dd(1) = 0 Then Response.Write " background:#dee2e6;" %>"></div>
</div> </div>
@@ -130,7 +130,7 @@ tiles = Array( _
ob = byOutcome(oi) %> ob = byOutcome(oi) %>
<tr> <tr>
<td><% If Len(ob(0)) = 0 Then Response.Write "<span class=""text-muted"">(no outcome)</span>" Else Response.Write H(Businesses_Label(Businesses_Outcomes(), ob(0))) %></td> <td><% If Len(ob(0)) = 0 Then Response.Write "<span class=""text-muted"">(no outcome)</span>" Else Response.Write H(Businesses_Label(Businesses_Outcomes(), ob(0))) %></td>
<td class="text-end"><%= FormatNumber(ob(1), 0) %></td>
<td class="text-end"><a href="/businesses?status=all&amp;outcome=<% If Len(ob(0)) = 0 Then Response.Write "none" Else Response.Write Server.URLEncode(ob(0)) %>" class="text-decoration-none" title="List these businesses"><%= FormatNumber(ob(1), 0) %></a></td>
</tr> </tr>
<% Next %> <% Next %>
</table> </table>


Chargement…
Annuler
Enregistrer

Powered by TurnKey Linux.