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)) && (
+
+
+ {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);
+ }
+ });
+});