// 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 // }