2026-05-16 23:03:50 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"net/http"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"archi_folio/internal/store"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (s *Server) home(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
content, err := s.store.SiteContent(r.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
projects, err := s.store.Projects(r.Context(), true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:55:41 +00:00
|
|
|
s.renderPublic(w, r, "home.html", "home_partial.html", pageData{Title: content.HeroTitle, Active: "home", Content: content, Projects: projects, CurrentPath: r.URL.Path})
|
2026-05-16 23:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) projects(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
content, err := s.store.SiteContent(r.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
projects, err := s.store.Projects(r.Context(), false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:55:41 +00:00
|
|
|
s.renderPublic(w, r, "projects.html", "projects_partial.html", pageData{Title: "Projects", Active: "projects", Content: content, Projects: projects, CurrentPath: r.URL.Path})
|
2026-05-16 23:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) projectDetail(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
content, err := s.store.SiteContent(r.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
project, err := s.store.ProjectBySlug(r.Context(), r.PathValue("slug"))
|
|
|
|
|
if store.IsNotFound(err) {
|
|
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:55:41 +00:00
|
|
|
s.renderPublic(w, r, "project.html", "project_partial.html", pageData{Title: project.Title, Active: "projects", Content: content, Project: project, CurrentPath: r.URL.Path})
|
2026-05-16 23:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) projectImageOverlay(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
id, err := strconv.ParseInt(r.PathValue("imageID"), 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
project, image, err := s.store.ProjectImageForSlug(r.Context(), r.PathValue("slug"), id)
|
|
|
|
|
if store.IsNotFound(err) {
|
|
|
|
|
http.NotFound(w, r)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
s.render(w, "overlay.html", pageData{Title: project.Title, Project: project, Image: image})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) about(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
content, err := s.store.SiteContent(r.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:55:41 +00:00
|
|
|
s.renderPublic(w, r, "about.html", "about_partial.html", pageData{Title: "Studio", Active: "about", Content: content, CurrentPath: r.URL.Path})
|
2026-05-17 12:36:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) services(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
content, err := s.store.SiteContent(r.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
services, err := s.store.Services(r.Context(), true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
faqs, err := s.store.FAQs(r.Context(), true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:55:41 +00:00
|
|
|
s.renderPublic(w, r, "services.html", "services_partial.html", pageData{Title: "Services", Active: "services", Content: content, Services: services, FAQs: faqs, CurrentPath: r.URL.Path})
|
2026-05-17 12:36:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) contactPage(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
content, err := s.store.SiteContent(r.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.error(w, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:55:41 +00:00
|
|
|
s.renderPublic(w, r, "contact.html", "contact_partial.html", pageData{Title: "Contact", Active: "contact", Content: content, CurrentPath: r.URL.Path})
|
2026-05-16 23:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) contact(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
|
|
|
s.render(w, "contact_result.html", pageData{Error: "Please check the form and try again."})
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:36:50 +00:00
|
|
|
request := store.ContactRequest{
|
|
|
|
|
Name: strings.TrimSpace(r.FormValue("name")),
|
|
|
|
|
Email: strings.TrimSpace(r.FormValue("email")),
|
|
|
|
|
Phone: strings.TrimSpace(r.FormValue("phone")),
|
|
|
|
|
ProjectType: strings.TrimSpace(r.FormValue("project_type")),
|
|
|
|
|
ProjectLocation: strings.TrimSpace(r.FormValue("project_location")),
|
|
|
|
|
BudgetRange: strings.TrimSpace(r.FormValue("budget_range")),
|
|
|
|
|
Timeline: strings.TrimSpace(r.FormValue("timeline")),
|
|
|
|
|
Message: strings.TrimSpace(r.FormValue("message")),
|
|
|
|
|
Status: "new",
|
|
|
|
|
}
|
|
|
|
|
if err := validateContactRequest(request); err != nil {
|
|
|
|
|
s.render(w, "contact_result.html", pageData{Error: err.Error()})
|
2026-05-16 23:03:50 +00:00
|
|
|
return
|
|
|
|
|
}
|
2026-05-17 12:36:50 +00:00
|
|
|
if err := s.store.SaveContact(r.Context(), request); err != nil {
|
2026-05-16 23:03:50 +00:00
|
|
|
s.render(w, "contact_result.html", pageData{Error: "The request could not be saved. Please try again."})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
s.render(w, "contact_result.html", pageData{Success: "Thanks. Your request has been saved and the studio will review it soon."})
|
|
|
|
|
}
|