Add the list of features for campsite type
This commit is contained in:
parent
d784291a04
commit
2e10966ad7
|
@ -130,6 +130,93 @@ values (72, 'en', 'Plots', '<h3>Camp in the middle of nature</h3><p>Located on t
|
|||
, (76, 'es', 'Cabañas de madera', '<h3>Alojamientos de lujo</h3><p>Ubicadas al lado montaña del camping y con vista a la naturaleza que nos rodea.</p><p>Dos cabañas de madera maciza de dos plantas y con porche cubierto para disfutrar entre árboles.</p>', '<h4>Proche/terraza (13 m²)</h4><ul><li>Moblado</li></ul><h4>Planta baja (32 m²)</h4><ul><li>Sala comedor</li><li>Cocina equipada</li><li>Una habitación cama doble (150 × 200)</li><li>Baño completo</li></ul><h4>Planta altillo (16 m²)</h4><ul><li>Tres camas individuales (90 × 200)</li></ul>', '<h4>El precio incluye</h4><ul><li>Sábanas y nórdico</li><li>Cesto de bienvenida: aceite de oliva, sal, azúcar, café y té</li><li>WiFi</li><li>Plaza de aparcamiento para un coche</li><li>Kit bebé (cuna, trona y bañera) <em>bajo reserva</em></li></ul><p>* Toallas: precio extra</p>', '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>')
|
||||
;
|
||||
|
||||
alter table campsite_type_feature alter column campsite_type_feature_id restart with 82;
|
||||
insert into campsite_type_feature (campsite_type_id, icon_name, name)
|
||||
values (72, 'person', 'Máx. 5 pers.')
|
||||
, (72, 'area', 'Cabana 48 m² Porxo 13 m²')
|
||||
, (72, 'wifi', 'WiFi')
|
||||
, (72, 'hvac', 'Climatització')
|
||||
, (72, 'ecofriendly', 'Eco-sostenible')
|
||||
, (72, 'nopet', 'Gossos NO')
|
||||
, (73, 'person', 'Máx. 5 pers.')
|
||||
, (73, 'area', 'Cabana 48 m² Porxo 13 m²')
|
||||
, (73, 'wifi', 'WiFi')
|
||||
, (73, 'hvac', 'Climatització')
|
||||
, (73, 'ecofriendly', 'Eco-sostenible')
|
||||
, (73, 'nopet', 'Gossos NO')
|
||||
, (74, 'person', 'Máx. 5 pers.')
|
||||
, (74, 'area', 'Cabana 48 m² Porxo 13 m²')
|
||||
, (74, 'wifi', 'WiFi')
|
||||
, (74, 'hvac', 'Climatització')
|
||||
, (74, 'ecofriendly', 'Eco-sostenible')
|
||||
, (74, 'nopet', 'Gossos NO')
|
||||
, (75, 'person', 'Máx. 5 pers.')
|
||||
, (75, 'area', 'Cabana 48 m² Porxo 13 m²')
|
||||
, (75, 'wifi', 'WiFi')
|
||||
, (75, 'hvac', 'Climatització')
|
||||
, (75, 'ecofriendly', 'Eco-sostenible')
|
||||
, (75, 'nopet', 'Gossos NO')
|
||||
, (76, 'person', 'Máx. 5 pers.')
|
||||
, (76, 'area', 'Cabana 48 m² Porxo 13 m²')
|
||||
, (76, 'wifi', 'WiFi')
|
||||
, (76, 'hvac', 'Climatització')
|
||||
, (76, 'ecofriendly', 'Eco-sostenible')
|
||||
, (76, 'nopet', 'Gossos NO')
|
||||
;
|
||||
|
||||
insert into campsite_type_feature_i18n (campsite_type_feature_id, lang_tag, name)
|
||||
values (82, 'en', 'Max. 5 pax')
|
||||
, (82, 'es', 'Máx. 5 pers.')
|
||||
, (83, 'en', 'Cabin 48 m² Porch 13 m²')
|
||||
, (83, 'es', 'Cabaña 48 m² Porche 13 m²')
|
||||
, (85, 'en', 'Climate Control')
|
||||
, (85, 'es', 'Climatización')
|
||||
, (86, 'en', 'Eco-sustainable')
|
||||
, (86, 'es', 'Eco-sostenible')
|
||||
, (87, 'en', 'Dogs NOT allowed')
|
||||
, (87, 'es', 'Perros NO')
|
||||
, (88, 'en', 'Max. 5 pax')
|
||||
, (88, 'es', 'Máx. 5 pers.')
|
||||
, (89, 'en', 'Cabin 48 m² Porch 13 m²')
|
||||
, (89, 'es', 'Cabaña 48 m² Porche 13 m²')
|
||||
, (91, 'en', 'Climate Control')
|
||||
, (91, 'es', 'Climatización')
|
||||
, (92, 'en', 'Eco-sustainable')
|
||||
, (92, 'es', 'Eco-sostenible')
|
||||
, (93, 'en', 'Dogs NOT allowed')
|
||||
, (93, 'es', 'Perros NO')
|
||||
, (94, 'en', 'Max. 5 pax')
|
||||
, (94, 'es', 'Máx. 5 pers.')
|
||||
, (95, 'en', 'Cabin 48 m² Porch 13 m²')
|
||||
, (95, 'es', 'Cabaña 48 m² Porche 13 m²')
|
||||
, (97, 'en', 'Climate Control')
|
||||
, (97, 'es', 'Climatización')
|
||||
, (98, 'en', 'Eco-sustainable')
|
||||
, (98, 'es', 'Eco-sostenible')
|
||||
, (99, 'en', 'Dogs NOT allowed')
|
||||
, (99, 'es', 'Perros NO')
|
||||
, (100, 'en', 'Max. 5 pax')
|
||||
, (100, 'es', 'Máx. 5 pers.')
|
||||
, (101, 'en', 'Cabin 48 m² Porch 13 m²')
|
||||
, (101, 'es', 'Cabaña 48 m² Porche 13 m²')
|
||||
, (103, 'en', 'Climate Control')
|
||||
, (103, 'es', 'Climatización')
|
||||
, (104, 'en', 'Eco-sustainable')
|
||||
, (104, 'es', 'Eco-sostenible')
|
||||
, (105, 'en', 'Dogs NOT allowed')
|
||||
, (105, 'es', 'Perros NO')
|
||||
, (106, 'en', 'Max. 5 pax')
|
||||
, (106, 'es', 'Máx. 5 pers.')
|
||||
, (107, 'en', 'Cabin 48 m² Porch 13 m²')
|
||||
, (107, 'es', 'Cabaña 48 m² Porche 13 m²')
|
||||
, (109, 'en', 'Climate Control')
|
||||
, (109, 'es', 'Climatización')
|
||||
, (110, 'en', 'Eco-sustainable')
|
||||
, (110, 'es', 'Eco-sostenible')
|
||||
, (111, 'en', 'Dogs NOT allowed')
|
||||
, (111, 'es', 'Perros NO')
|
||||
;
|
||||
|
||||
alter table campsite alter column campsite_id restart with 82;
|
||||
select add_campsite(72, '2');
|
||||
select add_campsite(72, '3');
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
-- Deploy camper:add_campsite_type_feature to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: campsite_type_feature
|
||||
-- requires: campsite_type
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create or replace function add_campsite_type_feature(type_slug uuid, icon_name text, name text) returns integer as
|
||||
$$
|
||||
insert into campsite_type_feature (campsite_type_id, icon_name, name)
|
||||
select campsite_type_id, add_campsite_type_feature.icon_name, add_campsite_type_feature.name
|
||||
from campsite_type
|
||||
where slug = type_slug
|
||||
returning campsite_type_feature_id
|
||||
;
|
||||
$$
|
||||
language sql
|
||||
;
|
||||
|
||||
revoke execute on function add_campsite_type_feature(uuid, text, text) from public;
|
||||
grant execute on function add_campsite_type_feature(uuid, text, text) to admin;
|
||||
|
||||
commit;
|
|
@ -5,15 +5,20 @@
|
|||
begin;
|
||||
|
||||
insert into camper.icon (icon_name)
|
||||
values ('baby')
|
||||
values ('area')
|
||||
, ('baby')
|
||||
, ('ball')
|
||||
, ('bicycle')
|
||||
, ('campfire')
|
||||
, ('castle')
|
||||
, ('ecofriendly')
|
||||
, ('fridge')
|
||||
, ('hvac')
|
||||
, ('information')
|
||||
, ('kayak')
|
||||
, ('nopet')
|
||||
, ('outing')
|
||||
, ('person')
|
||||
, ('pool')
|
||||
, ('puzzle')
|
||||
, ('restaurant')
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
-- Deploy camper:campsite_type_feature to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: campsite_type
|
||||
-- requires: icon
|
||||
-- requires: user_profile
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create table campsite_type_feature (
|
||||
campsite_type_feature_id integer generated by default as identity primary key,
|
||||
campsite_type_id integer not null references campsite_type,
|
||||
icon_name text not null references icon,
|
||||
name text not null constraint name_not_empty check(length(trim(name)) > 0)
|
||||
);
|
||||
|
||||
grant select on campsite_type_feature to guest;
|
||||
grant select on campsite_type_feature to employee;
|
||||
grant select, insert, update, delete on campsite_type_feature to admin;
|
||||
|
||||
alter table campsite_type_feature enable row level security;
|
||||
|
||||
create policy guest_ok
|
||||
on campsite_type_feature
|
||||
for select
|
||||
using (true)
|
||||
;
|
||||
|
||||
create policy insert_to_company
|
||||
on campsite_type_feature
|
||||
for insert
|
||||
with check (
|
||||
exists (select 1 from campsite_type join user_profile using (company_id) where campsite_type.campsite_type_id = campsite_type_feature.campsite_type_id)
|
||||
)
|
||||
;
|
||||
|
||||
create policy update_company
|
||||
on campsite_type_feature
|
||||
for update
|
||||
using (
|
||||
exists (select 1 from campsite_type join user_profile using (company_id) where campsite_type.campsite_type_id = campsite_type_feature.campsite_type_id)
|
||||
)
|
||||
;
|
||||
|
||||
create policy delete_from_company
|
||||
on campsite_type_feature
|
||||
for delete
|
||||
using (
|
||||
exists (select 1 from campsite_type join user_profile using (company_id) where campsite_type.campsite_type_id = campsite_type_feature.campsite_type_id)
|
||||
)
|
||||
;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,22 @@
|
|||
-- Deploy camper:campsite_type_feature_i18n to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: campsite_type_feature
|
||||
-- requires: language
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create table campsite_type_feature_i18n (
|
||||
campsite_type_feature_id integer not null references campsite_type_feature,
|
||||
lang_tag text not null references language,
|
||||
name text not null,
|
||||
primary key (campsite_type_feature_id, lang_tag)
|
||||
);
|
||||
|
||||
grant select on table campsite_type_feature_i18n to guest;
|
||||
grant select on table campsite_type_feature_i18n to employee;
|
||||
grant select, insert, update, delete on table campsite_type_feature_i18n to admin;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,25 @@
|
|||
-- Deploy camper:edit_campsite_type_feature to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: campsite_type_feature
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create or replace function edit_campsite_type_feature(feature_id integer, icon_name text, name text) returns integer as
|
||||
$$
|
||||
update campsite_type_feature
|
||||
set icon_name = edit_campsite_type_feature.icon_name
|
||||
, name = edit_campsite_type_feature.name
|
||||
where campsite_type_feature_id = feature_id
|
||||
returning campsite_type_feature_id
|
||||
;
|
||||
$$
|
||||
language sql
|
||||
;
|
||||
|
||||
revoke execute on function edit_campsite_type_feature(integer, text, text) from public;
|
||||
grant execute on function edit_campsite_type_feature(integer, text, text) to admin;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,24 @@
|
|||
-- Deploy camper:translate_campsite_type_feature to pg
|
||||
-- requires: roles
|
||||
-- requires: schema_camper
|
||||
-- requires: campsite_type_feature_i18n
|
||||
|
||||
begin;
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
create or replace function translate_campsite_type_feature(feature_id integer, lang_tag text, name text) returns void as
|
||||
$$
|
||||
insert into campsite_type_feature_i18n (campsite_type_feature_id, lang_tag, name)
|
||||
values (feature_id, lang_tag, name)
|
||||
on conflict (campsite_type_feature_id, lang_tag) do update
|
||||
set name = excluded.name
|
||||
;
|
||||
$$
|
||||
language sql
|
||||
;
|
||||
|
||||
revoke execute on function translate_campsite_type_feature(integer, text, text) from public;
|
||||
grant execute on function translate_campsite_type_feature(integer, text, text) to admin;
|
||||
|
||||
commit;
|
|
@ -91,6 +91,8 @@ func (h *AdminHandler) typeHandler(user *auth.User, company *auth.Company, conn
|
|||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
|
||||
}
|
||||
case "features":
|
||||
h.featuresHandler(user, company, conn, f.Slug).ServeHTTP(w, r)
|
||||
case "options":
|
||||
h.optionsHandler(user, company, conn, f.Slug).ServeHTTP(w, r)
|
||||
case "slides":
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
|
||||
"dev.tandem.ws/tandem/camper/pkg/auth"
|
||||
"dev.tandem.ws/tandem/camper/pkg/database"
|
||||
"dev.tandem.ws/tandem/camper/pkg/form"
|
||||
httplib "dev.tandem.ws/tandem/camper/pkg/http"
|
||||
"dev.tandem.ws/tandem/camper/pkg/locale"
|
||||
"dev.tandem.ws/tandem/camper/pkg/template"
|
||||
)
|
||||
|
||||
func (h *AdminHandler) featuresHandler(user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var head string
|
||||
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||
|
||||
switch head {
|
||||
case "":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
serveFeatureIndex(w, r, user, company, conn, typeSlug)
|
||||
case http.MethodPost:
|
||||
addFeature(w, r, user, company, conn, typeSlug)
|
||||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost)
|
||||
}
|
||||
case "new":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
f := newFeatureForm(r.Context(), conn, typeSlug)
|
||||
f.MustRender(w, r, user, company)
|
||||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet)
|
||||
}
|
||||
default:
|
||||
id, err := strconv.Atoi(head)
|
||||
if err != nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
f := newFeatureForm(r.Context(), conn, typeSlug)
|
||||
if err := f.FillFromDatabase(r.Context(), conn, id); err != nil {
|
||||
if database.ErrorIsNotFound(err) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
h.featureHandler(user, company, conn, f).ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (h *AdminHandler) featureHandler(user *auth.User, company *auth.Company, conn *database.Conn, f *featureForm) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var head string
|
||||
head, r.URL.Path = httplib.ShiftPath(r.URL.Path)
|
||||
|
||||
switch head {
|
||||
case "":
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
f.MustRender(w, r, user, company)
|
||||
case http.MethodPut:
|
||||
editFeature(w, r, user, company, conn, f)
|
||||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
|
||||
}
|
||||
default:
|
||||
loc, ok := h.locales.Get(head)
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
l10n := newFeatureL10nForm(f, loc)
|
||||
if err := l10n.FillFromDatabase(r.Context(), conn); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
l10n.MustRender(w, r, user, company)
|
||||
case http.MethodPut:
|
||||
editFeatureL10n(w, r, user, company, conn, l10n)
|
||||
default:
|
||||
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func serveFeatureIndex(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) {
|
||||
features, err := collectFeatureEntries(r.Context(), conn, typeSlug)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
page := &featureIndex{
|
||||
TypeSlug: typeSlug,
|
||||
Features: features,
|
||||
}
|
||||
page.MustRender(w, r, user, company)
|
||||
}
|
||||
|
||||
func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug string) ([]*featureEntry, error) {
|
||||
rows, err := conn.Query(ctx, `
|
||||
select '/admin/campsites/types/' || campsite_type.slug || '/features/' || campsite_type_feature_id
|
||||
, feature.icon_name
|
||||
, feature.name
|
||||
, array_agg((lang_tag, endonym, not exists (select 1 from campsite_type_feature_i18n as i18n where i18n.campsite_type_feature_id = feature.campsite_type_feature_id and i18n.lang_tag = language.lang_tag)) order by endonym)
|
||||
from campsite_type_feature as feature
|
||||
join campsite_type using (campsite_type_id)
|
||||
join company using (company_id)
|
||||
, language
|
||||
where lang_tag <> default_lang_tag
|
||||
and language.selectable
|
||||
and campsite_type.slug = $1
|
||||
group by campsite_type_feature_id
|
||||
, campsite_type.slug
|
||||
, feature.name
|
||||
order by name
|
||||
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, typeSlug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var features []*featureEntry
|
||||
for rows.Next() {
|
||||
feature := &featureEntry{}
|
||||
var translations database.RecordArray
|
||||
if err = rows.Scan(&feature.URL, &feature.Icon, &feature.Name, &translations); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, el := range translations.Elements {
|
||||
feature.Translations = append(feature.Translations, &locale.Translation{
|
||||
URL: feature.URL + "/" + el.Fields[0].Get().(string),
|
||||
Endonym: el.Fields[1].Get().(string),
|
||||
Missing: el.Fields[2].Get().(bool),
|
||||
})
|
||||
}
|
||||
features = append(features, feature)
|
||||
}
|
||||
|
||||
return features, nil
|
||||
}
|
||||
|
||||
type featureEntry struct {
|
||||
URL string
|
||||
Icon string
|
||||
Name string
|
||||
Translations []*locale.Translation
|
||||
}
|
||||
|
||||
type featureIndex struct {
|
||||
TypeSlug string
|
||||
Features []*featureEntry
|
||||
}
|
||||
|
||||
func (page *featureIndex) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
|
||||
template.MustRenderAdmin(w, r, user, company, "campsite/feature/index.gohtml", page)
|
||||
}
|
||||
|
||||
func addFeature(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) {
|
||||
f := newFeatureForm(r.Context(), conn, typeSlug)
|
||||
processFeatureForm(w, r, user, company, f, func(ctx context.Context) (int, error) {
|
||||
return conn.AddCampsiteTypeFeature(ctx, typeSlug, f.Icon.String(), f.Name.Val)
|
||||
})
|
||||
}
|
||||
|
||||
func editFeature(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *featureForm) {
|
||||
processFeatureForm(w, r, user, company, f, func(ctx context.Context) (int, error) {
|
||||
return conn.EditCampsiteTypeFeature(ctx, f.ID, f.Icon.String(), f.Name.Val)
|
||||
})
|
||||
}
|
||||
|
||||
func processFeatureForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, f *featureForm, act func(ctx context.Context) (int, error)) {
|
||||
if ok, err := form.Handle(f, w, r, user); err != nil {
|
||||
return
|
||||
} else if !ok {
|
||||
f.MustRender(w, r, user, company)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := act(r.Context()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
httplib.Redirect(w, r, "/admin/campsites/types/"+f.TypeSlug+"/features", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
type featureForm struct {
|
||||
ID int
|
||||
TypeSlug string
|
||||
Icon *form.Select
|
||||
Name *form.Input
|
||||
}
|
||||
|
||||
func newFeatureForm(ctx context.Context, conn *database.Conn, typeSlug string) *featureForm {
|
||||
return &featureForm{
|
||||
TypeSlug: typeSlug,
|
||||
Icon: &form.Select{
|
||||
Name: "icon",
|
||||
Options: form.MustGetOptions(ctx, conn, "select icon_name, icon_name from icon order by 1"),
|
||||
},
|
||||
Name: &form.Input{
|
||||
Name: "name",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *featureForm) FillFromDatabase(ctx context.Context, conn *database.Conn, id int) error {
|
||||
f.ID = id
|
||||
row := conn.QueryRow(ctx, `
|
||||
select array[icon_name]
|
||||
, name
|
||||
from campsite_type_feature
|
||||
where campsite_type_feature_id = $1
|
||||
`, id)
|
||||
return row.Scan(&f.Icon.Selected, &f.Name.Val)
|
||||
}
|
||||
|
||||
func (f *featureForm) Parse(r *http.Request) error {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
f.Icon.FillValue(r)
|
||||
f.Name.FillValue(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *featureForm) Valid(l *locale.Locale) bool {
|
||||
v := form.NewValidator(l)
|
||||
v.CheckSelectedOptions(f.Icon, l.GettextNoop("Selected icon is not valid."))
|
||||
if v.CheckRequired(f.Name, l.GettextNoop("Name can not be empty.")) {
|
||||
v.CheckMinLength(f.Name, 1, l.GettextNoop("Name must have at least one letter."))
|
||||
}
|
||||
return v.AllOK
|
||||
}
|
||||
|
||||
func (f *featureForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
|
||||
template.MustRenderAdmin(w, r, user, company, "campsite/feature/form.gohtml", f)
|
||||
}
|
|
@ -211,3 +211,60 @@ func (l10n *slideL10nForm) Valid(l *locale.Locale) bool {
|
|||
v := form.NewValidator(l)
|
||||
return v.AllOK
|
||||
}
|
||||
|
||||
type featureL10nForm struct {
|
||||
Locale *locale.Locale
|
||||
TypeSlug string
|
||||
ID int
|
||||
Name *form.L10nInput
|
||||
}
|
||||
|
||||
func newFeatureL10nForm(f *featureForm, loc *locale.Locale) *featureL10nForm {
|
||||
return &featureL10nForm{
|
||||
Locale: loc,
|
||||
TypeSlug: f.TypeSlug,
|
||||
ID: f.ID,
|
||||
Name: f.Name.L10nInput(),
|
||||
}
|
||||
}
|
||||
|
||||
func (l10n *featureL10nForm) FillFromDatabase(ctx context.Context, conn *database.Conn) error {
|
||||
row := conn.QueryRow(ctx, `
|
||||
select coalesce(i18n.name, '') as l10n_name
|
||||
from campsite_type_feature
|
||||
left join campsite_type_feature_i18n as i18n on campsite_type_feature.campsite_type_feature_id = i18n.campsite_type_feature_id and i18n.lang_tag = $1
|
||||
where campsite_type_feature.campsite_type_feature_id = $2
|
||||
`, l10n.Locale.Language, l10n.ID)
|
||||
return row.Scan(&l10n.Name.Val)
|
||||
}
|
||||
|
||||
func (l10n *featureL10nForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
|
||||
template.MustRenderAdmin(w, r, user, company, "campsite/feature/l10n.gohtml", l10n)
|
||||
}
|
||||
|
||||
func editFeatureL10n(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, l10n *featureL10nForm) {
|
||||
if ok, err := form.Handle(l10n, w, r, user); err != nil {
|
||||
return
|
||||
} else if !ok {
|
||||
l10n.MustRender(w, r, user, company)
|
||||
return
|
||||
}
|
||||
if err := conn.TranslateCampsiteTypeFeature(r.Context(), l10n.ID, l10n.Locale.Language, l10n.Name.Val); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
httplib.Redirect(w, r, "/admin/campsites/types/"+l10n.TypeSlug+"/features", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (l10n *featureL10nForm) Parse(r *http.Request) error {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
l10n.Name.FillValue(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l10n *featureL10nForm) Valid(l *locale.Locale) bool {
|
||||
v := form.NewValidator(l)
|
||||
v.CheckRequired(&l10n.Name.Input, l.GettextNoop("Name can not be empty."))
|
||||
return v.AllOK
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/jackc/pgx/v4"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"dev.tandem.ws/tandem/camper/pkg/auth"
|
||||
"dev.tandem.ws/tandem/camper/pkg/carousel"
|
||||
|
@ -54,6 +55,7 @@ type publicPage struct {
|
|||
Name string
|
||||
Carousel []*carousel.Slide
|
||||
Prices []*typePrice
|
||||
Features []*typeFeature
|
||||
Spiel gotemplate.HTML
|
||||
Info gotemplate.HTML
|
||||
Facilities gotemplate.HTML
|
||||
|
@ -73,10 +75,25 @@ type optionPrice struct {
|
|||
PricePerNight string
|
||||
}
|
||||
|
||||
type typeFeature struct {
|
||||
Icon string
|
||||
Name string
|
||||
}
|
||||
|
||||
func newPublicPage(ctx context.Context, conn *database.Conn, loc *locale.Locale, slug string) (*publicPage, error) {
|
||||
prices, err := collectPrices(ctx, conn, loc.Language, slug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
features, err := collectFeatures(ctx, conn, loc.Language, slug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
page := &publicPage{
|
||||
PublicPage: template.NewPublicPage(),
|
||||
Carousel: mustCollectSlides(ctx, conn, loc, slug),
|
||||
Prices: prices,
|
||||
Features: features,
|
||||
}
|
||||
row := conn.QueryRow(ctx, `
|
||||
select coalesce(i18n.name, campsite_type.name) as l10n_name
|
||||
|
@ -93,6 +110,10 @@ func newPublicPage(ctx context.Context, conn *database.Conn, loc *locale.Locale,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func collectPrices(ctx context.Context, conn *database.Conn, language language.Tag, slug string) ([]*typePrice, error) {
|
||||
rows, err := conn.Query(ctx, `
|
||||
select coalesce(i18n.name, season.name) as l10n_name
|
||||
, to_color(season.color)::text
|
||||
|
@ -117,11 +138,12 @@ func newPublicPage(ctx context.Context, conn *database.Conn, loc *locale.Locale,
|
|||
, season.color
|
||||
, cost.min_nights
|
||||
, cost.cost_per_night
|
||||
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, loc.Language, slug)
|
||||
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, language, slug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var prices []*typePrice
|
||||
for rows.Next() {
|
||||
price := &typePrice{}
|
||||
var options database.RecordArray
|
||||
|
@ -134,10 +156,33 @@ func newPublicPage(ctx context.Context, conn *database.Conn, loc *locale.Locale,
|
|||
PricePerNight: el.Fields[1].Get().(string),
|
||||
})
|
||||
}
|
||||
page.Prices = append(page.Prices, price)
|
||||
prices = append(prices, price)
|
||||
}
|
||||
return prices, nil
|
||||
}
|
||||
|
||||
func collectFeatures(ctx context.Context, conn *database.Conn, language language.Tag, slug string) ([]*typeFeature, error) {
|
||||
rows, err := conn.Query(ctx, `
|
||||
select feature.icon_name
|
||||
, coalesce(i18n.name, feature.name) as l10n_name
|
||||
from campsite_type_feature as feature
|
||||
join campsite_type using (campsite_type_id)
|
||||
left join campsite_type_feature_i18n as i18n on feature.campsite_type_feature_id = i18n.campsite_type_feature_id and i18n.lang_tag = $1
|
||||
where campsite_type.slug = $2
|
||||
`, language, slug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return page, nil
|
||||
var features []*typeFeature
|
||||
for rows.Next() {
|
||||
feature := &typeFeature{}
|
||||
if err := rows.Scan(&feature.Icon, &feature.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
features = append(features, feature)
|
||||
}
|
||||
return features, nil
|
||||
}
|
||||
|
||||
func (p *publicPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
|
||||
|
|
|
@ -103,6 +103,12 @@ func (c *Conn) GetBool(ctx context.Context, sql string, args ...interface{}) (bo
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Conn) GetInt(ctx context.Context, sql string, args ...interface{}) (int, error) {
|
||||
var result int
|
||||
err := c.QueryRow(ctx, sql, args...).Scan(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *Conn) GetBytes(ctx context.Context, sql string, args ...interface{}) ([]byte, error) {
|
||||
var result []byte
|
||||
err := c.QueryRow(ctx, sql, args...).Scan(&result)
|
||||
|
|
|
@ -45,3 +45,16 @@ func (c *Conn) TranslateCampsiteTypeOption(ctx context.Context, id int, langTag
|
|||
_, err := c.Exec(ctx, "select translate_campsite_type_option($1, $2, $3)", id, langTag, name)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) AddCampsiteTypeFeature(ctx context.Context, typeSlug string, iconName string, name string) (int, error) {
|
||||
return c.GetInt(ctx, "select add_campsite_type_feature($1, $2, $3)", typeSlug, iconName, name)
|
||||
}
|
||||
|
||||
func (c *Conn) EditCampsiteTypeFeature(ctx context.Context, id int, iconName string, name string) (int, error) {
|
||||
return c.GetInt(ctx, "select edit_campsite_type_feature($1, $2, $3)", id, iconName, name)
|
||||
}
|
||||
|
||||
func (c *Conn) TranslateCampsiteTypeFeature(ctx context.Context, id int, langTag language.Tag, name string) error {
|
||||
_, err := c.Exec(ctx, "select translate_campsite_type_feature($1, $2, $3)", id, langTag, name)
|
||||
return err
|
||||
}
|
||||
|
|
216
po/ca.po
216
po/ca.po
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: camper\n"
|
||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||
"POT-Creation-Date: 2023-10-13 18:05+0200\n"
|
||||
"POT-Creation-Date: 2023-10-13 20:28+0200\n"
|
||||
"PO-Revision-Date: 2023-07-22 23:45+0200\n"
|
||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||
"Language-Team: Catalan <ca@dodds.net>\n"
|
||||
|
@ -84,29 +84,34 @@ msgctxt "title"
|
|||
msgid "Prices"
|
||||
msgstr "Preus"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:47
|
||||
#: web/templates/public/campsite/type.gohtml:48
|
||||
msgid "%s €/night"
|
||||
msgstr "%s €/nit"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:49
|
||||
#: web/templates/public/campsite/type.gohtml:50
|
||||
msgid "%s: %s €/night"
|
||||
msgstr "%s: %s €/nit"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:52
|
||||
#: web/templates/public/campsite/type.gohtml:53
|
||||
msgid "*Minimum %d nights per stay"
|
||||
msgstr "*Mínim %d nits per estada"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:61
|
||||
#: web/templates/public/campsite/type.gohtml:62
|
||||
msgctxt "title"
|
||||
msgid "Features"
|
||||
msgstr "Característiques"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:73
|
||||
msgctxt "title"
|
||||
msgid "Info"
|
||||
msgstr "Informació"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:65
|
||||
#: web/templates/public/campsite/type.gohtml:77
|
||||
msgctxt "title"
|
||||
msgid "Facilities"
|
||||
msgstr "Equipaments"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:69
|
||||
#: web/templates/public/campsite/type.gohtml:81
|
||||
msgctxt "title"
|
||||
msgid "Description"
|
||||
msgstr "Descripció"
|
||||
|
@ -225,6 +230,7 @@ msgid "Caption"
|
|||
msgstr "Llegenda"
|
||||
|
||||
#: web/templates/admin/carousel/form.gohtml:47
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:62
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:47
|
||||
#: web/templates/admin/campsite/form.gohtml:70
|
||||
#: web/templates/admin/campsite/option/form.gohtml:78
|
||||
|
@ -237,6 +243,7 @@ msgid "Update"
|
|||
msgstr "Actualitza"
|
||||
|
||||
#: web/templates/admin/carousel/form.gohtml:49
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:64
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:49
|
||||
#: web/templates/admin/campsite/form.gohtml:72
|
||||
#: web/templates/admin/campsite/option/form.gohtml:80
|
||||
|
@ -254,6 +261,7 @@ msgid "Translate Carousel Slide to %s"
|
|||
msgstr "Traducció de la diapositiva del carrusel a %s"
|
||||
|
||||
#: web/templates/admin/carousel/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/carousel/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:21
|
||||
|
@ -268,6 +276,7 @@ msgid "Source:"
|
|||
msgstr "Origen:"
|
||||
|
||||
#: web/templates/admin/carousel/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/carousel/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:23
|
||||
|
@ -283,6 +292,7 @@ msgid "Translation:"
|
|||
msgstr "Traducció:"
|
||||
|
||||
#: web/templates/admin/carousel/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/carousel/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:84
|
||||
|
@ -292,6 +302,80 @@ msgctxt "action"
|
|||
msgid "Translate"
|
||||
msgstr "Tradueix"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:8
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:25
|
||||
msgctxt "title"
|
||||
msgid "Edit Campsite Type Feature"
|
||||
msgstr "Edició de les característiques del tipus d’allotjament"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:10
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:27
|
||||
msgctxt "title"
|
||||
msgid "New Campsite Type Feature"
|
||||
msgstr "Nova característica de tipus d’allotjament"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:34
|
||||
#: web/templates/admin/services/form.gohtml:34
|
||||
msgctxt "input"
|
||||
msgid "Icon"
|
||||
msgstr "Icona"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:52
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:20
|
||||
#: web/templates/admin/campsite/option/form.gohtml:34
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:20
|
||||
#: web/templates/admin/campsite/type/form.gohtml:46
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:20
|
||||
#: web/templates/admin/season/form.gohtml:46
|
||||
#: web/templates/admin/season/l10n.gohtml:20
|
||||
#: web/templates/admin/services/form.gohtml:52
|
||||
#: web/templates/admin/services/l10n.gohtml:20
|
||||
#: web/templates/admin/profile.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:6
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:12
|
||||
msgctxt "title"
|
||||
msgid "Campsite Type Features"
|
||||
msgstr "Característiques del tipus d’allotjaments"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:11
|
||||
msgctxt "action"
|
||||
msgid "Add Feature"
|
||||
msgstr "Afegeix característica"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:17
|
||||
#: web/templates/admin/campsite/option/index.gohtml:17
|
||||
#: web/templates/admin/campsite/type/index.gohtml:17
|
||||
#: web/templates/admin/season/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:18
|
||||
#: web/templates/admin/campsite/carousel/index.gohtml:19
|
||||
#: web/templates/admin/campsite/option/index.gohtml:18
|
||||
#: web/templates/admin/campsite/type/index.gohtml:18
|
||||
#: web/templates/admin/season/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:60
|
||||
#: web/templates/admin/home/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Translations"
|
||||
msgstr "Traduccions"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:39
|
||||
msgid "No campsite type features added yet."
|
||||
msgstr "No s’ha afegit cap característica al tipus d’allotjament encara."
|
||||
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:7
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:14
|
||||
msgctxt "title"
|
||||
msgid "Translate Campsite Type Feature to %s"
|
||||
msgstr "Traducció de la característica del tipus d’allotjament a %s"
|
||||
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:8
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:25
|
||||
msgctxt "title"
|
||||
|
@ -331,17 +415,6 @@ msgctxt "header"
|
|||
msgid "Caption"
|
||||
msgstr "Llegenda"
|
||||
|
||||
#: web/templates/admin/campsite/carousel/index.gohtml:19
|
||||
#: web/templates/admin/campsite/option/index.gohtml:18
|
||||
#: web/templates/admin/campsite/type/index.gohtml:18
|
||||
#: web/templates/admin/season/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:60
|
||||
#: web/templates/admin/home/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Translations"
|
||||
msgstr "Traduccions"
|
||||
|
||||
#: web/templates/admin/campsite/carousel/index.gohtml:20
|
||||
#: web/templates/admin/services/index.gohtml:20
|
||||
#: web/templates/admin/services/index.gohtml:61
|
||||
|
@ -420,19 +493,6 @@ msgctxt "title"
|
|||
msgid "New Campsite Type Option"
|
||||
msgstr "Nova opció del tipus d’allotjament"
|
||||
|
||||
#: web/templates/admin/campsite/option/form.gohtml:34
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:20
|
||||
#: web/templates/admin/campsite/type/form.gohtml:46
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:20
|
||||
#: web/templates/admin/season/form.gohtml:46
|
||||
#: web/templates/admin/season/l10n.gohtml:20
|
||||
#: web/templates/admin/services/form.gohtml:52
|
||||
#: web/templates/admin/services/l10n.gohtml:20
|
||||
#: web/templates/admin/profile.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: web/templates/admin/campsite/option/form.gohtml:42
|
||||
msgctxt "input"
|
||||
msgid "Minimum"
|
||||
|
@ -460,13 +520,6 @@ msgctxt "action"
|
|||
msgid "Add Option"
|
||||
msgstr "Afegeix opció"
|
||||
|
||||
#: web/templates/admin/campsite/option/index.gohtml:17
|
||||
#: web/templates/admin/campsite/type/index.gohtml:17
|
||||
#: web/templates/admin/season/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: web/templates/admin/campsite/option/index.gohtml:39
|
||||
msgid "No campsite type options added yet."
|
||||
msgstr "No s’ha afegit cap opció al tipus d’allotjament encara."
|
||||
|
@ -493,13 +546,13 @@ msgid "Type"
|
|||
msgstr "Tipus"
|
||||
|
||||
#: web/templates/admin/campsite/index.gohtml:28
|
||||
#: web/templates/admin/campsite/type/index.gohtml:39
|
||||
#: web/templates/admin/campsite/type/index.gohtml:47
|
||||
#: web/templates/admin/season/index.gohtml:39
|
||||
msgid "Yes"
|
||||
msgstr "Sí"
|
||||
|
||||
#: web/templates/admin/campsite/index.gohtml:28
|
||||
#: web/templates/admin/campsite/type/index.gohtml:39
|
||||
#: web/templates/admin/campsite/type/index.gohtml:47
|
||||
#: web/templates/admin/season/index.gohtml:39
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
|
@ -521,7 +574,7 @@ msgid "New Campsite Type"
|
|||
msgstr "Nou tipus d’allotjament"
|
||||
|
||||
#: web/templates/admin/campsite/type/form.gohtml:37
|
||||
#: web/templates/admin/campsite/type/index.gohtml:21
|
||||
#: web/templates/admin/campsite/type/index.gohtml:22
|
||||
msgctxt "campsite type"
|
||||
msgid "Active"
|
||||
msgstr "Actiu"
|
||||
|
@ -581,25 +634,35 @@ msgstr "Afegeix tipus"
|
|||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Features"
|
||||
msgstr "Característiques"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:20
|
||||
msgctxt "header"
|
||||
msgid "Options"
|
||||
msgstr "Opcions"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:20
|
||||
#: web/templates/admin/campsite/type/index.gohtml:21
|
||||
msgctxt "header"
|
||||
msgid "Carousel"
|
||||
msgstr "Carrusel"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:37
|
||||
#: web/templates/admin/campsite/type/index.gohtml:39
|
||||
msgctxt "action"
|
||||
msgid "Edit Features"
|
||||
msgstr "Edita les característiques"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:42
|
||||
msgctxt "action"
|
||||
msgid "Edit Options"
|
||||
msgstr "Edita les opcions"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:38
|
||||
#: web/templates/admin/campsite/type/index.gohtml:45
|
||||
msgctxt "action"
|
||||
msgid "Edit Carousel"
|
||||
msgstr "Edita el carrusel"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:45
|
||||
#: web/templates/admin/campsite/type/index.gohtml:53
|
||||
msgid "No campsite types added yet."
|
||||
msgstr "No s’ha afegit cap tipus d’allotjament encara."
|
||||
|
||||
|
@ -744,11 +807,6 @@ msgctxt "title"
|
|||
msgid "New Service"
|
||||
msgstr "Nou servei"
|
||||
|
||||
#: web/templates/admin/services/form.gohtml:34
|
||||
msgctxt "input"
|
||||
msgid "Icon"
|
||||
msgstr "Icona"
|
||||
|
||||
#: web/templates/admin/services/index.gohtml:6
|
||||
#: web/templates/admin/layout.gohtml:52
|
||||
msgctxt "title"
|
||||
|
@ -1021,8 +1079,9 @@ msgid "Automatic"
|
|||
msgstr "Automàtic"
|
||||
|
||||
#: pkg/app/user.go:249 pkg/campsite/types/l10n.go:87
|
||||
#: pkg/campsite/types/l10n.go:142 pkg/campsite/types/option.go:336
|
||||
#: pkg/campsite/types/admin.go:413 pkg/season/l10n.go:69
|
||||
#: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268
|
||||
#: pkg/campsite/types/option.go:340 pkg/campsite/types/feature.go:243
|
||||
#: pkg/campsite/types/admin.go:415 pkg/season/l10n.go:69
|
||||
#: pkg/season/admin.go:382 pkg/services/l10n.go:73 pkg/services/admin.go:266
|
||||
msgid "Name can not be empty."
|
||||
msgstr "No podeu deixar el nom en blanc."
|
||||
|
@ -1043,85 +1102,90 @@ msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida."
|
|||
msgid "Access forbidden"
|
||||
msgstr "Accés prohibit"
|
||||
|
||||
#: pkg/campsite/types/option.go:337 pkg/campsite/types/admin.go:414
|
||||
#: pkg/campsite/types/option.go:341 pkg/campsite/types/feature.go:244
|
||||
#: pkg/campsite/types/admin.go:416
|
||||
msgid "Name must have at least one letter."
|
||||
msgstr "El nom ha de tenir com a mínim una lletra."
|
||||
|
||||
#: pkg/campsite/types/option.go:340
|
||||
#: pkg/campsite/types/option.go:344
|
||||
msgid "Minimum can not be empty."
|
||||
msgstr "No podeu deixar el mínim en blanc."
|
||||
|
||||
#: pkg/campsite/types/option.go:341
|
||||
#: pkg/campsite/types/option.go:345
|
||||
msgid "Minimum must be an integer number."
|
||||
msgstr "El valor del mínim ha de ser un número enter."
|
||||
|
||||
#: pkg/campsite/types/option.go:343
|
||||
#: pkg/campsite/types/option.go:347
|
||||
msgid "Minimum must be zero or greater."
|
||||
msgstr "El valor del mínim ha de ser com a mínim zero."
|
||||
|
||||
#: pkg/campsite/types/option.go:346
|
||||
#: pkg/campsite/types/option.go:350
|
||||
msgid "Maximum can not be empty."
|
||||
msgstr "No podeu deixar el màxim en blanc."
|
||||
|
||||
#: pkg/campsite/types/option.go:347
|
||||
#: pkg/campsite/types/option.go:351
|
||||
msgid "Maximum must be an integer number."
|
||||
msgstr "El valor del màxim ha de ser un número enter."
|
||||
|
||||
#: pkg/campsite/types/option.go:349
|
||||
#: pkg/campsite/types/option.go:353
|
||||
msgid "Maximum must be equal or greater than minimum."
|
||||
msgstr "El valor del màxim ha de ser igual o superir al del mínim."
|
||||
|
||||
#: pkg/campsite/types/option.go:353 pkg/campsite/types/admin.go:427
|
||||
#: pkg/campsite/types/option.go:357 pkg/campsite/types/admin.go:429
|
||||
msgid "Price per night can not be empty."
|
||||
msgstr "No podeu deixar el preu per nit en blanc."
|
||||
|
||||
#: pkg/campsite/types/option.go:354 pkg/campsite/types/admin.go:428
|
||||
#: pkg/campsite/types/option.go:358 pkg/campsite/types/admin.go:430
|
||||
msgid "Price per night must be a decimal number."
|
||||
msgstr "El preu per nit ha de ser un número decimal."
|
||||
|
||||
#: pkg/campsite/types/option.go:355 pkg/campsite/types/admin.go:429
|
||||
#: pkg/campsite/types/option.go:359 pkg/campsite/types/admin.go:431
|
||||
msgid "Price per night must be zero or greater."
|
||||
msgstr "El preu per nit ha de ser com a mínim zero."
|
||||
|
||||
#: pkg/campsite/types/admin.go:289
|
||||
#: pkg/campsite/types/feature.go:242 pkg/services/admin.go:265
|
||||
msgid "Selected icon is not valid."
|
||||
msgstr "La icona escollida no és vàlida."
|
||||
|
||||
#: pkg/campsite/types/admin.go:291
|
||||
msgctxt "input"
|
||||
msgid "Cover image"
|
||||
msgstr "Imatge de portada"
|
||||
|
||||
#: pkg/campsite/types/admin.go:290
|
||||
#: pkg/campsite/types/admin.go:292
|
||||
msgctxt "action"
|
||||
msgid "Set campsite type cover"
|
||||
msgstr "Estableix la portada del tipus d’allotjament"
|
||||
|
||||
#: pkg/campsite/types/admin.go:416
|
||||
#: pkg/campsite/types/admin.go:418
|
||||
msgid "Cover image can not be empty."
|
||||
msgstr "No podeu deixar la imatge de portada en blanc."
|
||||
|
||||
#: pkg/campsite/types/admin.go:417
|
||||
#: pkg/campsite/types/admin.go:419
|
||||
msgid "Cover image must be an image media type."
|
||||
msgstr "La imatge de portada ha de ser un mèdia de tipus imatge."
|
||||
|
||||
#: pkg/campsite/types/admin.go:421
|
||||
#: pkg/campsite/types/admin.go:423
|
||||
msgid "Maximum number of campers can not be empty."
|
||||
msgstr "No podeu deixar el número màxim de persones en blanc."
|
||||
|
||||
#: pkg/campsite/types/admin.go:422
|
||||
#: pkg/campsite/types/admin.go:424
|
||||
msgid "Maximum number of campers must be an integer number."
|
||||
msgstr "El número màxim de persones ha de ser enter."
|
||||
|
||||
#: pkg/campsite/types/admin.go:423
|
||||
#: pkg/campsite/types/admin.go:425
|
||||
msgid "Maximum number of campers must be one or greater."
|
||||
msgstr "El número màxim de persones no pot ser zero."
|
||||
|
||||
#: pkg/campsite/types/admin.go:432
|
||||
#: pkg/campsite/types/admin.go:434
|
||||
msgid "Minimum number of nights can not be empty."
|
||||
msgstr "No podeu deixar el número mínim de nits en blanc."
|
||||
|
||||
#: pkg/campsite/types/admin.go:433
|
||||
#: pkg/campsite/types/admin.go:435
|
||||
msgid "Minimum number of nights must be an integer."
|
||||
msgstr "El número mínim de nits ha de ser enter."
|
||||
|
||||
#: pkg/campsite/types/admin.go:434
|
||||
#: pkg/campsite/types/admin.go:436
|
||||
msgid "Minimum number of nights must be one or greater."
|
||||
msgstr "El número mínim de nits no pot ser zero."
|
||||
|
||||
|
@ -1222,10 +1286,6 @@ msgstr "No podeu deixar la data de fi en blanc."
|
|||
msgid "End date must be a valid date."
|
||||
msgstr "La data de fi ha de ser una data vàlida."
|
||||
|
||||
#: pkg/services/admin.go:265
|
||||
msgid "Selected icon is not valid."
|
||||
msgstr "La icona escollida no és vàlida."
|
||||
|
||||
#: pkg/company/admin.go:186
|
||||
msgid "Selected country is not valid."
|
||||
msgstr "El país escollit no és vàlid."
|
||||
|
@ -1306,10 +1366,6 @@ msgstr "No podeu deixar el nom del fitxer en blanc."
|
|||
#~ msgid "Pricing"
|
||||
#~ msgstr "Preus"
|
||||
|
||||
#~ msgctxt "title"
|
||||
#~ msgid "Features"
|
||||
#~ msgstr "Característiques"
|
||||
|
||||
#~ msgctxt "input"
|
||||
#~ msgid "Features"
|
||||
#~ msgstr "Característiques"
|
||||
|
|
218
po/es.po
218
po/es.po
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: camper\n"
|
||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||
"POT-Creation-Date: 2023-10-13 18:05+0200\n"
|
||||
"POT-Creation-Date: 2023-10-13 20:28+0200\n"
|
||||
"PO-Revision-Date: 2023-07-22 23:46+0200\n"
|
||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||
|
@ -84,29 +84,34 @@ msgctxt "title"
|
|||
msgid "Prices"
|
||||
msgstr "Precios"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:47
|
||||
#: web/templates/public/campsite/type.gohtml:48
|
||||
msgid "%s €/night"
|
||||
msgstr "%s €/noche"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:49
|
||||
#: web/templates/public/campsite/type.gohtml:50
|
||||
msgid "%s: %s €/night"
|
||||
msgstr ":%s: %s €/noche"
|
||||
msgstr "%s: %s €/noche"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:52
|
||||
#: web/templates/public/campsite/type.gohtml:53
|
||||
msgid "*Minimum %d nights per stay"
|
||||
msgstr "*Mínimo %d noches por estancia"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:61
|
||||
#: web/templates/public/campsite/type.gohtml:62
|
||||
msgctxt "title"
|
||||
msgid "Features"
|
||||
msgstr "Características"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:73
|
||||
msgctxt "title"
|
||||
msgid "Info"
|
||||
msgstr "Información"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:65
|
||||
#: web/templates/public/campsite/type.gohtml:77
|
||||
msgctxt "title"
|
||||
msgid "Facilities"
|
||||
msgstr "Equipamento"
|
||||
|
||||
#: web/templates/public/campsite/type.gohtml:69
|
||||
#: web/templates/public/campsite/type.gohtml:81
|
||||
msgctxt "title"
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
|
@ -225,6 +230,7 @@ msgid "Caption"
|
|||
msgstr "Leyenda"
|
||||
|
||||
#: web/templates/admin/carousel/form.gohtml:47
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:62
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:47
|
||||
#: web/templates/admin/campsite/form.gohtml:70
|
||||
#: web/templates/admin/campsite/option/form.gohtml:78
|
||||
|
@ -237,6 +243,7 @@ msgid "Update"
|
|||
msgstr "Actualizar"
|
||||
|
||||
#: web/templates/admin/carousel/form.gohtml:49
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:64
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:49
|
||||
#: web/templates/admin/campsite/form.gohtml:72
|
||||
#: web/templates/admin/campsite/option/form.gohtml:80
|
||||
|
@ -254,6 +261,7 @@ msgid "Translate Carousel Slide to %s"
|
|||
msgstr "Traducción de la diapositiva de carrusel a %s"
|
||||
|
||||
#: web/templates/admin/carousel/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/carousel/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:21
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:21
|
||||
|
@ -268,6 +276,7 @@ msgid "Source:"
|
|||
msgstr "Origen:"
|
||||
|
||||
#: web/templates/admin/carousel/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/carousel/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:23
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:23
|
||||
|
@ -283,6 +292,7 @@ msgid "Translation:"
|
|||
msgstr "Traducción"
|
||||
|
||||
#: web/templates/admin/carousel/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/carousel/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:32
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:84
|
||||
|
@ -292,6 +302,80 @@ msgctxt "action"
|
|||
msgid "Translate"
|
||||
msgstr "Traducir"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:8
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:25
|
||||
msgctxt "title"
|
||||
msgid "Edit Campsite Type Feature"
|
||||
msgstr "Edición de las características del tipo de alojamiento"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:10
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:27
|
||||
msgctxt "title"
|
||||
msgid "New Campsite Type Feature"
|
||||
msgstr "Nueva característica del tipo de alojamiento"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:34
|
||||
#: web/templates/admin/services/form.gohtml:34
|
||||
msgctxt "input"
|
||||
msgid "Icon"
|
||||
msgstr "Icono"
|
||||
|
||||
#: web/templates/admin/campsite/feature/form.gohtml:52
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:20
|
||||
#: web/templates/admin/campsite/option/form.gohtml:34
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:20
|
||||
#: web/templates/admin/campsite/type/form.gohtml:46
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:20
|
||||
#: web/templates/admin/season/form.gohtml:46
|
||||
#: web/templates/admin/season/l10n.gohtml:20
|
||||
#: web/templates/admin/services/form.gohtml:52
|
||||
#: web/templates/admin/services/l10n.gohtml:20
|
||||
#: web/templates/admin/profile.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:6
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:12
|
||||
msgctxt "title"
|
||||
msgid "Campsite Type Features"
|
||||
msgstr "Características del tipo de alojamiento"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:11
|
||||
msgctxt "action"
|
||||
msgid "Add Feature"
|
||||
msgstr "Añadir características"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:17
|
||||
#: web/templates/admin/campsite/option/index.gohtml:17
|
||||
#: web/templates/admin/campsite/type/index.gohtml:17
|
||||
#: web/templates/admin/season/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:18
|
||||
#: web/templates/admin/campsite/carousel/index.gohtml:19
|
||||
#: web/templates/admin/campsite/option/index.gohtml:18
|
||||
#: web/templates/admin/campsite/type/index.gohtml:18
|
||||
#: web/templates/admin/season/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:60
|
||||
#: web/templates/admin/home/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Translations"
|
||||
msgstr "Traducciones"
|
||||
|
||||
#: web/templates/admin/campsite/feature/index.gohtml:39
|
||||
msgid "No campsite type features added yet."
|
||||
msgstr "No se ha añadido ninguna característica al tipo de alojamiento todavía."
|
||||
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:7
|
||||
#: web/templates/admin/campsite/feature/l10n.gohtml:14
|
||||
msgctxt "title"
|
||||
msgid "Translate Campsite Type Feature to %s"
|
||||
msgstr "Traducción de la característica del tipo de alojamiento a %s"
|
||||
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:8
|
||||
#: web/templates/admin/campsite/carousel/form.gohtml:25
|
||||
msgctxt "title"
|
||||
|
@ -331,17 +415,6 @@ msgctxt "header"
|
|||
msgid "Caption"
|
||||
msgstr "Leyenda"
|
||||
|
||||
#: web/templates/admin/campsite/carousel/index.gohtml:19
|
||||
#: web/templates/admin/campsite/option/index.gohtml:18
|
||||
#: web/templates/admin/campsite/type/index.gohtml:18
|
||||
#: web/templates/admin/season/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:19
|
||||
#: web/templates/admin/services/index.gohtml:60
|
||||
#: web/templates/admin/home/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Translations"
|
||||
msgstr "Traducciones"
|
||||
|
||||
#: web/templates/admin/campsite/carousel/index.gohtml:20
|
||||
#: web/templates/admin/services/index.gohtml:20
|
||||
#: web/templates/admin/services/index.gohtml:61
|
||||
|
@ -420,19 +493,6 @@ msgctxt "title"
|
|||
msgid "New Campsite Type Option"
|
||||
msgstr "Nueva opción del tipo de alojamiento"
|
||||
|
||||
#: web/templates/admin/campsite/option/form.gohtml:34
|
||||
#: web/templates/admin/campsite/option/l10n.gohtml:20
|
||||
#: web/templates/admin/campsite/type/form.gohtml:46
|
||||
#: web/templates/admin/campsite/type/l10n.gohtml:20
|
||||
#: web/templates/admin/season/form.gohtml:46
|
||||
#: web/templates/admin/season/l10n.gohtml:20
|
||||
#: web/templates/admin/services/form.gohtml:52
|
||||
#: web/templates/admin/services/l10n.gohtml:20
|
||||
#: web/templates/admin/profile.gohtml:26
|
||||
msgctxt "input"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: web/templates/admin/campsite/option/form.gohtml:42
|
||||
msgctxt "input"
|
||||
msgid "Minimum"
|
||||
|
@ -460,13 +520,6 @@ msgctxt "action"
|
|||
msgid "Add Option"
|
||||
msgstr "Añadir opción"
|
||||
|
||||
#: web/templates/admin/campsite/option/index.gohtml:17
|
||||
#: web/templates/admin/campsite/type/index.gohtml:17
|
||||
#: web/templates/admin/season/index.gohtml:18
|
||||
msgctxt "header"
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: web/templates/admin/campsite/option/index.gohtml:39
|
||||
msgid "No campsite type options added yet."
|
||||
msgstr "No se ha añadido ninguna opció al tipo de alojamiento todavía."
|
||||
|
@ -493,13 +546,13 @@ msgid "Type"
|
|||
msgstr "Tipo"
|
||||
|
||||
#: web/templates/admin/campsite/index.gohtml:28
|
||||
#: web/templates/admin/campsite/type/index.gohtml:39
|
||||
#: web/templates/admin/campsite/type/index.gohtml:47
|
||||
#: web/templates/admin/season/index.gohtml:39
|
||||
msgid "Yes"
|
||||
msgstr "Sí"
|
||||
|
||||
#: web/templates/admin/campsite/index.gohtml:28
|
||||
#: web/templates/admin/campsite/type/index.gohtml:39
|
||||
#: web/templates/admin/campsite/type/index.gohtml:47
|
||||
#: web/templates/admin/season/index.gohtml:39
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
|
@ -521,7 +574,7 @@ msgid "New Campsite Type"
|
|||
msgstr "Nuevo tipo de alojamiento"
|
||||
|
||||
#: web/templates/admin/campsite/type/form.gohtml:37
|
||||
#: web/templates/admin/campsite/type/index.gohtml:21
|
||||
#: web/templates/admin/campsite/type/index.gohtml:22
|
||||
msgctxt "campsite type"
|
||||
msgid "Active"
|
||||
msgstr "Activo"
|
||||
|
@ -581,25 +634,35 @@ msgstr "Añadir tipo"
|
|||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:19
|
||||
msgctxt "header"
|
||||
msgid "Features"
|
||||
msgstr "Características"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:20
|
||||
msgctxt "header"
|
||||
msgid "Options"
|
||||
msgstr "Opciones"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:20
|
||||
#: web/templates/admin/campsite/type/index.gohtml:21
|
||||
msgctxt "header"
|
||||
msgid "Carousel"
|
||||
msgstr "Carrusel"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:37
|
||||
#: web/templates/admin/campsite/type/index.gohtml:39
|
||||
msgctxt "action"
|
||||
msgid "Edit Features"
|
||||
msgstr "Editar las características"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:42
|
||||
msgctxt "action"
|
||||
msgid "Edit Options"
|
||||
msgstr "Editar opciones"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:38
|
||||
#: web/templates/admin/campsite/type/index.gohtml:45
|
||||
msgctxt "action"
|
||||
msgid "Edit Carousel"
|
||||
msgstr "Editar el carrusel"
|
||||
|
||||
#: web/templates/admin/campsite/type/index.gohtml:45
|
||||
#: web/templates/admin/campsite/type/index.gohtml:53
|
||||
msgid "No campsite types added yet."
|
||||
msgstr "No se ha añadido ningún tipo de alojamiento todavía."
|
||||
|
||||
|
@ -744,11 +807,6 @@ msgctxt "title"
|
|||
msgid "New Service"
|
||||
msgstr "Nuevo servicio"
|
||||
|
||||
#: web/templates/admin/services/form.gohtml:34
|
||||
msgctxt "input"
|
||||
msgid "Icon"
|
||||
msgstr "Icono"
|
||||
|
||||
#: web/templates/admin/services/index.gohtml:6
|
||||
#: web/templates/admin/layout.gohtml:52
|
||||
msgctxt "title"
|
||||
|
@ -1021,8 +1079,9 @@ msgid "Automatic"
|
|||
msgstr "Automático"
|
||||
|
||||
#: pkg/app/user.go:249 pkg/campsite/types/l10n.go:87
|
||||
#: pkg/campsite/types/l10n.go:142 pkg/campsite/types/option.go:336
|
||||
#: pkg/campsite/types/admin.go:413 pkg/season/l10n.go:69
|
||||
#: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268
|
||||
#: pkg/campsite/types/option.go:340 pkg/campsite/types/feature.go:243
|
||||
#: pkg/campsite/types/admin.go:415 pkg/season/l10n.go:69
|
||||
#: pkg/season/admin.go:382 pkg/services/l10n.go:73 pkg/services/admin.go:266
|
||||
msgid "Name can not be empty."
|
||||
msgstr "No podéis dejar el nombre en blanco."
|
||||
|
@ -1043,85 +1102,90 @@ msgstr "El archivo tiene que ser una imagen PNG o JPEG válida."
|
|||
msgid "Access forbidden"
|
||||
msgstr "Acceso prohibido"
|
||||
|
||||
#: pkg/campsite/types/option.go:337 pkg/campsite/types/admin.go:414
|
||||
#: pkg/campsite/types/option.go:341 pkg/campsite/types/feature.go:244
|
||||
#: pkg/campsite/types/admin.go:416
|
||||
msgid "Name must have at least one letter."
|
||||
msgstr "El nombre tiene que tener como mínimo una letra."
|
||||
|
||||
#: pkg/campsite/types/option.go:340
|
||||
#: pkg/campsite/types/option.go:344
|
||||
msgid "Minimum can not be empty."
|
||||
msgstr "No podéis dejar el mínimo en blanco."
|
||||
|
||||
#: pkg/campsite/types/option.go:341
|
||||
#: pkg/campsite/types/option.go:345
|
||||
msgid "Minimum must be an integer number."
|
||||
msgstr "El valor de mínimo tiene que ser un número entero."
|
||||
|
||||
#: pkg/campsite/types/option.go:343
|
||||
#: pkg/campsite/types/option.go:347
|
||||
msgid "Minimum must be zero or greater."
|
||||
msgstr "El valor de mínimo tiene que ser como mínimo cero."
|
||||
|
||||
#: pkg/campsite/types/option.go:346
|
||||
#: pkg/campsite/types/option.go:350
|
||||
msgid "Maximum can not be empty."
|
||||
msgstr "No podéis dejar el máxmimo en blanco."
|
||||
|
||||
#: pkg/campsite/types/option.go:347
|
||||
#: pkg/campsite/types/option.go:351
|
||||
msgid "Maximum must be an integer number."
|
||||
msgstr "El valor del máximo tiene que ser un número entero."
|
||||
|
||||
#: pkg/campsite/types/option.go:349
|
||||
#: pkg/campsite/types/option.go:353
|
||||
msgid "Maximum must be equal or greater than minimum."
|
||||
msgstr "El valor del máximo tiene que ser igual o mayor al del mínimo."
|
||||
|
||||
#: pkg/campsite/types/option.go:353 pkg/campsite/types/admin.go:427
|
||||
#: pkg/campsite/types/option.go:357 pkg/campsite/types/admin.go:429
|
||||
msgid "Price per night can not be empty."
|
||||
msgstr "No podéis dejar el precio por noche en blanco."
|
||||
|
||||
#: pkg/campsite/types/option.go:354 pkg/campsite/types/admin.go:428
|
||||
#: pkg/campsite/types/option.go:358 pkg/campsite/types/admin.go:430
|
||||
msgid "Price per night must be a decimal number."
|
||||
msgstr "El precio por noche tien que ser un número decimal."
|
||||
|
||||
#: pkg/campsite/types/option.go:355 pkg/campsite/types/admin.go:429
|
||||
#: pkg/campsite/types/option.go:359 pkg/campsite/types/admin.go:431
|
||||
msgid "Price per night must be zero or greater."
|
||||
msgstr "El precio por noche tiene que ser como mínimo cero."
|
||||
|
||||
#: pkg/campsite/types/admin.go:289
|
||||
#: pkg/campsite/types/feature.go:242 pkg/services/admin.go:265
|
||||
msgid "Selected icon is not valid."
|
||||
msgstr "El icono escogido no es válido."
|
||||
|
||||
#: pkg/campsite/types/admin.go:291
|
||||
msgctxt "input"
|
||||
msgid "Cover image"
|
||||
msgstr "Imagen de portada"
|
||||
|
||||
#: pkg/campsite/types/admin.go:290
|
||||
#: pkg/campsite/types/admin.go:292
|
||||
msgctxt "action"
|
||||
msgid "Set campsite type cover"
|
||||
msgstr "Establecer la portada del tipo de alojamiento"
|
||||
|
||||
#: pkg/campsite/types/admin.go:416
|
||||
#: pkg/campsite/types/admin.go:418
|
||||
msgid "Cover image can not be empty."
|
||||
msgstr "No podéis dejar la imagen de portada en blanco."
|
||||
|
||||
#: pkg/campsite/types/admin.go:417
|
||||
#: pkg/campsite/types/admin.go:419
|
||||
msgid "Cover image must be an image media type."
|
||||
msgstr "La imagen de portada tiene que ser un medio de tipo imagen."
|
||||
|
||||
#: pkg/campsite/types/admin.go:421
|
||||
#: pkg/campsite/types/admin.go:423
|
||||
msgid "Maximum number of campers can not be empty."
|
||||
msgstr "No podéis dejar el número máximo de personas en blanco."
|
||||
|
||||
#: pkg/campsite/types/admin.go:422
|
||||
#: pkg/campsite/types/admin.go:424
|
||||
msgid "Maximum number of campers must be an integer number."
|
||||
msgstr "El número máximo de personas tiene que ser entero."
|
||||
|
||||
#: pkg/campsite/types/admin.go:423
|
||||
#: pkg/campsite/types/admin.go:425
|
||||
msgid "Maximum number of campers must be one or greater."
|
||||
msgstr "El número máximo de personas no puede ser cero."
|
||||
|
||||
#: pkg/campsite/types/admin.go:432
|
||||
#: pkg/campsite/types/admin.go:434
|
||||
msgid "Minimum number of nights can not be empty."
|
||||
msgstr "No podéis dejar el número mínimo de noches en blanco."
|
||||
|
||||
#: pkg/campsite/types/admin.go:433
|
||||
#: pkg/campsite/types/admin.go:435
|
||||
msgid "Minimum number of nights must be an integer."
|
||||
msgstr "El número mínimo de noches tiene que ser entero."
|
||||
|
||||
#: pkg/campsite/types/admin.go:434
|
||||
#: pkg/campsite/types/admin.go:436
|
||||
msgid "Minimum number of nights must be one or greater."
|
||||
msgstr "El número mínimo de noches no puede ser cero."
|
||||
|
||||
|
@ -1222,10 +1286,6 @@ msgstr "No podéis dejar la fecha final en blanco."
|
|||
msgid "End date must be a valid date."
|
||||
msgstr "La fecha final tiene que ser una fecha válida."
|
||||
|
||||
#: pkg/services/admin.go:265
|
||||
msgid "Selected icon is not valid."
|
||||
msgstr "El icono escogido no es válido."
|
||||
|
||||
#: pkg/company/admin.go:186
|
||||
msgid "Selected country is not valid."
|
||||
msgstr "El país escogido no es válido."
|
||||
|
@ -1306,10 +1366,6 @@ msgstr "No podéis dejar el nombre del archivo en blanco."
|
|||
#~ msgid "Pricing"
|
||||
#~ msgstr "Precios"
|
||||
|
||||
#~ msgctxt "title"
|
||||
#~ msgid "Features"
|
||||
#~ msgstr "Características"
|
||||
|
||||
#~ msgctxt "input"
|
||||
#~ msgid "Features"
|
||||
#~ msgstr "Características"
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:add_campsite_type_feature from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop function if exists camper.add_campsite_type_feature(uuid, text, text);
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:campsite_type_feature from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop table if exists camper.campsite_type_feature;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:campsite_type_feature_i18n from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop table if exists camper.campsite_type_feature_i18n;
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:edit_campsite_type_feature from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop function if exists camper.edit_campsite_type_feature(integer, text, text);
|
||||
|
||||
commit;
|
|
@ -0,0 +1,7 @@
|
|||
-- Revert camper:translate_campsite_type_feature from pg
|
||||
|
||||
begin;
|
||||
|
||||
drop function if exists camper.translate_campsite_type_feature(integer, text, text);
|
||||
|
||||
commit;
|
|
@ -104,3 +104,8 @@ campsite_type_carousel_i18n [roles schema_camper campsite_type_carousel language
|
|||
add_campsite_type_carousel_slide [roles schema_camper campsite_type_carousel campsite_type] 2023-10-09T17:59:49Z jordi fita mas <jordi@tandem.blog> # Add function to create slides for the campsite type carousel
|
||||
translate_campsite_type_carousel_slide [roles schema_camper campsite_type campsite_type_carousel_i18n] 2023-10-09T18:17:13Z jordi fita mas <jordi@tandem.blog> # Add function to translate a campsite type slide
|
||||
remove_campsite_type_carousel_slide [roles schema_camper campsite_type_carousel campsite_type_carousel_i18n] 2023-10-09T18:26:49Z jordi fita mas <jordi@tandem.blog> # Add function to remove campsite type slides
|
||||
campsite_type_feature [roles schema_camper campsite_type icon user_profile] 2023-10-13T16:14:27Z jordi fita mas <jordi@tandem.blog> # Add the relation of campsite type feature
|
||||
campsite_type_feature_i18n [roles schema_camper campsite_type_feature language] 2023-10-13T16:29:07Z jordi fita mas <jordi@tandem.blog> # Add relation for campsite_type_feature internationalization
|
||||
add_campsite_type_feature [roles schema_camper campsite_type_feature campsite_type] 2023-10-13T16:26:04Z jordi fita mas <jordi@tandem.blog> # Add function to create new campsite type features
|
||||
edit_campsite_type_feature [roles schema_camper campsite_type_feature] 2023-10-13T16:37:43Z jordi fita mas <jordi@tandem.blog> # Add function to update campsite type features
|
||||
translate_campsite_type_feature [roles schema_camper campsite_type_feature_i18n] 2023-10-13T16:43:55Z jordi fita mas <jordi@tandem.blog> # Add function to translate campsite type features
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
-- Test add_campsite_type_feature
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(13);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_function('camper', 'add_campsite_type_feature', array['uuid', 'text', 'text']);
|
||||
select function_lang_is('camper', 'add_campsite_type_feature', array['uuid', 'text', 'text'], 'sql');
|
||||
select function_returns('camper', 'add_campsite_type_feature', array['uuid', 'text', 'text'], 'integer');
|
||||
select isnt_definer('camper', 'add_campsite_type_feature', array['uuid', 'text', 'text']);
|
||||
select volatility_is('camper', 'add_campsite_type_feature', array['uuid', 'text', 'text'], 'volatile');
|
||||
select function_privs_are('camper', 'add_campsite_type_feature', array ['uuid', 'text', 'text'], 'guest', array[]::text[]);
|
||||
select function_privs_are('camper', 'add_campsite_type_feature', array ['uuid', 'text', 'text'], 'employee', array[]::text[]);
|
||||
select function_privs_are('camper', 'add_campsite_type_feature', array ['uuid', 'text', 'text'], 'admin', array['EXECUTE']);
|
||||
select function_privs_are('camper', 'add_campsite_type_feature', array ['uuid', 'text', 'text'], 'authenticator', array[]::text[]);
|
||||
|
||||
|
||||
set client_min_messages to warning;
|
||||
truncate campsite_type_feature_i18n cascade;
|
||||
truncate campsite_type_feature cascade;
|
||||
truncate campsite_type cascade;
|
||||
truncate media cascade;
|
||||
truncate media_content cascade;
|
||||
truncate company cascade;
|
||||
reset client_min_messages;
|
||||
|
||||
|
||||
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_lang_tag)
|
||||
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 'ca')
|
||||
;
|
||||
|
||||
insert into media_content (media_type, bytes)
|
||||
values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};')
|
||||
;
|
||||
|
||||
insert into media (media_id, company_id, original_filename, content_hash)
|
||||
values (2, 1, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
;
|
||||
|
||||
insert into campsite_type (campsite_type_id, company_id, slug, media_id, name, description, active, dogs_allowed, max_campers)
|
||||
values (3, 1, '87452b88-b48f-48d3-bb6c-0296de64164e', 2, 'Type A', '<p>A</p>', true, false, 4)
|
||||
, (4, 1, '9ae5cf87-cd69-4541-b5a5-75f937cc9e58', 2, 'Type B', '<p>B</p>', true, false, 5)
|
||||
;
|
||||
|
||||
select lives_ok(
|
||||
$$ select add_campsite_type_feature('87452b88-b48f-48d3-bb6c-0296de64164e', 'wifi', 'Feature 1') $$,
|
||||
'Should be able to add an feature to the first campsite type'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ select add_campsite_type_feature('9ae5cf87-cd69-4541-b5a5-75f937cc9e58', 'information', 'Feature 2') $$,
|
||||
'Should be able to add an feature to the second campsite type'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
$$ select campsite_type_id, icon_name, name from campsite_type_feature $$,
|
||||
$$ values (3, 'wifi', 'Feature 1')
|
||||
, (4, 'information', 'Feature 2')
|
||||
$$,
|
||||
'Should have added all two campsite type features'
|
||||
);
|
||||
|
||||
select is_empty(
|
||||
$$ select * from campsite_type_feature_i18n $$,
|
||||
'Should not have added any translation for campsite type features.'
|
||||
);
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,204 @@
|
|||
-- Test campsite_type_feature
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(41);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_table('campsite_type_feature');
|
||||
select has_pk('campsite_type_feature');
|
||||
select table_privs_are('campsite_type_feature', 'guest', array['SELECT']);
|
||||
select table_privs_are('campsite_type_feature', 'employee', array['SELECT']);
|
||||
select table_privs_are('campsite_type_feature', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||
select table_privs_are('campsite_type_feature', 'authenticator', array[]::text[]);
|
||||
|
||||
select has_column('campsite_type_feature', 'campsite_type_feature_id');
|
||||
select col_is_pk('campsite_type_feature', 'campsite_type_feature_id');
|
||||
select col_type_is('campsite_type_feature', 'campsite_type_feature_id', 'integer');
|
||||
select col_not_null('campsite_type_feature', 'campsite_type_feature_id');
|
||||
select col_hasnt_default('campsite_type_feature', 'campsite_type_feature_id');
|
||||
|
||||
select has_column('campsite_type_feature', 'campsite_type_id');
|
||||
select col_is_fk('campsite_type_feature', 'campsite_type_id');
|
||||
select fk_ok('campsite_type_feature', 'campsite_type_id', 'campsite_type', 'campsite_type_id');
|
||||
select col_type_is('campsite_type_feature', 'campsite_type_id', 'integer');
|
||||
select col_not_null('campsite_type_feature', 'campsite_type_id');
|
||||
select col_hasnt_default('campsite_type_feature', 'campsite_type_id');
|
||||
|
||||
select has_column('campsite_type_feature', 'icon_name');
|
||||
select col_is_fk('campsite_type_feature', 'icon_name');
|
||||
select fk_ok('campsite_type_feature', 'icon_name', 'icon', 'icon_name');
|
||||
select col_type_is('campsite_type_feature', 'icon_name', 'text');
|
||||
select col_not_null('campsite_type_feature', 'icon_name');
|
||||
select col_hasnt_default('campsite_type_feature', 'icon_name');
|
||||
|
||||
select has_column('campsite_type_feature', 'name');
|
||||
select col_type_is('campsite_type_feature', 'name', 'text');
|
||||
select col_not_null('campsite_type_feature', 'name');
|
||||
select col_hasnt_default('campsite_type_feature', 'name');
|
||||
|
||||
|
||||
set client_min_messages to warning;
|
||||
truncate campsite_type_feature cascade;
|
||||
truncate campsite_type cascade;
|
||||
truncate media cascade;
|
||||
truncate media_content cascade;
|
||||
truncate company_host cascade;
|
||||
truncate company_user cascade;
|
||||
truncate company cascade;
|
||||
truncate auth."user" cascade;
|
||||
reset client_min_messages;
|
||||
|
||||
insert into auth."user" (user_id, email, name, password, cookie, cookie_expires_at)
|
||||
values (1, 'demo@tandem.blog', 'Demo', 'test', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||
, (5, 'admin@tandem.blog', 'Demo', 'test', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||
;
|
||||
|
||||
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_lang_tag)
|
||||
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 'ca')
|
||||
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 'ca')
|
||||
;
|
||||
|
||||
insert into company_user (company_id, user_id, role)
|
||||
values (2, 1, 'admin')
|
||||
, (4, 5, 'admin')
|
||||
;
|
||||
|
||||
insert into company_host (company_id, host)
|
||||
values (2, 'co2')
|
||||
, (4, 'co4')
|
||||
;
|
||||
|
||||
insert into media_content (media_type, bytes)
|
||||
values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};')
|
||||
;
|
||||
|
||||
insert into media (media_id, company_id, original_filename, content_hash)
|
||||
values (6, 2, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
, (8, 4, 'cover4.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
;
|
||||
|
||||
insert into campsite_type (campsite_type_id, company_id, name, media_id, dogs_allowed, max_campers)
|
||||
values (16, 2, 'Wooden lodge', 6, false, 7)
|
||||
, (18, 4, 'Bungalow', 8, false, 6)
|
||||
;
|
||||
|
||||
insert into campsite_type_feature (campsite_type_id, icon_name, name)
|
||||
values (16, 'information', 'Feature 16.1')
|
||||
, (18, 'wifi', 'Feature 18.1')
|
||||
;
|
||||
|
||||
prepare campsite_feature_data as
|
||||
select campsite_type_id, name
|
||||
from campsite_type_feature
|
||||
;
|
||||
|
||||
set role guest;
|
||||
select bag_eq(
|
||||
'campsite_feature_data',
|
||||
$$ values (16, 'Feature 16.1')
|
||||
, (18, 'Feature 18.1')
|
||||
$$,
|
||||
'Everyone should be able to list all campsite type features across all companies'
|
||||
);
|
||||
reset role;
|
||||
|
||||
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2');
|
||||
|
||||
select lives_ok(
|
||||
$$ insert into campsite_type_feature(campsite_type_id, icon_name, name) values (16, 'castle', 'Feature 16.2') $$,
|
||||
'Admin from company 2 should be able to insert a new campsite type feature to that company.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'campsite_feature_data',
|
||||
$$ values (16, 'Feature 16.1')
|
||||
, (16, 'Feature 16.2')
|
||||
, (18, 'Feature 18.1')
|
||||
$$,
|
||||
'The new row should have been added'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ update campsite_type_feature set name = 'Feature 16-2' where campsite_type_id = 16 and name = 'Feature 16.2' $$,
|
||||
'Admin from company 2 should be able to update campsite type feature of that company.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'campsite_feature_data',
|
||||
$$ values (16, 'Feature 16.1')
|
||||
, (16, 'Feature 16-2')
|
||||
, (18, 'Feature 18.1')
|
||||
$$,
|
||||
'The row should have been updated.'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ delete from campsite_type_feature where campsite_type_id = 16 and name = 'Feature 16-2' $$,
|
||||
'Admin from company 2 should be able to delete campsite type feature from that company.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'campsite_feature_data',
|
||||
$$ values (16, 'Feature 16.1')
|
||||
, (18, 'Feature 18.1')
|
||||
$$,
|
||||
'The row should have been deleted.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into campsite_type_feature (campsite_type_id, icon_name, name) values (18, 'toilet', 'Feature 18.2') $$,
|
||||
'42501', 'new row violates row-level security policy for table "campsite_type_feature"',
|
||||
'Admin from company 2 should NOT be able to insert new campsite type features to company 4.'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ update campsite_type_feature set name = 'Feature 18-1' where campsite_type_id = 18 $$,
|
||||
'Admin from company 2 should not be able to update campsite types of company 4, but no error if campsite_type_id is not changed.'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'campsite_feature_data',
|
||||
$$ values (16, 'Feature 16.1')
|
||||
, (18, 'Feature 18.1')
|
||||
$$,
|
||||
'No row should have been changed.'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ update campsite_type_feature set campsite_type_id = 18 where campsite_type_id = 16 $$,
|
||||
'42501', 'new row violates row-level security policy for table "campsite_type_feature"',
|
||||
'Admin from company 2 should NOT be able to move campsite type feature to one of company 4'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ delete from campsite_type_feature where campsite_type_id = 18 $$,
|
||||
'Admin from company 2 should NOT be able to delete campsite type from company 4, but not error is thrown'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
'campsite_feature_data',
|
||||
$$ values (16, 'Feature 16.1')
|
||||
, (18, 'Feature 18.1')
|
||||
$$,
|
||||
'No row should have been changed'
|
||||
);
|
||||
|
||||
select throws_ok(
|
||||
$$ insert into campsite_type_feature (campsite_type_id, icon_name, name) values (16, 'baby', ' ') $$,
|
||||
'23514', 'new row for relation "campsite_type_feature" violates check constraint "name_not_empty"',
|
||||
'Should not be able to insert campsite type features with a blank name.'
|
||||
);
|
||||
|
||||
reset role;
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
-- Test campsite_type_feature_i18n
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(23);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_table('campsite_type_feature_i18n');
|
||||
select has_pk('campsite_type_feature_i18n');
|
||||
select col_is_pk('campsite_type_feature_i18n', array['campsite_type_feature_id', 'lang_tag']);
|
||||
select table_privs_are('campsite_type_feature_i18n', 'guest', array['SELECT']);
|
||||
select table_privs_are('campsite_type_feature_i18n', 'employee', array['SELECT']);
|
||||
select table_privs_are('campsite_type_feature_i18n', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||
select table_privs_are('campsite_type_feature_i18n', 'authenticator', array[]::text[]);
|
||||
|
||||
select has_column('campsite_type_feature_i18n', 'campsite_type_feature_id');
|
||||
select col_is_fk('campsite_type_feature_i18n', 'campsite_type_feature_id');
|
||||
select fk_ok('campsite_type_feature_i18n', 'campsite_type_feature_id', 'campsite_type_feature', 'campsite_type_feature_id');
|
||||
select col_type_is('campsite_type_feature_i18n', 'campsite_type_feature_id', 'integer');
|
||||
select col_not_null('campsite_type_feature_i18n', 'campsite_type_feature_id');
|
||||
select col_hasnt_default('campsite_type_feature_i18n', 'campsite_type_feature_id');
|
||||
|
||||
select has_column('campsite_type_feature_i18n', 'lang_tag');
|
||||
select col_is_fk('campsite_type_feature_i18n', 'lang_tag');
|
||||
select fk_ok('campsite_type_feature_i18n', 'lang_tag', 'language', 'lang_tag');
|
||||
select col_type_is('campsite_type_feature_i18n', 'lang_tag', 'text');
|
||||
select col_not_null('campsite_type_feature_i18n', 'lang_tag');
|
||||
select col_hasnt_default('campsite_type_feature_i18n', 'lang_tag');
|
||||
|
||||
select has_column('campsite_type_feature_i18n', 'name');
|
||||
select col_type_is('campsite_type_feature_i18n', 'name', 'text');
|
||||
select col_not_null('campsite_type_feature_i18n', 'name');
|
||||
select col_hasnt_default('campsite_type_feature_i18n', 'name');
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
-- Test edit_campsite_type_feature
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(13);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_function('camper', 'edit_campsite_type_feature', array['integer', 'text', 'text']);
|
||||
select function_lang_is('camper', 'edit_campsite_type_feature', array['integer', 'text', 'text'], 'sql');
|
||||
select function_returns('camper', 'edit_campsite_type_feature', array['integer', 'text', 'text'], 'integer');
|
||||
select isnt_definer('camper', 'edit_campsite_type_feature', array['integer', 'text', 'text']);
|
||||
select volatility_is('camper', 'edit_campsite_type_feature', array['integer', 'text', 'text'], 'volatile');
|
||||
select function_privs_are('camper', 'edit_campsite_type_feature', array ['integer', 'text', 'text'], 'guest', array[]::text[]);
|
||||
select function_privs_are('camper', 'edit_campsite_type_feature', array ['integer', 'text', 'text'], 'employee', array[]::text[]);
|
||||
select function_privs_are('camper', 'edit_campsite_type_feature', array ['integer', 'text', 'text'], 'admin', array['EXECUTE']);
|
||||
select function_privs_are('camper', 'edit_campsite_type_feature', array ['integer', 'text', 'text'], 'authenticator', array[]::text[]);
|
||||
|
||||
|
||||
set client_min_messages to warning;
|
||||
truncate campsite_type_feature_i18n cascade;
|
||||
truncate campsite_type_feature cascade;
|
||||
truncate campsite_type cascade;
|
||||
truncate media cascade;
|
||||
truncate media_content cascade;
|
||||
truncate company cascade;
|
||||
reset client_min_messages;
|
||||
|
||||
|
||||
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_lang_tag)
|
||||
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 'ca')
|
||||
;
|
||||
|
||||
insert into media_content (media_type, bytes)
|
||||
values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};')
|
||||
;
|
||||
|
||||
insert into media (media_id, company_id, original_filename, content_hash)
|
||||
values (2, 1, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
;
|
||||
|
||||
insert into campsite_type (campsite_type_id, company_id, media_id, name, description, active, dogs_allowed, max_campers)
|
||||
values (3, 1, 2, 'Type A', '<p>A</p>', true, false, 4)
|
||||
;
|
||||
|
||||
insert into campsite_type_feature (campsite_type_feature_id, campsite_type_id, icon_name, name)
|
||||
values (4, 3, 'information', 'Feature 1')
|
||||
, (5, 3, 'wifi', 'Feature 2')
|
||||
;
|
||||
|
||||
select lives_ok(
|
||||
$$ select edit_campsite_type_feature(4, 'toilet', 'Feature A') $$,
|
||||
'Should be able to edit the first feature'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ select edit_campsite_type_feature(5, 'baby', 'Feature B') $$,
|
||||
'Should be able to edit the second feature'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
$$ select campsite_type_feature_id, campsite_type_id, icon_name, name from campsite_type_feature $$,
|
||||
$$ values (4, 3, 'toilet', 'Feature A')
|
||||
, (5, 3, 'baby', 'Feature B')
|
||||
$$,
|
||||
'Should have updated all campsite type features.'
|
||||
);
|
||||
|
||||
select is_empty(
|
||||
$$ select * from campsite_type_feature_i18n $$,
|
||||
'Should not have added any translation for campsite type features.'
|
||||
);
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,85 @@
|
|||
-- Test translate_campsite_type_feature
|
||||
set client_min_messages to warning;
|
||||
create extension if not exists pgtap;
|
||||
reset client_min_messages;
|
||||
|
||||
begin;
|
||||
|
||||
select plan(13);
|
||||
|
||||
set search_path to camper, public;
|
||||
|
||||
select has_function('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text']);
|
||||
select function_lang_is('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'sql');
|
||||
select function_returns('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'void');
|
||||
select isnt_definer('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text']);
|
||||
select volatility_is('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'volatile');
|
||||
select function_privs_are('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'guest', array[]::text[]);
|
||||
select function_privs_are('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'employee', array[]::text[]);
|
||||
select function_privs_are('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'admin', array['EXECUTE']);
|
||||
select function_privs_are('camper', 'translate_campsite_type_feature', array['integer', 'text', 'text'], 'authenticator', array[]::text[]);
|
||||
|
||||
|
||||
set client_min_messages to warning;
|
||||
truncate campsite_type_feature_i18n cascade;
|
||||
truncate campsite_type_feature cascade;
|
||||
truncate campsite_type cascade;
|
||||
truncate media cascade;
|
||||
truncate media_content cascade;
|
||||
truncate company cascade;
|
||||
reset client_min_messages;
|
||||
|
||||
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_lang_tag)
|
||||
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 'ca')
|
||||
;
|
||||
|
||||
insert into media_content (media_type, bytes)
|
||||
values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};')
|
||||
;
|
||||
|
||||
insert into media (media_id, company_id, original_filename, content_hash)
|
||||
values (2, 1, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
|
||||
;
|
||||
|
||||
insert into campsite_type (campsite_type_id, company_id, slug, media_id, name, description, active, dogs_allowed, max_campers)
|
||||
values (3, 1, '87452b88-b48f-48d3-bb6c-0296de64164e', 2, 'Type A', '<p>A</p>', true, false, 4)
|
||||
;
|
||||
|
||||
insert into campsite_type_feature (campsite_type_feature_id, campsite_type_id, icon_name, name)
|
||||
values (4, 3, 'toilet', 'Feature 1')
|
||||
, (5, 3, 'toilet', 'Feature 2')
|
||||
;
|
||||
|
||||
insert into campsite_type_feature_i18n (campsite_type_feature_id, lang_tag, name)
|
||||
values (5, 'ca', 'carácter2')
|
||||
;
|
||||
|
||||
select lives_ok(
|
||||
$$ select translate_campsite_type_feature(4, 'ca', 'Carácter 1') $$,
|
||||
'Should be able to translate the first feature'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ select translate_campsite_type_feature(5, 'es', 'Característica 2') $$,
|
||||
'Should be able to translate the second feature'
|
||||
);
|
||||
|
||||
select lives_ok(
|
||||
$$ select translate_campsite_type_feature(5, 'ca', 'Carácter 2') $$,
|
||||
'Should be able to overwrite the catalan translation of the second feature'
|
||||
);
|
||||
|
||||
select bag_eq(
|
||||
$$ select campsite_type_feature_id, lang_tag, name from campsite_type_feature_i18n $$,
|
||||
$$ values (4, 'ca', 'Carácter 1')
|
||||
, (5, 'ca', 'Carácter 2')
|
||||
, (5, 'es', 'Característica 2')
|
||||
$$,
|
||||
'Should have added and updated all translations.'
|
||||
);
|
||||
|
||||
|
||||
select *
|
||||
from finish();
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,7 @@
|
|||
-- Verify camper:add_campsite_type_feature on pg
|
||||
|
||||
begin;
|
||||
|
||||
select has_function_privilege('camper.add_campsite_type_feature(uuid, text, text)', 'execute');
|
||||
|
||||
rollback;
|
|
@ -4,15 +4,20 @@ begin;
|
|||
|
||||
set search_path to camper;
|
||||
|
||||
select 1 / count(*) from icon where icon_name = 'area';
|
||||
select 1 / count(*) from icon where icon_name = 'baby';
|
||||
select 1 / count(*) from icon where icon_name = 'ball';
|
||||
select 1 / count(*) from icon where icon_name = 'bicycle';
|
||||
select 1 / count(*) from icon where icon_name = 'campfire';
|
||||
select 1 / count(*) from icon where icon_name = 'castle';
|
||||
select 1 / count(*) from icon where icon_name = 'ecofriendly';
|
||||
select 1 / count(*) from icon where icon_name = 'fridge';
|
||||
select 1 / count(*) from icon where icon_name = 'hvac';
|
||||
select 1 / count(*) from icon where icon_name = 'information';
|
||||
select 1 / count(*) from icon where icon_name = 'kayak';
|
||||
select 1 / count(*) from icon where icon_name = 'nopet';
|
||||
select 1 / count(*) from icon where icon_name = 'outing';
|
||||
select 1 / count(*) from icon where icon_name = 'person';
|
||||
select 1 / count(*) from icon where icon_name = 'pool';
|
||||
select 1 / count(*) from icon where icon_name = 'puzzle';
|
||||
select 1 / count(*) from icon where icon_name = 'restaurant';
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
-- Verify camper:campsite_type_feature on pg
|
||||
|
||||
begin;
|
||||
|
||||
select campsite_type_feature_id
|
||||
, campsite_type_id
|
||||
, icon_name
|
||||
, name
|
||||
from camper.campsite_type_feature
|
||||
where false;
|
||||
|
||||
select 1 / count(*) from pg_class where oid = 'camper.campsite_type_feature'::regclass and relrowsecurity;
|
||||
select 1 / count(*) from pg_policy where polname = 'guest_ok' and polrelid = 'camper.campsite_type_feature'::regclass;
|
||||
select 1 / count(*) from pg_policy where polname = 'insert_to_company' and polrelid = 'camper.campsite_type_feature'::regclass;
|
||||
select 1 / count(*) from pg_policy where polname = 'update_company' and polrelid = 'camper.campsite_type_feature'::regclass;
|
||||
select 1 / count(*) from pg_policy where polname = 'delete_from_company' and polrelid = 'camper.campsite_type_feature'::regclass;
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,11 @@
|
|||
-- Verify camper:campsite_type_feature_i18n on pg
|
||||
|
||||
begin;
|
||||
|
||||
select campsite_type_feature_id
|
||||
, lang_tag
|
||||
, name
|
||||
from camper.campsite_type_feature_i18n
|
||||
where false;
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,7 @@
|
|||
-- Verify camper:edit_campsite_type_feature on pg
|
||||
|
||||
begin;
|
||||
|
||||
select has_function_privilege('camper.edit_campsite_type_feature(integer, text, text)', 'execute');
|
||||
|
||||
rollback;
|
|
@ -0,0 +1,7 @@
|
|||
-- Verify camper:translate_campsite_type_feature on pg
|
||||
|
||||
begin;
|
||||
|
||||
select has_function_privilege('camper.translate_campsite_type_feature(integer, text, text)', 'execute');
|
||||
|
||||
rollback;
|
|
@ -3,6 +3,9 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.icon_area {
|
||||
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 29.52905 28.08545" xmlns="http://www.w3.org/2000/svg"%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="24.65173 25.48701 24.65173 26.48701 23.65173 26.48701"/%3E%%3Cline stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="0 0 1.87099 4.67747" stroke="%23303334" fill="none" y2="26.48701" x2="8.21606" y1="26.48701" x1="18.97425"/%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="5.87732 26.48701 4.87732 26.48701 4.87732 25.48701"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="0 0 1.76066 4.40165" stroke="%23303334" fill="none" y2="4.79927" x2="4.87732" y1="21.08536" x1="4.87732"/%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="4.87732 2.59844 4.87732 1.59844 5.87732 1.59844"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="0 0 1.87099 4.67747" stroke="%23303334" fill="none" y2="1.59844" x2="21.31299" y1="1.59844" x1="10.5548"/%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="23.65173 1.59844 24.65173 1.59844 24.65173 2.59844"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="0 0 1.76066 4.40165" stroke="%23303334" fill="none" y2="23.28618" x2="24.65173" y1="7.00009" x1="24.65173"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="0 0 2 5" stroke="%23303334" fill="none" y2="20.16764" x2="22.97111" y1="20.16764" x1="6.55794"/%3E%3C/svg%3E');
|
||||
}
|
||||
.icon_baby {
|
||||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="%23000000" height="32" width="32"%3E%3Cpath d="M92,136a8,8,0,1,1,8-8A8,8,0,0,1,92,136Zm72-16a8,8,0,1,0,8,8A8,8,0,0,0,164,120Zm-10.13,44.62a49,49,0,0,1-51.74,0,4,4,0,0,0-4.26,6.76,57,57,0,0,0,60.26,0,4,4,0,1,0-4.26-6.76ZM228,128A100,100,0,1,1,128,28,100.11,100.11,0,0,1,228,128Zm-8,0a92.11,92.11,0,0,0-90.06-92C116.26,54.07,116,71.83,116,72a12,12,0,0,0,24,0,4,4,0,0,1,8,0,20,20,0,0,1-40,0c0-.78.16-17.31,12-35.64A92,92,0,1,0,220,128Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
@ -23,10 +26,18 @@
|
|||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="%23000000" height="32" width="32"%3E%3Cpath d="M200,28H184a12,12,0,0,0-12,12V56a4,4,0,0,1-4,4H152a4,4,0,0,1-4-4V40a12,12,0,0,0-12-12H120a12,12,0,0,0-12,12V56a4,4,0,0,1-4,4H88a4,4,0,0,1-4-4V40A12,12,0,0,0,72,28H56A12,12,0,0,0,44,40V84.69a11.93,11.93,0,0,0,3.51,8.48l11.32,11.32A4,4,0,0,1,60,107.31V216a12,12,0,0,0,12,12H184a12,12,0,0,0,12-12V107.31a4,4,0,0,1,1.17-2.82l11.32-11.32A11.93,11.93,0,0,0,212,84.69V40A12,12,0,0,0,200,28ZM148,220H108V152a20,20,0,0,1,40,0ZM204,84.69a4,4,0,0,1-1.17,2.82L191.51,98.83a11.93,11.93,0,0,0-3.51,8.48V216a4,4,0,0,1-4,4H156V152a28,28,0,0,0-56,0v68H72a4,4,0,0,1-4-4V107.31a11.93,11.93,0,0,0-3.51-8.48L53.17,87.51A4,4,0,0,1,52,84.69V40a4,4,0,0,1,4-4H72a4,4,0,0,1,4,4V56A12,12,0,0,0,88,68h16a12,12,0,0,0,12-12V40a4,4,0,0,1,4-4h16a4,4,0,0,1,4,4V56a12,12,0,0,0,12,12h16a12,12,0,0,0,12-12V40a4,4,0,0,1,4-4h16a4,4,0,0,1,4,4Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_ecofriendly {
|
||||
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 29.52905 28.08545" xmlns="http://www.w3.org/2000/svg"%3E%3Cpolygon stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="20.03209 6.02239 14.30328 13.46984 17.16768 13.46984 13.15752 18.62577 26.90666 18.62577 22.89649 13.46984 25.7609 13.46984 20.03209 6.02239"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="22.06306" x2="20.03209" y1="18.62577" x1="20.03209"/%3E%3Cpath stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" d="m12.38607,21.36565v-4.18444c0-.38517-.31224-.69741-.69741-.69741h-2.78962c-.38517,0-.69741.31224-.69741.69741v4.18444c0,.38517-.31224.69741-.69741.69741H3.31979c-.38517,0-.69741-.31224-.69741-.69741v-8.06027c.00002-.19652.08295-.38392.2284-.51608l6.97406-6.58526c.2661-.24221.67278-.24221.93888,0l6.97406,6.58526c.14545.13216.22838.31956.2284.51608v8.06027c0,.38517-.31224.69741-.69741.69741h-4.18531c-.38517,0-.69741-.31224-.69741-.69741Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_fridge {
|
||||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17.57617 28.04395"%3E%3Cpath stroke-width="0" d="m15.62988,0H1.94629C.87305,0,0,.87305,0,1.94629v25.59766c0,.27637.22363.5.5.5h16.57617c.27637,0,.5-.22363.5-.5V1.94629c0-1.07324-.87305-1.94629-1.94629-1.94629ZM1.94629,1h13.68359c.52148,0,.94629.42432.94629.94629v7.41357H1V1.94629c0-.52197.42432-.94629.94629-.94629Zm-.94629,26.04395V10.35986h15.57617v16.68408H1Z"/%3E%3Cpath stroke-width="0" d="m3.64453,5.36426h2.04248c.27637,0,.5-.22363.5-.5s-.22363-.5-.5-.5h-2.04248c-.27637,0-.5.22363-.5.5s.22363.5.5.5Z"/%3E%3Cpath stroke-width="0" d="m5.68701,13.271h-2.04248c-.27637,0-.5.22363-.5.5s.22363.5.5.5h2.04248c.27637,0,.5-.22363.5-.5s-.22363-.5-.5-.5Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_hvac {
|
||||
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 29.52905 28.08545" xmlns="http://www.w3.org/2000/svg"%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="22.04885" x2="12.97909" y1="12.87674" x1="12.97909"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="12.87674" x2="12.97909" y1="11.15696" x1="11.25932"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="22.04885" x2="12.97909" y1="23.76863" x1="11.25932"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="17.4628" x2="12.97909" y1="15.16977" x1="9.00713"/%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="6.67326 15.74302 9.00713 15.16977 8.39303 12.87674"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="17.4628" x2="12.97909" y1="19.75582" x1="9.00713"/%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="8.39303 22.04885 9.00713 19.75582 6.67326 19.18257"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="9.63923" x2="15.03222" y1="11.3157" x1="15.03222"/%3E%3Cpath stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" d="m15.03222,13.55101c2.16042,0,3.91179,1.75137,3.91179,3.91179s-1.75137,3.91179-3.91179,3.91179"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="11.87453" x2="20.62049" y1="12.99218" x1="19.50284"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="23.05106" x2="20.62049" y1="21.93341" x1="19.50284"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="25.28637" x2="15.03222" y1="23.60989" x1="15.03222"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="17.4628" x2="22.85579" y1="17.4628" x1="21.17931"/%3E%3Cpolyline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" points="27.00983 19.18257 27.00983 11.50591 14.76453 2.79908 2.51922 11.50591 2.51922 19.18257 2.51922 11.50591 14.76453 2.79908"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_information {
|
||||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="%23000000" height="32" width="32"%3E%3Cpath d="M140,176a4,4,0,0,1-4,4,12,12,0,0,1-12-12V128a4,4,0,0,0-4-4,4,4,0,0,1,0-8,12,12,0,0,1,12,12v40a4,4,0,0,0,4,4A4,4,0,0,1,140,176ZM124,92a8,8,0,1,0-8-8A8,8,0,0,0,124,92Zm104,36A100,100,0,1,1,128,28,100.11,100.11,0,0,1,228,128Zm-8,0a92,92,0,1,0-92,92A92.1,92.1,0,0,0,220,128Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
@ -35,10 +46,18 @@
|
|||
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 29.52905 28.08545" xmlns="http://www.w3.org/2000/svg" id="uuid-87ec619a-4896-40b8-8478-aa076dee3f7c"%3E%3Cpath stroke-width="0" d="m29.46728,11.26074l-.57617-2.15186c-.08398-.31299-.24609-.59229-.45801-.78613-.26758-.24658-.59863-.3418-.90625-.25879l-3.4834.93213c-.26953.07227-.48535.26807-.6084.54932l-.5752,1.30713c-.0719.16376-.10333.34686-.10742.53485l-3.05627.81787c-.23956-3.37067-1.03204-8.79126-2.35193-10.66425l-.22363-.31836C16.58057.45752,15.69971.00049,14.76318,0h-.00049c-.94873,0-1.80566.44434-2.35156,1.21875-1.71973,2.44043-2.65771,9.75146-2.65771,12.82422,0,.24457.00812.52399.0199.81769l-3.25604.87134c-.09741-.16071-.21613-.30347-.36005-.40924l-1.15088-.84424c-.24854-.18213-.53125-.24463-.80127-.17236l-3.48389.93164c-.56689.15234-.85693.84961-.65918,1.58691l.57617,2.15137c.0835.31348.24561.59277.45654.78613.20508.18848.4458.28809.68506.28809.07471,0,.14893-.00879.22168-.02832l3.48486-.93359c.26807-.07227.48389-.26758.60693-.54883l.57568-1.30664c.07172-.16357.10309-.3465.10718-.5343l3.05591-.81793c.25531,3.52673,1.14368,8.94983,2.5791,10.98602.5459.77441,1.40332,1.21875,2.35205,1.21875.93652,0,1.81738-.45703,2.35645-1.22266l.22461-.31738c1.60352-2.27637,2.43066-9.79492,2.43066-12.50244,0-.23499-.00854-.51709-.021-.81805l3.25732-.87183c.09747.16071.21625.30347.36035.40912l1.15039.84473c.18066.13281.38086.20166.5791.20166.07422,0,.14941-.00977.22168-.0293l3.48535-.93262c.56641-.15234.85645-.84863.65918-1.58594Zm-24.24072,6.86182l-3.41602.93262c-.03516-.01465-.14844-.12109-.20654-.33691l-.57617-2.15137c-.05713-.21484-.01318-.3623-.04688-.3623h-.00098l3.4165-.93164s.00586.00293.01709.01074c.00049,0,.00098.00098.00098.00098l1.00842.74017-1.90881.5108c-.2666.07227-.4248.3457-.35352.6123.05957.22363.26172.37109.48242.37109.04297,0,.08643-.00586.12988-.0166l1.91559-.5127-.46198,1.13281Zm5.52686-4.07959c0-3.07959.93994-10.06934,2.4751-12.24805.35596-.50488.91504-.79492,1.53418-.79492.62109.00049,1.18213.2915,1.54053.79932l.22266.31689c1.17902,1.67261,1.96533,7.08936,2.18457,10.35278l-1.50305.40228c-.19397-2.55505-1.02423-4.83514-2.44324-4.83514-1.63379,0-2.48828,3.02197-2.48828,6.00684,0,.04913.00214.09814.00262.14728l-1.51538.40552c-.00574-.19403-.0097-.38147-.0097-.5528Zm2.52692-.12079c.02441-2.93951.89984-4.88605,1.48383-4.88605.53003,0,1.29828,1.6062,1.45496,4.09961l-2.93878.78644Zm2.96765.24115c-.02441,2.93933-.89978,4.88599-1.48383,4.88599-.53003,0-1.29834-1.60632-1.45496-4.09937l2.93878-.78662Zm2.52692-.12036c0,2.66846-.84961,9.94092-2.24902,11.92725l-.22363.31641c-.71387,1.01367-2.36084,1.01562-3.07373.00391-1.31152-1.86127-2.18622-7.22681-2.414-10.67285l1.50641-.4032c.19397,2.55505,1.02417,4.83484,2.44324,4.83484,1.63379,0,2.48828-3.02148,2.48828-6.00635,0-.04926-.00214-.09845-.00262-.14777l1.51514-.40558c.00659.20087.00995.38617.00995.55334Zm6.35742-1.23047s-.00684-.00293-.01855-.01123l-1.00897-.74091,1.90936-.51105c.26758-.07129.42578-.34521.35449-.6123-.07227-.26562-.3418-.42725-.6123-.35352l-1.91577.5127.46069-1.13379,3.41699-.93164c.03516.01416.14844.12012.20605.33691l.57617,2.15186c.05957.21973.01953.36816.04883.36133l-3.41699.93164Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_nopet {
|
||||
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 29.52905 28.08545" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" d="m17.21239,7.49301s-4.87977.84632-8.52421,5.99327c-2.16998,3.06461-2.2348,5.76054-2.16343,6.96413-.20971.12828-.41646.23744-.60915.31138-1.52884.5874-3.2956.47276-3.31213.47143-.4288-.03178-.80523.29289-.83649.72349-.03114.43058.29272.80523.72347.83649.02465.00178.21278.01443.51249.01443.7371,0,2.14964-.07768,3.47368-.58659.40917-.15748.83392-.40365,1.23448-.67824-.00552.04298-.00973.08677-.00973.1312,0,.54621.44274.98878.98878.98878h6.45055l1.19972-.00985-.13038-.52151c-.09972-.39887-.3556-.74091-.71009-.94918h0c-.23523-.1382-.5031-.21107-.77593-.21107h-2.41299c1.63184-.71439,2.2461-2.1492,1.45294-3.47113l1.43136-.57254,2.78807,4.33263c.01879.03918.04916.06965.06582.10978.29509.71048,1.15391,1.28302,2.02047,1.28302h1.70989v-.33504c0-.49573-.28234-.94819-.72763-1.16605l-.35082-.11881c-.36735-.12441-.66131-.40423-.80365-.76502l-1.90756-4.83493,1.54591-4.46211,4.3585-1.15763.43585-1.29053c.16876-.49968-.12132-1.03771-.63151-1.17133l-1.93096-.54479c-.13345-1.31408-1.37293-1.72864-2.77284-1.4432-1.14081.23261-1.87678.73329-1.81146,1.89575.00439.07821.01285.15499.02897.23377h0Z"/%3E%3Cpath stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" d="m19.69654,6.92365l-.56872,1.6591c-.13062.38105-.45388.66399-.84887.74299h0c-.45328.09066-.90313-.1704-1.04931-.60894l-.0304-.09119"/%3E%3Cline stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" y2="25.06162" x2="24.09052" y1="3.02383" x1="2.05273"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_outing {
|
||||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="%23000000" height="32" width="32"%3E%3Cpath d="M164,44.17V32a20,20,0,0,0-20-20H112A20,20,0,0,0,92,32V44.17A52.05,52.05,0,0,0,44,96V216a12,12,0,0,0,12,12H200a12,12,0,0,0,12-12V96A52.05,52.05,0,0,0,164,44.17ZM112,20h32a12,12,0,0,1,12,12V44H100V32A12,12,0,0,1,112,20Zm60,144H84V152a12,12,0,0,1,12-12h64a12,12,0,0,1,12,12Zm-88,8h56v12a4,4,0,0,0,8,0V172h24v48H84Zm120,44a4,4,0,0,1-4,4H180V152a20,20,0,0,0-20-20H96a20,20,0,0,0-20,20v68H56a4,4,0,0,1-4-4V96A44.05,44.05,0,0,1,96,52h64a44.05,44.05,0,0,1,44,44ZM148,88a4,4,0,0,1-4,4H112a4,4,0,0,1,0-8h32A4,4,0,0,1,148,88Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_person {
|
||||
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 29.52905 28.08545" xmlns="http://www.w3.org/2000/svg"%3E%3Ccircle stroke-linejoin="round" stroke-linecap="round" stroke="%23000" fill="none" r="2.55477" cy="5.10916" cx="14.76453"/%3E%3Cpath stroke-linejoin="round" stroke-linecap="round" stroke="%23303334" fill="none" d="m17.01911,9.36711c.7333.00012,1.43119.31534,1.91608.86543l4.82426,5.46934c.49972.49972.49972,1.30991,0,1.80963s-1.30991.49972-1.80963,0l-3.77787-3.03485,2.43448,9.25359c.28892.64361.00138,1.39957-.64222,1.68848-.63062.28309-1.37202.01317-1.67304-.60909l-3.52558-6.07503-3.52558,6.07503c-.30721.63508-1.07109.90086-1.70617.59365-.62226-.30102-.89218-1.04242-.60909-1.67304l2.43448-9.25359-3.78,3.03273c-.49972.49972-1.30991.49972-1.80963,0s-.49972-1.30991,0-1.80963l4.82639-5.46721c.48489-.55009,1.18278-.86531,1.91608-.86543h4.50704Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.icon_pool {
|
||||
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="%23000000" height="32" width="32"%3E%3Cpath d="M88,145.39a4,4,0,0,0,4-4V124h72v19.29a4,4,0,0,0,8,0V32a4,4,0,0,0-8,0V52H92V32a4,4,0,0,0-8,0V141.39A4,4,0,0,0,88,145.39ZM92,116V92h72v24Zm72-56V84H92V60ZM28,168a4,4,0,0,1,4-4c13.21,0,20.12,4.61,26.22,8.67,5.9,3.93,11,7.33,21.78,7.33s15.88-3.4,21.78-7.33c6.09-4.06,13-8.67,26.21-8.67s20.13,4.61,26.22,8.67c5.9,3.93,11,7.33,21.79,7.33s15.88-3.4,21.78-7.33c6.1-4.06,13-8.67,26.22-8.67a4,4,0,0,1,0,8c-10.79,0-15.88,3.4-21.78,7.33-6.1,4.06-13,8.67-26.22,8.67s-20.13-4.61-26.22-8.67c-5.9-3.93-11-7.33-21.79-7.33s-15.88,3.4-21.78,7.33c-6.09,4.06-13,8.67-26.21,8.67s-20.12-4.61-26.22-8.67C47.88,175.4,42.79,172,32,172A4,4,0,0,1,28,168Zm200,40a4,4,0,0,1-4,4c-10.79,0-15.88,3.4-21.78,7.33-6.1,4.06-13,8.67-26.22,8.67s-20.13-4.61-26.22-8.67c-5.9-3.93-11-7.33-21.79-7.33s-15.88,3.4-21.78,7.33c-6.09,4.06-13,8.67-26.21,8.67s-20.12-4.61-26.22-8.67C47.88,215.4,42.79,212,32,212a4,4,0,0,1,0-8c13.21,0,20.12,4.61,26.22,8.67,5.9,3.93,11,7.33,21.78,7.33s15.88-3.4,21.78-7.33c6.09-4.06,13-8.67,26.21-8.67s20.13,4.61,26.22,8.67c5.9,3.93,11,7.33,21.79,7.33s15.88-3.4,21.78-7.33c6.1-4.06,13-8.67,26.22-8.67A4,4,0,0,1,228,208Z"/%3E%3C/svg%3E');
|
||||
}
|
||||
|
|
|
@ -235,10 +235,13 @@ h1 a .name {
|
|||
left: -9999em;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
nav ul, .campsite_type_features ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -666,18 +669,32 @@ dt {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.campsite_type_features li {
|
||||
flex: 1;
|
||||
font-size: 2.4rem;
|
||||
text-align: center;
|
||||
justify-content: space-between;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top center;
|
||||
background-size: 7.2rem 7.2rem;
|
||||
padding-top: 7.2rem;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
footer div, .campsite_type_features, .campsite_type_detail {
|
||||
padding: 5rem 0;
|
||||
border-top: 3px solid black;
|
||||
}
|
||||
|
||||
footer div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 5rem 0;
|
||||
margin: 0 2.5rem;
|
||||
border-top: 3px solid black;
|
||||
border-bottom: 3px solid black;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureForm*/ -}}
|
||||
{{ if .ID}}
|
||||
{{( pgettext "Edit Campsite Type Feature" "title" )}}
|
||||
{{ else }}
|
||||
{{( pgettext "New Campsite Type Feature" "title" )}}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureForm*/ -}}
|
||||
<form
|
||||
{{ if .ID }}
|
||||
data-hx-put="/admin/campsites/types/{{ .TypeSlug }}/features/{{ .ID }}"
|
||||
{{ else }}
|
||||
action="/admin/campsites/types/{{ .TypeSlug }}/features" method="post"
|
||||
{{ end }}
|
||||
>
|
||||
<h2>
|
||||
{{ if .ID }}
|
||||
{{( pgettext "Edit Campsite Type Feature" "title" )}}
|
||||
{{ else }}
|
||||
{{( pgettext "New Campsite Type Feature" "title" )}}
|
||||
{{ end }}
|
||||
</h2>
|
||||
{{ CSRFInput }}
|
||||
<fieldset>
|
||||
{{ with $field := .Icon -}}
|
||||
<fieldset class="icon-input">
|
||||
<legend>{{( pgettext "Icon" "input")}}</legend>
|
||||
<input type="hidden" name="{{ .Name }}"
|
||||
{{- range .Options }}
|
||||
{{ if $field.IsSelected .Value }} value="{{ .Value }}"{{ end }}
|
||||
{{- end }}
|
||||
>
|
||||
<ul>
|
||||
{{- range .Options }}
|
||||
<li>
|
||||
<button type="button" data-icon-name="{{ .Value }}" class="icon_{{ .Value }}"></button>
|
||||
</li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
{{ template "error-message" . }}
|
||||
</fieldset>
|
||||
{{- end }}
|
||||
{{ with .Name -}}
|
||||
<label>
|
||||
{{( pgettext "Name" "input")}}<br>
|
||||
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
|
||||
required {{ template "error-attrs" . }}><br>
|
||||
</label>
|
||||
{{ template "error-message" . }}
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
<footer>
|
||||
<button type="submit">
|
||||
{{ if .ID }}
|
||||
{{( pgettext "Update" "action" )}}
|
||||
{{ else }}
|
||||
{{( pgettext "Add" "action" )}}
|
||||
{{ end }}
|
||||
</button>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
<script type="module">
|
||||
import {setupIconInput} from "/static/camper.js";
|
||||
|
||||
setupIconInput(document.querySelector('.icon-input'));
|
||||
</script>
|
||||
{{- end }}
|
|
@ -0,0 +1,41 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{( pgettext "Campsite Type Features" "title" )}}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureIndex*/ -}}
|
||||
<a href="/admin/campsites/types/{{ .TypeSlug }}/features/new">{{( pgettext "Add Feature" "action" )}}</a>
|
||||
<h2>{{( pgettext "Campsite Type Features" "title" )}}</h2>
|
||||
{{ if .Features -}}
|
||||
<table class="services">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{( pgettext "Name" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Features -}}
|
||||
<tr>
|
||||
<td class="icon_{{ .Icon }}"><a href="{{ .URL }}">{{ .Name }}</a></td>
|
||||
<td>
|
||||
{{ range .Translations }}
|
||||
<a
|
||||
{{ if .Missing }}
|
||||
class="missing-translation"
|
||||
{{ end }}
|
||||
href="{{ .URL }}">{{ .Endonym }}</a>
|
||||
{{ end }}
|
||||
</td>
|
||||
</tr>
|
||||
{{- end }}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ else -}}
|
||||
<p>{{( gettext "No campsite type features added yet." )}}</p>
|
||||
{{- end }}
|
||||
{{- end }}
|
|
@ -0,0 +1,35 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
{{ define "title" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureL10nForm*/ -}}
|
||||
{{printf (pgettext "Translate Campsite Type Feature to %s" "title") .Locale.Endonym }}
|
||||
{{- end }}
|
||||
|
||||
{{ define "content" -}}
|
||||
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.featureL10nForm*/ -}}
|
||||
<form data-hx-put="/admin/campsites/types/{{ .TypeSlug }}/features/{{ .ID }}/{{ .Locale.Language }}">
|
||||
<h2>
|
||||
{{printf (pgettext "Translate Campsite Type Feature to %s" "title") .Locale.Endonym }}
|
||||
</h2>
|
||||
{{ CSRFInput }}
|
||||
<fieldset>
|
||||
{{ with .Name -}}
|
||||
<fieldset>
|
||||
<legend>{{( pgettext "Name" "input")}}</legend>
|
||||
{{( gettext "Source:" )}} {{ .Source }}<br>
|
||||
<label>
|
||||
{{( pgettext "Translation:" "input" )}}
|
||||
<input type="text" name="{{ .Name }}" value="{{ .Val }}"
|
||||
required {{ template "error-attrs" . }}><br>
|
||||
</label>
|
||||
{{ template "error-message" . }}
|
||||
</fieldset>
|
||||
{{- end }}
|
||||
</fieldset>
|
||||
<footer>
|
||||
<button type="submit">{{( pgettext "Translate" "action" )}}</button>
|
||||
</footer>
|
||||
</form>
|
||||
{{- end }}
|
|
@ -16,6 +16,7 @@
|
|||
<tr>
|
||||
<th scope="col">{{( pgettext "Name" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Features" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Options" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Carousel" "header" )}}</th>
|
||||
<th scope="col">{{( pgettext "Active" "campsite type" )}}</th>
|
||||
|
@ -34,8 +35,15 @@
|
|||
href="/admin/campsites/types/{{ $type.Slug }}/{{ .Language }}">{{ .Endonym }}</a>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td><a href="/admin/campsites/types/{{ .Slug }}/options">{{( pgettext "Edit Options" "action" )}}</a></td>
|
||||
<td><a href="/admin/campsites/types/{{ .Slug }}/slides">{{( pgettext "Edit Carousel" "action" )}}</a></td>
|
||||
<td>
|
||||
<a href="/admin/campsites/types/{{ .Slug }}/features">{{( pgettext "Edit Features" "action" )}}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/admin/campsites/types/{{ .Slug }}/options">{{( pgettext "Edit Options" "action" )}}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/admin/campsites/types/{{ .Slug }}/slides">{{( pgettext "Edit Carousel" "action" )}}</a>
|
||||
</td>
|
||||
<td>{{ if .Active }}{{( gettext "Yes" )}}{{ else }}{{( gettext "No" )}}{{ end }}</td>
|
||||
</tr>
|
||||
{{- end }}
|
||||
|
|
|
@ -56,7 +56,18 @@
|
|||
</article>
|
||||
{{- end }}
|
||||
|
||||
<article>
|
||||
{{ with .Features -}}
|
||||
<article class="campsite_type_features">
|
||||
<h3>{{( pgettext "Features" "title" )}}</h3>
|
||||
<ul>
|
||||
{{ range . -}}
|
||||
<li class="icon_{{ .Icon }}">{{ .Name }}</li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
</article>
|
||||
{{- end }}
|
||||
|
||||
<article class="campsite_type_detail">
|
||||
<section>
|
||||
<h3>{{( pgettext "Info" "title" )}}</h3>
|
||||
{{ .Info }}
|
||||
|
|
Loading…
Reference in New Issue