package server import ( "context" "fmt" "io" "net/http" "strconv" "time" "github.com/a-h/templ" "github.com/labstack/echo/v4" "github.com/labstack/gommon/log" u "github.com/rjNemo/underscore" "github.com/rjNemo/rentease/config" "github.com/rjNemo/rentease/constant" "github.com/rjNemo/rentease/internal/booking" "github.com/rjNemo/rentease/internal/view" myTime "github.com/rjNemo/rentease/pkg/time" ) func handleListBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc { return func(c echo.Context) error { bookings := bs.All() bvm := u.Map(bookings, func(b *booking.Line) *view.ListBookingsViewModel { return &view.ListBookingsViewModel{ Id: b.InvoiceNumber(hc), Url: templ.SafeURL(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)), From: b.From.Format(time.DateOnly), To: b.To.Format(time.DateOnly), Platform: b.Platform, Name: b.CustomerName, Total: strconv.FormatFloat(b.Total, 'f', 2, 64), Canceled: b.Canceled, } }) component := view.ListBookings(bvm) return renderTempl(c, http.StatusOK, component) } } func handleNewBookingPage(hc *config.Host) echo.HandlerFunc { return func(c echo.Context) error { return renderTempl(c, http.StatusOK, view.NewBooking(hc.Platforms)) } } func handleCreateBooking(bs *booking.Service) echo.HandlerFunc { return func(c echo.Context) error { type NewBooking struct { From time.Time `json:"from"` To time.Time `json:"to"` Name string `form:"name"` PhoneNumber string `form:"phone_number"` Email string `form:"email"` Platform string `form:"platform"` CustomerNumber int `form:"customer_number"` PlatformFees float64 `form:"platform_fees"` } nb := new(NewBooking) err := c.Bind(nb) if err != nil { log.Warn(err) return err } ts, _ := myTime.ParseFromForm(c.FormValue("from")) nb.From = ts ts, _ = myTime.ParseFromForm(c.FormValue("to")) nb.To = ts b := bs.Create(nb.From, nb.To, nb.Name, nb.PhoneNumber, nb.Email, nb.Platform, nb.CustomerNumber, nb.PlatformFees) return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)) } } func handleBookingPage(bs *booking.Service, hc *config.Host) echo.HandlerFunc { return func(c echo.Context) error { idStr := c.Param("id") id, err := strconv.Atoi(idStr) if err != nil { return err } b := bs.One(id) bvm := &view.BookingViewModel{ Id: b.InvoiceNumber(hc), Name: b.Name, PhoneNumber: b.PhoneNumber, CustomerNumber: strconv.Itoa(b.CustomerNumber), Email: b.Email, From: b.From.Format(time.DateOnly), To: b.To.Format(time.DateOnly), Platform: b.Platform, Canceled: b.Canceled, PlatformFees: strconv.FormatFloat(b.PlatformFees, 'f', 2, 64), Url: templ.EscapeString(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)), PdfUrl: templ.SafeURL(fmt.Sprintf("%s/pdf/%d", constant.RouteBooking, b.Id)), CancelUrl: fmt.Sprintf("%s/%d/cancel", constant.RouteBooking, b.Id), Items: u.Map(b.Items, func(i booking.Item) view.ItemViewModel { return view.ItemViewModel{ Id: strconv.Itoa(i.Id), Item: i.Item, Quantity: strconv.Itoa(i.Quantity), Price: strconv.FormatFloat(i.Price, 'f', 2, 64), SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64), PaymentMethod: i.PaymentMethod, PaymentStatus: i.PaymentStatus, ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id), } }), Total: strconv.FormatFloat(u.Reduce(b.Items, func(i booking.Item, sum float64) float64 { return sum + i.Price*float64(i.Quantity) }, 0.0), 'f', 2, 64), Platforms: hc.Platforms, ItemList: u.Map(hc.Items, func(i config.HostItem) string { return i.Name }), PaymentMethods: hc.PaymentMethods, } component := view.BookingById(bvm) return renderTempl(c, http.StatusOK, component) } } func handleUpdateBooking(bs *booking.Service, hc *config.Host) echo.HandlerFunc { return func(c echo.Context) error { type UpdateBooking struct { From time.Time `json:"from"` To time.Time `json:"to"` Name string `form:"name"` PhoneNumber string `form:"phone_number"` Email string `form:"email"` Platform string `form:"platform"` Id int `param:"id"` CustomerNumber int `form:"customer_number"` PlatformFees float64 `form:"platform_fees"` } nb := new(UpdateBooking) err := c.Bind(nb) if err != nil { log.Warn(err) return err } ts, _ := myTime.ParseFromForm(c.FormValue("from")) nb.From = ts ts, _ = myTime.ParseFromForm(c.FormValue("to")) nb.To = ts b := bs.Update(nb.Id, nb.From, nb.To, nb.Name, nb.PhoneNumber, nb.Email, nb.Platform, nb.CustomerNumber, nb.PlatformFees) form := view.BookingForm(view.BookingViewModel{ Id: b.InvoiceNumber(hc), Name: b.Name, PhoneNumber: b.PhoneNumber, CustomerNumber: strconv.Itoa(b.CustomerNumber), Email: b.Email, From: b.From.Format(time.DateOnly), To: b.To.Format(time.DateOnly), Canceled: b.Canceled, Platform: b.Platform, Platforms: hc.Platforms, PlatformFees: strconv.FormatFloat(b.PlatformFees, 'f', 2, 64), PaymentMethods: hc.PaymentMethods, Url: templ.EscapeString(fmt.Sprintf("%s/%d", constant.RouteBooking, b.Id)), PdfUrl: templ.SafeURL(fmt.Sprintf("%s/pdf/%d", constant.RouteBooking, b.Id)), }) return renderTempl(c, http.StatusOK, form) } } func handleLineItemForm(bs *booking.Service) echo.HandlerFunc { return func(c echo.Context) error { idStr := c.Param("id") id, err := strconv.Atoi(idStr) if err != nil { return err } i := bs.OneItem(id) form := view.LineItemForm(&view.ItemViewModel{ Id: strconv.Itoa(i.Id), Item: i.Item, Quantity: strconv.Itoa(i.Quantity), Price: strconv.FormatFloat(i.Price, 'f', 2, 64), PaymentMethod: i.PaymentMethod, PaymentStatus: i.PaymentStatus, SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64), ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id), }) return renderTempl(c, http.StatusOK, form) } } func handleCreateItem(bs *booking.Service) echo.HandlerFunc { return func(c echo.Context) error { bookingIdStr := c.Param("id") bid, err := strconv.Atoi(bookingIdStr) if err != nil { return err } type NewItem struct { Item string `form:"item"` PaymentMethod string `form:"method"` Quantity int `form:"quantity"` Price float64 `form:"price"` } ni := new(NewItem) if err := c.Bind(ni); err != nil { log.Warn(err) return err } i := bs.CreateItem(bid, ni.Item, ni.Quantity, ni.Price, ni.PaymentMethod) return renderTempl(c, http.StatusCreated, view.LineItem(&view.ItemViewModel{ Id: strconv.Itoa(i.Id), Item: i.Item, Quantity: strconv.Itoa(i.Quantity), Price: strconv.FormatFloat(i.Price, 'f', 2, 64), PaymentMethod: i.PaymentMethod, PaymentStatus: i.PaymentStatus, SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64), ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id), })) } } func handlePayItem(bs *booking.Service) echo.HandlerFunc { return func(c echo.Context) error { itemIdStr := c.Param("id") itemId, err := strconv.Atoi(itemIdStr) if err != nil { return err } i := bs.PayItem(itemId) return renderTempl(c, http.StatusOK, view.LineItem(&view.ItemViewModel{ Id: itemIdStr, Item: i.Item, Quantity: strconv.Itoa(i.Quantity), Price: strconv.FormatFloat(i.Price, 'f', 2, 64), PaymentMethod: i.PaymentMethod, PaymentStatus: i.PaymentStatus, SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64), ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id), })) } } func handleUpdateItem(bs *booking.Service) echo.HandlerFunc { return func(c echo.Context) error { type updateItem struct { Item string `form:"item"` PaymentMethod string `form:"paymentMethod"` PaymentStatus string `form:"paymentStatus"` Id int `param:"id"` Quantity int `form:"quantity"` Price float64 `form:"price"` } ui := new(updateItem) if err := c.Bind(ui); err != nil { log.Warn(err) return err } i := bs.UpdateItem(ui.Id, ui.Item, ui.Quantity, ui.Price, ui.PaymentMethod, ui.PaymentStatus) return renderTempl(c, http.StatusCreated, view.LineItem(&view.ItemViewModel{ Id: strconv.Itoa(ui.Id), Item: i.Item, Quantity: strconv.Itoa(i.Quantity), Price: strconv.FormatFloat(i.Price, 'f', 2, 64), PaymentMethod: i.PaymentMethod, PaymentStatus: i.PaymentStatus, SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64), ItemUrl: fmt.Sprintf("%s/%d", constant.RouteItem, i.Id), })) } } func handleCancelBooking(bs *booking.Service) echo.HandlerFunc { return func(c echo.Context) error { idStr := c.Param("id") id, err := strconv.Atoi(idStr) if err != nil { return err } bs.Cancel(id) return renderTempl(c, http.StatusOK, templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { _, err := io.WriteString(w, " Canceled") return err })) } }