@ -1,20 +1,58 @@ |
||||
import { StatusBar } from 'expo-status-bar'; |
||||
import { StyleSheet, Text, View } from 'react-native'; |
||||
import React from "react"; |
||||
import { StyleSheet, useColorScheme } from "react-native"; |
||||
import AsyncStorage from "@react-native-async-storage/async-storage"; |
||||
import { Provider } from "react-redux"; |
||||
import { applyMiddleware, createStore, compose } from "redux"; |
||||
import { createLogger } from "redux-logger"; |
||||
import thunk from "redux-thunk"; |
||||
import { persistStore, persistReducer } from "redux-persist"; |
||||
import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2"; |
||||
import allReducers from "./src/reducers"; |
||||
import Navigator from "./navigation"; |
||||
import AlertModal from "./src/components/AlertModal"; |
||||
|
||||
const persistConfig = { |
||||
key: "root", |
||||
storage: AsyncStorage, |
||||
stateReconciler: autoMergeLevel2, // see "Merge Process" section for details.
|
||||
whitelist: ["profile"], |
||||
}; |
||||
const pReducer = persistReducer(persistConfig, allReducers); |
||||
|
||||
const middleWare = []; |
||||
|
||||
middleWare.push(thunk); |
||||
|
||||
const loggerMiddleware = createLogger({ |
||||
predicate: () => process.env.NODE_ENV === "development", |
||||
}); |
||||
middleWare.push(loggerMiddleware); |
||||
|
||||
const store = createStore(pReducer, compose(applyMiddleware(...middleWare))); |
||||
|
||||
const persistor = persistStore(store); |
||||
|
||||
const ReactNative = require("react-native"); |
||||
try { |
||||
ReactNative.I18nManager.allowRTL(true); |
||||
// enableScreens();
|
||||
} catch (e) { |
||||
console.log(e); |
||||
} |
||||
|
||||
console.disableYellowBox = true; |
||||
|
||||
const App = () => { |
||||
const isDarkMode = useColorScheme() === "dark"; |
||||
|
||||
export default function App() { |
||||
return ( |
||||
<View style={styles.container}> |
||||
<Text>Open up App.js to start working on your app!</Text> |
||||
<StatusBar style="auto" /> |
||||
</View> |
||||
<Provider store={store}> |
||||
<Navigator /> |
||||
<AlertModal /> |
||||
</Provider> |
||||
); |
||||
} |
||||
}; |
||||
|
||||
const styles = StyleSheet.create({ |
||||
container: { |
||||
flex: 1, |
||||
backgroundColor: '#fff', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
}, |
||||
}); |
||||
const styles = StyleSheet.create({}); |
||||
|
||||
export default App; |
||||
|
@ -0,0 +1,130 @@ |
||||
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 {connect} from 'react-redux'; |
||||
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) { |
||||
const {t} = useTranslation('translation', {keyPrefix: 'main'}); |
||||
|
||||
return ( |
||||
<Tab.Navigator initialRouteName={'Home'}> |
||||
<Tab.Screen |
||||
name={'Profile'} |
||||
component={Profile} |
||||
options={{ |
||||
title: t('profile'), |
||||
}} |
||||
/> |
||||
<Tab.Screen |
||||
name={'Exams'} |
||||
component={Exams} |
||||
options={{ |
||||
title: t('exams'), |
||||
}} |
||||
/> |
||||
<Tab.Screen |
||||
name={'Videos'} |
||||
component={Videos} |
||||
options={{ |
||||
title: t('videos'), |
||||
}} |
||||
/> |
||||
<Tab.Screen |
||||
name={'OrderDetails'} |
||||
component={OrderDetails} |
||||
options={{ |
||||
title: t('books'), |
||||
}} |
||||
/> |
||||
<Tab.Screen |
||||
name={'Home'} |
||||
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={Products} |
||||
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 connect(mapStateToProps)(Navigator); |
@ -0,0 +1,2 @@ |
||||
export const PROFILE_RECORD = 'PROFILE_RECORD'; |
||||
export const APP_CONFIG = 'APP_CONFIG'; |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 623 B |
After Width: | Height: | Size: 834 B |
After Width: | Height: | Size: 275 B |
After Width: | Height: | Size: 159 B |
After Width: | Height: | Size: 271 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 24 KiB |
@ -0,0 +1,137 @@ |
||||
import React, { useState } from "react" |
||||
import AwesomeAlert from 'react-native-awesome-alerts'; |
||||
const ReactNative = require('react-native'); |
||||
|
||||
const AlertModal = props => { |
||||
const [alert, setAlert] = useState({ |
||||
show: false, |
||||
showProgress: false, |
||||
title: "خطا", |
||||
message: "خطای ناشناخته", |
||||
closeOnTouchOutside: false, |
||||
closeOnHardwareBackPress: false, |
||||
showCancelButton: true, |
||||
showConfirmButton: true, |
||||
cancelText: "بیخیال", |
||||
confirmText: "باشه", |
||||
confirmButtonColor: "#2980b9", |
||||
onCancel: () => { |
||||
}, |
||||
onConfirm: () => { |
||||
|
||||
}, |
||||
}) |
||||
const [apiAlert, setApiAlert] = useState({ |
||||
show: false, |
||||
showProgress: false, |
||||
title: "خطا", |
||||
message: "خطای ناشناخته", |
||||
closeOnTouchOutside: false, |
||||
closeOnHardwareBackPress: false, |
||||
showCancelButton: true, |
||||
showConfirmButton: true, |
||||
cancelText: "بیخیال", |
||||
confirmText: "باشه", |
||||
confirmButtonColor: "#2980b9", |
||||
onCancel: () => { |
||||
}, |
||||
onConfirm: () => { |
||||
}, |
||||
}) |
||||
|
||||
global.globalAlert = (params) => { |
||||
setAlert({ |
||||
...alert, |
||||
...params |
||||
}) |
||||
} |
||||
global.globalApiAlert = (params) => { |
||||
|
||||
setApiAlert({ |
||||
...apiAlert, |
||||
...params |
||||
}) |
||||
} |
||||
|
||||
function hideAlert() { |
||||
setAlert({ ...alert, show: false }) |
||||
} |
||||
function onApiCancelPressed(){ |
||||
globalApiAlert({ show: false }) |
||||
|
||||
apiAlert.onCancel() |
||||
} |
||||
function onApiConfirmPressed(){ |
||||
globalApiAlert({ show: false }) |
||||
apiAlert.onConfirm() |
||||
} |
||||
function onCancelPressed(){ |
||||
hideAlert() |
||||
alert.onCancel() |
||||
} |
||||
function onConfirmPressed(){ |
||||
hideAlert() |
||||
alert.onConfirm() |
||||
} |
||||
return <> |
||||
<AwesomeAlert |
||||
show={alert.show} |
||||
progressColor="red" |
||||
showProgress={alert.showProgress} |
||||
title={alert.title} |
||||
message={alert.message} |
||||
closeOnTouchOutside={alert.closeOnTouchOutside} |
||||
closeOnHardwareBackPress={alert.closeOnHardwareBackPress} |
||||
showCancelButton={alert.showCancelButton} |
||||
showConfirmButton={alert.showConfirmButton} |
||||
cancelText={alert.cancelText} |
||||
confirmText={alert.confirmText} |
||||
confirmButtonColor={alert.confirmButtonColor} |
||||
onCancelPressed={onCancelPressed} |
||||
onConfirmPressed={(onConfirmPressed)} |
||||
contentStyle={{ |
||||
width: ReactNative.Dimensions.get('window').width / 1.5, |
||||
|
||||
}} |
||||
confirmButtonStyle={ |
||||
{ |
||||
width: ReactNative.Dimensions.get('window').width / 4, |
||||
alignItems: 'center', |
||||
justifyContent: 'center' |
||||
|
||||
} |
||||
} |
||||
useNativeDriver={true} |
||||
/> |
||||
<AwesomeAlert |
||||
show={apiAlert.show} |
||||
progressColor="red" |
||||
showProgress={apiAlert.showProgress} |
||||
title={apiAlert.title} |
||||
message={apiAlert.message} |
||||
closeOnTouchOutside={apiAlert.closeOnTouchOutside} |
||||
closeOnHardwareBackPress={apiAlert.closeOnHardwareBackPress} |
||||
showCancelButton={apiAlert.showCancelButton} |
||||
showConfirmButton={apiAlert.showConfirmButton} |
||||
cancelText={apiAlert.cancelText} |
||||
confirmText={apiAlert.confirmText} |
||||
confirmButtonColor={apiAlert.confirmButtonColor} |
||||
onCancelPressed={onApiCancelPressed} |
||||
onConfirmPressed={(onApiConfirmPressed)} |
||||
contentStyle={{ |
||||
width: ReactNative.Dimensions.get('window').width / 1.5 |
||||
}} |
||||
confirmButtonStyle={ |
||||
{ |
||||
width: ReactNative.Dimensions.get('window').width / 4, |
||||
alignItems: 'center', |
||||
justifyContent: 'center' |
||||
} |
||||
} |
||||
useNativeDriver={true} |
||||
/> |
||||
</> |
||||
|
||||
} |
||||
|
||||
export default AlertModal; |
@ -0,0 +1,59 @@ |
||||
import React, {useState} from 'react'; |
||||
import {TextInput, View, Text, Dimensions, StyleSheet} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
const FloatingLabelInput = ({ |
||||
label, |
||||
textAlign, |
||||
direction, |
||||
labelBackgroundColor, |
||||
onChange, |
||||
value, |
||||
name, |
||||
...props |
||||
}) => { |
||||
const [isFocused, setIsFocused] = useState(false); |
||||
const styles = StyleSheet.create({ |
||||
labelStyle: { |
||||
position: 'absolute', |
||||
right: 15, |
||||
backgroundColor: 'white', |
||||
zIndex: 100, |
||||
paddingHorizontal: 5, |
||||
textAlign: 'center', |
||||
top: !isFocused ? '50%' : 0, |
||||
fontSize: !isFocused ? Dimensions.get('window').width / 27 : 14, |
||||
transform: [{translateY: -Dimensions.get('window').width / 35}], |
||||
color: !isFocused ? '#555' : '#6CBE44', |
||||
// transition: Transitions.all(Transitions.)
|
||||
}, |
||||
inputStyle: { |
||||
fontSize: Dimensions.get('window').width / 25, |
||||
color: '#000', |
||||
borderWidth: 0.5, |
||||
borderColor: isFocused ? '#6CBE44' : '#555', |
||||
paddingVertical: 15, |
||||
paddingHorizontal: 10, |
||||
direction: 'rtl', |
||||
textAlign: 'right', |
||||
}, |
||||
}); |
||||
return ( |
||||
<View style={{marginTop: 18}}> |
||||
<Text |
||||
style={[styles.labelStyle, tw.style('transition-all transform duration-300')]}> |
||||
{label} |
||||
</Text> |
||||
<TextInput |
||||
style={[styles.inputStyle , tw.style('rounded-md') ]} |
||||
onChangeText={text => onChange(name, text)} |
||||
onFocus={() => setIsFocused(true)} |
||||
onBlur={() => |
||||
value ? setIsFocused(() => true) : setIsFocused(() => false) |
||||
} |
||||
/> |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
export default FloatingLabelInput; |
@ -0,0 +1,31 @@ |
||||
import React from 'react'; |
||||
import {StyleSheet, Text, Pressable, Dimensions } from 'react-native'; |
||||
|
||||
export default function FormButton({text, color, onPress}) { |
||||
const styles = StyleSheet.create({ |
||||
button: { |
||||
width : '100%', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
paddingVertical: 12, |
||||
paddingHorizontal: 0, |
||||
borderRadius: 6, |
||||
elevation: 3, |
||||
backgroundColor: color, |
||||
}, |
||||
text: { |
||||
fontSize: Dimensions.get('window').width / 25, |
||||
fontWeight: '300', |
||||
color: 'white', |
||||
}, |
||||
}); |
||||
return ( |
||||
<Pressable |
||||
color={color} |
||||
style={styles.button} |
||||
onPress={() => onPress} |
||||
> |
||||
<Text style={styles.text}>{text}</Text> |
||||
</Pressable> |
||||
); |
||||
} |
@ -0,0 +1,33 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, Image} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Header({icon, title, description, background}) { |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-col items-center justify-end pb-3 relative mb-0'), |
||||
{height: height / 4.5, backgroundColor: '#196EC015'}, |
||||
]}> |
||||
<Image source={background} style={[tw.style('absolute left-0 top-0'), {}]} /> |
||||
<Image source={icon} style={[{width : width / 5, height : height / 10, marginBottom : 10}]} /> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 18, color: '#196EC0'}, |
||||
tw.style('font-semibold mb-1'), |
||||
]}> |
||||
{title} |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
{color: '#86A0B9', fontSize: width / 30}, |
||||
tw.style('font-semibold mb-2'), |
||||
]}> |
||||
{description} |
||||
</Text> |
||||
</View> |
||||
); |
||||
} |
@ -0,0 +1,69 @@ |
||||
import React, {useCallback} from 'react'; |
||||
import {Image, StyleSheet, View, TouchableOpacity} from 'react-native'; |
||||
import {useNavigation} from '@react-navigation/native'; |
||||
import tw from 'tailwind-rn'; |
||||
|
||||
//colors
|
||||
import Color from '../constants/Colors'; |
||||
|
||||
//assets
|
||||
import hamburgerLightIcon from '../assets/icons/hamburger-light.png'; |
||||
import logoIcon from '../assets/icons/logo.png'; |
||||
import qrLightIcon from '../assets/icons/qr-light.png'; |
||||
import arLightIcon from '../assets/icons/ar-light.png'; |
||||
|
||||
const Navbar = ({notification}) => { |
||||
const navigation = useNavigation(); |
||||
const Button = useCallback(({icon, route}) => { |
||||
return ( |
||||
<TouchableOpacity |
||||
style={[ |
||||
tw('rounded-sm p-1'), |
||||
{ |
||||
backgroundColor: Color.theme1.light.blue1, |
||||
borderColor: Color.theme1.light.blue2, |
||||
borderWidth: 1, |
||||
marginLeft : route === 'ar' ? 10 : 0
|
||||
}, |
||||
]} |
||||
onPress={() => navigation.navigate(route)}> |
||||
<Image source={icon} style={{width: 20, height: 20}} /> |
||||
</TouchableOpacity> |
||||
); |
||||
}, []); |
||||
return ( |
||||
<View |
||||
style={tw( |
||||
'w-full flex flex-row-reverse justify-between h-16 bg-white items-center px-4 relative', |
||||
)}> |
||||
<View style={tw('relative')}> |
||||
<Image source={hamburgerLightIcon} style={{width: 29.5, height: 27}} /> |
||||
{notification && ( |
||||
<View |
||||
style={tw( |
||||
'h-2.5 w-2.5 absolute -left-1 -top-1 bg-red-500 rounded-full', |
||||
)}></View> |
||||
)} |
||||
</View> |
||||
<Image |
||||
source={logoIcon} |
||||
style={[ |
||||
tw('absolute right-1/2 top-1/2'), |
||||
{ |
||||
width: 19.6, |
||||
height: 28.9, |
||||
transform: [{translateX: 0}, {translateY: -14.5}], |
||||
}, |
||||
]} |
||||
/> |
||||
<View style={tw('flex flex-row items-center')}> |
||||
<Button icon={qrLightIcon} route={'qr'} /> |
||||
<Button icon={arLightIcon} route={'ar'} /> |
||||
</View> |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
export default Navbar; |
||||
|
||||
const styles = StyleSheet.create({}); |
@ -0,0 +1,20 @@ |
||||
import React, {useState} from 'react'; |
||||
import {View, Text, Dimensions} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
|
||||
function Or(props) { |
||||
return ( |
||||
<View |
||||
style={[tw.style('w-full flex flex-row justify-between items-center mt-3 mb-5')]}> |
||||
<View |
||||
style={{width: '43%', height: 1, backgroundColor: '#EFEFEF'}}></View> |
||||
<Text style={{fontSize: width / 27, color: '#C2C2C2'}}>یا</Text> |
||||
<View |
||||
style={{width: '43%', height: 1, backgroundColor: '#EFEFEF'}}></View> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
export default Or; |
@ -0,0 +1,28 @@ |
||||
import React from 'react'; |
||||
import {Pressable, Text, Dimensions} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
const fullWidth = Dimensions.get('window').width; |
||||
|
||||
export default function Pressable1({ |
||||
title, |
||||
backgroundColor, |
||||
color, |
||||
border, |
||||
width, |
||||
}) { |
||||
return ( |
||||
<Pressable |
||||
style={[ |
||||
tw.style('rounded-md py-4 flex flex-row justify-center mb-3'), |
||||
{ |
||||
backgroundColor: backgroundColor, |
||||
borderWidth: border.width, |
||||
borderColor: border.color, |
||||
width : width, |
||||
}, |
||||
]}> |
||||
<Text style={{fontSize: fullWidth / 27, color: color}}>{title}</Text> |
||||
</Pressable> |
||||
); |
||||
} |
@ -0,0 +1,34 @@ |
||||
import React, {useState, useEffect} from 'react'; |
||||
import {View} from 'react-native'; |
||||
import tw from 'tailwind-rn'; |
||||
|
||||
//Color
|
||||
import Color from '../constants/Colors'; |
||||
|
||||
function Progress({percent}) { |
||||
const [delayPercent, setDelayPercent] = useState(0); |
||||
useEffect(() => { |
||||
setTimeout(() => { |
||||
setDelayPercent(() => percent); |
||||
}, 1000); |
||||
}, [percent]); |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw('w-full h-1.5 rounded-full overflow-hidden my-3'), |
||||
{backgroundColor: '#D3E9FF'}, |
||||
]}> |
||||
<View |
||||
style={[ |
||||
tw('h-full transition-all duration-500 rounded-full'), |
||||
{ |
||||
backgroundColor: Color.theme1.light.blue3, |
||||
width: percent + '%', |
||||
// backgroundColor: Color.theme1.light.blue4,
|
||||
}, |
||||
]}></View> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
export default Progress; |
@ -0,0 +1,30 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, Image} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import leftIcon from '../assets/icons/leftWhite.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Redirect({text}) { |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-row-reverse items-center p-4 rounded-md mb-5'), |
||||
{backgroundColor: '#196EC0'}, |
||||
]}> |
||||
<View style={tw.style('flex-1 flex flex-col')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium text-right'), |
||||
{fontSize: width / 30, color: 'white'}, |
||||
]}> |
||||
{text} |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('p-0')}> |
||||
<Image source={leftIcon} style={{width: 24, height: 24}} /> |
||||
</View> |
||||
</View> |
||||
); |
||||
} |
@ -0,0 +1,55 @@ |
||||
import React, {useState} from 'react'; |
||||
import { |
||||
TextInput, |
||||
View, |
||||
Dimensions, |
||||
StyleSheet, |
||||
Pressable, |
||||
Image, |
||||
} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import searchIcon from '../assets/icons/search.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const Search = ({ |
||||
placeholder, |
||||
textAlign, |
||||
direction, |
||||
onChange, |
||||
value, |
||||
}) => { |
||||
const styles = StyleSheet.create({ |
||||
inputStyle: { |
||||
fontSize: width / 30, |
||||
color: '#000', |
||||
borderWidth: 0.5, |
||||
borderColor: '#DBDBDB', |
||||
paddingVertical: 16, |
||||
paddingHorizontal: 10, |
||||
direction: direction, |
||||
textAlign: textAlign, |
||||
backgroundColor: '#F9F9F9', |
||||
}, |
||||
}); |
||||
return ( |
||||
<View style={[{marginTop: 18}, tw.style('w-full relative')]}> |
||||
<TextInput |
||||
style={[styles.inputStyle, tw.style('rounded-md')]} |
||||
onChangeText={text => onChange(text)} |
||||
placeholder={placeholder} |
||||
placeholderTextColor={'#cccccc'} |
||||
value={value} |
||||
/> |
||||
<Pressable style={tw.style('absolute left-3 top-0 transform inset-y-4')}> |
||||
<Image source={searchIcon} style={[{width: 20, height: 20}]} /> |
||||
</Pressable> |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
export default Search; |
||||
|
||||
Search.defaultProps = { |
||||
direction: 'rtl', |
||||
textAlign: 'right', |
||||
}; |
@ -0,0 +1,46 @@ |
||||
import React from 'react'; |
||||
import {Image, Dimensions} from 'react-native'; |
||||
import SelectDropdown from 'react-native-select-dropdown'; |
||||
import dropdownIcon from '../assets/icons/dropdown.png'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
function Select({iconPosition, options, onChange, value, width, defaultValue}) { |
||||
return ( |
||||
<SelectDropdown |
||||
data={options} |
||||
buttonStyle={{ |
||||
width: width, |
||||
borderWidth: 1, |
||||
borderColor: '#DBDBDB', |
||||
borderRadius: 6, |
||||
height: 36, |
||||
backgroundColor: '#F9F9F9', |
||||
}} |
||||
rowTextStyle={{fontSize: Dimensions.get('window').width / 30}} |
||||
defaultButtonText={defaultValue} |
||||
statusBarTranslucent={true} |
||||
buttonTextStyle={{ |
||||
textAlign: 'center', |
||||
justifyContent: 'flex-end', |
||||
flex: 0, |
||||
fontSize: Dimensions.get('window').width / 30, |
||||
color: '#707070', |
||||
// display: 'inline'
|
||||
}} |
||||
dropdownIconPosition={iconPosition} |
||||
onSelect={selectedItem => { |
||||
onChange(selectedItem); |
||||
}} |
||||
renderDropdownIcon={() => ( |
||||
<Image source={dropdownIcon} style={{width: 12, height: 8}} /> |
||||
)} |
||||
/> |
||||
); |
||||
} |
||||
|
||||
export default Select; |
||||
|
||||
Select.defaultProps = { |
||||
options: ['1', '2', '3'], |
||||
iconPosition: 'left', |
||||
}; |
@ -0,0 +1,23 @@ |
||||
import {StyleSheet} from 'react-native'; |
||||
import Video from 'react-native-video'; |
||||
import file from '../assets/video.mp4'; |
||||
|
||||
// Within your render function, assuming you have a file called
|
||||
// "background.mp4" in your project. You can include multiple videos
|
||||
// on a single screen if you like.
|
||||
import React from 'react'; |
||||
|
||||
export default function CustomVideo() { |
||||
return ( |
||||
<Video |
||||
source={file} // Can be a URL or a local file.
|
||||
ref={ref => { |
||||
this.player = ref; |
||||
}} // Store reference
|
||||
onBuffer={this.onBuffer} // Callback when remote video is buffering
|
||||
onError={this.videoError} // Callback when video cannot be loaded
|
||||
style={{width: '100%', height: '100%', borderRadius : 10}} |
||||
controls |
||||
/> |
||||
); |
||||
} |
@ -0,0 +1,19 @@ |
||||
const Colors = { |
||||
theme1 : { |
||||
light : { |
||||
blue1 : '#E9F0FF', |
||||
blue2 : '#D7E3FC', |
||||
blue3 : '#D3E9FF', |
||||
blue4 : '#2B8DEB', |
||||
blue5 : "#196EC0", |
||||
blue6 : '#05335F', |
||||
blue7 : '#235A90', |
||||
}, |
||||
dark : { |
||||
|
||||
} |
||||
} |
||||
}; |
||||
|
||||
export default Colors; |
||||
|
@ -0,0 +1,29 @@ |
||||
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; |
||||
}; |
||||
} |
@ -0,0 +1,14 @@ |
||||
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,13 @@ |
||||
import React from 'react' |
||||
import { View, Text } from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
|
||||
function AR({}) { |
||||
return ( |
||||
<View> |
||||
<Text></Text> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default AR; |
After Width: | Height: | Size: 684 B |
After Width: | Height: | Size: 7.9 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,13 @@ |
||||
import React from 'react' |
||||
import { View, Text } from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
|
||||
function Blog({}) { |
||||
return ( |
||||
<View> |
||||
<Text></Text> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Blog; |
@ -0,0 +1,13 @@ |
||||
import React from 'react' |
||||
import { View, Text } from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
|
||||
function Blogs({}) { |
||||
return ( |
||||
<View> |
||||
<Text></Text> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Blogs; |
@ -0,0 +1,13 @@ |
||||
import React from 'react' |
||||
import { View, Text } from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
|
||||
function Chat({}) { |
||||
return ( |
||||
<View> |
||||
<Text></Text> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Chat; |
@ -0,0 +1,13 @@ |
||||
import React from 'react' |
||||
import { View, Text } from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
|
||||
function Contact({}) { |
||||
return ( |
||||
<View> |
||||
<Text></Text> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Contact; |
@ -0,0 +1,13 @@ |
||||
import React from 'react' |
||||
import { View, Text } from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
|
||||
function Exams({}) { |
||||
return ( |
||||
<View> |
||||
<Text></Text> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Exams; |
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 161 B |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 780 B |
After Width: | Height: | Size: 242 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 417 B |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 956 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 853 B |
After Width: | Height: | Size: 573 B |
After Width: | Height: | Size: 591 B |
After Width: | Height: | Size: 37 KiB |
@ -0,0 +1,25 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Image, Pressable} from 'react-native'; |
||||
import {useNavigation} from '@react-navigation/native'; |
||||
import tw from 'tailwind-rn'; |
||||
//assets
|
||||
import arrowIcon from '../assets/arrow.png'; |
||||
//Color
|
||||
import Color from '../../../constants/Colors'; |
||||
|
||||
const Header = ({title, route}) => { |
||||
const navigation = useNavigation(); |
||||
return ( |
||||
<View style={tw('w-full flex flex-row-reverse justify-between mb-2')}> |
||||
<Text |
||||
style={[tw('text-2xl font-bold'), {color: Color.theme1.light.blue5}]}> |
||||
{title} |
||||
</Text> |
||||
<Pressable onPress={() => navigation.navigate(route)}> |
||||
<Image source={arrowIcon} style={{width: 24, height: 24}} /> |
||||
</Pressable> |
||||
</View> |
||||
); |
||||
}; |
||||
|
||||
export default Header; |
@ -0,0 +1,93 @@ |
||||
import React, {useState, useEffect} from 'react'; |
||||
import { |
||||
View, |
||||
Text, |
||||
Image, |
||||
TouchableOpacity, |
||||
Dimensions, |
||||
FlatList, |
||||
} from 'react-native'; |
||||
import tw from 'tailwind-rn'; |
||||
import {connect} from 'react-redux'; |
||||
// import { book } from "../../../../../redux/actions";
|
||||
import Progress from '../../../components/Progress'; |
||||
|
||||
//assets
|
||||
import bookImage from '../assets/zist11.png'; |
||||
|
||||
//Color
|
||||
import Color from '../../../constants/Colors'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
function MyBooks({getList, list, grades}) { |
||||
return ( |
||||
<View style={[tw('w-full px-4 mb-5')]}> |
||||
<View |
||||
style={[ |
||||
tw( |
||||
'w-full flex flex-col rounded-md pt-2 px-2 bg-blueFF1 overflow-hidden', |
||||
), |
||||
{ |
||||
backgroundColor: Color.theme1.light.blue1, |
||||
borderColor: Color.theme1.light.blue2, |
||||
borderWidth: 1, |
||||
}, |
||||
]}> |
||||
<Text |
||||
style={[tw('font-bold text-lg'), {color: Color.theme1.light.blue5}]}> |
||||
کتابهای من |
||||
</Text> |
||||
<FlatList |
||||
style={[tw('py-3')]} |
||||
horizontal={true} |
||||
inverted={true} |
||||
data={list} |
||||
renderItem={(book, index) => <Book key={index} />} |
||||
/> |
||||
</View> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
const Book = ({book, grades}) => { |
||||
return ( |
||||
<TouchableOpacity style={tw('flex flex-col ml-3')}> |
||||
<Image |
||||
source={bookImage} |
||||
style={[ |
||||
tw('rounded-md'), |
||||
{ |
||||
height: 180, |
||||
width: 114, |
||||
}, |
||||
]} |
||||
/> |
||||
<Text |
||||
style={[ |
||||
tw('mt-2 text-md font-semibold'), |
||||
{color: Color.theme1.light.blue6}, |
||||
]}> |
||||
{'نام کتاب'} |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw('font-medium text-xs mt-1'), |
||||
{color: Color.theme1.light.blue5}, |
||||
]}>{`پایه ${'اول'}`}</Text> |
||||
<Progress percent={60} /> |
||||
</TouchableOpacity> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = state => ({ |
||||
// list: state.book.list,
|
||||
// grades : state.publicApi.grades
|
||||
}); |
||||
|
||||
export default connect(mapStateToProps, {})(MyBooks); |
||||
|
||||
MyBooks.defaultProps = { |
||||
list: [{name: 1}, {name: 2}, {name: 3}, {name: 4}, {name: 5}], |
||||
}; |
@ -0,0 +1,85 @@ |
||||
import React from 'react'; |
||||
import { |
||||
View, |
||||
Image, |
||||
Dimensions, |
||||
TouchableOpacity, |
||||
FlatList, |
||||
} from 'react-native'; |
||||
import Header from '../components/Header'; |
||||
import tw from 'tailwind-rn'; |
||||
|
||||
import {connect} from 'react-redux'; |
||||
|
||||
import olum1Image from '../assets/olum1.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
function Scroll({products}) { |
||||
return ( |
||||
<View style={[tw('flex flex-col px-3 mb-5')]}> |
||||
<Header title={'فروشگاه'} route={'Products'} /> |
||||
<FlatList |
||||
horizontal={true} |
||||
inverted={true} |
||||
style={[tw('flex flex-col-reverse mt-3'), {height: 245}]} |
||||
data={products} |
||||
renderItem={({product, index}) => ( |
||||
<Product product={product} position={Number(index)} key={index} /> |
||||
)} |
||||
/> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
const Product = ({product, position}) => { |
||||
return ( |
||||
<TouchableOpacity |
||||
style={[ |
||||
tw('rounded-md mx-1 overflow-hidden rounded-md'), |
||||
{ |
||||
width: position === 0 ? 163 : 79, |
||||
height: position === 0 ? 245 : 118, |
||||
}, |
||||
]} |
||||
// onPress={() => navigation.navigate('Product')}
|
||||
> |
||||
<Image source={olum1Image} style={{width: '100%', height: '100%'}} /> |
||||
</TouchableOpacity> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = state => ({ |
||||
// features: state.publicApi.home?.features,
|
||||
}); |
||||
export default connect(mapStateToProps, {})(Scroll); |
||||
|
||||
Scroll.defaultProps = { |
||||
products: [ |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
{ |
||||
imageUrl: olum1Image, |
||||
}, |
||||
], |
||||
}; |
@ -0,0 +1,55 @@ |
||||
import React from 'react'; |
||||
import {useTranslation} from 'react-i18next'; |
||||
import { |
||||
View, |
||||
StyleSheet, |
||||
Dimensions, |
||||
ScrollView, |
||||
SafeAreaView, |
||||
} from 'react-native'; |
||||
import Navbar from '../../components/Navbar'; |
||||
import tw from 'tailwind-rn'; |
||||
import Scroll from './components/Scroll'; |
||||
import MyBooks from './components/MyBooks'; |
||||
import Videos from './components/Videos'; |
||||
import Blogs from './components/Blogs'; |
||||
|
||||
import qrIcon from './assets/qr.png'; |
||||
import arIcon from './assets/ar.png'; |
||||
// import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
// Within your render function
|
||||
function Home(props) { |
||||
return ( |
||||
<SafeAreaView> |
||||
<Navbar /> |
||||
<ScrollView |
||||
contentContainerStyle={styles.contentContainerStyle} |
||||
style={[ |
||||
styles.container, |
||||
tw('w-full flex flex-col'), |
||||
]}> |
||||
<MyBooks /> |
||||
<Scroll /> |
||||
<Videos /> |
||||
<Blogs /> |
||||
</ScrollView> |
||||
</SafeAreaView> |
||||
); |
||||
} |
||||
|
||||
// Later on in your styles..
|
||||
const styles = StyleSheet.create({ |
||||
contentContainerStyle: { |
||||
paddingBottom: 100, |
||||
}, |
||||
container: { |
||||
width: Dimensions.get('window').width, |
||||
backgroundColor: 'white', |
||||
flexDirection: 'column', |
||||
paddingVertical: 0, |
||||
paddingHorizontal: 0, |
||||
}, |
||||
}); |
||||
|
||||
export default Home; |
@ -0,0 +1,21 @@ |
||||
import React from 'react'; |
||||
import {Image, Dimensions} from 'react-native'; |
||||
|
||||
const {width} = Dimensions.get('window'); |
||||
|
||||
function IranFlag() { |
||||
return ( |
||||
<Image |
||||
source={{ |
||||
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAAABHNCSVQICAgIfAhkiAAAAiBJREFUSEvtVkFrU0EQ/mb3vTRJ08bURAVFA4K0CIKCNw8WQQQPKqj/oN56qgePnv0Vnjy0YPAiItWLFw8VtWhF9BClGE3S5tnmxaR5u+PuPgIKSnlQ46UDww6zM/PtNztveTR3HwEIeQxRBHCS5irgIWI6KAKmd4GH0nXX6sWVO+6Ou9F3p2kvj0LmCD6uPcXB8VO/+X89lY2rbS4jnz6ErD/h4npGD4ydQOvHJ2z2aiiNTrqUQV1rV1vPUMxOzlC1/uKD4khJ8qRd7aa1NVQkID3rE+QJc0oaxLkBqX0TNDYOlcsozZG2OWyEjPwtZ5D/ZWN5lsIwTDTV4u076GIR/uMn6J8/B9FsQh+fSnpFpxMBU70B+XwJ+mgZqYUH6N6chf9oEWrqWFLwZMCWrah+hi4fjoFv34I/X3Fs+9evJGGdDNgxfv0G1AogV94jOnsG7ElwYc+/ZewotUN4Sy+RunvPAW9dvQTkRpOwtbGGcRB8hVJbkNI3a99VEDJFWndZihHrM4OqWcS2266uZtHeUBDCM4PVBbOxTY5ZWZBwcSQkBratzeal1DGObKzfoN58hanTAYUd6FLR3SGX9gIjKdBqzdm03gKUju3GGnhfMX5zbU4mbTDMs8+mslGdy5kdY7fbloDzW+H9JVC9abQBnijMEF+8luhzStrTP8YTT+8C70gnty3y31rN5g+EL1wuw/PK255ypwI0BfRw4dVPHMAgJ7WnxBQAAAAASUVORK5CYII=', |
||||
}} |
||||
style={{ |
||||
width: width / 8, |
||||
height: width / 8 / 1.5, |
||||
left: 5, |
||||
}} |
||||
/> |
||||
); |
||||
} |
||||
|
||||
export default IranFlag; |
@ -0,0 +1,132 @@ |
||||
import React, {useState} from 'react'; |
||||
import {View, Text, Image, ActivityIndicator, Dimensions, TextInput, TouchableHighlight} from 'react-native'; |
||||
import Logo from '../../assets/images/logo.png'; |
||||
import IranFlag from "./components/IranFlag"; |
||||
import {digitToEn, digitToPersian} from "../../utils"; |
||||
import services from "./services"; |
||||
import {asyncAwesomeAlert} from "../../utils/AsyncWrappers"; |
||||
|
||||
const {width, height} = Dimensions.get('window'); |
||||
let faNums = ['۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹', '۰'] |
||||
|
||||
function Login(props) { |
||||
|
||||
const [phone, setPhone] = useState(''); |
||||
const [loading, setLoading] = useState(false) |
||||
|
||||
const onChangePhone = (value) => { |
||||
let items = digitToPersian(value).split(''); |
||||
for (let item of items) { |
||||
if (!faNums.includes(item)) { |
||||
return |
||||
} |
||||
} |
||||
setPhone(digitToPersian(value)); |
||||
} |
||||
|
||||
const checkPhoneNumber = () => { |
||||
return phone.split('').length === 9; |
||||
} |
||||
|
||||
const submit = async () => { |
||||
setLoading(true) |
||||
if (!checkPhoneNumber()) { |
||||
setLoading(false) |
||||
return asyncAwesomeAlert('خطا', 'شماره وارد شده اشتباه است', {showCancelButton: false}); |
||||
} |
||||
let res = await services.getSmsCode({ |
||||
cellphone: '09' + digitToEn(phone) |
||||
}) |
||||
if (res.ok) { |
||||
setLoading(false) |
||||
props.navigation.navigate('Otp', {phone: '09' + digitToEn(phone)}); |
||||
} |
||||
setLoading(false) |
||||
} |
||||
|
||||
return ( |
||||
<View style={{ |
||||
flex: 1, |
||||
justifyContent: 'center', |
||||
alignItems: 'center', |
||||
backgroundColor: 'white' |
||||
}}> |
||||
<Image source={Logo} style={{ |
||||
width: width * 0.7, |
||||
height: width * 0.7 / 2.09, |
||||
}} /> |
||||
<Text style={{ |
||||
width: width, |
||||
paddingHorizontal: 10, |
||||
marginTop: 20, |
||||
fontSize: 20, |
||||
textAlign: 'right', |
||||
}}>{'دانوین'}</Text> |
||||
<Text style={{ |
||||
width: width, |
||||
paddingHorizontal: 10, |
||||
marginTop: 10, |
||||
fontSize: 14, |
||||
color: '#6f7074', |
||||
textAlign: 'right', |
||||
}}>{'به دانوین خوش اومدی برای عضویت و ادامه شماره موبایلت رو وارد کن و روی گزینه ثبت بزن'}</Text> |
||||
<View style={{ |
||||
width: width - 10, |
||||
height: width / 8, |
||||
borderRadius: 8, |
||||
backgroundColor: '#f2f2f2', |
||||
flexDirection: 'row', |
||||
marginTop: 10, |
||||
alignItems: 'center' |
||||
}}> |
||||
<IranFlag /> |
||||
<Text style={{ |
||||
// width: width / 7 - 15,
|
||||
fontSize: 18, |
||||
marginLeft: 10, |
||||
color: '#a2a2a2', |
||||
textAlign: 'right', |
||||
// marginRight: 5,
|
||||
}}> |
||||
{'۰۹'} |
||||
</Text> |
||||
<TextInput |
||||
style={{ |
||||
width: width / 1.5, |
||||
color: '#a2a2a2', |
||||
fontSize: 18 |
||||
}} |
||||
maxLength={9} |
||||
underlineColorAndroid={'transparent'} |
||||
value={phone} |
||||
onChangeText={text => onChangePhone(text)} |
||||
/> |
||||
</View> |
||||
<TouchableHighlight |
||||
disabled={loading} |
||||
style={{ |
||||
width: width - 10, |
||||
height: width / 9, |
||||
backgroundColor: '#6cbe44', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
borderRadius: 10, |
||||
marginTop: 15, |
||||
}} |
||||
onPress={() => submit()}> |
||||
{loading ? |
||||
<ActivityIndicator size={'small'} color={'white'}/> |
||||
: |
||||
<Text style={{ |
||||
color: 'white', |
||||
fontSize: 18, |
||||
}}> |
||||
{'ادامه'} |
||||
</Text> |
||||
} |
||||
</TouchableHighlight> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
export default Login; |
@ -0,0 +1,10 @@ |
||||
import mocks from './mocks'; |
||||
import mainServices from './services'; |
||||
|
||||
const mock = false; |
||||
|
||||
let services = {...mainServices}; |
||||
if (mock) { |
||||
services = mocks; |
||||
} |
||||
export default services; |
@ -0,0 +1,18 @@ |
||||
import { asyncAwesomeAlert, randomApiSleep } from '../../../utils/AsyncWrappers'; |
||||
|
||||
const data = { |
||||
|
||||
}; |
||||
|
||||
const getSmsCode = async () => { |
||||
await randomApiSleep(); |
||||
return { |
||||
ok: true, |
||||
data: data |
||||
}; |
||||
}; |
||||
|
||||
|
||||
|
||||
const mocks = {getSmsCode}; |
||||
export default mocks; |
@ -0,0 +1,13 @@ |
||||
import {nextFetchApi} from '../../../services/api'; |
||||
const getSmsCode = async (obj) => { |
||||
return await nextFetchApi('/public/sendOTP', { |
||||
method: 'POST', |
||||
payload: obj |
||||
}); |
||||
}; |
||||
|
||||
const mainServices = { |
||||
getSmsCode, |
||||
}; |
||||
|
||||
export default mainServices; |
After Width: | Height: | Size: 8.6 KiB |
@ -0,0 +1,70 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, Image} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import _ from 'lodash'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Book({book}) { |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-row-reverse justify-between py-3'), |
||||
{borderBottomWidth: 1, borderColor: '#86A0B933'}, |
||||
]}> |
||||
<View style={tw.style('flex flex-row-reverse items-center flex-1')}> |
||||
<Image |
||||
source={book} |
||||
style={[ |
||||
tw.style('rounded-md'), |
||||
{width: width / 5.5, height: height / 8}, |
||||
]} |
||||
/> |
||||
<View style={tw.style('flex flex-col items-end mr-2')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 30, color: '#05335F'}, |
||||
]}> |
||||
علوم اجتماعی |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium mt-2'), |
||||
{fontSize: width / 36, color: '#707070'}, |
||||
]}> |
||||
پایه دوم |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium mt-2'), |
||||
{fontSize: width / 36, color: '#707070'}, |
||||
]}> |
||||
نسخه دیجیتال |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View style={tw.style('flex flex-row-reverse items-center')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium py-1 px-2'), |
||||
{ |
||||
color: '#132F52', |
||||
fontSize: width / 34, |
||||
backgroundColor: '#F1F1F1', |
||||
}, |
||||
]}> |
||||
1 |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium mr-3'), |
||||
{color: '#132F52', fontSize: width / 34}, |
||||
]}> |
||||
126.000 تومان |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
); |
||||
} |
@ -0,0 +1,312 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, StyleSheet, ScrollView} from 'react-native'; |
||||
import Book from './components/Book'; |
||||
import {connect} from 'react-redux'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import b1Image from './assets/b1.png'; |
||||
import _ from 'lodash'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
const colors = { |
||||
1: '#FFF700', |
||||
4: '#FF0000', |
||||
3: '#4CFF00', |
||||
2: '#196EC0', |
||||
}; |
||||
|
||||
const status = { |
||||
1: 'در حال پردازش', |
||||
4: 'درخواست رد شد', |
||||
3: 'تکمیل شد', |
||||
2: 'ارسال شده', |
||||
}; |
||||
|
||||
function OrderDetails({order}) { |
||||
return ( |
||||
<ScrollView |
||||
contentContainerStyle={styles.contentContainerStyle} |
||||
style={styles.container}> |
||||
<View |
||||
style={[ |
||||
tw.style( |
||||
'flex flex-row-reverse w-full justify-between items-center p-3', |
||||
), |
||||
{backgroundColor: '#EEF7FF'}, |
||||
]}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#20297B'}, |
||||
]}> |
||||
{_.join(['شماره سفارش:', order.number], ' ')} |
||||
</Text> |
||||
<View style={tw.style('flex flex-row-reverse items-center')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light'), |
||||
{color: '#20297B', fontSize: width / 32}, |
||||
]}> |
||||
{status[order.status]} |
||||
</Text> |
||||
<View |
||||
style={[ |
||||
tw.style('h-4 w-4 rounded-full mr-2'), |
||||
{backgroundColor: colors[order.status]}, |
||||
]}></View> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-row-reverse py-4'), |
||||
{borderBottomWidth: 1, borderColor: '#86A0B933'}, |
||||
]}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
آدرس تحویل: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('flex-1 font-light text-right mr-2'), |
||||
{fontSize: width / 32, lineHeight: 17, color: '#05335F'}, |
||||
]}> |
||||
{order.address} |
||||
</Text> |
||||
</View> |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-row-reverse justify-between py-4'), |
||||
{borderBottomWidth: 1, borderColor: '#86A0B933'}, |
||||
]}> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
مشخصات تحویل گیرنده: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 15, color: '#05335F'}, |
||||
]}> |
||||
{order.name} |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
شماره موبایل: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 17, color: '#05335F'}, |
||||
]}> |
||||
{order.cellphone} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={[ |
||||
tw.style('w-full rounded-md flex flex-col p-4 items-end mt-2'), |
||||
{backgroundColor: '#EEF6FF'}, |
||||
]}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
{_.join(['کد تحویل', order.receiveCode], ' ')} |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mt-2'), |
||||
{fontSize: width / 32, lineHeight: 17, color: '#05335F'}, |
||||
]}> |
||||
این کد را پس از دریافت کالا، به مامور ارسال دانوین اعلام فرمایید |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('w-full flex flex-column items-end')}> |
||||
{order.items.map((item, index) => ( |
||||
<Book book={item} key={index} /> |
||||
))} |
||||
</View> |
||||
<View |
||||
style={[tw.style('w-full flex flex-row-reverse justify-between py-4')]}> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
مبلغ سبد خرید: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 15, color: '#05335F'}, |
||||
]}> |
||||
{_.join([order.shoppingCardPrice, 'تومان'], ' ')} |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
تخفیف: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 17, color: '#05335F'}, |
||||
]}> |
||||
{_.join([order.discountPrice, 'تومان'], ' ')} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-row-reverse justify-between py-4'), |
||||
{borderBottomWidth: 1, borderColor: '#86A0B933'}, |
||||
]}> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
هزینه ارسال کالا: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 15, color: '#05335F'}, |
||||
]}> |
||||
{_.join([order.sendPrice, 'تومان'], ' ')} |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
جمع هزینه پرداختی: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 17, color: '#05335F'}, |
||||
]}> |
||||
{_.join([order.totalPrice, 'تومان'], ' ')} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-row-reverse justify-between py-4'), |
||||
{borderBottomWidth: 1, borderColor: '#86A0B933'}, |
||||
]}> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
نحوه پرداخت: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 15, color: '#05335F'}, |
||||
]}> |
||||
{order.payMethod} |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
شماره تراکنش: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 17, color: '#05335F'}, |
||||
]}> |
||||
{order.transactionNumber} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={[tw.style('w-full flex flex-row-reverse justify-between py-4')]}> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#05335F'}, |
||||
]}> |
||||
تاریخ تحویل: |
||||
</Text> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light text-right mr-1'), |
||||
{fontSize: width / 32, lineHeight: 15, color: '#05335F'}, |
||||
]}> |
||||
{order.date} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
</ScrollView> |
||||
); |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
contentContainerStyle: { |
||||
paddingBottom: 50, |
||||
alignItems: 'flex-end', |
||||
}, |
||||
container: { |
||||
width: width, |
||||
backgroundColor: 'white', |
||||
flexDirection: 'column', |
||||
paddingVertical: 5, |
||||
paddingHorizontal: 10, |
||||
}, |
||||
}); |
||||
|
||||
export default OrderDetails; |
||||
|
||||
OrderDetails.defaultProps = { |
||||
order: { |
||||
number: '535353523653', |
||||
receiveCode: '300031', |
||||
status: 2, |
||||
items: [b1Image, b1Image], |
||||
date: '1400/1/11', |
||||
cost: '1.240.000', |
||||
address: |
||||
'تهران خیابان انقلاب حدفاصل ابوریحان و فلسطین بن بست سروش پلاک 2 واحد 12 شرقی', |
||||
name: 'هومن عابدی', |
||||
cellphone: '09121234568', |
||||
shoppingCardPrice: '981.000', |
||||
discountPrice: '12.000', |
||||
sendPrice: '18.000', |
||||
totalPrice: '18.000', |
||||
payMethod: 'حضوری', |
||||
transactionNumber: ' BS3194DNB98312', |
||||
}, |
||||
}; |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 241 B |
After Width: | Height: | Size: 186 B |
@ -0,0 +1,175 @@ |
||||
import React from 'react'; |
||||
import { |
||||
View, |
||||
Text, |
||||
Dimensions, |
||||
StyleSheet, |
||||
Image, |
||||
Pressable, |
||||
} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import leftArrowIcon from '../assets/leftArrow.png'; |
||||
import plusIcon from '../assets/plus.png'; |
||||
import _ from 'lodash'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
const colors = { |
||||
1: '#FFF700', |
||||
4: '#FF0000', |
||||
3: '#4CFF00', |
||||
2: '#196EC0', |
||||
}; |
||||
|
||||
const status = { |
||||
1: 'در حال پردازش', |
||||
4: 'درخواست رد شد', |
||||
3: 'تکمیل شد', |
||||
2: 'ارسال شده', |
||||
}; |
||||
|
||||
function Order({order}) { |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw.style('w-full flex flex-col rounded-md overflow-hidden my-3'), |
||||
{borderWidth: 1, borderColor: '#EEF7FF'}, |
||||
]}> |
||||
<View |
||||
style={[ |
||||
tw.style( |
||||
'flex flex-row-reverse w-full justify-between items-center p-3', |
||||
), |
||||
{backgroundColor: '#EEF7FF'}, |
||||
]}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-medium'), |
||||
{fontSize: width / 32, color: '#20297B'}, |
||||
]}> |
||||
{_.join(['شماره سفارش:', order.number], ' ')} |
||||
</Text> |
||||
<View style={tw.style('flex flex-row-reverse items-center')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-light'), |
||||
{color: '#20297B', fontSize: width / 32}, |
||||
]}> |
||||
{status[order.status]} |
||||
</Text> |
||||
<View |
||||
style={[ |
||||
tw.style('h-4 w-4 rounded-full mr-2'), |
||||
{backgroundColor: colors[order.status]}, |
||||
]}></View> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={tw.style('w-full flex flex-row-reverse justify-between p-3')}> |
||||
<View style={tw.style('flex flex-col')}> |
||||
<View style={tw.style('flex flex-row-reverse mb-2')}> |
||||
{order.items.length < 2 |
||||
? order?.items?.map(item => ( |
||||
<Image |
||||
source={item} |
||||
style={[ |
||||
tw.style('rounded-md ml-1.5'), |
||||
{width: width / 5.8, height: height / 8}, |
||||
]} |
||||
/> |
||||
)) |
||||
: order.items |
||||
?.slice(0, 1) |
||||
?.map(item => ( |
||||
<Image |
||||
source={item} |
||||
style={[ |
||||
tw.style('rounded-md ml-1.5'), |
||||
{width: width / 5.8, height: height / 8}, |
||||
]} |
||||
/> |
||||
))} |
||||
{order.items.length >= 2 && ( |
||||
<View |
||||
style={[ |
||||
tw.style( |
||||
'flex flex-row-reverse items-center justify-center relative rounded-md overflow-hidden', |
||||
), |
||||
{ |
||||
width: width / 5.8, |
||||
height: height / 8, |
||||
backgroundColor: '#EBEBEB', |
||||
}, |
||||
]}> |
||||
{/* <Image |
||||
source={order.items[2]} |
||||
style={[tw.style('absolute left-0 top-0 h-full w-full z-10')]} |
||||
/> */} |
||||
<Image source={plusIcon} style={[tw.style('w-4 h-6 z-30')]} /> |
||||
</View> |
||||
)} |
||||
</View> |
||||
<View style={[tw.style('bg-red-400')]}> |
||||
<Text |
||||
style={[ |
||||
tw.style('p-2 rounded-md text-center'), |
||||
{ |
||||
fontSize: width / 32, |
||||
backgroundColor: '#F0FFF1', |
||||
color: '#05335F', |
||||
}, |
||||
]}> |
||||
{_.join(['کد تحویل:', order.receiveCode], ' ')} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View style={tw.style('flex flex-col items-center mr-4')}> |
||||
<Text |
||||
style={[ |
||||
tw.style('my-3'), |
||||
{fontSize: width / 25, color: '#132F52'}, |
||||
]}> |
||||
{_.join(['جمع فاکتور:', order.cost], ' ')} |
||||
</Text> |
||||
<Pressable |
||||
style={[ |
||||
tw.style('rounded-md flex flex-row-reverse justify-center px-5 py-3'), |
||||
{borderWidth: 1, borderColor: '#1999C0'}, |
||||
]}> |
||||
<Text style={{fontSize: width / 28, color: '#1999C0'}}> |
||||
جزئیات سفارش |
||||
</Text> |
||||
<Image |
||||
source={leftArrowIcon} |
||||
style={{width: 18, height: 18, marginRight: 10}} |
||||
/> |
||||
</Pressable> |
||||
<Text |
||||
style={[ |
||||
tw.style('my-5'), |
||||
{fontSize: width / 30, color: '#132F52'}, |
||||
]}> |
||||
{_.join(['تاریخ سفارش:', order.date], ' ')} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
contentContainerStyle: { |
||||
paddingBottom: 50, |
||||
alignItems: 'flex-end', |
||||
}, |
||||
container: { |
||||
width: width, |
||||
backgroundColor: 'white', |
||||
flexDirection: 'column', |
||||
paddingVertical: 5, |
||||
paddingHorizontal: 10, |
||||
}, |
||||
}); |
||||
|
||||
export default Order; |
@ -0,0 +1,66 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, StyleSheet, ScrollView} from 'react-native'; |
||||
import Order from './components/Order'; |
||||
import {connect} from 'react-redux'; |
||||
import b1Image from './assets/b1.png'; |
||||
import b2Image from './assets/b2.png'; |
||||
import b3Image from './assets/b3.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
|
||||
function OrdersFollowUp({orders}) { |
||||
return ( |
||||
<ScrollView |
||||
contentContainerStyle={styles.contentContainerStyle} |
||||
style={styles.container}> |
||||
{ |
||||
orders.map((order, index) => <Order order={order} key={index} />) |
||||
} |
||||
</ScrollView> |
||||
); |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
contentContainerStyle: { |
||||
paddingBottom: 50, |
||||
alignItems: 'flex-end', |
||||
}, |
||||
container: { |
||||
width: width, |
||||
backgroundColor: 'white', |
||||
flexDirection: 'column', |
||||
paddingVertical: 5, |
||||
paddingHorizontal: 10, |
||||
}, |
||||
}); |
||||
|
||||
export default OrdersFollowUp; |
||||
|
||||
OrdersFollowUp.defaultProps = { |
||||
orders: [ |
||||
{ |
||||
number: '535353523653', |
||||
receiveCode: '300031', |
||||
status: 2, |
||||
items: [b1Image, b2Image, b3Image, b3Image], |
||||
date: '1400/1/12', |
||||
cost: '1.240.000', |
||||
}, |
||||
{ |
||||
number: '535353523653', |
||||
receiveCode: '300031', |
||||
status: 3, |
||||
items: [b1Image, b2Image, b3Image], |
||||
date: '1400/1/12', |
||||
cost: '1.240.000', |
||||
}, |
||||
{ |
||||
number: '535353523653', |
||||
receiveCode: '300031', |
||||
status: 4, |
||||
items: [b1Image, b2Image, b3Image], |
||||
date: '1400/1/12', |
||||
cost: '1.240.000', |
||||
}, |
||||
], |
||||
}; |
@ -0,0 +1,245 @@ |
||||
import React, {useEffect, useState} from 'react' |
||||
import { |
||||
View, |
||||
Text, |
||||
Image, |
||||
TextInput, |
||||
TouchableHighlight, |
||||
Dimensions, |
||||
StyleSheet, |
||||
TouchableOpacity, |
||||
ActivityIndicator, |
||||
AsyncStorage |
||||
} from 'react-native'; |
||||
import {connect} from 'react-redux'; |
||||
import Logo from "../../assets/images/logo.png"; |
||||
import IranFlag from "../Login/components/IranFlag"; |
||||
import {digitToEn, digitToPersian} from "../../utils"; |
||||
import services from "./services"; |
||||
import {buildAction} from "../../reducers/DefaultReducer"; |
||||
import {PROFILE_RECORD} from "../../actions/actionTypes"; |
||||
|
||||
const {width} = Dimensions.get('window') |
||||
let ref1; |
||||
let ref2; |
||||
let ref3; |
||||
let ref4; |
||||
|
||||
let timer = 60; |
||||
|
||||
const mapStateToProps = state => { |
||||
return { |
||||
profile: state.profile, |
||||
} |
||||
} |
||||
|
||||
function Otp(props) { |
||||
let faNums = ['۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹', '۰'] |
||||
|
||||
const [firstCode, setFirstCode] = useState(''); |
||||
const [secondCode, setSecondCode] = useState(''); |
||||
const [thirdCode, setThirdCode] = useState(''); |
||||
const [fourthCode, setFourthCode] = useState(''); |
||||
const [time, setTime] = useState(60); |
||||
const [loading, setLoading] = useState(false); |
||||
|
||||
const checkValue = (value) => { |
||||
return faNums.includes(digitToPersian(value)); |
||||
} |
||||
|
||||
const onChangeCode = (value, key) => { |
||||
// if (!checkValue()) {
|
||||
// return
|
||||
// }
|
||||
switch (key) { |
||||
case '1': |
||||
setFirstCode(digitToPersian(value)); |
||||
ref2.focus(); |
||||
break; |
||||
case '2': |
||||
setSecondCode(digitToPersian(value)); |
||||
ref3.focus(); |
||||
break; |
||||
case '3': |
||||
setThirdCode(digitToPersian(value)); |
||||
ref4.focus(); |
||||
break; |
||||
case '4': |
||||
setFourthCode(digitToPersian(value)) |
||||
submit(); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
const getEnCode = () => { |
||||
return Number(digitToEn(firstCode) + digitToEn(secondCode) + digitToEn(thirdCode) + digitToEn(fourthCode)) |
||||
} |
||||
|
||||
const submit = async () => { |
||||
setLoading(true) |
||||
let res = await services.sendOtpCode({ |
||||
cellphone: props.route.params.phone, |
||||
otp: String(getEnCode()), |
||||
applicationToken: "1", |
||||
userToken: "1" |
||||
}) |
||||
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: 'Home'}] |
||||
}) |
||||
} |
||||
setLoading(false) |
||||
} |
||||
|
||||
useEffect(() => { |
||||
let interval = setInterval(() => { |
||||
if (time > 0) { |
||||
setTime(timer - 1); |
||||
timer -= 1; |
||||
} |
||||
}, 1000); |
||||
let timeout = setTimeout(() => { |
||||
clearInterval(interval) |
||||
}, 60000) |
||||
return () => { |
||||
clearInterval(interval); |
||||
clearTimeout(timeout) |
||||
} |
||||
}, []); |
||||
|
||||
return ( |
||||
<View style={{ |
||||
flex: 1, |
||||
justifyContent: 'center', |
||||
alignItems: 'center', |
||||
backgroundColor: 'white' |
||||
}}> |
||||
<Image source={Logo} style={{ |
||||
width: width * 0.7, |
||||
height: width * 0.7 / 2.09, |
||||
}} /> |
||||
<Text style={{ |
||||
width: width, |
||||
paddingHorizontal: 10, |
||||
marginTop: 20, |
||||
fontSize: 20, |
||||
textAlign: 'right', |
||||
}}>{'دانوین'}</Text> |
||||
<Text style={{ |
||||
width: width, |
||||
paddingHorizontal: 10, |
||||
marginTop: 10, |
||||
fontSize: 14, |
||||
color: '#6f7074', |
||||
textAlign: 'right', |
||||
}}>{`یک کد تائیدیه به شماره ${props.route.params.phone} ارسال شد. آن را در قسمت زیر وارد کنید`}</Text> |
||||
<View style={{ |
||||
width: width - 10, |
||||
height: width / 8, |
||||
borderRadius: 8, |
||||
flexDirection: 'row', |
||||
marginTop: 10, |
||||
alignItems: 'center', |
||||
justifyContent: 'space-evenly' |
||||
}}> |
||||
<TextInput |
||||
style={styles.input} |
||||
underlineColorAndroid={'transparent'} |
||||
value={firstCode} |
||||
maxLength={1} |
||||
ref={ref => ref1 = ref} |
||||
onChangeText={text => onChangeCode(text, '1')} |
||||
/> |
||||
<TextInput |
||||
style={styles.input} |
||||
underlineColorAndroid={'transparent'} |
||||
value={secondCode} |
||||
maxLength={1} |
||||
ref={ref => ref2 = ref} |
||||
onChangeText={text => onChangeCode(text, '2')} |
||||
/> |
||||
<TextInput |
||||
style={styles.input} |
||||
underlineColorAndroid={'transparent'} |
||||
value={thirdCode} |
||||
maxLength={1} |
||||
ref={ref => ref3 = ref} |
||||
onChangeText={text => onChangeCode(text, '3')} |
||||
/> |
||||
<TextInput |
||||
style={styles.input} |
||||
underlineColorAndroid={'transparent'} |
||||
value={fourthCode} |
||||
maxLength={1} |
||||
ref={ref => ref4 = ref} |
||||
onChangeText={text => onChangeCode(text, '4')} |
||||
/> |
||||
</View> |
||||
<TouchableOpacity |
||||
disabled={loading} |
||||
style={{ |
||||
width: width - 10, |
||||
height: width / 9, |
||||
backgroundColor: '#6cbe44', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
borderRadius: 10, |
||||
marginTop: 15, |
||||
}} |
||||
onPress={() => submit()}> |
||||
{loading ? |
||||
<ActivityIndicator color={'white'} size={'small'} /> : |
||||
<Text style={{ |
||||
color: 'white', |
||||
fontSize: 18, |
||||
}}> |
||||
{'ثبت'} |
||||
</Text> |
||||
} |
||||
</TouchableOpacity> |
||||
<View> |
||||
<Text style={{marginTop: 30, textAlign: 'center'}}> |
||||
{'زمان باقی مانده تا انقضای کد: ' + time} |
||||
</Text> |
||||
<TouchableOpacity |
||||
style={{ |
||||
marginTop: 20, |
||||
}} |
||||
onPress={() => { |
||||
props.navigation.reset({ |
||||
index: 0, |
||||
routes: [{ name: 'Login' }], |
||||
}); |
||||
}}> |
||||
<Text style={{textAlign: 'center'}}> |
||||
{'بازگشت به مرحله قبل و اصلاح شماره'} |
||||
</Text> |
||||
</TouchableOpacity> |
||||
</View> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
input: { |
||||
width: width / 13 * 2, |
||||
height: width / 16 * 2, |
||||
backgroundColor: '#a2a2a2', |
||||
color: '#000', |
||||
fontSize: 22, |
||||
borderRadius: 8, |
||||
textAlign: 'center' |
||||
} |
||||
}) |
||||
|
||||
export default connect(mapStateToProps)(Otp); |
@ -0,0 +1,10 @@ |
||||
import mocks from './mocks'; |
||||
import mainServices from './services'; |
||||
|
||||
const mock = false; |
||||
|
||||
let services = {...mainServices}; |
||||
if (mock) { |
||||
services = mocks; |
||||
} |
||||
export default services; |
@ -0,0 +1,18 @@ |
||||
import { asyncAwesomeAlert, randomApiSleep } from '../../../utils/AsyncWrappers'; |
||||
|
||||
const data = { |
||||
|
||||
}; |
||||
|
||||
const sendOtpCode = async () => { |
||||
await randomApiSleep(); |
||||
return { |
||||
ok: true, |
||||
data: data |
||||
}; |
||||
}; |
||||
|
||||
|
||||
|
||||
const mocks = {sendOtpCode}; |
||||
export default mocks; |
@ -0,0 +1,13 @@ |
||||
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; |
After Width: | Height: | Size: 217 B |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1,192 @@ |
||||
import {t} from 'i18next'; |
||||
import React from 'react'; |
||||
import { |
||||
View, |
||||
Text, |
||||
Image, |
||||
Dimensions, |
||||
ScrollView, |
||||
Pressable, |
||||
} from 'react-native'; |
||||
import CustomPressable from '../../../components/Pressable'; |
||||
import Description from './Description'; |
||||
import LinkBox from './LinkBox'; |
||||
import Comments from './Comments'; |
||||
import Rates from './Rates'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import arrowMoreIcon from '../assets/arrowMore.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Book({product}) { |
||||
return ( |
||||
<ScrollView style={[tw.style('flex flex-col flex-1')]}> |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<View |
||||
style={[ |
||||
tw.style('rounded-md'), |
||||
{height: height / 5, width: width / 3.5}, |
||||
]}> |
||||
<Image |
||||
source={{uri: product.imageUrl}} |
||||
style={[tw.style('rounded-md h-full w-full')]} |
||||
/> |
||||
</View> |
||||
|
||||
<View |
||||
style={[ |
||||
tw.style('flex flex-col flex-1 justify-between items-end'), |
||||
{ |
||||
paddingRight: 10, |
||||
}, |
||||
]}> |
||||
<View style={tw.style('flex flex-col items-end')}> |
||||
<Text |
||||
style={{ |
||||
color: '#05335F', |
||||
fontSize: width / 17, |
||||
marginBottom: 5, |
||||
}}> |
||||
{product.name} |
||||
</Text> |
||||
<Text style={{color: '#196EC0', fontSize: width / 30}}> |
||||
{product.grade} |
||||
</Text> |
||||
</View> |
||||
<Text |
||||
style={[ |
||||
tw.style('text-right w-full'), |
||||
{color: '#323232', fontSize: width / 32}, |
||||
]}> |
||||
{product.text} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={tw.style( |
||||
'flex flex-row-reverse items-center justify-around py-6', |
||||
)}> |
||||
<View> |
||||
<Text |
||||
style={{ |
||||
color: '#196EC0', |
||||
textAlign: 'center', |
||||
fontSize: width / 27, |
||||
}}> |
||||
{' '} |
||||
{473 + '\n' + 'صفحه'} |
||||
</Text> |
||||
</View> |
||||
<View |
||||
style={{backgroundColor: '#196EC055', height: 20, width: 2}}></View> |
||||
<View> |
||||
<Text |
||||
style={{ |
||||
color: '#196EC0', |
||||
textAlign: 'center', |
||||
fontSize: width / 27, |
||||
}}> |
||||
{' '} |
||||
{'فیزیکی- دیجیتالی - ویدئو' + '\n' + 'در دسترس'} |
||||
</Text> |
||||
</View> |
||||
<View |
||||
style={{backgroundColor: '#196EC055', height: 20, width: 2}}></View> |
||||
<View> |
||||
<Text |
||||
style={{ |
||||
color: '#196EC0', |
||||
textAlign: 'center', |
||||
fontSize: width / 27, |
||||
}}> |
||||
{' '} |
||||
{4.8 + '\n' + 'امتیاز'} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View style={'flex flex-col mt-3'}> |
||||
<Text |
||||
style={[ |
||||
tw.style('w-full text-right font-medium'), |
||||
{color: '#196EC0', fontSize: width / 26}, |
||||
]}> |
||||
نسخه محصول را انتخاب کنید |
||||
</Text> |
||||
<View style={tw.style('flex justify-between')}></View> |
||||
</View> |
||||
<View |
||||
style={tw.style( |
||||
'flex flex-row-reverse justify-between flex-wrap py-3', |
||||
)}> |
||||
<CustomPressable |
||||
title={'نسخه فیزیکی'} |
||||
backgroundColor="transparent" |
||||
color={'#196EC0'} |
||||
border={{color: '#196EC0', width: 1}} |
||||
width={'49%'} |
||||
/> |
||||
<CustomPressable |
||||
title={'نسخه دیجیتال'} |
||||
backgroundColor="transparent" |
||||
color={'#196EC0'} |
||||
border={{color: '#196EC0', width: 1}} |
||||
width={'49%'} |
||||
/> |
||||
<CustomPressable |
||||
title={'خرید با قیمت 245.000 تومان'} |
||||
backgroundColor="#196EC0" |
||||
color={'white'} |
||||
border={{color: '#196EC0', width: 0}} |
||||
width={'65%'} |
||||
/> |
||||
<CustomPressable |
||||
title={'مشاهده نمونه'} |
||||
backgroundColor="transparent" |
||||
color={'#196EC0'} |
||||
border={{color: '#196EC0', width: 1}} |
||||
width={'33%'} |
||||
/> |
||||
<Pressable |
||||
style={[ |
||||
tw.style( |
||||
'w-full rounded-md flex flex-row justify-center items-center py-3.5', |
||||
), |
||||
{backgroundColor: '#196EC01a'}, |
||||
]}> |
||||
<Image |
||||
source={arrowMoreIcon} |
||||
style={{width: 12, height: 16, marginRight: 10}} |
||||
/> |
||||
|
||||
<Text |
||||
style={[tw.style(''), {color: '#275077', fontSize: width / 27}]}> |
||||
مشاهده دوره ویدئویی این محصول |
||||
</Text> |
||||
</Pressable> |
||||
</View> |
||||
<Description description={product.description} /> |
||||
<LinkBox title="مشخصات محصول" path="" /> |
||||
<LinkBox title="نقد بررسی و توضیحات تکمیلی محصول" path="" /> |
||||
<LinkBox title="پرسش و پاسخ" path="" /> |
||||
<View |
||||
style={tw.style( |
||||
'flex flex-row-reverse justify-between items-center my-4', |
||||
)}> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 25, color: '#275077'}, |
||||
tw.style('semibold'), |
||||
]}> |
||||
امتیازات و نظرات |
||||
</Text> |
||||
<Image |
||||
source={arrowMoreIcon} |
||||
style={{width: 12, height: 16, marginRight: 10}} |
||||
/> |
||||
</View> |
||||
<Rates rates={product.rates} /> |
||||
<Comments comments={product.comments} /> |
||||
</ScrollView> |
||||
); |
||||
} |
@ -0,0 +1,61 @@ |
||||
import React from 'react'; |
||||
import {View, Text, ScrollView, Image, Dimensions} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
|
||||
export default function Commnets({comments}) { |
||||
return ( |
||||
<ScrollView horizontal={true} style={{direction: 'rtl', marginTop: 20}}> |
||||
{comments.map((comment, index) => ( |
||||
<Comment comment={comment} key={index} /> |
||||
))} |
||||
</ScrollView> |
||||
); |
||||
} |
||||
|
||||
const Comment = ({comment}) => { |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw.style('flex flex-col rounded-md p-4 ml-2'), |
||||
{width: width / 1.3, borderWidth: 1, borderColor: '#7070701a'}, |
||||
]}> |
||||
<View style={[tw.style('flex flex-row justify-between items-center')]}> |
||||
<View style={tw.style('flex flex-row items-center')}> |
||||
<Image |
||||
source={comment.imageUrl} |
||||
style={[tw.style('rounded-full'), {width: 35, height: 35}]} |
||||
/> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 25, color: '#132F52'}, |
||||
tw.style('font-bold'), |
||||
]}> |
||||
{comment.name} |
||||
</Text> |
||||
</View> |
||||
<View style={tw.style('flex flex-row items-center')}> |
||||
<Text style={{fontSize: width / 38, color: '#196EC0'}}>18:20</Text> |
||||
<View |
||||
style={{ |
||||
backgroundColor: '#196EC055', |
||||
height: 12, |
||||
width: 2, |
||||
marginHorizontal: 4, |
||||
}}></View> |
||||
<Text style={{fontSize: width / 38, color: '#196EC0'}}> |
||||
1400/08/19 |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 32, lineHeight: 20, color: '#132F52'}, |
||||
tw.style('text-left mt-2'), |
||||
]}> |
||||
{comment.message} |
||||
</Text> |
||||
</View> |
||||
); |
||||
}; |
@ -0,0 +1,35 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, Image} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import arrowMoreIcon from '../assets/arrowMore.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Description({description}) { |
||||
return ( |
||||
<View style={[tw.style('w-full flex flex-col pt-6 mt-2 mb-3'), {borderTopWidth : 1, borderColor : '#86A0B944'}]}> |
||||
<View |
||||
style={tw.style('flex flex-row-reverse justify-between items-center mb-2')}> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 25, color: '#275077'}, |
||||
tw.style('semibold'), |
||||
]}> |
||||
توضیحات |
||||
</Text> |
||||
<Image |
||||
source={arrowMoreIcon} |
||||
style={{width: 12, height: 16, marginRight: 10}} |
||||
/> |
||||
</View> |
||||
<Text |
||||
style={[ |
||||
tw.style('w-full text-right mt-2'), |
||||
{fontSize: width / 30, color: '#323232bb', lineHeight: 20}, |
||||
]}> |
||||
{description} |
||||
</Text> |
||||
</View> |
||||
); |
||||
} |
@ -0,0 +1,31 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions, Image} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import arrowMoreIcon from '../assets/arrowMore.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Description({title, path}) { |
||||
return ( |
||||
<View |
||||
style={[ |
||||
tw.style('flex flex-row-reverse justify-between items-center mt-3 rounded-md px-5 py-4'), |
||||
{ |
||||
backgroundColor: '#50A9FF33' |
||||
} |
||||
]}> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 30, color: '#275077'}, |
||||
tw.style('semibold'), |
||||
]}> |
||||
{title} |
||||
</Text> |
||||
<Image |
||||
source={arrowMoreIcon} |
||||
style={{width: 12, height: 16, marginRight: 10}} |
||||
/> |
||||
</View> |
||||
); |
||||
} |
@ -0,0 +1,61 @@ |
||||
import React from 'react'; |
||||
import {View, Text, Dimensions} from 'react-native'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
|
||||
export default function Rates({rates}) { |
||||
return ( |
||||
<View style={tw.style('flex flex-row-reverse')}> |
||||
<View |
||||
style={[ |
||||
tw.style('flex flex-col items-center justify-center'), |
||||
{width: '25%'}, |
||||
]}> |
||||
<Text |
||||
style={[ |
||||
tw.style('font-bold'), |
||||
{fontSize: width / 10, color: '#05335F'}, |
||||
]}> |
||||
{rates.mid} |
||||
</Text> |
||||
<Text style={{fontSize: width / 30, color: '#707070'}}> |
||||
{'از' + ' ' + rates.allRates + ' ' + 'نفر'} |
||||
</Text> |
||||
</View> |
||||
<View style={[tw.style('flex flex-col flex-1'), {width: '60%'}]}> |
||||
{rates.fields.map((field, index) => ( |
||||
<Progress key={index} data={field} /> |
||||
))} |
||||
</View> |
||||
</View> |
||||
); |
||||
} |
||||
|
||||
const Progress = ({data}) => { |
||||
return ( |
||||
<View style={[tw.style('flex flex-1 flex-row items-center py-0.5')]}> |
||||
<Text style={{fontSize: width / 30, color: '#05335F'}}>{data.name}</Text> |
||||
<View |
||||
style={[ |
||||
tw.style('rounded-md ml-2 flex-1'), |
||||
{height: 6, backgroundColor: '#D3E9FF'}, |
||||
]}> |
||||
<View |
||||
style={[ |
||||
tw.style('h-full rounded-md my-auto'), |
||||
{width: data.value + '%', backgroundColor: '#2B8DEB'}, |
||||
]}></View> |
||||
</View> |
||||
<Text |
||||
style={{ |
||||
fontSize: width / 30, |
||||
width: width / 7.5, |
||||
textAlign: 'center', |
||||
color: '#05335F', |
||||
}}> |
||||
{data.value + '%'} |
||||
</Text> |
||||
</View> |
||||
); |
||||
}; |
@ -0,0 +1,207 @@ |
||||
import {t} from 'i18next'; |
||||
import React from 'react'; |
||||
import { |
||||
View, |
||||
Text, |
||||
Image, |
||||
Dimensions, |
||||
ScrollView, |
||||
Pressable, |
||||
} from 'react-native'; |
||||
import CustomPressable from '../../../components/Pressable'; |
||||
import Description from './Description'; |
||||
import LinkBox from './LinkBox'; |
||||
import Comments from './Comments'; |
||||
import Rates from './Rates'; |
||||
import tw from 'tailwind-react-native-classnames'; |
||||
import arrowMoreIcon from '../assets/arrowMore.png'; |
||||
|
||||
const width = Dimensions.get('window').width; |
||||
const height = Dimensions.get('window').height; |
||||
|
||||
export default function Video({product}) { |
||||
return ( |
||||
<ScrollView style={[tw.style('flex flex-col flex-1')]}> |
||||
<View style={tw.style('flex flex-column')}> |
||||
<View |
||||
style={[ |
||||
tw.style( |
||||
'w-full flex flex-row flex-1 justify-between items-center relative overflow-hidden', |
||||
), |
||||
{height: height / 3.8}, |
||||
]}> |
||||
{/* <View |
||||
style={[ |
||||
tw.style('rounded-full bg-black bg-opacity-20 z-50'), |
||||
{width: 50, height: 50}, |
||||
]}></View> */} |
||||
<Image |
||||
source={product.poster} |
||||
style={tw.style('w-full rounded-md h-full absolute left-0 top-0')} |
||||
/> |
||||
<Image |
||||
source={{uri: product.imageUrl}} |
||||
style={[ |
||||
tw.style('rounded-md h-full rounded-md ml-2'), |
||||
{width: width / 5, height: height / 7}, |
||||
]} |
||||
/> |
||||
</View> |
||||
|
||||
<View |
||||
style={[ |
||||
tw.style('flex flex-col flex-1 justify-between items-end'), |
||||
{ |
||||
paddingRight: 10, |
||||
}, |
||||
]}> |
||||
<View style={tw.style('flex flex-col items-end')}> |
||||
<Text |
||||
style={{ |
||||
marginTop : 5, |
||||
color: '#05335F', |
||||
fontSize: width / 17, |
||||
marginBottom: 5, |
||||
}}> |
||||
{product.name} |
||||
</Text> |
||||
<Text style={{color: '#196EC0', fontSize: width / 30, marginBottom: 10}}> |
||||
{product.grade} |
||||
</Text> |
||||
</View> |
||||
<Text |
||||
style={[ |
||||
tw.style('text-right w-full'), |
||||
{color: '#323232', fontSize: width / 32}, |
||||
]}> |
||||
{product.text} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View |
||||
style={tw.style( |
||||
'flex flex-row-reverse items-center justify-around py-6', |
||||
)}> |
||||
<View> |
||||
<Text |
||||
style={{ |
||||
color: '#196EC0', |
||||
textAlign: 'center', |
||||
fontSize: width / 27, |
||||
}}> |
||||
{' '} |
||||
{473 + '\n' + 'صفحه'} |
||||
</Text> |
||||
</View> |
||||
<View |
||||
style={{backgroundColor: '#196EC055', height: 20, width: 2}}></View> |
||||
<View> |
||||
<Text |
||||
style={{ |
||||
color: '#196EC0', |
||||
textAlign: 'center', |
||||
fontSize: width / 27, |
||||
}}> |
||||
{' '} |
||||
{'فیزیکی- دیجیتالی - ویدئو' + '\n' + 'در دسترس'} |
||||
</Text> |
||||
</View> |
||||
<View |
||||
style={{backgroundColor: '#196EC055', height: 20, width: 2}}></View> |
||||
<View> |
||||
<Text |
||||
style={{ |
||||
color: '#196EC0', |
||||
textAlign: 'center', |
||||
fontSize: width / 27, |
||||
}}> |
||||
{' '} |
||||
{4.8 + '\n' + 'امتیاز'} |
||||
</Text> |
||||
</View> |
||||
</View> |
||||
<View style={'flex flex-col mt-3'}> |
||||
<Text |
||||
style={[ |
||||
tw.style('w-full text-right font-medium'), |
||||
{color: '#196EC0', fontSize: width / 26}, |
||||
]}> |
||||
نسخه محصول را انتخاب کنید |
||||
</Text> |
||||
<View style={tw.style('flex justify-between')}></View> |
||||
</View> |
||||
<View |
||||
style={tw.style( |
||||
'flex flex-row-reverse justify-between flex-wrap py-3', |
||||
)}> |
||||
<CustomPressable |
||||
title={'نسخه فیزیکی'} |
||||
backgroundColor="transparent" |
||||
color={'#196EC0'} |
||||
border={{color: '#196EC0', width: 1}} |
||||
width={'49%'} |
||||
/> |
||||
<CustomPressable |
||||
title={'نسخه دیجیتال'} |
||||
backgroundColor="transparent" |
||||
color={'#196EC0'} |
||||
border={{color: '#196EC0', width: 1}} |
||||
width={'49%'} |
||||
/> |
||||
<CustomPressable |
||||
title={'خرید با قیمت 245.000 تومان'} |
||||
backgroundColor="#196EC0" |
||||
color={'white'} |
||||
border={{color: '#196EC0', width: 0}} |
||||
width={'65%'} |
||||
/> |
||||
<CustomPressable |
||||
title={'مشاهده نمونه'} |
||||
backgroundColor="transparent" |
||||
color={'#196EC0'} |
||||
border={{color: '#196EC0', width: 1}} |
||||
width={'33%'} |
||||
/> |
||||
<Pressable |
||||
style={[ |
||||
tw.style( |
||||
'w-full rounded-md flex flex-row justify-center items-center py-3.5', |
||||
), |
||||
{backgroundColor: '#196EC01a'}, |
||||
]}> |
||||
<Image |
||||
source={arrowMoreIcon} |
||||
style={{width: 12, height: 16, marginRight: 10}} |
||||
/> |
||||
|
||||
<Text |
||||
style={[tw.style(''), {color: '#275077', fontSize: width / 27}]}> |
||||
مشاهده دوره ویدئویی این محصول |
||||
</Text> |
||||
</Pressable> |
||||
</View> |
||||
<Description description={product.description} /> |
||||
<LinkBox title="مشخصات محصول" path="" /> |
||||
<LinkBox title="نقد بررسی و توضیحات تکمیلی محصول" path="" /> |
||||
<LinkBox title="پرسش و پاسخ" path="" /> |
||||
<View |
||||
style={tw.style( |
||||
'flex flex-row-reverse justify-between items-center my-4', |
||||
)}> |
||||
<Text |
||||
style={[ |
||||
{fontSize: width / 25, color: '#275077'}, |
||||
tw.style('semibold'), |
||||
]}> |
||||
امتیازات و نظرات |
||||
</Text> |
||||
<Image |
||||
source={arrowMoreIcon} |
||||
style={{width: 12, height: 16, marginRight: 10}} |
||||
/> |
||||
</View> |
||||
<Rates rates={product.rates} /> |
||||
<Comments comments={product.comments} /> |
||||
</ScrollView> |
||||
); |
||||
} |
@ -0,0 +1,76 @@ |
||||
import React from 'react'; |
||||
import {View, StyleSheet, Dimensions, ScrollView} from 'react-native'; |
||||
import Book from './components/Book'; |
||||
import Video from './components/Video'; |
||||
import {connect} from 'react-redux'; |
||||
import userImage from './assets/user.png'; |
||||
import poster from './assets/poster.png'; |
||||
|
||||
function Product({ |
||||
product = { |
||||
type: 'ویدئوها', |
||||
name: 'ریاضی', |
||||
price: '145.000 تومان', |
||||
imageUrl: 'https://dnvn.ir/api/v1/file/2105', |
||||
poster : poster, |
||||
grade: 'پایه هفتم ابتدایی', |
||||
text: 'خالد حسینی تو رمان باد بادک باز مینویسه : ﻣﺮﺩ ﺁﻫﺴﺘﻪ ﺩﺭ ﮔﻮﺵ ﻓﺮﺯﻧﺪ ﺗﺎﺯﻩ ﺑﻪ ﺑﻠﻮﻍ ﺭﺳﯿﺪﻩ ﺍﺵ ﺑﺮﺍﯼ ﭘﻨﺪ ﭼﻨﯿﻦ ﻧﺠﻮﺍ ﮐﺮﺩ : ” ﭘﺴﺮﻡ ﺩﺭ ﺯﻧﺪﮔﯽ ﻫﺮﮔﺰ ﺩﺯﺩﯼ ﻧﮑﻦ ” ﭘﺴﺮ ﻣﺘﻌﺠﺐ ﻭ ﻣﺒﻬﻮﺕ ﺑﻪ ﭘﺪﺭ ﻧﮕﺎﻩ ﮐﺮﺩ ﺑﺪﯾﻦ ', |
||||
description: |
||||
'خالد حسینی تو رمان باد بادک باز مینویسه : ﻣﺮﺩ ﺁﻫﺴﺘﻪ ﺩﺭ ﮔﻮﺵ ﻓﺮﺯﻧﺪ ﺗﺎﺯﻩ ﺑﻪ ﺑﻠﻮﻍ ﺭﺳﯿﺪﻩ ﺍﺵ ﺑﺮﺍﯼ ﭘﻨﺪ ﭼﻨﯿﻦ ﻧﺠﻮﺍ ﮐﺮﺩ : ” ﭘﺴﺮﻡ ﺩﺭ ﺯﻧﺪﮔﯽ ﻫﺮﮔﺰ ﺩﺯﺩﯼ ﻧﮑﻦ ” ﭘﺴﺮ ﻣﺘﻌﺠﺐ ﻭ ﻣﺒﻬﻮﺕ ﺑﻪ ﭘﺪﺭ ﻧﮕﺎﻩ ﮐﺮﺩ ﺑﺪﯾﻦ ﻣﻌﻨﺎ ﮐﻪ ﺍﻭ ﻫﺮﮔﺰ ﺩﺳﺖ ﮐﺞ ﻧﺪﺍﺷﺘﻪ ﭘﺪﺭ ﺑﻪ ﻧﮕﺎﻩ ﻣﺘﻌﺠﺐ ﻓﺮﺯﻧﺪ ﻟﺒﺨﻨﺪﯼ ﺯﺩ ﻭ ﺍﺩﺍﻣﻪ ﺩﺍﺩ : ﺩﺭ ﺯﻧﺪﮔﯽ ﺩﺭﻭﻍ ﻧﮕﻮ ﭼﺮﺍ ﮐﻪ ﺍﮔﺮ ﮔﻔﺘﯽ ﺻﺪﺍﻗﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺧﯿﺎﻧﺖ ﻧﮑﻦ ﮐﻪ ﺍﮔﺮ ﮐﺮﺩﯼ ﻋﺸﻖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺧﺸﻮﻧﺖ ﻧﮑﻦ ﺍﮔﺮ ﮐﺮﺩﯼ ﻣﺤﺒﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﻧﺎ ﺣﻖ ﻧﮕﻮ ﺍﮔﺮ ﮔﻔﺘﯽ ﺣﻖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍﯼ، ﺑﯽ ﺣﯿﺎﯾﯽ ﻧﮑﻦ ﺍﮔﺮ ﮐﺮﺩﯼ ﺷﺮﺍﻓﺖ ﺭﺍ ﺩﺯﺩﯾﺪﻩ ﺍی... ﭘﺲ ﺩﺭ ﺯﻧﺪﮔﯽ ﻓﻘﻂ ﺩﺯﺩﯼ نکن ', |
||||
rates: { |
||||
mid: 4.5, |
||||
allRates: 2456, |
||||
fields: [ |
||||
{name: 'field1', value: 49}, |
||||
{name: 'field2', value: 31}, |
||||
{name: 'field3', value: 9}, |
||||
{name: 'field4', value: 5}, |
||||
{name: 'field5', value: 4}, |
||||
], |
||||
}, |
||||
comments: [ |
||||
{ |
||||
name: 'سورنا عابدی', |
||||
imageUrl: userImage, |
||||
vote: 4, |
||||
date: new Date(), |
||||
message: |
||||
'خالد حسینی تو رمان باد بادک باز مینویسه : ﻣﺮﺩ ﺁﻫﺴﺘﻪ ﺩﺭ ﮔﻮﺵ ﻓﺮﺯﻧﺪ ﺗﺎﺯﻩ ﺑﻪ ﺑﻠﻮﻍ ﺭﺳﯿﺪﻩ ﺍﺵ ﺑﺮﺍﯼ ﭘﻨﺪ ﭼﻨﯿﻦ ﻧﺠﻮﺍ ﮐﺮﺩ : ” ﭘﺴﺮﻡ ﺩﺭ ﺯﻧﺪﮔﯽ ﻫﺮﮔﺰ ﺩﺯﺩﯼ ﻧﮑﻦ ” ﭘﺴﺮ ﻣﺘﻌﺠﺐ ﻭ ﻣﺒﻬﻮﺕ ﺑﻪ ﭘﺪﺭ ﻧﮕﺎﻩ ﮐﺮﺩ ﺑﺪﯾﻦ ﻣﻌﻨﺎ ﮐﻪ ﺍﻭ ﻫﺮﮔﺰ ﺩﺳﺖ ﮐﺞ ﻧﺪﺍﺷﺘﻪ ﭘﺪﺭ ﺑﻪ ﻧﮕﺎﻩ ﻣﺘﻌﺠﺐ ﻓﺮﺯﻧﺪ ﻟﺒﺨﻨﺪﯼ ﺯﺩ ﻭ ﺍﺩﺍﻣﻪ ', |
||||
}, |
||||
{ |
||||
name: 'سورنا عابدی', |
||||
imageUrl: userImage, |
||||
vote: 4, |
||||
date: new Date(), |
||||
message: |
||||
'خالد حسینی تو رمان باد بادک باز مینویسه : ﻣﺮﺩ ﺁﻫﺴﺘﻪ ﺩﺭ ﮔﻮﺵ ﻓﺮﺯﻧﺪ ﺗﺎﺯﻩ ﺑﻪ ﺑﻠﻮﻍ ﺭﺳﯿﺪﻩ ﺍﺵ ﺑﺮﺍﯼ ﭘﻨﺪ ﭼﻨﯿﻦ ﻧﺠﻮﺍ ﮐﺮﺩ : ” ﭘﺴﺮﻡ ﺩﺭ ﺯﻧﺪﮔﯽ ﻫﺮﮔﺰ ﺩﺯﺩﯼ ﻧﮑﻦ ” ﭘﺴﺮ ﻣﺘﻌﺠﺐ ﻭ ﻣﺒﻬﻮﺕ ﺑﻪ ﭘﺪﺭ ﻧﮕﺎﻩ ﮐﺮﺩ ﺑﺪﯾﻦ ﻣﻌﻨﺎ ﮐﻪ ﺍﻭ ﻫﺮﮔﺰ ﺩﺳﺖ ﮐﺞ ﻧﺪﺍﺷﺘﻪ ﭘﺪﺭ ﺑﻪ ﻧﮕﺎﻩ ﻣﺘﻌﺠﺐ ﻓﺮﺯﻧﺪ ﻟﺒﺨﻨﺪﯼ ﺯﺩ ﻭ ﺍﺩﺍﻣﻪ ', |
||||
}, |
||||
], |
||||
}, |
||||
}) { |
||||
return ( |
||||
<ScrollView |
||||
contentContainerStyle={styles.contentContainerStyle} |
||||
style={styles.container}> |
||||
{product.type === 'ویدئوها' ? ( |
||||
<Video product={product} /> |
||||
) : ( |
||||
<Book product={product} /> |
||||
)} |
||||
</ScrollView> |
||||
); |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
contentContainerStyle: { |
||||
paddingBottom: 50, |
||||
}, |
||||
container: { |
||||
width: Dimensions.get('window').width, |
||||
backgroundColor: 'white', |
||||
flexDirection: 'column', |
||||
paddingVertical: 5, |
||||
paddingHorizontal: 10, |
||||
}, |
||||
}); |
||||
export default Product; |