Add management of surroundings’ highlights (points of interest)

Customer does not want the new “masonry-like” design of the surroundings
page, and wants the same style they already had: a regular list with
text and photo, alternating the photo’s side.

And, of course, they want to be able to add and edit them themselves. It
is like another carousel, but with an additional rich-text description.

The photos that we had in that page are no longer of use.
This commit is contained in:
jordi fita mas 2024-01-16 01:25:25 +01:00
parent 8205bec34d
commit a0f9c10193
50 changed files with 2118 additions and 412 deletions

View File

@ -595,4 +595,56 @@ values (72, 77, 'en', 'Legend')
, (76, 103, 'es', 'Leyenda')
;
alter table surroundings_highlight alter column surroundings_highlight_id restart with 112;
select add_surroundings_highlight(52, 62, 'El Pont del Llierca', '<p>Pont destil romànic i bany natural a 400 m del càmping.</p>');
select add_surroundings_highlight(52, 63, 'Alta Garrotxa', '<p>Excursions pels voltants que no us podeu perdre:</p><ul><li>Sant Aniol dAgulla</li><li>La Cova del Bisbe</li><li>Santa Bàrbara de Pruneres</li></ul>');
select add_surroundings_highlight(52, 64, 'Sadernes', '<p>Zona descalada de Sadernes a 5 km del càmping</p><p>Escalada esportiva.</p><p>Descens de barrancs.</p>');
select add_surroundings_highlight(52, 65, 'Besalú', '<p>Vila comtal medieval a 15 minuts</p><p><a href="https://besalu.cat/">besalu.cat</a></p>');
select add_surroundings_highlight(52, 65, 'Parc natural de la zona volcànica de la Garrotxa', '<p>El millor exponent de paisatge volcànic de la península a només 20 minuts.</p><p><a href="https://ca.turismegarrotxa.com/">turismegarrotxa.com</a></p><p><a href="https://www.itinerannia.net/ca/">itinerannia.net</a></p>');
select add_surroundings_highlight(52, 66, 'Les millors platges a només una hora', '<p><a href="https://costabrava.org/">costabrava.org</a></p>');
select add_surroundings_highlight(52, 67, 'Empordà', '<p>Esplèndida comarca entre el Pirineu i el Mediterrani. Figueres i el Museu Dalí a només 30 minuts.</p><p><a href="https://ca.visitfigueres.cat/">visitfigueres.cat</a><br/><a href="https://www.salvador-dali.org/ca/">salvador-dali.org</a></p>');
select add_surroundings_highlight(52, 68, 'Denominació dOrígen Empordà', '<p>Una experiència inoblidable, la Ruta del vi DO Empordà.</p><p><a href="https://www.doemporda.cat/">doemporda.cat</a></p><p>Autor de la foto: Rafael Lopez-Monné</p>');
select add_surroundings_highlight(52, 69, 'Pirineus', '<p>Pirineu de Girona</p><p>Cims de quasi 3.000 metres, valls i paratges màgics com la Vall de Núria.</p><p><a href="https://www.valldenuria.cat/ca/">valldenuria.com</a></p>');
select add_surroundings_highlight(52, 70, 'Girona', '<p>Val la pena visitar Girona: us recomanem visitar el Call Jueu, les Rambles, la catedral i els jardins que lenvolten…</p><p><a href="https://www.girona.cat/turisme/cat/">Turisme Girona</a></p>');
select add_surroundings_highlight(52, 71, 'Barcelona', '<p>Barcelona és més que botigues o el Barça… Descobreix els seus barris i les seves «joies» i respira el seu ambient.</p><p><a href="https://www.barcelonaturisme.com/wv3/ca/">Turisme Barcelona</a></p>');
select order_surroundings_highlights('{112,113,114,115,116,117,118,119,120,121,122}');
select translate_surroundings_highlight(112, 'en', 'Bridge of Llierca', '<p>Romanesque style bridge and natural bath at only 400 m from the camp site.</p>');
select translate_surroundings_highlight(113, 'en', 'Alta Garrotxa', '<p>Walks in the neighbourhood that nobody should miss:</p><ul><li>Sant Aniol dAgulla</li><li>La Cova del Bisbe</li><li>Santa Bàrbara de Pruneres</li></ul>');
select translate_surroundings_highlight(114, 'en', 'Sadernes', '<p>The Sadernes climbing area only 5 km from the camp site</p><p>Sport climbing.</p><p>Canyoning.</p>');
select translate_surroundings_highlight(115, 'en', 'Besalú', '<p>County medieval village only 15 minutes distance</p><p><a href="https://besalu.cat/">besalu.cat</a></p>');
select translate_surroundings_highlight(116, 'en', 'La Garrotxa volcanic zone natural park', '<p>The best exponent of volcanic scenery in the Iberian Peninsula at 20 minutes.</p><p><a href="https://en.turismegarrotxa.com/">turismegarrotxa.com</a></p><p><a href="https://www.itinerannia.net/en/">itinerannia.net</a></p>');
select translate_surroundings_highlight(117, 'en', 'The best beaches at only one hour', '<p><a href="https://costabrava.org/en/">costabrava.org</a></p>');
select translate_surroundings_highlight(118, 'en', 'Empordà', '<p>Splendid region between the Pyrenees and the Mediterranean sea. Figueres and the Dalí Museum at only 30 minutes.</p><p><a href="https://en.visitfigueres.cat/">visitfigueres.cat</a><br/><a href="https://www.salvador-dali.org/en/">salvador-dali.org</a></p>');
select translate_surroundings_highlight(119, 'en', 'Empordà Designation of Origin', '<p>An unforgetable experience, the DO Empordà wine rute.</p><p><a href="https://www.doemporda.cat/">doemporda.cat</a></p><p>Photo author: Rafael Lopez-Monné</p>');
select translate_surroundings_highlight(120, 'en', 'Pyrenees', '<p>The Girona Pyrenees</p><p>With mountains of up to 3.000 meters, valleys and magic places as the Núria Valley.</p><p><a href="https://www.valldenuria.cat/en/">valldenuria.com</a></p>');
select translate_surroundings_highlight(121, 'en', 'Girona', '<p>Girona is worthwhile: we recommend to visit the Jewis Call, the Rambles, the cathedral and the gardens nearby…</p><p><a href="https://www.girona.cat/turisme/eng/">Turisme Girona</a></p>');
select translate_surroundings_highlight(122, 'en', 'Barcelona', '<p>Barcelona is more than shops or Barça… Discover the quarters, their “jewels” and breathe the ambiance.</p><p><a href="https://www.barcelonaturisme.com/wv3/en/">Turisme Barcelona</a></p>');
select translate_surroundings_highlight(112, 'es', 'El Puente del Llierca', '<p>Puente de estilo románico y baño natural a 400 m del camping.</p>');
select translate_surroundings_highlight(113, 'es', 'Alta Garrotxa', '<p>Excursiones por los alrededores que no os podéis perder:</p><ul><li>Sant Aniol dAgulla</li><li>La Cova del Bisbe</li><li>Santa Bàrbara de Pruneres</li></ul>');
select translate_surroundings_highlight(114, 'es', 'Sadernes', '<p>Zona de escalada de Sadernes a 5 km del camping Escalada deportiva Descenso de barrancos.</p>');
select translate_surroundings_highlight(115, 'es', 'Besalú', '<p>Villa condal medieval a 15 minutos.</p><p><a href="https://besalu.cat/">besalu.cat</a></p>');
select translate_surroundings_highlight(116, 'es', 'Parque Natural de la Zona Volcánica de la Garrotxa', '<p>El mejor exponente de paisaje volcánico de la península a sólo 20 minutos.</p><p><a href="https://es.turismegarrotxa.com/">turismegarrotxa.com</a></p><p><a href="https://www.itinerannia.net/es/">itinerannia.net</a></p>');
select translate_surroundings_highlight(117, 'es', 'Las mejores playas a sólo una hora', '<p><a href="https://costabrava.org/en/">costabrava.org</a></p>');
select translate_surroundings_highlight(118, 'es', 'Empordà', '<p>Espléndida comarca entre los Pirineos y el Mediterráneo. Figueres y el Museo Dalí a sólo 30 minutos.</p><p><a href="https://es.visitfigueres.cat/">visitfigueres.cat</a><br/><a href="https://www.salvador-dali.org/es/">salvador-dali.org</a></p>');
select translate_surroundings_highlight(119, 'es', 'Denominación de Orígen Empordà', '<p>Una experiéncia inolvidable, la Ruta del vino DO Empordà.</p><p><a href="https://www.doemporda.cat/">doemporda.cat</a></p><p>Autor de la foto: Rafael Lopez-Monné</p>');
select translate_surroundings_highlight(120, 'es', 'Pirineos', '<p>Pirineos de Girona</p><p> Cimas de casi 3.000 metros, valles y parajes mágicos como el Valle de Núria.</p><p><a href="https://www.valldenuria.cat/es/">valldenuria.com</a></p>');
select translate_surroundings_highlight(121, 'es', 'Girona', '<p>Girona vale una visita: os recomendamos visitar el Call Judío, las Ramblas, la catedral y los jardines que la rodean…</p><p><a href="https://www.girona.cat/turisme/esp/">Turismo Girona</a></p>');
select translate_surroundings_highlight(122, 'es', 'Barcelona', '<p>Barcelona es más que tiendas o el Barça… Descubre sus barrios y sus «joyas» y respira su ambiente.</p><p><a href="https://www.barcelonaturisme.com/wv3/es/">Turismo Barcelona</a></p>');
select translate_surroundings_highlight(112, 'fr', 'Le Pont de Llierca', '<p>Pont de style romain et bain naturel à 400 m du camping.</p>');
select translate_surroundings_highlight(113, 'fr', 'Haute Garrotxa', '<p>Randonnées incontournables:</p><ul><li>Sant Aniol dAgulla</li><li>La Cova del Bisbe</li><li>Santa Bàrbara de Pruneres</li></ul>');
select translate_surroundings_highlight(114, 'fr', 'Sadernes', '<p>Zone descalade de Sadernes a 5 km du camping.</p><p>Escalade sportive.</p><p>Canyoning.</p>');
select translate_surroundings_highlight(115, 'fr', 'Besalú', '<p>Village médiévale à 15 minutes.</p><p><a href="https://besalu.cat/">besalu.cat</a></p>');
select translate_surroundings_highlight(116, 'fr', 'Parc naturel de la zone volcanique de la Garrotxa', '<p>Un magnifique paysage volcanique à seulement 20 minutes.</p><p><a href="https://fr.turismegarrotxa.com/">turismegarrotxa.com</a></p><p><a href="https://www.itinerannia.net/fr/">itinerannia.net</a></p>');
select translate_surroundings_highlight(117, 'fr', 'Les plus belles plages à moins dune heure', '<p><a href="https://costabrava.org/en/">costabrava.org</a></p>');
select translate_surroundings_highlight(118, 'fr', 'Empordà', '<p>Magnifique région entre Pyrénées et Méditerranée.</p><p>Figueres et le musée Dalí a seulement 30 minutes.</p><p><a href="https://fr.visitfigueres.cat/">visitfigueres.cat</a><br/><a href="https://www.salvador-dali.org/en/">salvador-dali.org</a></p>');
select translate_surroundings_highlight(119, 'fr', 'Appellation dorigine Empordà', '<p>Une expérience inoubliable, la route des Vin DO Empordà</p><p><a href="https://www.doemporda.cat/">doemporda.cat</a></p><p>Auteur de la photo: Rafael Lopez-Monné</p>');
select translate_surroundings_highlight(120, 'fr', 'Pyrénées', '<p>Pyrénées de Gérone.</p><p>Sommet de prêt de 3.000 mètres, vallées et lieux magiques comme la Vall de Núria.</p><p><a href="https://www.valldenuria.cat/fr/">valldenuria.com</a></p>');
select translate_surroundings_highlight(121, 'fr', 'Gérone', '<p>Visite incontournable, principalement: le quartier juifs, les Rambles, la cathédrale et les jardins qui lentourent … Sans oublier ses nombreuses boutiques !</p><p><a href="https://www.girona.cat/turisme/fra/">Turisme Girona</a></p>');
select translate_surroundings_highlight(122, 'fr', 'Barcelone', '<p>Barcelone cest plus que des boutiques et le Barça … Découvrez la richesse de ces quartiers: Gràcia, Barceloneta, …</p><p><a href="https://www.barcelonaturisme.com/wv3/fr/">Turisme Barcelona</a></p>');
commit;

View File

@ -0,0 +1,23 @@
-- Deploy camper:add_surroundings_highlight to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_highlight
begin;
set search_path to camper, public;
create or replace function add_surroundings_highlight(company integer, media_id integer, name text, description text) returns integer as
$$
insert into surroundings_highlight (company_id, media_id, name, description)
values (company, media_id, name, xmlparse(content description))
returning surroundings_highlight_id
;
$$
language sql
;
revoke execute on function add_surroundings_highlight(integer, integer, text, text) from public;
grant execute on function add_surroundings_highlight(integer, integer, text, text) to admin;
commit;

View File

@ -0,0 +1,25 @@
-- Deploy camper:edit_surroundings_highlight to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_highlight
begin;
set search_path to camper, public;
create or replace function edit_surroundings_highlight(highlight_id integer, media_id integer, name text, description text) returns integer as
$$
update surroundings_highlight
set media_id = coalesce(edit_surroundings_highlight.media_id, surroundings_highlight.media_id)
, name = edit_surroundings_highlight.name
, description = xmlparse(content edit_surroundings_highlight.description)
where surroundings_highlight_id = highlight_id
returning surroundings_highlight_id;
$$
language sql
;
revoke execute on function edit_surroundings_highlight(integer, integer, text, text) from public;
grant execute on function edit_surroundings_highlight(integer, integer, text, text) to admin;
commit;

View File

@ -0,0 +1,24 @@
-- Deploy camper:order_surroundings_highlights to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_highlight
begin;
set search_path to camper, public;
create or replace function order_surroundings_highlights(positions integer[]) returns void as
$$
update surroundings_highlight
set position = cast(temp.position as integer)
from unnest(positions) with ordinality as temp(surroundings_highlight_id, position)
where surroundings_highlight.surroundings_highlight_id = temp.surroundings_highlight_id
;
$$
language sql
;
revoke execute on function order_surroundings_highlights(integer[]) from public;
grant execute on function order_surroundings_highlights(integer[]) to admin;
commit;

View File

@ -0,0 +1,22 @@
-- Deploy camper:remove_surroundings_highlight to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_highlight
-- requires: surroundings_highlight_i18n
begin;
set search_path to camper, public;
create or replace function remove_surroundings_highlight(highlight_id integer) returns void as
$$
delete from surroundings_highlight_i18n where surroundings_highlight_id = highlight_id;
delete from surroundings_highlight where surroundings_highlight_id = highlight_id;
$$
language sql
;
revoke execute on function remove_surroundings_highlight(integer) from public;
grant execute on function remove_surroundings_highlight(integer) to admin;
commit;

View File

@ -0,0 +1,58 @@
-- Deploy camper:surroundings_highlight to pg
-- requires: roles
-- requires: schema_camper
-- requires: company
-- requires: media
-- requires: user_profile
begin;
set search_path to camper, public;
create table surroundings_highlight (
surroundings_highlight_id integer generated by default as identity primary key,
company_id integer not null references company,
media_id integer not null references media,
name text not null constraint name_not_empty check(length(trim(name)) > 0),
description xml not null,
position integer not null default 2147483647
);
grant select on table surroundings_highlight to guest;
grant select on table surroundings_highlight to employee;
grant select, insert, update, delete on table surroundings_highlight to admin;
alter table surroundings_highlight enable row level security;
create policy guest_ok
on surroundings_highlight
for select
using (true)
;
create policy insert_to_company
on surroundings_highlight
for insert
with check (
company_id in (select company_id from user_profile)
)
;
create policy update_company
on surroundings_highlight
for update
using (
company_id in (select company_id from user_profile)
)
;
create policy delete_from_company
on surroundings_highlight
for delete
using (
company_id in (select company_id from user_profile)
)
;
commit;

