Aggiunge cookie policy, banner consenso e Google Analytics opzionale.
Il banner consente solo necessari o tutti i cookie; GA4 si carica solo dopo consenso. Aggiornati privacy, footer, sitemap e variabile GOOGLE_ANALYTICS_MEASUREMENT_ID. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -30,6 +30,9 @@ module Public
|
|||||||
def terms
|
def terms
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cookies
|
||||||
|
end
|
||||||
|
|
||||||
def faq
|
def faq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ module Public
|
|||||||
{ loc: "#{base}/faq", changefreq: "monthly", priority: "0.8" },
|
{ loc: "#{base}/faq", changefreq: "monthly", priority: "0.8" },
|
||||||
{ loc: "#{base}/live", changefreq: "hourly", priority: "0.85" },
|
{ loc: "#{base}/live", changefreq: "hourly", priority: "0.85" },
|
||||||
{ loc: "#{base}/privacy", changefreq: "yearly", priority: "0.3" },
|
{ loc: "#{base}/privacy", changefreq: "yearly", priority: "0.3" },
|
||||||
|
{ loc: "#{base}/cookie", changefreq: "yearly", priority: "0.3" },
|
||||||
{ loc: "#{base}/termini", changefreq: "yearly", priority: "0.3" }
|
{ loc: "#{base}/termini", changefreq: "yearly", priority: "0.3" }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
module LegalHelper
|
module LegalHelper
|
||||||
def legal_last_updated
|
def legal_last_updated
|
||||||
"26 maggio 2026"
|
"3 giugno 2026"
|
||||||
|
end
|
||||||
|
|
||||||
|
def cookie_policy_last_updated
|
||||||
|
"3 giugno 2026"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
<%= render "shared/meta_tags" %>
|
<%= render "shared/meta_tags" %>
|
||||||
<%= yield :head %>
|
<%= yield :head %>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||||
<link rel="stylesheet" href="/marketing.css?v=35">
|
<link rel="stylesheet" href="/marketing.css?v=36">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body<% if MatchLiveTv.google_analytics_configured? %> data-ga-id="<%= MatchLiveTv.google_analytics_measurement_id %>"<% end %>>
|
||||||
|
<%= render "shared/cookie_banner" %>
|
||||||
<%= render "shared/marketing_nav" %>
|
<%= render "shared/marketing_nav" %>
|
||||||
<main>
|
<main>
|
||||||
<% if flash[:notice] %><div class="wrap"><div class="flash notice"><%= flash[:notice] %></div></div><% end %>
|
<% if flash[:notice] %><div class="wrap"><div class="flash notice"><%= flash[:notice] %></div></div><% end %>
|
||||||
@@ -21,5 +22,6 @@
|
|||||||
<script src="/branding-form.js?v=1" defer></script>
|
<script src="/branding-form.js?v=1" defer></script>
|
||||||
<script src="/roster-form.js?v=1" defer></script>
|
<script src="/roster-form.js?v=1" defer></script>
|
||||||
<script src="/password-toggle.js?v=2" defer></script>
|
<script src="/password-toggle.js?v=2" defer></script>
|
||||||
|
<script src="/cookie-consent.js?v=1" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -6,15 +6,17 @@
|
|||||||
<title><%= content_for?(:title) ? yield(:title) : "Match Live TV" %></title>
|
<title><%= content_for?(:title) ? yield(:title) : "Match Live TV" %></title>
|
||||||
<%= render "shared/meta_tags" %>
|
<%= render "shared/meta_tags" %>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||||
<link rel="stylesheet" href="/marketing.css?v=34">
|
<link rel="stylesheet" href="/marketing.css?v=36">
|
||||||
<link rel="stylesheet" href="/live.css?v=4">
|
<link rel="stylesheet" href="/live.css?v=4">
|
||||||
<%= yield :head %>
|
<%= yield :head %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body<% if MatchLiveTv.google_analytics_configured? %> data-ga-id="<%= MatchLiveTv.google_analytics_measurement_id %>"<% end %>>
|
||||||
|
<%= render "shared/cookie_banner" %>
|
||||||
<%= render "shared/marketing_nav" %>
|
<%= render "shared/marketing_nav" %>
|
||||||
<main class="live-main">
|
<main class="live-main">
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</main>
|
</main>
|
||||||
<%= render "shared/marketing_footer" %>
|
<%= render "shared/marketing_footer" %>
|
||||||
|
<script src="/cookie-consent.js?v=1" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
150
backend/app/views/public/pages/cookies.html.erb
Normal file
150
backend/app/views/public/pages/cookies.html.erb
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<% content_for :title, "Cookie policy — Match Live TV" %>
|
||||||
|
<% content_for :meta_description, "Cookie policy di Match Live TV: cookie tecnici, sessione, Google Analytics e gestione del consenso." %>
|
||||||
|
<% content_for :canonical_url, seo_absolute_url(public_cookies_path) %>
|
||||||
|
|
||||||
|
<div class="wrap legal-doc">
|
||||||
|
<h1>Cookie policy</h1>
|
||||||
|
<p class="legal-meta">
|
||||||
|
Ultimo aggiornamento: <%= cookie_policy_last_updated %>
|
||||||
|
· Vedi anche <%= link_to "informativa privacy", public_privacy_path %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>1. Cosa sono i cookie</h2>
|
||||||
|
<p>
|
||||||
|
I cookie sono piccoli file di testo che i siti salvano sul dispositivo del visitatore.
|
||||||
|
Servono a far funzionare il sito, ricordare preferenze o, previo consenso, analizzare l’uso del servizio.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>2. Titolare</h2>
|
||||||
|
<p>
|
||||||
|
<strong><%= MatchLiveTv.privacy_controller_name %></strong> —
|
||||||
|
<%= MatchLiveTv.privacy_controller_address %> —
|
||||||
|
<a href="mailto:<%= MatchLiveTv.privacy_controller_email %>"><%= MatchLiveTv.privacy_controller_email %></a>
|
||||||
|
<% if MatchLiveTv.privacy_controller_vat.present? %>
|
||||||
|
· P. IVA <%= MatchLiveTv.privacy_controller_vat %>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>3. Come gestiamo il consenso</h2>
|
||||||
|
<p>
|
||||||
|
Al primo accesso mostriamo un banner che ti permette di accettare tutti i cookie,
|
||||||
|
usare <strong>solo quelli necessari</strong> o aprire questa pagina per maggiori dettagli.
|
||||||
|
Puoi modificare la scelta in qualsiasi momento con il link
|
||||||
|
<strong>«Gestisci cookie»</strong> nel footer.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
La preferenza viene memorizzata in un cookie tecnico di prima parte
|
||||||
|
(<code>mltv_cookie_consent</code>) e in <code>localStorage</code> del browser.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>4. Cookie e tecnologie che utilizziamo</h2>
|
||||||
|
|
||||||
|
<h3>4.1 Strettamente necessari (sempre attivi)</h3>
|
||||||
|
<p>Non richiedono consenso perché indispensabili al funzionamento del sito e dell’area riservata.</p>
|
||||||
|
<table class="legal-table">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Nome / tipo</th><th>Finalità</th><th>Durata</th><th>Fornitore</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>_app_session</code> (cookie di sessione)</td>
|
||||||
|
<td>Mantiene l’accesso dell’utente registrato, protezione CSRF, preferenze di navigazione sicura</td>
|
||||||
|
<td>Sessione / fino a chiusura browser</td>
|
||||||
|
<td>Match Live TV (prima parte)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>mltv_cookie_consent</code></td>
|
||||||
|
<td>Memorizza le scelte sul banner cookie (necessari / analytics)</td>
|
||||||
|
<td>12 mesi</td>
|
||||||
|
<td>Match Live TV (prima parte)</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.2 Analytics (solo con il tuo consenso)</h3>
|
||||||
|
<p>
|
||||||
|
Se accetti «Tutti i cookie» o abiliti le statistiche nel banner, carichiamo
|
||||||
|
<strong>Google Analytics 4</strong> per capire come viene usato il sito (pagine visitate, provenienza aggregata, dispositivo).
|
||||||
|
I dati sono trattati da Google Ireland Limited / Google LLC secondo le loro policy.
|
||||||
|
</p>
|
||||||
|
<% if MatchLiveTv.google_analytics_configured? %>
|
||||||
|
<p class="muted">ID misurazione attivo sul sito: <code><%= MatchLiveTv.google_analytics_measurement_id %></code></p>
|
||||||
|
<% else %>
|
||||||
|
<p class="muted">Google Analytics è configurato solo quando il titolare imposta l’ID misurazione sul server.</p>
|
||||||
|
<% end %>
|
||||||
|
<table class="legal-table">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Nome</th><th>Finalità</th><th>Durata</th><th>Fornitore</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>_ga</code></td>
|
||||||
|
<td>Distingue gli utenti (statistiche)</td>
|
||||||
|
<td>2 anni</td>
|
||||||
|
<td>Google</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>_ga_*</code></td>
|
||||||
|
<td>Mantiene lo stato della sessione Analytics</td>
|
||||||
|
<td>2 anni</td>
|
||||||
|
<td>Google</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>_gid</code></td>
|
||||||
|
<td>Distingue gli utenti (statistiche)</td>
|
||||||
|
<td>24 ore</td>
|
||||||
|
<td>Google</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
Puoi revocare il consenso dal banner o dalle impostazioni del browser.
|
||||||
|
Informazioni Google:
|
||||||
|
<a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Privacy Policy Google</a>,
|
||||||
|
<a href="https://tools.google.com/dlpage/gaoptout" target="_blank" rel="noopener noreferrer">componente opt-out Analytics</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>4.3 Cookie di terze parti durante il pagamento</h3>
|
||||||
|
<p>
|
||||||
|
Se acquisti un piano Premium, vieni reindirizzato a <strong>Stripe</strong> (checkout sicuro).
|
||||||
|
Stripe può impostare cookie propri sul dominio <code>stripe.com</code> per prevenire frodi e completare il pagamento.
|
||||||
|
Non controlliamo direttamente tali cookie: consulta la
|
||||||
|
<a href="https://stripe.com/privacy" target="_blank" rel="noopener noreferrer">privacy policy di Stripe</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>4.4 YouTube e servizi collegati</h3>
|
||||||
|
<p>
|
||||||
|
L’integrazione YouTube per le dirette avviene tramite API lato server; il sito pubblico non incorpora
|
||||||
|
player YouTube con cookie di profilazione. I visitatori che aprono un link YouTube esterno
|
||||||
|
sono soggetti alle policy di Google/YouTube su quel dominio.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>5. Come disabilitare i cookie dal browser</h2>
|
||||||
|
<p>
|
||||||
|
Puoi bloccare o cancellare i cookie dalle impostazioni del browser (Chrome, Firefox, Safari, Edge).
|
||||||
|
Disabilitando i cookie necessari alcune funzioni (es. login) potrebbero non funzionare.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>6. Diritti e contatti</h2>
|
||||||
|
<p>
|
||||||
|
Per esercitare i diritti previsti dal GDPR (accesso, cancellazione, opposizione, revoca consenso)
|
||||||
|
scrivi a <a href="mailto:<%= MatchLiveTv.privacy_controller_email %>"><%= MatchLiveTv.privacy_controller_email %></a>.
|
||||||
|
Dettagli nel <%= link_to "documento privacy", public_privacy_path %>.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<p style="margin-top:24px">
|
||||||
|
<button type="button" class="btn btn-secondary" data-cookie-manage>Gestisci preferenze cookie</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
@@ -171,8 +171,12 @@
|
|||||||
<section>
|
<section>
|
||||||
<h2>11. Cookie e tecnologie simili</h2>
|
<h2>11. Cookie e tecnologie simili</h2>
|
||||||
<p>
|
<p>
|
||||||
Il sito utilizza cookie tecnici necessari al funzionamento (es. sessione di login) e, in futuro,
|
Il sito utilizza cookie tecnici necessari (sessione di login, sicurezza, memorizzazione delle preferenze cookie)
|
||||||
eventuali strumenti di analisi solo previo consenso ove richiesto. Per dettagli aggiornati contatta il titolare.
|
e, previo consenso tramite il banner, <strong>Google Analytics</strong> per statistiche aggregate.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Puoi gestire le preferenze in qualsiasi momento dal link «Gestisci cookie» nel footer
|
||||||
|
o consultare la <%= link_to "Cookie policy", public_cookies_path %>.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
21
backend/app/views/shared/_cookie_banner.html.erb
Normal file
21
backend/app/views/shared/_cookie_banner.html.erb
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<div id="cookie-banner" class="cookie-banner" role="dialog" aria-labelledby="cookie-banner-title" aria-describedby="cookie-banner-desc" hidden>
|
||||||
|
<div class="cookie-banner__inner">
|
||||||
|
<div class="cookie-banner__text">
|
||||||
|
<p id="cookie-banner-title" class="cookie-banner__title">Cookie e privacy</p>
|
||||||
|
<p id="cookie-banner-desc" class="cookie-banner__desc">
|
||||||
|
Usiamo cookie necessari per login e sicurezza. Con il tuo consenso attiviamo anche
|
||||||
|
<strong>Google Analytics</strong> per statistiche aggregate sul sito.
|
||||||
|
<%= link_to "Cookie policy", public_cookies_path, class: "cookie-banner__link" %>
|
||||||
|
e <%= link_to "Privacy", public_privacy_path, class: "cookie-banner__link" %>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="cookie-banner__actions">
|
||||||
|
<button type="button" class="btn btn-secondary cookie-banner__btn" data-cookie-reject>
|
||||||
|
Solo necessari
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-primary cookie-banner__btn" data-cookie-accept-all>
|
||||||
|
Accetta tutti
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -8,7 +8,9 @@
|
|||||||
<%= link_to "Dirette", public_live_index_path %> ·
|
<%= link_to "Dirette", public_live_index_path %> ·
|
||||||
<%= link_to "FAQ", public_faq_path %> ·
|
<%= link_to "FAQ", public_faq_path %> ·
|
||||||
<%= link_to "Privacy", public_privacy_path %> ·
|
<%= link_to "Privacy", public_privacy_path %> ·
|
||||||
|
<%= link_to "Cookie", public_cookies_path %> ·
|
||||||
<%= link_to "Termini", public_termini_path %>
|
<%= link_to "Termini", public_termini_path %>
|
||||||
|
· <button type="button" class="footer-link-btn" data-cookie-manage>Gestisci cookie</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="site-footer__legal">
|
<div class="site-footer__legal">
|
||||||
<p>© 2026 Emiliano Frascaro – P. IVA 14230270960</p>
|
<p>© 2026 Emiliano Frascaro – P. IVA 14230270960</p>
|
||||||
|
|||||||
@@ -140,5 +140,13 @@ module MatchLiveTv
|
|||||||
def replay_download_url_ttl_seconds
|
def replay_download_url_ttl_seconds
|
||||||
ENV.fetch("REPLAY_DOWNLOAD_URL_TTL_SECONDS", "900").to_i
|
ENV.fetch("REPLAY_DOWNLOAD_URL_TTL_SECONDS", "900").to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def google_analytics_measurement_id
|
||||||
|
ENV["GOOGLE_ANALYTICS_MEASUREMENT_ID"].presence
|
||||||
|
end
|
||||||
|
|
||||||
|
def google_analytics_configured?
|
||||||
|
google_analytics_measurement_id.present?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ Rails.application.routes.draw do
|
|||||||
get "prezzi", to: "pages#pricing", as: :prezzi
|
get "prezzi", to: "pages#pricing", as: :prezzi
|
||||||
get "pricing", to: redirect("/prezzi")
|
get "pricing", to: redirect("/prezzi")
|
||||||
get "privacy", to: "pages#privacy", as: :privacy
|
get "privacy", to: "pages#privacy", as: :privacy
|
||||||
|
get "cookie", to: "pages#cookies", as: :cookies
|
||||||
|
get "cookies", to: redirect("/cookie")
|
||||||
get "termini", to: "pages#terms", as: :termini
|
get "termini", to: "pages#terms", as: :termini
|
||||||
get "signup", to: "registrations#new"
|
get "signup", to: "registrations#new"
|
||||||
post "signup", to: "registrations#create"
|
post "signup", to: "registrations#create"
|
||||||
|
|||||||
134
backend/public/cookie-consent.js
Normal file
134
backend/public/cookie-consent.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var STORAGE_KEY = "mltv_cookie_consent";
|
||||||
|
var COOKIE_NAME = "mltv_cookie_consent";
|
||||||
|
var COOKIE_MAX_AGE = 365 * 24 * 60 * 60;
|
||||||
|
|
||||||
|
function readConsent() {
|
||||||
|
try {
|
||||||
|
var raw = localStorage.getItem(STORAGE_KEY);
|
||||||
|
if (!raw) return null;
|
||||||
|
return JSON.parse(raw);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeConsent(consent) {
|
||||||
|
var payload = {
|
||||||
|
necessary: true,
|
||||||
|
analytics: !!consent.analytics,
|
||||||
|
ts: Date.now()
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(payload));
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
var value = payload.analytics ? "all" : "necessary";
|
||||||
|
document.cookie =
|
||||||
|
COOKIE_NAME + "=" + value +
|
||||||
|
"; path=/; max-age=" + COOKIE_MAX_AGE +
|
||||||
|
"; SameSite=Lax" +
|
||||||
|
(location.protocol === "https:" ? "; Secure" : "");
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function measurementId() {
|
||||||
|
return document.body && document.body.getAttribute("data-ga-id");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGoogleAnalytics() {
|
||||||
|
var id = measurementId();
|
||||||
|
if (!id || window.__mltvGaLoaded) return;
|
||||||
|
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag() { window.dataLayer.push(arguments); }
|
||||||
|
window.gtag = gtag;
|
||||||
|
|
||||||
|
gtag("consent", "default", {
|
||||||
|
analytics_storage: "denied",
|
||||||
|
ad_storage: "denied",
|
||||||
|
ad_user_data: "denied",
|
||||||
|
ad_personalization: "denied",
|
||||||
|
functionality_storage: "granted",
|
||||||
|
security_storage: "granted"
|
||||||
|
});
|
||||||
|
|
||||||
|
gtag("consent", "update", { analytics_storage: "granted" });
|
||||||
|
|
||||||
|
var script = document.createElement("script");
|
||||||
|
script.async = true;
|
||||||
|
script.src = "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(id);
|
||||||
|
script.onload = function () {
|
||||||
|
gtag("js", new Date());
|
||||||
|
gtag("config", id, { anonymize_ip: true, allow_google_signals: false });
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
window.__mltvGaLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyConsent(consent) {
|
||||||
|
if (consent && consent.analytics) {
|
||||||
|
loadGoogleAnalytics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideBanner(banner) {
|
||||||
|
if (!banner) return;
|
||||||
|
banner.hidden = true;
|
||||||
|
banner.setAttribute("aria-hidden", "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showBanner(banner) {
|
||||||
|
if (!banner) return;
|
||||||
|
banner.hidden = false;
|
||||||
|
banner.removeAttribute("aria-hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindBanner(banner) {
|
||||||
|
var acceptAll = banner.querySelector("[data-cookie-accept-all]");
|
||||||
|
var reject = banner.querySelector("[data-cookie-reject]");
|
||||||
|
|
||||||
|
if (acceptAll) {
|
||||||
|
acceptAll.addEventListener("click", function () {
|
||||||
|
var c = writeConsent({ analytics: true });
|
||||||
|
applyConsent(c);
|
||||||
|
hideBanner(banner);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reject) {
|
||||||
|
reject.addEventListener("click", function () {
|
||||||
|
writeConsent({ analytics: false });
|
||||||
|
hideBanner(banner);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
var banner = document.getElementById("cookie-banner");
|
||||||
|
var consent = readConsent();
|
||||||
|
|
||||||
|
if (consent) {
|
||||||
|
applyConsent(consent);
|
||||||
|
hideBanner(banner);
|
||||||
|
} else {
|
||||||
|
showBanner(banner);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindBanner(banner);
|
||||||
|
|
||||||
|
document.querySelectorAll("[data-cookie-manage]").forEach(function (el) {
|
||||||
|
el.addEventListener("click", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
showBanner(banner);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -1060,6 +1060,7 @@ body.nav-menu-open { overflow: hidden; }
|
|||||||
.legal-doc { max-width: 760px; padding-top: 24px; padding-bottom: 48px; color: #bbb; line-height: 1.65; font-size: 0.95rem; }
|
.legal-doc { max-width: 760px; padding-top: 24px; padding-bottom: 48px; color: #bbb; line-height: 1.65; font-size: 0.95rem; }
|
||||||
.legal-doc h1 { color: #fff; font-size: 1.6rem; margin-bottom: 8px; }
|
.legal-doc h1 { color: #fff; font-size: 1.6rem; margin-bottom: 8px; }
|
||||||
.legal-doc h2 { color: #fff; font-size: 1.1rem; margin: 28px 0 10px; }
|
.legal-doc h2 { color: #fff; font-size: 1.1rem; margin: 28px 0 10px; }
|
||||||
|
.legal-doc h3 { color: #ddd; font-size: 1rem; margin: 20px 0 8px; }
|
||||||
.legal-doc p { margin: 0 0 12px; }
|
.legal-doc p { margin: 0 0 12px; }
|
||||||
.legal-doc ul { margin: 0 0 14px; padding-left: 1.25rem; }
|
.legal-doc ul { margin: 0 0 14px; padding-left: 1.25rem; }
|
||||||
.legal-doc a { color: #e53935; }
|
.legal-doc a { color: #e53935; }
|
||||||
@@ -1272,3 +1273,84 @@ label { display: block; margin-bottom: 6px; font-size: 0.9rem; color: #c8c8d4; f
|
|||||||
.plan-change-info__box li + li {
|
.plan-change-info__box li + li {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cookie banner (GDPR / ePrivacy) */
|
||||||
|
.cookie-banner {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
padding: 16px;
|
||||||
|
background: rgba(10, 10, 14, 0.96);
|
||||||
|
border-top: 1px solid #2a2a36;
|
||||||
|
box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__inner {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px 24px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__text {
|
||||||
|
flex: 1 1 280px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__title {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__desc {
|
||||||
|
margin: 0;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__link {
|
||||||
|
color: #e53935;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cookie-banner__btn {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font: inherit;
|
||||||
|
color: #ff6b6b;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link-btn:hover {
|
||||||
|
color: #e53935;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.cookie-banner-visible {
|
||||||
|
padding-bottom: 120px;
|
||||||
|
}
|
||||||
|
|||||||
BIN
brand/CopertinaCanale.png
Normal file
BIN
brand/CopertinaCanale.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
brand/CopertinaCanale_2.png
Normal file
BIN
brand/CopertinaCanale_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
brand/CopertinaCanale_3.png
Normal file
BIN
brand/CopertinaCanale_3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
brand/CopertinaCanale_4.png
Normal file
BIN
brand/CopertinaCanale_4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
brand/CopertinaCanale_5.png
Normal file
BIN
brand/CopertinaCanale_5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
brand/CopertinaCanale_6.png
Normal file
BIN
brand/CopertinaCanale_6.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -15,6 +15,9 @@ PRIVACY_CONTACT_EMAIL=privacy@matchlive.it
|
|||||||
MAILER_FROM=Match Live TV <noreply@matchlive.it>
|
MAILER_FROM=Match Live TV <noreply@matchlive.it>
|
||||||
PASSWORD_RESET_EXPIRY_HOURS=2
|
PASSWORD_RESET_EXPIRY_HOURS=2
|
||||||
|
|
||||||
|
# Google Analytics 4 (opzionale — caricato solo dopo consenso cookie «Accetta tutti»)
|
||||||
|
# GOOGLE_ANALYTICS_MEASUREMENT_ID=G-XXXXXXXXXX
|
||||||
|
|
||||||
# Stripe (test: sk_test_... / price_... da Dashboard modalità Test)
|
# Stripe (test: sk_test_... / price_... da Dashboard modalità Test)
|
||||||
STRIPE_SECRET_KEY=
|
STRIPE_SECRET_KEY=
|
||||||
STRIPE_WEBHOOK_SECRET=
|
STRIPE_WEBHOOK_SECRET=
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ services:
|
|||||||
REPLAY_STORAGE_ACCESS_KEY_ID: ${REPLAY_STORAGE_ACCESS_KEY_ID:-}
|
REPLAY_STORAGE_ACCESS_KEY_ID: ${REPLAY_STORAGE_ACCESS_KEY_ID:-}
|
||||||
REPLAY_STORAGE_SECRET_ACCESS_KEY: ${REPLAY_STORAGE_SECRET_ACCESS_KEY:-}
|
REPLAY_STORAGE_SECRET_ACCESS_KEY: ${REPLAY_STORAGE_SECRET_ACCESS_KEY:-}
|
||||||
REPLAY_STORAGE_FORCE_PATH_STYLE: ${REPLAY_STORAGE_FORCE_PATH_STYLE:-true}
|
REPLAY_STORAGE_FORCE_PATH_STYLE: ${REPLAY_STORAGE_FORCE_PATH_STYLE:-true}
|
||||||
|
GOOGLE_ANALYTICS_MEASUREMENT_ID: ${GOOGLE_ANALYTICS_MEASUREMENT_ID:-}
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000" # Solo LAN — NPM proxy HTTPS
|
- "3000:3000" # Solo LAN — NPM proxy HTTPS
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
Reference in New Issue
Block a user