feat: added a side bar
This commit is contained in:
@@ -208,7 +208,7 @@ func AddressHandler(w http.ResponseWriter, r *http.Request) {
|
||||
PageNumbers: pageNumbers,
|
||||
}
|
||||
|
||||
utils.Render(w, "address/address.html", map[string]interface{}{
|
||||
utils.Render(w, "address.html", map[string]interface{}{
|
||||
"Title": "Addresses",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": true,
|
||||
|
||||
@@ -67,7 +67,7 @@ func AdminDashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
housesLeftPercent = 0 // Set default value on error
|
||||
}
|
||||
|
||||
utils.Render(w, "dashboard/dashboard.html", map[string]interface{}{
|
||||
utils.Render(w, "dashboard.html", map[string]interface{}{
|
||||
"Title": "Admin Dashboard",
|
||||
"IsAuthenticated": true,
|
||||
"VolunteerCount": volunteerCount,
|
||||
|
||||
@@ -75,7 +75,7 @@ func ReportsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
"ShowAdminNav": role == 1,
|
||||
"ShowVolunteerNav": role != 1,
|
||||
"UserName": username,
|
||||
"ActiveSection": "reports",
|
||||
"ActiveSection": "reports",
|
||||
"Category": category,
|
||||
"ReportID": reportID,
|
||||
"DateFrom": dateFrom,
|
||||
@@ -177,20 +177,23 @@ func getAllReportDefinitions() map[string][]ReportDefinition {
|
||||
return map[string][]ReportDefinition{
|
||||
"users": {
|
||||
{
|
||||
ID: "users_by_role",
|
||||
Name: "Users by Role",
|
||||
ID: "volunteer_participation_rate", // get all the appointment(done, notdone, total) poll(done, not doen, total)
|
||||
Name: "Volunteer participation rate",
|
||||
Description: "Count of users grouped by their role",
|
||||
SQL: `SELECT
|
||||
CASE
|
||||
WHEN role_id = 1 THEN 'Admin'
|
||||
WHEN role_id = 2 THEN 'Volunteer'
|
||||
ELSE 'Unknown'
|
||||
END as role,
|
||||
COUNT(*) as user_count,
|
||||
COUNT(CASE WHEN created_at >= ?1 THEN 1 END) as new_this_period
|
||||
FROM users
|
||||
GROUP BY role_id
|
||||
ORDER BY role_id`,
|
||||
u.user_id,
|
||||
u.first_name,
|
||||
u.last_name,
|
||||
COUNT(p.poll_id) AS total_polls,
|
||||
COUNT(a.user_id) AS total_appointments,
|
||||
case
|
||||
WHEN COUNT(a.user_id) = 0 THEN NULL -- avoid division by zero
|
||||
ELSE ROUND(CAST(COUNT(p.poll_id) AS numeric) / COUNT(a.user_id), 2)
|
||||
END AS poll_to_appointment_rate
|
||||
from users u
|
||||
LEFT JOIN poll p ON u.user_id = p.user_id
|
||||
LEFT JOIN appointment a ON u.user_id = a.user_id
|
||||
GROUP BY u.user_id, u.first_name, u.last_name;`,
|
||||
},
|
||||
{
|
||||
ID: "volunteer_activity",
|
||||
|
||||
@@ -81,7 +81,7 @@ func TeamBuilderHandler(w http.ResponseWriter, r *http.Request) {
|
||||
unassignedVolunteers = append(unassignedVolunteers, vol)
|
||||
}
|
||||
|
||||
utils.Render(w, "volunteer/team_builder.html", map[string]interface{}{
|
||||
utils.Render(w, "team_builder.html", map[string]interface{}{
|
||||
"Title": "Team Builder",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": true,
|
||||
|
||||
@@ -39,7 +39,7 @@ func VolunteerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
user = append(user, b)
|
||||
}
|
||||
|
||||
utils.Render(w, "volunteer/volunteer.html", map[string]interface{}{
|
||||
utils.Render(w, "volunteer.html", map[string]interface{}{
|
||||
"Title": "Assigned Volunteers",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": true,
|
||||
@@ -66,7 +66,7 @@ func EditVolunteerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Render(w, "volunteer/edit_volunteer.html", map[string]interface{}{
|
||||
utils.Render(w, "edit_volunteer.html", map[string]interface{}{
|
||||
"Title": "Edit Volunteer",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": true,
|
||||
|
||||
@@ -30,29 +30,12 @@ func getDefaultRedirectURL(role int) string {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to render error pages with consistent data
|
||||
func renderLoginError(w http.ResponseWriter, errorMsg string) {
|
||||
utils.Render(w, "login.html", map[string]interface{}{
|
||||
"Error": errorMsg,
|
||||
"Title": "Login",
|
||||
"IsAuthenticated": false,
|
||||
})
|
||||
}
|
||||
|
||||
func renderRegisterError(w http.ResponseWriter, errorMsg string) {
|
||||
utils.Render(w, "register.html", map[string]interface{}{
|
||||
"Error": errorMsg,
|
||||
"Title": "Register",
|
||||
"IsAuthenticated": false,
|
||||
})
|
||||
}
|
||||
|
||||
// Helper function to create and sign JWT token
|
||||
func createJWTToken(userID, role int) (string, time.Time, error) {
|
||||
|
||||
err := godotenv.Load() // or specify path: godotenv.Load("/path/to/.env")
|
||||
if err != nil {
|
||||
log.Fatalf("Error loading .env file: %v", err)
|
||||
log.Fatalf("Error loading .env file: %v", err)
|
||||
}
|
||||
|
||||
// Get individual components from environment variables
|
||||
@@ -60,7 +43,6 @@ func createJWTToken(userID, role int) (string, time.Time, error) {
|
||||
|
||||
var jwtKey = []byte(jwtSecret)
|
||||
|
||||
|
||||
expirationTime := time.Now().Add(12 * time.Hour)
|
||||
claims := &models.Claims{
|
||||
UserID: userID,
|
||||
@@ -113,7 +95,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Input validation
|
||||
if email == "" || password == "" {
|
||||
http.Redirect(w, r, "/?error=EmailAndPasswordRequired", http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -130,7 +112,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Login failed for email %s: %v", email, err)
|
||||
http.Redirect(w, r, "/?error=InvalidCredentials", http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,7 +120,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err = bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(password))
|
||||
if err != nil {
|
||||
log.Printf("Password verification failed for user ID %d", userID)
|
||||
http.Redirect(w, r, "/?error=InvalidCredentials", http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -146,7 +128,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tokenString, expirationTime, err := createJWTToken(userID, role)
|
||||
if err != nil {
|
||||
log.Printf("JWT token creation failed for user ID %d: %v", userID, err)
|
||||
http.Redirect(w, r, "/?error=InternalError", http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -159,7 +141,6 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, redirectURL, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
utils.Render(w, "layout.html", map[string]interface{}{
|
||||
@@ -179,7 +160,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Input validation
|
||||
if firstName == "" || lastName == "" || email == "" || password == "" || role == "" {
|
||||
renderRegisterError(w, "All fields are required")
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -187,21 +168,21 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
log.Printf("Password hashing failed: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert role to int
|
||||
roleID, err := strconv.Atoi(role)
|
||||
if err != nil {
|
||||
renderRegisterError(w, "Invalid role")
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
var adminID int
|
||||
if roleID == 3 { // volunteer
|
||||
if adminCode == "" {
|
||||
renderRegisterError(w, "Admin code is required for volunteers")
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -209,11 +190,11 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err = models.DB.QueryRow(`SELECT user_id FROM users WHERE role_id = 1 AND admin_code = $1`, adminCode).Scan(&adminID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
renderRegisterError(w, "Invalid admin code")
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
log.Printf("DB error checking admin code: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -227,7 +208,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
`, firstName, lastName, email, phone, string(hashedPassword), roleID).Scan(&userID)
|
||||
if err != nil {
|
||||
log.Printf("User registration failed: %v", err)
|
||||
renderRegisterError(w, "Could not create account. Email might already be in use.")
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -239,7 +220,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
`, adminID, userID)
|
||||
if err != nil {
|
||||
log.Printf("Failed to link volunteer to admin: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -248,9 +229,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
clearSessionCookie(w)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func ProfileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
volunteernav = true
|
||||
}
|
||||
|
||||
utils.Render(w, "profile/profile.html", map[string]interface{}{
|
||||
utils.Render(w, "profile.html", map[string]interface{}{
|
||||
"Title": "My Profile",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": adminnav,
|
||||
|
||||
@@ -98,7 +98,7 @@ func VolunteerAppointmentHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Render template
|
||||
utils.Render(w, "/appointment.html", map[string]interface{}{
|
||||
utils.Render(w, "appointment.html", map[string]interface{}{
|
||||
"Title": "My Profile",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": adminnav,
|
||||
|
||||
@@ -124,7 +124,7 @@ func VolunteerPostsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fmt.Printf("Volunteer viewing %d posts\n", len(posts))
|
||||
|
||||
utils.Render(w, "dashboard/volunteer_dashboard.html", map[string]interface{}{
|
||||
utils.Render(w, "volunteer_dashboard.html", map[string]interface{}{
|
||||
"Title": "Volunteer Dashboard",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": showAdminNav,
|
||||
|
||||
@@ -65,7 +65,7 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
utils.Render(w, "volunteer/poll_form.html", map[string]interface{}{
|
||||
utils.Render(w, "poll_form.html", map[string]interface{}{
|
||||
"Title": "Poll Questions",
|
||||
"IsAuthenticated": true,
|
||||
"ShowAdminNav": true,
|
||||
@@ -120,7 +120,6 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Insert poll response
|
||||
_, err = models.DB.Exec(`
|
||||
INSERT INTO poll_response (
|
||||
@@ -135,6 +134,22 @@ func PollHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Print(err)
|
||||
http.Error(w, "Failed to save poll response", http.StatusInternalServerError)
|
||||
return
|
||||
}else{
|
||||
_, err := models.DB.Exec(`
|
||||
UPDATE address_database
|
||||
SET visited_validated = true
|
||||
WHERE address_id IN (
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/volunteer/Addresses", http.StatusSeeOther)
|
||||
|
||||
11
app/internal/handlers/volunteer_schedual.go
Normal file
11
app/internal/handlers/volunteer_schedual.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func VolunteerSchedualHandler(w *http.ResponseWriter, r http.Request) {
|
||||
|
||||
fmt.Print("Not Implementated Yet!!!")
|
||||
}
|
||||
Reference in New Issue
Block a user