reza added added proxy

master
Reza_ashrafi 3 years ago
parent a680b975c3
commit ebaefb4b66
  1. 8
      app.json
  2. BIN
      assets/adaptive-icon.png
  3. BIN
      assets/favicon.png
  4. BIN
      assets/icon.png
  5. BIN
      assets/splash.png
  6. 116
      navigation.js
  7. 52
      navigation/index.js
  8. 2
      package.json
  9. 2
      src/actions/actionTypes.js
  10. 3
      src/components/CustomTextInput.js
  11. 4
      src/components/Drawer.js
  12. 4
      src/components/Search.js
  13. 9
      src/constants/defaultValues.js
  14. 29
      src/reducers/DefaultReducer.js
  15. 14
      src/reducers/index.js
  16. 27
      src/redux/actions/blog.js
  17. 44
      src/redux/actions/book.js
  18. 14
      src/redux/actions/content.js
  19. 20
      src/redux/actions/faq.js
  20. 22
      src/redux/actions/file.js
  21. 16
      src/redux/actions/index.js
  22. 26
      src/redux/actions/product.js
  23. 50
      src/redux/actions/public.js
  24. 65
      src/redux/actions/user.js
  25. 55
      src/redux/actions/userFactor.js
  26. 33
      src/redux/actions/userProduct.js
  27. 6
      src/redux/index.js
  28. 171
      src/redux/proxy.js
  29. 26
      src/redux/reducers/blog.js
  30. 167
      src/redux/reducers/book.js
  31. 56
      src/redux/reducers/faq.js
  32. 26
      src/redux/reducers/file.js
  33. 10
      src/redux/reducers/index.js
  34. 26
      src/redux/reducers/product.js
  35. 169
      src/redux/reducers/public.js
  36. 64
      src/redux/reducers/user.js
  37. 60
      src/redux/reducers/userFactor.js
  38. 48
      src/redux/reducers/userProduct.js
  39. 40
      src/redux/store.js
  40. 2
      src/screens/Home/components/Scroll.js
  41. 55
      src/screens/Login/index.js
  42. 10
      src/screens/Login/services/index.js
  43. 18
      src/screens/Login/services/mocks.js
  44. 13
      src/screens/Login/services/services.js
  45. 97
      src/screens/Otp/index.js
  46. 10
      src/screens/Otp/services/index.js
  47. 18
      src/screens/Otp/services/mocks.js
  48. 13
      src/screens/Otp/services/services.js
  49. 2
      src/screens/Product/components/Comments.js
  50. 32
      src/screens/Splash/index.js
  51. 71
      src/screens/Videos/index.js
  52. 3
      src/services/api/config.js
  53. 118
      src/services/api/fetch-retry.js
  54. 149
      src/services/api/index.js
  55. 203
      src/services/api/oldindex.js
  56. 145
      src/services/api/utils.js
  57. 16
      src/services/i18n/index.js
  58. 28
      src/services/i18n/locales/en/translation.json
  59. 29
      src/services/i18n/locales/fa/translation.json
  60. 11
      src/services/i18n/locales/index.js
  61. 2
      src/utils/message.js
  62. 280
      src/utils/onInput.js
  63. 12
      yarn.lock

