From 4d0123def71818569581afb72d166cbf8de5e0d7 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Fri, 22 Dec 2023 03:27:49 +0100 Subject: [PATCH] Bring back the whole list of options in type page, but in accordion This is how the customer wants it. --- pkg/campsite/types/public.go | 54 ++++++++------ web/static/public.css | 87 +++++++++++++++++------ web/templates/admin/layout.gohtml | 2 +- web/templates/public/campsite/type.gohtml | 85 +++++++++++----------- 4 files changed, 140 insertions(+), 88 deletions(-) diff --git a/pkg/campsite/types/public.go b/pkg/campsite/types/public.go index f5c73e6..bd64633 100644 --- a/pkg/campsite/types/public.go +++ b/pkg/campsite/types/public.go @@ -7,6 +7,7 @@ package types import ( "context" + "github.com/jackc/pgx/v4" gotemplate "html/template" "net/http" "time" @@ -78,7 +79,12 @@ type typePrice struct { SeasonColor string MinNights int PricePerNight string - HasOptions bool + Options []*optionPrice +} + +type optionPrice struct { + OptionName string + PricePerNight string } type typeFeature struct { @@ -131,33 +137,29 @@ func collectPrices(ctx context.Context, conn *database.Conn, language language.T select coalesce(i18n.name, season.name) as l10n_name , to_color(season.color)::text , coalesce(cost.min_nights, 1) - , to_price(coalesce(cost.cost_per_night, 0) + coalesce(option.cost_per_night, 0)) - , option.cost_per_night is not null - , season.position + , to_price(coalesce(cost.cost_per_night, 0)) + , array_agg((coalesce(option_i18n.name, option.name), to_price(coalesce(option_cost.cost_per_night, 0))) order by option.position) filter (where option.campsite_type_option_id is not null) from season left join season_i18n as i18n on season.season_id = i18n.season_id and i18n.lang_tag = $1 left join ( campsite_type_cost as cost join campsite_type as type on cost.campsite_type_id = type.campsite_type_id and type.slug = $2 ) as cost on cost.season_id = season.season_id left join ( - select season_id - , sum(lower(range) * cost_per_night)::integer as cost_per_night - from campsite_type_option - join campsite_type using(campsite_type_id) - join campsite_type_option_cost using (campsite_type_option_id) - where slug = $2 - group by season_id - ) as option on option.season_id = season.season_id + select option.* + from campsite_type_option as option + join campsite_type as type on option.campsite_type_id = type.campsite_type_id and type.slug = $2 + ) as option on true + left join campsite_type_option_i18n as option_i18n on option_i18n.campsite_type_option_id = option.campsite_type_option_id and option_i18n.lang_tag = $1 + left join campsite_type_option_cost as option_cost on option_cost.campsite_type_option_id = option.campsite_type_option_id and option_cost.season_id = season.season_id where season.active - union all - select $3 - , to_color($4)::text - , 1 - , '' - , false - , 2147483647 as position - order by position, l10n_name - `, language, slug, locale.PgettextNoop("Closed", "season"), season.UnsetColor) + group by i18n.name + , season.name + , season.color + , cost.min_nights + , cost.cost_per_night + , season.position + order by season.position, l10n_name + `, pgx.QueryResultFormats{pgx.BinaryFormatCode}, language, slug) if err != nil { return nil, err } @@ -165,10 +167,16 @@ func collectPrices(ctx context.Context, conn *database.Conn, language language.T var prices []*typePrice for rows.Next() { price := &typePrice{} - var position int - if err := rows.Scan(&price.SeasonName, &price.SeasonColor, &price.MinNights, &price.PricePerNight, &price.HasOptions, &position); err != nil { + var options database.RecordArray + if err := rows.Scan(&price.SeasonName, &price.SeasonColor, &price.MinNights, &price.PricePerNight, &options); err != nil { return nil, err } + for _, el := range options.Elements { + price.Options = append(price.Options, &optionPrice{ + OptionName: el.Fields[0].Get().(string), + PricePerNight: el.Fields[1].Get().(string), + }) + } prices = append(prices, price) } return prices, nil diff --git a/web/static/public.css b/web/static/public.css index 4d62627..c2a6fc4 100644 --- a/web/static/public.css +++ b/web/static/public.css @@ -467,12 +467,12 @@ nav:last-of-type > ul > li:last-child { padding: 1.5rem 2rem; } -.nature div:first-child a span, .services a span, .surroundings .spiel a:hover span, .campsite_type_booking form button span { +.nature div:first-child a span, .services a span, .surroundings .spiel a:hover span, .campsite_type_booking button span { display: inline-block; transition: transform 0.5s ease; } -.nature div:first-child a:hover span, .services a:hover span, .spiel a:hover span, .campsite_type_booking form button:hover span { +.nature div:first-child a:hover span, .services a:hover span, .spiel a:hover span, .campsite_type_booking button:hover span { transform: translateX(1.3rem); } @@ -785,37 +785,39 @@ dt { } } -.campsite_type_booking form { - flex: .4; +.campsite_type_booking fieldset, .campsite_type_booking footer { + flex: 1; +} + +.campsite_type_booking { background-color: var(--accent); padding: 2rem; } -.campsite_type_booking form fieldset { +.campsite_type_booking fieldset { display: flex; gap: 2.5rem; padding: 0; border: none; } -.campsite_type_booking form label { +.campsite_type_booking label { flex: 1; font-size: 2rem; } -.campsite_type_booking form input { +.campsite_type_booking input { padding: 1.5rem .5rem; width: 100%; background-color: var(--base); } -.campsite_type_booking form footer { +.campsite_type_booking footer { margin-top: 2rem; + text-align: right; } -.campsite_type_booking form button { - width: 100%; - text-align: left; +.campsite_type_booking button { background-color: var(--clar); padding: 1.5rem 2rem; cursor: pointer; @@ -824,24 +826,35 @@ dt { line-height: 0.9em; } -.campsite_type_booking form, -.campsite_type_booking form button, -.campsite_type_booking form input { +.campsite_type_booking, +.campsite_type_booking button, +.campsite_type_booking input { border: none; border-radius: 5px; } +.campsite_type_calendar_prices { + display: flex; + flex-direction: row-reverse; +} + +@media (max-width: 48rem) { + .campsite_type_calendar_prices { + flex-direction: column; + } +} + .campsite_type_prices { - flex: .6; padding: 2.5rem; border-radius: 5px; - border: 3px solid black; + flex: .5; } .campsite_type_prices dl { display: flex; - justify-content: space-between; + flex-direction: column; gap: 1rem; + border-bottom: 1px solid black; } .campsite_type_prices dl div:hover { @@ -850,18 +863,49 @@ dt { .campsite_type_prices div { flex-basis: unset; + min-height: 0; + padding: 0; } .campsite_type_prices dt { display: flex; align-items: center; - gap: .5rem; - border: none; - padding: 0; + gap: 1.5rem; + border-top: 1px solid black; + border-bottom: none; + padding: .5em 0 0; + cursor: pointer; + position: relative; +} + +.campsite_type_prices dt::after { + position: absolute; + right: 0; + top: 50%; + content: '+'; + width: 1em; + aspect-ratio: 1; + display: flex; + justify-content: center; + align-items: center; + background-color: black; + color: white; + border-radius: 50%; + line-height: 0; +} + +.campsite_type_prices dt.open::after { + content: '-'; +} + +.campsite_type_prices dd { + padding: 0 0 0 calc(30px + 1.5rem); } .campsite_type_calendar { - padding: 5rem 0 2.5rem; + padding: 2.5rem 0; + min-width: 0; + flex: 1; } .campsite_type_features li { @@ -936,6 +980,7 @@ dt { .campsite_type_calendar button { display: flex; gap: 1em; + font-size: 2.5rem; border: none; cursor: pointer; } diff --git a/web/templates/admin/layout.gohtml b/web/templates/admin/layout.gohtml index da3e3a2..959a117 100644 --- a/web/templates/admin/layout.gohtml +++ b/web/templates/admin/layout.gohtml @@ -11,7 +11,7 @@ - + {{ block "head" . }}{{ end }} diff --git a/web/templates/public/campsite/type.gohtml b/web/templates/public/campsite/type.gohtml index a5840f3..3466ca3 100644 --- a/web/templates/public/campsite/type.gohtml +++ b/web/templates/public/campsite/type.gohtml @@ -9,6 +9,7 @@ {{ define "head" -}} {{ template "carouselStyle" }} + {{- end }} {{ define "content" -}} @@ -33,48 +34,58 @@ {{- end }} -
-
- -
- - -
-
- -
-
+
+ +
+ + +
+
+ +
+
+ +
+
+ {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/season.Calendar*/ -}} +
+

{{( pgettext "Calendar" "title" )}}

+ + +
+
+ {{ template "calendar.gohtml" .Calendar }} +
+
{{ with .Prices -}}

{{( pgettext "Prices" "title" )}}

{{ range . -}} -
-
- - +
+
+ + {{ .SeasonName }}
- {{ if .HasOptions -}} -
{{ printf (gettext "Starting from %s €/night") .PricePerNight }}
- {{- else if .PricePerNight -}} -
{{ printf (gettext "%s €/night") .PricePerNight }}
+
{{ printf (gettext "%s €/night") .PricePerNight }}
+ {{ range .Options }} +
{{ printf (gettext "%s: %s €/night") .OptionName .PricePerNight }}
{{- end }} {{ if gt .MinNights 1 -}} -
{{ printf (gettext "*Minimum %d nights per stay") .MinNights }}
+
{{ printf (gettext "*Minimum %d nights per stay") .MinNights }}
{{- end }}
{{- end }} @@ -83,18 +94,6 @@ {{- end }}
-
- {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/season.Calendar*/ -}} -
-

{{( pgettext "Calendar" "title" )}}

- - -
-
- {{ template "calendar.gohtml" .Calendar }} -
-
- {{ with .Features -}}

{{( pgettext "Features" "title" )}}