top bar update

This commit is contained in:
Mann Patel
2025-08-29 16:49:13 -06:00
parent f1b5cdc806
commit 2136dd6759
19 changed files with 1257 additions and 438 deletions

8
.gitignore vendored
View File

@@ -1,4 +1,4 @@
/uploads
.env
/tmp
/Example_code
/app/uploads
/app/.env
/app/tmp/
/app/Example_code

402
Example_code/admin.go Normal file
View File

@@ -0,0 +1,402 @@
// package handlers
// import (
// "database/sql"
// "errors"
// "log"
// "net/http"
// "strconv"
// "time"
// "github.com/patel-mann/poll-system/app/internal/models"
// "github.com/patel-mann/poll-system/app/internal/utils"
// )
// // View model for listing/assigning schedules
// type AssignmentVM struct {
// ID int
// VolunteerID int
// VolunteerName string
// AddressID int
// Address string
// Date string // YYYY-MM-DD (for input[type=date])
// AppointmentTime string // HH:MM
// VisitedValidated bool
// }
// // GET + POST in one handler:
// // - GET: show assignments + form to assign
// // - POST: create a new assignment
// func AdminAssignmentsHandler(w http.ResponseWriter, r *http.Request) {
// switch r.Method {
// case http.MethodPost:
// if err := createAssignmentFromForm(r); err != nil {
// log.Println("create assignment error:", err)
// volunteers, _ := fetchVolunteers()
// addresses, _ := fetchAddresses()
// assignments, _ := fetchAssignments()
// utils.Render(w, "schedual/assignments.html", map[string]interface{}{
// "Title": "Admin — Assign Addresses",
// "IsAuthenticated": true,
// "ActiveSection": "admin_assignments",
// "Volunteers": volunteers,
// "Addresses": addresses,
// "Assignments": assignments,
// "Error": err.Error(),
// })
// return
// }
// http.Redirect(w, r, "/admin/assignments", http.StatusSeeOther)
// return
// }
// // GET: fetch volunteers, addresses, and existing assignments
// volunteers, err := fetchVolunteers()
// if err != nil {
// log.Println("fetch volunteers error:", err)
// http.Error(w, "Failed to load volunteers", http.StatusInternalServerError)
// return
// }
// addresses, err := fetchAddresses()
// if err != nil {
// log.Println("fetch addresses error:", err)
// http.Error(w, "Failed to load addresses", http.StatusInternalServerError)
// return
// }
// assignments, err := fetchAssignments()
// if err != nil {
// log.Println("fetch assignments error:", err)
// http.Error(w, "Failed to load assignments", http.StatusInternalServerError)
// return
// }
// utils.Render(w, "assignments.html", map[string]interface{}{
// "Title": "Admin — Assign Addresses",
// "IsAuthenticated": true,
// "ActiveSection": "admin_assignments",
// "Volunteers": volunteers,
// "Addresses": addresses,
// "Assignments": assignments,
// })
// }
// // GET (edit form) + POST (update/delete)
// func AdminAssignmentEditHandler(w http.ResponseWriter, r *http.Request) {
// idStr := r.URL.Query().Get("id")
// id, _ := strconv.Atoi(idStr)
// if id <= 0 {
// http.NotFound(w, r)
// return
// }
// if r.Method == http.MethodPost {
// action := r.FormValue("action")
// switch action {
// case "delete":
// if err := deleteAssignment(id); err != nil {
// log.Println("delete assignment error:", err)
// http.Error(w, "Failed to delete assignment", http.StatusInternalServerError)
// return
// }
// http.Redirect(w, r, "/admin/assignments", http.StatusSeeOther)
// return
// case "update":
// if err := updateAssignmentFromForm(id, r); err != nil {
// log.Println("update assignment error:", err)
// vm, _ := fetchAssignmentByID(id)
// volunteers, _ := fetchVolunteers()
// addresses, _ := fetchAddresses()
// utils.Render(w, "assignment_edit.html", map[string]interface{}{
// "Title": "Edit Assignment",
// "Assignment": vm,
// "Volunteers": volunteers,
// "Addresses": addresses,
// "Error": err.Error(),
// })
// return
// }
// http.Redirect(w, r, "/admin/assignments", http.StatusSeeOther)
// return
// default:
// http.Error(w, "Unknown action", http.StatusBadRequest)
// return
// }
// }
// // GET edit
// vm, err := fetchAssignmentByID(id)
// if err != nil {
// if err == sql.ErrNoRows {
// http.NotFound(w, r)
// return
// }
// log.Println("fetch assignment by ID error:", err)
// http.Error(w, "Failed to load assignment", http.StatusInternalServerError)
// return
// }
// volunteers, err := fetchVolunteers()
// if err != nil {
// log.Println("fetch volunteers error:", err)
// http.Error(w, "Failed to load volunteers", http.StatusInternalServerError)
// return
// }
// addresses, err := fetchAddresses()
// if err != nil {
// log.Println("fetch addresses error:", err)
// http.Error(w, "Failed to load addresses", http.StatusInternalServerError)
// return
// }
// utils.Render(w, "assignment_edit.html", map[string]interface{}{
// "Title": "Edit Assignment",
// "Assignment": vm,
// "Volunteers": volunteers,
// "Addresses": addresses,
// })
// }
// // ----- Helpers -----
// func createAssignmentFromForm(r *http.Request) error {
// volID, _ := strconv.Atoi(r.FormValue("volunteer_id"))
// addrID, _ := strconv.Atoi(r.FormValue("address_id"))
// dateStr := r.FormValue("date")
// timeStr := r.FormValue("appointment_time")
// if volID <= 0 || addrID <= 0 || dateStr == "" || timeStr == "" {
// return errors.New("please fill all required fields")
// }
// if _, err := time.Parse("2006-01-02", dateStr); err != nil {
// return errors.New("invalid date format")
// }
// if _, err := time.Parse("15:04", timeStr); err != nil {
// return errors.New("invalid time format")
// }
// _, err := models.DB.Exec(`
// INSERT INTO schedual (user_id, address_id, appointment_date, appointment_time, created_at, updated_at)
// VALUES ($1,$2,$3,$4,NOW(),NOW())
// `, volID, addrID, dateStr, timeStr)
// if err != nil {
// log.Println("database insert error:", err)
// return errors.New("failed to create assignment")
// }
// return nil
// }
// func updateAssignmentFromForm(id int, r *http.Request) error {
// volID, _ := strconv.Atoi(r.FormValue("volunteer_id"))
// addrID, _ := strconv.Atoi(r.FormValue("address_id"))
// dateStr := r.FormValue("date")
// timeStr := r.FormValue("appointment_time")
// if volID <= 0 || addrID <= 0 || dateStr == "" || timeStr == "" {
// return errors.New("please fill all required fields")
// }
// if _, err := time.Parse("2006-01-02", dateStr); err != nil {
// return errors.New("invalid date format")
// }
// if _, err := time.Parse("15:04", timeStr); err != nil {
// return errors.New("invalid time format")
// }
// result, err := models.DB.Exec(`
// UPDATE schedual
// SET user_id=$1, address_id=$2, appointment_date=$3, appointment_time=$4, updated_at=NOW()
// WHERE schedual_id=$5
// `, volID, addrID, dateStr, timeStr, id)
// if err != nil {
// log.Println("database update error:", err)
// return errors.New("failed to update assignment")
// }
// rowsAffected, _ := result.RowsAffected()
// if rowsAffected == 0 {
// return errors.New("assignment not found")
// }
// return nil
// }
// func deleteAssignment(id int) error {
// result, err := models.DB.Exec(`DELETE FROM schedual WHERE schedual_id=$1`, id)
// if err != nil {
// log.Println("database delete error:", err)
// return errors.New("failed to delete assignment")
// }
// rowsAffected, _ := result.RowsAffected()
// if rowsAffected == 0 {
// return errors.New("assignment not found")
// }
// return nil
// }
// // Fetch volunteers
// type VolunteerPick struct {
// ID int
// FirstName string
// LastName string
// Email string
// }
// func fetchVolunteers() ([]VolunteerPick, error) {
// rows, err := models.DB.Query(`
// SELECT users_id, first_name, last_name, email
// FROM "user"
// WHERE role='volunteer'
// ORDER BY first_name, last_name
// `)
// if err != nil {
// return nil, err
// }
// defer rows.Close()
// var out []VolunteerPick
// for rows.Next() {
// var v VolunteerPick
// if err := rows.Scan(&v.ID, &v.FirstName, &v.LastName, &v.Email); err != nil {
// log.Println("fetchVolunteers scan:", err)
// continue
// }
// out = append(out, v)
// }
// return out, rows.Err()
// }
// // Fetch addresses
// type AddressPick struct {
// ID int
// Label string
// VisitedValidated bool
// }
// func fetchAddresses() ([]AddressPick, error) {
// rows, err := models.DB.Query(`
// SELECT
// address_id,
// address,
// street_name,
// street_type,
// street_quadrant,
// house_number,
// house_alpha,
// longitude,
// latitude,
// visited_validated
// FROM address_database
// ORDER BY address_id DESC
// `)
// if err != nil {
// return nil, err
// }
// defer rows.Close()
// var out []AddressPick
// for rows.Next() {
// var addr models.AddressDatabase
// if err := rows.Scan(
// &addr.AddressID,
// &addr.Address,
// &addr.StreetName,
// &addr.StreetType,
// &addr.StreetQuadrant,
// &addr.HouseNumber,
// &addr.HouseAlpha,
// &addr.Longitude,
// &addr.Latitude,
// &addr.VisitedValidated,
// ); err != nil {
// log.Println("fetchAddresses scan:", err)
// continue
// }
// label := addr.Address
// if label == "" {
// label = addr.HouseNumber
// if addr.StreetName != "" {
// if label != "" {
// label += " "
// }
// label += addr.StreetName
// }
// if addr.StreetType != "" {
// label += " " + addr.StreetType
// }
// if addr.StreetQuadrant != "" {
// label += " " + addr.StreetQuadrant
// }
// if addr.HouseAlpha != nil {
// label += " " + *addr.HouseAlpha
// }
// }
// out = append(out, AddressPick{
// ID: addr.AddressID,
// Label: label,
// VisitedValidated: addr.VisitedValidated,
// })
// }
// return out, rows.Err()
// }
// // Add this missing function
// func fetchAssignments() ([]AssignmentVM, error) {
// rows, err := models.DB.Query(`
// SELECT
// s.schedual_id,
// u.users_id,
// COALESCE(u.first_name,'') || ' ' || COALESCE(u.last_name,'') AS volunteer_name,
// a.address_id,
// COALESCE(a.address,'') AS address,
// s.appointment_date,
// s.appointment_time
// FROM schedual s
// JOIN "user" u ON u.users_id = s.user_id
// JOIN address_database a ON a.address_id = s.address_id
// ORDER BY s.appointment_date DESC, s.appointment_time DESC
// `)
// if err != nil {
// return nil, err
// }
// defer rows.Close()
// var assignments []AssignmentVM
// for rows.Next() {
// var vm AssignmentVM
// if err := rows.Scan(&vm.ID, &vm.VolunteerID, &vm.VolunteerName, &vm.AddressID, &vm.Address,
// &vm.Date, &vm.AppointmentTime); err != nil {
// log.Println("fetchAssignments scan:", err)
// continue
// }
// assignments = append(assignments, vm)
// }
// return assignments, rows.Err()
// }
// func fetchAssignmentByID(id int) (AssignmentVM, error) {
// var vm AssignmentVM
// err := models.DB.QueryRow(`
// SELECT
// s.schedual_id,
// u.users_id,
// COALESCE(u.first_name,'') || ' ' || COALESCE(u.last_name,'') AS volunteer_name,
// a.address_id,
// COALESCE(a.address,'') AS address,
// s.appointment_date,
// s.appointment_time
// FROM schedual s
// JOIN "user" u ON u.users_id = s.user_id
// JOIN address_database a ON a.address_id = s.address_id
// WHERE s.schedual_id = $1
// `, id).Scan(&vm.ID, &vm.VolunteerID, &vm.VolunteerName, &vm.AddressID, &vm.Address,
// &vm.Date, &vm.AppointmentTime)
// return vm, err
// }

