diff --git a/.gitignore b/.gitignore index 258af4f..9ce101a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/uploads -.env -/tmp -/Example_code +/app/uploads +/app/.env +/app/tmp/ +/app/Example_code diff --git a/Example_code/admin.go b/Example_code/admin.go new file mode 100644 index 0000000..e012e21 --- /dev/null +++ b/Example_code/admin.go @@ -0,0 +1,402 @@ +// 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 +// } diff --git a/Example_code/admin_apointment.go b/Example_code/admin_apointment.go new file mode 100644 index 0000000..33b18f9 --- /dev/null +++ b/Example_code/admin_apointment.go @@ -0,0 +1,83 @@ +package handlers + +import ( + "log" + "net/http" + + "github.com/patel-mann/poll-system/app/internal/models" + "github.com/patel-mann/poll-system/app/internal/utils" +) + +type AssignedAddress struct { + AddressID int + Address string + StreetName string + StreetType string + StreetQuadrant string + HouseNumber string + HouseAlpha *string + Longitude float64 + Latitude float64 + VisitedValidated bool + CreatedAt string + UpdatedAt string + Assigned bool + UserName string + UserEmail string + UserPhone string + AppointmentDate *string + AppointmentTime *string +} + +func AssignedAddressesHandler(w http.ResponseWriter, r *http.Request) { + username,_ := models.GetCurrentUserName(r) + + rows, err := models.DB.Query(` + SELECT + a.address_id, a.address, a.street_name, a.street_type, a.street_quadrant, + a.house_number, a.house_alpha, a.longitude, a.latitude, a.visited_validated, + a.created_at, a.updated_at, + CASE WHEN ap.user_id IS NOT NULL THEN true ELSE false END as assigned, + COALESCE(u.first_name || ' ' || u.last_name, '') as user_name, + COALESCE(u.email, '') as user_email, + COALESCE(u.phone, '') as user_phone, + TO_CHAR(ap.appointment_date, 'YYYY-MM-DD') as appointment_date, + TO_CHAR(ap.appointment_time, 'HH24:MI') as appointment_time + FROM address_database a + LEFT JOIN appointment ap ON a.address_id = ap.address_id + LEFT JOIN users u ON ap.user_id = u.user_id + ORDER BY a.address_id; + `) + if err != nil { + log.Printf("query error: %v", err) + http.Error(w, "query error", http.StatusInternalServerError) + return + } + defer rows.Close() + + var assignedAddresses []AssignedAddress + for rows.Next() { + var addr AssignedAddress + err := rows.Scan( + &addr.AddressID, &addr.Address, &addr.StreetName, &addr.StreetType, &addr.StreetQuadrant, + &addr.HouseNumber, &addr.HouseAlpha, &addr.Longitude, &addr.Latitude, &addr.VisitedValidated, + &addr.CreatedAt, &addr.UpdatedAt, &addr.Assigned, &addr.UserName, &addr.UserEmail, + &addr.UserPhone, &addr.AppointmentDate, &addr.AppointmentTime, + ) + if err != nil { + log.Printf("scan error: %v", err) + continue + } + assignedAddresses = append(assignedAddresses, addr) + } + + utils.Render(w, "address_assigned.html", map[string]interface{}{ + "Title": "Assigned Addresses", + "IsAuthenticated": true, + "AssignedList": assignedAddresses, + "ShowAdminNav": true, + "Role": "admin", + "UserName": username, + "ActiveSection": "assigned", + }) +} diff --git a/app/internal/handlers/volunteer_address.go b/app/internal/handlers/volunteer_address.go index 68362b9..aab1694 100644 --- a/app/internal/handlers/volunteer_address.go +++ b/app/internal/handlers/volunteer_address.go @@ -75,11 +75,11 @@ func VolunteerAppointmentHandler(w http.ResponseWriter, r *http.Request) { // Set button properties based on poll response status a.HasPollResponse = pollResponseExists if pollResponseExists { - a.PollButtonText = "Poll Taken" - a.PollButtonClass = "px-3 py-1 bg-green-600 text-white text-sm rounded cursor-not-allowed" + a.PollButtonText = "Poll" + a.PollButtonClass = "px-1 py-1 bg-green-600 text-white text-sm rounded cursor-not-allowed" } else { - a.PollButtonText = "Ask Poll" - a.PollButtonClass = "px-3 py-1 bg-blue-600 text-white text-sm hover:bg-blue-700 rounded" + a.PollButtonText = "Ask" + a.PollButtonClass = "px-1 py-1 bg-blue-600 text-white text-sm hover:bg-blue-700 rounded" } appointments = append(appointments, a) diff --git a/app/internal/handlers/volunteer_posts.go b/app/internal/handlers/volunteer_posts.go index 17c9233..c1fead1 100644 --- a/app/internal/handlers/volunteer_posts.go +++ b/app/internal/handlers/volunteer_posts.go @@ -150,7 +150,6 @@ func getVolunteerStatistics(userID int) (*VolunteerStatistics, error) { if err != nil { return nil, err } - fmt.Print("Stats: ", stats.AppointmentsThisWeek," Today's date: " , today ,"fasd", weekStart) // Total appointments diff --git a/app/internal/templates/address/address.html b/app/internal/templates/address/address.html index 2bc760a..8a2e855 100644 --- a/app/internal/templates/address/address.html +++ b/app/internal/templates/address/address.html @@ -1,25 +1,5 @@ {{ define "content" }}
- -
-
-
-
- - Address Database -
-
- {{if .Pagination}} -
- Showing {{.Pagination.StartRecord}}-{{.Pagination.EndRecord}} of - {{.Pagination.TotalRecords}} addresses -
- {{end}} -
-
-
diff --git a/app/internal/templates/appointment.html b/app/internal/templates/appointment.html index 3528b70..b9cfe1c 100644 --- a/app/internal/templates/appointment.html +++ b/app/internal/templates/appointment.html @@ -1,19 +1,5 @@ {{ define "content" }}
- -
-
-
-
- - Appointments -
-
-
-
-
@@ -41,16 +27,28 @@ + Poll Address Coordinates Appointment Date Appointment Time - Poll Question {{ range .Appointments }} + + {{ if .HasPollResponse }} + {{ .PollButtonText }} + {{ else }} + + {{ .PollButtonText }} + + {{ end }} + {{ .Address }} {{ .AppointmentTime.Format "15:04" }} - - {{ if .HasPollResponse }} - {{ .PollButtonText }} - {{ else }} - - {{ .PollButtonText }} - - {{ end }} - {{ else }} diff --git a/app/internal/templates/dashboard/dashboard.html b/app/internal/templates/dashboard/dashboard.html index 9de96ed..82756fb 100644 --- a/app/internal/templates/dashboard/dashboard.html +++ b/app/internal/templates/dashboard/dashboard.html @@ -18,40 +18,6 @@
- -
-
-
-
-
- -
- - Dashboard Overview - -
-
- - - -
-
-
-
-
diff --git a/app/internal/templates/dashboard/volunteer_dashboard.html b/app/internal/templates/dashboard/volunteer_dashboard.html index 0cd63c6..ff6cd68 100644 --- a/app/internal/templates/dashboard/volunteer_dashboard.html +++ b/app/internal/templates/dashboard/volunteer_dashboard.html @@ -1,29 +1,18 @@ {{ define "content" }}
- -
-
-
-
- - Volunteer Dashboard -
-
-
-
-
-
+
-
+
{{ if .Posts }}{{range .Posts}} +
-
+
{{slice .AuthorName 0 1}}
@@ -50,7 +39,7 @@ {{if .Content}} -
+

