From 67dc55481047d29bb375399b50ed59c21313d0d6 Mon Sep 17 00:00:00 2001 From: "Adriano (goldrake)" Date: Tue, 29 Sep 2026 20:30:09 +0000 Subject: [PATCH] Reformer Class: bottone consulenza conoscitiva gratuita (#22) Co-Authored-By: Claude Sonnet 5.5 --- src/data/consulenza.ts | 15 +++++++++++++++ src/data/content-seed.ts | 4 ++++ src/pages/services/[slug].astro | 18 ++++++++++++++++-- tests/consulenza.test.ts | 28 ++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/data/consulenza.ts create mode 100644 tests/consulenza.test.ts diff --git a/src/data/consulenza.ts b/src/data/consulenza.ts new file mode 100644 index 0000000..4906fe4 --- /dev/null +++ b/src/data/consulenza.ts @@ -0,0 +1,15 @@ +// Consulenza conoscitiva gratuita con Nicola (prenotazione su Google Calendar). +// +// Il link vive nel pannello contenuti (tag `global.consulenza.url`): qui c'è il valore di +// partenza e la guardia. Il tag è modificabile da admin, quindi si accetta solo https. +export const CONSULENZA_URL_DEFAULT = 'https://calendar.app.google/nWXMGD2S5g2pVeeD7'; + +/** Slug delle pagine servizio che mostrano il bottone di prenotazione. */ +export const PAGINE_CON_CONSULENZA = ['reformer-class']; + +/** Link da usare: il valore del pannello se è https, altrimenti quello di default + * (niente javascript:, http:, vuoto). */ +export function linkConsulenza(valore: string): string { + const v = (valore ?? '').trim(); + return v.startsWith('https://') ? v : CONSULENZA_URL_DEFAULT; +} diff --git a/src/data/content-seed.ts b/src/data/content-seed.ts index 32a6bfc..4e2d591 100644 --- a/src/data/content-seed.ts +++ b/src/data/content-seed.ts @@ -7,6 +7,7 @@ import { partners } from './partners'; import { disciplines, days, slots } from './agenda'; import { services } from './services'; import { performanceClassPricing } from './pricing'; +import { CONSULENZA_URL_DEFAULT } from './consulenza'; export type ContentType = 'text' | 'html' | 'image'; export interface SeedEntry { tag: string; type: ContentType; value: string; styleOptions?: StyleGroup[] } @@ -270,6 +271,9 @@ export const contentSeed: SeedEntry[] = [ T('service.pricing.entries-plural', 'ingressi settimanali', []), T('service.pricing.buy-cta', 'Acquista', []), T('service.contact-cta', 'Contattaci', []), + T('service.consulenza-cta', 'Prenota una consulenza conoscitiva gratuita', []), + T('service.consulenza-note', '30-45 minuti con Nicola', []), + T('global.consulenza.url', CONSULENZA_URL_DEFAULT, []), // --- Pricing performance class (data-driven da pricing.ts; monthly/entries restano nel data file) --- T('pricing.heading', performanceClassPricing.heading), diff --git a/src/pages/services/[slug].astro b/src/pages/services/[slug].astro index e28268c..dad1042 100644 --- a/src/pages/services/[slug].astro +++ b/src/pages/services/[slug].astro @@ -10,6 +10,7 @@ import TImg from '../../components/content/TImg.astro'; import CalendarioModal from '../../components/CalendarioModal.astro'; import { calendariDaMostrare, PAGINE_CON_CALENDARIO } from '../../data/calendari'; import { t } from '../../lib/content'; +import { PAGINE_CON_CONSULENZA, linkConsulenza } from '../../data/consulenza'; export const prerender = false; const service = getService(Astro.params.slug!); @@ -38,8 +39,16 @@ const tones = ['tan', 'taupe', 'dark'];

{t(`service.${slug}.title`).toUpperCase()}

- {slug === 'reformer-class' && ( -

{t('service.contact-cta')}

+ {(slug === 'reformer-class' || PAGINE_CON_CONSULENZA.includes(slug)) && ( +
+
+ {slug === 'reformer-class' && {t('service.contact-cta')}} + {PAGINE_CON_CONSULENZA.includes(slug) && ( + {t('service.consulenza-cta')} + )} +
+ {PAGINE_CON_CONSULENZA.includes(slug) && } +
)} {service.features.length > 0 && (
    @@ -149,6 +158,11 @@ const tones = ['tan', 'taupe', 'dark']; .prog__calendario { display: flex; align-items: center; gap: 14px; width: 100%; margin-top: 36px; padding: 10px 16px 10px 10px; border: 0; cursor: pointer; text-align: left; background: #6b5d5b; color: #fff; font-family: var(--font-heading); font-size: .82rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; transition: background .2s; } .prog__calendario:hover { background: var(--c-accent-dark); } .prog__cta { margin: 10px 0 30px; } + .prog__cta-row { display: flex; flex-wrap: wrap; gap: 12px; } + .btn--consulenza { background: #6b5d5b; } + .btn--consulenza:hover { background: var(--c-accent-dark); } + .prog__cta-note { font-size: .8rem; color: var(--c-text-light); margin: 8px 0 0; } + @media (max-width: 600px) { .prog__cta-row .btn { flex: 1 1 100%; justify-content: center; text-align: center; } } .prog__icon { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; background: var(--c-accent); color: #fff; flex-shrink: 0; } .price__group { border-top: 1px solid #ddd5ca; padding-block: 18px; } .price__group summary { cursor: pointer; font-family: var(--font-heading); letter-spacing: .12em; text-transform: uppercase; font-size: .85rem; color: var(--c-heading); } diff --git a/tests/consulenza.test.ts b/tests/consulenza.test.ts new file mode 100644 index 0000000..914486d --- /dev/null +++ b/tests/consulenza.test.ts @@ -0,0 +1,28 @@ +import { describe, it, expect } from 'vitest'; +import { linkConsulenza, CONSULENZA_URL_DEFAULT, PAGINE_CON_CONSULENZA } from '../src/data/consulenza'; +import { contentSeed } from '../src/data/content-seed'; +import { services } from '../src/data/services'; + +describe('consulenza conoscitiva', () => { + it('accetta un link https, anche con spazi attorno', () => { + expect(linkConsulenza('https://example.com/x')).toBe('https://example.com/x'); + expect(linkConsulenza(' https://example.com/x ')).toBe('https://example.com/x'); + }); + it.each(['javascript:alert(1)', 'http://x.it', '', ' '])('scarta %j e usa il default', (v) => { + expect(linkConsulenza(v)).toBe(CONSULENZA_URL_DEFAULT); + }); + it('il seed ha i tre tag', () => { + const v = (tag: string) => contentSeed.find((e) => e.tag === tag)?.value; + expect(v('service.consulenza-cta')).toBe('Prenota una consulenza conoscitiva gratuita'); + expect(v('service.consulenza-note')).toBe('30-45 minuti con Nicola'); + expect(v('global.consulenza.url')).toBe(CONSULENZA_URL_DEFAULT); + }); + it('le pagine con consulenza esistono', () => { + expect(PAGINE_CON_CONSULENZA).toContain('reformer-class'); + for (const slug of PAGINE_CON_CONSULENZA) { + const s = services.find((x) => x.slug === slug); + expect(s, slug).toBeDefined(); + expect(s!.page).not.toBe(false); + } + }); +});