From b4173e780b3a05f7c45fdb14d096444586dddbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:37:46 -0500 Subject: [PATCH 01/13] feat; update readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d7376a310..fb20f6371 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +## Visit the website + +### https://blitzkit.app/ + +![BlitzKit website](https://i.imgur.com/m8e39Rv.png) + # BlitzKit [![built with Codeium](https://codeium.com/badges/main)](https://codeium.com) @@ -10,12 +16,6 @@ Go to [application directory for BlitzKit](https://discord.com/application-direc ![BlitzKit application directory](https://i.imgur.com/YWCtOuJ.png) -## Visit the website - -### https://blitzkit.app/ - -![BlitzKit website](https://i.imgur.com/bdYMUCL.png) - ## Visit the documentation website ### https://tresabhi.github.io/blitzkit/ From 84929f9732e38db89d3caead2ebef87099b2e079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:26:12 -0500 Subject: [PATCH 02/13] feat: responsive ads --- .../[id]/components/Characteristics/index.tsx | 21 ++++++- .../Model/CharacteristicsSection.tsx | 57 +++++++++++++++---- src/app/tools/tankopedia/[id]/page.tsx | 9 +-- src/components/AdMidSectionNarrowOnly.tsx | 19 +++++++ ...ctionAd.tsx => AdMidSectionResponsive.tsx} | 2 +- src/components/AdMidSectionWideOnly.tsx | 19 +++++++ 6 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 src/components/AdMidSectionNarrowOnly.tsx rename src/components/{MidSectionAd.tsx => AdMidSectionResponsive.tsx} (88%) create mode 100644 src/components/AdMidSectionWideOnly.tsx diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index e47201692..e0898aefe 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -11,6 +11,7 @@ import { import { debounce } from 'lodash'; import { Fragment, use, useEffect, useRef, useState } from 'react'; import { lerp } from 'three/src/math/MathUtils'; +import { Ad, AdType } from '../../../../../../components/Ad'; import { Link } from '../../../../../../components/Link'; import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits'; import { isExplosive } from '../../../../../../core/blitz/isExplosive'; @@ -26,14 +27,12 @@ import { GUN_TYPE_NAMES, } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { useEquipment } from '../../../../../../hooks/useEquipment'; -import { useWideFormat } from '../../../../../../hooks/useWideFormat'; import { mutateDuel, useDuel } from '../../../../../../stores/duel'; import { useTankopediaTemporary } from '../../../../../../stores/tankopedia'; import { Info } from './components/Info'; import { InfoWithDelta } from './components/InfoWithDelta'; export function Characteristics() { - const wideFormat = useWideFormat(960); const awaitedEquipmentDefinitions = use(equipmentDefinitions); const awaitedModelDefinitions = use(modelDefinitions); const awaitedProvisionDefinitions = use(provisionDefinitions); @@ -128,7 +127,13 @@ export function Characteristics() { }, [hasImprovedVerticalStabilizer]); return ( - + @@ -480,6 +485,16 @@ export function Characteristics() { + + + + Maneuverability diff --git a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx index 70f90c680..baa78d9bf 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx @@ -1,5 +1,5 @@ import { Flex, Heading } from '@radix-ui/themes'; -import { useWideFormat } from '../../../../../../hooks/useWideFormat'; +import { Ad, AdType } from '../../../../../../components/Ad'; import { Characteristics } from '../Characteristics'; import { Consumables } from '../Characteristics/components/Consumables'; import { Equipment } from '../Characteristics/components/Equipment'; @@ -9,22 +9,39 @@ import { Provisions } from '../Characteristics/components/Provisions'; import { Skills } from '../Characteristics/components/Skills'; export function CharacteristicsSection() { - const wideFormat = useWideFormat(880); - return ( + + + + + Configuration @@ -37,10 +54,11 @@ export function CharacteristicsSection() { + + + + + ); } diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index 4da1fc0e7..b2e50731e 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -1,7 +1,8 @@ 'use client'; import { useEffect } from 'react'; -import { MidSectionAd } from '../../../../components/MidSectionAd'; +import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive'; +import { AdMidSectionWideOnly } from '../../../../components/AdMidSectionWideOnly'; import PageWrapper from '../../../../components/PageWrapper'; import { assignDuelMember } from '../../../../core/blitzkit/assignDuelMember'; import { mutateDuel, useDuel } from '../../../../stores/duel'; @@ -75,12 +76,12 @@ export default function Page({ params }: { params: { id: string } }) { {assigned && ( <> - + - + - + {/* */} diff --git a/src/components/AdMidSectionNarrowOnly.tsx b/src/components/AdMidSectionNarrowOnly.tsx new file mode 100644 index 000000000..8d5361fe3 --- /dev/null +++ b/src/components/AdMidSectionNarrowOnly.tsx @@ -0,0 +1,19 @@ +import { Flex, FlexProps } from '@radix-ui/themes'; +import { Ad, AdType } from './Ad'; + +export function AdMidSectionNarrowOnly(props: FlexProps) { + return ( + + + + ); +} diff --git a/src/components/MidSectionAd.tsx b/src/components/AdMidSectionResponsive.tsx similarity index 88% rename from src/components/MidSectionAd.tsx rename to src/components/AdMidSectionResponsive.tsx index 4afccbfb6..5bd1a39b0 100644 --- a/src/components/MidSectionAd.tsx +++ b/src/components/AdMidSectionResponsive.tsx @@ -1,7 +1,7 @@ import { Flex, FlexProps } from '@radix-ui/themes'; import { Ad, AdType } from './Ad'; -export function MidSectionAd(props: FlexProps) { +export function AdMidSectionResponsive(props: FlexProps) { return ( + + + ); +} From 03aa690247abebd6ece88d49775b60d37fed4f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:50:44 -0500 Subject: [PATCH 03/13] fix: ctrl key functionality --- src/components/Link.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 46ef43164..130ea5f2d 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -11,7 +11,13 @@ export function Link({ href, onClick, ...props }: LinkProps) { href={href} onClick={(event) => { event.preventDefault(); - if (href) router.push(href); + if (href) { + if (event.ctrlKey || event.metaKey) { + window.open(href); + } else { + router.push(href); + } + } onClick?.(event); }} {...props} From a7e89c2147849824c6fef6a9870f1748e6ad3b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:52:43 -0500 Subject: [PATCH 04/13] feat: patreon login --- src/app/api/auth/patreon/[code]/route.ts | 17 +++ .../api/auth/patreon/refresh/[token]/route.ts | 14 +++ src/app/auth/[provider]/page.tsx | 91 ++++++++++++++++ src/app/callback/[provider]/page.tsx | 62 ----------- src/app/components/Checks.tsx | 38 +++++-- src/components/Navbar/components/LoggedIn.tsx | 26 ----- src/components/Navbar/index.tsx | 102 ++++++------------ src/core/blitz/authURL.ts | 10 -- src/core/blitz/extendAuthPatreon.ts | 20 ++++ .../{extendAuth.ts => extendAuthWargaming.ts} | 16 +-- .../blitz/{logout.ts => logoutPatreon.ts} | 4 +- src/core/blitz/logoutWargaming.ts | 7 ++ src/icons/Wargaming.tsx | 28 +++++ src/stores/app.ts | 16 ++- 14 files changed, 260 insertions(+), 191 deletions(-) create mode 100644 src/app/api/auth/patreon/[code]/route.ts create mode 100644 src/app/api/auth/patreon/refresh/[token]/route.ts create mode 100644 src/app/auth/[provider]/page.tsx delete mode 100644 src/app/callback/[provider]/page.tsx delete mode 100644 src/components/Navbar/components/LoggedIn.tsx delete mode 100644 src/core/blitz/authURL.ts create mode 100644 src/core/blitz/extendAuthPatreon.ts rename src/core/blitz/{extendAuth.ts => extendAuthWargaming.ts} (93%) rename src/core/blitz/{logout.ts => logoutPatreon.ts} (52%) create mode 100644 src/core/blitz/logoutWargaming.ts create mode 100644 src/icons/Wargaming.tsx diff --git a/src/app/api/auth/patreon/[code]/route.ts b/src/app/api/auth/patreon/[code]/route.ts new file mode 100644 index 000000000..9230c4b55 --- /dev/null +++ b/src/app/api/auth/patreon/[code]/route.ts @@ -0,0 +1,17 @@ +import { NextResponse } from 'next/server'; + +export async function GET( + request: Request, + { params }: { params: { code: string } }, +) { + const response = await fetch( + `https://www.patreon.com/api/oauth2/token?code=${params.code}&grant_type=authorization_code&client_id=${process.env.NEXT_PUBLIC_PATREON_CLIENT_ID}&client_secret=${process.env.PATREON_CLIENT_SECRET}&redirect_uri=${process.env.NEXT_PUBLIC_PATREON_REDIRECT_URI}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + }, + ); + const json = await response.json(); + + return NextResponse.json(json); +} diff --git a/src/app/api/auth/patreon/refresh/[token]/route.ts b/src/app/api/auth/patreon/refresh/[token]/route.ts new file mode 100644 index 000000000..a34e8e376 --- /dev/null +++ b/src/app/api/auth/patreon/refresh/[token]/route.ts @@ -0,0 +1,14 @@ +import { NextResponse } from 'next/server'; + +export async function GET( + request: Request, + { params }: { params: { token: string } }, +) { + const response = await fetch( + `https://www.patreon.com/api/oauth2/token?grant_type=refresh_token&refresh_token=${params.token}&client_id=${process.env.NEXT_PUBLIC_PATREON_CLIENT_ID}&client_secret=${process.env.PATREON_CLIENT_SECRET}`, + { method: 'POST' }, + ); + const json = await response.json(); + + return NextResponse.json(json); +} diff --git a/src/app/auth/[provider]/page.tsx b/src/app/auth/[provider]/page.tsx new file mode 100644 index 000000000..43323a52b --- /dev/null +++ b/src/app/auth/[provider]/page.tsx @@ -0,0 +1,91 @@ +'use client'; + +import { Flex, Heading, Text } from '@radix-ui/themes'; +import { useRouter } from 'next/navigation'; +import { useEffect } from 'react'; +import PageWrapper from '../../../components/PageWrapper'; +import { mutateApp } from '../../../stores/app'; + +export interface PatreonAuthResponse { + access_token: string; + expires_in: number; + token_type: 'Bearer'; + scope: string; + refresh_token: string; + version: string; +} + +export default function Page({ + params, + searchParams, +}: { + params: { provider: string }; + searchParams: { [key: string]: string }; +}) { + const router = useRouter(); + + useEffect(() => { + (async () => { + switch (params.provider) { + case 'wargaming': { + if ( + !searchParams.expires_at || + !searchParams.access_token || + !searchParams.account_id + ) { + break; + } + + mutateApp((draft) => { + draft.logins.wargaming = { + id: Number(searchParams.account_id), + token: searchParams.access_token, + expires: Number(searchParams.expires_at) * 1000, + }; + }); + + break; + } + + case 'patreon': { + if (!searchParams.code) break; + + const data = (await fetch( + `/api/auth/patreon/${searchParams.code}`, + ).then((response) => response.json())) as PatreonAuthResponse; + + mutateApp((draft) => { + draft.logins.patreon = { + token: data.access_token, + refreshToken: data.refresh_token, + expires: Date.now() + data.expires_in * 1000, + }; + }); + + break; + } + + default: { + console.error(`Unknown provider: ${params.provider}`); + } + } + + router.push(searchParams.return ?? '/'); + })(); + }); + + return ( + + + Verifying you... + You'll be on your way shortly. + + + ); +} diff --git a/src/app/callback/[provider]/page.tsx b/src/app/callback/[provider]/page.tsx deleted file mode 100644 index 1c21aac6c..000000000 --- a/src/app/callback/[provider]/page.tsx +++ /dev/null @@ -1,62 +0,0 @@ -'use client'; - -import { Flex, Heading, Text } from '@radix-ui/themes'; -import { useRouter } from 'next/navigation'; -import { useEffect } from 'react'; -import PageWrapper from '../../../components/PageWrapper'; -import { mutateApp } from '../../../stores/app'; - -export default function Page({ - params, - searchParams, -}: { - params: { provider: string }; - searchParams: { [key: string]: string }; -}) { - const router = useRouter(); - - useEffect(() => { - switch (params.provider) { - case 'wargaming': { - if ( - !searchParams.expires_at || - !searchParams.access_token || - !searchParams.account_id - ) { - break; - } - - mutateApp((draft) => { - draft.login = { - expiresAt: Number(searchParams.expires_at), - id: Number(searchParams.account_id), - token: searchParams.access_token, - }; - }); - - break; - } - - default: { - console.error(`Unknown provider: ${params.provider}`); - } - } - - router.push(searchParams.return ? searchParams.return : '/'); - }); - - return ( - - - Verifying you... - You'll be on your way shortly. - - - ); -} diff --git a/src/app/components/Checks.tsx b/src/app/components/Checks.tsx index a935d348d..719907fcb 100644 --- a/src/app/components/Checks.tsx +++ b/src/app/components/Checks.tsx @@ -10,17 +10,24 @@ import { } from '@radix-ui/themes'; import { usePathname } from 'next/navigation'; import { useEffect, useState } from 'react'; -import { extendAuth } from '../../core/blitz/extendAuth'; -import { logout } from '../../core/blitz/logout'; +import { extendAuthPatreon } from '../../core/blitz/extendAuthPatreon'; +import { extendAuthWargaming } from '../../core/blitz/extendAuthWargaming'; +import { logoutPatreon } from '../../core/blitz/logoutPatreon'; +import { logoutWargaming } from '../../core/blitz/logoutWargaming'; import isDev from '../../core/blitzkit/isDev'; import { isLocalhost } from '../../core/blitzkit/isLocalhost'; import { CURRENT_POLICIES_AGREEMENT_INDEX, useApp } from '../../stores/app'; const DEV_BUILD_AGREEMENT_COOLDOWN = 8 * 24 * 60 * 60 * 1000; +/** + * Wargaming: 14 (refresh: 7) + * Patreon: 31 (refresh: 15) + */ + export function Checks() { const [showDevBuildAlert, setShowDevBuildAlert] = useState(false); - const login = useApp((state) => state.login); + const logins = useApp((state) => state.logins); const policiesAgreementIndex = useApp( (state) => state.policiesAgreementIndex, ); @@ -43,15 +50,26 @@ export function Checks() { }, [policiesAgreementIndex, isLegal]); useEffect(() => { - if (!login) return; + if (logins.wargaming) { + const expiresIn = logins.wargaming.expires - Date.now(); + const expiresInDays = expiresIn / 1000 / 60 / 60 / 24; - const expiresIn = login.expiresAt - Date.now() / 1000; - const expiresInDays = expiresIn / 60 / 60 / 24; + if (expiresInDays < 0) { + logoutWargaming(); + } else if (expiresInDays < 7) { + extendAuthWargaming(); + } + } - if (expiresInDays < 0) { - logout(); - } else if (expiresInDays < 7) { - extendAuth(); + if (logins.patreon) { + const expiresIn = logins.patreon.expires - Date.now(); + const expiresInDays = expiresIn / 1000 / 60 / 60 / 24; + + if (expiresInDays < 0) { + logoutPatreon(); + } else if (expiresInDays < 15) { + extendAuthPatreon(); + } } }); diff --git a/src/components/Navbar/components/LoggedIn.tsx b/src/components/Navbar/components/LoggedIn.tsx deleted file mode 100644 index bafdbe7ed..000000000 --- a/src/components/Navbar/components/LoggedIn.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { ExitIcon } from '@radix-ui/react-icons'; -import { Flex, IconButton, Text } from '@radix-ui/themes'; -import { use } from 'react'; -import { getAccountInfo } from '../../../core/blitz/getAccountInfo'; -import { idToRegion } from '../../../core/blitz/idToRegion'; -import { logout } from '../../../core/blitz/logout'; -import { useApp } from '../../../stores/app'; - -export function LoggedIn() { - const login = useApp((state) => state.login!); - const accountInfo = use( - getAccountInfo(idToRegion(login.id), login.id, [], { - access_token: login.token, - }), - ); - - return ( - - Hello, {accountInfo.nickname} - - - - - - ); -} diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 34c259ab4..26ac4c298 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -5,28 +5,16 @@ import { HamburgerMenuIcon, PersonIcon, } from '@radix-ui/react-icons'; -import { - Box, - Button, - Dialog, - Flex, - Heading, - IconButton, - Popover, - Spinner, - Text, -} from '@radix-ui/themes'; +import { Box, Button, Flex, IconButton, Popover, Text } from '@radix-ui/themes'; import { usePathname } from 'next/navigation'; -import { Suspense, useState } from 'react'; -import { REGIONS, UNLOCALIZED_REGION_NAMES } from '../../constants/regions'; +import { useState } from 'react'; import { TOOLS } from '../../constants/tools'; -import { authURL } from '../../core/blitz/authURL'; import { BlitzkitWide } from '../../icons/BlitzkitWide'; import { PatreonIcon } from '../../icons/Patreon'; +import { WargamingIcon } from '../../icons/Wargaming'; import { theme } from '../../stitches.config'; import { useApp } from '../../stores/app'; import { Link } from '../Link'; -import { LoggedIn } from './components/LoggedIn'; import * as styles from './index.css'; export const NAVBAR_HEIGHT = 64; @@ -34,7 +22,7 @@ export const NAVBAR_HEIGHT = 64; export default function Navbar() { const [showHamburgerMenu, setShowHamburgerMenu] = useState(false); const pathname = usePathname(); - const login = useApp((state) => state.login!); + const logins = useApp((state) => state.logins); return ( - setShowHamburgerMenu(false)}> + setShowHamburgerMenu(false)} + color="gray" + highContrast + > - - - + - {login && ( - - - - - - + + + + - - - }> - - - - - - )} + + + Log in with... - {!login && false && ( - - - - - - - - Choose your region - - - {REGIONS.map((region) => ( - setShowHamburgerMenu(false)} - key={region} - href={authURL( - region, - typeof window === 'undefined' - ? undefined - : location.href, - )} - > - {UNLOCALIZED_REGION_NAMES[region]} - - ))} - - - - - )} + + + + + + + diff --git a/src/core/blitz/authURL.ts b/src/core/blitz/authURL.ts deleted file mode 100644 index b6853e9dd..000000000 --- a/src/core/blitz/authURL.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Region } from '../../constants/regions'; -import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; - -export function authURL(region: Region, callback?: string) { - if (typeof window === 'undefined') throw new Error('window is undefined'); - - return `https://api.worldoftanks.${region}/wot/auth/login/?application_id=${WARGAMING_APPLICATION_ID}&redirect_uri=${encodeURIComponent( - `${window.location.origin}/callback/wargaming/${callback ? `?return=${location.href}` : ''}`, - )}`; -} diff --git a/src/core/blitz/extendAuthPatreon.ts b/src/core/blitz/extendAuthPatreon.ts new file mode 100644 index 000000000..64bdea9c9 --- /dev/null +++ b/src/core/blitz/extendAuthPatreon.ts @@ -0,0 +1,20 @@ +import { PatreonAuthResponse } from '../../app/auth/[provider]/page'; +import { mutateApp, useApp } from '../../stores/app'; + +export async function extendAuthPatreon() { + const { patreon } = useApp.getState().logins; + + if (!patreon) return; + + const data = (await fetch( + `/api/auth/patreon/refresh/${patreon.refreshToken}`, + ).then((response) => response.json())) as PatreonAuthResponse; + + mutateApp((draft) => { + draft.logins.patreon = { + token: data.access_token, + refreshToken: data.refresh_token, + expires: Date.now() + data.expires_in * 1000, + }; + }); +} diff --git a/src/core/blitz/extendAuth.ts b/src/core/blitz/extendAuthWargaming.ts similarity index 93% rename from src/core/blitz/extendAuth.ts rename to src/core/blitz/extendAuthWargaming.ts index 578e7da38..fe507db07 100644 --- a/src/core/blitz/extendAuth.ts +++ b/src/core/blitz/extendAuthWargaming.ts @@ -10,10 +10,10 @@ interface Extension { }; } -export async function extendAuth() { - const { login } = useApp.getState(); +export async function extendAuthWargaming() { + const { wargaming } = useApp.getState().logins; - if (!login) return; + if (!wargaming) return; // error handling? what's that? /* @@ -42,18 +42,18 @@ export async function extendAuth() { const response = await fetch( `https://api.worldoftanks.${idToRegion( - login.id, + wargaming.id, )}/wot/auth/prolongate/?application_id=${WARGAMING_APPLICATION_ID}&access_token=${ - login.token + wargaming.token }`, ); const json = (await response.json()) as Extension; mutateApp((draft) => { - draft.login = { - id: login.id, + draft.logins.wargaming = { + id: wargaming.id, token: json.data.access_token, - expiresAt: json.data.expires_at, + expires: json.data.expires_at * 1000, }; }); } diff --git a/src/core/blitz/logout.ts b/src/core/blitz/logoutPatreon.ts similarity index 52% rename from src/core/blitz/logout.ts rename to src/core/blitz/logoutPatreon.ts index 290aa4774..fe7152882 100644 --- a/src/core/blitz/logout.ts +++ b/src/core/blitz/logoutPatreon.ts @@ -1,7 +1,7 @@ import { mutateApp } from '../../stores/app'; -export function logout() { +export function logoutPatreon() { mutateApp((draft) => { - draft.login = undefined; + draft.logins.patreon = undefined; }); } diff --git a/src/core/blitz/logoutWargaming.ts b/src/core/blitz/logoutWargaming.ts new file mode 100644 index 000000000..f96421385 --- /dev/null +++ b/src/core/blitz/logoutWargaming.ts @@ -0,0 +1,7 @@ +import { mutateApp } from '../../stores/app'; + +export function logoutWargaming() { + mutateApp((draft) => { + draft.logins.wargaming = undefined; + }); +} diff --git a/src/icons/Wargaming.tsx b/src/icons/Wargaming.tsx new file mode 100644 index 000000000..458b7951a --- /dev/null +++ b/src/icons/Wargaming.tsx @@ -0,0 +1,28 @@ +import { ComponentProps } from 'react'; + +export function WargamingIcon(props: ComponentProps<'svg'>) { + return ( + + + + + + + + + + + ); +} diff --git a/src/stores/app.ts b/src/stores/app.ts index 0931749f3..f0355572b 100644 --- a/src/stores/app.ts +++ b/src/stores/app.ts @@ -3,16 +3,25 @@ import { merge } from 'lodash'; import { create } from 'zustand'; import { persist } from 'zustand/middleware'; -interface Login { +interface WargamingLogin { id: number; token: string; - expiresAt: number; + expires: number; +} + +interface PatreonLogin { + token: string; + refreshToken: string; + expires: number; } export interface App { devBuildAgreementTime: number; developerMode: boolean; - login?: Login; + logins: { + wargaming?: WargamingLogin; + patreon?: PatreonLogin; + }; policiesAgreementIndex: number; } @@ -24,6 +33,7 @@ export const useApp = create()( devBuildAgreementTime: 0, developerMode: false, policiesAgreementIndex: -1, + logins: {}, }), { name: 'app', merge: (a, b) => merge(b, a) }, ), From cb09f57a91f87c39432956ffd0ea646defc55427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 13 Jun 2024 20:17:09 -0500 Subject: [PATCH 05/13] feat: wargaming login --- src/components/Navbar/index.tsx | 122 ++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 15 deletions(-) diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 26ac4c298..06e2ee8d4 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -5,13 +5,28 @@ import { HamburgerMenuIcon, PersonIcon, } from '@radix-ui/react-icons'; -import { Box, Button, Flex, IconButton, Popover, Text } from '@radix-ui/themes'; +import { + Box, + Button, + Dialog, + Flex, + IconButton, + Inset, + Popover, + Separator, + Text, +} from '@radix-ui/themes'; import { usePathname } from 'next/navigation'; import { useState } from 'react'; +import { REGIONS } from '../../constants/regions'; import { TOOLS } from '../../constants/tools'; +import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; +import { logoutPatreon } from '../../core/blitz/logoutPatreon'; +import { logoutWargaming } from '../../core/blitz/logoutWargaming'; import { BlitzkitWide } from '../../icons/BlitzkitWide'; import { PatreonIcon } from '../../icons/Patreon'; import { WargamingIcon } from '../../icons/Wargaming'; +import strings from '../../lang/en-US.json'; import { theme } from '../../stitches.config'; import { useApp } from '../../stores/app'; import { Link } from '../Link'; @@ -125,21 +140,98 @@ export default function Navbar() { - - Log in with... + {(logins.patreon || logins.wargaming) && ( + + + Logged in accounts + - - - - - + {logins.patreon && ( + + + Patreon + + + )} + + {logins.wargaming && ( + + + Wargaming + + + )} + + )} + + {!logins.patreon !== !logins.wargaming && ( + + + + )} + + {(!logins.patreon || !logins.wargaming) && ( + + + Log in with... + + + {!logins.patreon && ( + + + + )} + + {!logins.wargaming && ( + + + + + + + + Choose your region + + + {REGIONS.map((region) => ( + + + + + + ))} + + + + + )} + + )} From 0a0376312b6d882801b63b3ae0c9324c9559c16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:57:54 -0500 Subject: [PATCH 06/13] feat: patreon check --- .../patreon => patreon/auth}/[code]/route.ts | 0 .../api/patreon/membership/[token]/route.ts | 75 +++++++++++++++++++ .../patreon/refresh/[token]/route.ts | 0 src/app/auth/[provider]/page.tsx | 2 +- src/components/Ad.tsx | 26 ++++--- src/components/Navbar/index.tsx | 17 +++-- src/core/blitz/extendAuthPatreon.ts | 2 +- src/hooks/useAdExempt.ts | 11 +++ 8 files changed, 114 insertions(+), 19 deletions(-) rename src/app/api/{auth/patreon => patreon/auth}/[code]/route.ts (100%) create mode 100644 src/app/api/patreon/membership/[token]/route.ts rename src/app/api/{auth => }/patreon/refresh/[token]/route.ts (100%) create mode 100644 src/hooks/useAdExempt.ts diff --git a/src/app/api/auth/patreon/[code]/route.ts b/src/app/api/patreon/auth/[code]/route.ts similarity index 100% rename from src/app/api/auth/patreon/[code]/route.ts rename to src/app/api/patreon/auth/[code]/route.ts diff --git a/src/app/api/patreon/membership/[token]/route.ts b/src/app/api/patreon/membership/[token]/route.ts new file mode 100644 index 000000000..8c1a42e15 --- /dev/null +++ b/src/app/api/patreon/membership/[token]/route.ts @@ -0,0 +1,75 @@ +import { NextResponse } from 'next/server'; + +interface PatreonMembershipResponse { + data: { + attributes: unknown; + id: `${number}`; + relationships: { + memberships: { + data: { + id: string; // uuid + type: 'member'; + }[]; + }; + }; + type: 'user'; + }; + included: ( + | { + attributes: { + patron_status: + | 'active_patron' + | 'declined_patron' + | 'former_patron' + | null; // null = never a paid member + }; + id: string; // uuid + relationships: { + campaign: { + data: { + id: `${number}`; // id of my campaign to check against + type: 'campaign'; + }; + links: { + related: string; // url + }; + }; + }; + type: 'member'; + } + | { + attributes: {}; + id: `${number}`; + type: 'campaign'; // ignore this discriminator + } + )[]; + links: { + self: 'https://www.patreon.com/api/oauth2/v2/user/124201389'; + }; +} + +export async function GET( + request: Request, + { params }: { params: { token: string } }, +) { + const response = await fetch( + encodeURI( + 'https://www.patreon.com/api/oauth2/v2/identity?include=memberships.campaign&fields[member]=patron_status', + ), + { headers: { Authorization: `Bearer ${params.token}` } }, + ); + + if (!response.ok) return NextResponse.json(false); + + const json = (await response.json()) as PatreonMembershipResponse; + + return NextResponse.json( + json.included.some( + (item) => + item.type === 'member' && + item.relationships.campaign.data.id === + process.env.PATREON_CAMPAIGN_ID && + item.attributes.patron_status === 'active_patron', + ), + ); +} diff --git a/src/app/api/auth/patreon/refresh/[token]/route.ts b/src/app/api/patreon/refresh/[token]/route.ts similarity index 100% rename from src/app/api/auth/patreon/refresh/[token]/route.ts rename to src/app/api/patreon/refresh/[token]/route.ts diff --git a/src/app/auth/[provider]/page.tsx b/src/app/auth/[provider]/page.tsx index 43323a52b..4c63ad7dc 100644 --- a/src/app/auth/[provider]/page.tsx +++ b/src/app/auth/[provider]/page.tsx @@ -51,7 +51,7 @@ export default function Page({ if (!searchParams.code) break; const data = (await fetch( - `/api/auth/patreon/${searchParams.code}`, + `/api/patreon/auth/${searchParams.code}`, ).then((response) => response.json())) as PatreonAuthResponse; mutateApp((draft) => { diff --git a/src/components/Ad.tsx b/src/components/Ad.tsx index b785a6df6..5e7a973ad 100644 --- a/src/components/Ad.tsx +++ b/src/components/Ad.tsx @@ -1,10 +1,11 @@ 'use client'; -import { Box, BoxProps, Flex, Text } from '@radix-ui/themes'; +import { Box, BoxProps, Text } from '@radix-ui/themes'; import { uniqueId } from 'lodash'; import { useEffect, useRef } from 'react'; import { Vector2Tuple } from 'three'; import { imgur } from '../core/blitzkit/imgur'; +import { useAdExempt } from '../hooks/useAdExempt'; export enum AdType { MediumRectangleHorizontalPurple = 738182777, @@ -28,6 +29,8 @@ export function Ad({ type, style, ...props }: AdProps) { const id = useRef(uniqueId()); const dimensions = AD_DIMENSIONS[type]; + useAdExempt(); + useEffect(() => { (window as any).msAdsQueue.push(function () { (window as any).mmnow.render({ @@ -51,19 +54,18 @@ export function Ad({ type, style, ...props }: AdProps) { }} {...props} > - - Advertisement - - {dimensions[0]}x{dimensions[1]} - - + Advertisement + state.logins); @@ -191,7 +194,7 @@ export default function Navbar() { {!logins.patreon && ( + + {!patreon && ( + + + + )} + + + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index d3648388b..6bbbc6b97 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,15 +5,17 @@ import PageWrapper from '../components/PageWrapper'; import { TOOLS } from '../constants/tools'; import { ImgurSize, imgur } from '../core/blitzkit/imgur'; import { Hero } from './components/Hero'; +import { PatreonPlug } from './components/PatreonPlug'; export default function Page() { return ( <> + + { (window as any).msAdsQueue.push(function () { diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index c89f812a8..7689d3ed1 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -27,7 +27,13 @@ export function Footer() { sm: 'row', }} > - + BlitzKit{' '} diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 40f9174e3..1e8f75d51 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -25,6 +25,7 @@ import { TOOLS } from '../../constants/tools'; import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; import { logoutPatreon } from '../../core/blitz/logoutPatreon'; import { logoutWargaming } from '../../core/blitz/logoutWargaming'; +import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl'; import { BlitzkitWide } from '../../icons/BlitzkitWide'; import { PatreonIcon } from '../../icons/Patreon'; import { WargamingIcon } from '../../icons/Wargaming'; @@ -192,10 +193,7 @@ export default function Navbar() { {!logins.patreon && ( - + @@ -216,10 +214,10 @@ export default function Navbar() { {REGIONS.map((region) => ( - + response.json()) - .then(console.log); + const json = use( + fetch(`/api/patreon/membership/${patreon.token}`, { + cache: 'force-cache', + }).then((response) => response.json()), + ); + + return typeof json === 'boolean' && json; } diff --git a/src/icons/Blitzkit.tsx b/src/icons/Blitzkit.tsx index c8425ef4e..afc98baa4 100644 --- a/src/icons/Blitzkit.tsx +++ b/src/icons/Blitzkit.tsx @@ -36,8 +36,8 @@ export function Blitzkit(props: ComponentProps<'svg'>) { fill="url(#paint4_linear_513_245)" /> diff --git a/src/icons/BlitzkitButtonWatermark.tsx b/src/icons/BlitzkitButtonWatermark.tsx index c3b26f70e..5a9e7d4b5 100644 --- a/src/icons/BlitzkitButtonWatermark.tsx +++ b/src/icons/BlitzkitButtonWatermark.tsx @@ -10,7 +10,7 @@ export function BlitzkitButtonWatermark(props: ComponentProps<'svg'>) { xmlns="http://www.w3.org/2000/svg" {...props} > - + ) { fill="white" /> diff --git a/src/icons/Wargaming.tsx b/src/icons/Wargaming.tsx index 458b7951a..dd7e4ca02 100644 --- a/src/icons/Wargaming.tsx +++ b/src/icons/Wargaming.tsx @@ -10,10 +10,10 @@ export function WargamingIcon(props: ComponentProps<'svg'>) { xmlns="http://www.w3.org/2000/svg" {...props} > - + From 57fa29cc6e79fc161ad0e8bdd7540900a9b9ef42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 15 Jun 2024 13:24:53 -0500 Subject: [PATCH 09/13] feat: cleaner exempt --- .../[id]/components/Characteristics/index.tsx | 22 +++--- .../Model/CharacteristicsSection.tsx | 72 ++++++++++--------- src/app/tools/tankopedia/[id]/page.tsx | 10 +-- src/app/tools/tankopedia/page.tsx | 14 ++-- src/components/Ad.tsx | 4 -- src/hooks/useAdExempt.ts | 2 + 6 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index e0898aefe..be696b587 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -26,6 +26,7 @@ import { CREW_MEMBER_NAMES, GUN_TYPE_NAMES, } from '../../../../../../core/blitzkit/tankDefinitions/constants'; +import { useAdExempt } from '../../../../../../hooks/useAdExempt'; import { useEquipment } from '../../../../../../hooks/useEquipment'; import { mutateDuel, useDuel } from '../../../../../../stores/duel'; import { useTankopediaTemporary } from '../../../../../../stores/tankopedia'; @@ -33,6 +34,7 @@ import { Info } from './components/Info'; import { InfoWithDelta } from './components/InfoWithDelta'; export function Characteristics() { + const exempt = useAdExempt(); const awaitedEquipmentDefinitions = use(equipmentDefinitions); const awaitedModelDefinitions = use(modelDefinitions); const awaitedProvisionDefinitions = use(provisionDefinitions); @@ -485,15 +487,17 @@ export function Characteristics() { - - - + {!exempt && ( + + + + )} diff --git a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx index baa78d9bf..ac49fd42b 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx @@ -1,5 +1,6 @@ import { Flex, Heading } from '@radix-ui/themes'; import { Ad, AdType } from '../../../../../../components/Ad'; +import { useAdExempt } from '../../../../../../hooks/useAdExempt'; import { Characteristics } from '../Characteristics'; import { Consumables } from '../Characteristics/components/Consumables'; import { Equipment } from '../Characteristics/components/Equipment'; @@ -9,8 +10,11 @@ import { Provisions } from '../Characteristics/components/Provisions'; import { Skills } from '../Characteristics/components/Skills'; export function CharacteristicsSection() { + const exempt = useAdExempt(); + return ( - - - - + {!exempt && ( + + + + + )} - - - - + {!exempt && ( + + + + + )} ); } diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index b2e50731e..d1b2a9191 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -2,9 +2,9 @@ import { useEffect } from 'react'; import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive'; -import { AdMidSectionWideOnly } from '../../../../components/AdMidSectionWideOnly'; import PageWrapper from '../../../../components/PageWrapper'; import { assignDuelMember } from '../../../../core/blitzkit/assignDuelMember'; +import { useAdExempt } from '../../../../hooks/useAdExempt'; import { mutateDuel, useDuel } from '../../../../stores/duel'; import { mutateTankopediaTemporary } from '../../../../stores/tankopedia'; import { HistorySection } from './components/HistorySection'; @@ -16,6 +16,7 @@ import { VideoSection } from './components/VideoSection'; export default function Page({ params }: { params: { id: string } }) { const initialId = parseInt(params.id); const assigned = useDuel((state) => state.assigned); + const exempt = useAdExempt(); useEffect(() => { assignDuelMember('both', initialId); @@ -76,14 +77,13 @@ export default function Page({ params }: { params: { id: string } }) { {assigned && ( <> - + {!exempt && } - + {!exempt && } - + {!exempt && } - {/* */} )} diff --git a/src/app/tools/tankopedia/page.tsx b/src/app/tools/tankopedia/page.tsx index 31d7bd068..99d25801b 100644 --- a/src/app/tools/tankopedia/page.tsx +++ b/src/app/tools/tankopedia/page.tsx @@ -5,10 +5,12 @@ import { times } from 'lodash'; import { useRouter } from 'next/navigation'; import { Ad, AdType } from '../../../components/Ad'; import PageWrapper from '../../../components/PageWrapper'; +import { useAdExempt } from '../../../hooks/useAdExempt'; import { TankSearch } from './components/TankSearch'; export default function Page() { const router = useRouter(); + const exempt = useAdExempt(); return ( @@ -18,11 +20,13 @@ export default function Page() { }} /> - - {times(2, (index) => ( - - ))} - + {!exempt && ( + + {times(2, (index) => ( + + ))} + + )} ); } diff --git a/src/components/Ad.tsx b/src/components/Ad.tsx index e6893d264..529fdbf64 100644 --- a/src/components/Ad.tsx +++ b/src/components/Ad.tsx @@ -5,7 +5,6 @@ import { uniqueId } from 'lodash'; import { useEffect, useRef } from 'react'; import { Vector2Tuple } from 'three'; import { imgur } from '../core/blitzkit/imgur'; -import { useAdExempt } from '../hooks/useAdExempt'; export enum AdType { MediumRectangleHorizontalPurple = 738182777, @@ -28,9 +27,6 @@ type AdProps = BoxProps & { export function Ad({ type, style, ...props }: AdProps) { const id = useRef(uniqueId()); const dimensions = AD_DIMENSIONS[type]; - const exempt = useAdExempt(); - - if (exempt) return null; useEffect(() => { (window as any).msAdsQueue.push(function () { diff --git a/src/hooks/useAdExempt.ts b/src/hooks/useAdExempt.ts index 1aae3da9a..77617de48 100644 --- a/src/hooks/useAdExempt.ts +++ b/src/hooks/useAdExempt.ts @@ -2,6 +2,8 @@ import { use } from 'react'; import { useApp } from '../stores/app'; export function useAdExempt() { + return true; + const patreon = useApp((state) => state.logins.patreon); if (!patreon) return false; From 9f38f16d2b768b5667fa90cf7f831cc76c30729d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 15 Jun 2024 13:51:42 -0500 Subject: [PATCH 10/13] feat: homepage ads --- src/app/components/PatreonPlug.tsx | 6 +- src/app/components/ToolCard.tsx | 142 ++++++++++++++++++++++ src/app/page.tsx | 182 ++++++++--------------------- src/constants/tools.tsx | 167 +++++++++++++------------- src/hooks/useAdExempt.ts | 2 - 5 files changed, 281 insertions(+), 218 deletions(-) create mode 100644 src/app/components/ToolCard.tsx diff --git a/src/app/components/PatreonPlug.tsx b/src/app/components/PatreonPlug.tsx index 527eba5b1..e36c26639 100644 --- a/src/app/components/PatreonPlug.tsx +++ b/src/app/components/PatreonPlug.tsx @@ -23,11 +23,13 @@ export function PatreonPlug() { py="8" > - Active Patreon supports go ad-free + + Active Patreon supports go ad-free + - + + + + + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 6bbbc6b97..86081fa11 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,11 +1,19 @@ -import { CaretRightIcon } from '@radix-ui/react-icons'; -import { Box, Button, Flex, Grid, Heading, Text } from '@radix-ui/themes'; -import Link from 'next/link'; -import PageWrapper from '../components/PageWrapper'; -import { TOOLS } from '../constants/tools'; -import { ImgurSize, imgur } from '../core/blitzkit/imgur'; +'use client'; + +import { Box, Flex } from '@radix-ui/themes'; +import { Ad, AdType } from '../components/Ad'; +import { AdMidSectionResponsive } from '../components/AdMidSectionResponsive'; +import { + compareTool, + discordTool, + moreTool, + ratingTool, + sessionTool, + tankopediaTool, +} from '../constants/tools'; import { Hero } from './components/Hero'; import { PatreonPlug } from './components/PatreonPlug'; +import { ToolCard } from './components/ToolCard'; export default function Page() { return ( @@ -14,136 +22,46 @@ export default function Page() { - - + - {TOOLS.map((tool) => { - const size = tool.significant - ? ImgurSize.HugeThumbnail - : ImgurSize.LargeThumbnail; + /> - return ( - - - + + - - - - {tool.title} - - - {tool.description} - - + - - - - - ); - })} - - + + + + + + + + + + + + + + + + + + + +
diff --git a/src/constants/tools.tsx b/src/constants/tools.tsx index dd5821259..0df8a2e02 100644 --- a/src/constants/tools.tsx +++ b/src/constants/tools.tsx @@ -1,7 +1,7 @@ import { Button } from '@radix-ui/themes'; import { ComponentProps } from 'react'; -interface Tool { +export interface Tool { id: string; image: string; title: string; @@ -16,86 +16,89 @@ interface Tool { significant?: boolean; } +export const tankopediaTool: Tool = { + id: 'tankopedia', + title: 'Tankopedia', + description: 'Blitz tank encyclopedia', + pageDescription: + 'Statistics, armor, and more for all tanks in World of Tanks Blitz', + image: 'D8j6GZx', + button: { + text: 'Find your tank', + color: 'purple', + }, + significant: true, +}; + +export const ratingTool: Tool = { + id: 'rating', + title: 'Rating', + description: 'Full rating leaderboard', + pageDescription: + 'Live and archived full rating leaderboard for World of Tanks Blitz', + image: 'WEyMZH3', + button: { + text: 'View leaderboard', + color: 'orange', + }, +}; + +export const compareTool: Tool = { + id: 'compare', + title: 'Compare', + description: 'Compare tank statistics', + pageDescription: + 'Compare tanks statistics and loadouts in World of Tanks Blitz', + image: 'O6VNl6e', + button: { + text: 'Compare tanks', + color: 'crimson', + }, +}; + +export const sessionTool: Tool = { + // TODO: rename to tracker + id: 'session', + title: 'Session', + description: 'Live session stats', + pageDescription: + 'Track your stats in real time as you play World of Tanks Blitz', + image: 'HdG9sTf', + button: { + text: 'Start tracking', + color: 'blue', + }, +}; + +export const discordTool: Tool = { + id: 'discord', + title: 'Discord bot', + description: 'Stats right in Discord', + href: 'https://discord.com/application-directory/1097673957865443370', + image: '0bWE5hC', + button: { + text: 'Install now', + color: 'indigo', + }, +}; + +export const moreTool: Tool = { + id: 'more', + title: 'More coming soon', + description: "What we're making", + href: 'https://discord.gg/nDt7AjGJQH', + image: '1nPm6VI', + button: { + text: 'Join Discord', + color: 'indigo', + }, +}; + export const TOOLS: Tool[] = [ - // { - // id: 'statistics', - // title: 'Statistics', - // description: 'Periodical player statistics', - // pageDescription: - // 'Periodical player statistics and tanks played in World of Tanks Blitz', - // disabled: true, - // image: '8gJGkKP' - // }, - { - id: 'tankopedia', - title: 'Tankopedia', - description: 'Blitz tank encyclopedia', - pageDescription: - 'Statistics, armor, and more for all tanks in World of Tanks Blitz', - image: 'D8j6GZx', - button: { - text: 'Find your tank', - color: 'purple', - }, - significant: true, - }, - { - id: 'rating', - title: 'Rating', - description: 'Full rating leaderboard', - pageDescription: - 'Live and archived full rating leaderboard for World of Tanks Blitz', - image: 'WEyMZH3', - button: { - text: 'View leaderboard', - color: 'orange', - }, - }, - { - id: 'compare', - title: 'Compare', - description: 'Compare tank statistics', - pageDescription: - 'Compare tanks statistics and loadouts in World of Tanks Blitz', - image: 'O6VNl6e', - button: { - text: 'Compare tanks', - color: 'crimson', - }, - }, - { - // TODO: rename to tracker - id: 'session', - title: 'Session', - description: 'Live session stats', - pageDescription: - 'Track your stats in real time as you play World of Tanks Blitz', - image: 'HdG9sTf', - button: { - text: 'Start tracking', - color: 'blue', - }, - }, - { - id: 'discord', - title: 'Discord bot', - description: 'Stats right in Discord', - href: 'https://discord.com/application-directory/1097673957865443370', - image: '0bWE5hC', - button: { - text: 'Install now', - color: 'indigo', - }, - }, - { - id: 'more', - title: 'More coming soon', - description: "What we're making", - href: 'https://discord.gg/nDt7AjGJQH', - image: '1nPm6VI', - button: { - text: 'Join Discord', - color: 'indigo', - }, - }, + tankopediaTool, + ratingTool, + compareTool, + sessionTool, + discordTool, + moreTool, ]; diff --git a/src/hooks/useAdExempt.ts b/src/hooks/useAdExempt.ts index 77617de48..1aae3da9a 100644 --- a/src/hooks/useAdExempt.ts +++ b/src/hooks/useAdExempt.ts @@ -2,8 +2,6 @@ import { use } from 'react'; import { useApp } from '../stores/app'; export function useAdExempt() { - return true; - const patreon = useApp((state) => state.logins.patreon); if (!patreon) return false; From bcabb6585775c3f92a0b70125f665212b4fa86e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 15 Jun 2024 14:01:51 -0500 Subject: [PATCH 11/13] feat: homepage ads --- src/app/components/PatreonPlug.tsx | 13 +++--- src/app/page.tsx | 74 +++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/app/components/PatreonPlug.tsx b/src/app/components/PatreonPlug.tsx index e36c26639..c4b20b900 100644 --- a/src/app/components/PatreonPlug.tsx +++ b/src/app/components/PatreonPlug.tsx @@ -11,8 +11,6 @@ export function PatreonPlug() { const patreon = useApp((state) => state.logins.patreon); const exempt = useAdExempt(); - if (exempt) return null; - return ( - Active Patreon supports go ad-free + {exempt + ? 'You are supporting BlitzKit, thank you!' + : 'Active Patreon supports go ad-free'} - + {!exempt && } - {!patreon && ( + {!patreon && !exempt && ( diff --git a/src/app/page.tsx b/src/app/page.tsx index 86081fa11..e30978171 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -11,30 +11,56 @@ import { sessionTool, tankopediaTool, } from '../constants/tools'; +import { useAdExempt } from '../hooks/useAdExempt'; import { Hero } from './components/Hero'; import { PatreonPlug } from './components/PatreonPlug'; import { ToolCard } from './components/ToolCard'; export default function Page() { + const exempt = useAdExempt(); + return ( <> - - + + {!exempt && ( + + )} - + {!exempt && ( + + + + )} @@ -46,22 +72,36 @@ export default function Page() { + {!exempt && ( + + + + )} + - + {!exempt && ( + + )} - + {!exempt && }
From 4d462508bc15b062c3cac46dccbe27aa2c9891b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 15 Jun 2024 14:05:47 -0500 Subject: [PATCH 12/13] fix: swap window undef check --- src/components/Navbar/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 1e8f75d51..362c6cd78 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -217,11 +217,11 @@ export default function Navbar() {