{{.AuthorName}} {{.Content}}

@@ -58,7 +47,7 @@ {{end}}
{{else}} -
+

No posts yet

+

+ Be the first to share something with the community! +

{{ end }} {{ else }} @@ -94,7 +86,163 @@
-
+
+ +
+
+

+ Today's Overview +

+
+
+
+
+ +
+ Appointments Today +
+ + {{ .Statistics.AppointmentsToday }} + +
+ +
+
+
+ +
+ Appointments Tomorrow +
+ + {{ .Statistics.AppointmentsTomorrow }} + +
+ +
+
+
+ +
+ This Week +
+ + {{ .Statistics.AppointmentsThisWeek }} + +
+
+
+
+ + +
+
+

+ Polling Progress +

+
+
+
+
+ +
+ Polls Completed +
+ + {{ .Statistics.PollsCompleted }} + +
+ +
+
+
+ +
+ Polls Remaining +
+ + {{ .Statistics.PollsRemaining }} + +
+ + + {{ if gt .Statistics.TotalAppointments 0 }} +
+
+ Progress + {{ .Statistics.PollsCompleted }}/{{ + .Statistics.TotalAppointments }} +
+
+
+
+
+ {{ end }} +
+
+
+ + +
+
+

+ Signs Requested +

+
+
+
+
+ +
+ Lawn Signs +
+ + {{ .Statistics.LawnSignsRequested }} + +
+ +
+
+
+ +
+ Banner Signs +
+ + {{ .Statistics.BannerSignsRequested }} + +
+
+
+
+
+ + +
diff --git a/app/internal/templates/layout.html b/app/internal/templates/layout.html index 326f58d..27b3129 100644 --- a/app/internal/templates/layout.html +++ b/app/internal/templates/layout.html @@ -14,172 +14,185 @@ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" /> - + {{ if .IsAuthenticated }} -
- -
-
-
- L -
- Poll System -
-
- - {{.UserName}} -
- {{slice .UserName 0 1}} -
- - - -
-
- - - -
- -
-
- - -
- - -
-
-
- L +
+ + + - -
-
- {{ template "content" . }} -
+ +
+ +
+ {{ template "content" . }}
-
+
+ {{else}} - + @@ -193,63 +206,63 @@
- - -
+

Simple Polling @@ -272,7 +285,7 @@

-
+

Our Products

