@@ -13,3 +13,4 @@ export const INVITE_USER = 'invite-user'
export const INVITE_SECURITY_MODAL = 'invite-security'
export const LIMIT_MODAL = 'limit-modal'
export const LIMIT_SECURITY_MODAL = 'limit-security-modal'
+export const ERROR_MESSAGE = 'error-message'
@@ -28,6 +28,8 @@ export interface PlatesTemplateProps {
containerClassName?: string
paddingVariant?: PaddingVariant
blurToogle?: BlurToogle
+ hasCLoseButton?: boolean
+ hasCloseOnCLickOutside?: boolean
}
export default function PlatesTemplate({
@@ -45,6 +47,8 @@ export default function PlatesTemplate({
variant = 'primary',
paddingVariant = 'default',
blurToogle = 'off',
+ hasCLoseButton = true,
+ hasCloseOnCLickOutside = true,
}: PlatesTemplateProps) {
const { setModal, getModal } = usePlatesStore()
@@ -64,7 +68,7 @@ export default function PlatesTemplate({
containerClassName
)}
onClick={() => {
- if (hasBg) modal.setState(false)
+ if (hasBg && hasCloseOnCLickOutside) modal.setState(false)
}}
>
{hasTemplate ? (
@@ -77,20 +81,22 @@ export default function PlatesTemplate({
)}
onClick={(e) => e.stopPropagation()}
>
-
= 400 && resp.status < 500) {
+ throw new Error(
+ ERROR_MAPPING[(data as { detail: string }).detail] ??
+ JSON.stringify(data as Object)
+ .replace(/\s+/, '_')
+ .replace(/[А-Яа-я]/, '')
+ .toLowerCase()
+ )
+ }
+ return (await data) as User
+ },
+ }),
+ CredentialsProvider({
+ id: 'email_token',
+ type: 'credentials',
+ credentials: {},
+ async authorize(credentials, req) {
+ const { token } = credentials as { token: string }
+
+ const resp = await AuthProxy.loginByEmailToken(token)
+
+ const data = await resp.json()
+
+ if (resp.status >= 400 && resp.status < 500) {
+ throw new Error(
+ ERROR_MAPPING[(data as { detail: string }).detail] ??
+ JSON.stringify(data as Object)
+ .replace(/\s+/, '_')
+ .replace(/[А-Яа-я]/, '')
+ .toLowerCase()
+ )
+ }
+ return (await data) as User
+ },
+ }),
+ ],
+ callbacks: {
+ async jwt({ token, user, account, trigger }) {
+ if (account?.provider === 'yandex') {
+ const result = await AuthProxy.exchangeTokenYandex(account.access_token || '')
+
+ if (result.status >= 400 && result.status < 500) {
+ throw new Error('Непредвиденная ошибка')
+ }
+
+ const info = await getAll(
+ (result.data as { access_token: string }).access_token
+ )
+
+ return { ...info.token, tokenExpiry: AuthConstants.getExpiresDate() }
+ }
+
+ if (user) {
+ try {
+ token.access = user.token.access
+ token.refresh = user.token.refresh
+ token.tokenExpiry = AuthConstants.getExpiresDate()
+ return token
+ } catch (error) {
+ return { ...token, ...user }
+ }
+ }
+
+ const shouldRefreshTime = Math.round(Date.now() - token.tokenExpiry) >= 0
+
+ if (shouldRefreshTime) {
+ return await AuthProxy.refreshToken(token)
+ }
+
+ return token
+ },
+ signIn: async ({ user, account, ...props }) => {
+ if (account?.provider === 'yandex') {
+ const { data: result, status } = await AuthProxy.exchangeTokenYandex(
+ account.access_token!
+ )
+
+ if (status >= 400 && status < 500) {
+ return Promise.reject(
+ new Error(
+ ERROR_YANDEX_MAPPING[
+ (result as { error_description: string }).error_description
+ ]
+ )
+ )
+ }
+
+ return Promise.resolve(true)
+ }
+
+ return Promise.resolve(true)
+ },
+ async session({ session, token }) {
+ session.access = token.access
+ session.refresh = token.refresh
+ return session
+ },
+ },
+ pages: {
+ signIn: '/login',
+ error: '/login',
+ },
+}
+
+export default NextAuth(authOptions)
@@ -18,6 +18,7 @@ import { Error } from '#/shared'
import { pingFangFont } from '#/shared/lib/constants/font/font'
import { useBlockTelegram } from '#/shared/lib/hooks/use-block-telegram'
import { Providers } from '#/widgets/providers'
+import { ERROR_MESSAGE, getModalById } from '#/features/modals'
const inter = Raleway({ subsets: ['latin'] })
@@ -31,8 +32,17 @@ export interface AppPropsWithLayout extends AppProps {
}
function App({ Component, pageProps: { session, ...pageProps } }: AppPropsWithLayout) {
+ const modal = getModalById(ERROR_MESSAGE)
+ /* axios.interceptors.response.use(
+ (response) => response,
+ (error) => {
+ if (!error.response) {
+ modal.setState(true)
+ }
+ return error
+ }
+ ) */
useBlockTelegram()
-
const getLayout = Component.getLayout ?? ((page) => page)
return (
@@ -2,7 +2,7 @@ import axios, { AxiosResponse } from 'axios'
import { User } from 'next-auth'
import { API_URL } from '#/shared/lib/constants'
-import { IOffer } from '#/widgets/payment/model/payment'
+import { IOffer } from '#/widgets/payment/ui/payment'
interface IUserBalance {
current_token_balance: number
@@ -3,6 +3,7 @@ import { useRouter } from 'next/navigation'
import { api } from './instance'
import axios, { InternalAxiosRequestConfig } from 'axios'
import { useCallback } from 'react'
+import { ERROR_MESSAGE, getModalById } from '#/features/modals'
export function makePrivateRequest
(
callback: (...params: Params) => Promise
@@ -11,6 +12,8 @@ export function makePrivateRequest(
const { push } = useRouter()
+ const modal = getModalById(ERROR_MESSAGE)
+
const onRequest = async (config: any) => {
if (config.headers.Authorization) return config
@@ -26,6 +29,8 @@ export function makePrivateRequest(
api.interceptors.response.use(
async ({ status, ...r }) => {
+ if ([402, 403, 404].includes(status)) modal.setState(true)
+
if (![401].includes(status)) return { status, ...r }
const session = await update('refresh')
@@ -39,7 +44,7 @@ export function makePrivateRequest(
return { status, ...r }
},
(error) => {
- if (!error.respose) return (window.location.href = '/network-error')
+ if (!error.respose) return modal.setState(true)
}
)
@@ -1,4 +1,5 @@
import { c } from '#/shared/lib/helpers'
+import { forwardRef } from 'react'
import styles from './common-button.module.scss'
export type ButtonVariant = 'outline' | 'primary' | 'primary-outline' | 'gray'
@@ -8,25 +9,22 @@ export interface CommonButtonProps extends React.ButtonHTMLAttributes {
- return (
-
- )
-}
+export const CommonButton = forwardRef(
+ ({ children, variant = 'outline', className, disabled, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
@@ -31,11 +31,21 @@ export const InfoPageTemplate = ({
{secondaryTitle}
{description}