Update: Few issues to resolve see readme
this push will conclude the majority of pulls. this repos will now, not be actively be managed or any further code pushes will not be frequent.
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
"fmt"
|
||||
|
||||
"github.com/patel-mann/poll-system/app/internal/models"
|
||||
"github.com/patel-mann/poll-system/app/internal/utils"
|
||||
@@ -36,19 +35,18 @@ type PageNumber struct {
|
||||
// AddressWithDetails extends AddressDatabase with appointment and user info
|
||||
type AddressWithDetails struct {
|
||||
models.AddressDatabase
|
||||
UserID *int
|
||||
UserName string
|
||||
UserEmail string
|
||||
AppointmentDate string
|
||||
AppointmentTime string
|
||||
UserID *int
|
||||
UserName string
|
||||
UserEmail string
|
||||
AppointmentDate string
|
||||
AppointmentTime string
|
||||
}
|
||||
|
||||
func AddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Get pagination parameters from query string
|
||||
pageStr := r.URL.Query().Get("page")
|
||||
pageSizeStr := r.URL.Query().Get("pageSize")
|
||||
username,_ := models.GetCurrentUserName(r)
|
||||
|
||||
username, _ := models.GetCurrentUserName(r)
|
||||
|
||||
page := 1
|
||||
pageSize := 20
|
||||
@@ -157,7 +155,7 @@ func AddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Get users associated with this admin
|
||||
currentAdminID := r.Context().Value("user_id").(int)
|
||||
currentAdminID := models.GetCurrentUserID(w, r)
|
||||
userRows, err := models.DB.Query(`
|
||||
SELECT u.user_id, u.first_name || ' ' || u.last_name AS name
|
||||
FROM users u
|
||||
@@ -216,7 +214,7 @@ func AddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
"ActiveSection": "address",
|
||||
"Addresses": addresses,
|
||||
"Users": users,
|
||||
"UserName": username,
|
||||
"UserName": username,
|
||||
"Role": "admin",
|
||||
"Pagination": pagination,
|
||||
})
|
||||
@@ -267,13 +265,9 @@ func AssignAddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
appointmentDate := r.FormValue("appointment_date")
|
||||
startTime := r.FormValue("time")
|
||||
|
||||
if userIDStr == "" || addressIDStr == "" {
|
||||
http.Error(w, "User ID and Address ID are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if appointmentDate == "" || startTime == "" {
|
||||
http.Error(w, "Appointment date and start time are required", http.StatusBadRequest)
|
||||
// Basic validation
|
||||
if userIDStr == "" || addressIDStr == "" || appointmentDate == "" || startTime == "" {
|
||||
http.Error(w, "All fields are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -289,54 +283,30 @@ func AssignAddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse and validate the appointment date
|
||||
// Parse date
|
||||
parsedDate, err := time.Parse("2006-01-02", appointmentDate)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid appointment date format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate that the appointment date is not in the past
|
||||
today := time.Now().Truncate(24 * time.Hour)
|
||||
if parsedDate.Before(today) {
|
||||
http.Error(w, "Appointment date cannot be in the past", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse and validate the start time
|
||||
// Parse time
|
||||
parsedTime, err := time.Parse("15:04", startTime)
|
||||
is_valid := ValidatedFreeTime(parsedDate, parsedTime, userID)
|
||||
if is_valid != true {
|
||||
http.Error(w, "User is not availabile", http.StatusBadRequest)
|
||||
return
|
||||
}else{
|
||||
fmt.Print("hello")
|
||||
}
|
||||
|
||||
// Verify the user exists and is associated with the current admin
|
||||
currentAdminID := r.Context().Value("user_id").(int)
|
||||
var userExists int
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT COUNT(*) FROM admin_volunteers av
|
||||
JOIN users u ON av.volunteer_id = u.user_id
|
||||
WHERE av.admin_id = $1 AND u.user_id = $2 AND av.is_active = true
|
||||
`, currentAdminID, userID).Scan(&userExists)
|
||||
if err != nil {
|
||||
log.Println("User verification error:", err)
|
||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if userExists == 0 {
|
||||
http.Error(w, "Invalid user selection", http.StatusBadRequest)
|
||||
http.Error(w, "Invalid appointment time format", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this address is already assigned to any user
|
||||
// --- Availability Check (non-blocking) ---
|
||||
isValid := ValidateAvailability(parsedDate, parsedTime, userID)
|
||||
if !isValid {
|
||||
// Instead of blocking, just log it
|
||||
log.Printf("⚠️ User %d is not available on %s at %s", userID, appointmentDate, startTime)
|
||||
}
|
||||
|
||||
// Check if this address is already assigned
|
||||
var exists int
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT COUNT(*) FROM appointment
|
||||
WHERE address_id = $1
|
||||
`, addressID).Scan(&exists)
|
||||
err = models.DB.QueryRow(`SELECT COUNT(*) FROM appointment WHERE address_id = $1`, addressID).Scan(&exists)
|
||||
if err != nil {
|
||||
log.Println("Assignment check error:", err)
|
||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||
@@ -347,38 +317,39 @@ func AssignAddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the user already has an appointment at the same date and time
|
||||
var timeConflict int
|
||||
// Check for conflicting appointment for the user
|
||||
var conflict int
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT COUNT(*) FROM appointment
|
||||
WHERE user_id = $1 AND appointment_date = $2 AND appointment_time = $3
|
||||
`, userID, appointmentDate, startTime).Scan(&timeConflict)
|
||||
WHERE user_id = $1 AND appointment_date = $2 AND appointment_time = $3`,
|
||||
userID, appointmentDate, startTime).Scan(&conflict)
|
||||
if err != nil {
|
||||
log.Println("Time conflict check error:", err)
|
||||
log.Println("Conflict check error:", err)
|
||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if timeConflict > 0 {
|
||||
if conflict > 0 {
|
||||
http.Error(w, "User already has an appointment at this date and time", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Assign the address - create appointment with specific date and time
|
||||
// Insert the appointment anyway
|
||||
_, err = models.DB.Exec(`
|
||||
INSERT INTO appointment (user_id, address_id, appointment_date, appointment_time, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, NOW(), NOW())
|
||||
`, userID, addressID, appointmentDate, startTime)
|
||||
VALUES ($1, $2, $3, $4, NOW(), NOW())`,
|
||||
userID, addressID, appointmentDate, startTime)
|
||||
if err != nil {
|
||||
log.Println("Assignment error:", err)
|
||||
log.Println("Insert appointment error:", err)
|
||||
http.Error(w, "Failed to assign address", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Redirect back to addresses page with success
|
||||
// ✅ Later: you can pass `UserNotAvailable: !isValid` to utils.Render instead of redirect
|
||||
log.Printf("✅ Address %d assigned to user %d for %s at %s (Available: %v)",
|
||||
addressID, userID, appointmentDate, startTime, isValid)
|
||||
|
||||
http.Redirect(w, r, "/addresses?success=assigned", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
func RemoveAssignedAddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Redirect(w, r, "/addresses", http.StatusSeeOther)
|
||||
|
||||
@@ -12,22 +12,22 @@ import (
|
||||
)
|
||||
|
||||
type VolunteerStatistics struct {
|
||||
AppointmentsToday int
|
||||
AppointmentsTomorrow int
|
||||
AppointmentsThisWeek int
|
||||
TotalAppointments int
|
||||
PollsCompleted int
|
||||
PollsRemaining int
|
||||
LawnSignsRequested int
|
||||
BannerSignsRequested int
|
||||
AppointmentsToday int
|
||||
AppointmentsTomorrow int
|
||||
AppointmentsThisWeek int
|
||||
TotalAppointments int
|
||||
PollsCompleted int
|
||||
PollsRemaining int
|
||||
LawnSignsRequested int
|
||||
BannerSignsRequested int
|
||||
PollCompletionPercent int
|
||||
}
|
||||
type TeamMate struct {
|
||||
UserID int
|
||||
FullName string
|
||||
Phone string
|
||||
Role string
|
||||
IsLead bool
|
||||
UserID int
|
||||
FullName string
|
||||
Phone string
|
||||
Role string
|
||||
IsLead bool
|
||||
}
|
||||
|
||||
// VolunteerPostsHandler - Dashboard view for volunteers with posts and statistics
|
||||
@@ -79,7 +79,7 @@ func VolunteerPostsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Fetch teammates
|
||||
teammatesRows, err := models.DB.Query(`
|
||||
teammatesRows, err := models.DB.Query(`
|
||||
SELECT u.user_id,
|
||||
u.first_name || ' ' || u.last_name AS full_name,
|
||||
COALESCE(u.phone, '') AS phone,
|
||||
@@ -94,21 +94,20 @@ func VolunteerPostsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
)
|
||||
ORDER BY CASE WHEN r.name = 'team_lead' THEN 0 ELSE 1 END, u.first_name;
|
||||
`, CurrentUserID, CurrentUserID)
|
||||
if err != nil {
|
||||
fmt.Printf("Database query error (teammates): %v\n", err)
|
||||
}
|
||||
defer teammatesRows.Close()
|
||||
|
||||
var teammates []TeamMate
|
||||
for teammatesRows.Next() {
|
||||
var t TeamMate
|
||||
if err := teammatesRows.Scan(&t.UserID, &t.FullName, &t.Phone, &t.Role); err != nil {
|
||||
fmt.Printf("Row scan error (teammates): %v\n", err)
|
||||
continue
|
||||
}
|
||||
teammates = append(teammates, t)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("Database query error (teammates): %v\n", err)
|
||||
}
|
||||
defer teammatesRows.Close()
|
||||
|
||||
var teammates []TeamMate
|
||||
for teammatesRows.Next() {
|
||||
var t TeamMate
|
||||
if err := teammatesRows.Scan(&t.UserID, &t.FullName, &t.Phone, &t.Role); err != nil {
|
||||
fmt.Printf("Row scan error (teammates): %v\n", err)
|
||||
continue
|
||||
}
|
||||
teammates = append(teammates, t)
|
||||
}
|
||||
|
||||
// Get volunteer statistics
|
||||
stats, err := getVolunteerStatistics(CurrentUserID)
|
||||
@@ -125,23 +124,23 @@ func VolunteerPostsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Printf("Volunteer viewing %d posts\n", len(posts))
|
||||
|
||||
utils.Render(w, "volunteer_dashboard.html", map[string]interface{}{
|
||||
"Title": "Volunteer Dashboard",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": showAdminNav,
|
||||
"ShowVolunteerNav": showVolunteerNav,
|
||||
"UserName": username,
|
||||
"Posts": posts,
|
||||
"Statistics": stats,
|
||||
"Teammates": teammates,
|
||||
"ActiveSection": "dashboard",
|
||||
"IsVolunteer": true,
|
||||
"Title": "Volunteer Dashboard",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": showAdminNav,
|
||||
"ShowVolunteerNav": showVolunteerNav,
|
||||
"UserName": username,
|
||||
"Posts": posts,
|
||||
"Statistics": stats,
|
||||
"Teammates": teammates,
|
||||
"ActiveSection": "dashboard",
|
||||
"IsVolunteer": true,
|
||||
})
|
||||
}
|
||||
|
||||
func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
stats := &VolunteerStatistics{}
|
||||
today := time.Now().Format("2006-01-02")
|
||||
|
||||
|
||||
// Get start of current week (Monday)
|
||||
now := time.Now()
|
||||
oneDayLater := now.Add(time.Hour * 12)
|
||||
@@ -160,11 +159,10 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
fmt.Println("Week Start:", weekStart.Format("2006-01-02"))
|
||||
fmt.Println("Week End:", weekEnd.Format("2006-01-02"))
|
||||
|
||||
|
||||
// Appointments today
|
||||
err := models.DB.QueryRow(`
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
WHERE user_id = $1 AND DATE(appointment_date) = $2
|
||||
`, userID, today).Scan(&stats.AppointmentsToday)
|
||||
if err != nil {
|
||||
@@ -173,8 +171,8 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
|
||||
// Appointments tomorrow
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
WHERE user_id = $1 AND DATE(appointment_date) = $2
|
||||
`, userID, oneDayLater).Scan(&stats.AppointmentsTomorrow)
|
||||
if err != nil {
|
||||
@@ -183,19 +181,18 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
|
||||
// Appointments this week
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
WHERE user_id = $1 AND DATE(appointment_date) >= $2 AND DATE(appointment_date) <= $3
|
||||
`, userID, weekStart, weekEnd).Scan(&stats.AppointmentsThisWeek)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
// Total appointments
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
SELECT COUNT(*)
|
||||
FROM appointment
|
||||
WHERE user_id = $1
|
||||
`, userID).Scan(&stats.TotalAppointments)
|
||||
if err != nil {
|
||||
@@ -214,8 +211,12 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
}
|
||||
|
||||
// Polls remaining (appointments without poll responses)
|
||||
|
||||
stats.PollsRemaining = stats.TotalAppointments - stats.PollsCompleted
|
||||
|
||||
fmt.Print(stats.PollsRemaining)
|
||||
|
||||
|
||||
// Calculate completion percentage
|
||||
if stats.TotalAppointments > 0 {
|
||||
stats.PollCompletionPercent = (stats.PollsCompleted * 100) / stats.TotalAppointments
|
||||
@@ -225,7 +226,7 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
|
||||
// Signs requested
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT
|
||||
SELECT
|
||||
COALESCE(SUM(pr.question3_lawn_signs), 0),
|
||||
COALESCE(SUM(pr.question4_banner_signs), 0)
|
||||
FROM poll p
|
||||
@@ -237,4 +238,4 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) {
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
username, _ := models.GetCurrentUserName(r)
|
||||
|
||||
|
||||
if r.Method == http.MethodGet {
|
||||
addressID := r.URL.Query().Get("address_id")
|
||||
if addressID == "" {
|
||||
@@ -27,7 +27,7 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var userID int
|
||||
fmt.Print(addressID, userID)
|
||||
err := models.DB.QueryRow(`
|
||||
SELECT a.address, ap.user_id
|
||||
SELECT a.address, ap.user_id
|
||||
FROM appointment AS ap
|
||||
JOIN address_database a ON a.address_id = ap.address_id
|
||||
WHERE ap.address_id = $1
|
||||
@@ -41,8 +41,8 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Check if poll already exists for this address
|
||||
var pollID int
|
||||
err = models.DB.QueryRow(`
|
||||
SELECT poll_id
|
||||
FROM poll
|
||||
SELECT poll_id
|
||||
FROM poll
|
||||
WHERE address_id = $1 AND user_id = $2
|
||||
`, addressID, userID).Scan(&pollID)
|
||||
|
||||
@@ -53,7 +53,7 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
VALUES ($1, $2, 'Door-to-Door Poll', 'Campaign polling questions', true)
|
||||
RETURNING poll_id
|
||||
`, userID, addressID).Scan(&pollID)
|
||||
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to create poll: %v", err)
|
||||
http.Error(w, "Failed to create poll", http.StatusInternalServerError)
|
||||
@@ -66,15 +66,15 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
utils.Render(w, "poll_form.html", map[string]interface{}{
|
||||
"Title": "Poll Questions",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": true,
|
||||
"UserName": username,
|
||||
"ActiveSection": "appointments",
|
||||
"PollID": pollID,
|
||||
"AddressID": addressID,
|
||||
"Address": address,
|
||||
"PageIcon": "fas fa-poll",
|
||||
"Title": "Poll Questions",
|
||||
"IsAuthenticated": true,
|
||||
"ShowVolunteerNav": true,
|
||||
"ActiveSection": "schedule",
|
||||
"UserName": username,
|
||||
"PollID": pollID,
|
||||
"AddressID": addressID,
|
||||
"Address": address,
|
||||
"PageIcon": "fas fa-poll",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -123,35 +123,35 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Insert poll response
|
||||
_, err = models.DB.Exec(`
|
||||
INSERT INTO poll_response (
|
||||
poll_id, respondent_postal_code, question1_voted_before,
|
||||
poll_id, respondent_postal_code, question1_voted_before,
|
||||
question2_vote_again, question3_lawn_signs, question4_banner_signs,
|
||||
question5_thoughts, question6_donation_amount
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`, pollID, postalCode, question1VotedBefore, question2VoteAgain,
|
||||
question3LawnSigns, question4BannerSigns, question5Thoughts, question6donation)
|
||||
`, pollID, postalCode, question1VotedBefore, question2VoteAgain,
|
||||
question3LawnSigns, question4BannerSigns, question5Thoughts, question6donation)
|
||||
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
http.Error(w, "Failed to save poll response", http.StatusInternalServerError)
|
||||
return
|
||||
}else{
|
||||
} else {
|
||||
_, err := models.DB.Exec(`
|
||||
UPDATE address_database
|
||||
SET visited_validated = true
|
||||
UPDATE address_database
|
||||
SET visited_validated = true
|
||||
WHERE address_id IN (
|
||||
SELECT address_id
|
||||
FROM poll
|
||||
SELECT address_id
|
||||
FROM poll
|
||||
WHERE poll_id = $1
|
||||
)
|
||||
`, pollID)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
http.Error(w, "Failed to save poll response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/volunteer/Addresses", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,132 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"database/sql"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/patel-mann/poll-system/app/internal/models"
|
||||
"github.com/patel-mann/poll-system/app/internal/utils"
|
||||
)
|
||||
|
||||
func ValidatedFreeTime(parsedDate time.Time, assignTime time.Time, userID int) (bool) {
|
||||
var startTime, endTime time.Time
|
||||
/////////////////////
|
||||
// Core Validation //
|
||||
/////////////////////
|
||||
|
||||
dateOnly := parsedDate.Format("2006-01-02")
|
||||
// ValidateAvailability checks if a user is available at a specific time
|
||||
func ValidateAvailability(checkDate time.Time, checkTime time.Time, userID int) bool {
|
||||
var startTime, endTime time.Time
|
||||
day := checkDate.Format("2006-01-02")
|
||||
|
||||
err := models.DB.QueryRow(
|
||||
`SELECT start_time, end_time
|
||||
FROM availability
|
||||
WHERE user_id = $1 AND day = $2`,
|
||||
userID, dateOnly,
|
||||
).Scan(&startTime, &endTime)
|
||||
err := models.DB.QueryRow(`
|
||||
SELECT start_time, end_time
|
||||
FROM availability
|
||||
WHERE user_id = $1 AND day_of_week = $2`,
|
||||
userID, day).Scan(&startTime, &endTime)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Database query failed: %v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if assignTime.After(startTime) && assignTime.Before(endTime) {
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
log.Printf("DB error in ValidateAvailability: %v", err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
return checkTime.After(startTime) && checkTime.Before(endTime)
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Volunteer CRUD //
|
||||
////////////////////
|
||||
|
||||
// View volunteer availability
|
||||
func VolunteerGetAvailabilityHandler(w http.ResponseWriter, r *http.Request) {
|
||||
userID := models.GetCurrentUserID(w, r)
|
||||
username, _ := models.GetCurrentUserName(r)
|
||||
role, _ := r.Context().Value("user_role").(int)
|
||||
|
||||
rows, err := models.DB.Query(`
|
||||
SELECT availability_id, day_of_week, start_time, end_time, created_at
|
||||
FROM availability
|
||||
WHERE user_id = $1
|
||||
ORDER BY day_of_week DESC`, userID)
|
||||
if err != nil {
|
||||
log.Println("Error fetching availability:", err)
|
||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var availability []models.Availability
|
||||
for rows.Next() {
|
||||
var a models.Availability
|
||||
if err := rows.Scan(&a.AvailabilityID, &a.DayOfWeek, &a.StartTime, &a.EndTime, &a.CreatedAt); err != nil {
|
||||
log.Println("Row scan error:", err)
|
||||
continue
|
||||
}
|
||||
availability = append(availability, a)
|
||||
}
|
||||
|
||||
utils.Render(w, "volunteer_schedule.html", map[string]interface{}{
|
||||
"Title": "My Schedule",
|
||||
"ShowVolunteerNav": true,
|
||||
"IsVolunteer": true,
|
||||
"IsAuthenticated": true,
|
||||
"Availability": availability,
|
||||
"UserName": username,
|
||||
"Role": role,
|
||||
"ActiveSection": "schedule",
|
||||
})
|
||||
}
|
||||
|
||||
// Add or update schedule
|
||||
func VolunteerPostScheduleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Redirect(w, r, "/volunteer/schedule", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
userID := models.GetCurrentUserID(w, r)
|
||||
day := r.FormValue("day")
|
||||
start := r.FormValue("start_time")
|
||||
end := r.FormValue("end_time")
|
||||
|
||||
if day == "" || start == "" || end == "" {
|
||||
http.Error(w, "All fields required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := models.DB.Exec(`
|
||||
INSERT INTO availability (user_id, day_of_week, start_time, end_time, created_at)
|
||||
VALUES ($1, $2, $3, $4, NOW())
|
||||
ON CONFLICT (user_id, day_of_week)
|
||||
DO UPDATE SET start_time = $3, end_time = $4`,
|
||||
userID, day, start, end)
|
||||
if err != nil {
|
||||
log.Println("Insert availability error:", err)
|
||||
http.Error(w, "Could not save schedule", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/volunteer/schedule", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// Delete schedule
|
||||
func VolunteerDeleteScheduleHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
userID := models.GetCurrentUserID(w, r)
|
||||
idStr := r.FormValue("id")
|
||||
|
||||
_, err := models.DB.Exec(`DELETE FROM availability WHERE availability_id = $1 AND user_id = $2`, idStr, userID)
|
||||
if err != nil {
|
||||
log.Println("Delete availability error:", err)
|
||||
http.Error(w, "Could not delete schedule", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/volunteer/schedule", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user