View File

@@ -0,0 +1,83 @@
package handlers
import (
"log"
"net/http"
"github.com/patel-mann/poll-system/app/internal/models"
"github.com/patel-mann/poll-system/app/internal/utils"
)
type AssignedAddress struct {
AddressID int
Address string
StreetName string
StreetType string
StreetQuadrant string
HouseNumber string
HouseAlpha *string
Longitude float64
Latitude float64
VisitedValidated bool
CreatedAt string
UpdatedAt string
Assigned bool
UserName string
UserEmail string
UserPhone string
AppointmentDate *string
AppointmentTime *string
}
func AssignedAddressesHandler(w http.ResponseWriter, r *http.Request) {
username,_ := models.GetCurrentUserName(r)
rows, err := models.DB.Query(`
SELECT
a.address_id, a.address, a.street_name, a.street_type, a.street_quadrant,
a.house_number, a.house_alpha, a.longitude, a.latitude, a.visited_validated,
a.created_at, a.updated_at,
CASE WHEN ap.user_id IS NOT NULL THEN true ELSE false END as assigned,
COALESCE(u.first_name || ' ' || u.last_name, '') as user_name,
COALESCE(u.email, '') as user_email,
COALESCE(u.phone, '') as user_phone,
TO_CHAR(ap.appointment_date, 'YYYY-MM-DD') as appointment_date,
TO_CHAR(ap.appointment_time, 'HH24:MI') as appointment_time
FROM address_database a
LEFT JOIN appointment ap ON a.address_id = ap.address_id
LEFT JOIN users u ON ap.user_id = u.user_id
ORDER BY a.address_id;
`)
if err != nil {
log.Printf("query error: %v", err)
http.Error(w, "query error", http.StatusInternalServerError)
return
}
defer rows.Close()
var assignedAddresses []AssignedAddress
for rows.Next() {
var addr AssignedAddress
err := rows.Scan(
&addr.AddressID, &addr.Address, &addr.StreetName, &addr.StreetType, &addr.StreetQuadrant,
&addr.HouseNumber, &addr.HouseAlpha, &addr.Longitude, &addr.Latitude, &addr.VisitedValidated,
&addr.CreatedAt, &addr.UpdatedAt, &addr.Assigned, &addr.UserName, &addr.UserEmail,
&addr.UserPhone, &addr.AppointmentDate, &addr.AppointmentTime,
)
if err != nil {
log.Printf("scan error: %v", err)
continue
}
assignedAddresses = append(assignedAddresses, addr)
}
utils.Render(w, "address_assigned.html", map[string]interface{}{
"Title": "Assigned Addresses",
"IsAuthenticated": true,
"AssignedList": assignedAddresses,
"ShowAdminNav": true,
"Role": "admin",
"UserName": username,
"ActiveSection": "assigned",
})
}