@ -4,9 +4,9 @@
"slug": "RnDanovinExpo", "slug": "RnDanovinExpo",
"version": "1.0.0", "version": "1.0.0",
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/icon.png", "icon": "",
"splash": { "splash": {
"image": "./assets/splash.png", "image": "",
"resizeMode": "contain", "resizeMode": "contain",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
@ -21,13 +21,13 @@
}, },
"android": { "android": {
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "",
"backgroundColor": "#FFFFFF" "backgroundColor": "#FFFFFF"
}, },
"package": "com.appsazz.RnDanovinExpo" "package": "com.appsazz.RnDanovinExpo"
}, },
"web": { "web": {
"favicon": "./assets/favicon.png" "favicon": ""
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

@ -1,116 +0,0 @@
import * as React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import Splash from './src/screens/Splash';
import Home from './src/screens/Home';
import Login from './src/screens/Login';
import Otp from './src/screens/Otp';
import Product from './src/screens/Product';
import Products from './src/screens/Products';
import ShoppingCart from './src/screens/ShoppingCart';
import QR from './src/screens/QR/index';
import i18n from './src/services/i18n';
import {useTranslation} from 'react-i18next';
import Profile from './src/screens/Profile';
import Videos from './src/screens/Videos';
import Exams from './src/screens/Exams';
import OrderDetails from './src/screens/OrderDetails';
const mapStateToProps = state => {
return {
profile: state.profile,
config: state.config,
};
};
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
function BottomTab(props) {
return (
<Tab.Navigator initialRouteName={'Home'}>
<Tab.Screen
name={'Profile'}
component={Profile}
/>
<Tab.Screen
name={'Exams'}
component={Exams}
/>
<Tab.Screen
name={'Videos'}
component={Videos}
/>
<Tab.Screen
name={'محصولات'}
component={Products}
/>
<Tab.Screen
name={'خانه'}
component={Home}
options={{
headerShown : false
// title: t('home'),
}}
/>
</Tab.Navigator>
);
}
function Navigator(props) {
React.useEffect(() => {
// i18n.changeLanguage(props.config.lan);
}, [props.config]);
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
options={{headerShown: false}}
name="Splash"
component={Splash}
/>
<Stack.Screen
name="Login"
component={Login}
options={{headerShown: false}}
/>
{/* <Stack.Screen
name="Home"
component={Home}
options={{headerShown: false}}
/> */}
<Stack.Screen
name="Otp"
component={Otp}
options={{headerShown: false}}
/>
<Stack.Screen
name="Home"
component={BottomTab}
options={{headerShown: false}}
/>
<Stack.Screen
name="Product"
component={Product}
options={{headerShown: false}}
/>
<Stack.Screen
name="Products"
component={BottomTab}
options={{headerShown: false}}
/>
<Stack.Screen name="QR" component={QR} options={{headerShown: true}} />
<Stack.Screen
name="سبد خرید"
component={ShoppingCart}
options={{headerShown: true}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default Navigator;

@ -2,7 +2,7 @@ import React from "react";
import { NavigationContainer } from "@react-navigation/native"; import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack"; import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Entypo, FontAwesome, Ionicons } from "@expo/vector-icons"; import { Entypo, FontAwesome, Ionicons, MaterialIcons } from "@expo/vector-icons";
import OrderDetails from "../src/screens/OrderDetails"; import OrderDetails from "../src/screens/OrderDetails";
import OrdersFollowUp from "../src/screens/OrdersFollowUp"; import OrdersFollowUp from "../src/screens/OrdersFollowUp";
import { Dimensions } from "react-native"; import { Dimensions } from "react-native";
@ -16,8 +16,6 @@ import QR from "../src/screens/QR";
import Faq from "../src/screens/Faq" import Faq from "../src/screens/Faq"
import Activation from "../src/screens/Activation"; import Activation from "../src/screens/Activation";
import { connect } from "react-redux"; import { connect } from "react-redux";
import i18n from "../src/services/i18n";
import { useTranslation } from "react-i18next";
import Profile from "../src/screens/Profile"; import Profile from "../src/screens/Profile";
import Videos from "../src/screens/Videos"; import Videos from "../src/screens/Videos";
import Exams from "../src/screens/Exams"; import Exams from "../src/screens/Exams";
@ -29,7 +27,7 @@ const Tab = createBottomTabNavigator();
const BottomTabNavigator = () => { const BottomTabNavigator = () => {
return ( return (
<Tab.Navigator <Tab.Navigator
initialRouteName="Home" initialRouteName="HomeTab"
screenOptions={{ screenOptions={{
headerShown: false, headerShown: false,
tabBarActiveTintColor: "#06BACE", tabBarActiveTintColor: "#06BACE",
@ -46,7 +44,7 @@ const BottomTabNavigator = () => {
}} }}
> >
<Tab.Screen <Tab.Screen
name="Splash" name="SplashTab"
component={AuthStackScreen} component={AuthStackScreen}
options={{ options={{
tabBarIcon: ({ focused, color }) => ( tabBarIcon: ({ focused, color }) => (
@ -55,7 +53,7 @@ const BottomTabNavigator = () => {
}} }}
/> />
<Tab.Screen <Tab.Screen
name="ShoppingCart" name="ShoppingCartTab"
component={ShoppingCart} component={ShoppingCart}
options={{ options={{
tabBarIcon: ({ focused, color }) => ( tabBarIcon: ({ focused, color }) => (
@ -68,7 +66,16 @@ const BottomTabNavigator = () => {
}} }}
/> />
<Tab.Screen <Tab.Screen
name="Products" name="VODTab"
component={VODStackScreen}
options={{
tabBarIcon: ({ focused, color }) => (
<MaterialIcons name="ondemand-video" size={focused ? 27 : 23} color={color} />
),
}}
/>
<Tab.Screen
name="ProductsTab"
component={ProductsStackScreen} component={ProductsStackScreen}
options={{ options={{
tabBarIcon: ({ focused, color }) => ( tabBarIcon: ({ focused, color }) => (
@ -77,7 +84,7 @@ const BottomTabNavigator = () => {
}} }}
/> />
<Tab.Screen <Tab.Screen
name="Home" name="HomeTab"
component={HomeStackScreen} component={HomeStackScreen}
options={{ options={{
tabBarIcon: ({ focused, color }) => ( tabBarIcon: ({ focused, color }) => (
@ -115,24 +122,38 @@ const ProductsStackScreen = () => {
return ( return (
<ProductsStack.Navigator <ProductsStack.Navigator
screenOptions={{ headerShown: false }} screenOptions={{ headerShown: false }}
initialRouteName="Products"
> >
<ProductsStack.Screen name="Products" component={Products} /> <ProductsStack.Screen name="Products" component={Products} />
<ProductsStack.Screen name="QR" component={QR} /> <ProductsStack.Screen name="QR" component={QR} />
<ProductsStack.Screen name="Product" component={Product} /> <ProductsStack.Screen name="Product" component={Product} />
<Stack.Screen name="Orders" component={OrderStackScreen} /> <ProductsStack.Screen name="Orders" component={OrderStackScreen} />
<Stack.Screen name="Faq" component={Faq} /> <ProductsStack.Screen name="Faq" component={Faq} />
<Stack.Screen name="Activation" component={Activation} /> <ProductsStack.Screen name="Activation" component={Activation} />
</ProductsStack.Navigator> </ProductsStack.Navigator>
); );
}; };
const VODStack = createNativeStackNavigator();
const VODStackScreen = () => {
return (
<VODStack.Navigator
screenOptions={{ headerShown: false }}
>
<VODStack.Screen name="VOD" component={Videos} />
<VODStack.Screen name="QR" component={QR} />
<VODStack.Screen name="Orders" component={OrderStackScreen} />
<VODStack.Screen name="Faq" component={Faq} />
<VODStack.Screen name="Activation" component={Activation} />
</VODStack.Navigator>
);
};
const AuthStack = createNativeStackNavigator(); const AuthStack = createNativeStackNavigator();
const AuthStackScreen = () => { const AuthStackScreen = () => {
return ( return (
<AuthStack.Navigator <AuthStack.Navigator
screenOptions={{ headerShown: false }} screenOptions={{ headerShown: false }}
initialRouteName="Splash" // initialRouteName="Splash"
> >
<AuthStack.Screen name="Splash" component={Splash} /> <AuthStack.Screen name="Splash" component={Splash} />
<AuthStack.Screen name="Login" component={Login} /> <AuthStack.Screen name="Login" component={Login} />
@ -155,7 +176,7 @@ const OrderStackScreen = () => {
} }
const Stack = createNativeStackNavigator(); const Stack = createNativeStackNavigator();
const Navigation = ({ profile }) => { const Navigation = ({ }) => {
return ( return (
<NavigationContainer> <NavigationContainer>
<Stack.Navigator <Stack.Navigator
@ -173,8 +194,7 @@ const Navigation = ({ profile }) => {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
profile: state.profile,
config: state.config,
}; };
}; };

@ -16,6 +16,7 @@
"@react-navigation/drawer": "^6.1.8", "@react-navigation/drawer": "^6.1.8",
"@react-navigation/native": "^6.0.6", "@react-navigation/native": "^6.0.6",
"@react-navigation/native-stack": "^6.2.5", "@react-navigation/native-stack": "^6.2.5",
"axios": "^0.24.0",
"expo": "^44.0.1", "expo": "^44.0.1",
"expo-app-loading": "~1.3.0", "expo-app-loading": "~1.3.0",
"expo-barcode-scanner": "~11.2.0", "expo-barcode-scanner": "~11.2.0",
@ -48,5 +49,6 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9" "@babel/core": "^7.12.9"
}, },
"private": true "private": true
} }

@ -1,2 +0,0 @@
export const PROFILE_RECORD = 'PROFILE_RECORD';
export const APP_CONFIG = 'APP_CONFIG';

@ -15,6 +15,7 @@ const FloatingLabelInput = ({
color, color,
maxLength, maxLength,
autoFocus, autoFocus,
regex,
...props ...props
}) => { }) => {
const [isFocused, setIsFocused] = useState(false); const [isFocused, setIsFocused] = useState(false);
@ -43,7 +44,7 @@ const FloatingLabelInput = ({
</Text> </Text>
<TextInput <TextInput
style={[styles.inputStyle , tw('rounded-md p-2') ]} style={[styles.inputStyle , tw('rounded-md p-2') ]}
onChangeText={text => onChange(name, text)} onChangeText={text => onChange(name, text = regex(text))}
placeholder={'09123456789'} placeholder={'09123456789'}
onFocus={() => setIsFocused(true)} onFocus={() => setIsFocused(true)}
autoFocus={autoFocus} autoFocus={autoFocus}

@ -62,7 +62,7 @@ const Drawer = ({ position, setBoxPosition }) => {
{ {
name: "سوالات متداول", name: "سوالات متداول",
route: "Faq", route: "Faq",
icon: <Ionicons name="question" size={23} color={"#555555"} />, icon: <Ionicons name="reorder-four" size={23} color={"#555555"} />,
toast: "", toast: "",
message: "", message: "",
} }
@ -72,7 +72,7 @@ const Drawer = ({ position, setBoxPosition }) => {
return ( return (
<TouchableOpacity <TouchableOpacity
style={[ style={[
tw("w-full flex flex-row-reverse justify-start items-end items mt-6"), tw("w-full flex flex-row-reverse justify-start items-end mt-6"),
{}, {},
]} ]}
onPress={() => navigation.navigate(route.route)} onPress={() => navigation.navigate(route.route)}

@ -8,7 +8,7 @@ import {
Image, Image,
} from 'react-native'; } from 'react-native';
import tw from 'tailwind-react-native-classnames'; import tw from 'tailwind-react-native-classnames';
import searchIcon from '../assets/icons/search.png'; import { AntDesign } from '@expo/vector-icons';
const width = Dimensions.get('window').width; const width = Dimensions.get('window').width;
const Search = ({ const Search = ({
@ -42,7 +42,7 @@ const Search = ({
value={value} value={value}
/> />
<Pressable style={tw.style('absolute left-3 top-0 inset-y-2')}> <Pressable style={tw.style('absolute left-3 top-0 inset-y-2')}>
<Image source={searchIcon} style={[{width: 20, height: 20}]} /> <AntDesign name="search1" size={18} color="#196EC0" />
</Pressable> </Pressable>
</View> </View>
); );

@ -0,0 +1,9 @@
export const ApiConfig = {
apiKey: 'AIzaSyBBksq-Asxq2M4Ot-75X19IyrEYJqNBPcg',
authDomain: 'dnvn.ir',
baseUrl: 'https://dnvn.ir/api/v1',
//baseUrl: 'http://localhost:3030/api/v1',
loginURL: 'user/login',
otploginURL: 'user/otp/login',
logoutURL: 'user/logout',
};

@ -1,29 +0,0 @@
export function DefaultReducer(key, initialState = {}) {
return (state = initialState, {type = '', payload = {}}) => {
switch (type) {
case key:
return {...state, ...payload};
}
return state;
};
}
export function buildAction(id) {
return function(payload) {
return {
type: id,
payload: payload,
};
};
}
export function buildActionForKey(id, key) {
return function(payload) {
let result = {
type: id,
payload: {},
};
result.payload[key] = payload;
return result;
};
}

@ -1,14 +0,0 @@
import {combineReducers} from 'redux';
import {DefaultReducer} from './DefaultReducer';
import * as action from '../actions/actionTypes';
const allReducers = combineReducers({
profile: DefaultReducer(action.PROFILE_RECORD, {
isLogin: false,
}),
config: DefaultReducer(action.APP_CONFIG, {
lan: 'fa',
}),
});
export default allReducers;

@ -0,0 +1,27 @@
import proxy from "../proxy";
const blog = {
list:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/blogList", data, { dispatch }),
// update:
// (data = {}, data2 = {}) =>
// async (dispatch : Dispatch) => {
// await proxy.put("blog/update", data);
// await proxy.get("blog/list", data2, { dispatch });
// },
// add:
// (data = {}, data2 = {}) =>
// async (dispatch : Dispatch) => {
// await proxy.post("blog/add", data);
// await proxy.get("blog/list", data2, { dispatch });
// },
// del:
// (data = {}, data2 = {}) =>
// async (dispatch : Dispatch) => {
// await proxy.delete("blog/delete", data);
// await proxy.get("blog/list", data2, { dispatch });
// },
};
export default blog;

@ -0,0 +1,44 @@
import proxy from "../proxy";
const book = {
list:
(data = {}) =>
async (dispatch) =>
await proxy.get("book/list", data, { dispatch }),
info:
(data = {}) =>
async (dispatch) =>
await proxy.get("book/info", data, { dispatch }),
setLessonActive: (data) => async (dispatch) =>
await dispatch({ type: "book/lesson/active", data: data }),
gradeFilter: (data) => async (dispatch) =>
await dispatch({ type: "book/gradeFilter", data: data }),
sortFilter: (data) => async (dispatch) =>
await dispatch({ type: "book/sortFilter", data: data }),
// update:
// (data = {}, data2 = {}) =>
// async (dispatch : Dispatch) => {
// await proxy.put("book/update", data);
// await proxy.get("book/list", data2, { dispatch });
// },
// add:
// (data = {}, data2 = {}) =>
// async (dispatch) => {
// await proxy.post("book/add", data);
// await proxy.get("book/list", data2, { dispatch });
// },
// del:
// (data = {}, data2 = {}) =>
// async (dispatch) => {
// await proxy.delete("book/delete", data);
// await proxy.get("book/list", data2, { dispatch });
// },
// searchBook: (data) => async (dispatch) => {
// dispatch({ type: "book/search", data: data });
// },
// filterBook: (data) => async (dispatch) => {
// dispatch({ type: "book/filter", data: data });
// },
};
export default book;

@ -0,0 +1,14 @@
import proxy from "../proxy";
import { Dispatch } from "redux";
const content = {
listVOD:
(data = {}) =>
async (dispatch) =>
await proxy.get("content/listVOD", data, { dispatch }),
infoVOD:
(data = {}) =>
async (dispatch) =>
await proxy.get("content/infoVOD", data, { dispatch }),
};
export default content;

@ -0,0 +1,20 @@
import proxy from "../proxy";
import { Dispatch } from "redux";
const faq = {
list:
(data = {}) =>
async (dispatch) =>
await proxy.get("faq/list", data, { dispatch }),
add:
(data = {}) =>
async (dispatch) =>
await proxy.post("faq/add", data, { dispatch }),
selectFaq:
(data = {}) =>
async (dispatch) =>
await dispatch({ type: "faq/selectFaq", data: data }),
searchFaq: (data) => async (dispatch) =>
await dispatch({ type: "faq/search", data: data }),
};
export default faq;

@ -0,0 +1,22 @@
import proxy from "../proxy";
const file = {
upload:
(data = {}) =>
async (dispatch) => {
var formData = new FormData();
for (let key in data) formData.append(key, data[key]);
return await proxy.post(
"file/upload",
formData,
{
dispatch,
headers: {
"Content-Type": "multipart/form-data",
},
},
data
);
},
};
export default file;

@ -0,0 +1,16 @@
// @create-index
export { default as publicApi } from "./public";
export { default as user } from "./user";
export { default as book } from "./book";
export { default as blog } from "./blog";
export { default as product } from "./product";
export { default as userFactor } from "./userFactor";
export { default as userProduct } from "./userProduct";
export { default as content } from "./content";
export { default as faq } from "./faq";
export { default as file } from "./file";

@ -0,0 +1,26 @@
import proxy from "../proxy";
const product = {
listVOD:
(data = {}) =>
async (dispatch) =>
await proxy.get("product/listVOD", data, { dispatch }),
addVOD:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.post("product/addVOD", data);
await proxy.get("product/listVOD", data2, { dispatch });
},
deleteVOD:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("product/deleteVOD", data);
await proxy.get("product/listVOD", data2, { dispatch });
},
selectVOD:
(data = {}) =>
async (dispatch) => {
await dispatch({ type: "product/selectVOD", data });
},
};
export default product;

@ -0,0 +1,50 @@
import proxy from "../proxy";
const publicApi = {
setIsDark: (data) => async (dispatch) =>
await dispatch({ type: "public/setIsDark", data: data }),
getHomeData: (data) => async (dispatch) =>
await proxy.get("public/homePage", data, { dispatch }),
setFaqActive: (data) => async (dispatch) =>
await dispatch({ type: "public/faq/activate", data: data }),
bookInfo:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/vod/bookCourse", data, { dispatch }),
bookSection:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/vod/bookSection", data, { dispatch }),
getContactData:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/contact", data, { dispatch }),
getBlogList: (data) => async (dispatch) =>
await proxy.get("public/blogList", data, { dispatch }),
getBlogInfo: (data) => async (dispatch) =>
await proxy.get("public/blogInfo", data, { dispatch }),
setSubscribe: (data) => async (dispatch) =>
await dispatch({ type: "public/setSubscribe", data: data }),
getProvince:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/province", data, { dispatch }),
getCity:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/city", data, { dispatch }),
selectMenu: (data) => async (dispatch) =>
await dispatch({ type: "public/selectMenu", data: data }),
getHeader:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/VOD/homePage", data, { dispatch }),
activeCategory: (data) => async (dispatch) =>
await dispatch({ type: "active/category", data: data }),
setVideoActive: (data) => async (dispatch) =>
await dispatch({ type: "active/video", data: data }),
};
export default publicApi;

@ -0,0 +1,65 @@
import proxy from "../proxy";
const user = {
otp: (data) => async (dispatch) => {
console.log(data);
await proxy.post("public/sendOTP", data, { dispatch });
},
otp_login: (data) => async (dispatch) =>
await proxy.login("user/otp/login", data, { dispatch }),
login: (data) => async (dispatch) =>
await proxy.login("user/login", data, { dispatch }),
// register: (data : undefined) => async (dispatch : Dispatch) =>
// await proxy.login("user/register", data, { dispatch }),
// switchRole: (data : String) => async (dispatch : Dispatch) =>
// await proxy.login("user/switchRole", data, { dispatch }),
logout: (data) => async (dispatch) =>
await proxy.logout("user/logout", data, { dispatch }),
getUserRole: (data) => async (dispatch) =>
await proxy.get("user/getUserRole", data, { dispatch }),
// list:
// (data = {}) =>
// async (dispatch : Dispatch) =>
// await proxy.get("user/list", data, { dispatch }),
// domains:
// (data = {}) =>
// async (dispatch : Dispatch) =>
// await proxy.get("user/domains", data, { dispatch }),
// getmothers:
// (data = {}) =>
// async (dispatch : Dispatch) =>
// await proxy.get("mothers/list", data, {
// dispatch,
// }),
getProfile:
(data = {}) =>
async (dispatch) =>
await proxy.get("user/getProfile", data, { dispatch }),
setProfile:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.put("user/setProfile", data, { dispatch });
await proxy.get("user/getProfile", data2, { dispatch });
},
add:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.post("user/add", data);
await proxy.get("user/list", data2, { dispatch });
},
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("user/delete", data);
await proxy.get("user/list", data2, { dispatch });
},
};
export default user;

@ -0,0 +1,55 @@
import proxy from "../proxy";
const userFactor = {
//dnvn
list:
(data = {}) =>
async (dispatch) =>
await proxy.get("userFactor/list", data, { dispatch }),
payment:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.post("userFactor/payment", data, { dispatch });
},
add:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.post("userFactor/add", data, { dispatch });
await proxy.get("userFactor/list", data2, { dispatch });
},
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userFactor/delete", data);
await proxy.get("userFactor/list", data2, { dispatch });
},
//vod
payment:
(data1 = {}, data2 = {}) =>
async (dispatch) => {
await proxy.post("userProduct/addVOD", data1, { dispatch });
await proxy.post("userFactor/paymentVOD", data2, { dispatch });
},
verify:
(data = {}) =>
async (dispatch) =>
await proxy.post("userFactor/verifyVOD", data, { dispatch }),
info:
(data = {}) =>
async (dispatch) =>
await proxy.get("userFactor/info", data, { dispatch }),
update:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.put("userFactor/update", data, { dispatch });
await proxy.get("userFactor/info", data2, { dispatch });
},
deleteUserOffCode:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userFactor/deleteUserOffCode", data, { dispatch });
await proxy.get("userFactor/info", data2, { dispatch });
},
};
export default userFactor;

@ -0,0 +1,33 @@
import proxy from "../proxy";
const userProduct = {
list:
(data = {}) =>
async (dispatch) => {
await proxy.get("userProduct/list", data, { dispatch });
},
info:
(data = {}) =>
async (dispatch) =>
await proxy.get("userProduct/info", data, { dispatch }),
update:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.put("userProduct/update", data);
await proxy.get("userProduct/list", data2, { dispatch });
},
add:
(data = {}, data2 = {}, data3 = {}) =>
async (dispatch) => {
await proxy.post("userProduct/add", data, { dispatch });
await proxy.get("userProduct/list", data2, { dispatch });
await proxy.get("userFactor/info", data3, { dispatch });
},
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userProduct/delete", data);
await proxy.get("userProduct/list", data2, { dispatch });
},
};
export default userProduct;

@ -0,0 +1,6 @@
// @create-index
export { default as actions } from './actions';
export { default as proxy } from './proxy.js';
export { default as reducers } from './reducers';
export { default as store } from './store.js';

@ -0,0 +1,171 @@
import { ApiConfig } from "../constants/defaultValues";
import axios from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { useNavigation } from "@react-navigation/native";
let { baseUrl } = ApiConfig;
let access;
() => {
access = AsyncStorage.getItem("access");
};
baseUrl = baseUrl + "/";
const Axios = axios.create({
withCredentials: true,
validateStatus: null,
baseURL: baseUrl,
//headers: access ? { Authorization: `Bearer ${access}` } : {},
});
class Proxy {
get = (url, params, opt, data) => {
try {
this.check(
url,
opt,
() => Axios.get(url, { params, ...opt }),
data || params
);
} catch (error) {
console.log("proxy get error! : ", error);
}
};
post = (url, params, opt, data) => {
try {
this.check(
url,
opt,
() => Axios.post(url, params, opt),
data || params
);
} catch (error) {
console.log("proxy post error! : ", error);
}
};
put = (url, params, opt, data) => {
try {
this.check(
url,
opt,
() => Axios.put(url, params, opt),
data || params
);
} catch (error) {
console.log("proxy put error! : ", error);
}
};
delete = (url, params, opt, data) => {
try {
this.check(
url,
opt,
() => Axios.delete(url, { ...opt, data: params }),
data || params
);
} catch (error) {
console.log("proxy delete error! : ", error);
}
};
check = (url, { dispatch }, fetch, params) => {
try {
dispatch = dispatch || (() => {});
dispatch({ type: url.split("/")[0] + "/" + "loading" });
let response = fetch();
switch (response.status) {
case 200:
dispatch({ type: url, data: response.data.data, params });
return response.data.data;
case 401:
if (this.refresh()) {
let response = fetch();
dispatch({ type: url, data: response.data.data, params });
return response.data.data;
}
break;
default:
dispatch({
type: url.split("/")[0] + "/" + "error",
data: response.data,
params,
});
}
return false;
} catch (error) {
console.log("proxy check error! : ", error);
}
};
refresh = () => {
try {
const navigation = useNavigation();
let refresh = AsyncStorage.getItem("refresh");
if (!refresh) navigation.push("Root");
let login = this.login(
"user/login",
{},
{ headers: { Authorization: `Bearer ${refresh}` } }
);
return login ? true : false;
} catch (error) {
console.log("proxy refresh error! : ", error);
}
};
login = (url, params, { dispatch }) => {
try {
console.log('------------------------------login---------------------------------');
this.post(url, params, {
dispatch: (obj) => {
let login = obj.data;
console.log('login data: ',login);
if (!login || !login.refreshToken) return false;
const refresh = ["refresh", login.refreshToken];
const access = ["access", login.accessToken];
const userData = ["userData", JSON.stringify(login.profile)];
AsyncStorage.multiSet([refresh, access, userData]);
delete login.refreshToken;
delete login.accessToken;
dispatch(obj);
},
});
} catch (error) {
console.log("proxy login error! : ", error);
}
};
logout = (url, params, { dispatch }) => {
try {
this.post(url, params, {
dispatch: (obj) => {
const keys = ["refresh", "access", "userData"];
AsyncStorage.multiRemove(keys);
dispatch(obj);
},
});
} catch (error) {
console.log("proxy logout error : ", error);
}
};
status = () => {
try {
let refresh = AsyncStorage.getItem("refresh");
let userData = AsyncStorage.getItem("userData");
if (!refresh) return false;
if (refresh == "undefined") {
const keys = ["refresh", "access", "userData"];
AsyncStorage.multiRemove(keys);
return false;
}
return userData || null;
} catch (error) {
console.log("proxy status error : ", error);
}
};
}
const _proxy = new Proxy();
export default _proxy;

@ -0,0 +1,26 @@
const initialState = {
loading: false,
error: null,
list: [],
};
export default function blog(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "public/blogList":
return { ...state, loading: false, list: data, error: null };
// case "blog/update":
// return { ...state, loading: false, error: null };
// case "blog/add":
// return { ...state, loading: false, error: null };
// case "blog/delete":
// return { ...state, loading: false, error: null };
/////////////
case "blog/loading":
return { ...state, loading: true };
case "blog/error":
// toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,167 @@
const initialState = {
loading: false,
error: null,
list: [],
info: null,
searchResult: [],
filterResult: [],
subjects: [],
levels: [],
sortFilters: ["مرتب سازی", "محبوب ترین", "جدیدترین"],
selectedVideo: null,
gradeFilterBooks: null,
sortFilterCourse: null,
selectedGrade: null,
selectedSort: "پربازدید ترین ها",
};
const grades = [
"پیش دبستان",
"اول",
"دوم",
"سوم",
"چهارم",
"پنجم",
"ششم",
"هفتم",
"هشتم",
"نهم",
"دهم",
"یازدهم",
"دوازدهم",
];
export default function book(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "book/list":
let itemsSubject = (Array.isArray(data) ? data : []).map(
(item, index) => item.name
);
if (window.innerWidth < 1000) {
itemsSubject.unshift("نام کتاب");
}
let itemsLevel = (Array.isArray(data) ? data : [])
.map((item) => item.gradeId * 1)
.sort((a, b) => a - b)
.map((e) => grades[e]);
if (window.innerWidth < 1000) {
itemsLevel.unshift("پایه تحصیلی");
}
return {
...state,
loading: false,
list: data,
subjects: Array.from(new Set(itemsSubject)),
levels: Array.from(new Set(itemsLevel)),
filterResult: data,
error: null,
};
case "book/info":
return { ...state, loading: false, info: data, error: null };
case "book/lesson/active":
return {
...state,
loading: false,
error: null,
};
case "book/gradeFilter":
if (data === state.selectedGrade) {
return { ...state, gradeFilterBooks: null, selectedGrade: null };
} else {
return {
...state,
gradeFilterBooks: state.list.filter(
(item, i) => grades[item.gradeId] === data
),
selectedGrade: data,
};
}
case "book/sortFilter":
const search = state.list.filter(
(item) => item.name.indexOf(data.search) !== -1
);
if (data.sort === "تمامی دورهها") {
return { ...state, sortFilterCourse: search, selectedSort: data.sort };
} else if (data.sort === "جدیدترینها") {
return {
...state,
sortFilterCourse: search.sort((item1, item2) => {
return item1.publishYear - item2.publishYear;
}),
selectedSort: data.sort,
};
}
return { ...state, sortFilterCourse: search, selectedSort: data.sort };
// case "book/update":
// return { ...state, loading: false, error: null };
// case "book/add":
// return { ...state, loading: false, error: null };
// case "book/delete":
// return { ...state, loading: false, error: null };
// case "book/search":
// return { ...state };
// case "book/filter":
// const realList = state.list;
// const level = data.level;
// const subject = data.subject;
// const sort = data.sort;
// const search = data.search;
// if (level.length > 0 || subject.length > 0 || sort || search) {
// localStorage.setItem("filter", "ON");
// }
// let finalSort;
// let byLevelFilter = [];
// if (level.length > 0) {
// level.map((item1) => {
// for (let i = 0; i < realList.length; i++) {
// if (grades[realList[i].gradeId] === item1) {
// byLevelFilter.push(realList[i]);
// }
// }
// });
// } else {
// byLevelFilter = realList;
// }
// let bySubjectFilter = [];
// if (subject.length > 0) {
// subject.map((item1) => {
// for (let i = 0; i < byLevelFilter.length; i++) {
// if (byLevelFilter[i].name === item1) {
// bySubjectFilter.push(byLevelFilter[i]);
// }
// }
// });
// } else {
// bySubjectFilter = byLevelFilter;
// }
// const bySearchFilter = search
// ? bySubjectFilter.filter((item1) => item1.name.indexOf(search) !== -1)
// : bySubjectFilter;
// if (sort === "گران ترین") {
// finalSort = bySearchFilter.sort((item1, item2) => {
// return item1.product[0].price - item2.product[0].price;
// });
// } else {
// finalSort = bySearchFilter;
// }
// return {
// ...state,
// loading: false,
// error: null,
// filterResult: finalSort,
// };
case "book/loading":
return { ...state, loading: true };
case "book/error":
// toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,56 @@
const initialState = {
loading: false,
error: null,
list: [],
searchResult: [],
search: null,
};
export default function faq(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "faq/list":
return { ...state, loading: false, list: data, error: null };
case "faq/add":
return { ...state, loading: false, error: null };
case "faq/selectFaq":
return {
...state,
loading: false,
error: null,
list: !state.search
? state.list.map((item) =>
item.id === data
? { ...item, active: !item.active }
: { ...item, active: false }
)
: state.list,
searchResult: state.search
? state.searchResult.map((item) =>
item.id === data
? { ...item, active: !item.active }
: { ...item, active: false }
)
: state.searchResult,
};
case "faq/search":
return {
...state,
loading: false,
error: null,
search: data,
searchResult: state.list.filter(
(item) =>
item.title.indexOf(data) !== -1 ||
item.description.indexOf(data) !== -1
),
};
case "faq/loading":
return { ...state, loading: true };
case "faq/error":
// toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,26 @@
const initialState = {
loading: false,
error: null,
uploads: {},
lastUpload: null,
};
export default function file(state = initialState, action) {
let { type, data, params } = action;
switch (type) {
case "file/upload":
return {
...state,
loading: false,
error: null,
uploads: { ...state.uploads, [params?.target || "last"]: data.id },
lastUpload: data.id,
};
case "file/loading":
return { ...state, loading: true };
case "file/error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,10 @@
// @create-index
export { default as publicApi } from "./public";
export { default as user } from "./user";
export { default as book } from "./book";
export { default as blog } from "./blog";
export { default as product } from "./product";
export { default as faq } from "./faq";
export { default as file } from "./file";
export { default as userFactor } from "./userFactor";
export { default as userProduct } from "./userProduct";

@ -0,0 +1,26 @@
const initialState = {
loading: false,
error: null,
listVOD: [],
selectedVOD: null,
};
export default function product(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "product/listVOD":
return { ...state, loading: false, listVOD: data, error: null };
case "product/addVOD":
return { ...state, loading: false, error: null };
case "product/deleteVOD":
return { ...state, loading: false, error: null };
case "product/selectVOD":
return {...state, selectedVOD : data};
case "product/loading":
return { ...state, loading: true };
case "product/error":
// toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,169 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import { Dimensions } from "react-native";
const width = Dimensions.get("window").width;
const initialState = {
// isDark: (await AsyncStorage.getItem("isDark")) || false,
homeData: [],
newProducts: [],
levels: [],
loading: false,
error: null,
searchResult: [],
arList: [],
blogList: [],
blog: null,
province: null,
city: null,
departmans: [
{
id: 0,
name: "محتوا",
},
{
id: 0,
name: "دیزاین",
},
{
id: 0,
name: "برنامه نویسی",
},
],
header: [],
selectedMenu: null,
contactData: null,
selectedVideo: null,
bookInfo: null,
activeCategory: null,
categories: null,
bookSection: null,
grades: {
0: "پیش دبستان",
1: "اول",
2: "دوم",
3: "سوم",
4: "چهارم",
5: "پنجم",
6: "ششم",
7: "هفتم",
8: "هشتم",
9: "نهم",
10: "دهم",
11: "یازدهم",
12: "دوازدهم",
},
};
const grades = [
"پیش دبستان",
"اول",
"دوم",
"سوم",
"چهارم",
"پنجم",
"ششم",
"هفتم",
"هشتم",
"نهم",
"دهم",
"یازدهم",
"دوازدهم",
];
const publicApi = (state = initialState, action) => {
let { type, data } = action;
switch (type) {
case "public/setIsDark":
// AsyncStorage.setItem("isDark", data);
return { ...state, location: false, error: null, isDark: data };
case "active/video":
return {
...state,
loading: false,
error: null,
selectedVideo: data,
};
case "active/category":
return {
...state,
loading: false,
activeCategory: state.activeCategory === data ? null : data,
error: null,
};
case "public/vod/bookSection":
const videoId = location.getId();
return {
...state,
loading: false,
bookSection: data,
error: null,
selectedVideo: data.vods?.filter((item) => item.id !== videoId)[0],
};
case "public/vod/bookCourse":
let allCats;
allCats = Array.from(
new Set(data.vods.map((item) => item.categoryId && item.categoryId))
);
return {
...state,
loading: false,
bookInfo: {
...data,
vods: data.vods.map((item) => {
return { ...item, active: false };
}),
},
error: null,
categories: allCats.map((item) =>
data.vods.filter((item1) => item1.categoryId === item)
),
selectedVideo: data.vods.filter((item) => item.id !== 1)[0],
};
case "public/homePage":
let itemsLevel;
if (width > 1000) {
const jadidTarin = data.filter(
(item) => item.title === "جدیدترین کتابهای دانوین"
);
itemsLevel = jadidTarin[0].data
.map((item) => item.book.gradeId * 1)
.sort((a, b) => a - b)
.map((e) => grades[e]);
itemsLevel.unshift("همه");
}
return {
...state,
loading: false,
levels: width > 1000 ? Array.from(new Set(itemsLevel)) : [],
error: null,
homeData: data,
};
case "public/contact":
return { ...state, loading: false, error: null, contactData: data };
case "public/blogList":
return { ...state, loading: false, error: null, blogList: data };
case "public/blogInfo":
return { ...state, loading: false, error: null, blog: data };
case "public/setSubscribe":
return { ...state, loading: false, error: null, selectedSubscribe: data };
case "public/province":
return { ...state, loading: false, error: null, province: data };
case "public/city":
return { ...state, loading: false, error: null, city: data };
case "public/selectMenu":
return { ...state, loading: false, error: null, selectedMenu: data };
case "public/VOD/homePage":
return { ...state, loading: false, error: null, header: data };
case "loading":
return { ...state, loading: true };
case "error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
};
export default publicApi;

@ -0,0 +1,64 @@
import proxy from "../proxy";
import AsyncStorage from "@react-native-async-storage/async-storage";
let initialState = {
status: proxy.status(),
loading: false,
error: null,
list: null,
domains: [],
mothers: [],
profileStatus: false,
setDone: false,
setLogin: false,
check : 'check'
};
const user = (state = initialState, action) => {
let { type, data } = action;
switch (type) {
// case "user/login":
// case "user/register":
// case "user/switchRole":
case "public/sendOTP":
return { ...state, loading: false, error: null };
case "user/login":
case "user/otp/login":
return {
...state,
loading: false,
status: data.profile,
error: null,
setLogin: !state.setLogin,
};
case "user/getProfile":
const myData = JSON.stringify(data);
try{
AsyncStorage.setItem("userData", myData);
}catch(error){
console.log('user/getProfile', error);
}
return {
...state,
loading: false,
status: data,
error: null,
setDone: false,
};
case "user/logout":
return { ...state, loading: false, status: proxy.status(), error: null };
case "user/getUserRole":
return { ...state, loading: false, userRoles: data, error: null };
case "user/setProfile":
// toast.success("تغییرات اعمال شد.");
return { ...state, loading: false, error: null, setDone: true };
case "loading":
return { ...state, loading: true };
case "error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
}
export default user;

@ -0,0 +1,60 @@
import {useNavigation} from '@react-navigation/native';
const initialState = {
loading: false,
error: null,
list: null,
info: null,
sum: null,
checkEmpty: false,
isVerified: null,
};
export default function userFactor(state = initialState, action) {
// const navigation = useNavigation();
let { type, data } = action;
switch (type) {
//dnvn
case "userFactor/list":
const checkEmpty = data.filter(
(item) => item.condition === 2 && item.product.productType === (1 || 3)
);
return {
...state,
loading: false,
list: data,
checkEmpty: checkEmpty.length > 0 ? false : true,
error: null,
};
case "userFactor/info":
return { ...state, loading: false, info: data, error: null };
case "userFactor/add":
// toast.success("درخواست شما با موفقیت انجام شد.");
return { ...state, loading: false, error: null, sum: data.payPrice };
case "userFactor/delete":
return { ...state, loading: false, error: null };
case "userFactor/payment":
// navigation.push(data);
return { ...state, loading: false, error: null };
//vod
case "userFactor/myList":
return { ...state, loading: false, list: data, error: null };
case "userFactor/update":
// toast.success("درخواست شما با موفقیت انجام شد.");
return { ...state, loading: false, error: null };
case "userFactor/deleteUserOffCode":
return { ...state, loading: false, error: null };
case "userFactor/paymentVOD":
// navigation.push(data);
return { ...state, loading: false, error: null, isVerified: false };
case "userFactor/verifyVOD":
return { ...state, loading: false, error: null, isVerified: true };
case "userFactor/loading":
return { ...state, loading: true };
case "userFactor/error":
// toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,48 @@
const initialState = {
loading: false,
error: null,
list: [],
info: null,
sum: null,
checkEmpty: false,
hasPhysical: false,
};
export default function userFactor(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userProduct/list":
const checkEmpty = data.filter(
(item) => item.condition === 2 && item.product.productType === (1 || 3)
);
const hasPhysical =
data.filter((item) => item.product.productType === 2).length > 0
? true
: false;
return {
...state,
loading: false,
list: data,
checkEmpty: checkEmpty.length > 0 ? false : true,
error: null,
hasPhysical: hasPhysical,
};
case "userProduct/info":
return { ...state, loading: false, info: data, error: null };
case "userProduct/update":
return { ...state, loading: false, error: null };
case "userProduct/add":
// if (window.location.pathname.indexOf("products") !== -1) {
// toast.success("درخواست شما با موفقیت انجام شد.");
// }
return { ...state, loading: false, error: null, sum: data.payPrice };
case "userProduct/delete":
return { ...state, loading: false, error: null };
case "userProduct/loading":
return { ...state, loading: true };
case "userProduct/error":
// toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -1,10 +1,18 @@
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { applyMiddleware, createStore, compose } from "redux"; import { applyMiddleware, createStore, compose, combineReducers } from "redux";
import { createLogger } from "redux-logger"; import { createLogger } from "redux-logger";
import thunk from "redux-thunk"; import thunk from "redux-thunk";
import { persistStore, persistReducer } from "redux-persist"; import { persistStore, persistReducer } from "redux-persist";
import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2"; import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2";
import allReducers from "../reducers"; import publicApi from "./reducers/public";
import user from "./reducers/user";
import book from "./reducers/book";
import blog from "./reducers/blog";
import product from "./reducers/product";
import faq from "./reducers/faq";
import file from "./reducers/file";
import userFactor from "./reducers/userFactor";
import userProduct from "./reducers/userProduct";
const persistConfig = { const persistConfig = {
key: "root", key: "root",
@ -12,18 +20,34 @@ const persistConfig = {
stateReconciler: autoMergeLevel2, // see "Merge Process" section for details. stateReconciler: autoMergeLevel2, // see "Merge Process" section for details.
whitelist: ["profile"], whitelist: ["profile"],
}; };
const pReducer = persistReducer(persistConfig, allReducers);
const middleWare = []; const initialState = {};
middleWare.push(thunk); const middleWare = [thunk];
const loggerMiddleware = createLogger({ const loggerMiddleware = createLogger({
predicate: () => process.env.NODE_ENV === "development", predicate: () => process.env.NODE_ENV === "development",
}); });
middleWare.push(loggerMiddleware); middleWare.push(loggerMiddleware);
const store = createStore(pReducer, compose(applyMiddleware(...middleWare))); const store = createStore(
persistReducer(
persistConfig,
combineReducers({
publicApi,
user,
book,
blog,
product,
faq,
file,
userFactor,
userProduct,
})
),
initialState,
compose(applyMiddleware(...middleWare))
);
const persistor = persistStore(store); const persistor = persistStore(store);
@ -32,9 +56,9 @@ try {
ReactNative.I18nManager.allowRTL(true); ReactNative.I18nManager.allowRTL(true);
// enableScreens(); // enableScreens();
} catch (e) { } catch (e) {
console.log(e); // console.log(e);
} }
console.disableYellowBox = true; // console.disableYellowBox = true;
export default store; export default store;

@ -25,7 +25,7 @@ function Scroll({ products }) {
horizontal={true} horizontal={true}
inverted={true} inverted={true}
style={[tw("mt-3 pb-2")]} style={[tw("mt-3 pb-2")]}
data={[{}]} data={[{id : 0}]}
renderItem={({}) => <Box products={products} />} renderItem={({}) => <Box products={products} />}
keyExtractor={(item) => item.id} keyExtractor={(item) => item.id}
/> />

@ -1,57 +1,46 @@
import React, { useState } from "react"; import React, { useState } from "react";
import {connect} from 'react-redux';
import { import {
View, View,
Text, Text,
Image, Image,
ActivityIndicator, ActivityIndicator,
Dimensions, Dimensions,
TextInput,
TouchableHighlight, TouchableHighlight,
} from "react-native"; } from "react-native";
import Logo from "./assets/logo.png"; import Logo from "./assets/logo.png";
import CustomTextInput from "../../components/CustomTextInput"; import CustomTextInput from "../../components/CustomTextInput";
import { digitToEn, digitToPersian } from "../../utils"; import onInput from '../../utils/onInput';
import services from "./services";
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers"; import { asyncAwesomeAlert } from "../../utils/AsyncWrappers";
import tw from "tailwind-rn"; import tw from "tailwind-rn";
import {user} from '../../redux/actions';
const { width, height } = Dimensions.get("window"); const { width, height } = Dimensions.get("window");
let faNums = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"];
function Login(props) { function Login(props) {
const [phone, setPhone] = useState(""); const [phone, setPhone] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const onChangePhone = (name, value) => { const onChangePhone = (name, value) => {
let items = digitToPersian(value).split(""); setPhone(() => value);
for (let item of items) {
if (!faNums.includes(item)) {
return;
}
}
setPhone(digitToPersian(value));
}; };
const checkPhoneNumber = () => { const checkPhoneNumber = () => {
return phone.split("").length === 11; return phone.split("").length === 11 && phone.slice(0, 2) === '09';
}; };
const submit = async () => { const submit = async () => {
setLoading(true); // setLoading(true);
if (!checkPhoneNumber()) { // if (!checkPhoneNumber()) {
setLoading(false); // setLoading(false);
return asyncAwesomeAlert("خطا", "شماره وارد شده اشتباه است", { // return asyncAwesomeAlert("خطا", "شماره وارد شده اشتباه است", {
showCancelButton: false, // showCancelButton: false,
}); // });
} // }
let res = await services.getSmsCode({ // props.sendPhoneNumber({cellphone : phone});
cellphone: digitToEn(phone), props.navigation.navigate("Otp", { phone: '09360467907' });
}); // setLoading(false);
if (res.ok) {
setLoading(false);
props.navigation.navigate("Otp", { phone: digitToEn(phone) });
}
setLoading(false);
}; };
return ( return (
@ -99,6 +88,7 @@ function Login(props) {
value={phone} value={phone}
onChange={onChangePhone} onChange={onChangePhone}
autoFocus={true} autoFocus={true}
regex={onInput.phonenumber}
/> />
</View> </View>
<TouchableHighlight <TouchableHighlight
@ -132,4 +122,13 @@ function Login(props) {
); );
} }
export default Login; const mapStateToProps = (state) => ({
})
const mapDispatchToProps = {
sendPhoneNumber : user.otp
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);

@ -1,10 +0,0 @@
import mocks from './mocks';
import mainServices from './services';
const mock = false;
let services = {...mainServices};
if (mock) {
services = mocks;
}
export default services;

@ -1,18 +0,0 @@
import { asyncAwesomeAlert, randomApiSleep } from '../../../utils/AsyncWrappers';
const data = {
};
const getSmsCode = async () => {
await randomApiSleep();
return {
ok: true,
data: data
};
};
const mocks = {getSmsCode};
export default mocks;

@ -1,13 +0,0 @@
import {nextFetchApi} from '../../../services/api';
const getSmsCode = async (obj) => {
return await nextFetchApi('/public/sendOTP', {
method: 'POST',
payload: obj
});
};
const mainServices = {
getSmsCode,
};
export default mainServices;

@ -4,21 +4,16 @@ import {
Text, Text,
Image, Image,
TextInput, TextInput,
TouchableHighlight,
Dimensions, Dimensions,
StyleSheet,
TouchableOpacity, TouchableOpacity,
ActivityIndicator, ActivityIndicator,
} from "react-native"; } from "react-native";
import tw from "tailwind-rn"; import tw from "tailwind-rn";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { connect } from "react-redux"; import { connect } from "react-redux";
import Logo from "../Login/assets/logo.png"; import Logo from "../Login/assets/logo.png";
import IranFlag from "../Login/components/IranFlag"; import { digitToEn } from "../../utils";
import { digitToEn, digitToPersian } from "../../utils"; import onInput from "../../utils/onInput";
import services from "./services"; import {user} from '../../redux/actions';
import { buildAction } from "../../reducers/DefaultReducer";
import { PROFILE_RECORD } from "../../actions/actionTypes";
const { width } = Dimensions.get("window"); const { width } = Dimensions.get("window");
let ref1; let ref1;
@ -28,15 +23,7 @@ let ref4;
let timer = 60; let timer = 60;
const mapStateToProps = (state) => {
return {
profile: state.profile,
};
};
function Otp(props) { function Otp(props) {
let faNums = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"];
const [firstCode, setFirstCode] = useState(""); const [firstCode, setFirstCode] = useState("");
const [secondCode, setSecondCode] = useState(""); const [secondCode, setSecondCode] = useState("");
const [thirdCode, setThirdCode] = useState(""); const [thirdCode, setThirdCode] = useState("");
@ -44,20 +31,7 @@ function Otp(props) {
const [time, setTime] = useState(60); const [time, setTime] = useState(60);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
// useEffect(() => {
// if (fourthCode) {
// submit();
// }
// }, [fourthCode]);
const checkValue = (value) => {
return faNums.includes(digitToPersian(value));
};
const onChangeCode = (value, key) => { const onChangeCode = (value, key) => {
// if (!checkValue()) {
// return
// }
switch (key) { switch (key) {
case "1": case "1":
setFirstCode(value); setFirstCode(value);
@ -104,39 +78,17 @@ function Otp(props) {
const submit = async () => { const submit = async () => {
setLoading(true); setLoading(true);
let res = await services.sendOtpCode({ props.sendOtp({
cellphone: props.route.params.phone, cellphone: props.route.params.phone,
otp: String(getEnCode()), otp: String(getEnCode()),
applicationToken: "1", applicationToken: "1",
userToken: "1", userToken: "1",
}); });
console.log(
digitToEn(firstCode) +
digitToEn(secondCode) +
digitToEn(thirdCode) +
digitToEn(fourthCode)
);
if (res.ok) {
setLoading(false);
await AsyncStorage.setItem("accessToken", res.data.accessToken);
await AsyncStorage.setItem("refreshToken", res.data.refreshToken);
let action = buildAction(PROFILE_RECORD);
await props.dispatch(
action({
accessToken: res.data.accessToken,
refreshToken: res.data.refreshToken,
...res.data.profile,
})
);
props.navigation.reset({
index: 0,
routes: [{ name: "Root" }],
});
}
setLoading(false); setLoading(false);
}; };
useEffect(() => { useEffect(() => {
ref1.focus();
let interval = setInterval(() => { let interval = setInterval(() => {
if (time > 0) { if (time > 0) {
setTime(timer - 1); setTime(timer - 1);
@ -152,6 +104,12 @@ function Otp(props) {
}; };
}, []); }, []);
// useEffect(() => {
// if (props.isLogin) {
// props.navigation.navigate('Root');
// }
// }, [props.isLogin]);
return ( return (
<View style={[tw("px-4 flex-1 justify-center items-center bg-white")]}> <View style={[tw("px-4 flex-1 justify-center items-center bg-white")]}>
<Image <Image
@ -188,7 +146,9 @@ function Otp(props) {
value={firstCode} value={firstCode}
maxLength={1} maxLength={1}
ref={(ref) => (ref1 = ref)} ref={(ref) => (ref1 = ref)}
onChangeText={(text) => onChangeCode(text, "1")} onChangeText={(text) =>
onChangeCode(text, "1")
}
/> />
<TextInput <TextInput
style={[ style={[
@ -199,7 +159,9 @@ function Otp(props) {
value={secondCode} value={secondCode}
maxLength={1} maxLength={1}
ref={(ref) => (ref2 = ref)} ref={(ref) => (ref2 = ref)}
onChangeText={(text) => onChangeCode(text, "2")} onChangeText={(text) =>
onChangeCode(text, "2")
}
/> />
<TextInput <TextInput
style={[ style={[
@ -210,7 +172,9 @@ function Otp(props) {
value={thirdCode} value={thirdCode}
maxLength={1} maxLength={1}
ref={(ref) => (ref3 = ref)} ref={(ref) => (ref3 = ref)}
onChangeText={(text) => onChangeCode(text, "3")} onChangeText={(text) =>
onChangeCode(text, "3")
}
/> />
<TextInput <TextInput
style={[ style={[
@ -221,7 +185,9 @@ function Otp(props) {
value={fourthCode} value={fourthCode}
maxLength={1} maxLength={1}
ref={(ref) => (ref4 = ref)} ref={(ref) => (ref4 = ref)}
onChangeText={(text) => onChangeCode(text, "4")} onChangeText={(text) =>
onChangeCode(text, "4")
}
/> />
</View> </View>
<TouchableOpacity <TouchableOpacity
@ -261,12 +227,7 @@ function Otp(props) {
style={{ style={{
marginTop: 20, marginTop: 20,
}} }}
onPress={() => { onPress={() => props.navigation.navigate("Login")}
props.navigation.reset({
index: 0,
routes: [{ name: "Login" }],
});
}}
> >
<Text <Text
style={{ style={{
@ -284,4 +245,12 @@ function Otp(props) {
); );
} }
export default connect(mapStateToProps)(Otp); const mapStateToProps = (state) => ({
isLogin: state.user.status,
});
const mapDispatchToProps = {
sendOtp: user.otp_login,
};
export default connect(mapStateToProps, mapDispatchToProps)(Otp);

@ -1,10 +0,0 @@
import mocks from './mocks';
import mainServices from './services';
const mock = false;
let services = {...mainServices};
if (mock) {
services = mocks;
}
export default services;

@ -1,18 +0,0 @@
import { asyncAwesomeAlert, randomApiSleep } from '../../../utils/AsyncWrappers';
const data = {
};
const sendOtpCode = async () => {
await randomApiSleep();
return {
ok: true,
data: data
};
};
const mocks = {sendOtpCode};
export default mocks;

@ -1,13 +0,0 @@
import {nextFetchApi} from '../../../services/api';
const sendOtpCode = async (obj) => {
return await nextFetchApi('/user/otp/login', {
method: 'POST',
payload: obj
});
};
const mainServices = {
sendOtpCode,
};
export default mainServices;

@ -5,7 +5,6 @@ import tw from "tailwind-rn";
const width = Dimensions.get("window").width; const width = Dimensions.get("window").width;
export default function Commnets({ comments }) { export default function Commnets({ comments }) {
console.log(comments);
return ( return (
<FlatList <FlatList
horizontal={true} horizontal={true}
@ -19,7 +18,6 @@ export default function Commnets({ comments }) {
} }
const Comment = ({ comment }) => { const Comment = ({ comment }) => {
console.log(comment);
return ( return (
<View <View
style={[ style={[

@ -5,26 +5,17 @@ import Logo from "../../assets/images/logo.png";
const { width, height } = Dimensions.get("window"); const { width, height } = Dimensions.get("window");
const mapStateToProps = (state) => { function Splash({ navigation, isLogin, loading}) {
return {
profile: state.profile,
};
};
function Splash({ navigation, profile }) {
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {
!profile.accessToken !isLogin
? navigation.reset({ ? navigation.navigate('Login')
index: 0, : navigation.navigate('Root');
routes: [{ name: "Login" }],
})
: navigation.reset({
index: 0,
routes: [{ name: "Root" }],
});
}, 2000); }, 2000);
}, [profile]);
}, [isLogin]);
return ( return (
<View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}> <View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}>
@ -40,4 +31,11 @@ function Splash({ navigation, profile }) {
); );
} }
export default connect(mapStateToProps)(Splash); const mapStateToProps = (state) => ({
isLogin: state.user.status,
loading : state.userProduct.loading,
});
const mapDispatchToProps = {};
export default connect(mapStateToProps, mapDispatchToProps)(Splash);

@ -1,13 +1,68 @@
import React from 'react' import React, { useState } from "react";
import { View, Text } from 'react-native'; import {
import {connect} from 'react-redux'; View,
StyleSheet,
Dimensions,
ScrollView,
SafeAreaView,
StatusBar,
Platform,
LayoutAnimation
} from "react-native";
import tw from "tailwind-react-native-classnames";
import Navbar from "../../components/Navbar";
import Drawer from "../../components/Drawer";
import Search from "../../components/Search";
//assets
const width = Dimensions.get("window").width;
function Videos(props) {
const [search, setSearch] = useState("");
const [position, setPosition] = useState("100%");
const setBoxPosition = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setPosition(position === "100%" ? "0%" : "100%");
};
function Videos({}) {
return ( return (
<View> <SafeAreaView
<Text></Text> style={{
</View> paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
) position: "relative",
}}
>
<Navbar setBoxPosition={setBoxPosition} />
<Drawer setBoxPosition={setBoxPosition} position={position} />
<ScrollView
contentContainerStyle={styles.contentContainerStyle}
style={[styles.container, { width: width }]}
>
<Search
value={search}
onChange={setSearch}
placeholder={"نام کتاب یا دوره را جستجو کنید"}
/>
</ScrollView>
</SafeAreaView>
);
} }
// Later on in your styles..
const styles = StyleSheet.create({
contentContainerStyle: {
paddingBottom: 100,
alignItems: "flex-end",
},
container: {
width: Dimensions.get("window").width,
backgroundColor: "white",
flexDirection: "column",
paddingVertical: 0,
paddingHorizontal: 16,
},
});
export default Videos; export default Videos;

@ -1,3 +0,0 @@
export default {
dev: 'https://dnvn.ir/api/v1',
};

@ -1,118 +0,0 @@
'use strict';
module.exports = function (fetch, defaults) {
defaults = defaults || {};
if (typeof fetch !== 'function') {
throw new ArgumentError('fetch must be a function');
}
if (typeof defaults !== 'object') {
throw new ArgumentError('defaults must be an object');
}
if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {
throw new ArgumentError('retries must be a positive integer');
}
if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {
throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
}
if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {
throw new ArgumentError('retryOn property expects an array or function');
}
var baseDefaults = {
retries: 3,
retryDelay: 1000,
retryOn: [500, 502, 503, 504],
};
defaults = Object.assign(baseDefaults, defaults);
return function fetchRetry(input, init) {
var retries = defaults.retries;
var retryDelay = defaults.retryDelay;
var retryOn = defaults.retryOn;
if (init && init.retries !== undefined) {
if (isPositiveInteger(init.retries)) {
retries = init.retries;
} else {
throw new ArgumentError('retries must be a positive integer');
}
}
if (init && init.retryDelay !== undefined) {
if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {
retryDelay = init.retryDelay;
} else {
throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
}
}
if (init && init.retryOn) {
if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {
retryOn = init.retryOn;
} else {
throw new ArgumentError('retryOn property expects an array or function');
}
}
// eslint-disable-next-line no-undef
return new Promise(function (resolve, reject) {
var wrappedFetch = function (attempt) {
fetch(input, init)
.then(function (response) {
if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {
resolve(response);
} else if (typeof retryOn === 'function') {
if (retryOn(attempt, null, response)) {
retry(attempt, null, response);
} else {
resolve(response);
}
} else {
if (attempt < retries) {
retry(attempt, null, response);
} else {
resolve(response);
}
}
})
.catch(function (error) {
if (typeof retryOn === 'function') {
if (retryOn(attempt, error, null)) {
retry(attempt, error, null);
} else {
reject(error);
}
} else if (attempt < retries) {
retry(attempt, error, null);
} else {
reject(error);
}
});
};
function retry(attempt, error, response) {
var delay = (typeof retryDelay === 'function') ?
retryDelay(attempt, error, response) : retryDelay;
setTimeout(function () {
wrappedFetch(++attempt);
}, delay);
}
wrappedFetch(0);
});
};
};
function isPositiveInteger(value) {
return Number.isInteger(value) && value >= 0;
}
function ArgumentError(message) {
this.name = 'ArgumentError';
this.message = message;
}

@ -1,149 +0,0 @@
import {Alert} from 'react-native';
import {toastMessage} from '../../utils/message';
import {
restartApp,
getToken,
deviceHeaders,
getUrl,
isUnexpected,
renewTokenHandler,
resetApp,
networkAlert,
unexpectedAlert,
} from './utils';
import FetchRetry from './fetch-retry';
import {asyncApiAwesomeAlert} from '../../utils/AsyncWrappers';
const fetchRetry = FetchRetry(fetch, {});
let deviceInfo;
export async function fetchApi(
endPoint,
payload = {},
method = 'GET',
headers = {},
isS = false,
splash = false,
dev = 'production',
) {
var timeout = setTimeout(() => {
console.log(endPoint, ' TIMEOUT ');
asyncApiAwesomeAlert('خطای ارتباط', '. لطفا اینترنت خود را بررسی کنید .').then(
async () => await fetchApi(endPoint, payload, method, headers, isS),
);
}, 30000);
if (!deviceInfo) {
deviceInfo = await deviceHeaders();
if (!deviceInfo) {
deviceInfo = [];
}
}
let options = {
method,
headers: {
Accept: 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
Authorization: await getToken(),
...deviceInfo,
...headers,
},
};
if (['POST', 'PUT'].includes(method)) {
options.body = JSON.stringify(payload);
}
console.log('===========================')
console.log(await getUrl(endPoint, dev))
console.log(options)
console.log('===========================')
try {
// console.log('req', await getUrl(endPoint), options)
let res = await fetchRetry(await getUrl(endPoint, dev), options);
clearTimeout(timeout);
let statusCode = res.status;
// console.log('RES', { statusCode, url: await getUrl(endPoint) })
if (isUnexpected(statusCode)) {
console.log('unexpected', await res.json());
console.log('RES-unexpected', {statusCode, url: await getUrl(endPoint)});
let check = await unexpectedAlert();
return await fetchApi(
endPoint,
payload,
method,
headers,
isS,
false,
true,
);
}
let {data, error, status} = await res.json();
if (res.ok) {
return data;
}
if (!res.ok) {
// if (data.hasOwnProperty('message')) {
// toastMessage(data.message);
// }
console.log('=====================')
console.log(statusCode)
console.log(data)
console.log(error)
console.log('=====================')
if (statusCode === 403) {
console.log('req-401', await getUrl(endPoint), options);
return resetApp();
}
if (statusCode === 401) {
let checkRenew = await renewTokenHandler();
if (!checkRenew.ok && checkRenew.restart) {
console.log('req-401', await getUrl(endPoint), options);
resetApp();
} else if (!checkRenew.ok) {
console.log('req-401', await getUrl(endPoint), options);
restartApp();
}
return await fetchApi(endPoint, payload, method, headers, isS, splash);
}
if (statusCode === 400) {
return error;
}
return data;
}
} catch (err) {
clearTimeout(timeout);
console.log('catch', endPoint, err);
// global.globalAlert({
// show: true
// })
let check = await networkAlert();
return await fetchApi(endPoint, payload, method, headers, isS);
}
}
/**
* next version of fetch API
* @param {String} endPoint
* @param {Object} options
* @param {string} options.method
* @param {string} options.payload
* @param {string} options.headers
* @param {Boolean} options.splash
*/
export async function nextFetchApi(endPoint, options = {}) {
let {payload, method, headers, isS, splash} = options;
try {
let res = await fetchApi(endPoint, payload, method, headers, isS, splash);
return {
ok: true,
data: res,
};
} catch (error) {
return {
ok: false,
data: error,
};
}
}

@ -1,203 +0,0 @@
/* global fetch */
import apiConfig from './config';
import {
Alert,
AlertIOS,
Platform,
ToastAndroid,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {toastMessage} from '../../utils/message';
import RNRestart from 'react-native-restart';
import config from './config';
import Refresh from './fetch-retry';
import FetchRetry from './fetch-retry';
let fetchRetry = FetchRetry(fetch, {});
function restartApp() {
AsyncStorage.setItem('UID_USER', JSON.stringify({}), () => {
RNRestart.Restart();
});
}
export function fetchApi(
endPoint,
payload = {},
method = 'GET',
headers = {},
isS = false,
splash = false,
) {
return new Promise((resolve, reject) => {
var timeout = setTimeout(() => {
console.log(endPoint, ' TIMEOUT ');
Alert.alert('خطای ارتباط', 'خطایی ارتباط با سرور پیش امده .', [
{
text: 'تلاش مجدد',
onPress: () =>
resolve(fetchApi(endPoint, payload, method, headers, isS)),
},
]);
}, 10000);
AsyncStorage.getItem('UID_USER', (err, result) => {
var tokens = '';
var refreshTokens = '';
var userDATA = JSON.parse(result);
var headrsRequest = {};
if (
userDATA != null &&
userDATA.token != null &&
userDATA.token != '' &&
isS
) {
tokens = userDATA.token;
refreshTokens = userDATA.refresh_token;
headers = {
Authorization: 'Bearer ' + tokens,
};
}
if (method === 'POST' || method === 'PUT') {
headrsRequest = {
method: method,
headers: {
Accept: 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
...headers,
},
body: JSON.stringify(payload),
};
} else {
headrsRequest = {
method: method,
headers: {
Accept: 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
...headers,
},
};
}
AsyncStorage.getItem('SPLASH_DATA', (err, result) => {
var splashDATA = JSON.parse(result);
var baseUrl;
if (endPoint.includes('splash')) {
baseUrl = apiConfig.splash;
} else {
var baseUrl = splashDATA.base_urls.backend + '/v1.1';
}
fetchRetry(`${baseUrl}${endPoint}`, headrsRequest)
.then(response => {
const statusCode = response.status;
const data = response.json();
return Promise.all([statusCode, data]);
})
.then(([statusCode, data]) => {
console.log(baseUrl + endPoint, statusCode, data);
if (data.hasOwnProperty('message')) {
toastMessage(data.message);
}
if (statusCode === 403) {
clearTimeout(timeout);
restartApp();
}
if (statusCode === 401) {
clearTimeout(timeout);
var dataaaaa = {
method: 'POST',
body: JSON.stringify({
refresh_token: refreshTokens,
}),
headers: {
Accept: 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8',
},
};
fetchRetry(`${baseUrl}/auth/renew-token`, dataaaaa)
.then(response1 => {
const statusCode1 = response1.status;
const data1 = response1.json();
return Promise.all([statusCode1, data1]);
})
.then(([statusCode1, data1]) => {
console.log(
'refresh token call and response is ',
statusCode1,
data1,
refreshTokens,
);
if (statusCode1 == 200) {
userDATA.token = data1.data.token;
AsyncStorage.setItem(
'UID_USER',
JSON.stringify(userDATA),
() => {
resolve(
fetchApi(endPoint, payload, method, headers, isS),
);
},
);
} else {
restartApp();
}
})
.catch(e => restartApp());
}
if (statusCode === 400) {
toastMessage(data.error.message);
clearTimeout(timeout);
reject(data.error);
}
if (statusCode === 200) {
clearTimeout(timeout);
resolve(data.data);
}
if (statusCode === 201) {
clearTimeout(timeout);
resolve(data.data);
}
return data;
})
.catch(async e => {
console.log('e', error.message);
let res = await neto();
if (e.networkError) {
toastMessage('اشکال در اتصال اینترنت دوباره تلاش کنید .');
Alert.alert(
'اینترنت',
'اشکال در اتصال اینترنت دوباره تلاش کنید .',
[
{
text: 'تلاش مجدد',
onPress: () =>
resolve(
fetchApi(endPoint, payload, method, headers, isS),
),
},
{text: 'بیخیال', onPress: () => reject(e)},
],
);
}
});
});
});
});
}

@ -1,145 +0,0 @@
import RNRestart from 'react-native-restart';
import { toastMessage } from "../../utils/message"
import { asyncAlert, asyncAwesomeAlert, asyncApiAwesomeAlert } from "../../utils/AsyncWrappers";
import * as Device from 'expo-device';
import {
ImageBackground,
Text,
Image,
View,
SafeAreaView,
StyleSheet,
BackHandler,
Platform,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import apiConfig from './config';
import FetchRetry from './fetch-retry'
import { nextFetchApi } from '.';
const fetchRetry = FetchRetry(fetch, {})
export const restartApp = () => {
RNRestart.Restart()
}
export const resetApp = () => {
AsyncStorage.setItem('UID_USER', JSON.stringify({}), () => {
RNRestart.Restart()
});
}
export const networkAlert = async () => {
return await asyncApiAwesomeAlert("خطا", "خطا در اتصال به اینترنت", {
confirmText: "تلاش مجدد"
})
}
export const unexpectedAlert = async () => {
return await asyncApiAwesomeAlert("خطا", "خطای داخلی سرور!", {
confirmText: "تلاش مجدد"
})
// return await asyncAlert("خطا","خطای داخلی سرور!", [
// { text: "تلاش مجدد", value: 'retry' },
// // { text: "بیخیال", value: 'ignore' }
// ])
}
export const getToken = async () => {
let token = await AsyncStorage.getItem('accessToken')
if (!token) {
return ''
}
return 'Bearer ' + token
}
export const deviceHeaders = async () => {
return {
'dev-os': Platform.OS,
'dev-app-version': '1.6.0',
'dev-os-version': Platform.Version + '',
'dev-phone-manufacturer': Device.brand,
'dev-phone-model': Device.modelName,
'dev-phone-hash': Device.modelId,
}
}
export const getUrl = async (endpoint, dev) => {
if (endpoint.includes('splash')) {
if (dev === 'dev') {
return apiConfig.dev + endpoint
}
return apiConfig.splash + endpoint
}
let base_urls = await getBaseUrls()
return base_urls + endpoint
}
export const isUnexpected = (statusCode) => {
if (![200, 201, 400, 401, 403].includes(statusCode)) return true
return false
}
export const renewTokenHandler = async () => {
try {
let refreshToken = JSON.parse(await AsyncStorage.getItem('refreshToken'))
if (!refreshToken) {
return {
ok: false,
restart: true
}
}
const options = {
method: 'POST',
body: JSON.stringify({
refresh_token: refreshToken
}),
headers: {
Accept: 'application/json;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8'
}
}
let res = await fetchRetry(await getUrl('/user/login'), options)
let { data } = await res.json()
const statusCode = res.status
if (statusCode == 200) {
await AsyncStorage.setItem('refreshToken', JSON.stringify(data.refreshToken))
await AsyncStorage.setItem('accessToken', JSON.stringify(data.accessToken))
return {
ok: true
}
}
if (statusCode == 400) {
return {
ok: false,
restart: true
}
}
return {
ok: false
}
} catch (error) {
return {
ok: false
}
}
}
export const getBaseUrls = async () => {
// let { base_urls } = JSON.parse((await AsyncStorage.getItem('SPLASH_DATA')))
return apiConfig.dev
}
export const getCachedProfile = async () => {
return JSON.parse(await AsyncStorage.getItem('UID_USER'))
}
export const cacheProfile = async () => {
let data = await getProfile()
let oldData = await getCachedProfile()
if (data) {
await AsyncStorage.removeItem('UID_USER')
await AsyncStorage.setItem('UID_USER', JSON.stringify({
...oldData,
...data
}))
}
}
export const getProfile = async () => {
let { ok, data } = await nextFetchApi('/profile?with_details=1&no_cache=1')
if (!ok) return null
return data
}

@ -1,16 +0,0 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import { Platform } from "react-native";
import resources from './locales'
i18n.use(initReactI18next).init({
resources: resources,
lng: "fa",
fallbackLng: "fa",
compatibilityJSON: Platform.OS === 'android' ? 'v3' : '',
interpolation: {
escapeValue: false
}
});
export default i18n;

@ -1,28 +0,0 @@
{
"main": {
"home": "Home",
"settings": "Settings",
"profile": "Profile",
"filter": "filter"
},
"filter": {
"newest": "newest",
"oldest": "oldest"
},
"profile": {
"first name": "first name",
"last name": "last name",
"birthday": "birthday",
"gender": "gender",
"addresses": "addresses",
"day": "day",
"month": "month",
"year": "year",
"male": "male",
"female": "female",
"submit changes": "submit changes"
},
"settings": {
"language": "language"
}
}

@ -1,29 +0,0 @@
{
"main": {
"home": "صفحه اصلی",
"books": "کتاب ها",
"videos": "ویدئوها",
"exams": "آزمون ها",
"profile": "حساب کاربری"
},
"filter": {
"newest": "جدیدترین",
"oldest": "قدیمی ترین"
},
"profile": {
"first name": "نام",
"last name": "نام خانوادگی",
"birthday": "تاریخ تولد",
"gender": "جنسیت",
"addresses": "آدرس ها",
"day": "روز",
"month": "ماه",
"year": "سال",
"male": "آقا",
"female": "خانم",
"submit changes": "ثبت تغییرات"
},
"settings": {
"language": "زبان"
}
}

@ -1,11 +0,0 @@
import en from './en/translation.json';
import fa from './fa/translation.json';
export default {
en: {
translation: en
},
fa: {
translation: fa
}
}

@ -1,4 +1,4 @@
import { AsyncStorage, AlertIOS, Platform, ToastAndroid, } from "react-native" import { AlertIOS, Platform, ToastAndroid, } from "react-native"
export const toastMessage = (msg) => { export const toastMessage = (msg) => {
if (Platform.OS === 'android') { if (Platform.OS === 'android') {

@ -0,0 +1,280 @@
class onInput {
persianOnly = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "");
newText = newText.replace(/1/g, "");
newText = newText.replace(/2/g, "");
newText = newText.replace(/3/g, "");
newText = newText.replace(/4/g, "");
newText = newText.replace(/5/g, "");
newText = newText.replace(/6/g, "");
newText = newText.replace(/7/g, "");
newText = newText.replace(/8/g, "");
newText = newText.replace(/9/g, "");
newText = newText.replace(/0/g, "");
newText = newText.replace(/q/g, "");
newText = newText.replace(/w/g, "");
newText = newText.replace(/e/g, "");
newText = newText.replace(/r/g, "");
newText = newText.replace(/t/g, "");
newText = newText.replace(/y/g, "");
newText = newText.replace(/u/g, "");
newText = newText.replace(/i/g, "");
newText = newText.replace(/o/g, "");
newText = newText.replace(/p/g, "");
newText = newText.replace(/\[/g, "");
newText = newText.replace(/\]/g, "");
newText = newText.replace(/a/g, "");
newText = newText.replace(/s/g, "");
newText = newText.replace(/d/g, "");
newText = newText.replace(/f/g, "");
newText = newText.replace(/g/g, "");
newText = newText.replace(/h/g, "");
newText = newText.replace(/j/g, "");
newText = newText.replace(/k/g, "");
newText = newText.replace(/l/g, "");
newText = newText.replace(/;/g, "");
newText = newText.replace(/'/g, "");
newText = newText.replace(/z/g, "");
newText = newText.replace(/x/g, "");
newText = newText.replace(/c/g, "");
newText = newText.replace(/v/g, "");
newText = newText.replace(/b/g, "");
newText = newText.replace(/n/g, "");
newText = newText.replace(/m/g, "");
newText = newText.replace(/,/g, "");
newText = newText.replace(/./g, "");
newText = newText.replace(/\//g, "");
newText = newText.replace(/~/g, " ");
newText = newText.replace(/Q/g, "");
newText = newText.replace(/W/g, "");
newText = newText.replace(/E/g, "");
newText = newText.replace(/R/g, "");
newText = newText.replace(/T/g, "");
newText = newText.replace(/Y/g, "");
newText = newText.replace(/U/g, "");
newText = newText.replace(/I/g, "");
newText = newText.replace(/O/g, "");
newText = newText.replace(/P/g, "");
newText = newText.replace(/A/g, "");
newText = newText.replace(/S/g, "");
newText = newText.replace(/G/g, "");
newText = newText.replace(/H/g, "");
newText = newText.replace(/J/g, "");
newText = newText.replace(/K/g, "");
newText = newText.replace(/L/g, "");
newText = newText.replace(/Z/g, "");
newText = newText.replace(/X/g, "");
newText = newText.replace(/B/g, "");
newText = newText.replace(/N/g, "");
newText = newText.replace(/M/g, "");
newText = newText.replace(/\?/g, "");
if (!newText && newText.length !== 0) {
// toast.info("از کاراکتر فارسی استفاده کنید");
}
return newText;
};
englishAndNumberWithoutSpace = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "0");
newText = newText.replace(/1/g, "1");
newText = newText.replace(/2/g, "2");
newText = newText.replace(/3/g, "3");
newText = newText.replace(/4/g, "4");
newText = newText.replace(/5/g, "5");
newText = newText.replace(/6/g, "6");
newText = newText.replace(/7/g, "7");
newText = newText.replace(/8/g, "8");
newText = newText.replace(/9/g, "9");
newText = newText.replace(/ا/g, "");
newText = newText.replace(/ب/g, "");
newText = newText.replace(/پ/g, "");
newText = newText.replace(/ت/g, "");
newText = newText.replace(/ث/g, "");
newText = newText.replace(/ج/g, "");
newText = newText.replace(/چ/g, "");
newText = newText.replace(/ح/g, "");
newText = newText.replace(/خ/g, "");
newText = newText.replace(/د/g, "");
newText = newText.replace(/\[/g, "");
newText = newText.replace(/\]/g, "");
newText = newText.replace(/ذ/g, "");
newText = newText.replace(/ر/g, "");
newText = newText.replace(/ز/g, "");
newText = newText.replace(/ژ/g, "");
newText = newText.replace(/ط/g, "");
newText = newText.replace(/ظ/g, "");
newText = newText.replace(/ع/g, "");
newText = newText.replace(/غ/g, "");
newText = newText.replace(/ف/g, "");
newText = newText.replace(/;/g, "");
newText = newText.replace(/'/g, "");
newText = newText.replace(/ق/g, "");
newText = newText.replace(/س/g, "");
newText = newText.replace(/ش/g, "");
newText = newText.replace(/ص/g, "");
newText = newText.replace(/ض/g, "");
newText = newText.replace(/ک/g, "");
newText = newText.replace(/گ/g, "");
newText = newText.replace(/,/g, "");
newText = newText.replace(/\./g, "");
newText = newText.replace(/\//g, "");
newText = newText.replace(/~/g, " ");
newText = newText.replace(/ل/g, "");
newText = newText.replace(/م/g, "");
newText = newText.replace(/ن/g, "");
newText = newText.replace(/و/g, "");
newText = newText.replace(/ه/g, "");
newText = newText.replace(/ی/g, "");
newText = newText.replace(/\?/g, "");
if (!newText && newText.length !== 0) {
// toast.info("از کاراکتر انگلیسی واعداداستفاده کنید");
}
return newText;
};
numberOnly = (txt) => {
let newText = txt;
newText = newText.replace(/`/g, "");
newText = newText.replace(/0/g, "0");
newText = newText.replace(/1/g, "1");
newText = newText.replace(/2/g, "2");
newText = newText.replace(/3/g, "3");
newText = newText.replace(/4/g, "4");
newText = newText.replace(/5/g, "5");
newText = newText.replace(/6/g, "6");
newText = newText.replace(/7/g, "7");
newText = newText.replace(/8/g, "8");
newText = newText.replace(/9/g, "9");
newText = newText.replace(/ا/g, "");
newText = newText.replace(/ب/g, "");
newText = newText.replace(/پ/g, "");
newText = newText.replace(/ت/g, "");
newText = newText.replace(/ث/g, "");
newText = newText.replace(/ج/g, "");
newText = newText.replace(/چ/g, "");
newText = newText.replace(/ح/g, "");
newText = newText.replace(/خ/g, "");
newText = newText.replace(/د/g, "");
newText = newText.replace(/\[/g, "");
newText = newText.replace(/\]/g, "");
newText = newText.replace(/ذ/g, "");
newText = newText.replace(/ر/g, "");
newText = newText.replace(/ز/g, "");
newText = newText.replace(/ژ/g, "");
newText = newText.replace(/ط/g, "");
newText = newText.replace(/ظ/g, "");
newText = newText.replace(/ع/g, "");
newText = newText.replace(/غ/g, "");
newText = newText.replace(/ف/g, "");
newText = newText.replace(/;/g, "");
newText = newText.replace(/'/g, "");
newText = newText.replace(/ق/g, "");
newText = newText.replace(/س/g, "");
newText = newText.replace(/ش/g, "");
newText = newText.replace(/ص/g, "");
newText = newText.replace(/ض/g, "");
newText = newText.replace(/ک/g, "");
newText = newText.replace(/گ/g, "");
newText = newText.replace(/\,/g, "");
newText = newText.replace(/\./g, "");
newText = newText.replace(/\//g, "");
newText = newText.replace(/~/g, " ");
newText = newText.replace(/ل/g, "");
newText = newText.replace(/م/g, "");
newText = newText.replace(/ن/g, "");
newText = newText.replace(/و/g, "");
newText = newText.replace(/ه/g, "");
newText = newText.replace(/ی/g, "");
newText = newText.replace(/\?/g, "");
newText = newText.replace(/q/g, "");
newText = newText.replace(/w/g, "");
newText = newText.replace(/e/g, "");
newText = newText.replace(/r/g, "");
newText = newText.replace(/t/g, "");
newText = newText.replace(/y/g, "");
newText = newText.replace(/u/g, "");
newText = newText.replace(/i/g, "");
newText = newText.replace(/o/g, "");
newText = newText.replace(/p/g, "");
newText = newText.replace(/a/g, "");
newText = newText.replace(/s/g, "");
newText = newText.replace(/d/g, "");
newText = newText.replace(/f/g, "");
newText = newText.replace(/g/g, "");
newText = newText.replace(/h/g, "");
newText = newText.replace(/j/g, "");
newText = newText.replace(/k/g, "");
newText = newText.replace(/l/g, "");
newText = newText.replace(/z/g, "");
newText = newText.replace(/x/g, "");
newText = newText.replace(/c/g, "");
newText = newText.replace(/v/g, "");
newText = newText.replace(/b/g, "");
newText = newText.replace(/n/g, "");
newText = newText.replace(/m/g, "");
newText = newText.replace(/Q/g, "");
newText = newText.replace(/W/g, "");
newText = newText.replace(/E/g, "");
newText = newText.replace(/R/g, "");
newText = newText.replace(/T/g, "");
newText = newText.replace(/Y/g, "");
newText = newText.replace(/U/g, "");
newText = newText.replace(/I/g, "");
newText = newText.replace(/O/g, "");
newText = newText.replace(/P/g, "");
newText = newText.replace(/A/g, "");
newText = newText.replace(/S/g, "");
newText = newText.replace(/G/g, "");
newText = newText.replace(/H/g, "");
newText = newText.replace(/J/g, "");
newText = newText.replace(/K/g, "");
newText = newText.replace(/L/g, "");
newText = newText.replace(/Z/g, "");
newText = newText.replace(/X/g, "");
newText = newText.replace(/B/g, "");
newText = newText.replace(/N/g, "");
newText = newText.replace(/M/g, "");
if (!newText && newText.length !== 0) {
// toast.info("از اعداداستفاده کنید");
}
return newText;
};
dayHandler = (num) => {
let newNum = this.numberOnly(num);
if (newNum > 31) {
// toast.error("روز نباید بزرگتر از 31 باشد.");
return Math.floor(newNum / 10);
}
return newNum;
};
monthHandler = (num) => {
let newNum = this.numberOnly(num);
if (newNum > 12 || newNum < 0) {
// toast.error("ماه باید بین 1 تا 12 باشد.");
return Math.floor(newNum / 10);
}
return newNum;
};
yearHandler = (num) => {
let newNum = this.numberOnly(num);
if (newNum > 1395) {
// toast.error("سال باید کوچکتر از 1395 باشد.");
return Math.floor(newNum / 10);
}
return newNum;
};
phonenumber = (value) => {
let formattedValue = value
.replace(/[\u0660-\u0669\u06f0-\u06f9]/g, function (c) {
return c.charCodeAt(0) & 0xf;
})
.replace(/[^\d]/, "");
return formattedValue;
};
}
const _onInput = new onInput();
export default _onInput;

@ -1845,6 +1845,13 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios@^0.24.0:
version "0.24.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==
dependencies:
follow-redirects "^1.14.4"
babel-core@^7.0.0-bridge.0: babel-core@^7.0.0-bridge.0:
version "7.0.0-bridge.0" version "7.0.0-bridge.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
@ -3143,6 +3150,11 @@ flow-parser@^0.121.0:
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.121.0.tgz#9f9898eaec91a9f7c323e9e992d81ab5c58e618f" resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.121.0.tgz#9f9898eaec91a9f7c323e9e992d81ab5c58e618f"
integrity sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg== integrity sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==
follow-redirects@^1.14.4:
version "1.14.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.6.tgz#8cfb281bbc035b3c067d6cd975b0f6ade6e855cd"
integrity sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==
fontfaceobserver@^2.1.0: fontfaceobserver@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991" resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991"

Loading…
Cancel
Save