View File

@ -0,0 +1,23 @@
-- Deploy camper:surroundings_highlight_i18n to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_highlight
-- requires: language
begin;
set search_path to camper, public;
create table surroundings_highlight_i18n (
surroundings_highlight_id integer not null references surroundings_highlight,
lang_tag text not null references language,
name text not null,
description xml not null,
primary key (surroundings_highlight_id, lang_tag)
);
grant select on table surroundings_highlight_i18n to guest;
grant select on table surroundings_highlight_i18n to employee;
grant select, insert, update, delete on table surroundings_highlight_i18n to admin;
commit;

View File

@ -0,0 +1,25 @@
-- Deploy camper:translate_surroundings_highlight to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_highlight_i18n
begin;
set search_path to camper, public;
create or replace function translate_surroundings_highlight(highlight_id integer, lang_tag text, name text, description text) returns void as
$$
insert into surroundings_highlight_i18n (surroundings_highlight_id, lang_tag, name, description)
values (highlight_id, lang_tag, name, xmlparse(content coalesce(description, '')))
on conflict (surroundings_highlight_id, lang_tag) do update
set name = excluded.name
, description = excluded.description
;
$$
language sql
;
revoke execute on function translate_surroundings_highlight(integer, text, text, text) from public;
grant execute on function translate_surroundings_highlight(integer, text, text, text) to admin;
commit;

View File

@ -20,32 +20,35 @@ import (
"dev.tandem.ws/tandem/camper/pkg/media"
"dev.tandem.ws/tandem/camper/pkg/season"
"dev.tandem.ws/tandem/camper/pkg/services"
"dev.tandem.ws/tandem/camper/pkg/surroundings"
"dev.tandem.ws/tandem/camper/pkg/template"
)
type adminHandler struct {
campsite *campsite.AdminHandler
company *company.AdminHandler
home *home.AdminHandler
legal *legal.AdminHandler
location *location.AdminHandler
media *media.AdminHandler
payment *booking.AdminHandler
season *season.AdminHandler
services *services.AdminHandler
campsite *campsite.AdminHandler
company *company.AdminHandler
home *home.AdminHandler
legal *legal.AdminHandler
location *location.AdminHandler
media *media.AdminHandler
payment *booking.AdminHandler
season *season.AdminHandler
services *services.AdminHandler
surroundings *surroundings.AdminHandler
}
func newAdminHandler(mediaDir string) *adminHandler {
return &adminHandler{
campsite: campsite.NewAdminHandler(),
company: company.NewAdminHandler(),
home: home.NewAdminHandler(),
legal: legal.NewAdminHandler(),
location: location.NewAdminHandler(),
media: media.NewAdminHandler(mediaDir),
payment: booking.NewAdminHandler(),
season: season.NewAdminHandler(),
services: services.NewAdminHandler(),
campsite: campsite.NewAdminHandler(),
company: company.NewAdminHandler(),
home: home.NewAdminHandler(),
legal: legal.NewAdminHandler(),
location: location.NewAdminHandler(),
media: media.NewAdminHandler(mediaDir),
payment: booking.NewAdminHandler(),
season: season.NewAdminHandler(),
services: services.NewAdminHandler(),
surroundings: surroundings.NewAdminHandler(),
}
}
@ -83,6 +86,8 @@ func (h *adminHandler) Handle(user *auth.User, company *auth.Company, conn *data
h.season.Handler(user, company, conn).ServeHTTP(w, r)
case "services":
h.services.Handler(user, company, conn).ServeHTTP(w, r)
case "surroundings":
h.surroundings.Handler(user, company, conn).ServeHTTP(w, r)
case "":
switch r.Method {
case http.MethodGet:

View File

@ -6,7 +6,6 @@
package app
import (
"dev.tandem.ws/tandem/camper/pkg/legal"
"net/http"
"dev.tandem.ws/tandem/camper/pkg/auth"
@ -15,28 +14,32 @@ import (
"dev.tandem.ws/tandem/camper/pkg/database"
"dev.tandem.ws/tandem/camper/pkg/home"
httplib "dev.tandem.ws/tandem/camper/pkg/http"
"dev.tandem.ws/tandem/camper/pkg/legal"
"dev.tandem.ws/tandem/camper/pkg/location"
"dev.tandem.ws/tandem/camper/pkg/services"
"dev.tandem.ws/tandem/camper/pkg/surroundings"
"dev.tandem.ws/tandem/camper/pkg/template"
)
type publicHandler struct {
home *home.PublicHandler
booking *booking.PublicHandler
campsite *campsite.PublicHandler
legal *legal.PublicHandler
location *location.PublicHandler
services *services.PublicHandler
home *home.PublicHandler
booking *booking.PublicHandler
campsite *campsite.PublicHandler
legal *legal.PublicHandler
location *location.PublicHandler
services *services.PublicHandler
surroundings *surroundings.PublicHandler
}
func newPublicHandler() *publicHandler {
return &publicHandler{
home: home.NewPublicHandler(),
booking: booking.NewPublicHandler(),
campsite: campsite.NewPublicHandler(),
legal: legal.NewPublicHandler(),
location: location.NewPublicHandler(),
services: services.NewPublicHandler(),
home: home.NewPublicHandler(),
booking: booking.NewPublicHandler(),
campsite: campsite.NewPublicHandler(),
legal: legal.NewPublicHandler(),
location: location.NewPublicHandler(),
services: services.NewPublicHandler(),
surroundings: surroundings.NewPublicHandler(),
}
}
@ -60,27 +63,7 @@ func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *da
case "services":
h.services.Handler(user, company, conn).ServeHTTP(w, r)
case "surroundings":
surroundingsHandler(user, company, conn).ServeHTTP(w, r)
default:
http.NotFound(w, r)
}
})
}
func surroundingsHandler(user *auth.User, company *auth.Company, conn *database.Conn) 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:
page := template.NewPublicPage()
page.Setup(r, user, company, conn)
template.MustRenderPublic(w, r, user, company, "surroundings.gohtml", page)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet)
}
h.surroundings.Handler(user, company, conn).ServeHTTP(w, r)
default:
http.NotFound(w, r)
}

View File

@ -150,3 +150,27 @@ func (c *Conn) OrderServices(ctx context.Context, ids []int) error {
_, err := c.Exec(ctx, "select order_services($1)", ids)
return err
}
func (tx *Tx) AddSurroundingsHighlight(ctx context.Context, companyID int, mediaID int, name string, description string) (int, error) {
return tx.GetInt(ctx, "select add_surroundings_highlight($1, $2, $3, $4)", companyID, mediaID, name, description)
}
func (tx *Tx) EditSurroundingsHighlight(ctx context.Context, id int, mediaID int, name string, description string) error {
_, err := tx.Exec(ctx, "select edit_surroundings_highlight($1, $2, $3, $4)", id, mediaID, name, description)
return err
}
func (tx *Tx) TranslateSurroundingsHighlight(ctx context.Context, id int, langTag language.Tag, name string, description string) error {
_, err := tx.Exec(ctx, "select translate_surroundings_highlight($1, $2, $3, $4)", id, langTag, name, description)
return err
}
func (c *Conn) OrderSurroundingsHighlights(ctx context.Context, ids []int) error {
_, err := c.Exec(ctx, "select order_surroundings_highlights($1)", ids)
return err
}
func (c *Conn) RemoveSurroundingsHighlight(ctx context.Context, id int) error {
_, err := c.Exec(ctx, "select remove_surroundings_highlight($1)", id)
return err
}

327
pkg/surroundings/admin.go Normal file
View File