View File

@@ -75,11 +75,11 @@ func VolunteerAppointmentHandler(w http.ResponseWriter, r *http.Request) {
// Set button properties based on poll response status
a.HasPollResponse = pollResponseExists
if pollResponseExists {
a.PollButtonText = "Poll Taken"
a.PollButtonClass = "px-3 py-1 bg-green-600 text-white text-sm rounded cursor-not-allowed"
a.PollButtonText = "Poll"
a.PollButtonClass = "px-1 py-1 bg-green-600 text-white text-sm rounded cursor-not-allowed"
} else {
a.PollButtonText = "Ask Poll"
a.PollButtonClass = "px-3 py-1 bg-blue-600 text-white text-sm hover:bg-blue-700 rounded"
a.PollButtonText = "Ask"
a.PollButtonClass = "px-1 py-1 bg-blue-600 text-white text-sm hover:bg-blue-700 rounded"
}
appointments = append(appointments, a)

View File

@@ -150,7 +150,6 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
if err != nil {
return nil, err
}
fmt.Print("Stats: ", stats.AppointmentsThisWeek," Today's date: " , today ,"fasd", weekStart)
// Total appointments

View File

@@ -1,25 +1,5 @@
{{ define "content" }}
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-map-marker-alt{{end}} text-green-600"
></i>
<span class="text-sm font-medium"> Address Database </span>
</div>
</div>
{{if .Pagination}}
<div class="text-sm text-gray-600">
Showing {{.Pagination.StartRecord}}-{{.Pagination.EndRecord}} of
{{.Pagination.TotalRecords}} addresses
</div>
{{end}}
</div>
</div>
<!-- Toolbar -->
<div class="bg-gray-50 border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">

View File

@@ -1,19 +1,5 @@
{{ define "content" }}
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-calendar-alt{{end}} text-green-600"
></i>
<span class="text-sm font-medium">Appointments</span>
</div>
</div>
</div>
</div>
<!-- Toolbar -->
<div class="bg-gray-50 border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
@@ -41,16 +27,28 @@
<tr
class="text-left text-gray-700 font-medium border-b border-gray-200"
>
<th class="px-6 py-3 whitespace-nowrap">Poll</th>
<th class="px-6 py-3 whitespace-nowrap">Address</th>
<th class="px-6 py-3 whitespace-nowrap">Coordinates</th>
<th class="px-6 py-3 whitespace-nowrap">Appointment Date</th>
<th class="px-6 py-3 whitespace-nowrap">Appointment Time</th>
<th class="px-6 py-3 whitespace-nowrap">Poll Question</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{{ range .Appointments }}
<tr class="hover:bg-gray-50">
<td class="px-6 py-3 whitespace-nowrap">
{{ if .HasPollResponse }}
<span class="{{ .PollButtonClass }}"> {{ .PollButtonText }} </span>
{{ else }}
<a
href="/poll?address_id={{ .AddressID }}"
class="{{ .PollButtonClass }}"
>
{{ .PollButtonText }}
</a>
{{ end }}
</td>
<td class="px-6 py-3 whitespace-nowrap">{{ .Address }}</td>
<td class="px-6 py-3 whitespace-nowrap">
<a
@@ -67,18 +65,6 @@
<td class="px-6 py-3 whitespace-nowrap">
{{ .AppointmentTime.Format "15:04" }}
</td>
<td class="px-6 py-3 whitespace-nowrap">
{{ if .HasPollResponse }}
<span class="{{ .PollButtonClass }}"> {{ .PollButtonText }} </span>
{{ else }}
<a
href="/poll?address_id={{ .AddressID }}"
class="{{ .PollButtonClass }}"
>
{{ .PollButtonText }}
</a>
{{ end }}
</td>
</tr>
{{ else }}
<tr>

View File

@@ -18,40 +18,6 @@
<body class="bg-gray-50">
<!-- Full Width Container -->
<div class="min-h-screen w-full flex flex-col">
<!-- Top Navigation Bar -->
<div class="bg-white border-b border-gray-200 w-full">
<div class="px-8 py-6">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-8 h-8 bg-blue-600 flex items-center justify-center">
<i class="fas fa-chart-bar text-white text-sm"></i>
</div>
<span class="text-xl font-semibold text-gray-900">
Dashboard Overview
</span>
</div>
<div class="flex items-center gap-4">
<button
class="px-6 py-2.5 bg-blue-600 text-white text-sm font-medium hover:bg-blue-700 transition-colors"
>
<i class="fas fa-download mr-2"></i>Export Data
</button>
<button
class="px-6 py-2.5 bg-green-600 text-white text-sm font-medium hover:bg-green-700 transition-colors"
onclick="window.location.href='/addresses/upload-csv'"
>
<i class="fas fa-upload mr-2"></i>Import Data
</button>
<button
class="px-6 py-2.5 border border-gray-300 text-gray-700 text-sm font-medium hover:bg-gray-50 transition-colors"
>
<i class="fas fa-filter mr-2"></i>Filter
</button>
</div>
</div>
</div>
</div>
<!-- Main Dashboard Content -->
<div class="w-full">
<!-- Stats Grid - Full Width -->

View File

@@ -1,29 +1,18 @@
{{ define "content" }}
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-4 sm:px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i class="fas fa-tachometer-alt text-green-600"></i>
<span class="text-sm font-medium">Volunteer Dashboard</span>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="flex-1 overflow-hidden bg-gray-50">
<div class="h-full flex flex-col lg:flex-row gap-6 p-4 sm:p-6">
<div class="h-screen flex flex-col lg:flex-row gap-6 p-4 sm:p-6">
<!-- Left Column - Posts -->
<div class="flex-1 lg:flex-none lg:w-2/3 space-y-0">
<div class="flex-1 lg:flex-none lg:w-1/3 overflow-y-auto pr-2">
{{ if .Posts }}{{range .Posts}}
<!-- Posts Feed -->
<article class="bg-white border-b border-gray-200">
<!-- Post Header -->
<div class="flex items-center px-4 sm:px-6 py-4">
<div class="flex items-center px-6 py-4">
<div class="flex-shrink-0">
<div
class="w-10 h-10 bg-blue-500 flex items-center justify-center text-white font-semibold rounded-full"
class="w-10 h-10 bg-blue-500 flex items-center justify-center text-white font-semibold"
>
{{slice .AuthorName 0 1}}
</div>
@@ -50,7 +39,7 @@
<!-- Post Content -->
{{if .Content}}
<div class="px-4 sm:px-6 pt-2 pb-4">
<div class="px-6 pt-2 pb-4">
<p class="text-gray-900 leading-relaxed">
<span class="font-semibold">{{.AuthorName}}</span> {{.Content}}
</p>
@@ -58,7 +47,7 @@
{{end}}
</article>
{{else}}
<div class="bg-white p-8 sm:p-12 text-center border-b border-gray-200">
<div class="bg-white p-12 text-center">
<div class="max-w-sm mx-auto">
<svg
class="w-16 h-16 mx-auto text-gray-300 mb-4"
@@ -74,6 +63,9 @@
></path>
</svg>
<h3 class="text-lg font-medium text-gray-900 mb-2">No posts yet</h3>
<p class="text-gray-500">
Be the first to share something with the community!
</p>
</div>
</div>
{{ end }} {{ else }}
@@ -94,7 +86,163 @@
</div>
<!-- Right Column - Statistics -->
<div class="w-full lg:w-1/3 flex flex-col gap-4 sm:gap-6">
<div
class="w-full lg:w-1/3 flex flex-col gap-4 sm:gap-6 sticky top-0 self-start h-fit"
>
<!-- Today's Overview -->
<div class="bg-white border-b border-gray-200">
<div class="px-4 sm:px-6 py-4">
<h3 class="text-sm font-semibold text-gray-900 mb-4">
Today's Overview
</h3>
<div class="space-y-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-calendar-day text-gray-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700">Appointments Today</span>
</div>
<span class="text-lg font-semibold text-gray-900">
{{ .Statistics.AppointmentsToday }}
</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-calendar-week text-gray-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700"
>Appointments Tomorrow</span
>
</div>
<span class="text-lg font-semibold text-gray-900">
{{ .Statistics.AppointmentsTomorrow }}
</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-calendar-week text-gray-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700">This Week</span>
</div>
<span class="text-lg font-semibold text-gray-900">
{{ .Statistics.AppointmentsThisWeek }}
</span>
</div>
</div>
</div>
</div>
<!-- Polling Progress -->
<div class="bg-white border-b border-gray-200">
<div class="px-4 sm:px-6 py-4">
<h3 class="text-sm font-semibold text-gray-900 mb-4">
Polling Progress
</h3>
<div class="space-y-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-check-circle text-green-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700">Polls Completed</span>
</div>
<span class="text-lg font-semibold text-green-600">
{{ .Statistics.PollsCompleted }}
</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-clock text-orange-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700">Polls Remaining</span>
</div>
<span class="text-lg font-semibold text-orange-600">
{{ .Statistics.PollsRemaining }}
</span>
</div>
<!-- Progress Bar -->
{{ if gt .Statistics.TotalAppointments 0 }}
<div class="mt-4">
<div class="flex justify-between text-xs text-gray-600 mb-2">
<span>Progress</span>
<span
>{{ .Statistics.PollsCompleted }}/{{
.Statistics.TotalAppointments }}</span
>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div
class="bg-gray-600 h-2 rounded-full transition-all duration-300"
style="width: {{ .Statistics.PollCompletionPercent }}%"
></div>
</div>
</div>
{{ end }}
</div>
</div>
</div>
<!-- Signs Summary -->
<div class="bg-white border-b border-gray-200">
<div class="px-4 sm:px-6 py-4">
<h3 class="text-sm font-semibold text-gray-900 mb-4">
Signs Requested
</h3>
<div class="space-y-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-sign text-gray-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700">Lawn Signs</span>
</div>
<span class="text-lg font-semibold text-gray-900">
{{ .Statistics.LawnSignsRequested }}
</span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div
class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0"
>
<i class="fas fa-flag text-gray-600 text-xs"></i>
</div>
<span class="text-sm text-gray-700">Banner Signs</span>
</div>
<span class="text-lg font-semibold text-gray-900">
{{ .Statistics.BannerSignsRequested }}
</span>
</div>
</div>
</div>
</div>
</div>
<!-- Right Column - Statistics -->
<div
class="w-full lg:w-1/3 flex flex-col gap-4 sm:gap-6 sticky top-0 self-start h-fit"
>
<!-- Today's Overview -->
<div class="bg-white border-b border-gray-200">
<div class="px-4 sm:px-6 py-4">

View File

@@ -14,172 +14,185 @@
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
/>
</head>
<body class="bg-white font-sans">
<body class="bg-gray-50 font-sans">
{{ if .IsAuthenticated }}
<!-- Authenticated User Interface -->
<div class="w-full h-screen bg-white overflow-hidden" x-data="{ sidebarOpen: false }">
<!-- Mobile Header -->
<div class="lg:hidden bg-gray-100 px-4 py-3 flex items-center justify-between border-b border-gray-200">
<div class="flex items-center gap-2">
<div class="w-5 h-5 bg-orange-500 rounded text-white text-xs flex items-center justify-center font-bold">
L
</div>
<span class="text-sm font-medium">Poll System</span>
</div>
<div class="flex items-center gap-2">
<button @click="sidebarOpen = !sidebarOpen" class="p-2 hover:bg-gray-200 rounded">
<i class="fas fa-bars text-gray-600"></i>
</button>
<span class="text-sm font-medium text-gray-600">{{.UserName}}</span>
<div class="w-9 h-9 bg-blue-500 flex items-center justify-center text-white font-semibold">
{{slice .UserName 0 1}}
</div>
<a href="/logout" class="p-2 hover:bg-gray-200 rounded">
<i class="fas fa-external-link-alt text-gray-500"></i>
</a>
</div>
</div>
<div class="min-h-screen" x-data="{ mobileMenuOpen: false }">
<!-- Desktop Title Bar -->
<div class="hidden lg:flex bg-gray-100 px-4 py-3 items-center justify-between border-b border-gray-200">
<!-- Left Side: Logo + Title -->
<div class="flex items-center gap-2">
<div class="w-6 h-6 flex items-center justify-center">
<!-- Simple Navigation Bar -->
<nav class="bg-gray-700 border-b border-gray-600 fixed top-0 left-0 w-full z-50">
<div class="max-w-9xl mx-auto px-4 sm:px-6 lg:px-8 ">
<div class="flex justify-between items-center h-14 ">
<!-- Left: Logo and Navigation Links -->
<div class="flex items-center space-x-12">
<!-- Logo -->
<div class="flex items-center space-x-4">
<img src="../../static/icon-512.png" alt="Logo" class="w-6 h-6"/>
</div>
<span class="text-sm font-medium">Poll System</span>
<span class="text-xl font-semibold text-white">Poll System</span>
</div>
<!-- Right Side: User Info -->
<div class="flex items-center gap-3">
<span class="text-sm text-gray-600 hidden sm:block">Welcome back, {{ .UserName }}!</span>
<div class="w-9 h-9 bg-blue-500 flex items-center justify-center text-white font-semibold">
{{slice .UserName 0 1}}
</div>
<a href="/logout" class="p-2 hover:bg-gray-200 rounded">
<i class="fas fa-external-link-alt text-gray-500"></i>
</a>
</div>
</div>
<div class="flex h-full">
<!-- Mobile Sidebar Overlay -->
<div x-show="sidebarOpen"
x-transition:enter="transition-opacity ease-linear duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-linear duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-gray-600 bg-opacity-75 z-20 lg:hidden"
@click="sidebarOpen = false">
</div>
<!-- Sidebar -->
<div class="fixed inset-y-0 left-0 w-64 bg-gray-50 border-r border-gray-200 transform transition-transform duration-300 ease-in-out z-30 lg:relative lg:translate-x-0 lg:z-0"
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
x-show="sidebarOpen || window.innerWidth >= 1024"
x-transition:enter="transition ease-in-out duration-300 transform"
x-transition:enter-start="-translate-x-full"
x-transition:enter-end="translate-x-0"
x-transition:leave="transition ease-in-out duration-300 transform"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="-translate-x-full">
<!-- Mobile Close Button -->
<div class="lg:hidden flex justify-between items-center p-4 border-b border-gray-200">
<div class="flex items-center gap-2">
<div class="w-5 h-5 bg-orange-500 rounded text-white text-xs flex items-center justify-center font-bold">
L
</div>
<span class="text-sm font-medium">Poll System</span>
</div>
<button @click="sidebarOpen = false" class="p-1 hover:bg-gray-200 rounded">
<i class="fas fa-times text-gray-500"></i>
</button>
</div>
<div class="p-3 space-y-4">
<div class="space-y-1">
<!-- Desktop Navigation Links -->
<div class="hidden md:flex items-center space-x-10">
{{ if .ShowAdminNav }}
<a href="/dashboard"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "dashboard"}}bg-gray-100{{end}}">
<i class="fas fa-chart-pie text-gray-400 mr-2"></i>
<span>Dashboard</span>
<a href="/dashboard" class="text-sm font-medium {{if eq .ActiveSection "dashboard"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Dashboard
</a>
<a href="/volunteers"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "volunteer"}}bg-gray-100{{end}}">
<i class="fas fa-users text-gray-400 mr-2"></i>
<span>Volunteers</span>
<a href="/volunteers" class="text-sm font-medium {{if eq .ActiveSection "volunteer"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Volunteers
</a>
<a href="/team_builder"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "team_builder"}}bg-gray-100{{end}}">
<i class="fas fa-user-friends text-gray-400 mr-2"></i>
<span>Team Builder</span>
<a href="/team_builder" class="text-sm font-medium {{if eq .ActiveSection "team_builder"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Team Builder
</a>
<a href="/addresses"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "address"}}bg-gray-100{{end}}">
<i class="fas fa-map-marked-alt text-gray-400 mr-2"></i>
<span>Addresses</span>
<a href="/addresses" class="text-sm font-medium {{if eq .ActiveSection "address"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Addresses
</a>
<a href="/posts"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "post"}}bg-gray-100{{end}}">
<i class="fas fa-blog text-gray-400 mr-2"></i>
<span>Posts</span>
<a href="/posts" class="text-sm font-medium {{if eq .ActiveSection "post"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Posts
</a>
<a href="/reports"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "report"}}bg-gray-100{{end}}">
<i class="fas fa-table text-gray-400 mr-2"></i>
<span>Reports</span>
<a href="/reports" class="text-sm font-medium {{if eq .ActiveSection "report"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Reports
</a>
{{ end }}
{{ if .ShowVolunteerNav }}
<a href="/volunteer/dashboard"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "dashboard"}}bg-gray-100{{end}}">
<i class="fas fa-chart-pie text-gray-400 mr-2"></i>
<span>Dashboard</span>
<a href="/volunteer/dashboard" class="text-sm font-medium {{if eq .ActiveSection "dashboard"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Dashboard
</a>
<a href="/volunteer/Addresses"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "address"}}bg-gray-100{{end}}">
<i class="fas fa-home text-gray-400 mr-2"></i>
<span>Assigned Address</span>
<a href="/volunteer/Addresses" class="text-sm font-medium {{if eq .ActiveSection "address"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Assigned Address
</a>
<a href="/volunteer/schedual"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "schedual"}}bg-gray-100{{end}}">
<i class="fas fa-calendar-alt text-gray-400 mr-2"></i>
<span>My Schedule</span>
<a href="/volunteer/schedual" class="text-sm font-medium {{if eq .ActiveSection "schedual"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
My Schedule
</a>
{{ end }}
<a href="/profile"
@click="sidebarOpen = false"
class="flex items-center text-sm text-gray-600 hover:bg-gray-100 rounded px-2 py-1 {{if eq .ActiveSection "profile"}}bg-gray-100{{end}}">
<i class="fas fa-user-circle text-gray-400 mr-2"></i>
<span>Profile</span>
<a href="/profile" class="text-sm font-medium {{if eq .ActiveSection "profile"}}text-blue-300 border-b-2 border-blue-300{{else}}text-gray-300 hover:text-white{{end}} py-3 px-1">
Profile
</a>
</div>
<!-- Right: User Info and Actions -->
<div class="flex items-center space-x-4">
<!-- User Avatar and Name -->
<div class="hidden sm:flex items-center space-x-3">
<span class="text-sm text-gray-300">{{.UserName}}</span>
<div class="w-8 h-8 bg-blue-500 flex items-center justify-center text-white font-medium rounded-full">
{{slice .UserName 0 1}}
</div>
</div>
<!-- Logout Button -->
<a href="/logout" class="hidden sm:flex items-center px-3 py-2 text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-600 rounded-md">
<i class="fas fa-sign-out-alt mr-2"></i>
Logout
</a>
<!-- Mobile Menu Button -->
<button @click="mobileMenuOpen = !mobileMenuOpen" class="md:hidden p-2 rounded-md text-gray-300 hover:text-white hover:bg-gray-600">
<i class="fas fa-bars" x-show="!mobileMenuOpen"></i>
<i class="fas fa-times" x-show="mobileMenuOpen"></i>
</button>
</div>
</div>
<!-- Mobile Navigation Menu -->
<div x-show="mobileMenuOpen"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="md:hidden border-t border-gray-600"
@click.outside="mobileMenuOpen = false">
<div class="px-4 py-4 bg-gray-800">
<!-- User Info Mobile -->
<div class="flex items-center space-x-3 pb-4 mb-4 border-b border-gray-600">
<div class="w-10 h-10 bg-blue-500 flex items-center justify-center text-white font-medium rounded-full">
{{slice .UserName 0 1}}
</div>
<div>
<p class="text-sm font-medium text-white">{{.UserName}}</p>
<p class="text-xs text-gray-400">Logged in</p>
</div>
</div>
<!-- Mobile Navigation Links -->
<div class="space-y-2">
{{ if .ShowAdminNav }}
<a href="/dashboard" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "dashboard"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-chart-pie mr-3 w-4"></i>Dashboard
</a>
<a href="/volunteers" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "volunteer"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-users mr-3 w-4"></i>Volunteers
</a>
<a href="/team_builder" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "team_builder"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-user-friends mr-3 w-4"></i>Team Builder
</a>
<a href="/addresses" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "address"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-map-marked-alt mr-3 w-4"></i>Addresses
</a>
<a href="/posts" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "post"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-blog mr-3 w-4"></i>Posts
</a>
<a href="/reports" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "report"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-table mr-3 w-4"></i>Reports
</a>
{{ end }}
{{ if .ShowVolunteerNav }}
<a href="/volunteer/dashboard" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "dashboard"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-chart-pie mr-3 w-4"></i>Dashboard
</a>
<a href="/volunteer/Addresses" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "address"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-home mr-3 w-4"></i>Assigned Address
</a>
<a href="/volunteer/schedual" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "schedual"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-calendar-alt mr-3 w-4"></i>My Schedule
</a>
{{ end }}
<a href="/profile" @click="mobileMenuOpen = false"
class="block px-3 py-2 rounded-md text-base font-medium {{if eq .ActiveSection "profile"}}text-blue-300 bg-gray-700{{else}}text-gray-300 hover:text-white hover:bg-gray-700{{end}}">
<i class="fas fa-user-circle mr-3 w-4"></i>Profile
</a>
<!-- Logout for Mobile -->
<div class="border-t border-gray-600 pt-2 mt-4">
<a href="/logout" class="block px-3 py-2 rounded-md text-base font-medium text-gray-300 hover:text-white hover:bg-gray-700">
<i class="fas fa-sign-out-alt mr-3 w-4"></i>Logout
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<!-- Main Content -->
<div class="flex-1 flex flex-col overflow-hidden min-h-screen">
<div class="bg-white flex-1 overflow-auto pb-[60px]">
<!-- Main Content Area -->
<main class="flex-1 mt-14">
<!--sm:px-4 lg:px-6-->
<div class="max-w-9xl mx-auto overflow-hidden ">
{{ template "content" . }}
</div>
</main>
</div>
</div>
</div>
{{else}}
<!-- Landing Page -->
<!-- Landing Page (unchanged) -->
<!DOCTYPE html>
<html lang="en">
<head>
@@ -194,52 +207,52 @@
<div class="min-h-screen" x-data="{ mobileMenuOpen: false }">
<!-- Navigation -->
<nav class="bg-white border-b border-gray-200">
<nav class="bg-gray-700 border-b border-gray-600">
<div class="max-w-7xl mx-auto px-6">
<div class="flex justify-between items-center h-16">
<div class="flex justify-between items-center h-14">
<!-- Logo -->
<div class="flex items-center gap-3">
<img src="../../static/icon-512.png" alt="Logo" class="w-8 h-8"/>
<span class="text-xl font-semibold text-gray-900">Linq</span>
<span class="text-xl font-semibold text-white">Linq</span>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center gap-8">
<a href="#home" class="text-gray-600 hover:text-gray-900">Home</a>
<a href="#products" class="text-gray-600 hover:text-gray-900">Products</a>
<a href="#about" class="text-gray-600 hover:text-gray-900">About</a>
<a href="#home" class="text-gray-300 hover:text-white py-3 px-1">Home</a>
<a href="#products" class="text-gray-300 hover:text-white py-3 px-1">Products</a>
<a href="#about" class="text-gray-300 hover:text-white py-3 px-1">About</a>
</div>
<!-- Auth Buttons -->
<div class="hidden md:flex items-center gap-3">
<button onclick="openLoginModal()" class="px-4 py-2 text-gray-600 hover:text-gray-900">
<button onclick="openLoginModal()" class="px-4 py-2 text-gray-300 hover:text-white">
Sign In
</button>
<button onclick="openRegisterModal()" class="px-6 py-2 bg-blue-600 text-white hover:bg-blue-700 rounded">
<button onclick="openRegisterModal()" class="px-6 py-2 bg-blue-500 text-white hover:bg-blue-600 rounded">
Get Started
</button>
</div>
<!-- Mobile Menu Button -->
<button @click="mobileMenuOpen = !mobileMenuOpen" class="md:hidden p-2">
<i class="fas fa-bars text-gray-600" x-show="!mobileMenuOpen"></i>
<i class="fas fa-times text-gray-600" x-show="mobileMenuOpen"></i>
<button @click="mobileMenuOpen = !mobileMenuOpen" class="md:hidden p-2 text-gray-300 hover:text-white hover:bg-gray-600 rounded-md">
<i class="fas fa-bars" x-show="!mobileMenuOpen"></i>
<i class="fas fa-times" x-show="mobileMenuOpen"></i>
</button>
</div>
<!-- Mobile Menu -->
<div x-show="mobileMenuOpen" class="md:hidden border-t border-gray-200 bg-white">
<div x-show="mobileMenuOpen" class="md:hidden border-t border-gray-600 bg-gray-800">
<div class="px-6 py-4 space-y-3">
<a href="#home" @click="mobileMenuOpen = false" class="block py-2 text-gray-600">Home</a>
<a href="#products" @click="mobileMenuOpen = false" class="block py-2 text-gray-600">Products</a>
<a href="#about" @click="mobileMenuOpen = false" class="block py-2 text-gray-600">About</a>
<div class="border-t border-gray-200 pt-3 space-y-2">
<a href="#home" @click="mobileMenuOpen = false" class="block py-2 text-gray-300 hover:text-white">Home</a>
<a href="#products" @click="mobileMenuOpen = false" class="block py-2 text-gray-300 hover:text-white">Products</a>
<a href="#about" @click="mobileMenuOpen = false" class="block py-2 text-gray-300 hover:text-white">About</a>
<div class="border-t border-gray-600 pt-3 space-y-2">
<button onclick="openLoginModal(); document.querySelector('[x-data]').__x.$data.mobileMenuOpen = false"
class="block w-full text-left py-2 text-gray-600">
class="block w-full text-left py-2 text-gray-300 hover:text-white">
Sign In
</button>
<button onclick="openRegisterModal(); document.querySelector('[x-data]').__x.$data.mobileMenuOpen = false"
class="block w-full py-2 bg-blue-600 text-white rounded">
class="block w-full py-2 bg-blue-500 text-white hover:bg-blue-600 rounded">
Get Started
</button>
</div>
@@ -249,7 +262,7 @@
</nav>
<!-- Hero -->
<section id="home" class="pt-20 pb-16 px-6">
<section id="home" class="pt-40 pb-16 px-6 min-h-[600px]">
<div class="max-w-4xl mx-auto text-center">
<h1 class="text-4xl sm:text-5xl font-bold text-gray-900 mb-6">
Simple Polling
@@ -272,7 +285,7 @@
</section>
<!-- Products Section -->
<section id="products" class="py-16 bg-white">
<section id="products" class="py-16 bg-white min-h-[600px]">
<div class="max-w-6xl mx-auto px-6">
<div class="text-center mb-12">
<h2 class="text-3xl font-bold text-gray-900 mb-4">Our Products</h2>
@@ -317,7 +330,7 @@
</section>
<!-- About -->
<section id="about" class="py-16 bg-gray-50">
<section id="about" class="py-16 bg-gray-50 min-h-[600px]">
<div class="max-w-6xl mx-auto px-6">
<div class="grid lg:grid-cols-2 gap-12 items-center">
<div>
@@ -380,13 +393,7 @@
<div class="flex flex-col lg:flex-row min-h-[500px]">
<!-- Left Side - Image -->
<div class="hidden lg:flex flex-1 bg-gradient-to-br from-blue-500 to-blue-700 flex-col items-center justify-center">
<!-- <div class="text-center text-white">
<i class="fas fa-chart-line text-4xl sm:text-6xl mb-6"></i>
<h2 class="text-2xl sm:text-3xl font-bold mb-4">Welcome Back</h2>
<p class="text-base sm:text-lg opacity-90">Continue managing your polling operations</p>
</div> -->
<img src="../../static/feature-mobile2.jpg" alt="Welcome Image" class="object-cover h-full rounded-lg shadow-lg">
</div>
<!-- Right Side - Form -->
<div class="flex-1 p-6 sm:p-8">
@@ -426,11 +433,6 @@
<div class="flex flex-col lg:flex-row min-h-[600px]">
<!-- Left Side - Image -->
<div class="hidden lg:flex flex-1 bg-gradient-to-br from-blue-600 to-blue-800 flex-col items-center justify-center">
<!-- <div class="text-center text-white">
<i class="fas fa-rocket text-4xl sm:text-6xl mb-6"></i>
<h2 class="text-2xl sm:text-3xl font-bold mb-4">Get Started</h2>
<p class="text-base sm:text-lg opacity-90">Join our platform and streamline your operations</p>
</div> -->
<img src="../../static/feature-mobile1.jpg" alt="Welcome Image" class="object-cover h-full rounded-lg shadow-lg">
</div>

