Browse Source

FEATURE | show blocked ip message

merge-requests/42/head
andrew_bashliy 3 years ago
parent
commit
c1cd9bebb6
  1. 8
      .eslintrc.js
  2. 28
      android/.project
  3. 34
      android/app/.project
  4. 4
      ios/Podfile.lock
  5. 8
      src/api/http.service.ts
  6. 32
      src/modules/auth/hooks/use-authorization.hook.ts
  7. 4
      src/modules/auth/screens/confirm-code.screen.tsx
  8. 12
      src/modules/auth/screens/sign-in.screen.tsx
  9. 10
      src/services/domain/auth.service.ts
  10. 2
      src/shared/components/layouts/auth-layout.component.tsx
  11. 1
      src/shared/enums/exception-keys.enum.ts
  12. 2
      src/shared/helpers/exceptions.helpers.ts
  13. 10
      src/store/shared/reducer.ts
  14. 4
      src/store/shared/selectors.ts
  15. 12
      src/store/shared/types.ts

8
.eslintrc.js

@ -1,5 +1,9 @@
module.exports = { module.exports = {
root: true, root: true,
extends: '@react-native-community', extends: '@react-native-community',
rules: {}, rules: {
}; semi: 0,
curly: 0,
'no-shadow': 'off',
},
}

28
android/.project

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>taskme</name>
<comment>Project android created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1630909588189</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

34
android/app/.project

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1630909588124</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

4
ios/Podfile.lock

@ -500,7 +500,7 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b
FBReactNativeSpec: 09a9b45481cf51e2fc98dd8dc8432607e43e1c52 FBReactNativeSpec: f92e05dd7f112a9a27a69b51545ca9e9c74439ff
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021 Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c
@ -549,4 +549,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 10a43cb7dc544fdabb001116ec92f9d67b11e153 PODFILE CHECKSUM: 10a43cb7dc544fdabb001116ec92f9d67b11e153
COCOAPODS: 1.10.2 COCOAPODS: 1.10.1

8
src/api/http.service.ts

@ -4,6 +4,8 @@ import { config } from '@/config'
import { GlobalContainerService } from '@/services/system' import { GlobalContainerService } from '@/services/system'
import Storage from 'react-native-expire-storage' import Storage from 'react-native-expire-storage'
import { AuthService } from '@/services/domain' import { AuthService } from '@/services/domain'
import { SetIsForbidden } from '@/store/shared'
import { simpleDispatch } from '@/store/store-helpers'
const store = () => GlobalContainerService.get('store') const store = () => GlobalContainerService.get('store')
@ -40,10 +42,14 @@ const request = async <T>(func: Function): Promise<AxiosResponse<T>> => {
let response = await func() let response = await func()
return response as any as AxiosResponse return response as any as AxiosResponse
} catch (e: any) { } catch (e: any) {
if (e.response.status === 401) { console.log('CAUGHT IN REQ', e.response?.data.statusCode)
if (e.response?.data?.statusCode === 401) {
await AuthService.refreshSession() await AuthService.refreshSession()
return (await func()) as any as AxiosResponse return (await func()) as any as AxiosResponse
} }
if (e.response?.data?.statusCode === 403) {
simpleDispatch(new SetIsForbidden({ isForbidden: true }))
}
throw e throw e
} }
} }

32
src/modules/auth/hooks/use-authorization.hook.ts

