package templates import ( "fmt" "html/template" "io" "os" "path/filepath" "time" ) type TemplateManager struct { templates map[string]*template.Template } func NewTemplateManager(templatesDir string) (*TemplateManager, error) { tm := &TemplateManager{ templates: make(map[string]*template.Template), } // Define template functions funcMap := template.FuncMap{ "formatDate": formatDate, "truncate": truncate, "currency": formatCurrency, } // Load all templates layouts, err := filepath.Glob(filepath.Join(templatesDir, "layouts/*.html")) if err != nil { return nil, err } partials, err := filepath.Glob(filepath.Join(templatesDir, "partials/*.html")) if err != nil { return nil, err } // Load page templates pages := []string{ "customers/index.html", "customers/show.html", "customers/form.html", "customers/table.html", "products/index.html", "products/show.html", "products/form.html", "products/table.html", "purchase-orders/index.html", "purchase-orders/show.html", "purchase-orders/form.html", "purchase-orders/table.html", "enquiries/index.html", "enquiries/show.html", "enquiries/form.html", "enquiries/table.html", "emails/index.html", "emails/show.html", "emails/table.html", "emails/attachments.html", "documents/index.html", "documents/show.html", "documents/table.html", "documents/view.html", "documents/quote-view.html", "documents/invoice-view.html", "documents/purchase-order-view.html", "documents/orderack-view.html", "documents/packinglist-view.html", "index.html", } for _, page := range pages { pagePath := filepath.Join(templatesDir, page) files := append(layouts, partials...) files = append(files, pagePath) // For index pages, also include the corresponding table template if filepath.Base(page) == "index.html" { dir := filepath.Dir(page) tablePath := filepath.Join(templatesDir, dir, "table.html") // Check if table file exists before adding it if _, err := os.Stat(tablePath); err == nil { files = append(files, tablePath) } } // For documents view page, include all document type elements if page == "documents/view.html" { docElements := []string{ "documents/quote-view.html", "documents/invoice-view.html", "documents/purchase-order-view.html", "documents/orderack-view.html", "documents/packinglist-view.html", } for _, elem := range docElements { elemPath := filepath.Join(templatesDir, elem) if _, err := os.Stat(elemPath); err == nil { files = append(files, elemPath) } } } tmpl, err := template.New(filepath.Base(page)).Funcs(funcMap).ParseFiles(files...) if err != nil { return nil, err } tm.templates[page] = tmpl } return tm, nil } func (tm *TemplateManager) Render(w io.Writer, name string, data interface{}) error { tmpl, ok := tm.templates[name] if !ok { return template.New("error").Execute(w, "Template not found") } return tmpl.ExecuteTemplate(w, "base", data) } func (tm *TemplateManager) RenderPartial(w io.Writer, templateFile, templateName string, data interface{}) error { tmpl, ok := tm.templates[templateFile] if !ok { return template.New("error").Execute(w, "Template not found") } return tmpl.ExecuteTemplate(w, templateName, data) } // Template helper functions func formatDate(t interface{}) string { switch v := t.(type) { case time.Time: return v.Format("2006-01-02") case string: if tm, err := time.Parse("2006-01-02 15:04:05", v); err == nil { return tm.Format("2006-01-02") } return v default: return fmt.Sprintf("%v", v) } } func truncate(s string, n int) string { if len(s) <= n { return s } return s[:n] + "..." } func formatCurrency(amount float64) string { return fmt.Sprintf("$%.2f", amount) }