@ -0,0 +1,327 @@
/*
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
* SPDX-License-Identifier: AGPL-3.0-only
*/
package surroundings
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"
)
type AdminHandler struct {
}
func NewAdminHandler() *AdminHandler {
return &AdminHandler{}
}
func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) 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:
serveHighlightsIndex(w, r, user, company, conn)
case http.MethodPost:
addHighlight(w, r, user, company, conn)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost)
}
case "new":
switch r.Method {
case http.MethodGet:
f := newHighlightForm(company)
f.MustRender(w, r, user, company)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet)
}
case "order":
switch r.Method {
case http.MethodPost:
orderHighlights(w, r, user, company, conn)
default:
httplib.MethodNotAllowed(w, r, http.MethodPost)
}
default:
id, err := strconv.Atoi(head)
if err != nil {
http.NotFound(w, r)
return
}
f := newHighlightForm(company)
if err := f.FillFromDatabase(r.Context(), conn, id); err != nil {
if database.ErrorIsNotFound(err) {
http.NotFound(w, r)
return
}
panic(err)
}
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:
editHighlight(w, r, user, company, conn, f)
case http.MethodDelete:
deleteHighlight(w, r, user, conn, id)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut, http.MethodDelete)
}
default:
http.NotFound(w, r)
}
}
})
}
func orderHighlights(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
if err := r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := user.VerifyCSRFToken(r); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
input := r.PostForm["highlight_id"]
if len(input) > 0 {
var ids []int
for _, s := range input {
if id, err := strconv.Atoi(s); err == nil {
ids = append(ids, id)
} else {
http.Error(w, err.Error(), http.StatusUnprocessableEntity)
return
}
}
if err := conn.OrderSurroundingsHighlights(r.Context(), ids); err != nil {
panic(err)
}
}
serveHighlightsIndex(w, r, user, company, conn)
}
func serveHighlightsIndex(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
highlights, err := collectHighlightEntries(r.Context(), company, conn)
if err != nil {
panic(err)
}
page := &highlightIndex{
Highlights: highlights,
}
page.MustRender(w, r, user, company)
}
type highlightIndex struct {
Highlights []*highlightEntry
}
func (page *highlightIndex) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "surroundings/index.gohtml", page)
}
type highlightEntry struct {
ID int
URL string
Media string
Name string
}
func collectHighlightEntries(ctx context.Context, company *auth.Company, conn *database.Conn) ([]*highlightEntry, error) {
rows, err := conn.Query(ctx, `
select surroundings_highlight_id
, '/admin/surroundings/' || surroundings_highlight_id
, media.path
, name
from surroundings_highlight as highlight
join media using (media_id)
where highlight.company_id = $1
order by position
, name
`, company.ID)
if err != nil {
return nil, err
}
defer rows.Close()
var highlights []*highlightEntry
for rows.Next() {
entry := &highlightEntry{}
if err = rows.Scan(&entry.ID, &entry.URL, &entry.Media, &entry.Name); err != nil {
return nil, err
}
highlights = append(highlights, entry)
}
return highlights, nil
}
func addHighlight(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
f := newHighlightForm(company)
processHighlightForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
var err error
if f.ID, err = tx.AddSurroundingsHighlight(ctx, company.ID, f.Media.Int(), f.Name[f.DefaultLang].Val, f.Description[f.DefaultLang].Val); err != nil {
return err
}
return translateHighlight(ctx, tx, company, f)
})
}
func processHighlightForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *highlightForm, act func(context.Context, *database.Tx) error) {
if err := f.Parse(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := user.VerifyCSRFToken(r); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
if ok, err := f.Valid(r.Context(), conn, user.Locale); err != nil {
panic(err)
} else if !ok {
if !httplib.IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity)
}
f.MustRender(w, r, user, company)
return
}
tx := conn.MustBegin(r.Context())
if err := act(r.Context(), tx); err == nil {
tx.MustCommit(r.Context())
} else {
if rErr := tx.Rollback(r.Context()); rErr != nil {
err = rErr
}
panic(err)
}
httplib.Redirect(w, r, "/admin/surroundings", http.StatusSeeOther)
}
func translateHighlight(ctx context.Context, tx *database.Tx, company *auth.Company, f *highlightForm) error {
for lang := range company.Locales {
l := lang.String()
if l == f.DefaultLang {
continue
}
if err := tx.TranslateSurroundingsHighlight(ctx, f.ID, lang, f.Name[l].Val, f.Description[l].Val); err != nil {
return err
}
}
return nil
}
func editHighlight(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *highlightForm) {
processHighlightForm(w, r, user, company, conn, f, func(ctx context.Context, tx *database.Tx) error {
if err := tx.EditSurroundingsHighlight(ctx, f.ID, f.Media.Int(), f.Name[f.DefaultLang].Val, f.Description[f.DefaultLang].Val); err != nil {
return err
}
return translateHighlight(ctx, tx, company, f)
})
httplib.Redirect(w, r, "/admin/surroundings", http.StatusSeeOther)
}
func deleteHighlight(w http.ResponseWriter, r *http.Request, user *auth.User, conn *database.Conn, id int) {
if err := user.VerifyCSRFToken(r); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
if err := conn.RemoveSurroundingsHighlight(r.Context(), id); err != nil {
panic(err)
}
httplib.Redirect(w, r, "/admin/surroundings", http.StatusSeeOther)
}
type highlightForm struct {
DefaultLang string
ID int
Media *form.Media
Name form.I18nInput
Description form.I18nInput
}
func newHighlightForm(company *auth.Company) *highlightForm {
return &highlightForm{
DefaultLang: company.DefaultLanguage.String(),
Media: &form.Media{
Input: &form.Input{
Name: "media",
},
Label: locale.PgettextNoop("Highlight image", "input"),
Prompt: locale.PgettextNoop("Set highlight image", "action"),
},
Name: form.NewI18nInput(company.Locales, "name"),
Description: form.NewI18nInput(company.Locales, "description"),
}
}
func (f *highlightForm) FillFromDatabase(ctx context.Context, conn *database.Conn, id int) error {
f.ID = id
var name database.RecordArray
var description database.RecordArray
row := conn.QueryRow(ctx, `
select media_id::text
, highlight.name
, highlight.description::text
, array_agg((lang_tag, i18n.name))
, array_agg((lang_tag, i18n.description::text))
from surroundings_highlight as highlight
left join surroundings_highlight_i18n as i18n using (surroundings_highlight_id)
where surroundings_highlight_id = $1
group by media_id::text
, highlight.name
, highlight.description::text
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, id)
if err := row.Scan(&f.Media.Val, &f.Name[f.DefaultLang].Val, &f.Description[f.DefaultLang].Val, &name, &description); err != nil {
return err
}
if err := f.Name.FillArray(name); err != nil {
return err
}
if err := f.Description.FillArray(description); err != nil {
return err
}
return nil
}
func (f *highlightForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
f.Media.FillValue(r)
f.Name.FillValue(r)
f.Description.FillValue(r)
return nil
}
func (f *highlightForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) {
v := form.NewValidator(l)
if v.CheckRequired(f.Media.Input, l.GettextNoop("Slide image can not be empty.")) {
if _, err := v.CheckImageMedia(ctx, conn, f.Media.Input, l.GettextNoop("Slide image must be an image media type.")); err != nil {
return false, err
}
}
v.CheckRequired(f.Name[f.DefaultLang], l.GettextNoop("Name can not be empty."))
return v.AllOK, nil
}
func (f *highlightForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "surroundings/form.gohtml", f)
}

View File

@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
* SPDX-License-Identifier: AGPL-3.0-only
*/
package surroundings
import (
"context"
gotemplate "html/template"
"net/http"
"dev.tandem.ws/tandem/camper/pkg/auth"
"dev.tandem.ws/tandem/camper/pkg/database"
httplib "dev.tandem.ws/tandem/camper/pkg/http"
"dev.tandem.ws/tandem/camper/pkg/locale"
"dev.tandem.ws/tandem/camper/pkg/template"
)
type PublicHandler struct {
}
func NewPublicHandler() *PublicHandler {
return &PublicHandler{}
}
func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) 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:
page := newSurroundingsPage()
page.MustRender(w, r, user, company, conn)
default:
httplib.MethodNotAllowed(w, r, http.MethodGet)
}
default:
http.NotFound(w, r)
}
})
}
type surroundingsPage struct {
*template.PublicPage
Highlights []*highlight
}
func newSurroundingsPage() *surroundingsPage {
return &surroundingsPage{PublicPage: template.NewPublicPage()}
}
func (p *surroundingsPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
p.Setup(r, user, company, conn)
p.Highlights = mustCollectSurroundings(r.Context(), company, conn, user.Locale)
template.MustRenderPublic(w, r, user, company, "surroundings.gohtml", p)
}
type highlight struct {
Media string
Name string
Description gotemplate.HTML
}
func mustCollectSurroundings(ctx context.Context, company *auth.Company, conn *database.Conn, loc *locale.Locale) []*highlight {
rows, err := conn.Query(ctx, `
select media.path
, coalesce(i18n.name, highlight.name) as l10_name
, coalesce(i18n.description, highlight.description)::text as l10_description
from surroundings_highlight as highlight
join media using (media_id)
left join surroundings_highlight_i18n as i18n on highlight.surroundings_highlight_id = i18n.surroundings_highlight_id and lang_tag = $1
where highlight.company_id = $2
order by position
, l10_name
`, loc.Language, company.ID)
if err != nil {
panic(err)
}
defer rows.Close()
var items []*highlight
for rows.Next() {
item := &highlight{}
err = rows.Scan(&item.Media, &item.Name, &item.Description)
if err != nil {
panic(err)
}
items = append(items, item)
}
if rows.Err() != nil {
panic(rows.Err())
}
return items
}

225
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-15 02:00+0100\n"
"POT-Creation-Date: 2024-01-16 00:48+0100\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"
@ -56,7 +56,7 @@ msgstr "El càmping disposa de diversos serveis."
#: web/templates/public/location.gohtml:6
#: web/templates/public/location.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
#: web/templates/admin/layout.gohtml:60
#: web/templates/admin/layout.gohtml:61
msgctxt "title"
msgid "Location"
msgstr "Com arribar"
@ -86,8 +86,9 @@ msgstr "Vine a gaudir!"
#: web/templates/public/home.gohtml:35
#: web/templates/public/surroundings.gohtml:6
#: web/templates/public/surroundings.gohtml:10
#: web/templates/public/surroundings.gohtml:11
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
#: web/templates/admin/layout.gohtml:64
msgctxt "title"
msgid "Surroundings"
msgstr "Lentorn"
@ -251,61 +252,45 @@ msgctxt "day"
msgid "Sun"
msgstr "dg"
#: web/templates/public/surroundings.gohtml:28
#: web/templates/public/surroundings.gohtml:31
msgctxt "title"
msgid "What to Do Outside the Campsite?"
msgstr "Què fer des del càmping?"
#: web/templates/public/surroundings.gohtml:31
msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…."
msgstr "El Càmping Montagut és ideal com a punt de partida dexcursions tranquil·les, escalada, banyar-se en el riu i gorgues, volcans, la Fageda den Jordà, sortides amb bicicleta per a tots els nivells…."
#: web/templates/public/surroundings.gohtml:38
msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
msgstr "Arribar fins a la costa brava i gaudir de les platges, la gastronomia o anar amb caiac…."
#: web/templates/public/surroundings.gohtml:47
msgid "You will also find museums in Olot, Figures, Girona."
msgstr "També trobareu museus a Olot, Figueres, Girona."
#: web/templates/public/surroundings.gohtml:48
msgid "As well as music festivals, dance, theater…."
msgstr "Com festivals de música, dansa, teatre…."
#: web/templates/public/surroundings.gohtml:54
#: web/templates/public/surroundings.gohtml:51
msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Un cop en el càmping, us podem informar de quines activitats fer"
#: web/templates/public/surroundings.gohtml:57
#: web/templates/public/surroundings.gohtml:54
msgid "Cycle routes"
msgstr "Rutes amb bicicleta"
#: web/templates/public/surroundings.gohtml:58
#: web/templates/public/surroundings.gohtml:55
msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podeu trobar empreses de lloguer de bicicletes."
#: web/templates/public/surroundings.gohtml:62
#: web/templates/public/surroundings.gohtml:59
msgid "Routes"
msgstr "Rutes"
#: web/templates/public/surroundings.gohtml:63
#: web/templates/public/surroundings.gohtml:60
msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Rutes de tota mena, escalada, ports de muntanya, per a tots els nivells."
#: web/templates/public/surroundings.gohtml:67
#: web/templates/public/surroundings.gohtml:64
msgid "Family outing"
msgstr "Excursions familiars"
#: web/templates/public/surroundings.gohtml:68
#: web/templates/public/surroundings.gohtml:65
msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursions per a totes les edats."
#: web/templates/public/surroundings.gohtml:72
#: web/templates/public/surroundings.gohtml:69
msgid "Kayak"
msgstr "Caiac"
#: web/templates/public/surroundings.gohtml:73
#: web/templates/public/surroundings.gohtml:70
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Hi ha diversos punts on poder anar amb caiac, des de trams del riu Ter com també a la costa…."
@ -410,7 +395,7 @@ msgstr "He llegit i accepto <a href=\"%s\" target=\"_blank\">les condicions de r
msgid "Campsite Montagut"
msgstr "Càmping Montagut"
#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:20
#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:21
msgid "Skip to main content"
msgstr "Salta al contingut principal"
@ -421,7 +406,7 @@ msgstr "Menú"
#: web/templates/public/layout.gohtml:57 web/templates/public/layout.gohtml:103
#: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:45 web/templates/admin/layout.gohtml:82
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:86
msgctxt "title"
msgid "Campsites"
msgstr "Allotjaments"
@ -464,6 +449,7 @@ msgstr "Àlies"
#: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/services/form.gohtml:52
#: web/templates/admin/profile.gohtml:26
#: web/templates/admin/surroundings/form.gohtml:37
msgctxt "input"
msgid "Name"
msgstr "Nom"
@ -482,6 +468,7 @@ msgstr "Contingut"
#: web/templates/admin/campsite/type/form.gohtml:171
#: web/templates/admin/season/form.gohtml:69
#: web/templates/admin/services/form.gohtml:80
#: web/templates/admin/surroundings/form.gohtml:65
#: web/templates/admin/media/form.gohtml:35
msgctxt "action"
msgid "Update"
@ -496,13 +483,14 @@ msgstr "Actualitza"
#: web/templates/admin/campsite/type/form.gohtml:173
#: web/templates/admin/season/form.gohtml:71
#: web/templates/admin/services/form.gohtml:82
#: web/templates/admin/surroundings/form.gohtml:67
msgctxt "action"
msgid "Add"
msgstr "Afegeix"
#: web/templates/admin/legal/index.gohtml:6
#: web/templates/admin/legal/index.gohtml:12
#: web/templates/admin/layout.gohtml:63
#: web/templates/admin/layout.gohtml:67
msgctxt "title"
msgid "Legal Texts"
msgstr "Texts legals"
@ -517,6 +505,7 @@ msgstr "Afegeix text legal"
#: web/templates/admin/campsite/option/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:25
#: web/templates/admin/season/index.gohtml:26
#: web/templates/admin/surroundings/index.gohtml:26
msgctxt "header"
msgid "Name"
msgstr "Nom"
@ -630,6 +619,7 @@ msgstr "Afegeix diapositiva"
#: web/templates/admin/campsite/carousel/index.gohtml:25
#: web/templates/admin/services/index.gohtml:25
#: web/templates/admin/surroundings/index.gohtml:25
#: web/templates/admin/home/index.gohtml:25
msgctxt "header"
msgid "Image"
@ -645,6 +635,7 @@ msgstr "Llegenda"
#: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:72
#: web/templates/admin/surroundings/index.gohtml:27
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Actions"
@ -659,6 +650,7 @@ msgstr "Esteu segur de voler esborrar aquesta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:44
#: web/templates/admin/services/index.gohtml:88
#: web/templates/admin/surroundings/index.gohtml:44
#: web/templates/admin/home/index.gohtml:44
msgctxt "action"
msgid "Delete"
@ -826,6 +818,7 @@ msgstr "Equipaments"
#: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/services/form.gohtml:65
#: web/templates/admin/surroundings/form.gohtml:50
msgctxt "input"
msgid "Description"
msgstr "Descripció"
@ -837,7 +830,7 @@ msgstr "Informació addicional"
#: web/templates/admin/campsite/type/index.gohtml:6
#: web/templates/admin/campsite/type/index.gohtml:12
#: web/templates/admin/layout.gohtml:42
#: web/templates/admin/layout.gohtml:43
msgctxt "title"
msgid "Campsite Types"
msgstr "Tipus dallotjaments"
@ -906,7 +899,7 @@ msgstr "Color"
#: web/templates/admin/season/index.gohtml:6
#: web/templates/admin/season/index.gohtml:12
#: web/templates/admin/layout.gohtml:48
#: web/templates/admin/layout.gohtml:49
msgctxt "title"
msgid "Seasons"
msgstr "Temporades"
@ -932,7 +925,7 @@ msgid "Cancel"
msgstr "Canceŀla"
#: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12
#: web/templates/admin/layout.gohtml:39
#: web/templates/admin/layout.gohtml:40
msgctxt "title"
msgid "Payment Settings"
msgstr "Paràmetres de pagament"
@ -968,7 +961,7 @@ msgid "Integration"
msgstr "Integració"
#: web/templates/admin/dashboard.gohtml:6
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:79
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:83
msgctxt "title"
msgid "Dashboard"
msgstr "Tauler"
@ -1001,7 +994,7 @@ msgid "New Service"
msgstr "Nou servei"
#: web/templates/admin/services/index.gohtml:6
#: web/templates/admin/layout.gohtml:57
#: web/templates/admin/layout.gohtml:58
msgctxt "title"
msgid "Services Page"
msgstr "Pàgina de serveis"
@ -1036,7 +1029,7 @@ msgid "No services added yet."
msgstr "No sha afegit cap servei encara."
#: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12
#: web/templates/admin/layout.gohtml:32
#: web/templates/admin/layout.gohtml:33
msgctxt "title"
msgid "Profile"
msgstr "Perfil"
@ -1143,29 +1136,64 @@ msgctxt "input"
msgid "Legal Disclaimer"
msgstr "Nota legal"
#: web/templates/admin/layout.gohtml:28
#: web/templates/admin/surroundings/form.gohtml:8
#: web/templates/admin/surroundings/form.gohtml:25
msgctxt "title"
msgid "Edit Highlight"
msgstr "Edició del punt dinterès"
#: web/templates/admin/surroundings/form.gohtml:10
#: web/templates/admin/surroundings/form.gohtml:27
msgctxt "title"
msgid "New Highlight"
msgstr "Nou punt dinterès"
#: web/templates/admin/surroundings/index.gohtml:6
msgctxt "title"
msgid "Surroundings Page"
msgstr "Pàgina de lentorn"
#: web/templates/admin/surroundings/index.gohtml:11
msgctxt "title"
msgid "Highlights"
msgstr "Punts dinterès"
#: web/templates/admin/surroundings/index.gohtml:12
msgctxt "action"
msgid "Add highlight"
msgstr "Afegeix punt dinterès"
#: web/templates/admin/surroundings/index.gohtml:31
msgid "Are you sure you wish to delete this highlight?"
msgstr "Esteu segur de voler esborrar aquest punt dinterès?"
#: web/templates/admin/surroundings/index.gohtml:53
msgid "No highlights added yet."
msgstr "No sha afegit cap punt dinterès encara."
#: web/templates/admin/layout.gohtml:29
msgctxt "title"
msgid "User Menu"
msgstr "Menú dusuari"
#: web/templates/admin/layout.gohtml:36
#: web/templates/admin/layout.gohtml:37
msgctxt "title"
msgid "Company Settings"
msgstr "Paràmetres de lempresa"
#: web/templates/admin/layout.gohtml:51
#: web/templates/admin/layout.gohtml:52
#: web/templates/admin/media/index.gohtml:6
#: web/templates/admin/media/index.gohtml:11
msgctxt "title"
msgid "Media"
msgstr "Mèdia"
#: web/templates/admin/layout.gohtml:54 web/templates/admin/home/index.gohtml:6
#: web/templates/admin/layout.gohtml:55 web/templates/admin/home/index.gohtml:6
msgctxt "title"
msgid "Home Page"
msgstr "Pàgina dinici"
#: web/templates/admin/layout.gohtml:68
#: web/templates/admin/layout.gohtml:72
msgctxt "action"
msgid "Logout"
msgstr "Surt"
@ -1236,31 +1264,34 @@ msgid "Upload Media"
msgstr "Pujada de mèdia"
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:344
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:464
#: pkg/season/admin.go:415 pkg/services/admin.go:319
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:463
#: pkg/season/admin.go:412 pkg/services/admin.go:314
#: pkg/surroundings/admin.go:321
msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc."
#: pkg/legal/admin.go:259 pkg/campsite/types/option.go:345
#: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:465
#: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:464
msgid "Name must have at least one letter."
msgstr "El nom ha de tenir com a mínim una lletra."
#: pkg/carousel/admin.go:269 pkg/campsite/types/carousel.go:223
#: pkg/carousel/admin.go:267 pkg/campsite/types/carousel.go:223
msgctxt "input"
msgid "Slide image"
msgstr "Imatge de la diapositiva"
#: pkg/carousel/admin.go:270 pkg/campsite/types/carousel.go:224
#: pkg/carousel/admin.go:268 pkg/campsite/types/carousel.go:224
msgctxt "action"
msgid "Set slide image"
msgstr "Estableix la imatge de la diapositiva"
#: pkg/carousel/admin.go:339 pkg/campsite/types/carousel.go:297
#: pkg/carousel/admin.go:337 pkg/campsite/types/carousel.go:297
#: pkg/surroundings/admin.go:316
msgid "Slide image can not be empty."
msgstr "No podeu deixar la imatge de la diapositiva en blanc."
#: pkg/carousel/admin.go:340 pkg/campsite/types/carousel.go:298
#: pkg/carousel/admin.go:338 pkg/campsite/types/carousel.go:298
#: pkg/surroundings/admin.go:317
msgid "Slide image must be an image media type."
msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge."
@ -1299,7 +1330,7 @@ msgstr "Lidioma escollit no és vàlid."
msgid "File must be a valid PNG or JPEG image."
msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida."
#: pkg/app/admin.go:62
#: pkg/app/admin.go:64
msgid "Access forbidden"
msgstr "Accés prohibit"
@ -1327,61 +1358,61 @@ msgstr "El valor del màxim ha de ser un número enter."
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:361 pkg/campsite/types/admin.go:478
#: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:477
msgid "Price per night can not be empty."
msgstr "No podeu deixar el preu per nit en blanc."
#: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:479
#: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:478
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:363 pkg/campsite/types/admin.go:480
#: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:479
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/feature.go:258 pkg/services/admin.go:318
#: pkg/campsite/types/feature.go:258 pkg/services/admin.go:313
msgid "Selected icon is not valid."
msgstr "La icona escollida no és vàlida."
#: pkg/campsite/types/admin.go:306
#: pkg/campsite/types/admin.go:305
msgctxt "input"
msgid "Cover image"
msgstr "Imatge de portada"
#: pkg/campsite/types/admin.go:307
#: pkg/campsite/types/admin.go:306
msgctxt "action"
msgid "Set campsite type cover"
msgstr "Estableix la portada del tipus dallotjament"
#: pkg/campsite/types/admin.go:467
#: pkg/campsite/types/admin.go:466
msgid "Cover image can not be empty."
msgstr "No podeu deixar la imatge de portada en blanc."
#: pkg/campsite/types/admin.go:468
#: pkg/campsite/types/admin.go:467
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:472
#: pkg/campsite/types/admin.go:471
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:473
#: pkg/campsite/types/admin.go:472
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:474
#: pkg/campsite/types/admin.go:473
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:483
#: pkg/campsite/types/admin.go:482
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:484
#: pkg/campsite/types/admin.go:483
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:485
#: pkg/campsite/types/admin.go:484
msgid "Minimum number of nights must be one or greater."
msgstr "El número mínim de nits no pot ser zero."
@ -1393,95 +1424,105 @@ msgstr "El tipus dallotjament escollit no és vàlid."
msgid "Label can not be empty."
msgstr "No podeu deixar letiqueta en blanc."
#: pkg/season/admin.go:186
#: pkg/season/admin.go:183
msgctxt "month"
msgid "January"
msgstr "gener"
#: pkg/season/admin.go:187
#: pkg/season/admin.go:184
msgctxt "month"
msgid "February"
msgstr "febrer"
#: pkg/season/admin.go:188
#: pkg/season/admin.go:185
msgctxt "month"
msgid "March"
msgstr "març"
#: pkg/season/admin.go:189
#: pkg/season/admin.go:186
msgctxt "month"
msgid "April"
msgstr "abril"
#: pkg/season/admin.go:190
#: pkg/season/admin.go:187
msgctxt "month"
msgid "May"
msgstr "maig"
#: pkg/season/admin.go:191
#: pkg/season/admin.go:188
msgctxt "month"
msgid "June"
msgstr "juny"
#: pkg/season/admin.go:192
#: pkg/season/admin.go:189
msgctxt "month"
msgid "July"
msgstr "juliol"
#: pkg/season/admin.go:193
#: pkg/season/admin.go:190
msgctxt "month"
msgid "August"
msgstr "agost"
#: pkg/season/admin.go:194
#: pkg/season/admin.go:191
msgctxt "month"
msgid "September"
msgstr "setembre"
#: pkg/season/admin.go:195
#: pkg/season/admin.go:192
msgctxt "month"
msgid "October"
msgstr "octubre"
#: pkg/season/admin.go:196
#: pkg/season/admin.go:193
msgctxt "month"
msgid "November"
msgstr "novembre"
#: pkg/season/admin.go:197
#: pkg/season/admin.go:194
msgctxt "month"
msgid "December"
msgstr "desembre"
#: pkg/season/admin.go:416
#: pkg/season/admin.go:413
msgid "Color can not be empty."
msgstr "No podeu deixar el color en blanc."
#: pkg/season/admin.go:417
#: pkg/season/admin.go:414
msgid "This color is not valid. It must be like #123abc."
msgstr "Aquest color no és vàlid. Hauria de ser similar a #123abc."
#: pkg/season/admin.go:517
#: pkg/season/admin.go:514
msgctxt "action"
msgid "Unset"
msgstr "Desassigna"
#: pkg/season/admin.go:548
#: pkg/season/admin.go:545
msgid "Start date can not be empty."
msgstr "No podeu deixar la data dinici en blanc."
#: pkg/season/admin.go:549
#: pkg/season/admin.go:546
msgid "Start date must be a valid date."
msgstr "La data dinici ha de ser una data vàlida."
#: pkg/season/admin.go:551
#: pkg/season/admin.go:548
msgid "End date can not be empty."
msgstr "No podeu deixar la data de fi en blanc."
#: pkg/season/admin.go:552
#: pkg/season/admin.go:549
msgid "End date must be a valid date."
msgstr "La data de fi ha de ser una data vàlida."
#: pkg/surroundings/admin.go:267
msgctxt "input"
msgid "Highlight image"
msgstr "Imatge del punt dinterès"
#: pkg/surroundings/admin.go:268
msgctxt "action"
msgid "Set highlight image"
msgstr "Estableix la imatge del punt dinterès"
#: pkg/company/admin.go:200 pkg/booking/public.go:256
msgid "Selected country is not valid."
msgstr "El país escollit no és vàlid."
@ -1562,11 +1603,11 @@ msgstr "No podeu deixar el format del número de factura en blanc."
msgid "Cross-site request forgery detected."
msgstr "Sha detectat un intent de falsificació de petició a llocs creuats."
#: pkg/media/admin.go:265
#: pkg/media/admin.go:312
msgid "Uploaded file can not be empty."
msgstr "No podeu deixar el fitxer del mèdia en blanc."
#: pkg/media/admin.go:324
#: pkg/media/admin.go:371
msgid "Filename can not be empty."
msgstr "No podeu deixar el nom del fitxer en blanc."
@ -1674,6 +1715,18 @@ msgstr "El valor de %s ha de ser com a mínim %d."
msgid "%s must be at most %d."
msgstr "El valor de %s ha de ser com a màxim %d."
#~ msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…."
#~ msgstr "El Càmping Montagut és ideal com a punt de partida dexcursions tranquil·les, escalada, banyar-se en el riu i gorgues, volcans, la Fageda den Jordà, sortides amb bicicleta per a tots els nivells…."
#~ msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
#~ msgstr "Arribar fins a la costa brava i gaudir de les platges, la gastronomia o anar amb caiac…."
#~ msgid "You will also find museums in Olot, Figures, Girona."
#~ msgstr "També trobareu museus a Olot, Figueres, Girona."
#~ msgid "As well as music festivals, dance, theater…."
#~ msgstr "Com festivals de música, dansa, teatre…."
#~ msgctxt "header"
#~ msgid "Translations"
#~ msgstr "Traduccions"

225
po/es.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-15 02:00+0100\n"
"POT-Creation-Date: 2024-01-16 00:48+0100\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"
@ -56,7 +56,7 @@ msgstr "El camping dispone de varios servicios."
#: web/templates/public/location.gohtml:6
#: web/templates/public/location.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
#: web/templates/admin/layout.gohtml:60
#: web/templates/admin/layout.gohtml:61
msgctxt "title"
msgid "Location"
msgstr "Cómo llegar"
@ -86,8 +86,9 @@ msgstr "¡Ven a disfrutar!"
#: web/templates/public/home.gohtml:35
#: web/templates/public/surroundings.gohtml:6
#: web/templates/public/surroundings.gohtml:10
#: web/templates/public/surroundings.gohtml:11
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
#: web/templates/admin/layout.gohtml:64
msgctxt "title"
msgid "Surroundings"
msgstr "El entorno"
@ -251,61 +252,45 @@ msgctxt "day"
msgid "Sun"
msgstr "do"
#: web/templates/public/surroundings.gohtml:28
#: web/templates/public/surroundings.gohtml:31
msgctxt "title"
msgid "What to Do Outside the Campsite?"
msgstr "¿Qué hacer desde el camping?"
#: web/templates/public/surroundings.gohtml:31
msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…."
msgstr "El Camping Montagut es ideal como punto de salida de excursiones tranquilas, escalada, bañarse en el río y piletones, volcanes, la Fageda den Jordà, salidas en bicicleta para todos los niveles…."
#: web/templates/public/surroundings.gohtml:38
msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
msgstr "Llegar hasta la Costa Brava y disfrutar de las playas, la gastronomía o ir en kayak…."
#: web/templates/public/surroundings.gohtml:47
msgid "You will also find museums in Olot, Figures, Girona."
msgstr "También encontraréis museos en Olot, Figueres, Girona."
#: web/templates/public/surroundings.gohtml:48
msgid "As well as music festivals, dance, theater…."
msgstr "Como festivales de música, danza, teatro…."
#: web/templates/public/surroundings.gohtml:54
#: web/templates/public/surroundings.gohtml:51
msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Una vez en el camping, os podemos informar de qué actividades hacer"
#: web/templates/public/surroundings.gohtml:57
#: web/templates/public/surroundings.gohtml:54
msgid "Cycle routes"
msgstr "Rutas en bicicleta"
#: web/templates/public/surroundings.gohtml:58
#: web/templates/public/surroundings.gohtml:55
msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podéis encontrar empresas de alquiler de bicicletas."
#: web/templates/public/surroundings.gohtml:62
#: web/templates/public/surroundings.gohtml:59
msgid "Routes"
msgstr "Rutas"
#: web/templates/public/surroundings.gohtml:63
#: web/templates/public/surroundings.gohtml:60
msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Rutas de todo tipo, escalada, puertos de montaña, para todos los niveles."
#: web/templates/public/surroundings.gohtml:67
#: web/templates/public/surroundings.gohtml:64
msgid "Family outing"
msgstr "Excusiones familiares"
#: web/templates/public/surroundings.gohtml:68
#: web/templates/public/surroundings.gohtml:65
msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursiones para todas las edades."
#: web/templates/public/surroundings.gohtml:72
#: web/templates/public/surroundings.gohtml:69
msgid "Kayak"
msgstr "Kayak"
#: web/templates/public/surroundings.gohtml:73
#: web/templates/public/surroundings.gohtml:70
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Hay diversos puntos dónde podéis ir en kayak, desde tramos del río Ter como también en la costa…."
@ -410,7 +395,7 @@ msgstr "He leído y acepto <a href=\"%s\" target=\"_blank\">las condiciones de r
msgid "Campsite Montagut"
msgstr "Camping Montagut"
#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:20
#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:21
msgid "Skip to main content"
msgstr "Saltar al contenido principal"
@ -421,7 +406,7 @@ msgstr "Menú"
#: web/templates/public/layout.gohtml:57 web/templates/public/layout.gohtml:103
#: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:45 web/templates/admin/layout.gohtml:82
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:86
msgctxt "title"
msgid "Campsites"
msgstr "Alojamientos"
@ -464,6 +449,7 @@ msgstr "Álias"
#: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/services/form.gohtml:52
#: web/templates/admin/profile.gohtml:26
#: web/templates/admin/surroundings/form.gohtml:37
msgctxt "input"
msgid "Name"
msgstr "Nombre"
@ -482,6 +468,7 @@ msgstr "Contenido"
#: web/templates/admin/campsite/type/form.gohtml:171
#: web/templates/admin/season/form.gohtml:69
#: web/templates/admin/services/form.gohtml:80
#: web/templates/admin/surroundings/form.gohtml:65
#: web/templates/admin/media/form.gohtml:35
msgctxt "action"
msgid "Update"
@ -496,13 +483,14 @@ msgstr "Actualizar"
#: web/templates/admin/campsite/type/form.gohtml:173
#: web/templates/admin/season/form.gohtml:71
#: web/templates/admin/services/form.gohtml:82
#: web/templates/admin/surroundings/form.gohtml:67
msgctxt "action"
msgid "Add"
msgstr "Añadir"
#: web/templates/admin/legal/index.gohtml:6
#: web/templates/admin/legal/index.gohtml:12
#: web/templates/admin/layout.gohtml:63
#: web/templates/admin/layout.gohtml:67
msgctxt "title"
msgid "Legal Texts"
msgstr "Textos legales"
@ -517,6 +505,7 @@ msgstr "Añadir texto legal"
#: web/templates/admin/campsite/option/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:25
#: web/templates/admin/season/index.gohtml:26
#: web/templates/admin/surroundings/index.gohtml:26
msgctxt "header"
msgid "Name"
msgstr "Nombre"
@ -630,6 +619,7 @@ msgstr "Añadir diapositiva"
#: web/templates/admin/campsite/carousel/index.gohtml:25
#: web/templates/admin/services/index.gohtml:25
#: web/templates/admin/surroundings/index.gohtml:25
#: web/templates/admin/home/index.gohtml:25
msgctxt "header"
msgid "Image"
@ -645,6 +635,7 @@ msgstr "Leyenda"
#: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:72
#: web/templates/admin/surroundings/index.gohtml:27
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Actions"
@ -659,6 +650,7 @@ msgstr "¿Estáis seguro de querer borrar esta diapositiva?"
#: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:44
#: web/templates/admin/services/index.gohtml:88
#: web/templates/admin/surroundings/index.gohtml:44
#: web/templates/admin/home/index.gohtml:44
msgctxt "action"
msgid "Delete"
@ -826,6 +818,7 @@ msgstr "Equipamento"
#: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/services/form.gohtml:65
#: web/templates/admin/surroundings/form.gohtml:50
msgctxt "input"
msgid "Description"
msgstr "Descripción"
@ -837,7 +830,7 @@ msgstr "Información adicional"
#: web/templates/admin/campsite/type/index.gohtml:6
#: web/templates/admin/campsite/type/index.gohtml:12
#: web/templates/admin/layout.gohtml:42
#: web/templates/admin/layout.gohtml:43
msgctxt "title"
msgid "Campsite Types"
msgstr "Tipos de alojamientos"
@ -906,7 +899,7 @@ msgstr "Color"
#: web/templates/admin/season/index.gohtml:6
#: web/templates/admin/season/index.gohtml:12
#: web/templates/admin/layout.gohtml:48
#: web/templates/admin/layout.gohtml:49
msgctxt "title"
msgid "Seasons"
msgstr "Temporadas"
@ -932,7 +925,7 @@ msgid "Cancel"
msgstr "Cancelar"
#: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12
#: web/templates/admin/layout.gohtml:39
#: web/templates/admin/layout.gohtml:40
msgctxt "title"
msgid "Payment Settings"
msgstr "Parámetros de pago"
@ -968,7 +961,7 @@ msgid "Integration"
msgstr "Integración"
#: web/templates/admin/dashboard.gohtml:6
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:79
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:83
msgctxt "title"
msgid "Dashboard"
msgstr "Panel"
@ -1001,7 +994,7 @@ msgid "New Service"
msgstr "Nuevo servicio"
#: web/templates/admin/services/index.gohtml:6
#: web/templates/admin/layout.gohtml:57
#: web/templates/admin/layout.gohtml:58
msgctxt "title"
msgid "Services Page"
msgstr "Página de servicios"
@ -1036,7 +1029,7 @@ msgid "No services added yet."
msgstr "No se ha añadido ningún servicio todavía."
#: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12
#: web/templates/admin/layout.gohtml:32
#: web/templates/admin/layout.gohtml:33
msgctxt "title"
msgid "Profile"
msgstr "Perfil"
@ -1143,29 +1136,64 @@ msgctxt "input"
msgid "Legal Disclaimer"
msgstr "Nota legal"
#: web/templates/admin/layout.gohtml:28
#: web/templates/admin/surroundings/form.gohtml:8
#: web/templates/admin/surroundings/form.gohtml:25
msgctxt "title"
msgid "Edit Highlight"
msgstr "Edición del punto de interés"
#: web/templates/admin/surroundings/form.gohtml:10
#: web/templates/admin/surroundings/form.gohtml:27
msgctxt "title"
msgid "New Highlight"
msgstr "Nuevo punto de interés"
#: web/templates/admin/surroundings/index.gohtml:6
msgctxt "title"
msgid "Surroundings Page"
msgstr "Página del entorno"
#: web/templates/admin/surroundings/index.gohtml:11
msgctxt "title"
msgid "Highlights"
msgstr "Puntos de interés"
#: web/templates/admin/surroundings/index.gohtml:12
msgctxt "action"
msgid "Add highlight"
msgstr "Añadir punto de interés"
#: web/templates/admin/surroundings/index.gohtml:31
msgid "Are you sure you wish to delete this highlight?"
msgstr "¿Estáis seguro de querer borrar este punto de interés?"
#: web/templates/admin/surroundings/index.gohtml:53
msgid "No highlights added yet."
msgstr "No se ha añadido ningún punto de interés todavía."
#: web/templates/admin/layout.gohtml:29
msgctxt "title"
msgid "User Menu"
msgstr "Menú de usuario"
#: web/templates/admin/layout.gohtml:36
#: web/templates/admin/layout.gohtml:37
msgctxt "title"
msgid "Company Settings"
msgstr "Parámetros de la empresa"
#: web/templates/admin/layout.gohtml:51
#: web/templates/admin/layout.gohtml:52
#: web/templates/admin/media/index.gohtml:6
#: web/templates/admin/media/index.gohtml:11
msgctxt "title"
msgid "Media"
msgstr "Medios"
#: web/templates/admin/layout.gohtml:54 web/templates/admin/home/index.gohtml:6
#: web/templates/admin/layout.gohtml:55 web/templates/admin/home/index.gohtml:6
msgctxt "title"
msgid "Home Page"
msgstr "Página de inicio"
#: web/templates/admin/layout.gohtml:68
#: web/templates/admin/layout.gohtml:72
msgctxt "action"
msgid "Logout"
msgstr "Salir"
@ -1236,31 +1264,34 @@ msgid "Upload Media"
msgstr "Subida de medio"
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:344
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:464
#: pkg/season/admin.go:415 pkg/services/admin.go:319
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:463
#: pkg/season/admin.go:412 pkg/services/admin.go:314
#: pkg/surroundings/admin.go:321
msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco."
#: pkg/legal/admin.go:259 pkg/campsite/types/option.go:345
#: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:465
#: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:464
msgid "Name must have at least one letter."
msgstr "El nombre tiene que tener como mínimo una letra."
#: pkg/carousel/admin.go:269 pkg/campsite/types/carousel.go:223
#: pkg/carousel/admin.go:267 pkg/campsite/types/carousel.go:223
msgctxt "input"
msgid "Slide image"
msgstr "Imagen de la diapositiva"
#: pkg/carousel/admin.go:270 pkg/campsite/types/carousel.go:224
#: pkg/carousel/admin.go:268 pkg/campsite/types/carousel.go:224
msgctxt "action"
msgid "Set slide image"
msgstr "Establecer la imagen de la diapositiva"
#: pkg/carousel/admin.go:339 pkg/campsite/types/carousel.go:297
#: pkg/carousel/admin.go:337 pkg/campsite/types/carousel.go:297
#: pkg/surroundings/admin.go:316
msgid "Slide image can not be empty."
msgstr "No podéis dejar la imagen de la diapositiva en blanco."
#: pkg/carousel/admin.go:340 pkg/campsite/types/carousel.go:298
#: pkg/carousel/admin.go:338 pkg/campsite/types/carousel.go:298
#: pkg/surroundings/admin.go:317
msgid "Slide image must be an image media type."
msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen."
@ -1299,7 +1330,7 @@ msgstr "El idioma escogido no es válido."
msgid "File must be a valid PNG or JPEG image."
msgstr "El archivo tiene que ser una imagen PNG o JPEG válida."
#: pkg/app/admin.go:62
#: pkg/app/admin.go:64
msgid "Access forbidden"
msgstr "Acceso prohibido"
@ -1327,61 +1358,61 @@ msgstr "El valor del máximo tiene que ser un número entero."
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:361 pkg/campsite/types/admin.go:478
#: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:477
msgid "Price per night can not be empty."
msgstr "No podéis dejar el precio por noche en blanco."
#: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:479
#: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:478
msgid "Price per night must be a decimal number."
msgstr "El precio por noche tiene que ser un número decimal."
#: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:480
#: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:479
msgid "Price per night must be zero or greater."
msgstr "El precio por noche tiene que ser como mínimo cero."
#: pkg/campsite/types/feature.go:258 pkg/services/admin.go:318
#: pkg/campsite/types/feature.go:258 pkg/services/admin.go:313
msgid "Selected icon is not valid."
msgstr "El icono escogido no es válido."
#: pkg/campsite/types/admin.go:306
#: pkg/campsite/types/admin.go:305
msgctxt "input"
msgid "Cover image"
msgstr "Imagen de portada"
#: pkg/campsite/types/admin.go:307
#: pkg/campsite/types/admin.go:306
msgctxt "action"
msgid "Set campsite type cover"
msgstr "Establecer la portada del tipo de alojamiento"
#: pkg/campsite/types/admin.go:467
#: pkg/campsite/types/admin.go:466
msgid "Cover image can not be empty."
msgstr "No podéis dejar la imagen de portada en blanco."
#: pkg/campsite/types/admin.go:468
#: pkg/campsite/types/admin.go:467
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:472
#: pkg/campsite/types/admin.go:471
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:473
#: pkg/campsite/types/admin.go:472
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:474
#: pkg/campsite/types/admin.go:473
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:483
#: pkg/campsite/types/admin.go:482
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:484
#: pkg/campsite/types/admin.go:483
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:485
#: pkg/campsite/types/admin.go:484
msgid "Minimum number of nights must be one or greater."
msgstr "El número mínimo de noches no puede ser cero."
@ -1393,95 +1424,105 @@ msgstr "El tipo de alojamiento escogido no es válido."
msgid "Label can not be empty."
msgstr "No podéis dejar la etiqueta en blanco."
#: pkg/season/admin.go:186
#: pkg/season/admin.go:183
msgctxt "month"
msgid "January"
msgstr "enero"
#: pkg/season/admin.go:187
#: pkg/season/admin.go:184
msgctxt "month"
msgid "February"
msgstr "febrero"
#: pkg/season/admin.go:188
#: pkg/season/admin.go:185
msgctxt "month"
msgid "March"
msgstr "marzo"
#: pkg/season/admin.go:189
#: pkg/season/admin.go:186
msgctxt "month"
msgid "April"
msgstr "abril"
#: pkg/season/admin.go:190
#: pkg/season/admin.go:187
msgctxt "month"
msgid "May"
msgstr "mayo"
#: pkg/season/admin.go:191
#: pkg/season/admin.go:188
msgctxt "month"
msgid "June"
msgstr "junio"
#: pkg/season/admin.go:192
#: pkg/season/admin.go:189
msgctxt "month"
msgid "July"
msgstr "julio"
#: pkg/season/admin.go:193
#: pkg/season/admin.go:190
msgctxt "month"
msgid "August"
msgstr "agosto"
#: pkg/season/admin.go:194
#: pkg/season/admin.go:191
msgctxt "month"
msgid "September"
msgstr "septiembre"
#: pkg/season/admin.go:195
#: pkg/season/admin.go:192
msgctxt "month"
msgid "October"
msgstr "octubre"
#: pkg/season/admin.go:196
#: pkg/season/admin.go:193
msgctxt "month"
msgid "November"
msgstr "noviembre"
#: pkg/season/admin.go:197
#: pkg/season/admin.go:194
msgctxt "month"
msgid "December"
msgstr "diciembre"
#: pkg/season/admin.go:416
#: pkg/season/admin.go:413
msgid "Color can not be empty."
msgstr "No podéis dejar el color en blanco."
#: pkg/season/admin.go:417
#: pkg/season/admin.go:414
msgid "This color is not valid. It must be like #123abc."
msgstr "Este color no es válido. Tiene que ser parecido a #123abc."
#: pkg/season/admin.go:517
#: pkg/season/admin.go:514
msgctxt "action"
msgid "Unset"
msgstr "Desasignar"
#: pkg/season/admin.go:548
#: pkg/season/admin.go:545
msgid "Start date can not be empty."
msgstr "No podéis dejar la fecha de inicio en blanco."
#: pkg/season/admin.go:549
#: pkg/season/admin.go:546
msgid "Start date must be a valid date."
msgstr "La fecha de inicio tiene que ser una fecha válida."
#: pkg/season/admin.go:551
#: pkg/season/admin.go:548
msgid "End date can not be empty."
msgstr "No podéis dejar la fecha final en blanco."
#: pkg/season/admin.go:552
#: pkg/season/admin.go:549
msgid "End date must be a valid date."
msgstr "La fecha final tiene que ser una fecha válida."
#: pkg/surroundings/admin.go:267
msgctxt "input"
msgid "Highlight image"
msgstr "Imagen del punto de interés"
#: pkg/surroundings/admin.go:268
msgctxt "action"
msgid "Set highlight image"
msgstr "Establecer la imagen del punto de interés"
#: pkg/company/admin.go:200 pkg/booking/public.go:256
msgid "Selected country is not valid."
msgstr "El país escogido no es válido."
@ -1562,11 +1603,11 @@ msgstr "No podéis dejar el formato de número de factura en blanco."
msgid "Cross-site request forgery detected."
msgstr "Se ha detectado un intento de falsificación de petición en sitios cruzados."
#: pkg/media/admin.go:265
#: pkg/media/admin.go:312
msgid "Uploaded file can not be empty."
msgstr "No podéis dejar el archivo del medio en blanco."
#: pkg/media/admin.go:324
#: pkg/media/admin.go:371
msgid "Filename can not be empty."
msgstr "No podéis dejar el nombre del archivo en blanco."
@ -1674,6 +1715,18 @@ msgstr "%s tiene que ser como mínimo %d."
msgid "%s must be at most %d."
msgstr "%s tiene que ser como máximo %d"
#~ msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…."
#~ msgstr "El Camping Montagut es ideal como punto de salida de excursiones tranquilas, escalada, bañarse en el río y piletones, volcanes, la Fageda den Jordà, salidas en bicicleta para todos los niveles…."
#~ msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
#~ msgstr "Llegar hasta la Costa Brava y disfrutar de las playas, la gastronomía o ir en kayak…."
#~ msgid "You will also find museums in Olot, Figures, Girona."
#~ msgstr "También encontraréis museos en Olot, Figueres, Girona."
#~ msgid "As well as music festivals, dance, theater…."
#~ msgstr "Como festivales de música, danza, teatro…."
#~ msgctxt "header"
#~ msgid "Translations"
#~ msgstr "Traducciones"

225
po/fr.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-15 02:00+0100\n"
"POT-Creation-Date: 2024-01-16 00:48+0100\n"
"PO-Revision-Date: 2023-12-20 10:13+0100\n"
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
"Language-Team: French <traduc@traduc.org>\n"
@ -57,7 +57,7 @@ msgstr "Le camping propose de nombreux services différents."
#: web/templates/public/location.gohtml:6
#: web/templates/public/location.gohtml:12
#: web/templates/public/layout.gohtml:68 web/templates/public/layout.gohtml:96
#: web/templates/admin/layout.gohtml:60
#: web/templates/admin/layout.gohtml:61
msgctxt "title"
msgid "Location"
msgstr "Comment nous rejoindre"
@ -87,8 +87,9 @@ msgstr "Venez et profitez-en !"
#: web/templates/public/home.gohtml:35
#: web/templates/public/surroundings.gohtml:6
#: web/templates/public/surroundings.gohtml:10
#: web/templates/public/surroundings.gohtml:11
#: web/templates/public/layout.gohtml:67 web/templates/public/layout.gohtml:95
#: web/templates/admin/layout.gohtml:64
msgctxt "title"
msgid "Surroundings"
msgstr "Entourage"
@ -252,61 +253,45 @@ msgctxt "day"
msgid "Sun"
msgstr "Dim."
#: web/templates/public/surroundings.gohtml:28
#: web/templates/public/surroundings.gohtml:31
msgctxt "title"
msgid "What to Do Outside the Campsite?"
msgstr "Que faire à lextérieur du camping ?"
#: web/templates/public/surroundings.gohtml:31
msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…."
msgstr "Le camping Montagut est un point de départ idéal pour des sorties tranquilles, de lescalade, des baignades dans la rivière et les gorges, les volcans, la Fageda dâen Jordã, des randonnées à vélo pour tous les âges…."
#: web/templates/public/surroundings.gohtml:38
msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
msgstr "Rendez-vous sur la Costa Brava et profitez des plages, de la gastronomie ou faites du kayak…."
#: web/templates/public/surroundings.gohtml:47
msgid "You will also find museums in Olot, Figures, Girona."
msgstr "Vous trouverez également des musées à Olot, Figures, Gérone."
#: web/templates/public/surroundings.gohtml:48
msgid "As well as music festivals, dance, theater…."
msgstr "Ainsi que des festivals de musique, de danse, de théâtre…."
#: web/templates/public/surroundings.gohtml:54
#: web/templates/public/surroundings.gohtml:51
msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Une fois au camping, nous pourrons vous informer sur les activités disponibles"
#: web/templates/public/surroundings.gohtml:57
#: web/templates/public/surroundings.gohtml:54
msgid "Cycle routes"
msgstr "Pistes cyclables"
#: web/templates/public/surroundings.gohtml:58
#: web/templates/public/surroundings.gohtml:55
msgid "There are many bicycle rental companies in Olot."
msgstr "Il existe de nombreuses sociétés de location de vélos à Olot."
#: web/templates/public/surroundings.gohtml:62
#: web/templates/public/surroundings.gohtml:59
msgid "Routes"
msgstr "Itinéraires"
#: web/templates/public/surroundings.gohtml:63
#: web/templates/public/surroundings.gohtml:60
msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Itinéraires de toutes sortes, escalade, cols de montagne, pour tous les niveaux."
#: web/templates/public/surroundings.gohtml:67
#: web/templates/public/surroundings.gohtml:64
msgid "Family outing"
msgstr "Sortie en famille"
#: web/templates/public/surroundings.gohtml:68
#: web/templates/public/surroundings.gohtml:65
msgid "Many outing possibilities, for all ages."
msgstr "Nombreuses possibilités de sorties, pour tous les âges."
#: web/templates/public/surroundings.gohtml:72
#: web/templates/public/surroundings.gohtml:69
msgid "Kayak"
msgstr "Kayak"
#: web/templates/public/surroundings.gohtml:73
#: web/templates/public/surroundings.gohtml:70
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Il y a plusieurs points où vous pouvez aller en kayak, à partir de sections de la rivière Ter ainsi que sur la côte…."
@ -411,7 +396,7 @@ msgstr "Jai lu et jaccepte <a href=\"%s\" target=\"_blank\">les conditions
msgid "Campsite Montagut"
msgstr "Camping Montagut"
#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:20
#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:21
msgid "Skip to main content"
msgstr "Passer au contenu principal"
@ -422,7 +407,7 @@ msgstr "Menu"
#: web/templates/public/layout.gohtml:57 web/templates/public/layout.gohtml:103
#: web/templates/admin/campsite/index.gohtml:6
#: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:45 web/templates/admin/layout.gohtml:82
#: web/templates/admin/layout.gohtml:46 web/templates/admin/layout.gohtml:86
msgctxt "title"
msgid "Campsites"
msgstr "Locatifs"
@ -465,6 +450,7 @@ msgstr "Slug"
#: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/services/form.gohtml:52
#: web/templates/admin/profile.gohtml:26
#: web/templates/admin/surroundings/form.gohtml:37
msgctxt "input"
msgid "Name"
msgstr "Nom"
@ -483,6 +469,7 @@ msgstr "Contenu"
#: web/templates/admin/campsite/type/form.gohtml:171
#: web/templates/admin/season/form.gohtml:69
#: web/templates/admin/services/form.gohtml:80
#: web/templates/admin/surroundings/form.gohtml:65
#: web/templates/admin/media/form.gohtml:35
msgctxt "action"
msgid "Update"
@ -497,13 +484,14 @@ msgstr "Mettre à jour"
#: web/templates/admin/campsite/type/form.gohtml:173
#: web/templates/admin/season/form.gohtml:71
#: web/templates/admin/services/form.gohtml:82
#: web/templates/admin/surroundings/form.gohtml:67
msgctxt "action"
msgid "Add"
msgstr "Ajouter"
#: web/templates/admin/legal/index.gohtml:6
#: web/templates/admin/legal/index.gohtml:12
#: web/templates/admin/layout.gohtml:63
#: web/templates/admin/layout.gohtml:67
msgctxt "title"
msgid "Legal Texts"
msgstr "Textes juridiques"
@ -518,6 +506,7 @@ msgstr "Ajouter un texte juridique"
#: web/templates/admin/campsite/option/index.gohtml:25
#: web/templates/admin/campsite/type/index.gohtml:25
#: web/templates/admin/season/index.gohtml:26
#: web/templates/admin/surroundings/index.gohtml:26
msgctxt "header"
msgid "Name"
msgstr "Nom"
@ -631,6 +620,7 @@ msgstr "Ajouter la diapositive"
#: web/templates/admin/campsite/carousel/index.gohtml:25
#: web/templates/admin/services/index.gohtml:25
#: web/templates/admin/surroundings/index.gohtml:25
#: web/templates/admin/home/index.gohtml:25
msgctxt "header"
msgid "Image"
@ -646,6 +636,7 @@ msgstr "Légende"
#: web/templates/admin/campsite/carousel/index.gohtml:27
#: web/templates/admin/services/index.gohtml:27
#: web/templates/admin/services/index.gohtml:72
#: web/templates/admin/surroundings/index.gohtml:27
#: web/templates/admin/home/index.gohtml:27
msgctxt "header"
msgid "Actions"
@ -660,6 +651,7 @@ msgstr "Êtes-vous sûr de vouloir supprimer cette diapositive ?"
#: web/templates/admin/campsite/carousel/index.gohtml:45
#: web/templates/admin/services/index.gohtml:44
#: web/templates/admin/services/index.gohtml:88
#: web/templates/admin/surroundings/index.gohtml:44
#: web/templates/admin/home/index.gohtml:44
msgctxt "action"
msgid "Delete"
@ -827,6 +819,7 @@ msgstr "Installations"
#: web/templates/admin/campsite/type/form.gohtml:143
#: web/templates/admin/services/form.gohtml:65
#: web/templates/admin/surroundings/form.gohtml:50
msgctxt "input"
msgid "Description"
msgstr "Description"
@ -838,7 +831,7 @@ msgstr "Informations Complémentaires"
#: web/templates/admin/campsite/type/index.gohtml:6
#: web/templates/admin/campsite/type/index.gohtml:12
#: web/templates/admin/layout.gohtml:42
#: web/templates/admin/layout.gohtml:43
msgctxt "title"
msgid "Campsite Types"
msgstr "Types demplacements de camping"
@ -907,7 +900,7 @@ msgstr "Couleur"
#: web/templates/admin/season/index.gohtml:6
#: web/templates/admin/season/index.gohtml:12
#: web/templates/admin/layout.gohtml:48
#: web/templates/admin/layout.gohtml:49
msgctxt "title"
msgid "Seasons"
msgstr "Saisons"
@ -933,7 +926,7 @@ msgid "Cancel"
msgstr "Annuler"
#: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12
#: web/templates/admin/layout.gohtml:39
#: web/templates/admin/layout.gohtml:40
msgctxt "title"
msgid "Payment Settings"
msgstr "Paramètres de paiement"
@ -969,7 +962,7 @@ msgid "Integration"
msgstr "Intégration"
#: web/templates/admin/dashboard.gohtml:6
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:79
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:83
msgctxt "title"
msgid "Dashboard"
msgstr "Tableau de bord"
@ -1002,7 +995,7 @@ msgid "New Service"
msgstr "Nouveau service"
#: web/templates/admin/services/index.gohtml:6
#: web/templates/admin/layout.gohtml:57
#: web/templates/admin/layout.gohtml:58
msgctxt "title"
msgid "Services Page"
msgstr "La page des services"
@ -1037,7 +1030,7 @@ msgid "No services added yet."
msgstr "Aucun service na encore été ajouté."
#: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12
#: web/templates/admin/layout.gohtml:32
#: web/templates/admin/layout.gohtml:33
msgctxt "title"
msgid "Profile"
msgstr "Profil"
@ -1144,29 +1137,64 @@ msgctxt "input"
msgid "Legal Disclaimer"
msgstr "Avertissement juridique"
#: web/templates/admin/layout.gohtml:28
#: web/templates/admin/surroundings/form.gohtml:8
#: web/templates/admin/surroundings/form.gohtml:25
msgctxt "title"
msgid "Edit Highlight"
msgstr "Modifier un point dintérêt"
#: web/templates/admin/surroundings/form.gohtml:10
#: web/templates/admin/surroundings/form.gohtml:27
msgctxt "title"
msgid "New Highlight"
msgstr "Nouveau point dintérêt"
#: web/templates/admin/surroundings/index.gohtml:6
msgctxt "title"
msgid "Surroundings Page"
msgstr "Page de lentourage"
#: web/templates/admin/surroundings/index.gohtml:11
msgctxt "title"
msgid "Highlights"
msgstr "Points dintérêt"
#: web/templates/admin/surroundings/index.gohtml:12
msgctxt "action"
msgid "Add highlight"
msgstr "Ajouter un point dintérêt"
#: web/templates/admin/surroundings/index.gohtml:31
msgid "Are you sure you wish to delete this highlight?"
msgstr "Êtes-vous sûr de vouloir supprimer cette point dintérêt ?"
#: web/templates/admin/surroundings/index.gohtml:53
msgid "No highlights added yet."
msgstr "Aucun point dintérêt na encore été ajoutée."
#: web/templates/admin/layout.gohtml:29
msgctxt "title"
msgid "User Menu"
msgstr "Menu utilisateur"
#: web/templates/admin/layout.gohtml:36
#: web/templates/admin/layout.gohtml:37
msgctxt "title"
msgid "Company Settings"
msgstr "Paramètres de l'entreprise"
#: web/templates/admin/layout.gohtml:51
#: web/templates/admin/layout.gohtml:52
#: web/templates/admin/media/index.gohtml:6
#: web/templates/admin/media/index.gohtml:11
msgctxt "title"
msgid "Media"
msgstr "Média"
#: web/templates/admin/layout.gohtml:54 web/templates/admin/home/index.gohtml:6
#: web/templates/admin/layout.gohtml:55 web/templates/admin/home/index.gohtml:6
msgctxt "title"
msgid "Home Page"
msgstr "Page d'accueil"
#: web/templates/admin/layout.gohtml:68
#: web/templates/admin/layout.gohtml:72
msgctxt "action"
msgid "Logout"
msgstr "Déconnexion"
@ -1237,31 +1265,34 @@ msgid "Upload Media"
msgstr "Envoyer un fichier"
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:344
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:464
#: pkg/season/admin.go:415 pkg/services/admin.go:319
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:463
#: pkg/season/admin.go:412 pkg/services/admin.go:314
#: pkg/surroundings/admin.go:321
msgid "Name can not be empty."
msgstr "Le nom ne peut pas être laissé vide."
#: pkg/legal/admin.go:259 pkg/campsite/types/option.go:345
#: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:465
#: pkg/campsite/types/feature.go:260 pkg/campsite/types/admin.go:464
msgid "Name must have at least one letter."
msgstr "Le nom doit comporter au moins une lettre."
#: pkg/carousel/admin.go:269 pkg/campsite/types/carousel.go:223
#: pkg/carousel/admin.go:267 pkg/campsite/types/carousel.go:223
msgctxt "input"
msgid "Slide image"
msgstr "Image du diaporama"
#: pkg/carousel/admin.go:270 pkg/campsite/types/carousel.go:224
#: pkg/carousel/admin.go:268 pkg/campsite/types/carousel.go:224
msgctxt "action"
msgid "Set slide image"
msgstr "Définir limage de la diapositive"
#: pkg/carousel/admin.go:339 pkg/campsite/types/carousel.go:297
#: pkg/carousel/admin.go:337 pkg/campsite/types/carousel.go:297
#: pkg/surroundings/admin.go:316
msgid "Slide image can not be empty."
msgstr "Limage de la diapositive ne peut pas être vide."
#: pkg/carousel/admin.go:340 pkg/campsite/types/carousel.go:298
#: pkg/carousel/admin.go:338 pkg/campsite/types/carousel.go:298
#: pkg/surroundings/admin.go:317
msgid "Slide image must be an image media type."
msgstr "Limage de la diapositive doit être de type média dimage."
@ -1300,7 +1331,7 @@ msgstr "La langue sélectionnée nest pas valide."
msgid "File must be a valid PNG or JPEG image."
msgstr "Le fichier doit être une image PNG ou JPEG valide."
#: pkg/app/admin.go:62
#: pkg/app/admin.go:64
msgid "Access forbidden"
msgstr "Accès interdit"
@ -1328,61 +1359,61 @@ msgstr "Le maximum doit être un nombre entier."
msgid "Maximum must be equal or greater than minimum."
msgstr "Le maximum doit être égal ou supérieur au minimum."
#: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:478
#: pkg/campsite/types/option.go:361 pkg/campsite/types/admin.go:477
msgid "Price per night can not be empty."
msgstr "Le prix par nuit ne peut pas être vide."
#: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:479
#: pkg/campsite/types/option.go:362 pkg/campsite/types/admin.go:478
msgid "Price per night must be a decimal number."
msgstr "Le prix par nuit doit être un nombre décimal."
#: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:480
#: pkg/campsite/types/option.go:363 pkg/campsite/types/admin.go:479
msgid "Price per night must be zero or greater."
msgstr "Le prix par nuit doit être égal ou supérieur."
#: pkg/campsite/types/feature.go:258 pkg/services/admin.go:318
#: pkg/campsite/types/feature.go:258 pkg/services/admin.go:313
msgid "Selected icon is not valid."
msgstr "Licône sélectionnée nest pas valide."
#: pkg/campsite/types/admin.go:306
#: pkg/campsite/types/admin.go:305
msgctxt "input"
msgid "Cover image"
msgstr "Image de couverture"
#: pkg/campsite/types/admin.go:307
#: pkg/campsite/types/admin.go:306
msgctxt "action"
msgid "Set campsite type cover"
msgstr "Définir une couverture type camping"
#: pkg/campsite/types/admin.go:467
#: pkg/campsite/types/admin.go:466
msgid "Cover image can not be empty."
msgstr "Limage de couverture ne peut pas être vide."
#: pkg/campsite/types/admin.go:468
#: pkg/campsite/types/admin.go:467
msgid "Cover image must be an image media type."
msgstr "Limage de couverture doit être de type média dimage."
#: pkg/campsite/types/admin.go:472
#: pkg/campsite/types/admin.go:471
msgid "Maximum number of campers can not be empty."
msgstr "Le nombre maximum de campeurs ne peut pas être vide."
#: pkg/campsite/types/admin.go:473
#: pkg/campsite/types/admin.go:472
msgid "Maximum number of campers must be an integer number."
msgstr "Le nombre maximum de campeurs doit être un nombre entier."
#: pkg/campsite/types/admin.go:474
#: pkg/campsite/types/admin.go:473
msgid "Maximum number of campers must be one or greater."
msgstr "Le nombre maximum de campeurs doit être égal ou supérieur à un campeur."
#: pkg/campsite/types/admin.go:483
#: pkg/campsite/types/admin.go:482
msgid "Minimum number of nights can not be empty."
msgstr "Le nombre minimum de nuits ne peut pas être vide."
#: pkg/campsite/types/admin.go:484
#: pkg/campsite/types/admin.go:483
msgid "Minimum number of nights must be an integer."
msgstr "Le nombre minimum de nuits doit être un entier."
#: pkg/campsite/types/admin.go:485
#: pkg/campsite/types/admin.go:484
msgid "Minimum number of nights must be one or greater."
msgstr "Le nombre minimum de nuits doit être supérieur ou égal à une nuit."
@ -1394,95 +1425,105 @@ msgstr "Le type demplacement sélectionné nest pas valide."
msgid "Label can not be empty."
msgstr "L'étiquette ne peut pas être vide."
#: pkg/season/admin.go:186
#: pkg/season/admin.go:183
msgctxt "month"
msgid "January"
msgstr "Janvier"
#: pkg/season/admin.go:187
#: pkg/season/admin.go:184
msgctxt "month"
msgid "February"
msgstr "Février"
#: pkg/season/admin.go:188
#: pkg/season/admin.go:185
msgctxt "month"
msgid "March"
msgstr "Mars"
#: pkg/season/admin.go:189
#: pkg/season/admin.go:186
msgctxt "month"
msgid "April"
msgstr "Avril"
#: pkg/season/admin.go:190
#: pkg/season/admin.go:187
msgctxt "month"
msgid "May"
msgstr "Mai"
#: pkg/season/admin.go:191
#: pkg/season/admin.go:188
msgctxt "month"
msgid "June"
msgstr "Juin"
#: pkg/season/admin.go:192
#: pkg/season/admin.go:189
msgctxt "month"
msgid "July"
msgstr "Juillet"
#: pkg/season/admin.go:193
#: pkg/season/admin.go:190
msgctxt "month"
msgid "August"
msgstr "Août"
#: pkg/season/admin.go:194
#: pkg/season/admin.go:191
msgctxt "month"
msgid "September"
msgstr "Septembre"
#: pkg/season/admin.go:195
#: pkg/season/admin.go:192
msgctxt "month"
msgid "October"
msgstr "Octobre"
#: pkg/season/admin.go:196
#: pkg/season/admin.go:193
msgctxt "month"
msgid "November"
msgstr "Novembre"
#: pkg/season/admin.go:197
#: pkg/season/admin.go:194
msgctxt "month"
msgid "December"
msgstr "Décembre"
#: pkg/season/admin.go:416
#: pkg/season/admin.go:413
msgid "Color can not be empty."
msgstr "La couleur ne peut pas être vide."
#: pkg/season/admin.go:417
#: pkg/season/admin.go:414
msgid "This color is not valid. It must be like #123abc."
msgstr "Cette couleur nest pas valide. Il doit être comme #123abc."
#: pkg/season/admin.go:517
#: pkg/season/admin.go:514
msgctxt "action"
msgid "Unset"
msgstr "Unset"
#: pkg/season/admin.go:548
#: pkg/season/admin.go:545
msgid "Start date can not be empty."
msgstr "La date de début ne peut pas être vide."
#: pkg/season/admin.go:549
#: pkg/season/admin.go:546
msgid "Start date must be a valid date."
msgstr "La date de début doit être une date valide."
#: pkg/season/admin.go:551
#: pkg/season/admin.go:548
msgid "End date can not be empty."
msgstr "La date de fin ne peut pas être vide."
#: pkg/season/admin.go:552
#: pkg/season/admin.go:549
msgid "End date must be a valid date."
msgstr "La date de fin doit être une date valide."
#: pkg/surroundings/admin.go:267
msgctxt "input"
msgid "Highlight image"
msgstr "Image du point dintérêt"
#: pkg/surroundings/admin.go:268
msgctxt "action"
msgid "Set highlight image"
msgstr "Définir limage du point dintérêt"
#: pkg/company/admin.go:200 pkg/booking/public.go:256
msgid "Selected country is not valid."
msgstr "Le pays sélectionné nest pas valide."
@ -1563,11 +1604,11 @@ msgstr "Le format du numéro de facture ne peut pas être vide."
msgid "Cross-site request forgery detected."
msgstr "Détection dune falsification de requête intersites."
#: pkg/media/admin.go:265
#: pkg/media/admin.go:312
msgid "Uploaded file can not be empty."
msgstr "Le fichier téléchargé ne peut pas être vide."
#: pkg/media/admin.go:324
#: pkg/media/admin.go:371
msgid "Filename can not be empty."
msgstr "Le nom de fichier ne peut pas être vide."
@ -1675,6 +1716,18 @@ msgstr "%s doit être %d ou plus."
msgid "%s must be at most %d."
msgstr "%s doit être tout au plus %d."
#~ msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…."
#~ msgstr "Le camping Montagut est un point de départ idéal pour des sorties tranquilles, de lescalade, des baignades dans la rivière et les gorges, les volcans, la Fageda dâen Jordã, des randonnées à vélo pour tous les âges…."
#~ msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
#~ msgstr "Rendez-vous sur la Costa Brava et profitez des plages, de la gastronomie ou faites du kayak…."
#~ msgid "You will also find museums in Olot, Figures, Girona."
#~ msgstr "Vous trouverez également des musées à Olot, Figures, Gérone."
#~ msgid "As well as music festivals, dance, theater…."
#~ msgstr "Ainsi que des festivals de musique, de danse, de théâtre…."
#~ msgctxt "header"
#~ msgid "Translations"
#~ msgstr "Traductions"

View File

@ -0,0 +1,7 @@
-- Revert camper:add_surroundings_highlight from pg
begin;
drop function if exists camper.add_surroundings_highlight(integer, integer, text, text);
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:edit_surroundings_highlight from pg
begin;
drop function if exists camper.edit_surroundings_highlight(integer, integer, text, text);
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:order_surroundings_highlights from pg
begin;
drop function if exists camper.order_surroundings_highlights(integer[]);
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:remove_surroundings_highlight from pg
begin;
drop function if exists camper.remove_surroundings_highlight(integer);
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:surroundings_highlight from pg
begin;
drop table if exists camper.surroundings_highlight;
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:surroundings_highlight_i18n from pg
begin;
drop table if exists camper.surroundings_highlight_i18n;
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:translate_surroundings_highlight from pg
begin;
drop function if exists camper.translate_surroundings_highlight(integer, text, text, text);
commit;

View File

@ -141,3 +141,10 @@ campsite_type_i18n__additional_info [campsite_type_i18n] 2024-01-14T22:03:03Z jo
add_campsite_type [add_campsite_type@v0 campsite_type__additional_info] 2024-01-14T22:06:19Z jordi fita mas <jordi@tandem.blog> # Add additional_info parameter to add_campsite_type
edit_campsite_type [edit_campsite_type@v0 campsite_type__additional_info] 2024-01-14T22:09:40Z jordi fita mas <jordi@tandem.blog> # Add additional_info parameter to edit_campsite_type
translate_campsite_type [translate_campsite_type@v0 campsite_type_i18n__additional_info] 2024-01-14T22:12:08Z jordi fita mas <jordi@tandem.blog> # Add additional_info parameter to translate_campsite_type
surroundings_highlight [roles schema_camper company media user_profile] 2024-01-15T19:22:57Z jordi fita mas <jordi@tandem.blog> # Add relation for surroundings highlights
add_surroundings_highlight [roles schema_camper surroundings_highlight] 2024-01-15T19:40:37Z jordi fita mas <jordi@tandem.blog> # Add function to add new surroundings highlighs
edit_surroundings_highlight [roles schema_camper surroundings_highlight] 2024-01-15T19:48:04Z jordi fita mas <jordi@tandem.blog> # Add function to update surrounding higlights
surroundings_highlight_i18n [roles schema_camper surroundings_highlight language] 2024-01-15T20:00:45Z jordi fita mas <jordi@tandem.blog> # Add relation for surrounding highlights translations
translate_surroundings_highlight [roles schema_camper surroundings_highlight_i18n] 2024-01-15T20:09:40Z jordi fita mas <jordi@tandem.blog> # Add function to translate surroundings highlights
remove_surroundings_highlight [roles schema_camper surroundings_highlight surroundings_highlight_i18n] 2024-01-15T20:19:37Z jordi fita mas <jordi@tandem.blog> # Add function to delete surroundings highlight and their translations
order_surroundings_highlights [roles schema_camper surroundings_highlight] 2024-01-15T20:29:59Z jordi fita mas <jordi@tandem.blog> # Add function to order surrounding highlights

View File

@ -0,0 +1,66 @@
-- Test add_surroundings_highlight
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(12);
set search_path to camper, public;
select has_function('camper', 'add_surroundings_highlight', array['integer', 'integer', 'text', 'text']);
select function_lang_is('camper', 'add_surroundings_highlight', array['integer', 'integer', 'text', 'text'], 'sql');
select function_returns('camper', 'add_surroundings_highlight', array['integer', 'integer', 'text', 'text'], 'integer');
select isnt_definer('camper', 'add_surroundings_highlight', array['integer', 'integer', 'text', 'text']);
select volatility_is('camper', 'add_surroundings_highlight', array['integer', 'integer', 'text', 'text'], 'volatile');
select function_privs_are('camper', 'add_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'guest', array[]::text[]);
select function_privs_are('camper', 'add_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'employee', array[]::text[]);
select function_privs_are('camper', 'add_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'add_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_highlight 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, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', '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 (3, 1, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
, (4, 2, 'cover4.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};'))
;
select lives_ok(
$$ select add_surroundings_highlight(1, 3, 'Highlight A', '<p>What</p>') $$,
'Should be able to add a surroundings highlight to the first company'
);
select lives_ok(
$$ select add_surroundings_highlight(2, 4, 'Highlight B', '') $$,
'Should be able to add a surroundings highlight to the second company'
);
select bag_eq(
$$ select company_id, media_id, name, description::text from surroundings_highlight $$,
$$ values (1, 3, 'Highlight A', '<p>What</p>')
, (2, 4, 'Highlight B', '')
$$,
'Should have added all two surroundings highlight'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,74 @@
-- Test edit_surroundings_highlight
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(12);
set search_path to camper, public;
select has_function('camper', 'edit_surroundings_highlight', array['integer', 'integer', 'text', 'text']);
select function_lang_is('camper', 'edit_surroundings_highlight', array['integer', 'integer', 'text', 'text'], 'sql');
select function_returns('camper', 'edit_surroundings_highlight', array['integer', 'integer', 'text', 'text'], 'integer');
select isnt_definer('camper', 'edit_surroundings_highlight', array['integer', 'integer', 'text', 'text']);
select volatility_is('camper', 'edit_surroundings_highlight', array['integer', 'integer', 'text', 'text'], 'volatile');
select function_privs_are('camper', 'edit_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'guest', array[]::text[]);
select function_privs_are('camper', 'edit_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'employee', array[]::text[]);
select function_privs_are('camper', 'edit_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'edit_surroundings_highlight', array ['integer', 'integer', 'text', 'text'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_highlight 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, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, '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"};')
, ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ff00ff","a"};')
, ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffff00","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"};'))
, (3, 1, 'cover3.xpm', sha256('static char *s[]={"1 1 1 1","a c #ff00ff","a"};'))
, (4, 1, 'cover4.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffff00","a"};'))
;
insert into surroundings_highlight (surroundings_highlight_id, company_id, media_id, name, description)
values (8, 1, 2, 'Highlight A', '<h1>1</h1>')
, (9, 1, 3, 'Highlight B', '<h2>2</h2>')
;
select lives_ok(
$$ select edit_surroundings_highlight(8, 4, 'Highlight 1', '<h3>A</h3>') $$,
'Should be able to edit the first highlight'
);
select lives_ok(
$$ select edit_surroundings_highlight(9, null, 'Highlight 2', '<h1>B</h1>') $$,
'Should be able to edit the second highlight'
);
select bag_eq(
$$ select surroundings_highlight_id, media_id, name, description::text from surroundings_highlight $$,
$$ values (8, 4, 'Highlight 1', '<h3>A</h3>')
, (9, 3, 'Highlight 2', '<h1>B</h1>')
$$,
'Should have updated all surroundings highlights.'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,71 @@
-- Test order_surroundings_highlights
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(11);
set search_path to camper, public;
select has_function('camper', 'order_surroundings_highlights', array['integer[]']);
select function_lang_is('camper', 'order_surroundings_highlights', array['integer[]'], 'sql');
select function_returns('camper', 'order_surroundings_highlights', array['integer[]'], 'void');
select isnt_definer('camper', 'order_surroundings_highlights', array['integer[]']);
select volatility_is('camper', 'order_surroundings_highlights', array['integer[]'], 'volatile');
select function_privs_are('camper', 'order_surroundings_highlights', array ['integer[]'], 'guest', array[]::text[]);
select function_privs_are('camper', 'order_surroundings_highlights', array ['integer[]'], 'employee', array[]::text[]);
select function_privs_are('camper', 'order_surroundings_highlights', array ['integer[]'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'order_surroundings_highlights', array ['integer[]'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_highlight 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, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, '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 surroundings_highlight (surroundings_highlight_id, company_id, media_id, name, description)
values (3, 1, 2, 'A', '')
, (4, 1, 2, 'B', '')
, (5, 1, 2, 'C', '')
, (6, 1, 2, 'D', '')
, (7, 1, 2, 'E', '')
;
select lives_ok(
$$ select order_surroundings_highlights('{5,7,6,3,4}') $$,
'Should be able to sort surroundings highlights using their ids'
);
select bag_eq(
$$ select surroundings_highlight_id, position from surroundings_highlight $$,
$$ values (5, 1)
, (7, 2)
, (6, 3)
, (3, 4)
, (4, 5)
$$,
'Should have sorted all surroundings highlights.'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,87 @@
-- Test remove_surroundings_highlight
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(12);
set search_path to camper, public;
select has_function('camper', 'remove_surroundings_highlight', array['integer']);
select function_lang_is('camper', 'remove_surroundings_highlight', array['integer'], 'sql');
select function_returns('camper', 'remove_surroundings_highlight', array['integer'], 'void');
select isnt_definer('camper', 'remove_surroundings_highlight', array['integer']);
select volatility_is('camper', 'remove_surroundings_highlight', array['integer'], 'volatile');
select function_privs_are('camper', 'remove_surroundings_highlight', array['integer'], 'guest', array[]::text[]);
select function_privs_are('camper', 'remove_surroundings_highlight', array['integer'], 'employee', array[]::text[]);
select function_privs_are('camper', 'remove_surroundings_highlight', array['integer'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'remove_surroundings_highlight', array['integer'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_highlight 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, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, '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"};')
, ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ff00ff","a"};')
, ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffff00","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"};'))
, (3, 1, 'cover3.xpm', sha256('static char *s[]={"1 1 1 1","a c #ff00ff","a"};'))
, (4, 1, 'cover4.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffff00","a"};'))
;
insert into surroundings_highlight (surroundings_highlight_id, company_id, media_id, name, description)
values (7, 1, 2, 'Highlight A', '<h2>One</h2>')
, (8, 1, 3, 'Highlight B', '<h2>Two</h2>')
, (9, 1, 3, 'Highlight C', '<h2>Three</h2>')
;
insert into surroundings_highlight_i18n (surroundings_highlight_id, lang_tag, name, description)
values (7, 'ca', 'Destacat A', '')
, (7, 'es', 'Destacado A', '')
, (8, 'ca', 'Destacat B', '')
, (8, 'es', 'Destacado B', '')
, (9, 'ca', 'Destacat C', '')
, (9, 'es', 'Destacado C', '')
;
select lives_ok(
$$ select remove_surroundings_highlight(8) $$,
'Should be able to delete a service'
);
select bag_eq(
$$ select surroundings_highlight_id, name from surroundings_highlight $$,
$$ values (7, 'Highlight A')
, (9, 'Highlight C')
$$,
'Should have removed the highlight'
);
select bag_eq(
$$ select surroundings_highlight_id, lang_tag, name from surroundings_highlight_i18n $$,
$$ values (7, 'ca', 'Destacat A')
, (7, 'es', 'Destacado A')
, (9, 'ca', 'Destacat C')
, (9, 'es', 'Destacado C')
$$,
'Should have removed the highlights translations'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,210 @@
-- Test surroundings_highlight
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(50);
set search_path to camper, public;
select has_table('surroundings_highlight');
select has_pk('surroundings_highlight');
select table_privs_are('surroundings_highlight', 'guest', array['SELECT']);
select table_privs_are('surroundings_highlight', 'employee', array['SELECT']);
select table_privs_are('surroundings_highlight', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
select table_privs_are('surroundings_highlight', 'authenticator', array[]::text[]);
select has_column('surroundings_highlight', 'surroundings_highlight_id');
select col_is_pk('surroundings_highlight', 'surroundings_highlight_id');
select col_type_is('surroundings_highlight', 'surroundings_highlight_id', 'integer');
select col_not_null('surroundings_highlight', 'surroundings_highlight_id');
select col_hasnt_default('surroundings_highlight', 'surroundings_highlight_id');
select has_column('surroundings_highlight', 'company_id');
select col_is_fk('surroundings_highlight', 'company_id');
select fk_ok('surroundings_highlight', 'company_id', 'company', 'company_id');
select col_type_is('surroundings_highlight', 'company_id', 'integer');
select col_not_null('surroundings_highlight', 'company_id');
select col_hasnt_default('surroundings_highlight', 'company_id');
select has_column('surroundings_highlight', 'media_id');
select col_type_is('surroundings_highlight', 'media_id', 'integer');
select col_not_null('surroundings_highlight', 'media_id');
select col_hasnt_default('surroundings_highlight', 'media_id');
select has_column('surroundings_highlight', 'name');
select col_is_fk('surroundings_highlight', 'media_id');
select fk_ok('surroundings_highlight', 'media_id', 'media', 'media_id');
select col_type_is('surroundings_highlight', 'name', 'text');
select col_not_null('surroundings_highlight', 'name');
select col_hasnt_default('surroundings_highlight', 'name');
select has_column('surroundings_highlight', 'description');
select col_type_is('surroundings_highlight', 'description', 'xml');
select col_not_null('surroundings_highlight', 'description');
select col_hasnt_default('surroundings_highlight', 'description');
select has_column('surroundings_highlight', 'position');
select col_type_is('surroundings_highlight', 'position', 'integer');
select col_not_null('surroundings_highlight', 'position');
select col_has_default('surroundings_highlight', 'position');
select col_default_is('surroundings_highlight', 'position', '2147483647');
set client_min_messages to warning;
truncate surroundings_highlight 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, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, '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 surroundings_highlight (company_id, media_id, name, description)
values (2, 6, 'Girona', '<p>Beautiful</p>')
, (4, 8, 'Barcelona', '<p>Shit</p>')
;
prepare surroundings_highlight_data as
select company_id, name
from surroundings_highlight
order by company_id, name;
set role guest;
select bag_eq(
'surroundings_highlight_data',
$$ values (2, 'Girona')
, (4, 'Barcelona')
$$,
'Everyone should be able to list all surroundings highlights across all companies'
);
reset role;
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2');
select lives_ok(
$$ insert into surroundings_highlight(company_id, media_id, name, description) values (2, 6, 'Another highlight', '<div/>') $$,
'Admin from company 2 should be able to insert a new surroundings highlights to that company.'
);
select bag_eq(
'surroundings_highlight_data',
$$ values (2, 'Girona')
, (2, 'Another highlight')
, (4, 'Barcelona')
$$,
'The new row should have been added'
);
select lives_ok(
$$ update surroundings_highlight set name = 'Another' where company_id = 2 and name = 'Another highlight' $$,
'Admin from company 2 should be able to update surroundings highlights of that company.'
);
select bag_eq(
'surroundings_highlight_data',
$$ values (2, 'Girona')
, (2, 'Another')
, (4, 'Barcelona')
$$,
'The row should have been updated.'
);
select lives_ok(
$$ delete from surroundings_highlight where company_id = 2 and name = 'Another' $$,
'Admin from company 2 should be able to delete surroundings highlights from that company.'
);
select bag_eq(
'surroundings_highlight_data',
$$ values (2, 'Girona')
, (4, 'Barcelona')
$$,
'The row should have been deleted.'
);
select throws_ok(
$$ insert into surroundings_highlight (company_id, media_id, name, description) values (4, 8, 'Another highlight', '<div/>') $$,
'42501', 'new row violates row-level security policy for table "surroundings_highlight"',
'Admin from company 2 should NOT be able to insert new surroundings highlights to company 4.'
);
select lives_ok(
$$ update surroundings_highlight set name = 'Nope' where company_id = 4 $$,
'Admin from company 2 should not be able to update new surroundings highlights of company 4, but no error if company_id is not changed.'
);
select bag_eq(
'surroundings_highlight_data',
$$ values (2, 'Girona')
, (4, 'Barcelona')
$$,
'No row should have been changed.'
);
select throws_ok(
$$ update surroundings_highlight set company_id = 4 where company_id = 2 $$,
'42501', 'new row violates row-level security policy for table "surroundings_highlight"',
'Admin from company 2 should NOT be able to move surroundings highlights to company 4'
);
select lives_ok(
$$ delete from surroundings_highlight where company_id = 4 $$,
'Admin from company 2 should NOT be able to delete surroundings highlights from company 4, but not error is thrown'
);
select bag_eq(
'surroundings_highlight_data',
$$ values (2, 'Girona')
, (4, 'Barcelona')
$$,
'No row should have been changed'
);
select throws_ok(
$$ insert into surroundings_highlight (company_id, media_id, name, description) values (2, 6, ' ', '') $$,
'23514', 'new row for relation "surroundings_highlight" violates check constraint "name_not_empty"',
'Should not be able to insert surroundings highlights with a blank name.'
);
reset role;
select *
from finish();
rollback;

View File

@ -0,0 +1,49 @@
-- Test surroundings_highlight_i18n
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(27);
set search_path to camper, public;
select has_table('surroundings_highlight_i18n');
select has_pk('surroundings_highlight_i18n');
select col_is_pk('surroundings_highlight_i18n', array['surroundings_highlight_id', 'lang_tag']);
select table_privs_are('surroundings_highlight_i18n', 'guest', array['SELECT']);
select table_privs_are('surroundings_highlight_i18n', 'employee', array['SELECT']);
select table_privs_are('surroundings_highlight_i18n', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
select table_privs_are('surroundings_highlight_i18n', 'authenticator', array[]::text[]);
select has_column('surroundings_highlight_i18n', 'surroundings_highlight_id');
select col_is_fk('surroundings_highlight_i18n', 'surroundings_highlight_id');
select fk_ok('surroundings_highlight_i18n', 'surroundings_highlight_id', 'surroundings_highlight', 'surroundings_highlight_id');
select col_type_is('surroundings_highlight_i18n', 'surroundings_highlight_id', 'integer');
select col_not_null('surroundings_highlight_i18n', 'surroundings_highlight_id');
select col_hasnt_default('surroundings_highlight_i18n', 'surroundings_highlight_id');
select has_column('surroundings_highlight_i18n', 'lang_tag');
select col_is_fk('surroundings_highlight_i18n', 'lang_tag');
select fk_ok('surroundings_highlight_i18n', 'lang_tag', 'language', 'lang_tag');
select col_type_is('surroundings_highlight_i18n', 'lang_tag', 'text');
select col_not_null('surroundings_highlight_i18n', 'lang_tag');
select col_hasnt_default('surroundings_highlight_i18n', 'lang_tag');
select has_column('surroundings_highlight_i18n', 'name');
select col_type_is('surroundings_highlight_i18n', 'name', 'text');
select col_not_null('surroundings_highlight_i18n', 'name');
select col_hasnt_default('surroundings_highlight_i18n', 'name');
select has_column('surroundings_highlight_i18n', 'description');
select col_type_is('surroundings_highlight_i18n', 'description', 'xml');
select col_not_null('surroundings_highlight_i18n', 'description');
select col_hasnt_default('surroundings_highlight_i18n', 'description');
select *
from finish();
rollback;

View File

@ -0,0 +1,83 @@
-- Test translate_surroundings_highlight
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_surroundings_highlight', array['integer', 'text', 'text', 'text']);
select function_lang_is('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'sql');
select function_returns('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'void');
select isnt_definer('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text']);
select volatility_is('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'volatile');
select function_privs_are('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'guest', array[]::text[]);
select function_privs_are('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'employee', array[]::text[]);
select function_privs_are('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'translate_surroundings_highlight', array['integer', 'text', 'text', 'text'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_highlight 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, rtc_number, tourist_tax, country_code, currency_code, default_lang_tag)
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, '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"};')
, ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ff00ff","a"};')
, ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffff00","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"};'))
, (3, 1, 'cover3.xpm', sha256('static char *s[]={"1 1 1 1","a c #ff00ff","a"};'))
, (4, 1, 'cover4.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffff00","a"};'))
;
insert into surroundings_highlight (surroundings_highlight_id, company_id, media_id, name, description)
values (8, 1, 2, 'Highlight A', '<h2>One</h2>')
, (9, 1, 3, 'Highlight B', '<h2>Two</h2>')
;
insert into surroundings_highlight_i18n (surroundings_highlight_id, lang_tag, name, description)
values (9, 'ca', 'destacatb', '<h2>dos</h2>')
;
select lives_ok(
$$ select translate_surroundings_highlight(8, 'ca', 'Destacat A', null) $$,
'Should be able to translate the first highlight'
);
select lives_ok(
$$ select translate_surroundings_highlight(9, 'es', 'Destacado B', '<h2>Dos</h2>') $$,
'Should be able to translate the second highlight'
);
select lives_ok(
$$ select translate_surroundings_highlight(9, 'ca', 'Destacat B', '<h2>I dos</h2>') $$,
'Should be able to overwrite the catalan translation of the second highlight'
);
select bag_eq(
$$ select surroundings_highlight_id, lang_tag, i18n.name, i18n.description::text from surroundings_highlight_i18n as i18n join surroundings_highlight using (surroundings_highlight_id) $$,
$$ values (8, 'ca', 'Destacat A', '')
, (9, 'ca', 'Destacat B', '<h2>I dos</h2>')
, (9, 'es', 'Destacado B', '<h2>Dos</h2>')
$$,
'Should have added and updated all translations.'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:add_surroundings_highlight on pg
begin;
select has_function_privilege('camper.add_surroundings_highlight(integer, integer, text, text)', 'execute');
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:edit_surroundings_highlight on pg
begin;
select has_function_privilege('camper.edit_surroundings_highlight(integer, integer, text, text)', 'execute');
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:order_surroundings_highlights on pg
begin;
select has_function_privilege('camper.order_surroundings_highlights(integer[])', 'execute');
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:remove_surroundings_highlight on pg
begin;
select has_function_privilege('camper.remove_surroundings_highlight(integer)', 'execute');
rollback;

View File

@ -0,0 +1,21 @@
-- Verify camper:surroundings_highlight on pg
begin;
select surroundings_highlight_id
, company_id
, media_id
, name
, description
, position
from camper.surroundings_highlight
where false;
select 1 / count(*) from pg_class where oid = 'camper.surroundings_highlight'::regclass and relrowsecurity;
select 1 / count(*) from pg_policy where polname = 'guest_ok' and polrelid = 'camper.surroundings_highlight'::regclass;
select 1 / count(*) from pg_policy where polname = 'insert_to_company' and polrelid = 'camper.surroundings_highlight'::regclass;
select 1 / count(*) from pg_policy where polname = 'update_company' and polrelid = 'camper.surroundings_highlight'::regclass;
select 1 / count(*) from pg_policy where polname = 'delete_from_company' and polrelid = 'camper.surroundings_highlight'::regclass;
rollback;

View File

@ -0,0 +1,12 @@
-- Verify camper:surroundings_highlight_i18n on pg
begin;
select surroundings_highlight_id
, lang_tag
, name
, description
from camper.surroundings_highlight_i18n
where false;
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:translate_surroundings_highlight on pg
begin;
select has_function_privilege('camper.translate_surroundings_highlight(integer, text, text, text)', 'execute');
rollback;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

View File

@ -282,7 +282,7 @@ h1 a .name {
left: -9999em;
}
nav ul, .campsite_type_features ul {
nav ul, .campsite_type_features ul, .outside_activities > ul {
list-style: none;
padding-left: 0;
display: flex;
@ -666,27 +666,6 @@ dt {
}
}
/* autside-activities tablet & mobile */
@media (max-width: 64rem) {
dl, .nature div + div, .outside_activities > div {
flex-direction: column;
}
.outside_activities > div:first-of-type p {
width: 100% !important;
margin-top: 0 !important;
}
.outside_activities > div:first-of-type img:last-child {
width: 100% !important;
margin-top: 0 !important;
}
}
/* end autside-activities tablet & mobile */
.outside_activities {
margin-top: 2rem;
}
@ -701,64 +680,52 @@ dt {
margin-bottom: 10rem;
}
.outside_activities img {
border-radius: 5px;
.outside_activities > ul {
max-width: 108rem;
margin: 0 auto;
flex-direction: column;
gap: 2.7rem;
}
.outside_activities > div {
align-items: start;
.outside_activities article {
display: flex;
gap: 5.5%;
justify-content: space-between;
}
.outside_activities > div:first-of-type {
margin-bottom: 5rem;
.outside_activities > ul > li:nth-child(2n) article {
flex-direction: row-reverse;
}
.outside_activities > div:first-of-type p {
width: 25%;
margin-top: 12rem;
.outside_activities article h4 {
font-size: 2.3rem;
}
.outside_activities > div:first-of-type img {
width: 40%;
.outside_activities article > div {
width: 29.5%;
}
.outside_activities > div:first-of-type img:last-child {
width: 35%;
margin-top: 22rem;
.outside_activities article > img {
width: 64%;
aspect-ratio: 16/9;
object-fit: cover;
}
.outside_activities > div:nth-of-type(2) > img {
width: 35%;
@media (max-width: 64rem) {
.outside_activities > ul {
gap: 5rem;
}
.outside_activities article, .outside_activities > ul > li:nth-child(2n) article {
flex-direction: column;
gap: 1rem;
}
.outside_activities article > div, .outside_activities article > img {
width: 100%;
}
}
.outside_activities > div:nth-of-type(2) > div {
width: 30%;
margin-top: 10rem;
}
.outside_activities > div:nth-of-type(2) > div img {
margin-top: 20rem;
}
.outside_activities > div:nth-of-type(2) > img:last-child {
margin-top: 22rem;
}
.outside_activities > div:last-child img {
width: 40%;
}
.outside_activities > div:last-child img:first-child {
margin-top: 10rem;
}
.outside_activities > div:last-child img:nth-child(2) {
margin-top: 22rem;
}
.outside_activities > div:last-child div {
width: 20%;
}
.campsite_activities {
margin-top: 10rem;
@ -1283,7 +1250,7 @@ input[type="checkbox"]:focus {
grid-template-columns: repeat(2, 1fr);
}
#booking a {
#booking a, .outside_activities a {
color: var(--accent);
text-decoration: var(--accent) wavy underline;
}

View File

@ -60,6 +60,9 @@
<li>
<a href="/admin/location">{{( pgettext "Location" "title" )}}</a>
</li>
<li>
<a href="/admin/surroundings">{{( pgettext "Surroundings" "title" )}}</a>
</li>
<li>
<a href="/admin/legal">{{( pgettext "Legal Texts" "title" )}}</a>
</li>

View File

@ -0,0 +1,72 @@
<!--
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/carousel.slideForm*/ -}}
{{ if .ID}}
{{( pgettext "Edit Highlight" "title" )}}
{{ else }}
{{( pgettext "New Highlight" "title" )}}
{{ end }}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.highlightForm*/ -}}
<form
{{ if .ID }}
data-hx-put="/admin/surroundings/{{ .ID }}"
{{ else }}
action="/admin/surroundings" method="post"
{{ end }}
>
<h2>
{{ if .ID }}
{{( pgettext "Edit Highlight" "title" )}}
{{ else }}
{{( pgettext "New Highlight" "title" )}}
{{ end }}
</h2>
{{ CSRFInput }}
<fieldset {{ template "init-lang" . }}>
{{ with .Media -}}
{{ template "media-picker" . }}
{{- end }}
{{ with .Name -}}
<fieldset>
<legend>{{( pgettext "Name" "input")}}</legend>
{{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br>
</label>
{{- end }}
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .Description -}}
<fieldset>
<legend>{{( pgettext "Description" "input")}}</legend>
{{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<textarea class="html"
name="{{ $input.Name }}" {{ template "error-attrs" $input }}>{{ $input.Val }}</textarea><br>
</label>
{{- end }}
{{ template "error-message" . }}
</fieldset>
{{- end }}
</fieldset>
<footer>
<button type="submit">
{{ if .ID }}
{{( pgettext "Update" "action" )}}
{{ else }}
{{( pgettext "Add" "action" )}}
{{ end }}
</button>
</footer>
</form>
{{- end }}

View File

@ -0,0 +1,55 @@
<!--
SPDX-FileCopyrightText: 2023 jordi fita mas <jordi@tandem.blog>
SPDX-License-Identifier: AGPL-3.0-only
-->
{{ define "title" -}}
{{( pgettext "Surroundings Page" "title" )}}
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.highlightIndex*/ -}}
<h2>{{( pgettext "Highlights" "title" )}}</h2>
<a href="/admin/surroundings/new">{{( pgettext "Add highlight" "action" )}}</a>
{{ if .Highlights -}}
<form id="highlight-index"
class="sortable"
data-hx-post="/admin/surroundings/order"
data-hx-trigger="end"
data-hx-select="#highlight-index"
data-hx-swap="outerHTML"
>
{{ CSRFInput }}
<table>
<thead>
<tr>
<th scope="col">{{( pgettext "Image" "header" )}}</th>
<th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Actions" "header" )}}</th>
</tr>
</thead>
<tbody>
{{ $confirm := ( gettext "Are you sure you wish to delete this highlight?" )}}
{{ range $highlight := .Highlights -}}
<tr>
<td>
<span class="handle"></span>
<input type="hidden" name="highlight_id" value="{{ .ID }}">
<a href="{{ .URL }}"><img src="{{ .Media }}" alt=""></a>
</td>
<td><a href="{{ .URL }}">{{ .Name }}</a></td>
<td>
<form data-hx-delete="/admin/surroundings//{{ .ID }}"
data-hx-confirm="{{ $confirm }}"
data-hx-headers='{ {{ CSRFHeader }} }'>
<button type="submit">{{( pgettext "Delete" "action" )}}</button>
</form>
</td>
</tr>
{{- end }}
</tbody>
</table>
</form>
{{ else -}}
<p>{{( gettext "No highlights added yet." )}}</p>
{{- end }}
{{- end }}

View File

@ -7,47 +7,44 @@
{{- end }}
{{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.surroundingsPage*/ -}}
<h2>{{( pgettext "Surroundings" "title" )}}</h2>
<section>
<div class="ad-container">
<div class="ad-image-container"></div>
<div class="ad-description-container">
<h3 class="ad-title">Vine a fer barranquisme per Sadernes!</h3>
<a class="ad-button" href="#">Reserva el teu dia<span class="ad-icon"><svg viewBox="0 0 93.69895 67.38545" xmlns="http://www.w3.org/2000/svg" class="arrow_link"><path d="m67.38545,67.38545l-13.49997-2.97457c.57203-5.72033,2.74576-10.99256,6.52117-15.8167,3.77542-4.82414,8.04659-7.94172,12.81353-9.35273H0v-11.09743h73.22018c-4.76694-1.41101-9.03812-4.53813-12.81353-9.38134-3.77542-4.84321-5.94914-10.12498-6.52117-15.8453l13.49997-2.91737c.26695,8.38981,2.70762,15.01586,7.32202,19.87813s10.94489,7.61757,18.99148,8.26587v11.09743c-8.04659.6483-14.37709,3.40359-18.99148,8.26587-4.6144,4.86228-7.05507,11.48832-7.32202,19.87813Z"></path></svg></span></a>
</div>
</div>
</section>
<section>
<div class="ad-container">
<div class="ad-image-container"></div>
<div class="ad-description-container">
<h3 class="ad-title">Vine a fer barranquisme per Sadernes!</h3>
<a class="ad-button" href="#">Reserva el teu dia<span class="ad-icon">
<svg viewBox="0 0 93.69895 67.38545"
xmlns="http://www.w3.org/2000/svg"
class="arrow_link">
<path d="m67.38545,67.38545l-13.49997-2.97457c.57203-5.72033,2.74576-10.99256,6.52117-15.8167,3.77542-4.82414,8.04659-7.94172,12.81353-9.35273H0v-11.09743h73.22018c-4.76694-1.41101-9.03812-4.53813-12.81353-9.38134-3.77542-4.84321-5.94914-10.12498-6.52117-15.8453l13.49997-2.91737c.26695,8.38981,2.70762,15.01586,7.32202,19.87813s10.94489,7.61757,18.99148,8.26587v11.09743c-8.04659.6483-14.37709,3.40359-18.99148,8.26587-4.6144,4.86228-7.05507,11.48832-7.32202,19.87813Z"/>
</svg>
</span>
</a>
</div>
</div>
</section>
<section class="outside_activities">
<h3>{{( pgettext "What to Do Outside the Campsite?" "title" )}}</h3>
<div>
<p>{{( gettext "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda den Jordà, cycle tours for all ages…." )}}</p>
<img src="/static/images/excusions.webp" alt="" width="640" height="960">
<img src="/static/images/escalada_sadernes.webp" alt="" width="640" height="960">
</div>
<div>
<img src="/static/images/rutes_amb_bicicleta.webp" alt="" width="1000" height="1500">
<div>
<p>{{( gettext "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking….")}}</p>
<img src="/static/images/calella_de_palafrugell.webp" alt="" width="640" height="427">
</div>
<img src="/static/images/caiac_mar.webp" alt="" width="1200" height="800">
</div>
<div>
<img src="/static/images/gastronomia.webp" alt="" width="640" height="426">
<img src="/static/images/museu_dali_figueres.webp" alt="" width="640" height="427">
<div>
<p>{{( gettext "You will also find museums in Olot, Figures, Girona.")}}</p>
<p>{{( gettext "As well as music festivals, dance, theater…." )}}</p>
</div>
</div>
{{ with .Highlights -}}
<ul>
{{ range . -}}
<li>
<article>
<div>
<h4>{{ .Name }}</h4>
{{ .Description }}
</div>
<img src="{{ .Media }}" alt="">
</article>
</li>
{{- end }}
</ul>
{{- end }}
</section>
<section class="campsite_activities">