// Add this to your handlers package (create volunteer_posts.go or add to existing file) package handlers import ( "fmt" "net/http" "strconv" "time" "github.com/patel-mann/poll-system/app/internal/models" "github.com/patel-mann/poll-system/app/internal/utils" ) type VolunteerStatistics struct { 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 } // VolunteerPostsHandler - Dashboard view for volunteers with posts and statistics func VolunteerPostsHandler(w http.ResponseWriter, r *http.Request) { // Only allow GET requests for volunteers if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // Get user info from context role := r.Context().Value("user_role").(int) CurrentUserID := models.GetCurrentUserID(w, r) username, _ := models.GetCurrentUserName(r) // Fetch posts from database rows, err := models.DB.Query(` SELECT p.post_id, p.author_id, u.first_name || ' ' || u.last_name AS author_name, p.content, COALESCE(p.image_url, '') as image_url, p.created_at FROM post p JOIN users u ON p.author_id = u.user_id JOIN admin_volunteers x ON u.user_id = x.admin_id WHERE x.volunteer_id = $1 ORDER BY p.created_at DESC `, CurrentUserID) if err != nil { fmt.Printf("Database query error: %v\n", err) http.Error(w, "Failed to fetch posts", http.StatusInternalServerError) return } defer rows.Close() var posts []models.Post for rows.Next() { var p models.Post err := rows.Scan(&p.PostID, &p.AuthorID, &p.AuthorName, &p.Content, &p.ImageURL, &p.CreatedAt) if err != nil { fmt.Printf("Row scan error: %v\n", err) continue } posts = append(posts, p) } // Add cache busting parameter to image URLs for i := range posts { if posts[i].ImageURL != "" { posts[i].ImageURL += "?t=" + strconv.FormatInt(time.Now().UnixNano(), 10) } } // Fetch teammates teammatesRows, err := models.DB.Query(` SELECT u.user_id, u.first_name || ' ' || u.last_name AS full_name, COALESCE(u.phone, '') AS phone, r.name AS role FROM users u JOIN role r ON u.role_id = r.role_id JOIN team tm ON u.user_id = tm.volunteer_id OR u.user_id = tm.team_lead_id WHERE tm.team_id = ( SELECT team_id FROM team WHERE volunteer_id = $1 or team_lead_id = $2 ) 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) } // Get volunteer statistics stats, err := getVolunteerStatistics(CurrentUserID) if err != nil { fmt.Printf("Failed to fetch statistics: %v\n", err) // Continue with empty stats rather than failing stats = &VolunteerStatistics{} } // Get navigation flags showAdminNav, showVolunteerNav := getNavFlags(role) fmt.Printf("Volunteer viewing %d posts\n", len(posts)) utils.Render(w, "dashboard/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, }) } 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) weekday := now.Weekday() if weekday == time.Sunday { weekday = 7 } // Get start of the week (Monday) weekStart := now.AddDate(0, 0, -int(weekday)+1) // Get end of the week (Sunday) weekEnd := weekStart.AddDate(0, 0, 6) 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 WHERE user_id = $1 AND DATE(appointment_date) = $2 `, userID, today).Scan(&stats.AppointmentsToday) if err != nil { return nil, err } // Appointments tomorrow err = models.DB.QueryRow(` SELECT COUNT(*) FROM appointment WHERE user_id = $1 AND DATE(appointment_date) = $2 `, userID, oneDayLater).Scan(&stats.AppointmentsTomorrow) if err != nil { return nil, err } // Appointments this week err = models.DB.QueryRow(` 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 WHERE user_id = $1 `, userID).Scan(&stats.TotalAppointments) if err != nil { return nil, err } // Polls completed err = models.DB.QueryRow(` SELECT COUNT(DISTINCT pr.poll_response_id) FROM poll p JOIN poll_response pr ON p.poll_id = pr.poll_id WHERE p.user_id = $1 `, userID).Scan(&stats.PollsCompleted) if err != nil { return nil, err } // Polls remaining (appointments without poll responses) stats.PollsRemaining = stats.TotalAppointments - stats.PollsCompleted // Calculate completion percentage if stats.TotalAppointments > 0 { stats.PollCompletionPercent = (stats.PollsCompleted * 100) / stats.TotalAppointments } else { stats.PollCompletionPercent = 0 } // Signs requested err = models.DB.QueryRow(` SELECT COALESCE(SUM(pr.question3_lawn_signs), 0), COALESCE(SUM(pr.question4_banner_signs), 0) FROM poll p JOIN poll_response pr ON p.poll_id = pr.poll_id WHERE p.user_id = $1 `, userID).Scan(&stats.LawnSignsRequested, &stats.BannerSignsRequested) if err != nil { return nil, err } return stats, nil }