F
This commit is contained in:
@@ -6,17 +6,28 @@ interface CsrfResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cachedToken: string | null = null
|
let cachedToken: string | null = null
|
||||||
|
let inflight: Promise<string> | null = null
|
||||||
|
|
||||||
export function clearCsrfCache(): void {
|
export function clearCsrfCache(): void {
|
||||||
cachedToken = null
|
cachedToken = null
|
||||||
|
inflight = null
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCsrfToken(): Promise<string> {
|
export function getCsrfToken(): Promise<string> {
|
||||||
if (cachedToken) return cachedToken
|
if (cachedToken) return Promise.resolve(cachedToken)
|
||||||
const res = await fetch(`${API_URL}/csrf/token`, {
|
if (inflight) return inflight
|
||||||
credentials: 'include',
|
|
||||||
})
|
inflight = fetch(`${API_URL}/csrf/token`, { credentials: 'include' })
|
||||||
const data: CsrfResponse = await res.json()
|
.then((res) => res.json() as Promise<CsrfResponse>)
|
||||||
cachedToken = data.token
|
.then((data) => {
|
||||||
return cachedToken
|
cachedToken = data.token
|
||||||
|
inflight = null
|
||||||
|
return cachedToken
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
inflight = null
|
||||||
|
throw err
|
||||||
|
})
|
||||||
|
|
||||||
|
return inflight
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export const COUNTDOWN_DAYS = 3
|
export const COUNTDOWN_TARGET = new Date('2026-05-21T00:00:00').getTime()
|
||||||
export const USDT_RATE = 80.00
|
export const USDT_RATE = 80.00
|
||||||
export const GAS_PRICE = 21.00
|
export const GAS_PRICE = 21.00
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ import logo from '@shared/assets/logo-full-white.png'
|
|||||||
import styles from './Header.module.css'
|
import styles from './Header.module.css'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { ROUTES } from '@shared/config/routes'
|
import { ROUTES } from '@shared/config/routes'
|
||||||
import { useIsAuthenticated } from '@features/auth'
|
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const isAuthenticated = useIsAuthenticated()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.nav}>
|
||||||
<a className={styles.logo} href="/">
|
<a className={styles.logo} href="/">
|
||||||
@@ -16,7 +13,7 @@ export function Header() {
|
|||||||
<a className={styles.link} href="#about">
|
<a className={styles.link} href="#about">
|
||||||
О нас
|
О нас
|
||||||
</a>
|
</a>
|
||||||
<Link className={styles.btn} to={isAuthenticated ? ROUTES.WALLET : ROUTES.LOGIN}>
|
<Link className={styles.btn} to={ROUTES.WALLET}>
|
||||||
Личный кабинет
|
Личный кабинет
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
const STORAGE_KEY = 'eksa_countdown_target'
|
|
||||||
|
|
||||||
export interface CountdownValue {
|
export interface CountdownValue {
|
||||||
d: string
|
d: string
|
||||||
h: string
|
h: string
|
||||||
@@ -9,15 +7,7 @@ export interface CountdownValue {
|
|||||||
s: string
|
s: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCountdown(days: number): CountdownValue {
|
export function useCountdown(target: number): CountdownValue {
|
||||||
const [target] = useState<number>(() => {
|
|
||||||
const saved = localStorage.getItem(STORAGE_KEY)
|
|
||||||
if (saved) return Number.parseInt(saved, 10)
|
|
||||||
const t = Date.now() + days * 86_400_000
|
|
||||||
localStorage.setItem(STORAGE_KEY, String(t))
|
|
||||||
return t
|
|
||||||
})
|
|
||||||
|
|
||||||
const [now, setNow] = useState<number>(Date.now())
|
const [now, setNow] = useState<number>(Date.now())
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ const UNITS: Array<['d' | 'h' | 'm' | 's', string]> = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
days: number
|
target: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Countdown({ days }: Props) {
|
export function Countdown({ target }: Props) {
|
||||||
const cd = useCountdown(days)
|
const cd = useCountdown(target)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { COUNTDOWN_DAYS } from '@shared/config/constants'
|
import { COUNTDOWN_TARGET } from '@shared/config/constants'
|
||||||
import { ConversionFlow } from './ConversionFlow'
|
import { ConversionFlow } from './ConversionFlow'
|
||||||
import { Countdown } from './Countdown'
|
import { Countdown } from './Countdown'
|
||||||
import { ExchangeCard } from './ExchangeCard'
|
import { ExchangeCard } from './ExchangeCard'
|
||||||
@@ -31,7 +31,7 @@ export function Hero() {
|
|||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div>
|
<div>
|
||||||
<Countdown days={COUNTDOWN_DAYS} />
|
<Countdown target={COUNTDOWN_TARGET} />
|
||||||
<a href="#converter" className={styles.cta}>
|
<a href="#converter" className={styles.cta}>
|
||||||
Попробовать калькулятор
|
Попробовать калькулятор
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user