3361f2e9e9
Se añade `<meta name="google-adsense-account">` al <head> de todas las páginas, que es lo que pide Google para verificar la propiedad del sitio. OJO: esto NO muestra anuncios ni carga adsbygoogle.js todavía; solo permite que Google confirme que el dominio es nuestro y arranque la revisión. TRES interruptores (ver components/AdSense.tsx): 1. `ADSENSE_CLIENT_ID` en el .env (no versionado). Vacío o sin poner = no se emite nada. Documentada en el README. NO lleva prefijo NEXT_PUBLIC_ a propósito: la etiqueta se pinta en el servidor, así que no hace falta exponerla al bundle ni rebuildear para activarla/desactivarla, al revés que NEXT_PUBLIC_GA_ID. 2. Admin (ADMIN_EMAILS o gmlevel de AzerothCore): sin etiqueta, para que la navegación del staff no cuente como tráfico con anuncios. 3. Rango de la cuenta (ns-ranks) Y pagos: solo ve anuncios el rango 1 (Newbie, el de por defecto) que ADEMÁS nunca ha pagado. Los dos cortes del punto 3 son distintos a propósito y no basta con mirar el rango: el mínimo de SumUp son 0,20 €, que a 100 PD/unidad son 20 PD, y eso sigue siendo rango 1. Mirando solo el rango, quien pagara el mínimo seguiría viendo anuncios, que es justo lo contrario de lo que queremos. Para no duplicar el SQL, las consultas de saldo y de total donado salen de getAccountDashboard a dos helpers (`getPoints`, `getDonatedPD`) que reutiliza el nuevo `getAccountRankInfo`, con las dos consultas mínimas en vez del panel entero (personajes, baneos, correo…). El criterio de rango es el mismo que ya usaba /my-account: el máximo entre lo donado y el saldo actual. Verificado contra la web real: anónimo y rango 1 sin pagos SÍ reciben la etiqueta; rango 1 con 99 PD también; 100 PD de saldo (rango 2) no; rango 1 tras pagar 0,20 € tampoco; admin tampoco; y con la variable vacía no la recibe nadie. Los dos últimos casos no existían en la BD, así que se probaron con datos temporales en la cuenta 14 (fila en stripelog y en api_points), ya borrados. /my-account sigue pintando el rango correcto tras mover las consultas. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
111 lines
4.5 KiB
TypeScript
111 lines
4.5 KiB
TypeScript
import type { Metadata } from 'next'
|
|
import Script from 'next/script'
|
|
import { notFound } from 'next/navigation'
|
|
import { NextIntlClientProvider, hasLocale } from 'next-intl'
|
|
import { getTranslations, setRequestLocale } from 'next-intl/server'
|
|
import { routing } from '@/i18n/routing'
|
|
import { Header } from '@/components/Header'
|
|
import { Video } from '@/components/Video'
|
|
import { Social } from '@/components/Social'
|
|
import { Footer } from '@/components/Footer'
|
|
import { CookieBanner } from '@/components/CookieConsent'
|
|
import { Analytics } from '@/components/Analytics'
|
|
import { AdSense } from '@/components/AdSense'
|
|
import '../globals.css'
|
|
|
|
export function generateStaticParams() {
|
|
return routing.locales.map((locale) => ({ locale }))
|
|
}
|
|
|
|
// SEO por idioma (SSR) vía Metadata API.
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ locale: string }>
|
|
}): Promise<Metadata> {
|
|
const { locale } = await params
|
|
const t = await getTranslations({ locale, namespace: 'Metadata' })
|
|
return {
|
|
title: t('title'),
|
|
description: t('description'),
|
|
openGraph: {
|
|
siteName: 'NightSpire',
|
|
title: t('title'),
|
|
description: t('description'),
|
|
type: 'website',
|
|
locale: locale === 'es' ? 'es_ES' : 'en_US',
|
|
url: 'https://www.nightspire.gg/',
|
|
},
|
|
}
|
|
}
|
|
|
|
export default async function LocaleLayout({
|
|
children,
|
|
params,
|
|
}: {
|
|
children: React.ReactNode
|
|
params: Promise<{ locale: string }>
|
|
}) {
|
|
const { locale } = await params
|
|
if (!hasLocale(routing.locales, locale)) notFound()
|
|
setRequestLocale(locale)
|
|
|
|
return (
|
|
<html lang={locale}>
|
|
<head>
|
|
{/* Verificación de la cuenta de Google AdSense: solo si hay ADSENSE_CLIENT_ID
|
|
y el visitante no es admin. Ver components/AdSense.tsx. */}
|
|
<AdSense />
|
|
{/* Iconos del sitio (idénticos a la web Django) */}
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
|
<link rel="icon" type="image/png" sizes="194x194" href="/favicon-194x194.png" />
|
|
<link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png" />
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
|
<link rel="manifest" href="/site.webmanifest" />
|
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#47210a" />
|
|
<link rel="shortcut icon" href="/favicon.ico" />
|
|
{/* Font Awesome (mismos iconos que la web Django) */}
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
|
/>
|
|
{/* Config de los tooltips de wowhead (debe definirse antes de tooltips.js).
|
|
OJO con el `window.`: tooltips.js lee `window.whTooltips`, y un `const` a
|
|
nivel de script queda en el ámbito léxico del script (no crea propiedad en
|
|
window), así que la config se ignoraba entera y valían los valores por
|
|
defecto de wowhead.
|
|
`colorLinks` tiñe cada enlace según la calidad del ítem e `iconizeLinks` le
|
|
antepone el icono pequeño: los dos replican lo que hace el store original
|
|
(sus enlaces acaban con las clases `icontinyl q4`). Sin colorLinks los
|
|
nombres caen al `a{color:#2471a9}` del tema y salen todos azules.
|
|
`renameLinks` NO: el texto de los enlaces es el nombre de nuestra BD (en
|
|
español), y wowhead lo sobreescribiría. El idioma del tooltip lo da el
|
|
subdominio del enlace (es./www.). */}
|
|
<script
|
|
dangerouslySetInnerHTML={{
|
|
__html: 'window.whTooltips={colorLinks:true,iconizeLinks:true,renameLinks:false};',
|
|
}}
|
|
/>
|
|
</head>
|
|
<body>
|
|
<NextIntlClientProvider>
|
|
<Header />
|
|
<Video />
|
|
{children}
|
|
<Social />
|
|
<Footer />
|
|
<CookieBanner />
|
|
</NextIntlClientProvider>
|
|
{/* Analítica: solo si hay NEXT_PUBLIC_GA_ID y el visitante ha aceptado
|
|
la categoría «Analíticas» del banner. Ver components/Analytics.tsx. */}
|
|
<Analytics />
|
|
{/* Tooltips de wowhead (WotLK) en todos los enlaces .../wowhead.com/... y
|
|
elementos con data-wowhead. Funciona con contenido añadido por React
|
|
(carrito, búsquedas) porque delega el hover en el documento. */}
|
|
<Script src="https://wow.zamimg.com/js/tooltips.js" strategy="afterInteractive" />
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|