I have to ask number and age ranges of hosts of guests for all campsite types, not only those that have price options for adults, children, etc. because i must compute the tourist tax for adults. These numbers will be used to generate de rows for guests when actually creating the booking, which is not done already. To satisfy the campsite types that do have a price per guest, not only per night, i had to add the prices for each range in the campsite_type_cost relation. If a campsite type does not have price per person, then that should be zero; the website then does not display the price. The minimal price for any campsite type is one adult for one night, thus to compute the price i need at least the campsite type, the dates, and the number of adults, that has a minimum of one. I changed the order of the form to ask for these values first, so i can compute the initial price as soon as possible. To help further, i show the <fieldset>s progressively when visitors select options.
246 lines
13 KiB
Plaintext
246 lines
13 KiB
Plaintext
<!--
|
||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||
SPDX-FileCopyrightText: 2023 Oriol Carbonell <info@oriolcarbonell.cat>
|
||
SPDX-License-Identifier: AGPL-3.0-only
|
||
-->
|
||
{{ define "title" -}}
|
||
{{( pgettext "Booking" "title" )}}
|
||
{{- end }}
|
||
|
||
{{ define "head" -}}
|
||
{{ template "alpineScript" }}
|
||
{{- end }}
|
||
|
||
{{ define "content" -}}
|
||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/booking.publicPage*/ -}}
|
||
<h2>{{( pgettext "Booking" "title" )}}</h2>
|
||
{{ with .Form -}}
|
||
<form id="booking" action="/{{ currentLocale }}/booking" method="post"
|
||
x-data="{campsiteType: '', arrivalDate: '', departureDate: '', hasCampsite() { return this.campsiteType !== '' }, hasDates() { return this.arrivalDate !== '' && this.departureDate !== ''} }"
|
||
x-init="campsiteType = (document.querySelector('[x-model=campsiteType]:checked') || {}).value || ''"
|
||
>
|
||
<fieldset
|
||
data-hx-get="/{{ currentLocale }}/booking/cart"
|
||
data-hx-include="#booking"
|
||
data-hx-trigger="load,change"
|
||
data-hx-target="#booking footer"
|
||
>
|
||
<fieldset class="accommodation">
|
||
<legend>{{( pgettext "Accommodation" "title" )}}</legend>
|
||
{{ range .CampsiteType.Options -}}
|
||
<label><input type="radio" name="{{ $.Form.CampsiteType.Name }}" value="{{ .Value }}"
|
||
x-model="campsiteType"
|
||
{{ if $.Form.CampsiteType.IsSelected .Value }}checked{{ end }}
|
||
> {{ .Label }}</label><br>
|
||
{{- end }}
|
||
{{ template "error-message" .CampsiteType }}
|
||
</fieldset>
|
||
<fieldset class="booking-period"
|
||
x-cloak
|
||
x-show="hasCampsite()"
|
||
x-transition.duration.250ms
|
||
>
|
||
<legend>{{( pgettext "Booking Period" "title" )}}</legend>
|
||
{{ with .ArrivalDate -}}
|
||
<label>
|
||
{{( pgettext "Arrival date" "input" )}}<br>
|
||
<input type="date" required
|
||
min="{{ today }}"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
x-model.fill="arrivalDate"
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .DepartureDate -}}
|
||
<label>
|
||
{{( pgettext "Departure date" "input" )}}<br>
|
||
<input type="date" required
|
||
min="{{ tomorrow }}"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
x-model.fill="departureDate"
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
</fieldset>
|
||
<fieldset class="guests campsite-options"
|
||
x-cloak
|
||
x-show="hasCampsite() && hasDates()"
|
||
x-transition.duration.250ms
|
||
>
|
||
<legend>{{( pgettext "Guests" "title" )}}</legend>
|
||
|
||
{{ with .NumberAdults -}}
|
||
<label>
|
||
{{( pgettext "Adults aged 17 or older" "input" )}}<br>
|
||
<input type="number" required
|
||
name="{{ .Name }}" value="{{ .Val }}" min="1"
|
||
{{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .NumberTeenagers -}}
|
||
<label>
|
||
{{( pgettext "Teenagers from 11 to 16 years old" "input" )}}<br>
|
||
<input type="number" required
|
||
name="{{ .Name }}" value="{{ .Val }}" min="0"
|
||
{{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .NumberChildren -}}
|
||
<label>
|
||
{{( pgettext "Children from 2 to 10 years old" "input" )}}<br>
|
||
<input type="number" required
|
||
name="{{ .Name }}" value="{{ .Val }}" min="0"
|
||
{{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .NumberDogs -}}
|
||
<label>
|
||
{{( pgettext "Dogs" "input" )}}<br>
|
||
<input type="number" required
|
||
name="{{ .Name }}" value="{{ .Val }}" min="0"
|
||
{{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
</fieldset>
|
||
{{ range $campsiteType := .CampsiteType.Options -}}
|
||
{{ $options := index $.Form.CampsiteTypeOptions .Value }}
|
||
{{ $zonePreferences := index $.Form.ZonePreferences .Value }}
|
||
{{ if or $options $zonePreferences }}
|
||
<fieldset class="campsite-options"
|
||
x-cloak
|
||
x-show="campsiteType === '{{ $campsiteType.Value }}' && hasDates()"
|
||
x-transition.duration.250ms>
|
||
<legend>{{ .Label }}</legend>
|
||
{{ with $zonePreferences -}}
|
||
<label>
|
||
<span>
|
||
{{( pgettext "Area preferences (optional)" "input" )}}
|
||
<a href="/{{ currentLocale }}/campground?zones"
|
||
target="_blank">{{( gettext "Campground map" )}}</a>
|
||
</span><br>
|
||
<input type="text"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ range $options -}}
|
||
<label>
|
||
{{ .Label }}<br>
|
||
<input type="number" required
|
||
name="{{ .Input.Name }}" value="{{ .Input.Val }}"
|
||
min="{{ .Min }}" max="{{ .Max }}"
|
||
{{ template "error-attrs" .Input }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" .Input }}
|
||
{{- end }}
|
||
</fieldset>
|
||
{{- end }}
|
||
{{- end }}
|
||
<fieldset class="customer-details"
|
||
x-cloak
|
||
x-show="hasCampsite() && hasDates()"
|
||
x-transition.duration.250ms
|
||
>
|
||
<legend>{{( pgettext "Customer Details" "title" )}}</legend>
|
||
{{ with .FullName -}}
|
||
<label>
|
||
{{( pgettext "Full name" "input" )}}<br>
|
||
<input type="text" required autocomplete="name" minlength="2"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .Address -}}
|
||
<label>
|
||
{{( pgettext "Address (optional)" "input" )}}<br>
|
||
<input type="text" autocomplete="billing street-address"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .PostalCode -}}
|
||
<label>
|
||
{{( pgettext "Postcode (optional)" "input" )}}<br>
|
||
<input type="text" autocomplete="billing postal-code"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .City -}}
|
||
<label>
|
||
{{( pgettext "Town or village (optional)" "input" )}}<br>
|
||
<input type="text"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .Country -}}
|
||
<label>
|
||
{{( pgettext "Country" "input" )}}<br>
|
||
<select name="{{ .Name }}"
|
||
required autocomplete="country">
|
||
<option>{{( gettext "Choose a country" )}}</option>
|
||
{{ template "error-attrs" . }}>{{ template "list-options" . }}
|
||
</select><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .Email -}}
|
||
<label>
|
||
{{( pgettext "Email" "input" )}}<br>
|
||
<input type="email" required autocomplete="email"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .Phone -}}
|
||
<label>
|
||
{{( pgettext "Phone" "input" )}}<br>
|
||
<input type="tel" required autocomplete="tel"
|
||
name="{{ .Name }}" value="{{ .Val }}" {{ template "error-attrs" . }}
|
||
><br>
|
||
</label>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .ACSICard -}}
|
||
<label class="full-row">
|
||
<input type="checkbox" name="{{ .Name }}" {{ if .Checked}}checked{{ end }}
|
||
{{ template "error-attrs" . }}
|
||
> {{( pgettext "ACSI card? (optional)" "input" )}}</label><br>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
{{ with .Agreement -}}
|
||
<label class="full-row">
|
||
<input type="checkbox" required name="{{ .Name }}" {{ if .Checked}}checked{{ end }}
|
||
{{ template "error-attrs" . }}
|
||
> {{ printf ( pgettext "I have read and I accept %[1]sthe reservation conditions%[2]s" "input" ) (printf "<a href=\"/%s/legal/reservation\" rel=\"terms-of-service\" target=\"_blank\">" currentLocale) (print "</a>") | raw }}
|
||
</label><br>
|
||
{{ template "error-message" . }}
|
||
{{- end }}
|
||
</fieldset>
|
||
</fieldset>
|
||
<footer :class="hasCampsite() && hasDates() && 'is-visible'">
|
||
{{ template "cart.gohtml" $.Cart }}
|
||
</footer>
|
||
</form>
|
||
{{- end }}
|
||
<script src="/static/booking-dates.js"></script>
|
||
{{- end }}
|