@ -1,12 +1,24 @@
import { AuthService } from '@/services/domain' import { AuthService } from '@/services/domain'
import { useState } from 'react' import { ExceptionKeys, getMessageByExceptionKey } from '@/shared'
import { selectIsForbidden } from '@/store/shared'
import { useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
export const useAuthorization = () => { export const useAuthorization = () => {
const [isSent, setIsSent] = useState(false) const [isSent, setIsSent] = useState(false)
const [isConfirmed, setIsConfirmed] = useState(false) const [isConfirmed, setIsConfirmed] = useState(false)
const [error, setError] = useState<any>(null) const [error, setError] = useState<string>(null)
const isForbidden = useSelector(selectIsForbidden)
const clearError = () => setError(false) const clearError = () => setError(null)
const setFirbiddenError = () => {
setError(getMessageByExceptionKey(ExceptionKeys.Forbidden))
}
useEffect(() => {
if (isForbidden) setFirbiddenError()
}, [isForbidden])
const sendCode = async (phoneNumber: string) => { const sendCode = async (phoneNumber: string) => {
try { try {
@ -15,7 +27,13 @@ export const useAuthorization = () => {
setIsSent(true) setIsSent(true)
clearError() clearError()
} catch (e: any) { } catch (e: any) {
setError(e.response?.data) console.log('ERROR', e.message)
if (e.response?.data.statusCode === 403) {
setFirbiddenError()
return
}
setError(getMessageByExceptionKey(e.response?.data?.key))
} }
} }
@ -25,7 +43,11 @@ export const useAuthorization = () => {
setIsConfirmed(true) setIsConfirmed(true)
clearError() clearError()
} catch (e: any) { } catch (e: any) {
setError(e.response?.data) if (e.response?.data.statusCode === 403) {
setFirbiddenError()
return
}
setError(getMessageByExceptionKey(e.response?.data?.key))
} }
} }

4
src/modules/auth/screens/confirm-code.screen.tsx

@ -3,7 +3,6 @@ import {
$size, $size,
AuthLayout, AuthLayout,
Button, Button,
getMessageByExceptionKey,
getTheme, getTheme,
ImageComponent, ImageComponent,
NavigationModuleKey, NavigationModuleKey,
@ -79,13 +78,14 @@ export const ConfirmCode = () => {
name: 'lock-1', name: 'lock-1',
color: getTheme().iconComponent.$primaryColor, color: getTheme().iconComponent.$primaryColor,
}} }}
error={getMessageByExceptionKey(error?.key)} error={error}
/> />
<Button <Button
title="Підтвердити" title="Підтвердити"
onPress={() => { onPress={() => {
confirmLogin(confirmCode) confirmLogin(confirmCode)
}} }}
style={{ marginBottom: 80 }}
/> />
</View> </View>
</View> </View>

12
src/modules/auth/screens/sign-in.screen.tsx