View File

@@ -1,19 +1,6 @@
{{ define "content" }}
<div class="min-h-screen bg-gray-100">
<!-- Header -->
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-users{{end}} text-blue-600"
></i>
<span class="text-sm font-medium">Volunteer Management</span>
</div>
</div>
</div>
</div>
<div class="max-w-2xl mx-auto">
<!-- Create Post Form -->

View File

@@ -1,18 +1,5 @@
{{ define "content" }}
<div class="min-h-screen bg-gray-50">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-users{{end}} text-blue-600"
></i>
<span class="text-sm font-medium">Volunteer Management</span>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="p-6">
<!-- Profile Info Section -->

View File

@@ -17,30 +17,6 @@
</head>
<body class="bg-gray-100">
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<i class="fas fa-chart-bar text-blue-600"></i>
<span class="text-xl font-semibold text-gray-800">
Schedual Overview
</span>
</div>
<div class="flex items-center gap-4">
<button
class="px-5 py-2 bg-blue-600 text-white text-sm hover:bg-blue-700 transition-colors"
>
<i class="fas fa-download mr-2"></i>Export Data
</button>
<button
class="px-5 py-2 border border-gray-300 text-gray-700 text-sm hover:bg-gray-50 transition-colors"
>
<i class="fas fa-filter mr-2"></i>Filter
</button>
</div>
</div>
</div>
<!-- Dashboard Content -->
<div class="flex-1 overflow-auto">
<!-- Top Stats Cards -->