@@ -317,7 +330,7 @@
-
+
@@ -380,13 +393,7 @@
@@ -426,11 +433,6 @@
diff --git a/app/internal/templates/posts.html b/app/internal/templates/posts.html index 927f14a..9721745 100644 --- a/app/internal/templates/posts.html +++ b/app/internal/templates/posts.html @@ -1,19 +1,6 @@ {{ define "content" }}
- -
-
-
-
- - Volunteer Management -
-
-
-
diff --git a/app/internal/templates/profile/profile.html b/app/internal/templates/profile/profile.html index 9ecd7eb..67d5f00 100644 --- a/app/internal/templates/profile/profile.html +++ b/app/internal/templates/profile/profile.html @@ -1,18 +1,5 @@ {{ define "content" }}
- -
-
-
-
- - Volunteer Management -
-
-
-
diff --git a/app/internal/templates/schedual/schedual.html b/app/internal/templates/schedual/schedual.html index 55cbe27..8c1e1d9 100644 --- a/app/internal/templates/schedual/schedual.html +++ b/app/internal/templates/schedual/schedual.html @@ -17,30 +17,6 @@
- -
-
-
- - - Schedual Overview - -
-
- - -
-
-
-
diff --git a/app/internal/templates/volunteer/edit_volunteer.html b/app/internal/templates/volunteer/edit_volunteer.html index bcf4593..c700d99 100644 --- a/app/internal/templates/volunteer/edit_volunteer.html +++ b/app/internal/templates/volunteer/edit_volunteer.html @@ -2,20 +2,6 @@
- -
-
-
-
- - Volunteer Management -
-
-
-
-
diff --git a/app/internal/templates/volunteer/poll_form.html b/app/internal/templates/volunteer/poll_form.html index ad6a9fb..c7c9279 100644 --- a/app/internal/templates/volunteer/poll_form.html +++ b/app/internal/templates/volunteer/poll_form.html @@ -1,27 +1,5 @@ {{ define "content" }}
- -
-
-
-
- - Poll Questions -
-
- -
-
-
@@ -150,7 +128,7 @@
Cancel diff --git a/app/internal/templates/volunteer/team_builder.html b/app/internal/templates/volunteer/team_builder.html index d4891f3..124c246 100644 --- a/app/internal/templates/volunteer/team_builder.html +++ b/app/internal/templates/volunteer/team_builder.html @@ -1,17 +1,5 @@ {{ define "content" }}
- -
-
-
- - Volunteer Management -
-
-
-
{{range .TeamLeads}} {{ $teamLeadID := .ID }} diff --git a/app/internal/templates/volunteer/volunteer.html b/app/internal/templates/volunteer/volunteer.html index 52af05d..0e539fa 100644 --- a/app/internal/templates/volunteer/volunteer.html +++ b/app/internal/templates/volunteer/volunteer.html @@ -1,20 +1,6 @@ {{ define "content" }}
- -
-
-
-
- - Volunteer Management -
-
-
-
-
diff --git a/app/tmp/main b/app/tmp/main index 1fc45f3..e7a8bcc 100755 Binary files a/app/tmp/main and b/app/tmp/main differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..a3cf7e0 --- /dev/null +++ b/index.html @@ -0,0 +1,365 @@ + + + + + + Moraine lake sunset - Google Search + + + + + +
+ +
+ + + + + + + + + + + + + + + +
+ + +
+
+ +
+

+ Google +

+
+ + +
+
+ + +
+
+
+
+ + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+ aurelien.salomon@gmail.com + + + +
+
+ + +
+
+
+ +
+ About 7,920,200 Results  0.18 seconds +
+
+
+
+ + +
+ +
+ +
+
+ wikipedia.com/morainelake +
+

+ Moraine lake - Wikipedia +

+

+ Moraine Lake is a glacially-fed lake in Banff National Park, 14 + kilometres outside the Village of Lake Louise, Alberta, Canada. It + is situated in the Valley of the Ten Peaks, at an elevation of + approximately 6,183 feet. The lake has a surface area of 5 square + kilometres. The lake, being glacially fed, does not reach its crest + until mid to ... +

+
+ + +
+
rockies.com
+

+ Best places to photograph rockies +

+

+ The light is usually best around sunrise and sunset, but interesting + photographs. Moraine Lake is about a 20 minute drive from Lake + Louise which is something ... +

+
+ + +
+

+ Images for Moraine lake sunset +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
estravel.com
+

+ Best point for sunset in Alberta +

+

+ Moraine Lake is only half the size of its nearby neighbour Lake + Louise, but perhaps even more scenic. It's a glacier-fed lake + situated in the beautiful valley of the ten ... +

+
+ + +
+
sunset.com
+

+ Sunset in the canada rocks +

+

+ Moraine Lake is only half the size of its nearby neighbour Lake + Louise, but perhaps even more scenic. It's a glacier-fed lake + situated in the beautiful valley of the ten ... +

+
+
+ + +
+
+
+

Moraine lake

+

Sunshine

+
+ + +
+
+ +
+ + +
+ 6:35 PM
+ Sunset +
+ + +
+ 6:00 AM + 1:00 PM + 8:00 PM +
+
+
+ + +
+
TODAY
+
THURSDAY
+
FRIDAY
+
SATURDAY
+
+
+
+
+ +