@ -4,13 +4,7 @@ import { StyleSheet, Text, View } from 'react-native'
import { AuthLayout, Button } from '$components' import { AuthLayout, Button } from '$components'
import { ImageComponent } from '../../../shared/components/elements/image.component' import { ImageComponent } from '../../../shared/components/elements/image.component'
import { FormPhone } from '../../../shared/components/forms/form-phone.component' import { FormPhone } from '../../../shared/components/forms/form-phone.component'
import { import { $size, getTheme, IRouteParams, RouteKey } from '@/shared'
$size,
getMessageByExceptionKey,
getTheme,
IRouteParams,
RouteKey,
} from '@/shared'
import { useAuthorization } from '../hooks' import { useAuthorization } from '../hooks'
interface IProps extends IRouteParams {} interface IProps extends IRouteParams {}
@ -21,7 +15,7 @@ export const SignInScreen = ({ navigation }: IProps) => {
useEffect(() => { useEffect(() => {
if (isSent) navigation.navigate(RouteKey.ConfirmCode) if (isSent) navigation.navigate(RouteKey.ConfirmCode)
}, [isSent]) }, [isSent, navigation])
return ( return (
<AuthLayout> <AuthLayout>
@ -41,7 +35,7 @@ export const SignInScreen = ({ navigation }: IProps) => {
name={'phoneNumber'} name={'phoneNumber'}
onChange={v => setPhoneNumber(v)} onChange={v => setPhoneNumber(v)}
value={phoneNumber} value={phoneNumber}
error={getMessageByExceptionKey(error?.key)} error={error}
/> />
<Button <Button
title="Підтвердити" title="Підтвердити"

10
src/services/domain/auth.service.ts

@ -2,9 +2,9 @@ import { Platform } from 'react-native'
import { requestConfirmationCode, finishLogin, sendRefreshToken } from '@/api' import { requestConfirmationCode, finishLogin, sendRefreshToken } from '@/api'
import { SaveTokens } from '@/store/auth' import { SaveTokens } from '@/store/auth'
import { simpleDispatch } from '@/store/store-helpers' import { simpleDispatch } from '@/store/store-helpers'
import { NavigationService, NetworkService, StorageService } from '../system' import { NavigationService, StorageService } from '../system'
import { ITokenPair, NavigationModuleKey, StorageKey } from '@/shared' import { ITokenPair, NavigationModuleKey, StorageKey } from '@/shared'
import { AccountService } from '.' import { AccountService } from './account.service'
let phoneNumber: string let phoneNumber: string
@ -41,10 +41,16 @@ const autoAuth = async () => {
} catch (e) { } catch (e) {
console.log('ACCOUNT LOADING ERROR', e) console.log('ACCOUNT LOADING ERROR', e)
await dropTokens()
NavigationService.setModule(NavigationModuleKey.Auth) NavigationService.setModule(NavigationModuleKey.Auth)
} }
} }
const dropTokens = async () => {
await StorageService.set(StorageKey.AccessToken, '')
await StorageService.set(StorageKey.RefreshToken, '')
}
const refreshSession = async (refreshToken?: string) => { const refreshSession = async (refreshToken?: string) => {
let token = refreshToken let token = refreshToken
if (!token) { if (!token) {

2
src/shared/components/layouts/auth-layout.component.tsx

@ -8,7 +8,7 @@ interface IProps {
export const AuthLayout = (props: IProps) => { export const AuthLayout = (props: IProps) => {
return ( return (
<ScreenLayout needScroll={false}> <ScreenLayout needScroll={true}>
<View style={styles.wrapper}>{props.children}</View> <View style={styles.wrapper}>{props.children}</View>
</ScreenLayout> </ScreenLayout>
) )

1
src/shared/enums/exception-keys.enum.ts

@ -3,4 +3,5 @@ export enum ExceptionKeys {
InvalidCredentials = 'invalid_credentials', InvalidCredentials = 'invalid_credentials',
WrongCode = 'wrong_code', WrongCode = 'wrong_code',
NotFound = 'not_found', NotFound = 'not_found',
Forbidden = 'forbidden_resource',
} }

2
src/shared/helpers/exceptions.helpers.ts

@ -3,6 +3,8 @@ import { ExceptionKeys } from '../enums'
const exceptionsDictionary = { const exceptionsDictionary = {
[ExceptionKeys.WrongCode]: 'Неправильний код', [ExceptionKeys.WrongCode]: 'Неправильний код',
[ExceptionKeys.InvalidCredentials]: 'Невірно введено дані', [ExceptionKeys.InvalidCredentials]: 'Невірно введено дані',
[ExceptionKeys.Forbidden]:
'Вашу IP-адресу заблоковано. Для розблокування зверніться до адміністратора',
} }
export const getMessageByExceptionKey = (key: ExceptionKeys) => { export const getMessageByExceptionKey = (key: ExceptionKeys) => {

10
src/store/shared/reducer.ts

@ -4,10 +4,12 @@ import { NavigationModuleKey } from '@/shared/enums'
export interface ISharedState { export interface ISharedState {
activeNavigationModule: NavigationModuleKey activeNavigationModule: NavigationModuleKey
isForbidden: ConstrainBoolean
} }
const initialState: ISharedState = { const initialState: ISharedState = {
activeNavigationModule: NavigationModuleKey.Loading, activeNavigationModule: NavigationModuleKey.Loading,
isForbidden: false,
} }
export const sharedReducer = createReducer<ISharedState, TAuthActions>( export const sharedReducer = createReducer<ISharedState, TAuthActions>(
@ -20,9 +22,17 @@ export const sharedReducer = createReducer<ISharedState, TAuthActions>(
} }
}, },
SET_IS_FORBIDDEN: (state, action) => {
return {
...state,
isForbidden: action.payload.isForbidden,
}
},
RESET: () => { RESET: () => {
return { return {
activeNavigationModule: NavigationModuleKey.Auth, activeNavigationModule: NavigationModuleKey.Auth,
isForbidden: false,
} }
}, },
}, },

4
src/store/shared/selectors.ts

@ -1,7 +1,9 @@
import { RootState } from '..' import { RootState } from '..'
export const selectActiveNavigationModule = (store: RootState) => { export const selectActiveNavigationModule = (store: RootState) => {
return store.shared.activeNavigationModule return store.shared.activeNavigationModule
} }
export const selectIsForbidden = (store: RootState) => {
return store.shared.isForbidden
}

12
src/store/shared/types.ts

@ -10,8 +10,18 @@ export class SetNavigationModule implements Action {
) {} ) {}
} }
export class SetIsForbidden implements Action {
readonly type = 'SET_IS_FORBIDDEN'
constructor(
public readonly payload: {
isForbidden: boolean
},
) {}
}
export class Reset { export class Reset {
readonly type = 'RESET' readonly type = 'RESET'
} }
export type TAuthActions = SetNavigationModule | Reset export type TAuthActions = SetNavigationModule | SetIsForbidden | Reset

Loading…
Cancel
Save