View File

@@ -2,20 +2,6 @@
<div class="min-h-screen bg-gray-50">
<!-- Header Bar -->
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-users{{end}} text-blue-600"
></i>
<span class="text-sm font-medium">Volunteer Management</span>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="p-6">
<!-- Volunteer Info Section -->

View File

@@ -1,27 +1,5 @@
{{ define "content" }}
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-poll{{end}} text-green-600"
></i>
<span class="text-sm font-medium">Poll Questions</span>
</div>
</div>
<div class="flex items-center gap-2">
<a
href="/appointments"
class="px-3 py-1 bg-gray-500 text-white text-sm hover:bg-gray-600 rounded"
>
Back to Appointments
</a>
</div>
</div>
</div>
<!-- Form Content -->
<div class="flex-1 overflow-y-auto bg-gray-50 p-6">
<div class="max-w-2xl mx-auto">
@@ -150,7 +128,7 @@
<!-- Submit Button -->
<div class="flex justify-end gap-3 pt-6">
<a
href="/appointments"
href="/volunteer/Addresses"
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
>
Cancel

View File

@@ -1,17 +1,5 @@
{{ define "content" }}
<div class="min-h-screen bg-gray-50">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-users{{end}} text-blue-600"
></i>
<span class="text-sm font-medium">Volunteer Management</span>
</div>
</div>
</div>
<!-- Main Content -->
<div class="p-6 space-y-6">
{{range .TeamLeads}} {{ $teamLeadID := .ID }}

