Преглед изворни кода

Refactor project into generic starter template

- remove domain-specific controllers, models, repositories, and views

- keep only Home/Error starter routing and controller registry entries

- add IIS Express startup support with run_site.cmd and applicationhost.config

Co-Authored-By: Abacus.AI CLI <agent@abacus.ai>
master
Daniel Covington пре 3 дана
родитељ
комит
e15cf7bf56
27 измењених фајлова са 1043 додато и 4483 уклоњено
  1. +0
    -397
      app/controllers/HouseholdController.asp
  2. +0
    -284
      app/controllers/HouseholderNameController.asp
  3. +0
    -226
      app/controllers/TerritoryController.asp
  4. +1
    -4
      app/controllers/autoload_controllers.asp
  5. +0
    -176
      app/models/HouseholderNamesRepository.asp
  6. +0
    -243
      app/models/HouseholdsRepository.asp
  7. +0
    -133
      app/models/POBO_HouseholderNames.asp
  8. +0
    -172
      app/models/POBO_Households.asp
  9. +0
    -103
      app/models/POBO_Territories.asp
  10. +0
    -176
      app/models/TerritoriesRepository.asp
  11. +0
    -153
      app/views/Household/create.asp
  12. +0
    -190
      app/views/Household/edit.asp
  13. +0
    -187
      app/views/Household/index.asp
  14. +0
    -291
      app/views/Household/show.asp
  15. +0
    -86
      app/views/HouseholderName/create.asp
  16. +0
    -95
      app/views/HouseholderName/edit.asp
  17. +0
    -171
      app/views/HouseholderName/index.asp
  18. +0
    -90
      app/views/HouseholderName/show.asp
  19. +0
    -134
      app/views/Territory/create.asp
  20. +0
    -164
      app/views/Territory/edit.asp
  21. +0
    -150
      app/views/Territory/index.asp
  22. +0
    -813
      app/views/Territory/show.asp
  23. +4
    -10
      app/views/shared/header.asp
  24. +1030
    -0
      applicationhost.config
  25. +0
    -3
      core/lib.ControllerRegistry.asp
  26. +4
    -32
      public/Default.asp
  27. +4
    -0
      run_site.cmd

+ 0
- 397
app/controllers/HouseholdController.asp Прегледај датотеку

@@ -1,397 +0,0 @@
<%
' HouseholdController - CRUD controller for Households
' NorthTerritory app
'
' Dependencies:
' - app/models/POBO_Households.asp
' - app/models/HouseholdsRepository.asp
' - app/models/POBO_HouseholderNames.asp
' - app/models/HouseholderNamesRepository.asp
%>
<!--#include file="../models/POBO_Households.asp" -->
<!--#include file="../models/HouseholdsRepository.asp" -->
<!--#include file="../models/POBO_HouseholderNames.asp" -->
<!--#include file="../models/HouseholderNamesRepository.asp" -->
<%

Class HouseholdController_Class
Private m_useLayout
Private m_title

' Public properties for views
Public households ' LinkedList for Index
Public household ' Single POBO for Show/Edit
Public territoriesList ' For dropdown
Public territoryNamesById ' Dictionary for territory labels
Public householderNames ' LinkedList for Show

' Pagination properties
Public currentPage
Public pageCount
Public recordCount
Public perPage
Public searchTerm
Public filterTerritoryId
Public filterDoNotCall

Private Sub Class_Initialize()
m_useLayout = True
m_title = "Households"
currentPage = 1
pageCount = 0
recordCount = 0
perPage = 25
searchTerm = ""
filterTerritoryId = 0
filterDoNotCall = -1
End Sub

Public Property Get useLayout
useLayout = m_useLayout
End Property

Public Property Let useLayout(v)
m_useLayout = v
End Property

Public Property Get Title
Title = m_title
End Property

Public Property Let Title(v)
m_title = v
End Property

'-------------------------------------------------------------------------------------------------------------------
' Index - List all households with pagination, search, and territory filter
'-------------------------------------------------------------------------------------------------------------------
Public Sub Index()
' Get pagination params
If Request.QueryString("page") <> "" And IsNumeric(Request.QueryString("page")) Then
currentPage = CInt(Request.QueryString("page"))
If currentPage < 1 Then currentPage = 1
End If

' Get search param
searchTerm = Trim(Request.QueryString("q") & "")

' Get territory filter
If Request.QueryString("territory") <> "" And IsNumeric(Request.QueryString("territory")) Then
filterTerritoryId = CInt(Request.QueryString("territory"))
End If

If Request.QueryString("dnc") <> "" Then
If Request.QueryString("dnc") = "1" Then
filterDoNotCall = 1
ElseIf Request.QueryString("dnc") = "0" Then
filterDoNotCall = 0
End If
End If

' Load territories for filter dropdown
Set territoriesList = TerritoriesRepository.GetAll(Empty)
Set territoryNamesById = BuildTerritoryNamesById(territoriesList)

