mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: migrated app store
This commit is contained in:
1 parent
5aa4b262f8
commit
cf841c9bb2
14 files changed
+156
-191
No files matched your search
@@ -4,7 +4,7 @@ import { Flex, Heading, Text } from '@radix-ui/themes';
|
|||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { mutateApp } from '../../../stores/app';
|
import * as App from '../../../stores/app';
|
||||||
|
|
||||||
export interface PatreonAuthResponse {
|
export interface PatreonAuthResponse {
|
||||||
access_token: string;
|
access_token: string;
|
||||||
@@ -23,6 +23,7 @@ export default function Page({
|
|||||||
searchParams: { [key: string]: string };
|
searchParams: { [key: string]: string };
|
||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const mutateApp = App.useMutation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (params.provider) {
|
switch (params.provider) {
|
||||||
|
|||||||
@@ -10,13 +10,21 @@ import {
|
|||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { extendAuthPatreon } from '../../core/blitz/extendAuthPatreon';
|
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
|
||||||
import { extendAuthWargaming } from '../../core/blitz/extendAuthWargaming';
|
import { idToRegion } from '../../core/blitz/idToRegion';
|
||||||
import { logoutPatreon } from '../../core/blitz/logoutPatreon';
|
|
||||||
import { logoutWargaming } from '../../core/blitz/logoutWargaming';
|
|
||||||
import isDev from '../../core/blitzkit/isDev';
|
import isDev from '../../core/blitzkit/isDev';
|
||||||
import { isLocalhost } from '../../core/blitzkit/isLocalhost';
|
import { isLocalhost } from '../../core/blitzkit/isLocalhost';
|
||||||
import { CURRENT_POLICIES_AGREEMENT_INDEX, useApp } from '../../stores/app';
|
import * as App from '../../stores/app';
|
||||||
|
import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants';
|
||||||
|
import { PatreonAuthResponse } from '../auth/[provider]/page';
|
||||||
|
|
||||||
|
interface Extension {
|
||||||
|
data: {
|
||||||
|
access_token: string;
|
||||||
|
account_id: number;
|
||||||
|
expires_at: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const DEV_BUILD_AGREEMENT_COOLDOWN = 8 * 24 * 60 * 60 * 1000;
|
const DEV_BUILD_AGREEMENT_COOLDOWN = 8 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@@ -27,8 +35,10 @@ const DEV_BUILD_AGREEMENT_COOLDOWN = 8 * 24 * 60 * 60 * 1000;
|
|||||||
|
|
||||||
export function Checks() {
|
export function Checks() {
|
||||||
const [showDevBuildAlert, setShowDevBuildAlert] = useState(false);
|
const [showDevBuildAlert, setShowDevBuildAlert] = useState(false);
|
||||||
const logins = useApp((state) => state.logins);
|
const mutateApp = App.useMutation();
|
||||||
const policiesAgreementIndex = useApp(
|
const logins = App.use((state) => state.logins);
|
||||||
|
const appStore = App.useStore();
|
||||||
|
const policiesAgreementIndex = App.use(
|
||||||
(state) => state.policiesAgreementIndex,
|
(state) => state.policiesAgreementIndex,
|
||||||
);
|
);
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
@@ -39,7 +49,7 @@ export function Checks() {
|
|||||||
setShowDevBuildAlert(
|
setShowDevBuildAlert(
|
||||||
isDev() &&
|
isDev() &&
|
||||||
!isLocalhost() &&
|
!isLocalhost() &&
|
||||||
Date.now() - useApp.getState().devBuildAgreementTime >=
|
Date.now() - appStore.getState().devBuildAgreementTime >=
|
||||||
DEV_BUILD_AGREEMENT_COOLDOWN,
|
DEV_BUILD_AGREEMENT_COOLDOWN,
|
||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -55,9 +65,31 @@ export function Checks() {
|
|||||||
const expiresInDays = expiresIn / 1000 / 60 / 60 / 24;
|
const expiresInDays = expiresIn / 1000 / 60 / 60 / 24;
|
||||||
|
|
||||||
if (expiresInDays < 0) {
|
if (expiresInDays < 0) {
|
||||||
logoutWargaming();
|
mutateApp((draft) => {
|
||||||
|
draft.logins.wargaming = undefined;
|
||||||
|
});
|
||||||
} else if (expiresInDays < 7) {
|
} else if (expiresInDays < 7) {
|
||||||
extendAuthWargaming();
|
const { wargaming } = appStore.getState().logins;
|
||||||
|
|
||||||
|
if (!wargaming) return;
|
||||||
|
|
||||||
|
fetch(
|
||||||
|
`https://api.worldoftanks.${idToRegion(
|
||||||
|
wargaming.id,
|
||||||
|
)}/wot/auth/prolongate/?application_id=${WARGAMING_APPLICATION_ID}&access_token=${
|
||||||
|
wargaming.token
|
||||||
|
}`,
|
||||||
|
)
|
||||||
|
.then((response) => response.json() as Promise<Extension>)
|
||||||
|
.then((json) => {
|
||||||
|
mutateApp((draft) => {
|
||||||
|
draft.logins.wargaming = {
|
||||||
|
id: wargaming.id,
|
||||||
|
token: json.data.access_token,
|
||||||
|
expires: json.data.expires_at * 1000,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,9 +98,25 @@ export function Checks() {
|
|||||||
const expiresInDays = expiresIn / 1000 / 60 / 60 / 24;
|
const expiresInDays = expiresIn / 1000 / 60 / 60 / 24;
|
||||||
|
|
||||||
if (expiresInDays < 0) {
|
if (expiresInDays < 0) {
|
||||||
logoutPatreon();
|
mutateApp((draft) => {
|
||||||
|
draft.logins.patreon = undefined;
|
||||||
|
});
|
||||||
} else if (expiresInDays < 15) {
|
} else if (expiresInDays < 15) {
|
||||||
extendAuthPatreon();
|
const { patreon } = appStore.getState().logins;
|
||||||
|
|
||||||
|
if (!patreon) return;
|
||||||
|
|
||||||
|
fetch(`/api/patreon/refresh/${patreon.refreshToken}`)
|
||||||
|
.then((response) => response.json() as Promise<PatreonAuthResponse>)
|
||||||
|
.then((data) => {
|
||||||
|
mutateApp((draft) => {
|
||||||
|
draft.logins.patreon = {
|
||||||
|
token: data.access_token,
|
||||||
|
refreshToken: data.refresh_token,
|
||||||
|
expires: Date.now() + data.expires_in * 1000,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -93,7 +141,7 @@ export function Checks() {
|
|||||||
variant="solid"
|
variant="solid"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowDevBuildAlert(false);
|
setShowDevBuildAlert(false);
|
||||||
useApp.setState({ devBuildAgreementTime: Date.now() });
|
appStore.setState({ devBuildAgreementTime: Date.now() });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Continue
|
Continue
|
||||||
@@ -158,7 +206,7 @@ export function Checks() {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
useApp.setState({
|
appStore.setState({
|
||||||
policiesAgreementIndex: CURRENT_POLICIES_AGREEMENT_INDEX,
|
policiesAgreementIndex: CURRENT_POLICIES_AGREEMENT_INDEX,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { Button, Flex, Link, Text } from '@radix-ui/themes';
|
|||||||
import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl';
|
import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl';
|
||||||
import { useAdExempt } from '../../hooks/useAdExempt';
|
import { useAdExempt } from '../../hooks/useAdExempt';
|
||||||
import { PatreonIcon } from '../../icons/Patreon';
|
import { PatreonIcon } from '../../icons/Patreon';
|
||||||
import { useApp } from '../../stores/app';
|
import * as App from '../../stores/app';
|
||||||
|
|
||||||
export function PatreonPlug() {
|
export function PatreonPlug() {
|
||||||
const patreon = useApp((state) => state.logins.patreon);
|
const patreon = App.use((state) => state.logins.patreon);
|
||||||
const exempt = useAdExempt();
|
const exempt = useAdExempt();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+54
-51
@@ -10,6 +10,7 @@ import { Footer } from '../components/Footer';
|
|||||||
import { Loader } from '../components/Loader';
|
import { Loader } from '../components/Loader';
|
||||||
import Navbar, { NAVBAR_HEIGHT } from '../components/Navbar';
|
import Navbar, { NAVBAR_HEIGHT } from '../components/Navbar';
|
||||||
import { Party3 } from '../components/Party3';
|
import { Party3 } from '../components/Party3';
|
||||||
|
import * as App from '../stores/app';
|
||||||
import { Checks } from './components/Checks';
|
import { Checks } from './components/Checks';
|
||||||
import './layout.css';
|
import './layout.css';
|
||||||
|
|
||||||
@@ -31,62 +32,64 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
|||||||
const isRoot = pathname === '/';
|
const isRoot = pathname === '/';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" className={robotoFlex.className}>
|
<App.Provider>
|
||||||
<head>
|
<html lang="en" className={robotoFlex.className}>
|
||||||
{isRoot && (
|
<head>
|
||||||
<>
|
{isRoot && (
|
||||||
<title>BlitzKit</title>
|
<>
|
||||||
<meta
|
<title>BlitzKit</title>
|
||||||
name="description"
|
<meta
|
||||||
content="🎉 Tools for everything World of Tanks Blitz"
|
name="description"
|
||||||
/>
|
content="🎉 Tools for everything World of Tanks Blitz"
|
||||||
</>
|
/>
|
||||||
)}
|
</>
|
||||||
<meta property="og:site_name" content="BlitzKit" />
|
)}
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
<meta property="og:site_name" content="BlitzKit" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
|
||||||
<Party3 />
|
<Party3 />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
style={{
|
style={{
|
||||||
margin: 0,
|
margin: 0,
|
||||||
backgroundColor: isEmbed ? 'transparent' : undefined,
|
backgroundColor: isEmbed ? 'transparent' : undefined,
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<Theme
|
|
||||||
appearance="dark"
|
|
||||||
panelBackground="solid"
|
|
||||||
radius="full"
|
|
||||||
accentColor="amber"
|
|
||||||
suppressHydrationWarning
|
|
||||||
suppressContentEditableWarning
|
|
||||||
>
|
>
|
||||||
<Flex
|
<Theme
|
||||||
direction="column"
|
appearance="dark"
|
||||||
style={{
|
panelBackground="solid"
|
||||||
minHeight: '100vh',
|
radius="full"
|
||||||
paddingTop: isEmbed ? undefined : NAVBAR_HEIGHT,
|
accentColor="amber"
|
||||||
}}
|
suppressHydrationWarning
|
||||||
|
suppressContentEditableWarning
|
||||||
>
|
>
|
||||||
{!isEmbed && <Navbar />}
|
<Flex
|
||||||
|
direction="column"
|
||||||
<Checks />
|
style={{
|
||||||
|
minHeight: '100vh',
|
||||||
<Suspense
|
paddingTop: isEmbed ? undefined : NAVBAR_HEIGHT,
|
||||||
fallback={
|
}}
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{children}
|
{!isEmbed && <Navbar />}
|
||||||
</Suspense>
|
|
||||||
|
|
||||||
{!isEmbed && <Footer />}
|
<Checks />
|
||||||
</Flex>
|
|
||||||
</Theme>
|
<Suspense
|
||||||
</body>
|
fallback={
|
||||||
</html>
|
<div style={{ flex: 1 }}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
|
{!isEmbed && <Footer />}
|
||||||
|
</Flex>
|
||||||
|
</Theme>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</App.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
import { Flex, Heading, Switch, Text } from '@radix-ui/themes';
|
import { Flex, Heading, Switch, Text } from '@radix-ui/themes';
|
||||||
import PageWrapper from '../../components/PageWrapper';
|
import PageWrapper from '../../components/PageWrapper';
|
||||||
import { useApp } from '../../stores/app';
|
import * as App from '../../stores/app';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const developerMode = useApp((state) => state.developerMode);
|
const developerMode = App.use((state) => state.developerMode);
|
||||||
|
const appStore = App.useStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper justify="center" align="center">
|
<PageWrapper justify="center" align="center">
|
||||||
@@ -18,7 +19,7 @@ export default function Page() {
|
|||||||
<Switch
|
<Switch
|
||||||
checked={developerMode}
|
checked={developerMode}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
useApp.setState({ developerMode: checked })
|
appStore.setState({ developerMode: checked })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
} from '../../../../../../../core/blitzkit/tankDefinitions/constants';
|
} from '../../../../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { useEquipment } from '../../../../../../../hooks/useEquipment';
|
import { useEquipment } from '../../../../../../../hooks/useEquipment';
|
||||||
import { useFullScreen } from '../../../../../../../hooks/useFullScreen';
|
import { useFullScreen } from '../../../../../../../hooks/useFullScreen';
|
||||||
import { useApp } from '../../../../../../../stores/app';
|
import * as App from '../../../../../../../stores/app';
|
||||||
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
||||||
import * as TankopediaPersistent from '../../../../../../../stores/tankopediaPersistent';
|
import * as TankopediaPersistent from '../../../../../../../stores/tankopediaPersistent';
|
||||||
@@ -65,7 +65,7 @@ export function Options() {
|
|||||||
const environment = TankopediaPersistent.use(
|
const environment = TankopediaPersistent.use(
|
||||||
(state) => state.model.visual.environment,
|
(state) => state.model.visual.environment,
|
||||||
);
|
);
|
||||||
const developerMode = useApp((state) => state.developerMode);
|
const developerMode = App.use((state) => state.developerMode);
|
||||||
const antagonistGun = useDuel((state) => state.antagonist!.gun);
|
const antagonistGun = useDuel((state) => state.antagonist!.gun);
|
||||||
const antagonistShell = useDuel((state) => state.antagonist!.shell);
|
const antagonistShell = useDuel((state) => state.antagonist!.shell);
|
||||||
const [antagonistSelectorOpen, setAntagonistSelectorOpen] = useState(false);
|
const [antagonistSelectorOpen, setAntagonistSelectorOpen] = useState(false);
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import { useState } from 'react';
|
|||||||
import { REGIONS } from '../../constants/regions';
|
import { REGIONS } from '../../constants/regions';
|
||||||
import { TOOLS } from '../../constants/tools';
|
import { TOOLS } from '../../constants/tools';
|
||||||
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
|
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
|
||||||
import { logoutPatreon } from '../../core/blitz/logoutPatreon';
|
|
||||||
import { logoutWargaming } from '../../core/blitz/logoutWargaming';
|
|
||||||
import { imgur, ImgurSize } from '../../core/blitzkit/imgur';
|
import { imgur, ImgurSize } from '../../core/blitzkit/imgur';
|
||||||
import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl';
|
import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl';
|
||||||
import { BlitzkitWide } from '../../icons/BlitzkitWide';
|
import { BlitzkitWide } from '../../icons/BlitzkitWide';
|
||||||
@@ -32,7 +30,7 @@ import { PatreonIcon } from '../../icons/Patreon';
|
|||||||
import { WargamingIcon } from '../../icons/Wargaming';
|
import { WargamingIcon } from '../../icons/Wargaming';
|
||||||
import strings from '../../lang/en-US.json';
|
import strings from '../../lang/en-US.json';
|
||||||
import { theme } from '../../stitches.config';
|
import { theme } from '../../stitches.config';
|
||||||
import { useApp } from '../../stores/app';
|
import * as App from '../../stores/app';
|
||||||
import { Link } from '../Link';
|
import { Link } from '../Link';
|
||||||
import * as styles from './index.css';
|
import * as styles from './index.css';
|
||||||
|
|
||||||
@@ -41,8 +39,9 @@ export const NAVBAR_HEIGHT = 64;
|
|||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
const [showHamburgerMenu, setShowHamburgerMenu] = useState(false);
|
const [showHamburgerMenu, setShowHamburgerMenu] = useState(false);
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const logins = useApp((state) => state.logins);
|
const logins = App.use((state) => state.logins);
|
||||||
const filteredTools = TOOLS.filter((tool) => !tool.href);
|
const filteredTools = TOOLS.filter((tool) => !tool.href);
|
||||||
|
const mutateApp = App.useMutation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -162,7 +161,11 @@ export default function Navbar() {
|
|||||||
<Button
|
<Button
|
||||||
color="red"
|
color="red"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={logoutPatreon}
|
onClick={() =>
|
||||||
|
mutateApp((draft) => {
|
||||||
|
draft.logins.patreon = undefined;
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Logout
|
Logout
|
||||||
</Button>
|
</Button>
|
||||||
@@ -176,7 +179,11 @@ export default function Navbar() {
|
|||||||
<Button
|
<Button
|
||||||
color="red"
|
color="red"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={logoutWargaming}
|
onClick={() =>
|
||||||
|
mutateApp((draft) => {
|
||||||
|
draft.logins.wargaming = undefined;
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Logout
|
Logout
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
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/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,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
|
|
||||||
import { mutateApp, useApp } from '../../stores/app';
|
|
||||||
import { idToRegion } from './idToRegion';
|
|
||||||
|
|
||||||
interface Extension {
|
|
||||||
data: {
|
|
||||||
access_token: string;
|
|
||||||
account_id: number;
|
|
||||||
expires_at: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function extendAuthWargaming() {
|
|
||||||
const { wargaming } = useApp.getState().logins;
|
|
||||||
|
|
||||||
if (!wargaming) return;
|
|
||||||
|
|
||||||
// error handling? what's that?
|
|
||||||
/*
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠙⠛⠛⠛⠿⠻⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⡀⠠⠤⠒⢂⣉⣉⣉⣑⣒⣒⠒⠒⠒⠒⠒⠒⠒⠀⠀⠐⠒⠚⠻⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⡠⠔⠉⣀⠔⠒⠉⣀⣀⠀⠀⠀⣀⡀⠈⠉⠑⠒⠒⠒⠒⠒⠈⠉⠉⠉⠁⠂⠀⠈⠙⢿⣿⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠔⠁⠠⠖⠡⠔⠊⠀⠀⠀⠀⠀⠀⠀⠐⡄⠀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠉⠲⢄⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠊⠀⢀⣀⣤⣤⣤⣤⣀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠜⠀⠀⠀⠀⣀⡀⠀⠈⠃⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⡿⠥⠐⠂⠀⠀⠀⠀⡄⠀⠰⢺⣿⣿⣿⣿⣿⣟⠀⠈⠐⢤⠀⠀⠀⠀⠀⠀⢀⣠⣶⣾⣯⠀⠀⠉⠂⠀⠠⠤⢄⣀⠙⢿⣿⣿⣿⣿
|
|
||||||
⣿⡿⠋⠡⠐⠈⣉⠭⠤⠤⢄⡀⠈⠀⠈⠁⠉⠁⡠⠀⠀⠀⠉⠐⠠⠔⠀⠀⠀⠀⠀⠲⣿⠿⠛⠛⠓⠒⠂⠀⠀⠀⠀⠀⠀⠠⡉⢢⠙⣿⣿⣿
|
|
||||||
⣿⠀⢀⠁⠀⠊⠀⠀⠀⠀⠀⠈⠁⠒⠂⠀⠒⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢀⣀⡠⠔⠒⠒⠂⠀⠈⠀⡇⣿⣿⣿⣿⣿
|
|
||||||
⣿⠀⢸⠀⠀⠀⢀⣀⡠⠋⠓⠤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠈⠢⠤⡀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⡠⠀⡇⣿⣿⣿⣿⣿
|
|
||||||
⣿⡀⠘⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠈⠑⡦⢄⣀⠀⠀⠐⠒⠁⢸⠀⠀⠠⠒⠄⠀⠀⠀⠀⠀⢀⠇⠀⣀⡀⠀⠀⢀⢾⡆⠀⠈⡀⠎⣸⣿⣿⣿
|
|
||||||
⣿⣿⣄⡈⠢⠀⠀⠀⠀⠘⣶⣄⡀⠀⠀⡇⠀⠀⠈⠉⠒⠢⡤⣀⡀⠀⠀⠀⠀⠀⠐⠦⠤⠒⠁⠀⠀⠀⠀⣀⢴⠁⠀⢷⠀⠀⠀⢰⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣇⠂⠀⠀⠀⠀⠈⢂⠀⠈⠹⡧⣀⠀⠀⠀⠀⠀⡇⠀⠀⠉⠉⠉⢱⠒⠒⠒⠒⢖⠒⠒⠂⠙⠏⠀⠘⡀⠀⢸⠀⠀⠀⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠑⠄⠰⠀⠀⠁⠐⠲⣤⣴⣄⡀⠀⠀⠀⠀⢸⠀⠀⠀⠀⢸⠀⠀⠀⠀⢠⠀⣠⣷⣶⣿⠀⠀⢰⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠁⢀⠀⠀⠀⠀⠀⡙⠋⠙⠓⠲⢤⣤⣷⣤⣤⣤⣤⣾⣦⣤⣤⣶⣿⣿⣿⣿⡟⢹⠀⠀⢸⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠑⠀⢄⠀⡰⠁⠀⠀⠀⠀⠀⠈⠉⠁⠈⠉⠻⠋⠉⠛⢛⠉⠉⢹⠁⢀⢇⠎⠀⠀⢸⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣀⠈⠢⢄⡉⠂⠄⡀⠀⠈⠒⠢⠄⠀⢀⣀⣀⣰⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⢀⣎⠀⠼⠊⠀⠀⠀⠘⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⡀⠉⠢⢄⡈⠑⠢⢄⡀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⢀⠀⠀⠀⠀⠀⢻⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣀⡈⠑⠢⢄⡀⠈⠑⠒⠤⠄⣀⣀⠀⠉⠉⠉⠉⠀⠀⠀⣀⡀⠤⠂⠁⠀⢀⠆⠀⠀⢸⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⡀⠁⠉⠒⠂⠤⠤⣀⣀⣉⡉⠉⠉⠉⠉⢀⣀⣀⡠⠤⠒⠈⠀⠀⠀⠀⣸⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿
|
|
||||||
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣶⣶⣤⣤⣤⣤⣀⣀⣤⣤⣤⣶⣾⣿⣿⣿⣿⣿
|
|
||||||
*/
|
|
||||||
|
|
||||||
const response = await fetch(
|
|
||||||
`https://api.worldoftanks.${idToRegion(
|
|
||||||
wargaming.id,
|
|
||||||
)}/wot/auth/prolongate/?application_id=${WARGAMING_APPLICATION_ID}&access_token=${
|
|
||||||
wargaming.token
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
const json = (await response.json()) as Extension;
|
|
||||||
|
|
||||||
mutateApp((draft) => {
|
|
||||||
draft.logins.wargaming = {
|
|
||||||
id: wargaming.id,
|
|
||||||
token: json.data.access_token,
|
|
||||||
expires: json.data.expires_at * 1000,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { mutateApp } from '../../stores/app';
|
|
||||||
|
|
||||||
export function logoutPatreon() {
|
|
||||||
mutateApp((draft) => {
|
|
||||||
draft.logins.patreon = undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { mutateApp } from '../../stores/app';
|
|
||||||
|
|
||||||
export function logoutWargaming() {
|
|
||||||
mutateApp((draft) => {
|
|
||||||
draft.logins.wargaming = undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { use, useMemo } from 'react';
|
import { use, useMemo } from 'react';
|
||||||
import { useApp } from '../stores/app';
|
import * as App from '../stores/app';
|
||||||
|
|
||||||
let cache: Record<string, boolean> = {};
|
let cache: Record<string, boolean> = {};
|
||||||
|
|
||||||
export function useAdExempt() {
|
export function useAdExempt() {
|
||||||
const patreon = useApp((state) => state.logins.patreon);
|
const patreon = App.use((state) => state.logins.patreon);
|
||||||
const promise = useMemo(
|
const promise = useMemo(
|
||||||
() =>
|
() =>
|
||||||
new Promise<boolean>(async (resolve) => {
|
new Promise<boolean>(async (resolve) => {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export const CURRENT_POLICIES_AGREEMENT_INDEX = 0;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { produce } from 'immer';
|
|
||||||
import { merge } from 'lodash';
|
import { merge } from 'lodash';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
|
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
|
||||||
|
|
||||||
interface WargamingLogin {
|
interface WargamingLogin {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -25,20 +25,17 @@ export interface App {
|
|||||||
policiesAgreementIndex: number;
|
policiesAgreementIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CURRENT_POLICIES_AGREEMENT_INDEX = 0;
|
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
|
||||||
|
() =>
|
||||||
export const useApp = create<App>()(
|
create<App>()(
|
||||||
persist(
|
persist(
|
||||||
(set) => ({
|
(set) => ({
|
||||||
devBuildAgreementTime: 0,
|
devBuildAgreementTime: 0,
|
||||||
developerMode: false,
|
developerMode: false,
|
||||||
policiesAgreementIndex: -1,
|
policiesAgreementIndex: -1,
|
||||||
logins: {},
|
logins: {},
|
||||||
}),
|
}),
|
||||||
{ name: 'app', merge: (a, b) => merge(b, a) },
|
{ name: 'app', merge: (a, b) => merge(b, a) },
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
export function mutateApp(recipe: (draft: App) => void) {
|
|
||||||
useApp.setState(produce(recipe));
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user