diff --git a/pkg/booking/admin.go b/pkg/booking/admin.go index 1c008d3..5a34d5a 100644 --- a/pkg/booking/admin.go +++ b/pkg/booking/admin.go @@ -243,124 +243,6 @@ func (page bookingIndex) MustRender(w http.ResponseWriter, r *http.Request, user } } -type filterForm struct { - locale *locale.Locale - company *auth.Company - perPage int - pagination bool - HolderName *form.Input - BookingStatus *form.Select - FromDate *form.Input - ToDate *form.Input - Cursor *form.Input -} - -func newFilterForm(ctx context.Context, conn *database.Conn, company *auth.Company, locale *locale.Locale) *filterForm { - return &filterForm{ - locale: locale, - company: company, - perPage: 25, - HolderName: &form.Input{ - Name: "holder_name", - }, - BookingStatus: &form.Select{ - Name: "booking_status", - Options: mustGetBookingStatusOptions(ctx, conn, locale), - }, - FromDate: &form.Input{ - Name: "from_date", - }, - ToDate: &form.Input{ - Name: "to_date", - }, - Cursor: &form.Input{ - Name: "cursor", - }, - } -} - -func mustGetBookingStatusOptions(ctx context.Context, conn *database.Conn, locale *locale.Locale) []*form.Option { - return form.MustGetOptions(ctx, conn, ` - select booking_status.booking_status - , isi18n.name - from booking_status - join booking_status_i18n isi18n using(booking_status) - where isi18n.lang_tag = $1 - and booking_status <> 'created' - order by booking_status`, locale.Language) -} - -func (f *filterForm) Parse(r *http.Request) error { - if err := r.ParseForm(); err != nil { - return err - } - f.HolderName.FillValue(r) - f.BookingStatus.FillValue(r) - f.FromDate.FillValue(r) - f.ToDate.FillValue(r) - f.Cursor.FillValue(r) - f.pagination = f.Cursor.Val != "" - return nil -} - -func (f *filterForm) BuildQuery(args []interface{}) (string, []interface{}) { - var where []string - appendWhere := func(expression string, value interface{}) { - args = append(args, value) - where = append(where, fmt.Sprintf(expression, len(args))) - } - maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) { - if value != "" { - if conv == nil { - appendWhere(expression, value) - } else { - appendWhere(expression, conv(value)) - } - } - } - - appendWhere("booking.company_id = $%d", f.company.ID) - maybeAppendWhere("booking.holder_name ILIKE $%d", f.HolderName.Val, func(v string) interface{} { - return "%" + v + "%" - }) - if len(f.BookingStatus.Selected) == 0 { - where = append(where, "booking.booking_status <> 'created'") - } else { - maybeAppendWhere("booking.booking_status = $%d", f.BookingStatus.String(), nil) - } - maybeAppendWhere("lower(stay) >= $%d", f.FromDate.Val, nil) - maybeAppendWhere("lower(stay) <= $%d", f.ToDate.Val, nil) - - if f.Cursor.Val != "" { - params := strings.Split(f.Cursor.Val, ";") - if len(params) == 2 { - where = append(where, fmt.Sprintf("(lower(stay), booking_id) < ($%d, $%d)", len(args)+1, len(args)+2)) - args = append(args, params[0]) - args = append(args, params[1]) - } - } - - return strings.Join(where, ") AND ("), args -} - -func (f *filterForm) buildCursor(bookings []*bookingEntry) []*bookingEntry { - if len(bookings) <= f.perPage { - f.Cursor.Val = "" - return bookings - } - bookings = bookings[:f.perPage] - last := bookings[f.perPage-1] - f.Cursor.Val = fmt.Sprintf("%s;%d", last.ArrivalDate.Format(database.ISODateFormat), last.ID) - return bookings -} - -func (f *filterForm) HasValue() bool { - return f.HolderName.Val != "" || - (len(f.BookingStatus.Selected) > 0 && f.BookingStatus.Selected[0] != "") || - f.FromDate.Val != "" || - f.ToDate.Val != "" -} - type adminBookingForm struct { *bookingForm ID int diff --git a/pkg/booking/filter.go b/pkg/booking/filter.go new file mode 100644 index 0000000..da657f2 --- /dev/null +++ b/pkg/booking/filter.go @@ -0,0 +1,131 @@ +package booking + +import ( + "context" + "fmt" + "net/http" + "strings" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + "dev.tandem.ws/tandem/camper/pkg/form" + "dev.tandem.ws/tandem/camper/pkg/locale" +) + +type filterForm struct { + locale *locale.Locale + company *auth.Company + perPage int + pagination bool + HolderName *form.Input + BookingStatus *form.Select + FromDate *form.Input + ToDate *form.Input + Cursor *form.Input +} + +func newFilterForm(ctx context.Context, conn *database.Conn, company *auth.Company, locale *locale.Locale) *filterForm { + return &filterForm{ + locale: locale, + company: company, + perPage: 25, + HolderName: &form.Input{ + Name: "holder_name", + }, + BookingStatus: &form.Select{ + Name: "booking_status", + Options: mustGetBookingStatusOptions(ctx, conn, locale), + }, + FromDate: &form.Input{ + Name: "from_date", + }, + ToDate: &form.Input{ + Name: "to_date", + }, + Cursor: &form.Input{ + Name: "cursor", + }, + } +} + +func mustGetBookingStatusOptions(ctx context.Context, conn *database.Conn, locale *locale.Locale) []*form.Option { + return form.MustGetOptions(ctx, conn, ` + select booking_status.booking_status + , isi18n.name + from booking_status + join booking_status_i18n isi18n using(booking_status) + where isi18n.lang_tag = $1 + and booking_status <> 'created' + order by booking_status`, locale.Language) +} + +func (f *filterForm) Parse(r *http.Request) error { + if err := r.ParseForm(); err != nil { + return err + } + f.HolderName.FillValue(r) + f.BookingStatus.FillValue(r) + f.FromDate.FillValue(r) + f.ToDate.FillValue(r) + f.Cursor.FillValue(r) + f.pagination = f.Cursor.Val != "" + return nil +} + +func (f *filterForm) BuildQuery(args []interface{}) (string, []interface{}) { + var where []string + appendWhere := func(expression string, value interface{}) { + args = append(args, value) + where = append(where, fmt.Sprintf(expression, len(args))) + } + maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) { + if value != "" { + if conv == nil { + appendWhere(expression, value) + } else { + appendWhere(expression, conv(value)) + } + } + } + + appendWhere("booking.company_id = $%d", f.company.ID) + maybeAppendWhere("booking.holder_name ILIKE $%d", f.HolderName.Val, func(v string) interface{} { + return "%" + v + "%" + }) + if len(f.BookingStatus.Selected) == 0 { + where = append(where, "booking.booking_status <> 'created'") + } else { + maybeAppendWhere("booking.booking_status = $%d", f.BookingStatus.String(), nil) + } + maybeAppendWhere("lower(stay) >= $%d", f.FromDate.Val, nil) + maybeAppendWhere("lower(stay) <= $%d", f.ToDate.Val, nil) + + if f.Cursor.Val != "" { + params := strings.Split(f.Cursor.Val, ";") + if len(params) == 2 { + where = append(where, fmt.Sprintf("(lower(stay), booking_id) < ($%d, $%d)", len(args)+1, len(args)+2)) + args = append(args, params[0]) + args = append(args, params[1]) + } + } + + return strings.Join(where, ") AND ("), args +} + +func (f *filterForm) buildCursor(bookings []*bookingEntry) []*bookingEntry { + if len(bookings) <= f.perPage { + f.Cursor.Val = "" + return bookings + } + bookings = bookings[:f.perPage] + last := bookings[f.perPage-1] + f.Cursor.Val = fmt.Sprintf("%s;%d", last.ArrivalDate.Format(database.ISODateFormat), last.ID) + return bookings +} + +func (f *filterForm) HasValue() bool { + return f.HolderName.Val != "" || + (len(f.BookingStatus.Selected) > 0 && f.BookingStatus.Selected[0] != "") || + f.FromDate.Val != "" || + f.ToDate.Val != "" +}