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.
242 lines
6.3 KiB
Go
242 lines
6.3 KiB
Go
// 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, "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
|
|
|
|
fmt.Print(stats.PollsRemaining)
|
|
|
|
|
|
// 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
|
|
}
|