' Fetch households with pagination
If searchTerm <> "" And filterDoNotCall <> -1 Then
Set households = HouseholdsRepository.SearchTablePagedByDoNotCall( _
Array("Address", "StreetName"), _
searchTerm, _
filterDoNotCall, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
ElseIf searchTerm <> "" Then
' Search in Address and StreetName columns
Set households = HouseholdsRepository.SearchTablePaged( _
Array("Address", "StreetName"), _
searchTerm, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
ElseIf filterTerritoryId > 0 And filterDoNotCall <> -1 Then
Set households = HouseholdsRepository.FindPagedByTerritoryAndDoNotCall( _
filterTerritoryId, _
filterDoNotCall, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
ElseIf filterTerritoryId > 0 Then
' Filter by territory
Set households = HouseholdsRepository.FindPaged( _
Array("TerritoryId", filterTerritoryId), _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
ElseIf filterDoNotCall <> -1 Then
Set households = HouseholdsRepository.FindPaged( _
Array("DoNotCall", filterDoNotCall), _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
Else
Set households = HouseholdsRepository.FindPaged( _
Empty, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
End If

%> <!--#include file="../views/Household/index.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Show - Display a single household
'-------------------------------------------------------------------------------------------------------------------
Public Sub Show(id)
On Error Resume Next
Set household = HouseholdsRepository.FindByID(id)
If Err.Number <> 0 Or household Is Nothing Then
On Error GoTo 0
Flash().AddError "Household not found."
Response.Redirect "/households"
Exit Sub
End If
On Error GoTo 0

' Load householder names for this household
Set householderNames = HouseholderNamesRepository.Find( _
Array("HouseholdId", id), _
"Name" _
)

%> <!--#include file="../views/Household/show.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' MarkReturned - Quick action to mark a householder name as returned
'-------------------------------------------------------------------------------------------------------------------
Public Sub MarkReturned(id)
Dim householderId, hn, householdId
householderId = Request.Form("householder_id")

If householderId = "" Or Not IsNumeric(householderId) Then
Flash().Error = "Invalid householder ID."
Response.Redirect "/households/" & id
Exit Sub
End If

On Error Resume Next
Set hn = HouseholderNamesRepository.FindByID(CLng(householderId))
If Err.Number <> 0 Or hn Is Nothing Then
On Error GoTo 0
Flash().Error = "Householder name not found."
Response.Redirect "/households/" & id
Exit Sub
End If
On Error GoTo 0

' Toggle the returned status
If hn.LetterReturned = 1 Then
hn.LetterReturned = 0
hn.ReturnDate = #1/1/1970#
Else
hn.LetterReturned = 1
hn.ReturnDate = Now()
End If

HouseholderNamesRepository.Update hn

If hn.LetterReturned = 1 Then
Flash().Success = "Marked as returned."
Else
Flash().Success = "Marked as not returned."
End If
Response.Redirect "/households/" & id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Create - Display form for new household
'-------------------------------------------------------------------------------------------------------------------
Public Sub Create()
Set household = New POBO_Households

' Pre-fill territory if passed in query string
If Request.QueryString("territory") <> "" And IsNumeric(Request.QueryString("territory")) Then
household.TerritoryId = CInt(Request.QueryString("territory"))
End If

' Load territories for dropdown
Set territoriesList = TerritoriesRepository.GetAll(Empty)

%> <!--#include file="../views/Household/create.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Store - Save new household
'-------------------------------------------------------------------------------------------------------------------
Public Sub Store()
Set household = New POBO_Households
household.Address = Trim(Request.Form("Address"))
household.StreetNumber = Request.Form("StreetNumber")
household.StreetName = Trim(Request.Form("StreetName"))
household.Latitude = Trim(Request.Form("Latitude"))
household.Longitude = Trim(Request.Form("Longitude"))
household.IsBusiness = IIf(Request.Form("IsBusiness") = "1", 1, 0)
household.DoNotCall = IIf(Request.Form("DoNotCall") = "1", 1, 0)
household.DoNotCallNotes = Trim(Request.Form("DoNotCallNotes"))
household.DoNotCallPrivateNotes = Trim(Request.Form("DoNotCallPrivateNotes"))
household.TerritoryId = Request.Form("TerritoryId")

If Request.Form("DoNotCallDate") <> "" Then
household.DoNotCallDate = CDate(Request.Form("DoNotCallDate"))
ElseIf household.DoNotCall = 1 Then
household.DoNotCallDate = Date()
Else
household.DoNotCallDate = Null
End If

' Validation
If household.Address = "" Then
Flash().AddError "Address is required."
Response.Redirect "/households/new"
Exit Sub
End If

If Not IsNumeric(household.TerritoryId) Or CInt(household.TerritoryId) < 1 Then
Flash().AddError "Please select a territory."
Response.Redirect "/households/new"
Exit Sub
End If

HouseholdsRepository.AddNew household

Flash().Success = "Household created successfully."
Response.Redirect "/households/" & household.Id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Edit - Display form to edit household
'-------------------------------------------------------------------------------------------------------------------
Public Sub Edit(id)
On Error Resume Next
Set household = HouseholdsRepository.FindByID(id)
If Err.Number <> 0 Or household Is Nothing Then
On Error GoTo 0
Flash().AddError "Household not found."
Response.Redirect "/households"
Exit Sub
End If
On Error GoTo 0

' Load territories for dropdown
Set territoriesList = TerritoriesRepository.GetAll(Empty)

%> <!--#include file="../views/Household/edit.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Update - Save changes to household
'-------------------------------------------------------------------------------------------------------------------
Public Sub Update(id)
On Error Resume Next
Set household = HouseholdsRepository.FindByID(id)
If Err.Number <> 0 Or household Is Nothing Then
On Error GoTo 0
Flash().AddError "Household not found."
Response.Redirect "/households"
Exit Sub
End If
On Error GoTo 0

household.Address = Trim(Request.Form("Address"))
household.StreetNumber = Request.Form("StreetNumber")
household.StreetName = Trim(Request.Form("StreetName"))
household.Latitude = Trim(Request.Form("Latitude"))
household.Longitude = Trim(Request.Form("Longitude"))
household.IsBusiness = IIf(Request.Form("IsBusiness") = "1", 1, 0)
household.DoNotCall = IIf(Request.Form("DoNotCall") = "1", 1, 0)
household.DoNotCallNotes = Trim(Request.Form("DoNotCallNotes"))
household.DoNotCallPrivateNotes = Trim(Request.Form("DoNotCallPrivateNotes"))
household.TerritoryId = Request.Form("TerritoryId")

If Request.Form("DoNotCallDate") <> "" Then
household.DoNotCallDate = CDate(Request.Form("DoNotCallDate"))
ElseIf household.DoNotCall = 1 Then
If IsNull(household.DoNotCallDate) Then
household.DoNotCallDate = Date()
ElseIf Trim(CStr(household.DoNotCallDate)) = "" Then
household.DoNotCallDate = Date()
End If
Else
household.DoNotCallDate = Null
End If

' Validation
If household.Address = "" Then
Flash().AddError "Address is required."
Response.Redirect "/households/" & id & "/edit"
Exit Sub
End If

HouseholdsRepository.Update household

Flash().Success = "Household updated successfully."
Response.Redirect "/households/" & id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Delete - Remove a household
'-------------------------------------------------------------------------------------------------------------------
Public Sub Delete(id)
On Error Resume Next
Set household = HouseholdsRepository.FindByID(id)
If Err.Number <> 0 Or household Is Nothing Then
On Error GoTo 0
Flash().AddError "Household not found."
Response.Redirect "/households"
Exit Sub
End If
On Error GoTo 0

HouseholdsRepository.Delete id

Flash().Success = "Household deleted successfully."
Response.Redirect "/households"
End Sub

Private Function BuildTerritoryNamesById(territories)
Dim dict : Set dict = Server.CreateObject("Scripting.Dictionary")
Dim iter, territory
Set iter = territories.Iterator()
Do While iter.HasNext()
Set territory = iter.GetNext()
dict(CStr(territory.Id)) = territory.Name & ""
Loop
Set BuildTerritoryNamesById = dict
End Function

End Class

' Singleton instance
Dim HouseholdController_Class__Singleton
Function HouseholdController()
If IsEmpty(HouseholdController_Class__Singleton) Then
Set HouseholdController_Class__Singleton = New HouseholdController_Class
End If
Set HouseholdController = HouseholdController_Class__Singleton
End Function
%>

+ 0
- 284
app/controllers/HouseholderNameController.asp Прегледај датотеку

@@ -1,284 +0,0 @@
<%
' HouseholderNameController - CRUD controller for HouseholderNames
' NorthTerritory app
'
' Dependencies (all included via HouseholdController which loads first):
' - app/models/POBO_HouseholderNames.asp
' - app/models/HouseholderNamesRepository.asp
' - app/models/POBO_Households.asp
' - app/models/HouseholdsRepository.asp

Class HouseholderNameController_Class
Private m_useLayout
Private m_title

' Public properties for views
Public householderNames ' LinkedList for Index
Public householderName ' Single POBO for Show/Edit
Public household ' Parent household
Public householdsList ' For dropdown

' Pagination properties
Public currentPage
Public pageCount
Public recordCount
Public perPage
Public searchTerm
Public filterHouseholdId

Private Sub Class_Initialize()
m_useLayout = True
m_title = "Householder Names"
currentPage = 1
pageCount = 0
recordCount = 0
perPage = 25
searchTerm = ""
filterHouseholdId = 0
End Sub

Public Property Get useLayout
useLayout = m_useLayout
End Property

Public Property Let useLayout(v)
m_useLayout = v
End Property

Public Property Get Title
Title = m_title
End Property

Public Property Let Title(v)
m_title = v
End Property

'-------------------------------------------------------------------------------------------------------------------
' Index - List all householder names with pagination, search, and household filter
'-------------------------------------------------------------------------------------------------------------------
Public Sub Index()
' Get pagination params
If Request.QueryString("page") <> "" And IsNumeric(Request.QueryString("page")) Then
currentPage = CInt(Request.QueryString("page"))
If currentPage < 1 Then currentPage = 1
End If

' Get search param
searchTerm = Trim(Request.QueryString("q") & "")

' Get household filter
If Request.QueryString("household") <> "" And IsNumeric(Request.QueryString("household")) Then
filterHouseholdId = CLng(Request.QueryString("household"))
End If

' Fetch householder names with pagination
If searchTerm <> "" Then
' Search in Name column
Set householderNames = HouseholderNamesRepository.SearchTablePaged( _
Array("Name"), _
searchTerm, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
ElseIf filterHouseholdId > 0 Then
' Filter by household
Set householderNames = HouseholderNamesRepository.FindPaged( _
Array("HouseholdId", filterHouseholdId), _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
' Load parent household for context
On Error Resume Next
Set household = HouseholdsRepository.FindByID(filterHouseholdId)
On Error GoTo 0
Else
Set householderNames = HouseholderNamesRepository.FindPaged( _
Empty, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
End If

%> <!--#include file="../views/HouseholderName/index.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Show - Display a single householder name
'-------------------------------------------------------------------------------------------------------------------
Public Sub Show(id)
On Error Resume Next
Set householderName = HouseholderNamesRepository.FindByID(id)
If Err.Number <> 0 Or householderName Is Nothing Then
On Error GoTo 0
Flash().Error = "Householder name not found."
Response.Redirect "/householder-names"
Exit Sub
End If
On Error GoTo 0

' Load parent household
On Error Resume Next
Set household = HouseholdsRepository.FindByID(householderName.HouseholdId)
On Error GoTo 0

%> <!--#include file="../views/HouseholderName/show.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Create - Display form for new householder name
'-------------------------------------------------------------------------------------------------------------------
Public Sub Create()
Set householderName = New POBO_HouseholderNames
householderName.Created = Now()
householderName.LetterReturned = 0

' Pre-fill household if passed in query string
If Request.QueryString("household") <> "" And IsNumeric(Request.QueryString("household")) Then
householderName.HouseholdId = CLng(Request.QueryString("household"))
' Load parent household for context
On Error Resume Next
Set household = HouseholdsRepository.FindByID(householderName.HouseholdId)
On Error GoTo 0
End If

%> <!--#include file="../views/HouseholderName/create.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Store - Save new householder name
'-------------------------------------------------------------------------------------------------------------------
Public Sub Store()
Set householderName = New POBO_HouseholderNames
householderName.Name = Trim(Request.Form("Name"))
householderName.HouseholdId = Request.Form("HouseholdId")
householderName.LetterReturned = IIf(Request.Form("LetterReturned") = "1", 1, 0)
householderName.Created = Now()

If Request.Form("ReturnDate") <> "" Then
On Error Resume Next
householderName.ReturnDate = CDate(Request.Form("ReturnDate"))
On Error GoTo 0
End If

' Validation
If householderName.Name = "" Then
Flash().Error = "Name is required."
Response.Redirect "/householder-names/new?household=" & householderName.HouseholdId
Exit Sub
End If

If Not IsNumeric(householderName.HouseholdId) Or CLng(householderName.HouseholdId) < 1 Then
Flash().Error = "Please select a household."
Response.Redirect "/householder-names/new"
Exit Sub
End If

HouseholderNamesRepository.AddNew householderName

Flash().Success = "Householder name created successfully."
Response.Redirect "/householder-names/" & householderName.Id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Edit - Display form to edit householder name
'-------------------------------------------------------------------------------------------------------------------
Public Sub Edit(id)
On Error Resume Next
Set householderName = HouseholderNamesRepository.FindByID(id)
If Err.Number <> 0 Or householderName Is Nothing Then
On Error GoTo 0
Flash().Error = "Householder name not found."
Response.Redirect "/householder-names"
Exit Sub
End If
On Error GoTo 0

' Load parent household for context
On Error Resume Next
Set household = HouseholdsRepository.FindByID(householderName.HouseholdId)
On Error GoTo 0

%> <!--#include file="../views/HouseholderName/edit.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Update - Save changes to householder name
'-------------------------------------------------------------------------------------------------------------------
Public Sub Update(id)
On Error Resume Next
Set householderName = HouseholderNamesRepository.FindByID(id)
If Err.Number <> 0 Or householderName Is Nothing Then
On Error GoTo 0
Flash().Error = "Householder name not found."
Response.Redirect "/householder-names"
Exit Sub
End If
On Error GoTo 0

householderName.Name = Trim(Request.Form("Name"))
householderName.LetterReturned = IIf(Request.Form("LetterReturned") = "1", 1, 0)

If Request.Form("ReturnDate") <> "" Then
On Error Resume Next
householderName.ReturnDate = CDate(Request.Form("ReturnDate"))
On Error GoTo 0
Else
householderName.ReturnDate = #1/1/1970#
End If

' Validation
If householderName.Name = "" Then
Flash().Error = "Name is required."
Response.Redirect "/householder-names/" & id & "/edit"
Exit Sub
End If

HouseholderNamesRepository.Update householderName

Flash().Success = "Householder name updated successfully."
Response.Redirect "/householder-names/" & id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Delete - Remove a householder name
'-------------------------------------------------------------------------------------------------------------------
Public Sub Delete(id)
On Error Resume Next
Set householderName = HouseholderNamesRepository.FindByID(id)
If Err.Number <> 0 Or householderName Is Nothing Then
On Error GoTo 0
Flash().Error = "Householder name not found."
Response.Redirect "/householder-names"
Exit Sub
End If
On Error GoTo 0

Dim householdId
householdId = householderName.HouseholdId

HouseholderNamesRepository.Delete id

Flash().Success = "Householder name deleted successfully."
Response.Redirect "/householder-names?household=" & householdId
End Sub

End Class

' Singleton instance
Dim HouseholderNameController_Class__Singleton
Function HouseholderNameController()
If IsEmpty(HouseholderNameController_Class__Singleton) Then
Set HouseholderNameController_Class__Singleton = New HouseholderNameController_Class
End If
Set HouseholderNameController = HouseholderNameController_Class__Singleton
End Function
%>

+ 0
- 226
app/controllers/TerritoryController.asp Прегледај датотеку

@@ -1,226 +0,0 @@
<%
' TerritoryController - CRUD controller for Territories
' Generated for NorthTerritory app
'
' Dependencies:
' - app/models/POBO_Territories.asp
' - app/models/TerritoriesRepository.asp
%>
<!--#include file="../models/POBO_Territories.asp" -->
<!--#include file="../models/TerritoriesRepository.asp" -->
<%

Class TerritoryController_Class
Private m_useLayout
Private m_title

' Public properties for views
Public territories ' LinkedList for Index
Public territory ' Single POBO for Show/Edit
Public territoryHouseholdCounts
Public territoryStreets ' LinkedList of street names for Show

' Pagination properties
Public currentPage
Public pageCount
Public recordCount
Public perPage
Public searchTerm

Private Sub Class_Initialize()
m_useLayout = True
m_title = "Territories"
currentPage = 1
pageCount = 0
recordCount = 0
perPage = 20
searchTerm = ""
Set territoryHouseholdCounts = Nothing
End Sub

Public Property Get useLayout
useLayout = m_useLayout
End Property

Public Property Let useLayout(v)
m_useLayout = v
End Property

Public Property Get Title
Title = m_title
End Property

Public Property Let Title(v)
m_title = v
End Property

'-------------------------------------------------------------------------------------------------------------------
' Index - List all territories with pagination and search
'-------------------------------------------------------------------------------------------------------------------
Public Sub Index()
' Get pagination params
If Request.QueryString("page") <> "" And IsNumeric(Request.QueryString("page")) Then
currentPage = CInt(Request.QueryString("page"))
If currentPage < 1 Then currentPage = 1
End If

' Get search param
searchTerm = Trim(Request.QueryString("q") & "")

' Fetch territories with pagination
If searchTerm <> "" Then
' Search in Name and Description columns
Set territories = TerritoriesRepository.SearchTablePaged( _
Array("Name", "Description"), _
searchTerm, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
Else
Set territories = TerritoriesRepository.FindPaged( _
Empty, _
Empty, _
perPage, _
currentPage, _
pageCount, _
recordCount _
)
End If

Set territoryHouseholdCounts = HouseholdsRepository.GetCountsByTerritory()

%> <!--#include file="../views/Territory/index.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Show - Display a single territory
'-------------------------------------------------------------------------------------------------------------------
Public Sub Show(id)
On Error Resume Next
Set territory = TerritoriesRepository.FindByID(id)
If Err.Number <> 0 Or territory Is Nothing Then
On Error GoTo 0
Flash().AddError "Territory not found."
Response.Redirect "/territories"
Exit Sub
End If
On Error GoTo 0

' Load distinct street names for this territory
Set territoryStreets = HouseholdsRepository.GetDistinctStreetsByTerritory(id)

%> <!--#include file="../views/Territory/show.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Create - Display form for new territory
'-------------------------------------------------------------------------------------------------------------------
Public Sub Create()
Set territory = New POBO_Territories
%> <!--#include file="../views/Territory/create.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Store - Save new territory
'-------------------------------------------------------------------------------------------------------------------
Public Sub Store()
Set territory = New POBO_Territories
territory.Name = Trim(Request.Form("Name"))
territory.Description = Trim(Request.Form("Description"))
territory.Coordinates = Trim(Request.Form("Coordinates"))

' Validation
If territory.Name = "" Then
Flash().AddError "Name is required."
Response.Redirect "/territories/new"
Exit Sub
End If

TerritoriesRepository.AddNew territory

Flash().Success = "Territory created successfully."
Response.Redirect "/territories/" & territory.Id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Edit - Display form to edit territory
'-------------------------------------------------------------------------------------------------------------------
Public Sub Edit(id)
On Error Resume Next
Set territory = TerritoriesRepository.FindByID(id)
If Err.Number <> 0 Or territory Is Nothing Then
On Error GoTo 0
Flash().AddError "Territory not found."
Response.Redirect "/territories"
Exit Sub
End If
On Error GoTo 0

%> <!--#include file="../views/Territory/edit.asp" --> <%
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Update - Save changes to territory
'-------------------------------------------------------------------------------------------------------------------
Public Sub Update(id)
On Error Resume Next
Set territory = TerritoriesRepository.FindByID(id)
If Err.Number <> 0 Or territory Is Nothing Then
On Error GoTo 0
Flash().AddError "Territory not found."
Response.Redirect "/territories"
Exit Sub
End If
On Error GoTo 0

territory.Name = Trim(Request.Form("Name"))
territory.Description = Trim(Request.Form("Description"))
territory.Coordinates = Trim(Request.Form("Coordinates"))

' Validation
If territory.Name = "" Then
Flash().AddError "Name is required."
Response.Redirect "/territories/" & id & "/edit"
Exit Sub
End If

TerritoriesRepository.Update territory

Flash().Success = "Territory updated successfully."
Response.Redirect "/territories/" & id
End Sub

'-------------------------------------------------------------------------------------------------------------------
' Delete - Remove a territory
'-------------------------------------------------------------------------------------------------------------------
Public Sub Delete(id)
On Error Resume Next
Set territory = TerritoriesRepository.FindByID(id)
If Err.Number <> 0 Or territory Is Nothing Then
On Error GoTo 0
Flash().AddError "Territory not found."
Response.Redirect "/territories"
Exit Sub
End If
On Error GoTo 0

TerritoriesRepository.Delete id

Flash().Success = "Territory deleted successfully."
Response.Redirect "/territories"
End Sub

End Class

' Singleton instance
Dim TerritoryController_Class__Singleton
Function TerritoryController()
If IsEmpty(TerritoryController_Class__Singleton) Then
Set TerritoryController_Class__Singleton = New TerritoryController_Class
End If
Set TerritoryController = TerritoryController_Class__Singleton
End Function
%>

+ 1
- 4
app/controllers/autoload_controllers.asp Прегледај датотеку

@@ -1,5 +1,2 @@
<!--#include file="ErrorController.asp" -->
<!--#include file="HomeController.asp" -->
<!--#include file="TerritoryController.asp" -->
<!--#include file="HouseholdController.asp" -->
<!--#include file="HouseholderNameController.asp" -->
<!--#include file="ErrorController.asp" -->

+ 0
- 176
app/models/HouseholderNamesRepository.asp Прегледај датотеку

@@ -1,176 +0,0 @@
<%
' Auto-generated Repository for table [HouseholderNames]
' Generated on 1/17/2026 7:59:02 PM
' Generator: GenerateRepo.vbs v1.0
'
' Dependencies:
' - core/lib.DAL.asp (DAL singleton for database access)
' - core/lib.AutoMapper.asp (Automapper for object mapping)
' - core/lib.Collections.asp (LinkedList_Class)
' - core/lib.helpers.asp (KVUnzip, BuildOrderBy, QI, Destroy)


Class HouseholderNamesRepository_Class

Public Function FindByID(id)
Dim sql : sql = "Select [Created], [HouseholdId], [Id], [LetterReturned], [Name], [ReturnDate] FROM [HouseholderNames] WHERE [Id] = ?"
Dim rs : Set rs = DAL.Query(sql, Array(id))
If rs.EOF Then
Err.Raise 1, "HouseholderNamesRepository_Class", RecordNotFoundException("Id", id)
Else
Set FindByID = Automapper.AutoMap(rs, "POBO_HouseholderNames")
End If
Destroy rs
End Function

Public Function GetAll(orderBy)
Set GetAll = Find(Empty, orderBy)
End Function

Public Function Find(where_kvarray, order_string_or_array)
Dim sql : sql = "Select [Created], [HouseholdId], [Id], [LetterReturned], [Name], [ReturnDate] FROM [HouseholderNames]"
Dim where_keys, where_values, i
If Not IsEmpty(where_kvarray) Then
KVUnzip where_kvarray, where_keys, where_values
If Not IsEmpty(where_keys) Then
sql = sql & " WHERE "
For i = 0 To UBound(where_keys)
If i > 0 Then sql = sql & " AND "
sql = sql & " " & QI(where_keys(i)) & " = ?"
Next
End If
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.Query(sql, where_values)
Dim list : Set list = new LinkedList_Class
Do Until rs.EOF
list.Push Automapper.AutoMap(rs, "POBO_HouseholderNames")
rs.MoveNext
Loop
Set Find = list
Destroy rs
End Function

Public Function FindPaged(where_kvarray, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Created], [HouseholdId], [Id], [LetterReturned], [Name], [ReturnDate] FROM [HouseholderNames]"
Dim where_keys, where_values, i
If Not IsEmpty(where_kvarray) Then
KVUnzip where_kvarray, where_keys, where_values
If Not IsEmpty(where_keys) Then
sql = sql & " WHERE "
For i = 0 To UBound(where_keys)
If i > 0 Then sql = sql & " AND "
sql = sql & " " & QI(where_keys(i)) & " = ?"
Next
End If
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, where_values, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set FindPaged = PagedList(rs, per_page)
Destroy rs
End Function

Public Function SearchTablePaged(columns_array, search_value, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Created], [HouseholdId], [Id], [LetterReturned], [Name], [ReturnDate] FROM [HouseholderNames]"
Dim i, params()
If IsArray(columns_array) And UBound(columns_array) >= 0 Then
sql = sql & " WHERE "
ReDim params(UBound(columns_array))
For i = 0 To UBound(columns_array)
If i > 0 Then sql = sql & " OR "
sql = sql & " " & QI(columns_array(i)) & " LIKE ?"
params(i) = "%" & search_value & "%"
Next
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, params, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set SearchTablePaged = PagedList(rs, per_page)
Destroy rs
End Function

Private Function PagedList(rs, per_page)
Dim list : Set list = new LinkedList_Class
Dim x : x = 0
Do While (per_page <= 0 Or x < per_page) And Not rs.EOF
list.Push Automapper.AutoMap(rs, "POBO_HouseholderNames")
x = x + 1
rs.MoveNext
Loop
Set PagedList = list
End Function

Public Sub AddNew(ByRef model)
Dim sql : sql = "INSERT INTO [HouseholderNames] ([Created], [HouseholdId], [LetterReturned], [Name], [ReturnDate]) VALUES (?, ?, ?, ?, ?)"
DAL.[Execute] sql, Array(model.Created, model.HouseholdId, model.LetterReturned, model.Name, model.ReturnDate)

' Retrieve the newly inserted ID
On Error Resume Next
Dim rsId : Set rsId = DAL.Query("SELECT @@IDENTITY AS NewID", Empty)
If Err.Number <> 0 Then
' Fallback for Access databases
Err.Clear
Set rsId = DAL.Query("SELECT TOP 1 [Id] FROM [HouseholderNames] ORDER BY [Id] DESC", Empty)
End If
On Error GoTo 0

If Not rsId.EOF Then
If Not IsNull(rsId(0)) Then model.Id = rsId(0)
End If
Destroy rsId
End Sub

Public Sub Update(model)
Dim sql : sql = "UPDATE [HouseholderNames] SET [Created] = ?, [HouseholdId] = ?, [LetterReturned] = ?, [Name] = ?, [ReturnDate] = ? WHERE [Id] = ?"
DAL.[Execute] sql, Array(model.Created, model.HouseholdId, model.LetterReturned, model.Name, model.ReturnDate, model.Id)
End Sub

Public Sub Delete(id)
Dim sql : sql = "DELETE FROM [HouseholderNames] WHERE [Id] = ?"
DAL.[Execute] sql, Array(id)
End Sub

Private Function RecordNotFoundException(ByVal field_name, ByVal field_val)
RecordNotFoundException = "HouseholderNames record was not found with " & field_name & " = '" & field_val & "'."
End Function

Private Function QI(name)
QI = "[" & Replace(CStr(name), "]", "]]") & "]"
End Function

Private Function BuildOrderBy(orderArg, defaultCol)
Dim s : s = ""
If IsEmpty(orderArg) Or IsNull(orderArg) Or orderArg = "" Then
s = " ORDER BY " & defaultCol & " ASC"
ElseIf IsArray(orderArg) Then
Dim i : s = " ORDER BY "
For i = 0 To UBound(orderArg)
If i > 0 Then s = s & ", "
s = s & QI(orderArg(i))
Next
Else
s = " ORDER BY " & QI(orderArg)
End If
BuildOrderBy = s
End Function
End Class

Dim HouseholderNamesRepository__Singleton
Function HouseholderNamesRepository()
If IsEmpty(HouseholderNamesRepository__Singleton) Then
Set HouseholderNamesRepository__Singleton = new HouseholderNamesRepository_Class
End If
Set HouseholderNamesRepository = HouseholderNamesRepository__Singleton
End Function
%>

+ 0
- 243
app/models/HouseholdsRepository.asp Прегледај датотеку

@@ -1,243 +0,0 @@
<%
' Auto-generated Repository for table [Households]
' Generator: GenerateRepo.vbs v1.0
'
' Dependencies:
' - core/lib.DAL.asp (DAL singleton for database access)
' - core/lib.AutoMapper.asp (Automapper for object mapping)
' - core/lib.Collections.asp (LinkedList_Class)
' - core/lib.helpers.asp (KVUnzip, BuildOrderBy, QI, Destroy)


Class HouseholdsRepository_Class

Public Function FindByID(id)
Dim sql : sql = "Select [Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [Id], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId] FROM [Households] WHERE [Id] = ?"
Dim rs : Set rs = DAL.Query(sql, Array(id))
If rs.EOF Then
Err.Raise 1, "HouseholdsRepository_Class", RecordNotFoundException("Id", id)
Else
Set FindByID = Automapper.AutoMap(rs, "POBO_Households")
End If
Destroy rs
End Function

Public Function GetAll(orderBy)
Set GetAll = Find(Empty, orderBy)
End Function

Public Function Find(where_kvarray, order_string_or_array)
Dim sql : sql = "Select [Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [Id], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId] FROM [Households]"
Dim where_keys, where_values, i
If Not IsEmpty(where_kvarray) Then
KVUnzip where_kvarray, where_keys, where_values
If Not IsEmpty(where_keys) Then
sql = sql & " WHERE "
For i = 0 To UBound(where_keys)
If i > 0 Then sql = sql & " AND "
sql = sql & " " & QI(where_keys(i)) & " = ?"
Next
End If
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.Query(sql, where_values)
Dim list : Set list = new LinkedList_Class
Do Until rs.EOF
list.Push Automapper.AutoMap(rs, "POBO_Households")
rs.MoveNext
Loop
Set Find = list
Destroy rs
End Function

Public Function FindPaged(where_kvarray, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [Id], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId] FROM [Households]"
Dim where_keys, where_values, i
If Not IsEmpty(where_kvarray) Then
KVUnzip where_kvarray, where_keys, where_values
If Not IsEmpty(where_keys) Then
sql = sql & " WHERE "
For i = 0 To UBound(where_keys)
If i > 0 Then sql = sql & " AND "
sql = sql & " " & QI(where_keys(i)) & " = ?"
Next
End If
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, where_values, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set FindPaged = PagedList(rs, per_page)
Destroy rs
End Function

Public Function SearchTablePaged(columns_array, search_value, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [Id], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId] FROM [Households]"
Dim i, params()
If IsArray(columns_array) And UBound(columns_array) >= 0 Then
sql = sql & " WHERE "
ReDim params(UBound(columns_array))
For i = 0 To UBound(columns_array)
If i > 0 Then sql = sql & " OR "
sql = sql & " " & QI(columns_array(i)) & " LIKE ?"
params(i) = "%" & search_value & "%"
Next
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, params, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set SearchTablePaged = PagedList(rs, per_page)
Destroy rs
End Function

Public Function SearchTablePagedByDoNotCall(columns_array, search_value, doNotCallValue, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [Id], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId] FROM [Households] WHERE [DoNotCall] = ?"
Dim i, params()
If IsArray(columns_array) And UBound(columns_array) >= 0 Then
ReDim params(UBound(columns_array) + 1)
params(0) = doNotCallValue
sql = sql & " AND ("
For i = 0 To UBound(columns_array)
If i > 0 Then sql = sql & " OR "
sql = sql & " " & QI(columns_array(i)) & " LIKE ?"
params(i + 1) = "%" & search_value & "%"
Next
sql = sql & ")"
Else
ReDim params(0)
params(0) = doNotCallValue
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, params, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set SearchTablePagedByDoNotCall = PagedList(rs, per_page)
Destroy rs
End Function

Public Function FindPagedByTerritoryAndDoNotCall(territoryId, doNotCallValue, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [Id], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId] FROM [Households] WHERE [TerritoryId] = ? AND [DoNotCall] = ?"
Dim rs : Set rs = DAL.PagedQuery(sql & BuildOrderBy(order_string_or_array, "[Id]"), Array(territoryId, doNotCallValue), per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set FindPagedByTerritoryAndDoNotCall = PagedList(rs, per_page)
Destroy rs
End Function

Private Function PagedList(rs, per_page)
Dim list : Set list = new LinkedList_Class
Dim x : x = 0
Do While (per_page <= 0 Or x < per_page) And Not rs.EOF
list.Push Automapper.AutoMap(rs, "POBO_Households")
x = x + 1
rs.MoveNext
Loop
Set PagedList = list
End Function

Public Function GetCountsByTerritory()
Dim sql : sql = "SELECT [TerritoryId], COUNT(*) AS [HouseholdCount] FROM [Households] GROUP BY [TerritoryId]"
Dim rs : Set rs = DAL.Query(sql, Empty)
Dim dict : Set dict = Server.CreateObject("Scripting.Dictionary")
Do Until rs.EOF
If Not IsNull(rs("TerritoryId")) Then
dict(CLng(rs("TerritoryId"))) = CLng(rs("HouseholdCount"))
End If
rs.MoveNext
Loop
Set GetCountsByTerritory = dict
Destroy rs
End Function

Public Function GetDistinctStreetsByTerritory(territoryId)
Dim sql : sql = "SELECT DISTINCT [StreetName] FROM [Households] WHERE [TerritoryId] = ? AND [StreetName] IS NOT NULL AND [StreetName] <> '' ORDER BY [StreetName]"
Dim rs : Set rs = DAL.Query(sql, Array(territoryId))
Dim list : Set list = new LinkedList_Class
Do Until rs.EOF
list.Push rs("StreetName") & ""
rs.MoveNext
Loop
Set GetDistinctStreetsByTerritory = list
Destroy rs
End Function

Public Sub AddNew(ByRef model)
Dim sql : sql = "INSERT INTO [Households] ([Address], [DoNotCall], [DoNotCallDate], [DoNotCallNotes], [DoNotCallPrivateNotes], [IsBusiness], [Latitude], [Longitude], [StreetName], [StreetNumber], [TerritoryId]) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
DAL.[Execute] sql, Array(model.Address, model.DoNotCall, model.DoNotCallDate, model.DoNotCallNotes, model.DoNotCallPrivateNotes, model.IsBusiness, model.Latitude, model.Longitude, model.StreetName, model.StreetNumber, model.TerritoryId)

' Retrieve the newly inserted ID
On Error Resume Next
Dim rsId : Set rsId = DAL.Query("SELECT @@IDENTITY AS NewID", Empty)
If Err.Number <> 0 Then
' Fallback for Access databases
Err.Clear
Set rsId = DAL.Query("SELECT TOP 1 [Id] FROM [Households] ORDER BY [Id] DESC", Empty)
End If
On Error GoTo 0

If Not rsId.EOF Then
If Not IsNull(rsId(0)) Then model.Id = rsId(0)
End If
Destroy rsId
End Sub

Public Sub Update(model)
Dim sql : sql = "UPDATE [Households] SET [Address] = ?, [DoNotCall] = ?, [DoNotCallDate] = ?, [DoNotCallNotes] = ?, [DoNotCallPrivateNotes] = ?, [IsBusiness] = ?, [Latitude] = ?, [Longitude] = ?, [StreetName] = ?, [StreetNumber] = ?, [TerritoryId] = ? WHERE [Id] = ?"
DAL.[Execute] sql, Array(model.Address, model.DoNotCall, model.DoNotCallDate, model.DoNotCallNotes, model.DoNotCallPrivateNotes, model.IsBusiness, model.Latitude, model.Longitude, model.StreetName, model.StreetNumber, model.TerritoryId, model.Id)
End Sub

Public Sub Delete(id)
Dim sql : sql = "DELETE FROM [Households] WHERE [Id] = ?"
DAL.[Execute] sql, Array(id)
End Sub

Private Function RecordNotFoundException(ByVal field_name, ByVal field_val)
RecordNotFoundException = "Households record was not found with " & field_name & " = '" & field_val & "'."
End Function

Private Function QI(name)
QI = "[" & Replace(CStr(name), "]", "]]") & "]"
End Function

Private Function BuildOrderBy(orderArg, defaultCol)
Dim s : s = ""
If IsEmpty(orderArg) Or IsNull(orderArg) Or orderArg = "" Then
s = " ORDER BY " & defaultCol & " ASC"
ElseIf IsArray(orderArg) Then
Dim i : s = " ORDER BY "
For i = 0 To UBound(orderArg)
If i > 0 Then s = s & ", "
s = s & QI(orderArg(i))
Next
Else
s = " ORDER BY " & QI(orderArg)
End If
BuildOrderBy = s
End Function
End Class

Dim HouseholdsRepository__Singleton
Function HouseholdsRepository()
If IsEmpty(HouseholdsRepository__Singleton) Then
Set HouseholdsRepository__Singleton = new HouseholdsRepository_Class
End If
Set HouseholdsRepository = HouseholdsRepository__Singleton
End Function
%>

+ 0
- 133
app/models/POBO_HouseholderNames.asp Прегледај датотеку

@@ -1,133 +0,0 @@
<%
' Auto-generated POBO for table [HouseholderNames]
' Generated on 1/17/2026 7:59:02 PM
' Generator: GenerateRepo.vbs v1.0
'
' Dependencies: core/helpers.asp (QuoteValue function)


Class POBO_HouseholderNames
' Public array of all property names
Public Properties

Private pCreated
Private pHouseholdId
Private pId
Private pLetterReturned
Private pName
Private pReturnDate

Private Sub Class_Initialize()
pCreated = #1/1/1970#
pHouseholdId = 0
pId = 0
pLetterReturned = 0
pName = Null
pReturnDate = #1/1/1970#
Properties = Array("Created","HouseholdId","Id","LetterReturned","Name","ReturnDate")
End Sub

Public Property Get PrimaryKey()
PrimaryKey = "Id"
End Property

Public Property Get TableName()
TableName = "HouseholderNames"
End Property

Public Property Get Created()
Created = pCreated
End Property

Public Property Let Created(val)
On Error Resume Next
pCreated = CDate(val)
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_HouseholderNames.Created", "Invalid value for Created: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get HouseholdId()
HouseholdId = pHouseholdId
End Property

Public Property Let HouseholdId(val)
On Error Resume Next
If IsNumeric(val) Then
pHouseholdId = CDbl(val)
Else
pHouseholdId = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_HouseholderNames.HouseholdId", "Invalid value for HouseholdId: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get Id()
Id = pId
End Property

Public Property Let Id(val)
On Error Resume Next
If IsNumeric(val) Then
pId = CDbl(val)
Else
pId = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_HouseholderNames.Id", "Invalid value for Id: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get LetterReturned()
LetterReturned = pLetterReturned
End Property

Public Property Let LetterReturned(val)
On Error Resume Next
If IsNumeric(val) Then
pLetterReturned = CDbl(val)
Else
pLetterReturned = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_HouseholderNames.LetterReturned", "Invalid value for LetterReturned: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get Name()
Name = pName
End Property

Public Property Let Name(val)
On Error Resume Next
If IsNumeric(val) Then
pName = CDbl(val)
Else
pName = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_HouseholderNames.Name", "Invalid value for Name: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get ReturnDate()
ReturnDate = pReturnDate
End Property

Public Property Let ReturnDate(val)
On Error Resume Next
pReturnDate = CDate(val)
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_HouseholderNames.ReturnDate", "Invalid value for ReturnDate: " & Err.Description
End If
On Error GoTo 0
End Property

End Class
%>

+ 0
- 172
app/models/POBO_Households.asp Прегледај датотеку

@@ -1,172 +0,0 @@
<%
' Auto-generated POBO for table [Households]
' Generator: GenerateRepo.vbs v1.0
'
' Dependencies: core/helpers.asp (QuoteValue function)


Class POBO_Households
' Public array of all property names
Public Properties

Private pAddress
Private pDoNotCall
Private pDoNotCallDate
Private pDoNotCallNotes
Private pDoNotCallPrivateNotes
Private pId
Private pIsBusiness
Private pLatitude
Private pLongitude
Private pStreetName
Private pStreetNumber
Private pTerritoryId

Private Sub Class_Initialize()
pAddress = Null
pDoNotCall = 0
pDoNotCallDate = Null
pDoNotCallNotes = Null
pDoNotCallPrivateNotes = Null
pId = 0
pIsBusiness = 0
pLatitude = Null
pLongitude = Null
pStreetName = Null
pStreetNumber = 0
pTerritoryId = 0
Properties = Array("Address","DoNotCall","DoNotCallDate","DoNotCallNotes","DoNotCallPrivateNotes","Id","IsBusiness","Latitude","Longitude","StreetName","StreetNumber","TerritoryId")
End Sub

Public Property Get PrimaryKey()
PrimaryKey = "Id"
End Property

Public Property Get TableName()
TableName = "Households"
End Property

Public Property Get Address()
Address = pAddress
End Property

Public Property Let Address(val)
pAddress = val
End Property

Public Property Get DoNotCall()
DoNotCall = pDoNotCall
End Property

Public Property Let DoNotCall(val)
If IsNumeric(val) Then
pDoNotCall = CLng(val)
Else
pDoNotCall = val
End If
End Property

Public Property Get DoNotCallDate()
DoNotCallDate = pDoNotCallDate
End Property

Public Property Let DoNotCallDate(val)
If IsNull(val) Then
pDoNotCallDate = Null
ElseIf Trim(CStr(val)) = "" Then
pDoNotCallDate = Null
Else
pDoNotCallDate = CDate(val)
End If
End Property

Public Property Get DoNotCallNotes()
DoNotCallNotes = pDoNotCallNotes
End Property

Public Property Let DoNotCallNotes(val)
pDoNotCallNotes = val
End Property

Public Property Get DoNotCallPrivateNotes()
DoNotCallPrivateNotes = pDoNotCallPrivateNotes
End Property

Public Property Let DoNotCallPrivateNotes(val)
pDoNotCallPrivateNotes = val
End Property

Public Property Get Id()
Id = pId
End Property

Public Property Let Id(val)
If IsNumeric(val) Then
pId = CLng(val)
Else
pId = val
End If
End Property

Public Property Get IsBusiness()
IsBusiness = pIsBusiness
End Property

Public Property Let IsBusiness(val)
If IsNumeric(val) Then
pIsBusiness = CLng(val)
Else
pIsBusiness = val
End If
End Property

Public Property Get Latitude()
Latitude = pLatitude
End Property

Public Property Let Latitude(val)
pLatitude = val
End Property

Public Property Get Longitude()
Longitude = pLongitude
End Property

Public Property Let Longitude(val)
pLongitude = val
End Property

Public Property Get StreetName()
StreetName = pStreetName
End Property

Public Property Let StreetName(val)
pStreetName = val
End Property

Public Property Get StreetNumber()
StreetNumber = pStreetNumber
End Property

Public Property Let StreetNumber(val)
If IsNumeric(val) Then
pStreetNumber = CLng(val)
Else
pStreetNumber = val
End If
End Property

Public Property Get TerritoryId()
TerritoryId = pTerritoryId
End Property

Public Property Let TerritoryId(val)
If IsNumeric(val) Then
pTerritoryId = CLng(val)
Else
pTerritoryId = val
End If
End Property

End Class
%>

+ 0
- 103
app/models/POBO_Territories.asp Прегледај датотеку

@@ -1,103 +0,0 @@
<%
' Auto-generated POBO for table [Territories]
' Generated on 1/17/2026 2:53:15 PM
' Generator: GenerateRepo.vbs v1.0
'
' Dependencies: core/helpers.asp (QuoteValue function)


Class POBO_Territories
' Public array of all property names
Public Properties

Private pCoordinates
Private pDescription
Private pId
Private pName

Private Sub Class_Initialize()
pCoordinates = Null
pDescription = Null
pId = 0
pName = Null
Properties = Array("Coordinates","Description","Id","Name")
End Sub

Public Property Get PrimaryKey()
PrimaryKey = "Id"
End Property

Public Property Get TableName()
TableName = "Territories"
End Property

Public Property Get Coordinates()
Coordinates = pCoordinates
End Property

Public Property Let Coordinates(val)
On Error Resume Next
If IsNumeric(val) Then
pCoordinates = CDbl(val)
Else
pCoordinates = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_Territories.Coordinates", "Invalid value for Coordinates: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get Description()
Description = pDescription
End Property

Public Property Let Description(val)
On Error Resume Next
If IsNumeric(val) Then
pDescription = CDbl(val)
Else
pDescription = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_Territories.Description", "Invalid value for Description: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get Id()
Id = pId
End Property

Public Property Let Id(val)
On Error Resume Next
If IsNumeric(val) Then
pId = CDbl(val)
Else
pId = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_Territories.Id", "Invalid value for Id: " & Err.Description
End If
On Error GoTo 0
End Property

Public Property Get Name()
Name = pName
End Property

Public Property Let Name(val)
On Error Resume Next
If IsNumeric(val) Then
pName = CDbl(val)
Else
pName = val
End If
If Err.Number <> 0 Then
Err.Raise Err.Number, "POBO_Territories.Name", "Invalid value for Name: " & Err.Description
End If
On Error GoTo 0
End Property

End Class
%>

+ 0
- 176
app/models/TerritoriesRepository.asp Прегледај датотеку

@@ -1,176 +0,0 @@
<%
' Auto-generated Repository for table [Territories]
' Generated on 1/17/2026 2:53:15 PM
' Generator: GenerateRepo.vbs v1.0
'
' Dependencies:
' - core/lib.DAL.asp (DAL singleton for database access)
' - core/lib.AutoMapper.asp (Automapper for object mapping)
' - core/lib.Collections.asp (LinkedList_Class)
' - core/lib.helpers.asp (KVUnzip, BuildOrderBy, QI, Destroy)


Class TerritoriesRepository_Class

Public Function FindByID(id)
Dim sql : sql = "Select [Coordinates], [Description], [Id], [Name] FROM [Territories] WHERE [Id] = ?"
Dim rs : Set rs = DAL.Query(sql, Array(id))
If rs.EOF Then
Err.Raise 1, "TerritoriesRepository_Class", RecordNotFoundException("Id", id)
Else
Set FindByID = Automapper.AutoMap(rs, "POBO_Territories")
End If
Destroy rs
End Function

Public Function GetAll(orderBy)
Set GetAll = Find(Empty, orderBy)
End Function

Public Function Find(where_kvarray, order_string_or_array)
Dim sql : sql = "Select [Coordinates], [Description], [Id], [Name] FROM [Territories]"
Dim where_keys, where_values, i
If Not IsEmpty(where_kvarray) Then
KVUnzip where_kvarray, where_keys, where_values
If Not IsEmpty(where_keys) Then
sql = sql & " WHERE "
For i = 0 To UBound(where_keys)
If i > 0 Then sql = sql & " AND "
sql = sql & " " & QI(where_keys(i)) & " = ?"
Next
End If
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.Query(sql, where_values)
Dim list : Set list = new LinkedList_Class
Do Until rs.EOF
list.Push Automapper.AutoMap(rs, "POBO_Territories")
rs.MoveNext
Loop
Set Find = list
Destroy rs
End Function

Public Function FindPaged(where_kvarray, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Coordinates], [Description], [Id], [Name] FROM [Territories]"
Dim where_keys, where_values, i
If Not IsEmpty(where_kvarray) Then
KVUnzip where_kvarray, where_keys, where_values
If Not IsEmpty(where_keys) Then
sql = sql & " WHERE "
For i = 0 To UBound(where_keys)
If i > 0 Then sql = sql & " AND "
sql = sql & " " & QI(where_keys(i)) & " = ?"
Next
End If
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, where_values, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set FindPaged = PagedList(rs, per_page)
Destroy rs
End Function

Public Function SearchTablePaged(columns_array, search_value, order_string_or_array, per_page, page_num, ByRef page_count, ByRef record_count)
Dim sql : sql = "Select [Coordinates], [Description], [Id], [Name] FROM [Territories]"
Dim i, params()
If IsArray(columns_array) And UBound(columns_array) >= 0 Then
sql = sql & " WHERE "
ReDim params(UBound(columns_array))
For i = 0 To UBound(columns_array)
If i > 0 Then sql = sql & " OR "
sql = sql & " " & QI(columns_array(i)) & " LIKE ?"
params(i) = "%" & search_value & "%"
Next
End If
sql = sql & BuildOrderBy(order_string_or_array, "[Id]")
Dim rs : Set rs = DAL.PagedQuery(sql, params, per_page, page_num)
If Not rs.EOF Then
rs.PageSize = per_page
rs.AbsolutePage = page_num
page_count = rs.PageCount
record_count = rs.RecordCount
End If
Set SearchTablePaged = PagedList(rs, per_page)
Destroy rs
End Function

Private Function PagedList(rs, per_page)
Dim list : Set list = new LinkedList_Class
Dim x : x = 0
Do While (per_page <= 0 Or x < per_page) And Not rs.EOF
list.Push Automapper.AutoMap(rs, "POBO_Territories")
x = x + 1
rs.MoveNext
Loop
Set PagedList = list
End Function

Public Sub AddNew(ByRef model)
Dim sql : sql = "INSERT INTO [Territories] ([Coordinates], [Description], [Name]) VALUES (?, ?, ?)"
DAL.[Execute] sql, Array(model.Coordinates, model.Description, model.Name)

' Retrieve the newly inserted ID
On Error Resume Next
Dim rsId : Set rsId = DAL.Query("SELECT @@IDENTITY AS NewID", Empty)
If Err.Number <> 0 Then
' Fallback for Access databases
Err.Clear
Set rsId = DAL.Query("SELECT TOP 1 [Id] FROM [Territories] ORDER BY [Id] DESC", Empty)
End If
On Error GoTo 0

If Not rsId.EOF Then
If Not IsNull(rsId(0)) Then model.Id = rsId(0)
End If
Destroy rsId
End Sub

Public Sub Update(model)
Dim sql : sql = "UPDATE [Territories] SET [Coordinates] = ?, [Description] = ?, [Name] = ? WHERE [Id] = ?"
DAL.[Execute] sql, Array(model.Coordinates, model.Description, model.Name, model.Id)
End Sub

Public Sub Delete(id)
Dim sql : sql = "DELETE FROM [Territories] WHERE [Id] = ?"
DAL.[Execute] sql, Array(id)
End Sub

Private Function RecordNotFoundException(ByVal field_name, ByVal field_val)
RecordNotFoundException = "Territories record was not found with " & field_name & " = '" & field_val & "'."
End Function

Private Function QI(name)
QI = "[" & Replace(CStr(name), "]", "]]") & "]"
End Function

Private Function BuildOrderBy(orderArg, defaultCol)
Dim s : s = ""
If IsEmpty(orderArg) Or IsNull(orderArg) Or orderArg = "" Then
s = " ORDER BY " & defaultCol & " ASC"
ElseIf IsArray(orderArg) Then
Dim i : s = " ORDER BY "
For i = 0 To UBound(orderArg)
If i > 0 Then s = s & ", "
s = s & QI(orderArg(i))
Next
Else
s = " ORDER BY " & QI(orderArg)
End If
BuildOrderBy = s
End Function
End Class

Dim TerritoriesRepository__Singleton
Function TerritoriesRepository()
If IsEmpty(TerritoriesRepository__Singleton) Then
Set TerritoriesRepository__Singleton = new TerritoriesRepository_Class
End If
Set TerritoriesRepository = TerritoriesRepository__Singleton
End Function
%>

+ 0
- 153
app/views/Household/create.asp Прегледај датотеку

@@ -1,153 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/households">Households</a></li>
<li class="breadcrumb-item active" aria-current="page">New Household</li>
</ol>
</nav>

<h1>New Household</h1>

<% Flash().ShowErrorsIfPresent %>

<div class="card">
<div class="card-body">
<form method="post" action="/households">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="Address" class="form-label">Address <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="Address" name="Address" required maxlength="255">
</div>

<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label for="StreetNumber" class="form-label">Street Number</label>
<input type="number" class="form-control" id="StreetNumber" name="StreetNumber" value="0">
</div>
</div>
<div class="col-md-8">
<div class="mb-3">
<label for="StreetName" class="form-label">Street Name</label>
<input type="text" class="form-control" id="StreetName" name="StreetName" maxlength="255">
</div>
</div>
</div>

<div class="mb-3">
<label for="TerritoryId" class="form-label">Territory <span class="text-danger">*</span></label>
<select class="form-select" id="TerritoryId" name="TerritoryId" required>
<option value="">Select a territory...</option>
<%
Dim tIter, tItem
Set tIter = HouseholdController.territoriesList.Iterator()
Do While tIter.HasNext()
Set tItem = tIter.GetNext()
%>
<option value="<%= tItem.Id %>" <% If tItem.Id = HouseholdController.household.TerritoryId Then Response.Write "selected" End If %>><%= Server.HTMLEncode(tItem.Name) %></option>
<%
Loop
%>
</select>
</div>

<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="IsBusiness" name="IsBusiness" value="1">
<label class="form-check-label" for="IsBusiness">
This household is a business
</label>
</div>
</div>

<div class="card border-danger-subtle mb-3">
<div class="card-body">
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="DoNotCall" name="DoNotCall" value="1">
<label class="form-check-label" for="DoNotCall">
Mark this household as Do Not Call
</label>
</div>

<div class="mb-3">
<label for="DoNotCallDate" class="form-label">Do Not Call Date</label>
<input type="date" class="form-control" id="DoNotCallDate" name="DoNotCallDate">
</div>

<div class="mb-3">
<label for="DoNotCallNotes" class="form-label">Do Not Call Notes</label>
<textarea class="form-control" id="DoNotCallNotes" name="DoNotCallNotes" rows="3"></textarea>
</div>

<div class="mb-0">
<label for="DoNotCallPrivateNotes" class="form-label">Private Do Not Call Notes</label>
<textarea class="form-control" id="DoNotCallPrivateNotes" name="DoNotCallPrivateNotes" rows="3"></textarea>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="Latitude" class="form-label">Latitude</label>
<input type="text" class="form-control" id="Latitude" name="Latitude" placeholder="-33.8688">
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="Longitude" class="form-label">Longitude</label>
<input type="text" class="form-control" id="Longitude" name="Longitude" placeholder="151.2093">
</div>
</div>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Create Household</button>
<a href="/households" class="btn btn-secondary">Cancel</a>
</div>
</div>
<div class="col-md-6">
<label class="form-label">Location (click to set coordinates)</label>
<div id="map" style="height: 350px; width: 100%; border-radius: 8px;"></div>
<small class="text-muted">Click on the map to set latitude and longitude.</small>
</div>
</div>
</form>
</div>
</div>
</div>

<script src="https://maps.googleapis.com/maps/api/js?key=<%= Server.HTMLEncode(GetAppSetting("GoogleMapsApiKey")) %>&callback=initMap" async defer></script>
<script>
var map, marker;

function initMap() {
var defaultCenter = { lat: -33.8688, lng: 151.2093 };

map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: defaultCenter,
mapTypeId: 'roadmap'
});

// Click to place marker and set coordinates
map.addListener('click', function(event) {
placeMarker(event.latLng);
});
}

function placeMarker(location) {
if (marker) {
marker.setPosition(location);
} else {
marker = new google.maps.Marker({
position: location,
map: map
});
}

document.getElementById('Latitude').value = location.lat().toFixed(6);
document.getElementById('Longitude').value = location.lng().toFixed(6);
}
</script>

+ 0
- 190
app/views/Household/edit.asp Прегледај датотеку

@@ -1,190 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/households">Households</a></li>
<li class="breadcrumb-item"><a href="/households/<%= HouseholdController.household.Id %>"><%= Server.HTMLEncode(HouseholdController.household.Address) %></a></li>
<li class="breadcrumb-item active" aria-current="page">Edit</li>
</ol>
</nav>

<h1>Edit Household</h1>

<% Flash().ShowErrorsIfPresent %>

<div class="card">
<div class="card-body">
<form method="post" action="/households/<%= HouseholdController.household.Id %>">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="Address" class="form-label">Address <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="Address" name="Address" required maxlength="255" value="<%= Server.HTMLEncode(HouseholdController.household.Address) %>">
</div>

<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label for="StreetNumber" class="form-label">Street Number</label>
<input type="number" class="form-control" id="StreetNumber" name="StreetNumber" value="<%= HouseholdController.household.StreetNumber %>">
</div>
</div>
<div class="col-md-8">
<div class="mb-3">
<label for="StreetName" class="form-label">Street Name</label>
<input type="text" class="form-control" id="StreetName" name="StreetName" maxlength="255" value="<%= Server.HTMLEncode(HouseholdController.household.StreetName & "") %>">
</div>
</div>
</div>

<div class="mb-3">
<label for="TerritoryId" class="form-label">Territory <span class="text-danger">*</span></label>
<select class="form-select" id="TerritoryId" name="TerritoryId" required>
<option value="">Select a territory...</option>
<%
Dim tIter, tItem
Set tIter = HouseholdController.territoriesList.Iterator()
Do While tIter.HasNext()
Set tItem = tIter.GetNext()
%>
<option value="<%= tItem.Id %>" <% If tItem.Id = HouseholdController.household.TerritoryId Then Response.Write "selected" End If %>><%= Server.HTMLEncode(tItem.Name) %></option>
<%
Loop
%>
</select>
</div>

<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="IsBusiness" name="IsBusiness" value="1"
<% If HouseholdController.household.IsBusiness = 1 Then Response.Write "checked" End If %>>
<label class="form-check-label" for="IsBusiness">
This household is a business
</label>
</div>
</div>

<%
Dim doNotCallDateVal, doNotCallNotesVal, doNotCallPrivateNotesVal
doNotCallDateVal = ""
doNotCallNotesVal = ""
doNotCallPrivateNotesVal = ""
If IsDate(HouseholdController.household.DoNotCallDate) Then
doNotCallDateVal = Year(HouseholdController.household.DoNotCallDate) & "-" & _
Right("0" & Month(HouseholdController.household.DoNotCallDate), 2) & "-" & _
Right("0" & Day(HouseholdController.household.DoNotCallDate), 2)
End If
If Not IsNull(HouseholdController.household.DoNotCallNotes) Then
doNotCallNotesVal = HouseholdController.household.DoNotCallNotes
End If
If Not IsNull(HouseholdController.household.DoNotCallPrivateNotes) Then
doNotCallPrivateNotesVal = HouseholdController.household.DoNotCallPrivateNotes
End If
%>
<div class="card border-danger-subtle mb-3">
<div class="card-body">
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="DoNotCall" name="DoNotCall" value="1"
<% If HouseholdController.household.DoNotCall = 1 Then Response.Write "checked" End If %>>
<label class="form-check-label" for="DoNotCall">
Mark this household as Do Not Call
</label>
</div>

<div class="mb-3">
<label for="DoNotCallDate" class="form-label">Do Not Call Date</label>
<input type="date" class="form-control" id="DoNotCallDate" name="DoNotCallDate" value="<%= doNotCallDateVal %>">
</div>

<div class="mb-3">
<label for="DoNotCallNotes" class="form-label">Do Not Call Notes</label>
<textarea class="form-control" id="DoNotCallNotes" name="DoNotCallNotes" rows="3"><%= Server.HTMLEncode(doNotCallNotesVal) %></textarea>
</div>

<div class="mb-0">
<label for="DoNotCallPrivateNotes" class="form-label">Private Do Not Call Notes</label>
<textarea class="form-control" id="DoNotCallPrivateNotes" name="DoNotCallPrivateNotes" rows="3"><%= Server.HTMLEncode(doNotCallPrivateNotesVal) %></textarea>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="Latitude" class="form-label">Latitude</label>
<input type="text" class="form-control" id="Latitude" name="Latitude" value="<%= Server.HTMLEncode(HouseholdController.household.Latitude & "") %>">
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="Longitude" class="form-label">Longitude</label>
<input type="text" class="form-control" id="Longitude" name="Longitude" value="<%= Server.HTMLEncode(HouseholdController.household.Longitude & "") %>">
</div>
</div>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Update Household</button>
<a href="/households/<%= HouseholdController.household.Id %>" class="btn btn-secondary">Cancel</a>
</div>
</div>
<div class="col-md-6">
<label class="form-label">Location (click to update coordinates)</label>
<div id="map" style="height: 350px; width: 100%; border-radius: 8px;"></div>
<small class="text-muted">Click on the map to update latitude and longitude.</small>
</div>
</div>
</form>
</div>
</div>
</div>

<script>
var existingLat = <%= IIf(HouseholdController.household.Latitude & "" <> "", HouseholdController.household.Latitude, "null") %>;
var existingLng = <%= IIf(HouseholdController.household.Longitude & "" <> "", HouseholdController.household.Longitude, "null") %>;
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=<%= Server.HTMLEncode(GetAppSetting("GoogleMapsApiKey")) %>&callback=initMap" async defer></script>
<script>
var map, marker;

function initMap() {
var defaultCenter = { lat: -33.8688, lng: 151.2093 };

// Use existing coordinates if available
if (existingLat !== null && existingLng !== null) {
defaultCenter = { lat: existingLat, lng: existingLng };
}

map = new google.maps.Map(document.getElementById('map'), {
zoom: existingLat !== null ? 17 : 12,
center: defaultCenter,
mapTypeId: 'roadmap'
});

// Place marker if coordinates exist
if (existingLat !== null && existingLng !== null) {
marker = new google.maps.Marker({
position: defaultCenter,
map: map
});
}

// Click to place/move marker and set coordinates
map.addListener('click', function(event) {
placeMarker(event.latLng);
});
}

function placeMarker(location) {
if (marker) {
marker.setPosition(location);
} else {
marker = new google.maps.Marker({
position: location,
map: map
});
}

document.getElementById('Latitude').value = location.lat().toFixed(6);
document.getElementById('Longitude').value = location.lng().toFixed(6);
}
</script>

+ 0
- 187
app/views/Household/index.asp Прегледај датотеку

@@ -1,187 +0,0 @@
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Households</h1>
<a href="/households/new" class="btn btn-primary">New Household</a>
</div>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<!-- Search and Filter Form -->
<div class="card mb-4">
<div class="card-body">
<form method="get" action="/households" class="row g-3">
<div class="col-md-5">
<div class="input-group">
<input type="text" class="form-control" name="q" placeholder="Search by address or street name..." value="<%= Server.HTMLEncode(HouseholdController.searchTerm) %>">
<button class="btn btn-outline-primary" type="submit">Search</button>
</div>
</div>
<div class="col-md-4">
<select name="territory" class="form-select" onchange="this.form.submit()">
<option value="">All Territories</option>
<%
Dim tIter, tItem
Set tIter = HouseholdController.territoriesList.Iterator()
Do While tIter.HasNext()
Set tItem = tIter.GetNext()
%>
<option value="<%= tItem.Id %>" <% If tItem.Id = HouseholdController.filterTerritoryId Then Response.Write "selected" End If %>><%= Server.HTMLEncode(tItem.Name) %></option>
<%
Loop
%>
</select>
</div>
<div class="col-md-2">
<select name="dnc" class="form-select" onchange="this.form.submit()">
<option value="" <% If HouseholdController.filterDoNotCall = -1 Then Response.Write "selected" End If %>>All DNC Status</option>
<option value="1" <% If HouseholdController.filterDoNotCall = 1 Then Response.Write "selected" End If %>>Do Not Call</option>
<option value="0" <% If HouseholdController.filterDoNotCall = 0 Then Response.Write "selected" End If %>>Callable</option>
</select>
</div>
<div class="col-md-1 text-end">
<span class="text-muted">
<%= HouseholdController.recordCount %> household(s)
</span>
<% If HouseholdController.searchTerm <> "" Or HouseholdController.filterTerritoryId > 0 Or HouseholdController.filterDoNotCall > -1 Then %>
<a href="/households" class="btn btn-sm btn-outline-secondary ms-2">Clear</a>
<% End If %>
</div>
</form>
</div>
</div>

<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Address</th>
<th>Type</th>
<th>DNC</th>
<th>Street</th>
<th>Territory</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<%
Dim iter, h
Set iter = HouseholdController.households.Iterator()
If Not iter.HasNext() Then
%>
<tr>
<td colspan="7" class="text-center text-muted py-4">
<% If HouseholdController.searchTerm <> "" Then %>
No households found matching "<%= Server.HTMLEncode(HouseholdController.searchTerm) %>"
<% ElseIf HouseholdController.filterTerritoryId > 0 Then %>
No households found in this territory.
<% Else %>
No households found. <a href="/households/new">Create one</a>
<% End If %>
</td>
</tr>
<%
Else
Do While iter.HasNext()
Set h = iter.GetNext()
%>
<tr>
<td><%= h.Id %></td>
<td><%= Server.HTMLEncode(h.Address) %></td>
<td>
<% If h.IsBusiness = 1 Then %>
<span class="badge bg-info">Business</span>
<% Else %>
<span class="badge bg-secondary">Residential</span>
<% End If %>
</td>
<td>
<% If h.DoNotCall = 1 Then %>
<span class="badge bg-danger">Do Not Call</span>
<% If IsDate(h.DoNotCallDate) Then %>
<div><small class="text-muted"><%= FormatDateTime(h.DoNotCallDate, 2) %></small></div>
<% End If %>
<% Else %>
<span class="text-muted">No</span>
<% End If %>
</td>
<td><%= h.StreetNumber %> <%= Server.HTMLEncode(h.StreetName) %></td>
<td>
<a href="/territories/<%= h.TerritoryId %>">
<%
If HouseholdController.territoryNamesById.Exists(CStr(h.TerritoryId)) Then
Response.Write Server.HTMLEncode(HouseholdController.territoryNamesById(CStr(h.TerritoryId)))
Else
Response.Write "Territory " & h.TerritoryId
End If
%>
</a>
</td>
<td>
<a href="/households/<%= h.Id %>" class="btn btn-sm btn-info">View</a>
<a href="/households/<%= h.Id %>/edit" class="btn btn-sm btn-warning">Edit</a>
<form method="post" action="/households/<%= h.Id %>/delete" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this household?');">
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
<%
Loop
End If
%>
</tbody>
</table>
</div>

<!-- Pagination -->
<% If HouseholdController.pageCount > 1 Then %>
<%
Dim baseUrl, pg, startPage, endPage
baseUrl = "/households?"
If HouseholdController.searchTerm <> "" Then
baseUrl = baseUrl & "q=" & Server.URLEncode(HouseholdController.searchTerm) & "&"
End If
If HouseholdController.filterTerritoryId > 0 Then
baseUrl = baseUrl & "territory=" & HouseholdController.filterTerritoryId & "&"
End If
If HouseholdController.filterDoNotCall > -1 Then
baseUrl = baseUrl & "dnc=" & HouseholdController.filterDoNotCall & "&"
End If

' Calculate pagination range (show 5 pages at a time)
startPage = HouseholdController.currentPage - 2
If startPage < 1 Then startPage = 1
endPage = startPage + 4
If endPage > HouseholdController.pageCount Then
endPage = HouseholdController.pageCount
startPage = endPage - 4
If startPage < 1 Then startPage = 1
End If
%>
<nav aria-label="Household pagination">
<ul class="pagination justify-content-center">
<li class="page-item <% If HouseholdController.currentPage = 1 Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=1">&laquo; First</a>
</li>
<li class="page-item <% If HouseholdController.currentPage = 1 Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= HouseholdController.currentPage - 1 %>">&lsaquo; Prev</a>
</li>
<% For pg = startPage To endPage %>
<li class="page-item <% If pg = HouseholdController.currentPage Then Response.Write "active" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= pg %>"><%= pg %></a>
</li>
<% Next %>
<li class="page-item <% If HouseholdController.currentPage >= HouseholdController.pageCount Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= HouseholdController.currentPage + 1 %>">Next &rsaquo;</a>
</li>
<li class="page-item <% If HouseholdController.currentPage >= HouseholdController.pageCount Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= HouseholdController.pageCount %>">Last &raquo;</a>
</li>
</ul>
</nav>
<p class="text-center text-muted">
Page <%= HouseholdController.currentPage %> of <%= HouseholdController.pageCount %>
</p>
<% End If %>
</div>

+ 0
- 291
app/views/Household/show.asp Прегледај датотеку

@@ -1,291 +0,0 @@
<div class="container mt-4">
<%
Dim dncNotesVal, dncPrivateNotesVal
dncNotesVal = ""
dncPrivateNotesVal = ""
If Not IsNull(HouseholdController.household.DoNotCallNotes) Then dncNotesVal = HouseholdController.household.DoNotCallNotes
If Not IsNull(HouseholdController.household.DoNotCallPrivateNotes) Then dncPrivateNotesVal = HouseholdController.household.DoNotCallPrivateNotes
%>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/households">Households</a></li>
<li class="breadcrumb-item active" aria-current="page"><%= Server.HTMLEncode(HouseholdController.household.Address) %></li>
</ol>
</nav>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h2 class="mb-0"><%= Server.HTMLEncode(HouseholdController.household.Address) %></h2>
<div>
<a href="/households/<%= HouseholdController.household.Id %>/edit" class="btn btn-warning">Edit</a>
<form method="post" action="/households/<%= HouseholdController.household.Id %>/delete" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this household?');">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<dl>
<dt>ID</dt>
<dd><%= HouseholdController.household.Id %></dd>

<dt>Address</dt>
<dd><%= Server.HTMLEncode(HouseholdController.household.Address) %></dd>

<dt>Street Number</dt>
<dd><%= HouseholdController.household.StreetNumber %></dd>

<dt>Street Name</dt>
<dd><%= Server.HTMLEncode(HouseholdController.household.StreetName & "") %></dd>

<dt>Type</dt>
<dd>
<% If HouseholdController.household.IsBusiness = 1 Then %>
<span class="badge bg-info">Business</span>
<% Else %>
<span class="badge bg-secondary">Residential</span>
<% End If %>
<% If HouseholdController.household.DoNotCall = 1 Then %>
<span class="badge bg-danger ms-2">Do Not Call</span>
<% End If %>
</dd>

<dt>Do Not Call Date</dt>
<dd>
<% If IsDate(HouseholdController.household.DoNotCallDate) Then %>
<%= FormatDateTime(HouseholdController.household.DoNotCallDate, 2) %>
<% Else %>
<span class="text-muted">Not set</span>
<% End If %>
</dd>

<dt>Do Not Call Notes</dt>
<dd>
<% If Trim(dncNotesVal) <> "" Then %>
<%= Server.HTMLEncode(dncNotesVal) %>
<% Else %>
<span class="text-muted">None</span>
<% End If %>
</dd>

<dt>Private DNC Notes</dt>
<dd>
<% If Trim(dncPrivateNotesVal) <> "" Then %>
<%= Server.HTMLEncode(dncPrivateNotesVal) %>
<% Else %>
<span class="text-muted">None</span>
<% End If %>
</dd>

<dt>Territory</dt>
<dd><a href="/territories/<%= HouseholdController.household.TerritoryId %>">Territory <%= HouseholdController.household.TerritoryId %></a></dd>
</dl>
</div>
<div class="col-md-6">
<dl>
<dt>Latitude</dt>
<dd><%= Server.HTMLEncode(HouseholdController.household.Latitude & "") %></dd>

<dt>Longitude</dt>
<dd><%= Server.HTMLEncode(HouseholdController.household.Longitude & "") %></dd>
</dl>

<% If HouseholdController.household.Latitude <> "" And HouseholdController.household.Longitude <> "" Then %>
<div id="map" style="height: 250px; width: 100%; border-radius: 8px;"></div>
<% End If %>
</div>
</div>
</div>
</div>

<!-- Householder Names Section -->
<div class="card mt-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Householder Names</h5>
<a href="/householder-names/new?household=<%= HouseholdController.household.Id %>" class="btn btn-sm btn-success">Add Name</a>
</div>
<div class="card-body p-0">
<%
Dim hnIter, hn
Set hnIter = HouseholdController.householderNames.Iterator()
If Not hnIter.HasNext() Then
%>
<div class="p-3 text-center text-muted">
No householder names recorded. <a href="/householder-names/new?household=<%= HouseholdController.household.Id %>">Add one</a>
</div>
<%
Else
%>
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Name</th>
<th>Type</th>
<th style="width: 180px;">Letter Status</th>
<th style="width: 100px;">Actions</th>
</tr>
</thead>
<tbody>
<%
Do While hnIter.HasNext()
Set hn = hnIter.GetNext()
%>
<tr>
<td>
<a href="/householder-names/<%= hn.Id %>"><%= Server.HTMLEncode(hn.Name & "") %></a>
</td>
<td>
<% If HouseholdController.household.IsBusiness = 1 Then %>
<span class="badge bg-info">Business</span>
<% Else %>
<span class="badge bg-secondary">Residential</span>
<% End If %>
</td>
<td>
<form method="post" action="/households/<%= HouseholdController.household.Id %>/mark-returned" style="display:inline;">
<input type="hidden" name="householder_id" value="<%= hn.Id %>">
<% If hn.LetterReturned = 1 Then %>
<button type="submit" class="btn btn-sm btn-warning" title="Click to mark as NOT returned">
Returned
<% If Year(hn.ReturnDate) > 1970 Then %>
<small>(<%= FormatDateTime(hn.ReturnDate, 2) %>)</small>
<% End If %>
</button>
<% Else %>
<button type="submit" class="btn btn-sm btn-outline-success" title="Click to mark as returned">
Not Returned
</button>
<% End If %>
</form>
</td>
<td>
<a href="/householder-names/<%= hn.Id %>/edit" class="btn btn-sm btn-outline-warning" title="Edit">Edit</a>
</td>
</tr>
<%
Loop
%>
</tbody>
</table>
<%
End If
%>
</div>
</div>

<div class="mt-3">
<a href="/households" class="btn btn-secondary">Back to List</a>
<a href="/households?territory=<%= HouseholdController.household.TerritoryId %>" class="btn btn-outline-primary">View Territory Households</a>
</div>
</div>

<% If HouseholdController.household.Latitude <> "" And HouseholdController.household.Longitude <> "" Then %>
<%
Dim mapProvider, googleMapsKey, mapTilerKey, mapTilerStyle, mapTilerSdkJsUrl, mapTilerSdkCssUrl
mapProvider = LCase(Trim(GetAppSetting("MapProvider") & ""))
If mapProvider <> "maptiler" Then mapProvider = "google"

googleMapsKey = Trim(GetAppSetting("GoogleMapsApiKey") & "")
mapTilerKey = Trim(GetAppSetting("MapTilerApiKey") & "")
mapTilerStyle = Trim(GetAppSetting("MapTilerStyle") & "")
If mapTilerStyle = "" Or LCase(mapTilerStyle) = "nothing" Then mapTilerStyle = "streets-v2"

mapTilerSdkJsUrl = Trim(GetAppSetting("MapTilerSdkJsUrl") & "")
mapTilerSdkCssUrl = Trim(GetAppSetting("MapTilerSdkCssUrl") & "")
If mapTilerSdkJsUrl = "" Or LCase(mapTilerSdkJsUrl) = "nothing" Then mapTilerSdkJsUrl = "https://cdn.maptiler.com/maptiler-sdk-js/v3.0.0/maptiler-sdk.umd.min.js"
If mapTilerSdkCssUrl = "" Or LCase(mapTilerSdkCssUrl) = "nothing" Then mapTilerSdkCssUrl = "https://cdn.maptiler.com/maptiler-sdk-js/v3.0.0/maptiler-sdk.css"
%>
<script>
var householdLat = <%= HouseholdController.household.Latitude %>;
var householdLng = <%= HouseholdController.household.Longitude %>;
var mapProvider = "<%= Replace(mapProvider, """", "\""") %>";
var googleMapsKey = "<%= Replace(googleMapsKey, """", "\""") %>";
var mapTilerKey = "<%= Replace(mapTilerKey, """", "\""") %>";
var mapTilerStyle = "<%= Replace(mapTilerStyle, """", "\""") %>";
</script>
<% If mapProvider = "maptiler" Then %>
<link rel="stylesheet" href="<%= Server.HTMLEncode(mapTilerSdkCssUrl) %>" />
<script src="<%= Server.HTMLEncode(mapTilerSdkJsUrl) %>"></script>
<% Else %>
<script src="https://maps.googleapis.com/maps/api/js?key=<%= Server.HTMLEncode(googleMapsKey) %>&callback=initMap" async defer></script>
<% End If %>
<script>
function setMapMessage(message) {
var mapEl = document.getElementById('map');
if (mapEl) {
mapEl.innerHTML = '<div class="alert alert-info">' + message + '</div>';
}
}

function initMap() {
try {
if (mapProvider === 'maptiler') {
if (!mapTilerKey || mapTilerKey === 'nothing') {
setMapMessage('MapTiler API key is missing.');
return;
}
if (typeof maptilersdk === 'undefined') {
setMapMessage('MapTiler SDK failed to load.');
return;
}

maptilersdk.config.apiKey = mapTilerKey;
var styleUrl = 'https://api.maptiler.com/maps/' + encodeURIComponent(mapTilerStyle) + '/style.json?key=' + encodeURIComponent(mapTilerKey);
var location = [parseFloat(householdLng), parseFloat(householdLat)];

var map = new maptilersdk.Map({
container: 'map',
style: styleUrl,
center: location,
zoom: 17
});

new maptilersdk.Marker()
.setLngLat(location)
.addTo(map);

return;
}

var location = { lat: householdLat, lng: householdLng };

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 17,
center: location,
mapTypeId: 'roadmap'
});

var marker = new google.maps.Marker({
position: location,
map: map,
title: '<%= Replace(HouseholdController.household.Address, "'", "\'") %>'
});
} catch (e) {
setMapMessage('Map error: ' + e.message);
}
}

if (mapProvider === 'maptiler') {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initMap);
} else {
initMap();
}
setTimeout(function() {
if (typeof maptilersdk === 'undefined') {
setMapMessage('MapTiler SDK failed to load.');
}
}, 2000);
} else {
setTimeout(function() {
if (typeof google === 'undefined') {
setMapMessage('Google Maps failed to load.');
}
}, 2000);
}
</script>
<% End If %>

+ 0
- 86
app/views/HouseholderName/create.asp Прегледај датотеку

@@ -1,86 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb" class="mb-3">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/householder-names">Householder Names</a></li>
<% If IsObject(HouseholderNameController.household) Then %>
<li class="breadcrumb-item"><a href="/households/<%= HouseholderNameController.household.Id %>"><%= Server.HTMLEncode(HouseholderNameController.household.Address) %></a></li>
<% End If %>
<li class="breadcrumb-item active">New</li>
</ol>
</nav>

<h1 class="mb-4">
New Householder Name
<% If IsObject(HouseholderNameController.household) Then %>
<small class="text-muted">for <%= Server.HTMLEncode(HouseholderNameController.household.Address) %></small>
<% End If %>
</h1>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<form method="post" action="/householder-names">
<div class="mb-3">
<label for="Name" class="form-label">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="Name" name="Name" required autofocus
value="<%= Server.HTMLEncode(HouseholderNameController.householderName.Name & "") %>">
</div>

<div class="mb-3">
<label for="HouseholdId" class="form-label">Household <span class="text-danger">*</span></label>
<% If IsObject(HouseholderNameController.household) Then %>
<input type="hidden" name="HouseholdId" value="<%= HouseholderNameController.household.Id %>">
<input type="text" class="form-control" readonly value="<%= Server.HTMLEncode(HouseholderNameController.household.Address) %>">
<% Else %>
<input type="number" class="form-control" id="HouseholdId" name="HouseholdId" required
value="<%= HouseholderNameController.householderName.HouseholdId %>"
placeholder="Enter Household ID">
<div class="form-text">Enter the ID of the household this name belongs to.</div>
<% End If %>
</div>

<!-- IsBusiness moved to Household -->

<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="LetterReturned" name="LetterReturned" value="1"
<% If HouseholderNameController.householderName.LetterReturned = 1 Then Response.Write "checked" End If %>>
<label class="form-check-label" for="LetterReturned">
Letter was returned
</label>
</div>
</div>

<div class="mb-3">
<label for="ReturnDate" class="form-label">Return Date</label>
<input type="date" class="form-control" id="ReturnDate" name="ReturnDate">
<div class="form-text">Only fill in if letter was returned.</div>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Create Householder Name</button>
<a href="/householder-names<% If HouseholderNameController.householderName.HouseholdId > 0 Then Response.Write "?household=" & HouseholderNameController.householderName.HouseholdId End If %>" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>
</div>

<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">Help</h5>
</div>
<div class="card-body">
<p class="mb-2"><strong>Name:</strong> The name of the person or business at this address.</p>
<p class="mb-2"><strong>Type:</strong> Business/Residential is now stored on the household, not the name.</p>
<p class="mb-0"><strong>Letter Returned:</strong> Check if a letter sent to this name was returned as undeliverable.</p>
</div>
</div>
</div>
</div>
</div>

+ 0
- 95
app/views/HouseholderName/edit.asp Прегледај датотеку

@@ -1,95 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb" class="mb-3">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/householder-names">Householder Names</a></li>
<% If IsObject(HouseholderNameController.household) Then %>
<li class="breadcrumb-item"><a href="/households/<%= HouseholderNameController.household.Id %>"><%= Server.HTMLEncode(HouseholderNameController.household.Address) %></a></li>
<% End If %>
<li class="breadcrumb-item"><a href="/householder-names/<%= HouseholderNameController.householderName.Id %>"><%= Server.HTMLEncode(HouseholderNameController.householderName.Name & "") %></a></li>
<li class="breadcrumb-item active">Edit</li>
</ol>
</nav>

<h1 class="mb-4">Edit Householder Name</h1>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<form method="post" action="/householder-names/<%= HouseholderNameController.householderName.Id %>">
<div class="mb-3">
<label for="Name" class="form-label">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="Name" name="Name" required autofocus
value="<%= Server.HTMLEncode(HouseholderNameController.householderName.Name & "") %>">
</div>

<div class="mb-3">
<label class="form-label">Household</label>
<% If IsObject(HouseholderNameController.household) Then %>
<p class="form-control-plaintext">
<a href="/households/<%= HouseholderNameController.household.Id %>"><%= Server.HTMLEncode(HouseholderNameController.household.Address) %></a>
</p>
<% Else %>
<p class="form-control-plaintext">ID: <%= HouseholderNameController.householderName.HouseholdId %></p>
<% End If %>
</div>

<!-- IsBusiness moved to Household -->

<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="LetterReturned" name="LetterReturned" value="1"
<% If HouseholderNameController.householderName.LetterReturned = 1 Then Response.Write "checked" End If %>>
<label class="form-check-label" for="LetterReturned">
Letter was returned
</label>
</div>
</div>

<div class="mb-3">
<label for="ReturnDate" class="form-label">Return Date</label>
<%
Dim returnDateVal
returnDateVal = ""
If Year(HouseholderNameController.householderName.ReturnDate) > 1970 Then
returnDateVal = Year(HouseholderNameController.householderName.ReturnDate) & "-" & _
Right("0" & Month(HouseholderNameController.householderName.ReturnDate), 2) & "-" & _
Right("0" & Day(HouseholderNameController.householderName.ReturnDate), 2)
End If
%>
<input type="date" class="form-control" id="ReturnDate" name="ReturnDate" value="<%= returnDateVal %>">
<div class="form-text">Only fill in if letter was returned.</div>
</div>

<div class="mb-3">
<label class="form-label">Created</label>
<p class="form-control-plaintext"><%= FormatDateTime(HouseholderNameController.householderName.Created, 2) %></p>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Update Householder Name</button>
<a href="/householder-names/<%= HouseholderNameController.householderName.Id %>" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>
</div>

<div class="col-md-4">
<div class="card border-danger">
<div class="card-header bg-danger text-white">
<h5 class="mb-0">Danger Zone</h5>
</div>
<div class="card-body">
<p>Permanently delete this householder name.</p>
<form method="post" action="/householder-names/<%= HouseholderNameController.householderName.Id %>/delete" onsubmit="return confirm('Are you sure you want to delete this householder name? This action cannot be undone.');">
<button type="submit" class="btn btn-danger w-100">Delete Householder Name</button>
</form>
</div>
</div>
</div>
</div>
</div>

+ 0
- 171
app/views/HouseholderName/index.asp Прегледај датотеку

@@ -1,171 +0,0 @@
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>
Householder Names
<% If IsObject(HouseholderNameController.household) Then %>
<small class="text-muted">for <%= Server.HTMLEncode(HouseholderNameController.household.Address) %></small>
<% End If %>
</h1>
<a href="/householder-names/new<% If HouseholderNameController.filterHouseholdId > 0 Then Response.Write "?household=" & HouseholderNameController.filterHouseholdId End If %>" class="btn btn-primary">New Householder Name</a>
</div>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<!-- Search Form -->
<div class="card mb-4">
<div class="card-body">
<form method="get" action="/householder-names" class="row g-3">
<div class="col-md-6">
<div class="input-group">
<input type="text" class="form-control" name="q" placeholder="Search by name..." value="<%= Server.HTMLEncode(HouseholderNameController.searchTerm) %>">
<button class="btn btn-outline-primary" type="submit">Search</button>
<% If HouseholderNameController.searchTerm <> "" Or HouseholderNameController.filterHouseholdId > 0 Then %>
<a href="/householder-names" class="btn btn-outline-secondary">Clear</a>
<% End If %>
</div>
</div>
<div class="col-md-3 text-end">
<span class="text-muted">
<% If HouseholderNameController.searchTerm <> "" Then %>
Found <%= HouseholderNameController.recordCount %> result(s)
<% Else %>
<%= HouseholderNameController.recordCount %> total
<% End If %>
</span>
</div>
</form>
</div>
</div>

<% If IsObject(HouseholderNameController.household) Then %>
<div class="alert alert-info">
Showing householder names for: <strong><a href="/households/<%= HouseholderNameController.household.Id %>"><%= Server.HTMLEncode(HouseholderNameController.household.Address) %></a></strong>
<a href="/householder-names" class="btn btn-sm btn-outline-info ms-2">Show All</a>
</div>
<% End If %>

<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Name</th>
<th>Type</th>
<th>Letter Returned</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<%
Dim iter, hn
Set iter = HouseholderNameController.householderNames.Iterator()
If Not iter.HasNext() Then
%>
<tr>
<td colspan="6" class="text-center text-muted py-4">
<% If HouseholderNameController.searchTerm <> "" Then %>
No householder names found matching "<%= Server.HTMLEncode(HouseholderNameController.searchTerm) %>"
<% ElseIf HouseholderNameController.filterHouseholdId > 0 Then %>
No householder names for this household. <a href="/householder-names/new?household=<%= HouseholderNameController.filterHouseholdId %>">Add one</a>
<% Else %>
No householder names found. <a href="/householder-names/new">Create one</a>
<% End If %>
</td>
</tr>
<%
Else
Do While iter.HasNext()
Set hn = iter.GetNext()
%>
<tr>
<td><%= hn.Id %></td>
<td><%= Server.HTMLEncode(hn.Name & "") %></td>
<td>
<span class="badge bg-secondary">Household</span>
</td>
<td>
<% If hn.LetterReturned = 1 Then %>
<span class="badge bg-warning text-dark">Returned</span>
<% If Year(hn.ReturnDate) > 1970 Then %>
<small class="text-muted"><%= FormatDateTime(hn.ReturnDate, 2) %></small>
<% End If %>
<% Else %>
<span class="badge bg-success">No</span>
<% End If %>
</td>
<td><%= FormatDateTime(hn.Created, 2) %></td>
<td>
<a href="/householder-names/<%= hn.Id %>" class="btn btn-sm btn-info">View</a>
<a href="/householder-names/<%= hn.Id %>/edit" class="btn btn-sm btn-warning">Edit</a>
<form method="post" action="/householder-names/<%= hn.Id %>/delete" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this householder name?');">
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
<%
Loop
End If
%>
</tbody>
</table>
</div>

<!-- Pagination -->
<% If HouseholderNameController.pageCount > 1 Then %>
<%
Dim baseUrl, pg, startPage, endPage
baseUrl = "/householder-names?"
If HouseholderNameController.searchTerm <> "" Then
baseUrl = baseUrl & "q=" & Server.URLEncode(HouseholderNameController.searchTerm) & "&"
End If
If HouseholderNameController.filterHouseholdId > 0 Then
baseUrl = baseUrl & "household=" & HouseholderNameController.filterHouseholdId & "&"
End If

' Calculate pagination range (show 5 pages at a time)
startPage = HouseholderNameController.currentPage - 2
If startPage < 1 Then startPage = 1
endPage = startPage + 4
If endPage > HouseholderNameController.pageCount Then
endPage = HouseholderNameController.pageCount
startPage = endPage - 4
If startPage < 1 Then startPage = 1
End If
%>
<nav aria-label="Householder names pagination">
<ul class="pagination justify-content-center">
<!-- First page -->
<li class="page-item <% If HouseholderNameController.currentPage = 1 Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=1">&laquo; First</a>
</li>

<!-- Previous page -->
<li class="page-item <% If HouseholderNameController.currentPage = 1 Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= HouseholderNameController.currentPage - 1 %>">&lsaquo; Prev</a>
</li>

<!-- Page numbers -->
<% For pg = startPage To endPage %>
<li class="page-item <% If pg = HouseholderNameController.currentPage Then Response.Write "active" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= pg %>"><%= pg %></a>
</li>
<% Next %>

<!-- Next page -->
<li class="page-item <% If HouseholderNameController.currentPage >= HouseholderNameController.pageCount Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= HouseholderNameController.currentPage + 1 %>">Next &rsaquo;</a>
</li>

<!-- Last page -->
<li class="page-item <% If HouseholderNameController.currentPage >= HouseholderNameController.pageCount Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= HouseholderNameController.pageCount %>">Last &raquo;</a>
</li>
</ul>
</nav>
<p class="text-center text-muted">
Page <%= HouseholderNameController.currentPage %> of <%= HouseholderNameController.pageCount %>
</p>
<% End If %>
</div>

+ 0
- 90
app/views/HouseholderName/show.asp Прегледај датотеку

@@ -1,90 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb" class="mb-3">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/householder-names">Householder Names</a></li>
<% If IsObject(HouseholderNameController.household) Then %>
<li class="breadcrumb-item"><a href="/households/<%= HouseholderNameController.household.Id %>"><%= Server.HTMLEncode(HouseholderNameController.household.Address) %></a></li>
<% End If %>
<li class="breadcrumb-item active"><%= Server.HTMLEncode(HouseholderNameController.householderName.Name & "") %></li>
</ol>
</nav>

<div class="d-flex justify-content-between align-items-center mb-4">
<h1><%= Server.HTMLEncode(HouseholderNameController.householderName.Name & "") %></h1>
<div>
<a href="/householder-names/<%= HouseholderNameController.householderName.Id %>/edit" class="btn btn-warning">Edit</a>
<a href="/householder-names?household=<%= HouseholderNameController.householderName.HouseholdId %>" class="btn btn-secondary">Back to List</a>
</div>
</div>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h5 class="mb-0">Householder Details</h5>
</div>
<div class="card-body">
<dl class="row mb-0">
<dt class="col-sm-4">ID</dt>
<dd class="col-sm-8"><%= HouseholderNameController.householderName.Id %></dd>

<dt class="col-sm-4">Name</dt>
<dd class="col-sm-8"><%= Server.HTMLEncode(HouseholderNameController.householderName.Name & "") %></dd>

<dt class="col-sm-4">Type</dt>
<dd class="col-sm-8">
<span class="badge bg-secondary">Household</span>
</dd>

<dt class="col-sm-4">Letter Returned</dt>
<dd class="col-sm-8">
<% If HouseholderNameController.householderName.LetterReturned = 1 Then %>
<span class="badge bg-warning text-dark">Yes - Returned</span>
<% If Year(HouseholderNameController.householderName.ReturnDate) > 1970 Then %>
<br><small class="text-muted">Return Date: <%= FormatDateTime(HouseholderNameController.householderName.ReturnDate, 2) %></small>
<% End If %>
<% Else %>
<span class="badge bg-success">No</span>
<% End If %>
</dd>

<dt class="col-sm-4">Created</dt>
<dd class="col-sm-8"><%= FormatDateTime(HouseholderNameController.householderName.Created, 2) %></dd>

<dt class="col-sm-4">Household</dt>
<dd class="col-sm-8">
<% If IsObject(HouseholderNameController.household) Then %>
<a href="/households/<%= HouseholderNameController.household.Id %>"><%= Server.HTMLEncode(HouseholderNameController.household.Address) %></a>
<% Else %>
ID: <%= HouseholderNameController.householderName.HouseholdId %>
<% End If %>
</dd>
</dl>
</div>
</div>
</div>

<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">Actions</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="/householder-names/<%= HouseholderNameController.householderName.Id %>/edit" class="btn btn-warning">Edit</a>
<% If IsObject(HouseholderNameController.household) Then %>
<a href="/households/<%= HouseholderNameController.household.Id %>" class="btn btn-outline-primary">View Household</a>
<a href="/householder-names/new?household=<%= HouseholderNameController.householderName.HouseholdId %>" class="btn btn-outline-success">Add Another Name</a>
<% End If %>
<form method="post" action="/householder-names/<%= HouseholderNameController.householderName.Id %>/delete" onsubmit="return confirm('Are you sure you want to delete this householder name?');">
<button type="submit" class="btn btn-danger w-100">Delete</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>

+ 0
- 134
app/views/Territory/create.asp Прегледај датотеку

@@ -1,134 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/territories">Territories</a></li>
<li class="breadcrumb-item active" aria-current="page">New Territory</li>
</ol>
</nav>

<h1>New Territory</h1>

<% Flash().ShowErrorsIfPresent %>

<div class="card">
<div class="card-body">
<form method="post" action="/territories">
<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label for="Name" class="form-label">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="Name" name="Name" required maxlength="255">
</div>

<div class="mb-3">
<label for="Description" class="form-label">Description</label>
<textarea class="form-control" id="Description" name="Description" rows="2"></textarea>
</div>

<div class="mb-3">
<label for="Coordinates" class="form-label">Coordinates (JSON)</label>
<textarea class="form-control" id="Coordinates" name="Coordinates" rows="4" style="font-family: monospace; font-size: 12px;"></textarea>
<small class="text-muted">Click on the map to draw the territory boundary.</small>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Create Territory</button>
<a href="/territories" class="btn btn-secondary">Cancel</a>
</div>
</div>
<div class="col-md-8">
<label class="form-label">Territory Boundary</label>
<div id="map" style="height: 400px; width: 100%; border-radius: 8px;"></div>
<div class="mt-2">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="clearPolygon()">Clear Polygon</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="undoLastPoint()">Undo Last Point</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

<script src="https://maps.googleapis.com/maps/api/js?key=<%= Server.HTMLEncode(GetAppSetting("GoogleMapsApiKey")) %>&callback=initMap" async defer></script>
<script>
var map, polygon;

function initMap() {
var defaultCenter = { lat: -33.8688, lng: 151.2093 }; // Sydney default

map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: defaultCenter,
mapTypeId: 'roadmap'
});

// Create editable polygon (empty initially)
polygon = new google.maps.Polygon({
paths: [],
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
editable: true,
draggable: true
});

polygon.setMap(map);

// Click to add points
map.addListener('click', function(event) {
var path = polygon.getPath();
path.push(event.latLng);
updateCoordinatesField();
});

// Update field when polygon is edited
google.maps.event.addListener(polygon.getPath(), 'set_at', updateCoordinatesField);
google.maps.event.addListener(polygon.getPath(), 'insert_at', updateCoordinatesField);
google.maps.event.addListener(polygon.getPath(), 'remove_at', updateCoordinatesField);

// Also update when dragged
google.maps.event.addListener(polygon, 'dragend', updateCoordinatesField);
}

function updateCoordinatesField() {
var path = polygon.getPath();
var coords = [];
for (var i = 0; i < path.getLength(); i++) {
var point = path.getAt(i);
coords.push({ lat: point.lat(), lng: point.lng() });
}
document.getElementById('Coordinates').value = JSON.stringify(coords, null, 2);
}

function clearPolygon() {
polygon.getPath().clear();
updateCoordinatesField();
}

function undoLastPoint() {
var path = polygon.getPath();
if (path.getLength() > 0) {
path.pop();
updateCoordinatesField();
}
}

// Allow manual JSON editing
document.getElementById('Coordinates').addEventListener('change', function() {
try {
var coords = JSON.parse(this.value);
if (Array.isArray(coords)) {
var path = polygon.getPath();
path.clear();
coords.forEach(function(coord) {
path.push(new google.maps.LatLng(coord.lat || coord[0], coord.lng || coord[1]));
});
}
} catch (e) {
// Invalid JSON, ignore
}
});
</script>

+ 0
- 164
app/views/Territory/edit.asp Прегледај датотеку

@@ -1,164 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/territories">Territories</a></li>
<li class="breadcrumb-item"><a href="/territories/<%= TerritoryController.territory.Id %>"><%= Server.HTMLEncode(TerritoryController.territory.Name) %></a></li>
<li class="breadcrumb-item active" aria-current="page">Edit</li>
</ol>
</nav>

<h1>Edit Territory</h1>

<% Flash().ShowErrorsIfPresent %>

<div class="card">
<div class="card-body">
<form method="post" action="/territories/<%= TerritoryController.territory.Id %>">
<div class="row">
<div class="col-md-4">
<div class="mb-3">
<label for="Name" class="form-label">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="Name" name="Name" required maxlength="255" value="<%= Server.HTMLEncode(TerritoryController.territory.Name) %>">
</div>

<div class="mb-3">
<label for="Description" class="form-label">Description</label>
<textarea class="form-control" id="Description" name="Description" rows="2"><%= Server.HTMLEncode(TerritoryController.territory.Description & "") %></textarea>
</div>

<div class="mb-3">
<label for="Coordinates" class="form-label">Coordinates (JSON)</label>
<textarea class="form-control" id="Coordinates" name="Coordinates" rows="4" style="font-family: monospace; font-size: 12px;"><%= Server.HTMLEncode(TerritoryController.territory.Coordinates & "") %></textarea>
<small class="text-muted">Click on the map to add points, or edit JSON directly.</small>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Update Territory</button>
<a href="/territories/<%= TerritoryController.territory.Id %>" class="btn btn-secondary">Cancel</a>
</div>
</div>
<div class="col-md-8">
<label class="form-label">Territory Boundary</label>
<div id="map" style="height: 400px; width: 100%; border-radius: 8px;"></div>
<div class="mt-2">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="clearPolygon()">Clear Polygon</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="undoLastPoint()">Undo Last Point</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

<script>
var existingCoordinates = <%= TerritoryController.territory.Coordinates & "" %>;
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=<%= Server.HTMLEncode(GetAppSetting("GoogleMapsApiKey")) %>&callback=initMap" async defer></script>
<script>
var map, polygon, polygonCoords = [];

function initMap() {
var defaultCenter = { lat: -33.8688, lng: 151.2093 }; // Sydney default

// Parse existing coordinates
if (existingCoordinates && Array.isArray(existingCoordinates) && existingCoordinates.length > 0) {
polygonCoords = existingCoordinates.map(function(coord) {
return { lat: coord.lat || coord[0], lng: coord.lng || coord[1] };
});
}

// Calculate center from existing coords or use default
var center = defaultCenter;
if (polygonCoords.length > 0) {
var bounds = new google.maps.LatLngBounds();
polygonCoords.forEach(function(coord) {
bounds.extend(coord);
});
center = bounds.getCenter();
}

map = new google.maps.Map(document.getElementById('map'), {
zoom: 14,
center: center,
mapTypeId: 'roadmap'
});

// Create editable polygon
polygon = new google.maps.Polygon({
paths: polygonCoords,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
editable: true,
draggable: true
});

polygon.setMap(map);

// Fit bounds if we have coordinates
if (polygonCoords.length > 0) {
var bounds = new google.maps.LatLngBounds();
polygonCoords.forEach(function(coord) {
bounds.extend(coord);
});
map.fitBounds(bounds);
}

// Click to add points
map.addListener('click', function(event) {
var path = polygon.getPath();
path.push(event.latLng);
updateCoordinatesField();
});

// Update field when polygon is edited
google.maps.event.addListener(polygon.getPath(), 'set_at', updateCoordinatesField);
google.maps.event.addListener(polygon.getPath(), 'insert_at', updateCoordinatesField);
google.maps.event.addListener(polygon.getPath(), 'remove_at', updateCoordinatesField);

// Also update when dragged
google.maps.event.addListener(polygon, 'dragend', updateCoordinatesField);
}

function updateCoordinatesField() {
var path = polygon.getPath();
var coords = [];
for (var i = 0; i < path.getLength(); i++) {
var point = path.getAt(i);
coords.push({ lat: point.lat(), lng: point.lng() });
}
document.getElementById('Coordinates').value = JSON.stringify(coords, null, 2);
}

function clearPolygon() {
polygon.getPath().clear();
updateCoordinatesField();
}

function undoLastPoint() {
var path = polygon.getPath();
if (path.getLength() > 0) {
path.pop();
updateCoordinatesField();
}
}

// Allow manual JSON editing
document.getElementById('Coordinates').addEventListener('change', function() {
try {
var coords = JSON.parse(this.value);
if (Array.isArray(coords)) {
var path = polygon.getPath();
path.clear();
coords.forEach(function(coord) {
path.push(new google.maps.LatLng(coord.lat || coord[0], coord.lng || coord[1]));
});
}
} catch (e) {
// Invalid JSON, ignore
}
});
</script>

+ 0
- 150
app/views/Territory/index.asp Прегледај датотеку

@@ -1,150 +0,0 @@
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Territories</h1>
<a href="/territories/new" class="btn btn-primary">New Territory</a>
</div>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<!-- Search Form -->
<div class="card mb-4">
<div class="card-body">
<form method="get" action="/territories" class="row g-3">
<div class="col-md-8">
<div class="input-group">
<input type="text" class="form-control" name="q" placeholder="Search by name or description..." value="<%= Server.HTMLEncode(TerritoryController.searchTerm) %>">
<button class="btn btn-outline-primary" type="submit">Search</button>
<% If TerritoryController.searchTerm <> "" Then %>
<a href="/territories" class="btn btn-outline-secondary">Clear</a>
<% End If %>
</div>
</div>
<div class="col-md-4 text-end">
<span class="text-muted">
<% If TerritoryController.searchTerm <> "" Then %>
Found <%= TerritoryController.recordCount %> result(s)
<% Else %>
<%= TerritoryController.recordCount %> total territories
<% End If %>
</span>
</div>
</form>
</div>
</div>

<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>Households</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<%
Dim iter, t
Set iter = TerritoryController.territories.Iterator()
If Not iter.HasNext() Then
%>
<tr>
<td colspan="5" class="text-center text-muted py-4">
<% If TerritoryController.searchTerm <> "" Then %>
No territories found matching "<%= Server.HTMLEncode(TerritoryController.searchTerm) %>"
<% Else %>
No territories found. <a href="/territories/new">Create one</a>
<% End If %>
</td>
</tr>
<%
Else
Do While iter.HasNext()
Set t = iter.GetNext()
%>
<tr>
<td><%= t.Id %></td>
<td><%= Server.HTMLEncode(t.Name) %></td>
<td><%= Server.HTMLEncode(Left(t.Description & "", 50)) %><% If Len(t.Description & "") > 50 Then Response.Write "..." End If %></td>
<%
Dim householdCount
householdCount = 0
If IsObject(TerritoryController.territoryHouseholdCounts) Then
If TerritoryController.territoryHouseholdCounts.Exists(CLng(t.Id)) Then
householdCount = TerritoryController.territoryHouseholdCounts(CLng(t.Id))
End If
End If
%>
<td><%= householdCount %></td>
<td>
<a href="/territories/<%= t.Id %>" class="btn btn-sm btn-info">View</a>
<a href="/territories/<%= t.Id %>/edit" class="btn btn-sm btn-warning">Edit</a>
<form method="post" action="/territories/<%= t.Id %>/delete" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this territory?');">
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
<%
Loop
End If
%>
</tbody>
</table>
</div>

<!-- Pagination -->
<% If TerritoryController.pageCount > 1 Then %>
<%
Dim baseUrl, pg, startPage, endPage
baseUrl = "/territories?"
If TerritoryController.searchTerm <> "" Then
baseUrl = baseUrl & "q=" & Server.URLEncode(TerritoryController.searchTerm) & "&"
End If

' Calculate pagination range (show 5 pages at a time)
startPage = TerritoryController.currentPage - 2
If startPage < 1 Then startPage = 1
endPage = startPage + 4
If endPage > TerritoryController.pageCount Then
endPage = TerritoryController.pageCount
startPage = endPage - 4
If startPage < 1 Then startPage = 1
End If
%>
<nav aria-label="Territory pagination">
<ul class="pagination justify-content-center">
<!-- First page -->
<li class="page-item <% If TerritoryController.currentPage = 1 Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=1">&laquo; First</a>
</li>

<!-- Previous page -->
<li class="page-item <% If TerritoryController.currentPage = 1 Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= TerritoryController.currentPage - 1 %>">&lsaquo; Prev</a>
</li>

<!-- Page numbers -->
<% For pg = startPage To endPage %>
<li class="page-item <% If pg = TerritoryController.currentPage Then Response.Write "active" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= pg %>"><%= pg %></a>
</li>
<% Next %>

<!-- Next page -->
<li class="page-item <% If TerritoryController.currentPage >= TerritoryController.pageCount Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= TerritoryController.currentPage + 1 %>">Next &rsaquo;</a>
</li>

<!-- Last page -->
<li class="page-item <% If TerritoryController.currentPage >= TerritoryController.pageCount Then Response.Write "disabled" End If %>">
<a class="page-link" href="<%= baseUrl %>page=<%= TerritoryController.pageCount %>">Last &raquo;</a>
</li>
</ul>
</nav>
<p class="text-center text-muted">
Page <%= TerritoryController.currentPage %> of <%= TerritoryController.pageCount %>
</p>
<% End If %>
</div>

+ 0
- 813
app/views/Territory/show.asp Прегледај датотеку

@@ -1,813 +0,0 @@
<div class="container mt-4">
<nav aria-label="breadcrumb" class="d-print-none">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/territories">Territories</a></li>
<li class="breadcrumb-item active" aria-current="page"><%= Server.HTMLEncode(TerritoryController.territory.Name) %></li>
</ol>
</nav>

<% Flash().ShowSuccessIfPresent %>
<% Flash().ShowErrorsIfPresent %>

<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h2 class="mb-0"><%= Server.HTMLEncode(TerritoryController.territory.Name) %></h2>
<div class="d-print-none">
<button type="button" class="btn btn-secondary" onclick="printTerritory()"><i class="bi bi-printer"></i> Print</button>
<a href="/territories/<%= TerritoryController.territory.Id %>/edit" class="btn btn-warning">Edit</a>
<form method="post" action="/territories/<%= TerritoryController.territory.Id %>/delete" style="display:inline;" onsubmit="return confirm('Are you sure you want to delete this territory?');">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4 territory-details">
<dl>
<dt>ID</dt>
<dd><%= TerritoryController.territory.Id %></dd>

<dt>Name</dt>
<dd><%= Server.HTMLEncode(TerritoryController.territory.Name) %></dd>

<dt>Description</dt>
<dd><%= Server.HTMLEncode(TerritoryController.territory.Description & "") %></dd>
</dl>
</div>
<div class="col-md-8 map-container">
<div id="map" style="height: 400px; width: 100%; border-radius: 8px;"></div>
</div>
</div>
</div>
</div>

<div class="mt-3 d-print-none">
<a href="/territories" class="btn btn-secondary">Back to List</a>
</div>
</div>

<style>
@media print {
/* Hide navigation and non-essential elements */
.d-print-none,
nav.navbar,
footer,
.breadcrumb {
display: none !important;
}

/* Set page size and margins */
@page {
size: letter portrait;
margin: 0.5in;
}

/* Reset body for print */
body {
margin: 0 !important;
padding: 0 !important;
}

.container {
max-width: 100% !important;
padding: 0 !important;
margin: 0 !important;
}

.card {
border: none !important;
box-shadow: none !important;
}

.card-header {
background-color: transparent !important;
border-bottom: 2px solid #000 !important;
padding: 0 0 10px 0 !important;
margin-bottom: 10px !important;
}

.card-body {
padding: 0 !important;
}

/* Territory title styling for print */
h2 {
font-size: 24pt !important;
margin: 0 !important;
text-align: center !important;
}

/* Hide details section in print, show only title and map */
.territory-details {
display: none !important;
}

/* Map takes 3/4 of 8.5x11 page (11in - 1in margins = 10in, 3/4 = 7.5in) */
#map {
height: 7.5in !important;
width: 100% !important;
page-break-inside: avoid;
border: 1px solid #ccc !important;
}

.map-container {
flex: 0 0 100% !important;
max-width: 100% !important;
}

.row {
display: block !important;
}

/* Ensure text is black for printing */
body, .card-body, dt, dd, h2 {
color: #000 !important;
}
}
</style>

<%
Dim mapProvider, googleMapsKey, mapTilerKey, mapTilerStyle, mapTilerSdkJsUrl, mapTilerSdkCssUrl
mapProvider = LCase(Trim(GetAppSetting("MapProvider") & ""))
If mapProvider <> "maptiler" Then mapProvider = "google"

googleMapsKey = Trim(GetAppSetting("GoogleMapsApiKey") & "")
mapTilerKey = Trim(GetAppSetting("MapTilerApiKey") & "")
mapTilerStyle = Trim(GetAppSetting("MapTilerStyle") & "")
If mapTilerStyle = "" Or LCase(mapTilerStyle) = "nothing" Then mapTilerStyle = "streets-v2"

mapTilerSdkJsUrl = Trim(GetAppSetting("MapTilerSdkJsUrl") & "")
mapTilerSdkCssUrl = Trim(GetAppSetting("MapTilerSdkCssUrl") & "")
If mapTilerSdkJsUrl = "" Or LCase(mapTilerSdkJsUrl) = "nothing" Then mapTilerSdkJsUrl = "https://cdn.maptiler.com/maptiler-sdk-js/v3.0.0/maptiler-sdk.umd.min.js"
If mapTilerSdkCssUrl = "" Or LCase(mapTilerSdkCssUrl) = "nothing" Then mapTilerSdkCssUrl = "https://cdn.maptiler.com/maptiler-sdk-js/v3.0.0/maptiler-sdk.css"
%>

<%
Dim coordsJson
coordsJson = Trim(TerritoryController.territory.Coordinates & "")
If coordsJson = "" Then coordsJson = "[]"

' Build street names array for JavaScript
Dim streetIter, streetName, streetsJson, isFirst
streetsJson = "["
isFirst = True
If Not TerritoryController.territoryStreets Is Nothing Then
Set streetIter = TerritoryController.territoryStreets.Iterator()
Do While streetIter.HasNext()
streetName = streetIter.GetNext()
If Not isFirst Then streetsJson = streetsJson & ","
streetsJson = streetsJson & """" & Replace(streetName, """", "\""") & """"
isFirst = False
Loop
End If
streetsJson = streetsJson & "]"

' Get border streets from the Description field
Dim borderStreets
borderStreets = Trim(TerritoryController.territory.Description & "")
%>
<script>
var territoryCoordinates = <%= coordsJson %>;
var territoryName = "<%= Replace(TerritoryController.territory.Name, """", "\""") %>";
var territoryBorderStreets = "<%= Replace(Replace(borderStreets, """", "\"""), vbCrLf, ", ") %>";
var territoryStreets = <%= streetsJson %>;
var mapProvider = "<%= Replace(mapProvider, """", "\""") %>";
var googleMapsKey = "<%= Replace(googleMapsKey, """", "\""") %>";
var mapTilerKey = "<%= Replace(mapTilerKey, """", "\""") %>";
var mapTilerStyle = "<%= Replace(mapTilerStyle, """", "\""") %>";
</script>
<% If mapProvider = "maptiler" Then %>
<link rel="stylesheet" href="<%= Server.HTMLEncode(mapTilerSdkCssUrl) %>" />
<script src="<%= Server.HTMLEncode(mapTilerSdkJsUrl) %>"></script>
<% Else %>
<script src="https://maps.googleapis.com/maps/api/js?key=<%= Server.HTMLEncode(googleMapsKey) %>&callback=initMap" async defer></script>
<% End If %>
<script>
var map, polygon;
var mapIsReady = false;

function setMapMessage(message) {
var mapEl = document.getElementById('map');
if (mapEl) {
mapEl.innerHTML = '<div class="alert alert-info">' + message + '</div>';
}
}

function getLatLng(coord) {
var lat, lng;
if (coord && typeof coord === 'object' && (coord.lat !== undefined || coord.lng !== undefined)) {
lat = parseFloat(coord.lat);
lng = parseFloat(coord.lng);
} else if (Array.isArray(coord) && coord.length >= 2) {
var a = parseFloat(coord[0]);
var b = parseFloat(coord[1]);
if (!isNaN(a) && !isNaN(b)) {
if (Math.abs(a) > 90 && Math.abs(b) <= 90) {
lng = a;
lat = b;
} else {
lat = a;
lng = b;
}
}
}
return { lat: lat, lng: lng };
}

function initMap() {
try {
var coords = territoryCoordinates;

if (!coords || !Array.isArray(coords) || coords.length === 0) {
setMapMessage('No coordinates available for this territory.');
return;
}

if (mapProvider === 'maptiler') {
if (!mapTilerKey || mapTilerKey === 'nothing') {
setMapMessage('MapTiler API key is missing.');
return;
}
if (typeof maptilersdk === 'undefined') {
setMapMessage('MapTiler SDK failed to load.');
return;
}

maptilersdk.config.apiKey = mapTilerKey;

var polygonCoords = coords.map(function(coord) {
var ll = getLatLng(coord);
return [ll.lng, ll.lat];
}).filter(function(p) {
return isFinite(p[0]) && isFinite(p[1]);
});

if (polygonCoords.length === 0) {
setMapMessage('No valid coordinates available for this territory.');
return;
}

if (polygonCoords.length > 0) {
var firstCoord = polygonCoords[0];
var lastCoord = polygonCoords[polygonCoords.length - 1];
if (firstCoord[0] !== lastCoord[0] || firstCoord[1] !== lastCoord[1]) {
polygonCoords.push([firstCoord[0], firstCoord[1]]);
}
}

var bounds = new maptilersdk.LngLatBounds();
polygonCoords.forEach(function(coord) {
bounds.extend(coord);
});

var styleUrl = 'https://api.maptiler.com/maps/' + encodeURIComponent(mapTilerStyle) + '/style.json?key=' + encodeURIComponent(mapTilerKey);

map = new maptilersdk.Map({
container: 'map',
style: styleUrl,
center: bounds.getCenter(),
zoom: 14,
preserveDrawingBuffer: true
});

map.on('styleimagemissing', function(e) {
if (map.hasImage(e.id)) return;
var emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
map.addImage(e.id, emptyCanvas);
});

map.on('load', function() {
map.addSource('territory', {
type: 'geojson',
data: {
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [polygonCoords]
}
}
});

map.addLayer({
id: 'territory-fill',
type: 'fill',
source: 'territory',
paint: {
'fill-color': '#ff0000',
'fill-opacity': 0.35
}
});

map.addLayer({
id: 'territory-line',
type: 'line',
source: 'territory',
paint: {
'line-color': '#ff0000',
'line-width': 2
}
});

map.fitBounds(bounds, { padding: 20 });
});

map.on('idle', function() {
mapIsReady = true;
});

return;
}

// Convert coordinates to Google Maps format
var polygonCoords = coords.map(function(coord) {
var ll = getLatLng(coord);
return { lat: ll.lat, lng: ll.lng };
}).filter(function(p) {
return isFinite(p.lat) && isFinite(p.lng);
});

if (polygonCoords.length === 0) {
setMapMessage('No valid coordinates available for this territory.');
return;
}

// Calculate bounds to center the map
var bounds = new google.maps.LatLngBounds();
polygonCoords.forEach(function(coord) {
bounds.extend(coord);
});

map = new google.maps.Map(document.getElementById('map'), {
zoom: 14,
center: bounds.getCenter(),
mapTypeId: 'roadmap'
});

// Draw the polygon
polygon = new google.maps.Polygon({
paths: polygonCoords,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});

polygon.setMap(map);
map.fitBounds(bounds);
} catch (e) {
setMapMessage('Map error: ' + e.message);
}
}

var printWindow = null;

function printTerritory() {
var coords = territoryCoordinates;
if (!coords || !Array.isArray(coords) || coords.length === 0) {
alert('No coordinates available to print.');
return;
}

if (mapProvider === 'maptiler') {

function openPrintWindowShell() {
// Build street lists HTML
var borderStreetsHtml = '';
if (territoryBorderStreets && territoryBorderStreets.trim() !== '') {
borderStreetsHtml = '<div class="streets-section"><strong>Border Streets:</strong> ' + territoryBorderStreets + '</div>';
}

var insideStreetsHtml = '';
if (territoryStreets && territoryStreets.length > 0) {
insideStreetsHtml = '<div class="streets-section"><strong>Streets Inside:</strong> ' + territoryStreets.join(', ') + '</div>';
}

var printContent = '<!DOCTYPE html>' +
'<html><head><title>Territory: ' + territoryName + '</title>' +
'<style>' +
'@page { size: letter portrait; margin: 0.25in; }' +
'body { margin: 0; padding: 0; font-family: Arial, sans-serif; }' +
'.header { text-align: center; border-bottom: 2px solid #000; padding-bottom: 5px; margin-bottom: 10px; }' +
'.header h1 { margin: 0; font-size: 20pt; }' +
'.streets-section { font-size: 10pt; margin: 5px 0; text-align: left; }' +
'.map-container { text-align: center; min-height: 200px; }' +
'.map-container img { max-width: 100%; height: auto; max-height: 7in; }' +
'.map-link { display: inline-block; margin-top: 10px; font-size: 12px; word-break: break-all; }' +
'.print-btn { margin-top: 15px; padding: 10px 30px; font-size: 16px; cursor: pointer; }' +
'.loading { color: #666; font-size: 14px; }' +
'@media print { .no-print { display: none !important; } }' +
'</style></head><body>' +
'<div class="header"><h1>' + territoryName + '</h1></div>' +
borderStreetsHtml +
insideStreetsHtml +
'<div class="map-container">' +
'<div class="loading">Preparing map for print...</div>' +
'<img id="print-map-img" src="" alt="Territory Map" style="display:none;">' +
'<div class="map-link no-print"><a id="print-map-link" href="#" target="_blank" rel="noopener">Open image in new tab</a></div>' +
'</div>' +
'<div class="no-print" style="text-align: center; margin-top: 15px;">' +
'<button class="print-btn" onclick="window.print();">Print</button> ' +
'<button class="print-btn" onclick="window.close();">Close</button>' +
'</div>' +
'</body></html>';

printWindow = window.open('', '_blank', 'width=900,height=1000');
printWindow.document.write(printContent);
printWindow.document.close();
}

function setPrintWindowImage(src) {
if (!printWindow || printWindow.closed) {
alert('Print window was blocked. Please allow popups and try again.');
return;
}

var attempts = 0;
function trySet() {
attempts = attempts + 1;
var doc = printWindow.document;
if (!doc) {
if (attempts < 20) return setTimeout(trySet, 100);
alert('Print window did not finish loading.');
return;
}
var img = doc.getElementById('print-map-img');
var loading = doc.querySelector('.loading');
var link = doc.getElementById('print-map-link');
if (!img) {
if (attempts < 20) return setTimeout(trySet, 100);
alert('Print image element not found.');
return;
}
if (loading) loading.style.display = 'none';
img.style.display = 'block';
img.src = src;
if (link) link.href = src;
}
trySet();
}

openPrintWindowShell();

function loadImage(url) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function() { resolve(img); };
img.onerror = function() { reject(url); };
img.src = url;
});
}

function renderMapTilerImage() {
return new Promise(function(resolve, reject) {
if (!mapTilerKey || mapTilerKey === 'nothing') {
reject('MapTiler API key is missing.');
return;
}

var tileCoordSize = 512;
if (map && typeof map.getStyle === 'function') {
var styleObj = map.getStyle();
if (styleObj && styleObj.sources) {
for (var srcKey in styleObj.sources) {
if (styleObj.sources.hasOwnProperty(srcKey)) {
var src = styleObj.sources[srcKey];
if (src && src.tileSize) {
tileCoordSize = src.tileSize;
break;
}
}
}
}
}

function buildTileUrl(z, x, y) {
return 'https://api.maptiler.com/maps/' +
encodeURIComponent(mapTilerStyle) + '/' +
z + '/' + x + '/' + y + '.png?key=' +
encodeURIComponent(mapTilerKey);
}

function buildImage(tileImageSize) {
function lngToWorldX(lng, zoom) {
var scale = tileCoordSize * Math.pow(2, zoom);
return (lng + 180) / 360 * scale;
}

function latToWorldY(lat, zoom) {
var rad = lat * Math.PI / 180;
var scale = tileCoordSize * Math.pow(2, zoom);
return (1 - Math.log(Math.tan(rad) + 1 / Math.cos(rad)) / Math.PI) / 2 * scale;
}

var minLat = Infinity, maxLat = -Infinity;
var minLng = Infinity, maxLng = -Infinity;
coords.forEach(function(coord) {
var ll = getLatLng(coord);
var lat = ll.lat;
var lng = ll.lng;
if (!isFinite(lat) || !isFinite(lng)) return;
if (lat < minLat) minLat = lat;
if (lat > maxLat) maxLat = lat;
if (lng < minLng) minLng = lng;
if (lng > maxLng) maxLng = lng;
});

if (!isFinite(minLat) || !isFinite(minLng) || !isFinite(maxLat) || !isFinite(maxLng)) {
reject('No valid coordinates available to print.');
return;
}

var centerLat = (minLat + maxLat) / 2;
var centerLng = (minLng + maxLng) / 2;

var isWide = (maxLng - minLng) > (maxLat - minLat) * 1.2;
var baseWidth = isWide ? 800 : 640;
var baseHeight = isWide ? 640 : 800;
var outputScale = tileImageSize > 0 ? (tileImageSize / tileCoordSize) : 1;
var width = baseWidth * outputScale;
var height = baseHeight * outputScale;

var x1 = lngToWorldX(minLng, 0);
var x2 = lngToWorldX(maxLng, 0);
var y1 = latToWorldY(maxLat, 0);
var y2 = latToWorldY(minLat, 0);
var spanX0 = Math.abs(x2 - x1);
var spanY0 = Math.abs(y2 - y1);
var paddingFactor = 1.02;
var zoomX = spanX0 > 0 ? Math.log2(baseWidth / (spanX0 * paddingFactor)) : 20;
var zoomY = spanY0 > 0 ? Math.log2(baseHeight / (spanY0 * paddingFactor)) : 20;
var zoom = Math.min(zoomX, zoomY);
if (!isFinite(zoom)) zoom = 1;
if (zoom < 1) zoom = 1;
if (zoom > 20) zoom = 20;

var zInt = Math.floor(zoom);
var zScale = Math.pow(2, zoom - zInt);
var worldCenterXint = lngToWorldX(centerLng, zInt);
var worldCenterYint = latToWorldY(centerLat, zInt);
var worldWidth = width / (outputScale * zScale);
var worldHeight = height / (outputScale * zScale);
var topLeftXint = worldCenterXint - worldWidth / 2;
var topLeftYint = worldCenterYint - worldHeight / 2;
var topLeftX = topLeftXint * outputScale * zScale;
var topLeftY = topLeftYint * outputScale * zScale;

var n = Math.pow(2, zInt);
var tileXStart = Math.floor(topLeftXint / tileCoordSize);
var tileYStart = Math.floor(topLeftYint / tileCoordSize);
var tileXEnd = Math.floor((topLeftXint + worldWidth) / tileCoordSize);
var tileYEnd = Math.floor((topLeftYint + worldHeight) / tileCoordSize);

var promises = [];
var tiles = [];
var tileX, tileY;
for (tileY = tileYStart; tileY <= tileYEnd; tileY++) {
if (tileY < 0 || tileY >= n) continue;
for (tileX = tileXStart; tileX <= tileXEnd; tileX++) {
var wrappedX = ((tileX % n) + n) % n;
var url = buildTileUrl(zInt, wrappedX, tileY);
(function(x, y, u) {
var p = loadImage(u).then(function(img) {
tiles.push({ x: x, y: y, img: img });
});
promises.push(p);
})(tileX, tileY, url);
}
}

Promise.all(promises).then(function() {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');

var tileDrawSize = tileCoordSize * zScale * outputScale;
tiles.forEach(function(t) {
var dx = (t.x * tileCoordSize * zScale * outputScale) - topLeftX;
var dy = (t.y * tileCoordSize * zScale * outputScale) - topLeftY;
ctx.drawImage(t.img, dx, dy, tileDrawSize, tileDrawSize);
});

if (coords.length > 1) {
ctx.save();
ctx.strokeStyle = 'rgba(255,0,0,0.8)';
ctx.fillStyle = 'rgba(255,0,0,0.25)';
ctx.lineWidth = 3;
ctx.beginPath();
coords.forEach(function(coord, idx) {
var ll = getLatLng(coord);
var lat = ll.lat;
var lng = ll.lng;
if (!isFinite(lat) || !isFinite(lng)) return;
var px = (lngToWorldX(lng, zInt) * zScale * outputScale) - topLeftX;
var py = (latToWorldY(lat, zInt) * zScale * outputScale) - topLeftY;
if (idx === 0) {
ctx.moveTo(px, py);
} else {
ctx.lineTo(px, py);
}
});
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}

var dataUrl = "";
try {
dataUrl = canvas.toDataURL('image/png');
} catch (e) {
reject('Unable to generate print image.');
return;
}

if (!dataUrl || dataUrl.length < 1000) {
reject('Generated print image is empty.');
return;
}

resolve(dataUrl);
}).catch(function() {
reject('Failed to load map tiles for printing.');
});
}

var testUrl = buildTileUrl(0, 0, 0);
loadImage(testUrl).then(function(img) {
var tileImageSize = (img && img.width) ? img.width : 256;
buildImage(tileImageSize);
}).catch(function() {
buildImage(256);
});
});
}

renderMapTilerImage().then(function(dataUrl) {
setPrintWindowImage(dataUrl);
}).catch(function(errMsg) {
alert(errMsg);
});
return;
}

// Build polygon path for Static Maps API
var pathPoints = coords.map(function(coord) {
var ll = getLatLng(coord);
if (!isFinite(ll.lat) || !isFinite(ll.lng)) return null;
return ll.lat + ',' + ll.lng;
}).filter(function(p) { return p !== null; });
// Close the polygon
pathPoints.push(pathPoints[0]);
var pathStr = pathPoints.join('|');

// Calculate bounding box to determine optimal zoom
var minLat = Infinity, maxLat = -Infinity;
var minLng = Infinity, maxLng = -Infinity;
coords.forEach(function(coord) {
var ll = getLatLng(coord);
var lat = ll.lat;
var lng = ll.lng;
if (!isFinite(lat) || !isFinite(lng)) return;
if (lat < minLat) minLat = lat;
if (lat > maxLat) maxLat = lat;
if (lng < minLng) minLng = lng;
if (lng > maxLng) maxLng = lng;
});

var centerLat = (minLat + maxLat) / 2;
var centerLng = (minLng + maxLng) / 2;

// Calculate the span of the polygon
var latSpan = maxLat - minLat;
var lngSpan = maxLng - minLng;

// Calculate optimal zoom level to maximize polygon size
// Map dimensions: 640x800 (width x height for portrait letter)
// Each zoom level doubles the scale
var zoom = 20; // Start with max zoom

// Degrees per pixel at zoom level 0 is approximately 360/256 for lng
// For latitude it varies, but we use equirectangular approximation
var mapWidth = 640;
var mapHeight = 800;

// Add 10% padding around the polygon
var paddedLatSpan = latSpan * 1.1;
var paddedLngSpan = lngSpan * 1.1;

// Calculate zoom based on longitude span
if (paddedLngSpan > 0) {
var lngZoom = Math.floor(Math.log2(360 / paddedLngSpan * mapWidth / 256));
if (lngZoom < zoom) zoom = lngZoom;
}

// Calculate zoom based on latitude span
if (paddedLatSpan > 0) {
var latZoom = Math.floor(Math.log2(180 / paddedLatSpan * mapHeight / 256));
if (latZoom < zoom) zoom = latZoom;
}

// Clamp zoom between 1 and 20
if (zoom < 1) zoom = 1;
if (zoom > 20) zoom = 20;

var staticMapUrl;

if (mapProvider === 'maptiler') {
if (!mapTilerKey || mapTilerKey === 'nothing') {
alert('MapTiler API key is missing.');
return;
}

var mapWidth = 640;
var mapHeight = 800;
var pathParam = 'stroke:#ff0000|width:3|fill:none|' + pathStr;

staticMapUrl = 'https://api.maptiler.com/maps/' +
encodeURIComponent(mapTilerStyle) +
'/static/auto/' +
mapWidth + 'x' + mapHeight + '@2x.png' +
'?path=' + encodeURIComponent(pathParam) +
'&key=' + encodeURIComponent(mapTilerKey);
} else {
// Build Google Static Maps URL with scale=2 for higher resolution (1280x1600 actual pixels)
staticMapUrl = 'https://maps.googleapis.com/maps/api/staticmap?' +
'size=640x800' +
'&scale=2' +
'&center=' + centerLat + ',' + centerLng +
'&zoom=' + zoom +
'&maptype=roadmap' +
'&path=color:0xFF0000CC|weight:3|fillcolor:0xFF000044|' + pathStr +
'&key=' + encodeURIComponent(googleMapsKey);
}

// Open print window with static map - landscape for wider polygons, portrait for taller
var isWide = lngSpan > latSpan * 1.2;
var pageSize = isWide ? 'letter landscape' : 'letter portrait';
var imgMaxHeight = isWide ? '5in' : '7in';

// Build street lists HTML
var borderStreetsHtml = '';
if (territoryBorderStreets && territoryBorderStreets.trim() !== '') {
borderStreetsHtml = '<div class="streets-section"><strong>Border Streets:</strong> ' + territoryBorderStreets + '</div>';
}

var insideStreetsHtml = '';
if (territoryStreets && territoryStreets.length > 0) {
insideStreetsHtml = '<div class="streets-section"><strong>Streets Inside:</strong> ' + territoryStreets.join(', ') + '</div>';
}

var printContent = '<!DOCTYPE html>' +
'<html><head><title>Territory: ' + territoryName + '</title>' +
'<style>' +
'@page { size: ' + pageSize + '; margin: 0.25in; }' +
'body { margin: 0; padding: 0; font-family: Arial, sans-serif; }' +
'.header { text-align: center; border-bottom: 2px solid #000; padding-bottom: 5px; margin-bottom: 10px; }' +
'.header h1 { margin: 0; font-size: 20pt; }' +
'.streets-section { font-size: 10pt; margin: 5px 0; text-align: left; }' +
'.map-container { text-align: center; }' +
'.map-container img { max-width: 100%; height: auto; max-height: ' + imgMaxHeight + '; }' +
'.print-btn { margin-top: 15px; padding: 10px 30px; font-size: 16px; cursor: pointer; }' +
'@media print { .no-print { display: none !important; } }' +
'</style></head><body>' +
'<div class="header"><h1>' + territoryName + '</h1></div>' +
borderStreetsHtml +
insideStreetsHtml +
'<div class="map-container">' +
'<img src="' + staticMapUrl + '" alt="Territory Map" onerror="document.body.innerHTML=\'<p>Error loading map. Please try again.</p>\';">' +
'</div>' +
'<div class="no-print" style="text-align: center; margin-top: 15px;">' +
'<button class="print-btn" onclick="window.print();">Print</button> ' +
'<button class="print-btn" onclick="window.close();">Close</button>' +
'</div>' +
'</body></html>';

printWindow = window.open('', '_blank', 'width=900,height=1000');
printWindow.document.write(printContent);
printWindow.document.close();
}

if (mapProvider === 'maptiler') {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initMap);
} else {
initMap();
}
setTimeout(function() {
if (!map) {
setMapMessage('Map failed to load.');
}
}, 2000);
} else {
setTimeout(function() {
if (typeof google === 'undefined') {
setMapMessage('Google Maps failed to load.');
}
}, 2000);
}
</script>

+ 4
- 10
app/views/shared/header.asp Прегледај датотеку

@@ -15,7 +15,7 @@ If IsObject(CurrentController) Then
On Error GoTo 0
End If

If Len(pageTitle) = 0 Then pageTitle = "Classic ASP Unified Framework"
If Len(pageTitle) = 0 Then pageTitle = "Classic ASP Starter Template"
%>
<html lang="en">
<head>
@@ -50,8 +50,8 @@ If Len(pageTitle) = 0 Then pageTitle = "Classic ASP Unified Framework"
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand rk-navbar-brand" href="/">
Classic ASP Unified
<span class="text-secondary small">Framework</span>
Classic ASP
<span class="text-secondary small">Starter</span>
</a>

<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#rkMainNav" aria-controls="rkMainNav" aria-expanded="false" aria-label="Toggle navigation">
@@ -61,13 +61,7 @@ If Len(pageTitle) = 0 Then pageTitle = "Classic ASP Unified Framework"
<div class="collapse navbar-collapse" id="rkMainNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/territories">Territories</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/households">Households</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/householder-names">Householder Names</a>
<a class="nav-link" href="/home">Home</a>
</li>
</ul>



+ 1030
- 0
applicationhost.config
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 0
- 3
core/lib.ControllerRegistry.asp Прегледај датотеку

@@ -15,9 +15,6 @@ Class ControllerRegistry_Class
' Format: m_controllers.Add "controllername", True
RegisterController "homecontroller"
RegisterController "errorcontroller"
RegisterController "territorycontroller"
RegisterController "householdcontroller"
RegisterController "householdernamecontroller"
End Sub

Private Sub Class_Terminate()


+ 4
- 32
public/Default.asp Прегледај датотеку

@@ -1,40 +1,12 @@
<!--#include file="..\core\autoload_core.asp" -->

<%
' Define application routes
router.AddRoute "GET", "/home", "homeController", "Index"
router.AddRoute "GET", "/", "TerritoryController", "Index"
router.AddRoute "GET", "", "TerritoryController", "Index"
' Define starter application routes
router.AddRoute "GET", "/home", "HomeController", "Index"
router.AddRoute "GET", "/", "HomeController", "Index"
router.AddRoute "GET", "", "HomeController", "Index"
router.AddRoute "GET", "/404", "ErrorController", "NotFound"

' Territory routes
router.AddRoute "GET", "/territories", "TerritoryController", "Index"
router.AddRoute "GET", "/territories/new", "TerritoryController", "Create"
router.AddRoute "POST", "/territories", "TerritoryController", "Store"
router.AddRoute "GET", "/territories/:id", "TerritoryController", "Show"
router.AddRoute "GET", "/territories/:id/edit", "TerritoryController", "Edit"
router.AddRoute "POST", "/territories/:id", "TerritoryController", "Update"
router.AddRoute "POST", "/territories/:id/delete", "TerritoryController", "Delete"

' Household routes
router.AddRoute "GET", "/households", "HouseholdController", "Index"
router.AddRoute "GET", "/households/new", "HouseholdController", "Create"
router.AddRoute "POST", "/households", "HouseholdController", "Store"
router.AddRoute "GET", "/households/:id", "HouseholdController", "Show"
router.AddRoute "GET", "/households/:id/edit", "HouseholdController", "Edit"
router.AddRoute "POST", "/households/:id", "HouseholdController", "Update"
router.AddRoute "POST", "/households/:id/delete", "HouseholdController", "Delete"
router.AddRoute "POST", "/households/:id/mark-returned", "HouseholdController", "MarkReturned"

' Householder Name routes
router.AddRoute "GET", "/householder-names", "HouseholderNameController", "Index"
router.AddRoute "GET", "/householder-names/new", "HouseholderNameController", "Create"
router.AddRoute "POST", "/householder-names", "HouseholderNameController", "Store"
router.AddRoute "GET", "/householder-names/:id", "HouseholderNameController", "Show"
router.AddRoute "GET", "/householder-names/:id/edit", "HouseholderNameController", "Edit"
router.AddRoute "POST", "/householder-names/:id", "HouseholderNameController", "Update"
router.AddRoute "POST", "/householder-names/:id/delete", "HouseholderNameController", "Delete"

' Dispatch the request (resolves route and executes controller action)
MVC.DispatchRequest Request.ServerVariables("REQUEST_METHOD"), _
TrimQueryParams(Request.ServerVariables("HTTP_X_ORIGINAL_URL"))


+ 4
- 0
run_site.cmd Прегледај датотеку

@@ -0,0 +1,4 @@
@echo off
setlocal
set "ASPC_STARTER_ROOT=%~dp0"
"C:\Program Files\IIS Express\iisexpress.exe" /config:"%~dp0applicationhost.config"

Loading…
Откажи
Сачувај

Powered by TurnKey Linux.