{{.AuthorName}} {{.Content}}
@@ -58,7 +47,7 @@ {{end}} {{else}} -No posts yet
++ Be the first to share something with the community! +
From 2136dd6759829c9c07e3a0dc88d27da55482285c Mon Sep 17 00:00:00 2001 From: Mann Patel <130435633+Patel-Mann@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:49:13 -0600 Subject: [PATCH] top bar update --- .gitignore | 8 +- Example_code/admin.go | 402 ++++++++++++++++ Example_code/admin_apointment.go | 83 ++++ app/internal/handlers/volunteer_address.go | 8 +- app/internal/handlers/volunteer_posts.go | 1 - app/internal/templates/address/address.html | 20 - app/internal/templates/appointment.html | 40 +- .../templates/dashboard/dashboard.html | 34 -- .../dashboard/volunteer_dashboard.html | 186 +++++++- app/internal/templates/layout.html | 434 +++++++++--------- app/internal/templates/posts.html | 13 - app/internal/templates/profile/profile.html | 13 - app/internal/templates/schedual/schedual.html | 24 - .../templates/volunteer/edit_volunteer.html | 14 - .../templates/volunteer/poll_form.html | 24 +- .../templates/volunteer/team_builder.html | 12 - .../templates/volunteer/volunteer.html | 14 - app/tmp/main | Bin 13296192 -> 13292080 bytes index.html | 365 +++++++++++++++ 19 files changed, 1257 insertions(+), 438 deletions(-) create mode 100644 Example_code/admin.go create mode 100644 Example_code/admin_apointment.go create mode 100644 index.html diff --git a/.gitignore b/.gitignore index 258af4f..9ce101a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/uploads -.env -/tmp -/Example_code +/app/uploads +/app/.env +/app/tmp/ +/app/Example_code diff --git a/Example_code/admin.go b/Example_code/admin.go new file mode 100644 index 0000000..e012e21 --- /dev/null +++ b/Example_code/admin.go @@ -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 +// } diff --git a/Example_code/admin_apointment.go b/Example_code/admin_apointment.go new file mode 100644 index 0000000..33b18f9 --- /dev/null +++ b/Example_code/admin_apointment.go @@ -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", + }) +} diff --git a/app/internal/handlers/volunteer_address.go b/app/internal/handlers/volunteer_address.go index 68362b9..aab1694 100644 --- a/app/internal/handlers/volunteer_address.go +++ b/app/internal/handlers/volunteer_address.go @@ -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) diff --git a/app/internal/handlers/volunteer_posts.go b/app/internal/handlers/volunteer_posts.go index 17c9233..c1fead1 100644 --- a/app/internal/handlers/volunteer_posts.go +++ b/app/internal/handlers/volunteer_posts.go @@ -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 diff --git a/app/internal/templates/address/address.html b/app/internal/templates/address/address.html index 2bc760a..8a2e855 100644 --- a/app/internal/templates/address/address.html +++ b/app/internal/templates/address/address.html @@ -1,25 +1,5 @@ {{ define "content" }}
{{.AuthorName}} {{.Content}}
@@ -58,7 +47,7 @@ {{end}} {{else}} -+ Be the first to share something with the community! +