View File

@@ -1,20 +1,6 @@
{{ define "content" }}
<!-- Main Content -->
<div class="flex-1 flex flex-col overflow-hidden" x-data="volunteerTable()">
<!-- Top Navigation -->
<div class="bg-white border-b border-gray-200 px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-users{{end}} text-blue-600"
></i>
<span class="text-sm font-medium">Volunteer Management</span>
</div>
</div>
</div>
</div>
<!-- Toolbar -->
<div class="bg-gray-50 border-b border-gray-200 px-6 py-3">
<div class="flex items-center gap-4 text-sm">

Binary file not shown.

365
index.html Normal file
View File

@@ -0,0 +1,365 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Moraine lake sunset - Google Search</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap");
body {
font-family: "Roboto", sans-serif;
}
.mountain-bg {
background: linear-gradient(
135deg,
#4fc3f7 0%,
#29b6f6 25%,
#0277bd 50%,
#01579b 75%,
#263238 100%
);
}
</style>
</head>
<body class="bg-white">
<!-- Header with mountain background -->
<div class="mountain-bg relative h-48 overflow-hidden">
<!-- Mountain silhouettes -->
<div class="absolute inset-0">
<svg viewBox="0 0 1200 200" class="w-full h-full">
<!-- Background mountains -->
<polygon
points="0,200 0,100 100,80 200,120 300,90 400,110 500,85 600,105 700,95 800,115 900,100 1000,120 1100,110 1200,130 1200,200"
fill="rgba(69,90,100,0.4)"
/>
<!-- Mid mountains -->
<polygon
points="0,200 0,120 80,100 180,140 280,110 380,130 480,105 580,125 680,115 780,135 880,125 980,145 1080,135 1200,155 1200,200"
fill="rgba(38,50,56,0.6)"
/>
<!-- Front mountains -->
<polygon
points="0,200 0,140 60,120 160,160 260,130 360,150 460,125 560,145 660,135 760,155 860,145 960,165 1060,155 1200,175 1200,200"
fill="rgba(38,50,56,0.8)"
/>
<!-- Snow caps -->
<polygon points="50,130 80,100 110,130" fill="white" opacity="0.9" />
<polygon
points="150,150 180,140 210,150"
fill="white"
opacity="0.9"
/>
<polygon
points="250,140 280,110 310,140"
fill="white"
opacity="0.9"
/>
<polygon
points="450,135 480,105 510,135"
fill="white"
opacity="0.9"
/>
<polygon
points="650,145 680,115 710,145"
fill="white"
opacity="0.9"
/>
<polygon
points="850,155 880,125 910,155"
fill="white"
opacity="0.9"
/>
</svg>
</div>
<!-- Google logo and search bar -->
<div class="relative z-10 pt-8 px-4">
<div class="max-w-2xl mx-auto">
<!-- Google logo -->
<div class="mb-8">
<h1 class="text-white text-6xl font-normal tracking-tight">
Google
</h1>
</div>
<!-- Search bar -->
<div class="relative">
<div
class="bg-white rounded-full shadow-lg flex items-center px-4 py-3"
>
<input
type="text"
value="Moraine lake sunset"
class="flex-1 text-gray-900 text-lg outline-none px-2"
/>
<button class="p-2 hover:bg-gray-100 rounded-full">
<svg
class="w-6 h-6 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- User info -->
<div class="absolute top-4 right-4 flex items-center space-x-4">
<svg
class="w-6 h-6 text-white opacity-70"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
clip-rule="evenodd"
></path>
</svg>
<div
class="w-6 h-6 bg-white bg-opacity-20 rounded grid grid-cols-3 gap-0.5 p-1"
>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
<div class="bg-white bg-opacity-60 rounded-sm"></div>
</div>
<span class="text-white text-sm">aurelien.salomon@gmail.com</span>
<svg class="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
</div>
</div>
<!-- Navigation -->
<div class="bg-gray-700 border-b border-gray-600">
<div class="max-w-6xl mx-auto px-4">
<div class="flex items-center justify-between">
<div class="flex space-x-8">
<a
href="#"
class="text-blue-300 border-b-2 border-blue-300 py-3 px-1 text-sm font-medium"
>WEB</a
>
<a href="#" class="text-gray-300 hover:text-white py-3 px-1 text-sm"
>MAPS</a
>
<a href="#" class="text-gray-300 hover:text-white py-3 px-1 text-sm"
>IMAGES</a
>
<a href="#" class="text-gray-300 hover:text-white py-3 px-1 text-sm"
>VIDEOS</a
>
<div class="relative">
<a
href="#"
class="text-gray-300 hover:text-white py-3 px-1 text-sm flex items-center"
>
MORE
<svg
class="w-4 h-4 ml-1"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
</a>
</div>
<a href="#" class="text-gray-300 hover:text-white py-3 px-1 text-sm"
>SEARCH TOOLS</a
>
</div>
<div class="text-gray-400 text-sm">
About 7,920,200 Results&nbsp;&nbsp;0.18 seconds
</div>
</div>
</div>
</div>
<!-- Main content -->
<div class="max-w-6xl mx-auto px-4 py-4 flex">
<!-- Left column - Search results -->
<div class="flex-1 max-w-2xl">
<!-- Result 1 -->
<div class="mb-6">
<div class="text-sm text-green-600 mb-1">
wikipedia.com/morainelake
</div>
<h3 class="text-xl text-blue-600 hover:underline cursor-pointer mb-2">
Moraine lake - Wikipedia
</h3>
<p class="text-sm text-gray-600 leading-relaxed">
Moraine Lake is a glacially-fed lake in Banff National Park, 14
kilometres outside the Village of Lake Louise, Alberta, Canada. It
is situated in the Valley of the Ten Peaks, at an elevation of
approximately 6,183 feet. The lake has a surface area of 5 square
kilometres. The lake, being glacially fed, does not reach its crest
until mid to ...
</p>
</div>
<!-- Result 2 -->
<div class="mb-6">
<div class="text-sm text-green-600 mb-1">rockies.com</div>
<h3 class="text-xl text-blue-600 hover:underline cursor-pointer mb-2">
Best places to photograph rockies
</h3>
<p class="text-sm text-gray-600 leading-relaxed">
The light is usually best around sunrise and sunset, but interesting
photographs. Moraine Lake is about a 20 minute drive from Lake
Louise which is something ...
</p>
</div>
<!-- Images section -->
<div class="mb-8">
<h3 class="text-xl text-gray-900 mb-4">
Images for Moraine lake sunset
</h3>
<div class="grid grid-cols-4 gap-2">
<div
class="aspect-square bg-gradient-to-br from-blue-400 to-orange-400 rounded overflow-hidden"
>
<div
class="w-full h-full bg-gradient-to-t from-blue-900 via-blue-400 to-orange-300 relative"
>
<div
class="absolute bottom-0 w-full h-1/3 bg-gradient-to-r from-gray-800 to-gray-600"
></div>
</div>
</div>
<div
class="aspect-square bg-gradient-to-br from-orange-500 to-red-600 rounded overflow-hidden"
>
<div
class="w-full h-full bg-gradient-to-t from-gray-900 via-orange-500 to-yellow-400 relative"
>
<div
class="absolute bottom-0 w-full h-1/3 bg-gradient-to-r from-gray-900 to-gray-700"
></div>
</div>
</div>
<div
class="aspect-square bg-gradient-to-br from-yellow-400 to-orange-500 rounded overflow-hidden"
>
<div
class="w-full h-full bg-gradient-to-t from-blue-800 via-yellow-400 to-orange-300 relative"
>
<div
class="absolute bottom-0 w-full h-1/3 bg-gradient-to-r from-gray-800 to-gray-600"
></div>
</div>
</div>
<div
class="aspect-square bg-gradient-to-br from-green-400 to-blue-500 rounded overflow-hidden"
>
<div
class="w-full h-full bg-gradient-to-t from-green-800 via-blue-400 to-orange-200 relative"
>
<div
class="absolute bottom-0 w-full h-1/3 bg-gradient-to-r from-gray-900 to-gray-700"
></div>
</div>
</div>
</div>
</div>
<!-- Result 3 -->
<div class="mb-6">
<div class="text-sm text-green-600 mb-1">estravel.com</div>
<h3 class="text-xl text-blue-600 hover:underline cursor-pointer mb-2">
Best point for sunset in Alberta
</h3>
<p class="text-sm text-gray-600 leading-relaxed">
Moraine Lake is only half the size of its nearby neighbour Lake
Louise, but perhaps even more scenic. It's a glacier-fed lake
situated in the beautiful valley of the ten ...
</p>
</div>
<!-- Result 4 -->
<div class="mb-6">
<div class="text-sm text-green-600 mb-1">sunset.com</div>
<h3 class="text-xl text-blue-600 hover:underline cursor-pointer mb-2">
Sunset in the canada rocks
</h3>
<p class="text-sm text-gray-600 leading-relaxed">
Moraine Lake is only half the size of its nearby neighbour Lake
Louise, but perhaps even more scenic. It's a glacier-fed lake
situated in the beautiful valley of the ten ...
</p>
</div>
</div>
<!-- Right column - Weather widget -->
<div class="ml-8 w-80">
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div class="mb-4">
<h3 class="text-lg font-medium text-gray-900">Moraine lake</h3>
<p class="text-sm text-gray-500">Sunshine</p>
</div>
<!-- Weather chart -->
<div class="mb-4">
<div
class="relative h-32 bg-gradient-to-t from-yellow-300 via-yellow-400 to-blue-400 rounded-lg overflow-hidden"
>
<!-- Sun -->
<div
class="absolute top-4 right-8 w-8 h-8 bg-yellow-400 rounded-full border-4 border-yellow-300"
></div>
<!-- Time indicator -->
<div
class="absolute top-2 right-2 text-xs font-medium text-gray-700"
>
6:35 PM<br />
<span class="text-blue-600">Sunset</span>
</div>
<!-- Time markers -->
<div
class="absolute bottom-2 left-0 right-0 flex justify-between text-xs text-gray-600 px-2"
>
<span>6:00 AM</span>
<span>1:00 PM</span>
<span>8:00 PM</span>
</div>
</div>
</div>
<!-- Days -->
<div class="grid grid-cols-4 gap-2 text-center text-sm">
<div class="text-gray-900 font-medium">TODAY</div>
<div class="text-gray-500">THURSDAY</div>
<div class="text-gray-500">FRIDAY</div>
<div class="text-gray-500">SATURDAY</div>
</div>
</div>
</div>
</div>
</body>
</html>