reza first commit

master
Reza_ashrafi 2 years ago
parent cd997ab64f
commit 1f0ee832db
  1. 11
      .expo-shared/README.md
  2. 5
      .expo-shared/assets.json
  3. 81
      App.js
  4. 14
      app.json
  5. BIN
      assets/adaptive-icon.png
  6. BIN
      assets/appLogo.png
  7. BIN
      assets/favicon.png
  8. BIN
      assets/fonts/Farsi/Black.ttf
  9. BIN
      assets/fonts/Farsi/Bold.ttf
  10. BIN
      assets/fonts/Farsi/DemiBold.ttf
  11. BIN
      assets/fonts/Farsi/IRANSansXFaNum-ExtraBold.ttf
  12. BIN
      assets/fonts/Farsi/IRANSansXFaNum-Thin.ttf
  13. BIN
      assets/fonts/Farsi/IRANSansXFaNum-UltraLight.ttf
  14. BIN
      assets/fonts/Farsi/Light.ttf
  15. BIN
      assets/fonts/Farsi/Medium.ttf
  16. BIN
      assets/fonts/Farsi/Regular.ttf
  17. BIN
      assets/icon.png
  18. BIN
      assets/splash.png
  19. 24
      bottomNavigation.json
  20. 18
      eas.json
  21. 10
      filters.json
  22. 24
      navigation/bottomNavigation.js
  23. 668
      navigation/index.js
  24. 39
      package.json
  25. BIN
      src/assets/icons/activation.png
  26. BIN
      src/assets/icons/bookmark.png
  27. BIN
      src/assets/icons/leftWhite.png
  28. BIN
      src/assets/icons/link.png
  29. BIN
      src/assets/icons/pdf.png
  30. BIN
      src/assets/icons/ppt.png
  31. BIN
      src/assets/images/logo.png
  32. 172
      src/components/AlertModal.js
  33. 62
      src/components/Avatar.js
  34. 26
      src/components/Blur.js
  35. 107
      src/components/CustomTextInput.js
  36. 24
      src/components/Divider.js
  37. 539
      src/components/Drawer.js
  38. 63
      src/components/Empty.js
  39. 30
      src/components/FormButton.js
  40. 58
      src/components/Header.js
  41. 18
      src/components/ImageSlider.js
  42. 35
      src/components/MapSelector.js
  43. 28
      src/components/MusicPlayer.js
  44. 726
      src/components/Navbar.js
  45. 20
      src/components/Or.js
  46. 62
      src/components/Pressable.js
  47. 38
      src/components/Progress.js
  48. 32
      src/components/Redirect.js
  49. 39
      src/components/Scanner.js
  50. 63
      src/components/Search.js
  51. 91
      src/components/Select.js
  52. 46
      src/constants/Colors.js
  53. 9
      src/constants/defaultValues.js
  54. 21
      src/constants/fontSize.js
  55. 27
      src/redux/actions/activation.js
  56. 13
      src/redux/actions/blog.js
  57. 18
      src/redux/actions/book.js
  58. 32
      src/redux/actions/comment.js
  59. 14
      src/redux/actions/content.js
  60. 20
      src/redux/actions/faq.js
  61. 22
      src/redux/actions/file.js
  62. 8
      src/redux/actions/form.js
  63. 19
      src/redux/actions/index.js
  64. 26
      src/redux/actions/product.js
  65. 54
      src/redux/actions/public.js
  66. 33
      src/redux/actions/qr.js
  67. 17
      src/redux/actions/transport.js
  68. 61
      src/redux/actions/user.js
  69. 36
      src/redux/actions/userAddress.js
  70. 59
      src/redux/actions/userFactor.js
  71. 27
      src/redux/actions/userFavorite.js
  72. 42
      src/redux/actions/userProduct.js
  73. 11
      src/redux/actions/vote.js
  74. 6
      src/redux/index.js
  75. 153
      src/redux/proxy.js
  76. 39
      src/redux/reducers/activation.js
  77. 36
      src/redux/reducers/blog.js
  78. 96
      src/redux/reducers/book.js
  79. 37
      src/redux/reducers/comment.js
  80. 55
      src/redux/reducers/faq.js
  81. 26
      src/redux/reducers/file.js
  82. 24
      src/redux/reducers/form.js
  83. 18
      src/redux/reducers/index.js
  84. 31
      src/redux/reducers/product.js
  85. 190
      src/redux/reducers/public.js
  86. 33
      src/redux/reducers/qr.js
  87. 25
      src/redux/reducers/transport.js
  88. 75
      src/redux/reducers/user.js
  89. 32
      src/redux/reducers/userAddress.js
  90. 67
      src/redux/reducers/userFactor.js
  91. 41
      src/redux/reducers/userFavorite.js
  92. 62
      src/redux/reducers/userProduct.js
  93. 27
      src/redux/reducers/vote.js
  94. 65
      src/redux/store.js
  95. 55
      src/screens/AR/components/Book.js
  96. 111
      src/screens/AR/index.js
  97. BIN
      src/screens/Activation/assets/QR.png
  98. 169
      src/screens/Activation/index.js
  99. 618
      src/screens/Address/index.js
  100. 323
      src/screens/Blog/index.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,11 @@
> Why do I have a folder named ".expo-shared" in my project?
The ".expo-shared" folder is created when running commands that produce state that is intended to be shared with all developers on the project. For example, "npx expo-optimize".
> What does the "assets.json" file contain?
The "assets.json" file describes the assets that have been optimized through "expo-optimize" and do not need to be processed again.
> Should I commit the ".expo-shared" folder?
Yes, you should share the ".expo-shared" folder with your collaborators.

@ -1,4 +1 @@
{ {}
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
}

@ -1,20 +1,69 @@
import { StatusBar } from 'expo-status-bar'; import { StyleSheet, View } from "react-native";
import { StyleSheet, Text, View } from 'react-native'; import { useFonts } from "expo-font";
import Navigation from "./navigation/index";
import AlertModal from "./src/components/AlertModal";
import { Provider } from "react-redux";
import { store, persistor } from "./src/redux/store";
import * as SplashScreen from 'expo-splash-screen';
import React from "react";
import { PersistGate } from "redux-persist/integration/react";
const App = () => {
const [appIsReady, setAppIsReady] = React.useState(false);
let [fontsLoaded] = useFonts({
light: require("./assets/fonts/Farsi/Light.ttf"),
regular: require("./assets/fonts/Farsi/Regular.ttf"),
bold: require("./assets/fonts/Farsi/Medium.ttf"),
demi: require("./assets/fonts/Farsi/DemiBold.ttf"),
});
React.useEffect(() => {
async function prepare() {
try {
// Keep the splash screen visible while we fetch resources
await SplashScreen.preventAutoHideAsync();
// Pre-load fonts, make any API calls you need to do here
// Artificially delay for two seconds to simulate a slow loading
// experience. Please remove this if you copy and paste the code!
await new Promise((resolve) => setTimeout(resolve, 2000));
} catch (e) {
console.warn(e);
} finally {
// Tell the application to render
setAppIsReady(true);
}
}
prepare();
}, []);
const onLayoutRootView = React.useCallback(async () => {
if (fontsLoaded) {
// This tells the splash screen to hide immediately! If we call this after
// `setAppIsReady`, then we may see a blank screen while the app is
// loading its initial state and rendering its first pixels. So instead,
// we hide the splash screen once we know the root view has already
// performed layout.
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null;
}
export default function App() {
return ( return (
<View style={styles.container}> <View style={{ flex: 1 }} onLayout={onLayoutRootView}>
<Text>Open up App.js to start working on your app!</Text> <Provider store={store}>
<StatusBar style="auto" /> <PersistGate loading={null} persistor={persistor}>
<Navigation />
<AlertModal />
</PersistGate>
</Provider>
</View> </View>
); );
} };
const styles = StyleSheet.create({ const styles = StyleSheet.create({});
container: {
flex: 1, export default App;
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

@ -4,10 +4,10 @@
"slug": "final_danovin_expo", "slug": "final_danovin_expo",
"version": "1.0.0", "version": "1.0.0",
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/icon.png", "icon": "./assets/appLogo.png",
"userInterfaceStyle": "light", "userInterfaceStyle": "light",
"splash": { "splash": {
"image": "./assets/splash.png", "image": "",
"resizeMode": "contain", "resizeMode": "contain",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
@ -22,12 +22,14 @@
}, },
"android": { "android": {
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "",
"backgroundColor": "#FFFFFF" "backgroundColor": "#FFFFFF"
} },
"package": "com.appsazz.final_danovin_expo"
}, },
"web": { "web": {
"favicon": "./assets/favicon.png" "favicon": ""
} },
"description": ""
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

@ -0,0 +1,24 @@
{
"bottomNavigationList": {
"home": {
"label": "خانه",
"isActive": true
},
"products": {
"label": "کتابها",
"isActive": true
},
"vod": {
"label": "ویدئوها",
"isActive": true
},
"cart": {
"label": "سبد خرید",
"isActive": true
},
"profile": {
"label": "پروفایل",
"isActive": true
}
}
}

@ -0,0 +1,18 @@
{
"cli": {
"version": ">= 0.52.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
},
"submit": {
"production": {}
}
}

@ -0,0 +1,10 @@
{
"sort": ["مرتب سازی", "مرتب سازی", "محبوب ترین", "جدیدترین"],
"productTypes" : [
"نوع محصول",
"کتاب فیزیکی",
"کتاب دیجیتال",
"دوره ویدئویی",
"بسته های آموزشی"
]
}

@ -0,0 +1,24 @@
const bottomNavigationList = {
home: {
label: "خانه",
isActive: true,
},
products: {
label: "کتابها",
isActive: true,
},
vod: {
label: "ویدئوها",
isActive: false,
},
cart: {
label: "سبد خرید",
isActive: true,
},
profile: {
label: "پروفایل",
isActive: true,
},
};
export default bottomNavigationList;

@ -0,0 +1,668 @@
import React, { useEffect } from "react";
import { Restart } from "fiction-expo-restart";
import { I18nManager, StatusBar } from "react-native";
import * as Linking from "expo-linking";
import Svg, { G, Path } from "react-native-svg";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { connect } from "react-redux";
import { user, publicApi } from "../src/redux/actions";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import bottomNavigationList from "./bottomNavigation";
//components
import OrderDetails from "../src/screens/OrderDetails";
import OrdersFollowUp from "../src/screens/OrdersFollowUp";
import Splash from "../src/screens/Splash";
import Home from "../src/screens/Home";
import Products from "../src/screens/Products";
import Login from "../src/screens/Login";
import Otp from "../src/screens/Otp";
import Product from "../src/screens/Product";
import AR from "../src/screens/AR";
import QR from "../src/screens/QR";
import QRContent from "../src/screens/QRContent";
import Faq from "../src/screens/Faq";
import Activation from "../src/screens/Activation";
import Videos from "../src/screens/Videos";
import Video from "../src/screens/Video";
import VideoDisplay from "../src/screens/VideoDisplay";
import Contact from "../src/screens/Contact";
import Tests from "../src/screens/Tests";
import ShoppingCart from "../src/screens/ShoppingCart";
import DeliveryForm from "../src/screens/DeliveryForm";
import Address from "../src/screens/Address";
import Profile from "../src/screens/Profile";
import ProfileBookmark from "../src/screens/Profile/components/ProfileBookmark";
import ProfileAddress from "../src/screens/Profile/components/ProfileAddress";
import Blogs from "../src/screens/Blogs";
import Blog from "../src/screens/Blog";
import Sample from "../src/screens/Product/components/Sample";
import Info from "../src/screens/Product/components/Info";
import Rules from "../src/screens/Rules/index";
import MyCourses from "../src/screens/Profile/components/MyCourses";
import Ticket from "../src/screens/Contact/layouts/Ticket";
import Tickets from "../src/screens/Contact/layouts/Tickets";
import TicketStatus from "../src/screens/Contact/layouts/TicketStatus";
import MoreBlog from "../src/screens/Blogs/layouts/More";
//style
import Colors from "../src/constants/Colors";
import fontSize from "../src/constants/fontSize";
const Tab = createBottomTabNavigator();
const BottomTabNavigator = ({ theme, userProducts }) => {
const insets = useSafeAreaInsets();
const [headerShown, setHeaderShown] = React.useState(true);
React.useEffect(() => {
setTimeout(() => {
setHeaderShown(false);
}, 600);
}, []);
return (
<Tab.Navigator
initialRouteName="HomeTab"
screenOptions={{
tabBarHideOnKeyboard: true,
headerShown,
headerStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
tabBarIconStyle: {
transform: [{ scaleX: -1 }],
},
tabBarLabelPosition: "below-icon",
tabBarActiveTintColor:
theme === "light" ? Colors.theme1.green79 : Colors.theme1.greenCF,
tabBarInactiveTintColor:
theme === "light" ? Colors.theme1.gray20 : Colors.theme1.white,
tabBarStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
transform: [{ scaleX: -1 }],
height: 65 + insets.bottom,
borderWidth: 0,
},
tabBarLabelStyle: {
transform: [{ scaleX: -1 }, { translateY: -5 }],
fontSize: fontSize.xs,
fontFamily: "bold",
},
tabBarShowLabel: true,
}}
>
{bottomNavigationList.home.isActive ? (
<Tab.Screen
name="HomeTab"
children={() => <HomeStackScreen theme={theme} />}
options={{
title: bottomNavigationList.home.label,
tabBarIcon: ({ focused, color }) =>
focused ? (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={33.58}
height={33.579}
>
<Path
d="M12.62 3.974 5.079 9.85a6.658 6.658 0 0 0-2.281 4.645v10.368a5.912 5.912 0 0 0 5.89 5.9h16.2a5.909 5.909 0 0 0 5.89-5.89V14.691a6.609 6.609 0 0 0-2.518-4.827l-8.644-6.058a6.278 6.278 0 0 0-6.996.168Z"
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.greenCF
}
/>
<Path
data-name="Vector"
d="M16.79 25.471v-6.693"
fill="none"
stroke={theme === "light" ? "#fff" : Colors.theme1.dark}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</Svg>
) : (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={33.58}
height={33.579}
style={{
transform: [{ scale: 0.7 }],
}}
>
<Path
d="M12.62 3.974 5.079 9.85a6.658 6.658 0 0 0-2.281 4.645v10.368a5.912 5.912 0 0 0 5.89 5.9h16.2a5.909 5.909 0 0 0 5.89-5.89V14.691a6.609 6.609 0 0 0-2.518-4.827l-8.644-6.058a6.278 6.278 0 0 0-6.996.168Z"
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
<Path
data-name="Vector"
d="M16.79 25.471v-6.693"
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</Svg>
),
}}
/>
) : null}
{bottomNavigationList.products.isActive ? (
<Tab.Screen
name="ProductsTab"
children={() => <ProductsStackScreen theme={theme} />}
options={{
title: bottomNavigationList.products.label,
tabBarIcon: ({ focused, color }) =>
focused ? (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={35.135}
height={34.763}
>
<Path
d="M32.207 24.227V6.798a2.869 2.869 0 0 0-3.179-2.875h-.088a27.857 27.857 0 0 0-10.35 3.422l-.249.159a1.641 1.641 0 0 1-1.552 0l-.361-.216A27.72 27.72 0 0 0 6.09 3.909a2.864 2.864 0 0 0-3.162 2.874v17.444a2.981 2.981 0 0 0 2.547 2.859l.425.058a37.976 37.976 0 0 1 10.892 3.524l.059.029a1.6 1.6 0 0 0 1.405 0 37.631 37.631 0 0 1 10.921-3.552l.483-.058a2.981 2.981 0 0 0 2.547-2.86Z"
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.greenCF
}
/>
<Path
data-name="Vector"
d="M17.567 8.851v20.774M29.213 12.298h-3.294M29.159 16.643h-4.392"
fill="none"
stroke={theme === "light" ? "#fff" : Colors.theme1.dark}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</Svg>
) : (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={35.135}
height={34.763}
style={{
transform: [{ scale: 0.7 }],
}}
>
<G
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
>
<Path d="M32.207 24.227V6.798a2.869 2.869 0 0 0-3.179-2.875h-.088a27.857 27.857 0 0 0-10.35 3.422l-.249.159a1.641 1.641 0 0 1-1.552 0l-.361-.216A27.72 27.72 0 0 0 6.09 3.909a2.864 2.864 0 0 0-3.162 2.874v17.444a2.981 2.981 0 0 0 2.547 2.859l.425.058a37.976 37.976 0 0 1 10.892 3.524l.059.029a1.6 1.6 0 0 0 1.405 0 37.631 37.631 0 0 1 10.921-3.552l.483-.058a2.981 2.981 0 0 0 2.547-2.86Z" />
<Path
data-name="Vector"
d="M17.567 7.666v21.959M29.213 12.298h-3.294M29.159 16.643h-4.392"
/>
</G>
</Svg>
),
}}
/>
) : null}
{bottomNavigationList.vod.isActive ? (
<Tab.Screen
name="VODTab"
children={() => <VODStackScreen theme={theme} />}
options={{
unmountOnExit: true,
unmountOnBlur: true,
title: bottomNavigationList.vod.label,
tabBarIcon: ({ focused, color }) =>
focused ? (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={35}
height={31.1}
>
<G data-name="Group 2000">
<Path
d="M25.421 29.241H8.974C4.04 29.241.75 26.392.75 19.744V10.25c0-6.651 3.29-9.5 8.224-9.5h16.447c4.935 0 8.229 2.849 8.229 9.5v9.5c0 6.642-3.294 9.491-8.229 9.491Z"
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.greenCF
}
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.greenCF
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
data-name="vuesax/linear/music-playlist"
/>
<Path
data-name="Vector"
d="M12.427 14.995v-2.083c0-2.673 1.892-3.766 4.2-2.43l1.805 1.042 1.806 1.041c2.308 1.336 2.308 3.523 0 4.86l-1.806 1.041-1.805 1.046c-2.308 1.332-4.2.239-4.2-2.434v-2.083Z"
fill="none"
stroke={theme === "light" ? "#fff" : Colors.theme1.dark}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</G>
</Svg>
) : (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={35}
height={32}
style={{
transform: [{ scale: 0.7 }],
}}
>
<G data-name="Group 1999">
<Path
d="M25.421 29.241H8.974C4.04 29.241.75 26.392.75 19.744V10.25c0-6.651 3.29-9.5 8.224-9.5h16.447c4.935 0 8.229 2.849 8.229 9.5v9.5c0 6.642-3.294 9.491-8.229 9.491Z"
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
data-name="vuesax/linear/music-playlist"
/>
<Path
data-name="Vector"
d="M12.427 14.995v-2.083c0-2.673 1.892-3.766 4.2-2.43l1.805 1.042 1.806 1.041c2.308 1.336 2.308 3.523 0 4.86l-1.806 1.041-1.805 1.046c-2.308 1.332-4.2.239-4.2-2.434v-2.083Z"
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</G>
</Svg>
),
}}
/>
) : null}
{bottomNavigationList.cart.isActive ? (
<Tab.Screen
name="ShoppingCartTab"
children={() => <CARTStackScreen theme={theme} />}
options={{
tabBarBadge: userProducts.filter((product) => product.condition < 2)
.length
? userProducts.filter((product) => product.condition < 2).length
: null,
tabBarBadgeStyle: {
color: "white",
backgroundColor:
theme === "light"
? Colors.theme1.greenCF
: Colors.theme1.greenCF,
fontSize: fontSize.sm,
paddingTop: 2,
color:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
borderWidth: 1,
borderColor:
theme === "light" ? Colors.theme1.greenCF : Colors.theme1.dark,
fontFamily: "bold",
},
title: bottomNavigationList.cart.label,
tabBarIcon: ({ focused, color }) =>
focused ? (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={31.017}
height={31.017}
style={{ transform: [{ scale: 1.2 }] }}
>
<G
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.greenCF
}
stroke={theme === "light" ? "white" : Colors.theme1.dark}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
data-name="vuesax/linear/bag-2"
>
<Path d="M9.693 9.912V8.659a6.168 6.168 0 0 1 5.247-6.036 5.816 5.816 0 0 1 6.384 5.79v1.782" />
<Path
data-name="Vector"
d="M11.631 28.433h7.754c5.2 0 6.126-2.081 6.4-4.614l.969-7.754c.345-3.154-.555-5.726-6.076-5.726H10.339c-5.519 0-6.423 2.572-6.074 5.725l.969 7.754c.271 2.534 1.202 4.615 6.397 4.615ZM20.027 15.509h.011M10.979 15.509h.011"
/>
</G>
</Svg>
) : (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={31.017}
height={31.017}
style={{
transform: [{ scale: 0.8 }],
}}
>
<G
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
data-name="vuesax/linear/bag-2"
>
<Path d="M9.693 9.912V8.659a6.168 6.168 0 0 1 5.247-6.036 5.816 5.816 0 0 1 6.384 5.79v1.782" />
<Path
data-name="Vector"
d="M11.631 28.433h7.754c5.2 0 6.126-2.081 6.4-4.614l.969-7.754c.345-3.154-.555-5.726-6.076-5.726H10.339c-5.519 0-6.423 2.572-6.074 5.725l.969 7.754c.271 2.534 1.202 4.615 6.397 4.615ZM20.027 15.509h.011M10.979 15.509h.011"
/>
</G>
</Svg>
),
}}
/>
) : null}
{bottomNavigationList.profile.isActive ? (
<Tab.Screen
name="ProfileTab"
children={() => <PROFILEStackScreen theme={theme} />}
options={{
title: bottomNavigationList.profile.label,
tabBarIcon: ({ focused, color }) =>
focused ? (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={31.192}
height={31.192}
>
<G
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.greenCF
}
>
<Path d="M15.803 14.127a2.363 2.363 0 0 0-.429 0 5.777 5.777 0 1 1 .429 0Z" />
<Path
data-name="Vector"
d="M9.306 18.923c-3.145 2.105-3.145 5.537 0 7.629a12.693 12.693 0 0 0 13.01 0c3.145-2.105 3.145-5.537 0-7.629a12.752 12.752 0 0 0-13.01 0Z"
/>
</G>
</Svg>
) : (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={31.192}
height={31.192}
style={{
transform: [{ scale: 0.8 }],
}}
>
<G
fill="none"
stroke={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
>
<Path d="M15.803 14.127a2.363 2.363 0 0 0-.429 0 5.777 5.777 0 1 1 .429 0Z" />
<Path
data-name="Vector"
d="M9.306 18.923c-3.145 2.105-3.145 5.537 0 7.629a12.693 12.693 0 0 0 13.01 0c3.145-2.105 3.145-5.537 0-7.629a12.752 12.752 0 0 0-13.01 0Z"
/>
</G>
</Svg>
),
contentStyle: {
backgroundColor: "white",
},
}}
/>
) : null}
</Tab.Navigator>
);
};
const HomeStack = createNativeStackNavigator();
const HomeStackScreen = ({ theme }) => {
return (
<HomeStack.Navigator
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
}}
initialRouteName="Home"
>
<HomeStack.Screen name="Home" component={Home} />
<HomeStack.Screen name="VOD" component={Videos} />
<HomeStack.Screen name="Video" component={Video} unmountOnExit={true} />
<HomeStack.Screen name="VideoDisplay" component={VideoDisplay} />
<HomeStack.Screen name="Products" component={Products} />
<HomeStack.Screen name="Product" component={Product} />
<HomeStack.Screen name="Sample" component={Sample} />
<HomeStack.Screen name="Blogs" component={Blogs} />
<HomeStack.Screen name="MoreBlog" component={MoreBlog} />
<HomeStack.Screen name="Blog" component={Blog} />
<HomeStack.Screen name="Info" component={Info} />
</HomeStack.Navigator>
);
};
const ProductsStack = createNativeStackNavigator();
const ProductsStackScreen = ({ theme }) => {
return (
<ProductsStack.Navigator
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
}}
initialRouteName="Products"
>
<ProductsStack.Screen name="Products" component={Products} />
<ProductsStack.Screen name="Product" component={Product} />
<ProductsStack.Screen name="Sample" component={Sample} />
<ProductsStack.Screen name="Info" component={Info} />
</ProductsStack.Navigator>
);
};
const VODStack = createNativeStackNavigator();
const VODStackScreen = ({ theme }) => {
return (
<VODStack.Navigator
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
}}
initialRouteName="VOD"
>
<VODStack.Screen name="VOD" component={Videos} />
<VODStack.Screen name="Video" component={Video} unmountOnExit={true} />
<VODStack.Screen name="VideoDisplay" component={VideoDisplay} />
</VODStack.Navigator>
);
};
const CARTStack = createNativeStackNavigator();
const CARTStackScreen = ({ theme }) => {
return (
<CARTStack.Navigator
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
}}
initialRouteName="ShoppingCart"
>
<CARTStack.Screen name="ShoppingCart" component={ShoppingCart} />
<CARTStack.Screen name="DeliveryForm" component={DeliveryForm} />
<CARTStack.Screen name="Info" component={Info} />
</CARTStack.Navigator>
);
};
const PROFILEStack = createNativeStackNavigator();
const PROFILEStackScreen = ({ theme }) => {
return (
<PROFILEStack.Navigator
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
}}
>
<PROFILEStack.Screen name="Profile" component={Profile} />
<PROFILEStack.Screen name="ProfileBookmark" component={ProfileBookmark} />
<PROFILEStack.Screen name="Products" component={Products} />
<PROFILEStack.Screen name="Product" component={Product} />
<PROFILEStack.Screen name="Blogs" component={Blogs} />
<PROFILEStack.Screen name="MoreBlog" component={MoreBlog} />
<PROFILEStack.Screen name="Blog" component={Blog} />
<PROFILEStack.Screen name="MyCourses" component={MyCourses} />
</PROFILEStack.Navigator>
);
};
const prefix = Linking.createURL("/");
const Stack = createNativeStackNavigator();
const Navigation = ({
getStatus,
isLogin,
userProducts,
ltr,
setLTR,
theme,
}) => {
const linking = {
prefixes: [prefix],
};
const setDirection = async () => {
setLTR();
await I18nManager.allowRTL(false);
};
useEffect(() => {
if (I18nManager.isRTL && !ltr) {
setDirection();
Restart();
}
getStatus();
StatusBar.setBarStyle(
`${theme === "light" ? "dark" : "light"}-content`,
true
);
return () => {
console.log("This will be logged on unmount");
};
}, []);
return (
<NavigationContainer linking={linking}>
<Stack.Navigator
// initialRouteName="Root"
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
}}
>
<Stack.Screen name="Splash" component={Splash} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Rules" component={Rules} />
<Stack.Screen name="Otp" component={Otp} />
<Stack.Screen
name="Root"
children={() => (
<BottomTabNavigator theme={theme} userProducts={userProducts} />
)}
/>
<Stack.Screen name="QR" component={QR} />
<Stack.Screen name="Orders" component={OrdersFollowUp} />
<Stack.Screen name="Order" component={OrderDetails} />
<Stack.Screen name="Faq" component={Faq} />
<Stack.Screen name="Activation" component={Activation} />
<Stack.Screen name="QRContent" component={QRContent} />
<Stack.Screen name="Contact" component={Contact} />
<Stack.Screen name="AR" component={AR} />
<Stack.Screen name="CreateAddress" component={Address} />
<Stack.Screen name="ProfileAddress" component={ProfileAddress} />
<Stack.Screen name="Info" component={Info} />
<Stack.Screen name="Ticket" component={Ticket} />
<Stack.Screen name="Tickets" component={Tickets} />
<Stack.Screen name="TicketStatus" component={TicketStatus} />
</Stack.Navigator>
</NavigationContainer>
);
};
const mapStateToProps = (state) => ({
isLogin: state.user.status,
userProducts: state.userProduct.list,
theme: state.publicApi.theme,
ltr: state.publicApi.ltr,
});
const mapDispatchToProps = {
getStatus: user.getStatus,
setLTR: publicApi.setLTR,
};
export default connect(mapStateToProps, mapDispatchToProps)(Navigation);

@ -7,15 +7,48 @@
"android": "expo start --android", "android": "expo start --android",
"ios": "expo start --ios", "ios": "expo start --ios",
"web": "expo start --web", "web": "expo start --web",
"eject": "expo eject" "eject": "expo eject",
"build:tailwind": "tailwindcss --input input.css --output tailwind.css --no-autoprefixer && tailwind-rn",
"dev:tailwind": "concurrently \"tailwindcss --input input.css --output tailwind.css --no-autoprefixer --watch\" \"tailwind-rn --watch\""
}, },
"dependencies": { "dependencies": {
"expo": "~45.0.0", "@react-native-async-storage/async-storage": "~1.17.3",
"@react-native-community/masked-view": "^0.1.11",
"@react-navigation/bottom-tabs": "^6.3.1",
"@react-navigation/native": "^6.0.10",
"@react-navigation/native-stack": "^6.6.2",
"axios": "^0.27.2",
"expo": "^45.0.0",
"expo-av": "~11.2.3",
"expo-barcode-scanner": "~11.3.0",
"expo-blur": "~11.1.0",
"expo-font": "~10.1.0",
"expo-linear-gradient": "~11.3.0",
"expo-linking": "~3.1.0",
"expo-screen-orientation": "~4.2.0",
"expo-splash-screen": "~0.15.1",
"expo-status-bar": "~1.3.0", "expo-status-bar": "~1.3.0",
"fiction-expo-restart": "^1.1.2",
"jalali-moment": "^3.3.11",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-native": "0.68.1", "react-native": "0.68.1",
"react-native-web": "0.17.7" "react-native-awesome-alerts": "^1.5.2",
"react-native-htmlview": "^0.16.0",
"react-native-openanything": "^0.0.6",
"react-native-ratings": "^8.1.0",
"react-native-safe-area-context": "4.2.4",
"react-native-screens": "~3.11.1",
"react-native-select-dropdown": "^1.13.0",
"react-native-svg": "12.3.0",
"react-native-web": "0.17.7",
"react-native-webview": "11.18.1",
"react-navigation-stack": "^2.10.4",
"react-redux": "^8.0.1",
"redux": "^4.2.0",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.4.1",
"tailwind-rn": "3.0.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9" "@babel/core": "^7.12.9"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

@ -0,0 +1,172 @@
import React, { useState } from "react";
import { Dimensions } from "react-native";
import { connect } from "react-redux";
import AwesomeAlert from "react-native-awesome-alerts";
//style
import Colors from "../constants/Colors";
//variables
const { width } = Dimensions.get("window");
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}
titleStyle={{
fontFamily: "bold",
color:
props.theme === "light"
? Colors.theme1.gray20
: Colors.theme1.white,
}}
message={alert.message}
messageStyle={{
textAlign: "right",
fontFamily: "regular",
color:
props.theme === "light"
? Colors.theme1.gray20
: Colors.theme1.white,
}}
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}
cancelButtonTextStyle={{
color: props.theme === "light" ? "#777" : Colors.theme1.grayE3,
fontFamily: "regular",
}}
confirmButtonTextStyle={{
fontFamily: "regular",
}}
contentStyle={{
width: width / 1.5,
}}
cancelButtonStyle={{
fontFamily: "regular",
borderColor: props.theme === "light" ? "#777" : Colors.theme1.grayE3,
borderWidth: 1,
backgroundColor:
props.theme === "light" ? Colors.theme1.white : Colors.theme1.black,
}}
confirmButtonStyle={{
alignItems: "center",
justifyContent: "center",
fontFamily: "regular",
borderColor: "#2980b9",
borderWidth: 1,
}}
contentContainerStyle={{
backgroundColor:
props.theme === "light" ? "white" : Colors.theme1.black,
}}
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: width / 1.5,
}}
confirmButtonStyle={{
width: width / 4,
alignItems: "center",
justifyContent: "center",
}}
useNativeDriver={true}
/>
</>
);
};
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(AlertModal);

@ -0,0 +1,62 @@
import React from "react";
import { Image, View } from "react-native";
import Svg, { G, Path } from "react-native-svg";
import { connect } from "react-redux";
//style
import tw from "tailwind-rn";
import Colors from "../constants/Colors";
function Avatar({ source, size, theme }) {
return (
<View
style={[
tw("rounded-full overflow-hidden flex justify-center items-center"),
{
minWidth: size,
minHeight: size,
backgroundColor:
theme === "light"
? Colors.theme1.grayE3
: Colors.theme1.white + '55',
},
]}
>
{source ? (
<Image
source={{ uri: `https:dnvn.ir/api/v1/file/${source}` }}
style={{ minWidth: "100%", minHeight: "100%" }}
resizeMode="contain"
/>
) : (
<Svg
data-name="vuesax/bold/frame"
xmlns="http://www.w3.org/2000/svg"
width={36.975}
height={36.975}
>
<G fill="none">
<Path d="M18.488 3.081a7.311 7.311 0 0 0-.185 14.621 1.243 1.243 0 0 1 .339 0h.108a7.313 7.313 0 0 0-.262-14.621Z" />
<Path
d="M18.488 5.081a5.324 5.324 0 0 0-5.318 5.318c0 1.395.528 2.705 1.486 3.689.94.965 2.215 1.535 3.6 1.61.165-.011.328-.01.484.002a5.31 5.31 0 0 0 5.066-5.304 5.324 5.324 0 0 0-5.318-5.315m0-2a7.325 7.325 0 0 1 7.318 7.318 7.3 7.3 0 0 1-7.056 7.303h-.108a1.243 1.243 0 0 0-.339 0c-4.036-.14-7.133-3.344-7.133-7.303a7.325 7.325 0 0 1 7.318-7.318Z"
fill={theme === 'light' ? "#818181" : Colors.theme1.white}
/>
<G data-name="Vector">
<Path d="M26.314 21.8a15.3 15.3 0 0 0-15.637 0 6.081 6.081 0 0 0-3.035 4.976 6.03 6.03 0 0 0 3.02 4.945 14.234 14.234 0 0 0 7.826 2.172 14.234 14.234 0 0 0 7.826-2.172 6.078 6.078 0 0 0 3.02-4.976 6.066 6.066 0 0 0-3.02-4.945Z" />
<Path
d="M18.507 21.651c-2.528 0-4.977.661-6.721 1.814-1.383.926-2.144 2.102-2.144 3.311 0 1.201.756 2.366 2.129 3.282l.006.003c1.734 1.165 4.18 1.833 6.711 1.833 2.53 0 4.977-.668 6.708-1.83 1.762-1.189 2.136-2.455 2.138-3.31-.01-.862-.388-2.129-2.129-3.29-1.729-1.152-4.17-1.813-6.698-1.813m0-2c2.831 0 5.658.716 7.807 2.15 1.942 1.293 3.005 3.05 3.02 4.945 0 1.91-1.078 3.666-3.02 4.976-4.313 2.896-11.339 2.896-15.652 0-1.942-1.294-3.02-3.05-3.02-4.946 0-1.895 1.078-3.666 3.035-4.976 2.165-1.433 5-2.149 7.83-2.149Z"
fill={theme === 'light' ? "#818181" : Colors.theme1.white}
/>
</G>
</G>
</Svg>
)}
</View>
);
}
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Avatar);

@ -0,0 +1,26 @@
import React from "react";
import { BlurView } from "expo-blur";
import { ActivityIndicator } from "react-native";
import { connect } from "react-redux";
import tw from "tailwind-rn";
function Blur({ theme }) {
return (
<BlurView
intensity={280}
tint="dark"
style={[
{ width: "100%", height: "100%" },
tw("flex-1 flex justify-center items-center"),
]}
>
<ActivityIndicator size="large" color="#12CF7F" />
</BlurView>
);
}
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Blur);

@ -0,0 +1,107 @@
import React from "react";
import { TextInput, View, Text, StyleSheet } from "react-native";
import { connect } from "react-redux";
import tw from "tailwind-rn";
import Colors from "../constants/Colors";
import fontSize from "../constants/fontSize";
const FloatingLabelInput = ({
label,
textAlign,
direction,
labelBackgroundColor,
onChange,
name,
value,
textColor,
placeholder,
maxLength,
autoFocus,
regex,
mobile,
keyboardType,
multiline,
theme,
editable = true,
...props
}) => {
const [isFocused, setIsFocused] = React.useState(false);
const styles = StyleSheet.create({
labelStyle: {
fontFamily: "regular",
top: !isFocused ? "50%" : 1,
fontSize: !isFocused
? Math.floor(fontSize.base)
: Math.floor(fontSize.sm),
transform: [
{
translateY: !isFocused
? -Math.floor(fontSize.base - 2)
: -Math.floor(fontSize.sm),
},
],
backgroundColor : theme === 'light' ? Colors.theme1.white : Colors.theme1.dark,
color: !isFocused ? theme === 'light' ? Colors.theme1.gray2077 : Colors.theme1.white + 'aa' : Colors.theme1.green79,
},
inputStyle: {
fontSize: fontSize.lg,
color: theme === 'light' ? Colors.theme1.black : Colors.theme1.white,
borderWidth: 1,
borderColor: isFocused
? Colors.theme1.greenC8
: theme === "light" ? Colors.theme1.gray2077 + "66" : Colors.theme1.white + 'aa',
textAlign: textAlign,
fontFamily: "regular",
direction: direction ? direction : "rtl",
},
});
React.useEffect(() => {
if (value) {
setIsFocused(true);
} else {
setIsFocused(false);
}
}, [value]);
return (
<View style={tw("mt-4 pb-1")}>
<Text
style={[
styles.labelStyle,
tw("px-1 z-10 absolute right-3 text-center"),
]}
onPress={() => setIsFocused(true)}
>
{label}
</Text>
<TextInput
style={[
styles.inputStyle,
tw(`rounded-sm ${mobile ? "py-2" : "py-3"} px-4`),
]}
onChangeText={(text) => onChange(name, (text = regex(text)))}
placeholder={placeholder}
onFocus={() => setIsFocused(true)}
autoFocus={autoFocus}
underlineColorAndroid={"transparent"}
maxLength={maxLength}
value={value}
onBlur={() => (value ? {} : setIsFocused(() => false))}
keyboardType={keyboardType}
multiline={multiline}
editable={editable}
placeholderTextColor={theme === 'light' ? Colors.theme1.gray20 + 'aa' : Colors.theme1.white + '55'}
/>
</View>
);
};
const mapStateToProps = (state) => ({
mobile: state.publicApi.mobile,
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(FloatingLabelInput);

@ -0,0 +1,24 @@
import React from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import tw from "tailwind-rn";
const Divider = ({ type, theme }) => {
return (
<View
style={[
tw(`bg-gray-100 ${theme === "light" ? "" : "bg-opacity-40"} my-4`),
{
height: type === "horizontal" ? "100%" : 1,
width: type === "horizontal" ? 1 : "100%",
},
]}
></View>
);
};
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Divider);

@ -0,0 +1,539 @@
import React, { useState, useEffect } from "react";
import {
View,
Platform,
UIManager,
Dimensions,
Pressable,
Text,
TouchableOpacity,
Image,
LayoutAnimation,
Animated,
} from "react-native";
import { useNavigation } from "@react-navigation/native";
import { asyncAwesomeAlert } from "../utils/AsyncWrappers";
import { connect } from "react-redux";
import { user, publicApi } from "../redux/actions";
import Svg, { Path, G } from "react-native-svg";
import { AntDesign } from "@expo/vector-icons";
//components
import Avatar from "../components/Avatar";
//style
import tw from "tailwind-rn";
import fontSize from "../constants/fontSize";
import Colors from "../constants/Colors";
//variables
const ios = Platform.OS === "ios";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const Drawer = ({
route,
position,
setBoxPosition,
user,
mobile,
theme,
setIsDark,
}) => {
const [height, setHeight] = useState(Dimensions.get("window").height);
const [width, setWidth] = useState(Dimensions.get("window").width);
const fadeAnim = React.useRef(new Animated.Value(0)).current; // Initial value for opacity: 0
const [dropdown, setDropdown] = useState(false);
const [dropdownHeight, setDropdownHeight] = useState(0);
const navigation = useNavigation();
const routes = React.useMemo(() => {
return [
{
name: "صفحه اصلی",
route: "Home",
icon: (
<Svg
data-name="vuesax/linear/home-2"
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
>
<G
fill="none"
stroke={
theme === "light" ? Colors.theme1.gray20 : Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
>
<Path d="m9.02 2.84-5.39 4.2A4.759 4.759 0 0 0 2 10.36v7.41a4.225 4.225 0 0 0 4.21 4.22h11.58A4.223 4.223 0 0 0 22 17.78V10.5a4.723 4.723 0 0 0-1.8-3.45l-6.18-4.333a4.487 4.487 0 0 0-5 .123Z" />
<Path data-name="Vector" d="M12 17.99v-3" />
</G>
</Svg>
),
message: "",
},
{
name: "فعال سازی",
route: "Activation",
icon: (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={21.431}
height={21.431}
>
<G
data-name="Group 1"
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
>
<Path d="M20.681 13.705V7.726c0-4.983-1.993-6.976-6.976-6.976H7.726C2.743.75.75 2.743.75 7.726v5.979c0 4.983 1.993 6.976 6.976 6.976h5.979c4.983 0 6.976-1.993 6.976-6.976Z" />
<Path
data-name="Vector"
d="m6.558 10.716 2.776 2.776 5.538-5.552"
/>
</G>
</Svg>
),
message: "",
},
{
name: "واقعیت افزوده",
route: "AR",
icon: (
<Svg
data-name="vuesax/linear/3dcube"
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
>
<G
data-name="3dcube"
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
>
<Path d="m12.92 2.26 6.51 3.51a1.153 1.153 0 0 1 0 1.99l-6.51 3.51a1.936 1.936 0 0 1-1.84 0L4.57 7.76a1.153 1.153 0 0 1 0-1.99l6.51-3.51a1.936 1.936 0 0 1 1.84 0Z" />
<Path
data-name="Vector"
d="m3.61 10.13 6.05 3.03a2.238 2.238 0 0 1 1.23 1.99v5.72a1.109 1.109 0 0 1-1.61.99l-6.05-3.03A2.238 2.238 0 0 1 2 16.84v-5.72a1.109 1.109 0 0 1 1.61-.99ZM20.39 10.13l-6.05 3.03a2.238 2.238 0 0 0-1.23 1.99v5.72a1.109 1.109 0 0 0 1.61.99l6.05-3.03A2.238 2.238 0 0 0 22 16.84v-5.72a1.109 1.109 0 0 0-1.61-.99Z"
/>
</G>
</Svg>
),
message: "",
},
{
name: "وبلاگ",
route: "Blogs",
icon: (
<Svg
xmlns="http://www.w3.org/2000/svg"
width={24.055}
height={24.055}
>
<G
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeLinecap="round"
strokeWidth={1.5}
strokeLinejoin="round"
data-name="vuesax/linear/note-2"
>
<Path d="m21.709 10.463-.982 4.19c-.842 3.618-2.506 5.081-5.633 4.781a10.538 10.538 0 0 1-1.624-.274l-1.684-.4c-4.178-.99-5.471-3.053-4.489-7.244l.982-4.2a10.5 10.5 0 0 1 .742-2.209c1.173-2.421 3.164-3.073 6.515-2.281l1.674.391c4.2.982 5.482 3.057 4.499 7.246Z" />
<Path
data-name="Vector"
d="M15.091 19.435a9.394 9.394 0 0 1-2.352 1.083l-1.583.521c-3.979 1.283-6.074.21-7.367-3.767l-1.283-3.96c-1.283-3.98-.221-6.085 3.759-7.368l1.583-.521a10.247 10.247 0 0 1 1.173-.311 10.5 10.5 0 0 0-.742 2.205l-.982 4.195c-.982 4.19.31 6.255 4.487 7.247l1.684.4a10.538 10.538 0 0 0 1.626.271ZM12.669 8.549l4.862 1.233M13.641 12.428l2.906.742"
/>
</G>
</Svg>
),
message: "",
},
{
name: "سفارشات",
route: "Orders",
icon: (
<Svg
data-name="vuesax/linear/ranking"
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
>
<Path
d="M8.67 14H4a2.006 2.006 0 0 0-2 2v6h6.67Z"
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
<Path
data-name="Vector"
d="M13.33 10h-2.67a2.006 2.006 0 0 0-2 2v10h6.67V12a2 2 0 0 0-2-2ZM20 17h-4.67v5H22v-3a2.006 2.006 0 0 0-2-2ZM12.52 2.07l.53 1.06a.6.6 0 0 0 .42.31l.96.16c.61.1.76.55.32.98l-.75.75a.639.639 0 0 0-.16.54l.21.92c.17.73-.22 1.01-.86.63l-.9-.53a.618.618 0 0 0-.59 0l-.9.53c-.64.38-1.03.1-.86-.63l.21-.92a.63.63 0 0 0-.156-.54l-.74-.74c-.44-.44-.3-.88.32-.98l.96-.16a.666.666 0 0 0 .42-.31l.53-1.06c.286-.58.746-.58 1.036-.01Z"
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</Svg>
),
message: "",
},
{
name: "سوالات متداول",
route: "Faq",
icon: (
<Svg
data-name="vuesax/linear/lamp-on"
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
>
<G
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
>
<Path d="M8.3 18.04v-1.16a8.579 8.579 0 0 1-4.19-6.984A7.919 7.919 0 0 1 13.8 2.19a7.784 7.784 0 0 1 5.27 4.07c2.09 4.2-.11 8.66-3.34 10.61v1.16c0 .29.11.96-.96.96H9.26c-1.1.006-.96-.42-.96-.95Z" />
<Path
data-name="Vector"
d="M8.5 21.999a12.808 12.808 0 0 1 7 0"
/>
</G>
</Svg>
),
message: "",
},
{
name: "تماس با ما",
route: "Contact",
icon: (
<Svg
data-name="vuesax/linear/call-calling"
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
>
<G
data-name="call-calling"
fill="none"
stroke={theme === "light" ? "#292d32" : Colors.theme1.white}
strokeWidth={1.5}
>
<Path d="M21.97 18.33a2.545 2.545 0 0 1-.25 1.09 4.126 4.126 0 0 1-.68 1.02 4.508 4.508 0 0 1-1.64 1.18 5.022 5.022 0 0 1-1.95.38 8.334 8.334 0 0 1-3.26-.73 17.564 17.564 0 0 1-3.44-1.98 28.75 28.75 0 0 1-3.28-2.8 28.414 28.414 0 0 1-2.79-3.27 17.828 17.828 0 0 1-1.96-3.41A8.423 8.423 0 0 1 2 6.54a5.173 5.173 0 0 1 .36-1.93 4.6 4.6 0 0 1 1.15-1.67A2.93 2.93 0 0 1 5.59 2a1.879 1.879 0 0 1 .81.18 1.63 1.63 0 0 1 .67.56l2.32 3.27a3.422 3.422 0 0 1 .4.7 1.581 1.581 0 0 1 .14.61 1.357 1.357 0 0 1-.21.71 3.4 3.4 0 0 1-.56.71l-.76.79a.535.535 0 0 0-.16.4.908.908 0 0 0 .03.23c.03.08.06.14.08.2a8.3 8.3 0 0 0 .93 1.28c.45.52.93 1.05 1.45 1.58.54.53 1.06 1.02 1.59 1.47a7.675 7.675 0 0 0 1.29.92c.05.02.11.05.18.08a.69.69 0 0 0 .25.04.55.55 0 0 0 .41-.17l.76-.75a3.068 3.068 0 0 1 .72-.56 1.332 1.332 0 0 1 .71-.21 1.6 1.6 0 0 1 .61.13 3.868 3.868 0 0 1 .7.39l3.31 2.35a1.517 1.517 0 0 1 .55.64 2.052 2.052 0 0 1 .16.78Z" />
<Path
data-name="Vector"
d="M18.5 9a3.965 3.965 0 0 0-1.17-2.27A3.416 3.416 0 0 0 15 5.5M22 9a7 7 0 0 0-7-7"
strokeLinecap="round"
strokeLinejoin="round"
/>
</G>
</Svg>
),
message: "",
},
];
}, [user, theme]);
const Route = React.useCallback(
({ route }) => {
return (
<TouchableOpacity
style={[
tw(
`w-full flex flex-row-reverse justify-start items-end ${
mobile ? "mt-6" : "mt-10"
}`
),
{},
]}
onPress={() => {
setBoxPosition();
setTimeout(() => {
navigation.navigate(route.route);
}, 300);
}}
>
{route.icon}
<Text
style={[
tw("mr-2"),
{
fontFamily: "regular",
fontSize: mobile ? fontSize.base : fontSize.lg,
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.white,
},
]}
>
{route.name}
</Text>
</TouchableOpacity>
);
},
[mobile, position, theme]
);
React.useEffect(() => {
if (position === "0%") {
setTimeout(() => {
Animated.timing(fadeAnim, {
toValue: 0.7,
duration: 300,
useNativeDriver: true, // Add This line
}).start();
}, 300);
}
if (position === "100%") {
Animated.timing(fadeAnim, {
toValue: 0,
duration: 10,
useNativeDriver: true, // Add This line
}).start();
}
}, [position]);
const onLayout = React.useCallback(() => {
setHeight(Dimensions.get("window").height);
setWidth(Dimensions.get("window").width);
}, [mobile]);
const animateDropdown = React.useCallback(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setDropdown(() => !dropdown);
setDropdownHeight(dropdownHeight === 0 ? fontSize.base + 30 : 0);
}, [position]);
return (
<View
style={[
tw(`absolute top-0 flex flex-row justify-end`),
{
left: position,
width: width,
height: height,
zIndex: 10000,
},
]}
onLayout={() => onLayout()}
>
<Animated.View
style={[tw("w-1/5 h-full bg-black"), { opacity: fadeAnim }]}
>
<Pressable
style={tw("flex-1 items-center pt-12")}
onPress={() => setBoxPosition()}
>
<AntDesign
name="close"
size={mobile ? 25 : 30}
color={Colors.theme1.white}
onPress={() => setBoxPosition()}
/>
</Pressable>
</Animated.View>
<View
style={[
tw("w-4/5 h-full flex"),
{
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.dark,
},
]}
>
<View
style={[
tw("flex items-end pt-12 px-4"),
{
backgroundColor:
theme === "light"
? Colors.theme1.greenCF
: Colors.theme1.blue90,
},
]}
>
<View
style={tw(
"flex flex-row-reverse items-center w-full justify-between"
)}
>
<Avatar souce={user?.picFileIds} size={width / 6} />
{theme === "light" ? (
<Svg
xmlns="http://www.w3.org/2000/svg"
onPress={() => setIsDark("dark")}
width={24}
height={24}
style={{ padding: 10 }}
>
<Path
d="M2.03 12.42a10.506 10.506 0 0 0 18.93 5.3c.82-1.11.38-1.85-.99-1.6a9.494 9.494 0 0 1-2.08.14 9.324 9.324 0 0 1-8.91-9.12 8.9 8.9 0 0 1 .75-3.65c.54-1.24-.11-1.83-1.36-1.3a10.3 10.3 0 0 0-6.34 10.23Z"
fill="#fff"
data-name="vuesax/linear/moon"
/>
</Svg>
) : (
<Svg
xmlns="http://www.w3.org/2000/svg"
onPress={() => setIsDark("light")}
width={24}
height={24}
style={{ padding: 10 }}
>
<G data-name="vuesax/linear/sun">
<Path
d="M18.5 12A6.5 6.5 0 1 1 12 5.5a6.5 6.5 0 0 1 6.5 6.5Z"
fill="#fff"
/>
<Path
data-name="Vector"
d="m19.01 4.99.13-.13ZM4.86 19.14l.13-.13ZM12 2.08h0ZM12 22h0ZM2.08 12h0ZM22 12h0ZM4.99 4.99l-.13-.13Zm14.15 14.15-.13-.13"
fill="none"
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
</G>
</Svg>
)}
</View>
<View
style={tw(
"flex flex-row-reverse w-full justify-between px-2 pb-1 mt-2"
)}
>
<View style={tw("flex")}>
<Text
style={{
fontSize: mobile ? fontSize.lg : fontSize.xl,
color: "white",
fontFamily: "demi",
textAlign: ios ? "right" : "auto",
}}
>
{user?.firstName + " " + user?.lastName}
</Text>
<Text
style={{
fontSize: mobile ? fontSize.tiny : fontSize.lg,
color: "white",
fontFamily: "bold",
marginTop: 5,
textAlign: "right",
}}
>
{user?.cellphone}
</Text>
</View>
{/* <Svg
data-name="vuesax/linear/arrow-left"
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
style={{
transform: [{ rotate: dropdown ? "90deg" : "-90deg" }],
padding: 10,
}}
onPress={() => animateDropdown()}
>
<Path
d="M15.002 19.92 8.479 13.4a1.986 1.986 0 0 1 0-2.8l6.523-6.52"
fill="none"
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
</Svg> */}
</View>
</View>
<View style={tw("flex-1 flex")}>
{/* <Pressable
style={[
tw(
`flex flex-row justify-between items-center w-full flex-row-reverse px-4 overflow-hidden`
),
{
borderBottomWidth: 1,
borderColor: Colors.theme1.grayE3,
height: dropdownHeight,
},
]}
onPress={() =>
asyncAwesomeAlert("نتیجه", "این قابلیت در حال توسعه است.", {
showCancelButton: false,
confirmText: "باشه",
})
}
>
<Text
style={{
fontSize: mobile ? fontSize.base : fontSize.xl,
fontFamily: "regular",
color: Colors.theme1.gray20,
}}
>
افزودن حساب کاربری جدید
</Text>
<Text
style={{
marginRight: 5,
marginTop: 3,
fontSize: fontSize.xl4,
fontFamily: "bold",
color: Colors.theme1.gray20 + "77",
}}
>
+
</Text>
</Pressable> */}
<View style={tw("flex w-full px-4")}>
{routes.map((route, index) => (
<Route route={route} key={index} />
))}
</View>
</View>
</View>
</View>
);
};
const mapStateToProps = (state) => ({
user: state.user.status,
mobile: state.publicApi.mobile,
theme: state.publicApi.theme,
});
const mapDispatchToProps = {
logout: user.logout,
setIsDark: publicApi.setIsDark,
};
export default connect(mapStateToProps, mapDispatchToProps)(Drawer);

@ -0,0 +1,63 @@
import { View, Text, Pressable } from "react-native";
import React from "react";
import { connect } from "react-redux";
//style
import Colors from "../constants/Colors";
import tw from "tailwind-rn";
import fontSize from "../constants/fontSize";
const Empty = ({ text, buttonText, buttonAction, theme }) => {
return (
<View style={tw("flex-1 flex justify-center items-center")}>
<Text
style={[
{
fontFamily: "regular",
fontSize: fontSize.tiny,
transform: [{ translateY: -50 }],
color:
theme === "light" ? Colors.theme1.gray20 : Colors.theme1.white,
},
]}
>
{text + " " + ":("}
</Text>
{buttonText ? (
<Pressable
style={[
tw("py-2 px-5 rounded-sm"),
{
backgroundColor: theme === "light" ? Colors.theme1.greenCF : null,
borderWidth: theme === "light" ? 0 : 1,
borderColor: Colors.theme1.greenCF,
},
]}
onPress={() => buttonAction()}
>
<Text
style={[
tw("text-white"),
{
fontFamily: "regular",
fontSize: fontSize.tiny,
color:
theme === "light"
? Colors.theme1.white
: Colors.theme1.greenCF,
},
]}
>
{buttonText}
</Text>
</Pressable>
) : null}
</View>
);
};
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Empty);

@ -0,0 +1,30 @@
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,
color: 'white',
},
});
return (
<Pressable
color={color}
style={styles.button}
onPress={() => onPress}
>
<Text style={styles.text}>{text}</Text>
</Pressable>
);
}

@ -0,0 +1,58 @@
import { View, Text, Dimensions, ImageBackground } from "react-native";
import { connect } from "react-redux";
//style
import tw from "tailwind-rn";
import fontSize from "../constants/fontSize";
import Colors from "../constants/Colors";
const height = Dimensions.get("window").height;
function Header({ title, description, background }) {
return (
<View
style={[
tw(`w-full flex items-center pb-7`),
{
height: height / 4.5,
backgroundColor: Colors.theme1.greenCF + "0F",
},
]}
>
<ImageBackground
source={background}
resizeMode="contain"
style={[tw("w-full"), { height: "80%" }]}
></ImageBackground>
<Text
style={[
{
fontSize: fontSize.xl,
color: Colors.theme1.greenCF,
fontFamily: "bold",
},
]}
>
{title}
</Text>
<Text
style={[
{
color: Colors.theme1.greenCF,
fontSize: fontSize.sm,
fontFamily: "regular",
marginTop: 5
},
]}
>
{description}
</Text>
</View>
);
}
const mapStateToProps = (state) => ({
mobile: state.publicApi.mobile,
});
export default connect(mapStateToProps)(Header);

@ -0,0 +1,18 @@
import { View, Dimensions } from "react-native";
import React from "react";
import tw from "tailwind-rn";
const { width, height } = Dimensions.get("window");
const ImageSlider = ({}) => {
return (
<View
style={[
tw("flex flex-row justify-center items-center absolute left-0 top-0"),
{ width : width, height : height, backgroundColor: "black", zIndex : 1 },
]}
></View>
);
};
export default ImageSlider;

@ -0,0 +1,35 @@
import React from "react";
import { StyleSheet } from "react-native";
// import MapboxGL from '@rnmapbox/maps';
// MapboxGL.setAccessToken('pk.eyJ1IjoicmV6YS1hc2hyYWZpNzciLCJhIjoiY2tsdXRxaGxjMjl3azJ2cW1wNDl4MWdpNCJ9.0EIgtsWEuemb7IpGtGhraw');
export default function MapSelector() {
onRegionDidChange = (e) => {};
return (
// <View style={styles.page}>
// <View style={styles.container}>
// <MapboxGL.MapView style={styles.map} />
// </View>
// </View>
<></>
);
}
const styles = StyleSheet.create({
page: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
container: {
height: 300,
width: 300,
backgroundColor: 'tomato'
},
map: {
flex: 1
}
});

@ -0,0 +1,28 @@
import * as React from 'react';
import { View, Button } from 'react-native';
import { Audio } from 'expo-av';
export default function VoicePlayer({fileIds}) {
const [sound, setSound] = React.useState();
async function playSound() {
const { sound } = await Audio.Sound.createAsync(
{uri : `https://dnvn.ir/api/v1/file/${fileIds}`}
);
setSound(sound);
await sound.playAsync(); }
React.useEffect(() => {
return sound
? () => {
sound.unloadAsync(); }
: undefined;
}, [sound]);
return (
<View style={styles.container}>
<Button title="Play Sound" onPress={playSound} />
</View>
);
}

@ -0,0 +1,726 @@
import React, { useCallback } from "react";
import {
View,
Pressable,
Text,
Appearance,
TouchableOpacity,
ActivityIndicator,
} from "react-native";
import Svg, {
G,
Defs,
Pattern,
Image as Imagee,
Path,
Text as Textt,
TSpan,
LinearGradient,
Stop,
ClipPath,
Circle,
} from "react-native-svg";
import { useNavigation } from "@react-navigation/native";
import { Ionicons, Entypo } from "@expo/vector-icons";
import { connect } from "react-redux";
import { userFavorite } from "../redux/actions";
//style
import Colors from "../constants/Colors";
import tw from "tailwind-rn";
import fontSize from "../constants/fontSize";
const Navbar = ({
notification,
setBoxPosition,
headerOptions,
addToBookmark,
deleteBookmark,
userFavoriteList,
theme,
bookmarkLoading,
}) => {
const navigation = useNavigation();
const isActiveBookmark = React.useMemo(() => {
return userFavoriteList.filter((object) =>
headerOptions.bookmarkItem?.productId
? object.productId === headerOptions.bookmarkItem?.productId
: object.contentId === headerOptions.bookmarkItem?.contentId
).length;
}, [headerOptions, userFavoriteList]);
const Button = useCallback(
({ icon, route, state }) => {
return (
<TouchableOpacity
style={[
tw("rounded-md p-1"),
{
backgrounds: Colors.theme1.greenCF + "05",
borderColor:
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white,
borderWidth: 1,
marginLeft: route === "AR" ? 10 : 0,
},
]}
onPress={() => navigation.navigate(route, { page: state })}
>
{icon}
</TouchableOpacity>
);
},
[theme]
);
return (
<View
style={[
tw("w-full flex flex-row-reverse justify-between items-center px-0"),
{
backgroundColor: headerOptions?.backgroundColor
? headerOptions?.backgroundColor
: theme === "light"
? Colors.theme1.white
: Colors.theme1.dark,
height: 64,
},
]}
>
{!headerOptions?.title ? (
headerOptions?.back ? (
<Ionicons
name="arrow-forward"
style={tw("mr-2")}
size={24}
color={
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white
}
onPress={() => navigation.goBack()}
/>
) : null
) : null}
{headerOptions?.title ? (
<Text
style={{
fontFamily: "demi",
fontSize: fontSize.xl,
color:
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white,
paddingRight: 16,
}}
>
{headerOptions?.title}
</Text>
) : null}
{headerOptions?.hamburgerMenu ? (
<Pressable style={tw("relative mr-4")} onPress={() => setBoxPosition()}>
<Svg
xmlns="http://www.w3.org/2000/svg"
width={31.567}
height={29.996}
>
<G
fill="none"
stroke={
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
>
<Path d="M1 1h29.567" />
<Path
data-name="Vector"
d="M1 9.999h29.567M1 18.998h29.567M1 27.996h29.567"
/>
</G>
</Svg>
{notification ? (
<View
style={tw("h-2.5 w-2.5 absolute -left-1 -top-1 rounded-full")}
></View>
) : null}
</Pressable>
) : null}
{headerOptions?.logo ? (
<Pressable
onPress={() => navigation.navigate("Home")}
style={tw("absolute right-1/2 top-1/2")}
>
<Svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
width={26.198}
height={40.393}
style={{ transform: [{ translateX: -13 }, { translateY: -21 }] }}
>
<Defs>
<LinearGradient
id="a"
y1={0.5}
x2={1}
y2={0.5}
gradientUnits="objectBoundingBox"
>
<Stop offset={0} stopColor="#5a595d" />
<Stop offset={1} stopColor="#515254" />
</LinearGradient>
<LinearGradient
id="c"
x1={0.226}
y1={0.051}
x2={0.802}
y2={0.929}
gradientUnits="objectBoundingBox"
>
<Stop offset={0} stopColor="#fff" />
<Stop offset={0.461} stopColor="#636466" />
<Stop offset={1} stopColor="#4a4a4c" />
</LinearGradient>
<LinearGradient
id="e"
x1={0.118}
y1={0.331}
x2={1.017}
y2={0.638}
gradientUnits="objectBoundingBox"
>
<Stop offset={0} stopColor="#c3e14b" />
<Stop offset={0.528} stopColor="#4cdb60" />
<Stop offset={1} stopColor="#4fb84a" />
</LinearGradient>
<LinearGradient
id="f"
y1={0.5}
x2={1}
y2={0.5}
gradientUnits="objectBoundingBox"
>
<Stop offset={0} stopColor="#8bc540" />
<Stop offset={1} stopColor="#4fb84a" />
</LinearGradient>
<LinearGradient
id="b"
x1={0.177}
y1={0.211}
x2={0.923}
y2={0.878}
gradientUnits="objectBoundingBox"
>
<Stop offset={0.156} stopColor="#c3e14b" />
<Stop offset={0.628} stopColor="#4cdb60" />
<Stop offset={1} stopColor="#4fb84a" />
</LinearGradient>
<LinearGradient
id="g"
x1={0}
y1={0.5}
x2={1}
y2={0.5}
xlinkHref="#b"
/>
<ClipPath id="d">
<Path
data-name="Path 11452"
d="M752.773 683.017c0-1.668.08-8.506-.023-8.462-.33 3.666-3.285 6.412-8.535 6.412a6.347 6.347 0 0 1-5.966-3.826c-3.262-2.317-3.731-4.787-3.731-4.787l.058 13.66v.011h15.133a2.759 2.759 0 0 0 3.064-3.008Z"
transform="translate(-734.518 -672.354)"
fill="url(#a)"
/>
</ClipPath>
</Defs>
<G data-name="Group 2024">
<G data-name="Layer 10">
<G data-name="Group 2013">
<G data-name="Group 2009">
<Path
data-name="Path 11446"
d="M2.534 4.411H.053s-.255 1.422.328 2.005 2.151.534 2.151.862Z"
fill="#7f8083"
/>
</G>
<Path
data-name="Path 11447"
d="M758.141 245.564h-1.422a3.668 3.668 0 0 0-3.937 3.718l-.009 26.913a2.759 2.759 0 0 1-3.062 3.008h-11.462v-8.884a10.446 10.446 0 0 1-1.033-4.34v-16.915c0-2.552-2.7-3.172-2.7-3.172v19.64l.108 13.671h-.049c.014.113.032.221.052.325v.006c.4 2.152 1.868 2.339 3.57 2.339h14.509c2.953 0 2.771-2.552 2.771-4.229V250.23c0-2.078.984-1.677 1.969-2.005s.695-2.661.695-2.661Z"
transform="translate(-731.983 -241.481)"
fill="url(#c)"
/>
<G data-name="Group 2010">
<Path
data-name="Path 11448"
d="M2.593 37.722Z"
fill="#4b4b4d"
/>
</G>
<G data-name="Group 2012">
<Path
data-name="Path 11449"
d="M752.773 683.017c0-1.668.08-8.506-.023-8.462-.33 3.666-3.285 6.412-8.535 6.412a6.347 6.347 0 0 1-5.966-3.826c-3.262-2.317-3.731-4.787-3.731-4.787l.058 13.66v.011h15.133a2.759 2.759 0 0 0 3.064-3.008Z"
transform="translate(-731.983 -648.303)"
fill="url(#a)"
/>
<G
data-name="Group 2011"
clipPath="url(#d)"
fill="#fff"
transform="translate(2.535 24.051)"
>
<Path data-name="Path 11450" d="M0 0Z" />
<Path data-name="Path 11451" d="M18.392 13.671Z" />
</G>
</G>
</G>
</G>
<G data-name="Layer 7">
<Path
data-name="Path 11453"
d="M802.306 400.555v12.358c0 1.6 1.9 6.854 7.036 6.854a7.19 7.19 0 0 0 7.437-6.562v-12.65a4.138 4.138 0 0 0-3.1-1.495c-1.969 0-4.393 1.566-6.289 2.149a5.78 5.78 0 0 1-4.024.094 3.059 3.059 0 0 1-1.06-.748Z"
transform="translate(-796.6 -387.795)"
fill="url(#e)"
/>
</G>
<G data-name="Layer 8">
<Path
data-name="Path 11454"
d="M816.779 400.576a5.934 5.934 0 0 0-4.63.115c-3.017 1.611-6.088 5.171-7.546 7.376s-2.3 3.664-2.3 3.664v-11.155a3.594 3.594 0 0 0 2.012 1 8.558 8.558 0 0 0 4.794-1.044 11.537 11.537 0 0 1 4.476-1.449 3.977 3.977 0 0 1 2.433.784c.67.417.761.709.761.709Z"
transform="translate(-796.6 -387.816)"
fill="url(#f)"
/>
</G>
<G data-name="Layer 9">
<G data-name="Group 2014">
<Path
data-name="Path 11455"
d="M12.751 12.6a6.145 6.145 0 0 0-3.727-1.335 4.267 4.267 0 0 0-3.317 1.495 3.672 3.672 0 0 0 2.232 1.029 8.888 8.888 0 0 0 4.812-1.189Z"
fill="#09793e"
/>
</G>
</G>
<G data-name="Layer 5" transform="translate(12.159 5.432)">
<Circle
data-name="Ellipse 177"
cx={2.06}
cy={2.06}
r={2.06}
fill="url(#b)"
/>
<G data-name="Group 2018">
<G data-name="Group 2015" transform="translate(2.394 1.041)">
<Circle
data-name="Ellipse 178"
cx={0.361}
cy={0.361}
r={0.361}
fill="#6c3b41"
/>
</G>
<G data-name="Group 2016" transform="translate(.973 1.041)">
<Circle
data-name="Ellipse 179"
cx={0.361}
cy={0.361}
r={0.361}
fill="#6c3b41"
/>
</G>
<G data-name="Group 2017">
<Path
data-name="Path 11456"
d="M2.068 3.185a1.594 1.594 0 0 1-1.286-.923l.194-.091c0 .008.386.8 1.092.8.706 0 1.073-.791 1.077-.8l.195.088a1.562 1.562 0 0 1-1.272.926Z"
fill="#6c3b41"
/>
</G>
</G>
</G>
<G data-name="Layer 3" transform="translate(8.294 3.336)">
<Circle
data-name="Ellipse 180"
cx={1.075}
cy={1.075}
r={1.075}
fill="url(#g)"
/>
</G>
<G data-name="Layer 4">
<G data-name="Group 2019" transform="translate(12.778)">
<Circle
data-name="Ellipse 181"
cx={0.547}
cy={0.547}
r={0.547}
fill="url(#g)"
/>
</G>
</G>
<G data-name="Layer 6">
<G data-name="Group 2020" transform="translate(12.158 23.751)">
<Circle
data-name="Ellipse 182"
cx={2.06}
cy={2.06}
r={2.06}
fill="#fff"
/>
</G>
<G data-name="Group 2021" transform="translate(9.743 21.162)">
<Circle
data-name="Ellipse 183"
cx={1.075}
cy={1.075}
r={1.075}
fill="#fff"
/>
</G>
<G data-name="Group 2022" transform="translate(12.532 18.571)">
<Circle
data-name="Ellipse 184"
cx={0.547}
cy={0.547}
r={0.547}
fill="#fff"
/>
</G>
<G data-name="Group 2023" transform="translate(11.247 34.222)">
<Circle
data-name="Ellipse 185"
cx={1.777}
cy={1.777}
r={1.777}
fill="#fff"
/>
</G>
</G>
</G>
</Svg>
</Pressable>
) : null}
<View style={tw("flex flex-row items-center ml-4")}>
{headerOptions?.back ? (
headerOptions?.title ? (
<Ionicons
name="arrow-back"
style={tw("mr-2")}
size={24}
color={
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white
}
onPress={() => navigation.goBack()}
/>
) : null
) : null}
{headerOptions?.qr ? (
<>
<Button
icon={
<Svg xmlns="http://www.w3.org/2000/svg" width={30} height={30}>
<G
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
>
<Path
data-name="Path 11446"
d="M2.131.275A3.177 3.177 0 0 0 .114 2.841 24.849 24.849 0 0 0 .045 5.98l.069 2.177h8.02V.137L5.499.091a18.649 18.649 0 0 0-3.368.184Zm4.973 3.873v2.979H1.146V4.973c0-2.452.229-3.277.962-3.575a13.17 13.17 0 0 1 2.773-.206l2.223-.023Z"
/>
<Path
data-name="Path 11447"
d="M2.521 4.263v1.742l1.673-.069 1.65-.069.069-1.673.068-1.65h-3.46Z"
/>
<Path
data-name="Path 11448"
d="M9.77.161a1.028 1.028 0 0 0-.16.6c0 .3.16.412.6.412.481 0 .573-.092.5-.5-.069-.535-.619-.81-.94-.512Z"
/>
<Path
data-name="Path 11449"
d="M16.888.71c0 .573-.092.687-.573.687-.412 0-.573.115-.573.458s.16.458.573.458c.481 0 .573.115.573.687 0 .665-.023.687-1.146.687-.985 0-1.146.069-1.146.458s.16.458 1.146.458c1.123 0 1.146.023 1.146.687s.023.687 1.146.687h1.146v1.146c0 1.077.046 1.146.573 1.146.55 0 .573-.046.573-1.719s-.023-1.719-.573-1.719c-.458 0-.573-.115-.573-.573s-.115-.573-.573-.573c-.55 0-.573-.069-.573-1.26v-1.26h1.169c1.077 0 1.146-.046 1.077-.527-.069-.458-.206-.5-1.719-.573l-1.673-.069Z"
/>
<Path
data-name="Path 11450"
d="M21.842.298a39.658 39.658 0 0 0-.069 4.079l.069 3.781h8.02V5.294c0-4.721-.367-5.087-4.973-5.225-2.36-.069-2.956-.023-3.047.229Zm6.325 1.306c.5.412.55.642.619 2.979l.092 2.544h-6V1.166h2.383c1.989 0 2.47.072 2.905.438Z"
/>
<Path
data-name="Path 11451"
d="M24.248 4.263v1.719h3.208V2.544h-3.208Z"
/>
<Path
data-name="Path 11452"
d="M11.966 1.856c0 .39.16.458 1.146.458s1.146-.069 1.146-.458-.16-.458-1.146-.458-1.146.069-1.146.458Z"
/>
<Path
data-name="Path 11453"
d="M10.735 3.117c0 .458-.115.573-.573.573h-.573v5.729H8.444c-1.077 0-1.146.046-1.146.573 0 .458.115.573.573.573s.573.115.573.573.115.573.573.573.573-.115.573-.573c0-.527.069-.573 1.146-.573h1.146V9.419c0-1.077-.046-1.146-.573-1.146s-.573-.069-.573-1.146V5.981h2.292V4.835c0-1.077-.046-1.146-.573-1.146-.458 0-.573-.115-.573-.573s-.116-.572-.574-.572-.573.115-.573.573Z"
/>
<Path
data-name="Path 11454"
d="M14.517 7.284c0 1.077-.046 1.146-.573 1.146-.55 0-.573.046-.573 1.719 0 1.558.046 1.719.458 1.719.344 0 .458-.16.458-.573 0-.458.115-.573.573-.573h.573V8.43c0-2.131-.023-2.292-.458-2.292-.389 0-.458.16-.458 1.146Z"
/>
<Path
data-name="Path 11455"
d="M12.046 7.628c-.183.458.092.8.619.8.321 0 .435-.16.435-.573s-.114-.571-.463-.571a.674.674 0 0 0-.591.344Z"
/>
<Path
data-name="Path 11456"
d="M16.876 7.884c0 .481.092.573.527.5a.638.638 0 0 0 .573-.6c.069-.412-.023-.5-.5-.5s-.6.115-.6.6Z"
/>
<Path
data-name="Path 11457"
d="M.16 9.795A2.612 2.612 0 0 0 0 10.941v.985h1.146c1.077 0 1.146-.046 1.146-.573 0-.458-.115-.573-.573-.573s-.573-.115-.573-.573c0-.412-.115-.573-.412-.573a.9.9 0 0 0-.574.161Z"
/>
<Path
data-name="Path 11458"
d="M4.812 10.198c0 .5.092.6.527.527a.512.512 0 0 0 .5-.527.512.512 0 0 0-.5-.527c-.435-.068-.527.023-.527.527Z"
/>
<Path
data-name="Path 11459"
d="M17.145 11.164c0 1.1-.046 1.169-.573 1.169-.458 0-.573.115-.573.573v.573h4.583v-.573c0-.458.115-.573.573-.573s.573-.115.573-.573c0-.55.069-.573 1.26-.573s1.26.046 1.26.55c0 .435-.137.573-.619.642-.5.046-.665.206-.71.687-.069.5-.206.642-.642.642s-.55.115-.55.573-.115.573-.573.573-.573.115-.573.573-.115.573-.573.573-.573-.115-.573-.573-.115-.573-.573-.573-.573.115-.573.573-.115.573-.573.573c-.412 0-.573.115-.573.458s.16.458.573.458c.481 0 .573.115.573.687s-.092.687-.573.687c-.458 0-.573.115-.573.573 0 .527.069.573 1.146.573h1.146v5.729h1.146c1.123 0 1.146.023 1.146.687s-.023.687-1.146.687c-.985 0-1.146.069-1.146.458s.16.458 1.146.458c1.077 0 1.146.046 1.146.573v.573h4.812v1.4l1.673-.069c1.512-.069 1.65-.115 1.719-.6.069-.435-.023-.5-.619-.5-.71 0-.71 0-.71-1.26s0-1.26.687-1.26h.71l-.069-1.673-.069-1.65-2.336-.071-2.36-.069V20.58h1.146c1.077 0 1.146-.046 1.146-.573 0-.458.115-.573.573-.573s.573-.115.573-.573-.115-.573-.573-.573-.573-.115-.573-.573c0-.527-.069-.573-1.146-.573s-1.146-.046-1.146-.573c0-.412-.115-.573-.458-.573s-.458.16-.458.573c0 .481-.115.573-.687.573s-.687.092-.687.573c0 .458-.115.573-.573.573s-.573.115-.573.573-.115.573-.573.573-.573-.115-.573-.573-.115-.573-.573-.573c-.481 0-.573-.115-.573-.687 0-.665.023-.687 1.146-.687 1.077 0 1.146-.046 1.146-.573 0-.458.115-.573.573-.573s.573-.115.573-.573.115-.573.573-.573.573-.115.573-.573c0-.55.069-.573 1.26-.573 1.237 0 1.26 0 1.26.687 0 .573-.092.687-.573.687-.412 0-.573.115-.573.458 0 .39.16.458 1.146.458 1.077 0 1.146.046 1.146.573 0 .756.848.8.962.046.046-.367.252-.527.71-.573.435-.046.619-.206.619-.527s-.16-.435-.687-.435c-.573 0-.687-.092-.687-.573 0-.458-.115-.573-.573-.573-.481 0-.573-.115-.573-.687s-.092-.687-.573-.687c-.527 0-.573-.069-.573-1.146v-1.146h-5.73v.573a.6.6 0 0 1-1.192.046c-.069-.435-.229-.5-1.146-.573l-1.1-.069Zm9.4 7.7c0 .481-.115.573-.687.573s-.687-.092-.687-.573.115-.573.687-.573.682.091.682.572Zm-2.346 3.482-.069 1.787-1.764.069-1.787.069v-3.689h3.689Zm2.337 3.391c0 .458.115.573.573.573.481 0 .573.115.573.687 0 .619-.069.687-.687.687-.573 0-.687-.092-.687-.573 0-.412-.115-.573-.458-.573s-.458.16-.458.573c0 .55-.069.573-1.26.573-1.237 0-1.26 0-1.26-.687 0-.573.092-.687.573-.687.458 0 .573-.115.573-.573 0-.55.069-.573 1.26-.573s1.262.024 1.262.574Z"
/>
<Path
data-name="Path 11460"
d="M21.725 21.73a.9.9 0 0 0-.16.573c0 .3.16.412.573.412.458 0 .573-.115.573-.573 0-.412-.115-.573-.412-.573a.9.9 0 0 0-.574.161Z"
/>
<Path
data-name="Path 11461"
d="M28.831 10.176c0 .481.115.6.6.6s.573-.092.5-.527a.636.636 0 0 0-.573-.573c-.435-.073-.527.019-.527.5Z"
/>
<Path
data-name="Path 11462"
d="M3.667 11.391c0 .458-.115.573-.573.573-.527 0-.573.069-.573 1.146 0 .985.069 1.146.458 1.146.344 0 .458-.16.458-.573v-.573h2.429c2.383 0 2.406 0 2.337-.527-.069-.458-.206-.5-1.833-.573-1.719-.069-1.787-.092-1.787-.619 0-.412-.115-.573-.458-.573s-.458.16-.458.573Z"
/>
<Path
data-name="Path 11463"
d="M27.686 11.37c0 .412.115.573.458.573s.458-.16.458-.573-.116-.573-.458-.573-.458.16-.458.573Z"
/>
<Path
data-name="Path 11464"
d="M9.77 12.106a1.027 1.027 0 0 0-.16.6c0 .3.16.412.6.412.481 0 .573-.092.5-.5-.069-.535-.619-.81-.94-.512Z"
/>
<Path
data-name="Path 11465"
d="M0 14.996v1.6h1.719c1.558 0 1.719-.046 1.719-.458 0-.344-.16-.458-.573-.458-.458 0-.573-.115-.573-.573s-.115-.573-.573-.573-.573-.115-.573-.573-.115-.565-.573-.565c-.55 0-.573.046-.573 1.6Z"
/>
<Path
data-name="Path 11466"
d="M8.438 13.829c0 .344.16.458.573.458s.573-.115.573-.458-.161-.458-.573-.458-.573.115-.573.458Z"
/>
<Path
data-name="Path 11467"
d="M13.371 14.414c0 .871.069 1.031.458 1.031.344 0 .458-.16.458-.573 0-.458.115-.573.573-.573.412 0 .573-.115.573-.458 0-.39-.16-.458-1.031-.458h-1.031Z"
/>
<Path
data-name="Path 11468"
d="M6.1 15c0 .39.16.458 1.146.458s1.146-.069 1.146-.458-.161-.458-1.146-.458S6.1 14.611 6.1 15Z"
/>
<Path
data-name="Path 11469"
d="M9.61 15c0 .344.16.458.573.458s.573-.115.573-.458-.161-.458-.573-.458-.573.115-.573.458Z"
/>
<Path
data-name="Path 11470"
d="M8.438 16.171c0 .344.16.458.573.458s.573-.115.573-.458-.161-.458-.573-.458-.573.115-.573.458Z"
/>
<Path
data-name="Path 11471"
d="M11.954 16.171c0 .344.16.458.573.458s.573-.115.573-.458-.161-.458-.573-.458-.573.115-.573.458Z"
/>
<Path
data-name="Path 11472"
d="M14.517 16.318c0 .458-.115.573-.573.573-.527 0-.573.069-.573 1.146 0 .985.069 1.146.458 1.146.344 0 .458-.16.458-.573 0-.458.115-.573.573-.573.527 0 .573-.069.573-1.146 0-.985-.069-1.146-.458-1.146-.344 0-.458.16-.458.573Z"
/>
<Path
data-name="Path 11473"
d="M3.666 17.459c0 .412.115.573.458.573s.458-.16.458-.573-.116-.573-.458-.573-.458.16-.458.573Z"
/>
<Path
data-name="Path 11474"
d="M7.104 17.53c0 .458-.115.573-.573.573s-.573.115-.573.573v.55l-2.91.069c-2.75.069-2.933.092-2.933.527s.183.458 4.652.527l4.629.046v2.292h3.437v-1.17c0-1.077-.046-1.146-.5-1.077a.638.638 0 0 0-.6.573.6.6 0 0 1-1.192-.046c0-.458-.115-.573-.573-.573s-.573-.115-.573-.573c0-.527-.069-.573-1.146-.573-1.054 0-1.146-.046-1.146-.55 0-.412.137-.573.527-.642a.638.638 0 0 0 .573-.6c.069-.412-.023-.5-.5-.5s-.599.116-.599.574Z"
/>
<Path
data-name="Path 11475"
d="m9.665 17.979.069 1.1 1.1.069 1.077.069v-2.315H9.596Z"
/>
<Path
data-name="Path 11476"
d="M14.53 19.801c0 .412.115.573.458.573s.458-.16.458-.573-.116-.573-.458-.573-.458.16-.458.573Z"
/>
<Path
data-name="Path 11477"
d="M15.702 21.564c0 .985.069 1.146.458 1.146s.458-.16.458-1.146-.068-1.146-.458-1.146-.458.16-.458 1.146Z"
/>
<Path
data-name="Path 11478"
d="M.092 22.072a20.5 20.5 0 0 0-.046 3.025c.137 4.377.573 4.766 5.225 4.766h2.864v-8.02l-3.964-.069c-3.369-.049-3.965 0-4.079.298Zm7.012 3.781v2.979H4.72c-3.346 0-3.437-.069-3.529-3.414l-.092-2.544h6Z"
/>
<Path
data-name="Path 11479"
d="M2.521 25.848v1.6h3.437v-3.2H2.521Z"
/>
<Path
data-name="Path 11480"
d="M14.53 23.314c0 .412.115.573.458.573s.458-.16.458-.573-.116-.573-.458-.573-.458.16-.458.573Z"
/>
<Path
data-name="Path 11481"
d="M9.61 24.706c0 .344.16.458.573.458s.573-.115.573-.458-.161-.458-.573-.458-.573.115-.573.458Z"
/>
<Path
data-name="Path 11482"
d="M13.358 24.706a.411.411 0 0 0 .458.458.411.411 0 0 0 .458-.458.411.411 0 0 0-.458-.458.411.411 0 0 0-.458.458Z"
/>
<Path
data-name="Path 11483"
d="M15.694 24.706c0 .344.16.458.573.458.481 0 .573.115.573.687 0 .619-.069.687-.687.687-.573 0-.687-.092-.687-.573 0-.412-.115-.573-.458-.573s-.458.16-.458.573c0 .458-.115.573-.573.573-.527 0-.573.092-.573 1.031 0 .871.069 1.031.458 1.031.344 0 .458-.16.458-.573 0-.481.115-.573.687-.573.619 0 .687.069.687.687 0 .573-.092.687-.573.687-.458 0-.573.115-.573.573 0 .527.092.573 1.031.573h1.031v-1.26c0-1.237 0-1.26.687-1.26h.687v-3.206h-1.145c-.985 0-1.145.069-1.145.458Z"
/>
<Path
data-name="Path 11484"
d="M10.792 26.994c0 1.558.023 1.6.573 1.6.527 0 .573-.069.573-1.146s.046-1.146.573-1.146c.412 0 .573-.115.573-.458 0-.39-.16-.458-1.146-.458h-1.146Z"
/>
<Path
data-name="Path 11485"
d="M18.048 28.855c0 1.077.046 1.146.527 1.077.435-.069.5-.229.573-1.169.069-1.031.046-1.077-.5-1.077s-.6.069-.6 1.169Z"
/>
<Path
data-name="Path 11486"
d="M9.657 29.331a.641.641 0 0 0 .6.6c.412.069.5-.023.5-.5s-.115-.6-.6-.6-.569.092-.5.5Z"
/>
<Path
data-name="Path 11487"
d="M12.001 29.331a.641.641 0 0 0 .6.6c.412.069.5-.023.5-.5s-.115-.6-.6-.6-.569.092-.5.5Z"
/>
</G>
</Svg>
}
route={"QR"}
state={"book"}
/>
<Button
icon={
<Svg
xmlns="http://www.w3.org/2000/svg"
width={29.9}
height={30.908}
>
<G
data-name="Group 419"
fill={
theme === "light"
? Colors.theme1.green79
: Colors.theme1.white
}
>
<Path
data-name="Path 1864"
d="M1.694 1.694h5.081V0H0v6.775h1.694Zm0 0"
/>
<Path
data-name="Path 1863"
d="M22.132 0v1.694h5.081v5.081h1.694V0Zm0 0"
/>
<Path
data-name="Path 1862"
d="M27.213 27.214h-5.081v1.694h6.775v-6.775h-1.694Zm0 0"
/>
<Path
data-name="Path 1861"
d="M1.694 22.133H0v6.775h6.775v-1.694H1.694Zm0 0"
/>
<Textt
transform="translate(15 19)"
fontSize={14}
// fontFamily="regular"
>
<TSpan x={-8.841} y={0}>
{"AR"}
</TSpan>
</Textt>
</G>
</Svg>
}
route={"AR"}
state={"AR"}
/>
</>
) : null}
{headerOptions?.bookmark ? (
bookmarkLoading ? (
<ActivityIndicator
size={20}
color={
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white
}
/>
) : isActiveBookmark ? (
<Ionicons
name="bookmark"
style={tw("mr-2")}
size={24}
color={
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white
}
onPress={() =>
headerOptions?.bookmarkItem?.contentId
? deleteBookmark({
id: userFavoriteList.filter(
(object) =>
object.contentId ===
headerOptions.bookmarkItem?.contentId
)[0].id,
})
: deleteBookmark({
id: userFavoriteList.filter(
(object) =>
object.productId ===
headerOptions.bookmarkItem?.productId
)[0].id,
})
}
/>
) : (
<Ionicons
name="bookmark-outline"
style={tw("mr-2")}
size={24}
color={
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white
}
onPress={() =>
headerOptions?.bookmarkItem?.contentId
? addToBookmark({
contentId: headerOptions?.bookmarkItem?.contentId,
})
: addToBookmark({
productId: headerOptions?.bookmarkItem?.productId,
})
}
/>
)
) : null}
{headerOptions?.menu ? (
<Entypo
name="dots-three-vertical"
size={24}
color={theme === "light" ? "#52796F" : Colors.theme1.white}
/>
) : null}
</View>
</View>
);
};
const mapStateToProps = (state) => ({
userFavoriteList: state.userFavorite.list,
theme: state.publicApi.theme,
bookmarkLoading: state.userFavorite.loading,
});
const mapDispatchToProps = {
addToBookmark: userFavorite.add,
deleteBookmark: userFavorite.del,
};
export default connect(mapStateToProps, mapDispatchToProps)(Navbar);

@ -0,0 +1,20 @@
import React, {useState} from 'react';
import {View, Text, Dimensions} from 'react-native';
import tw from 'tailwind-rn';
const width = Dimensions.get('window').width;
function Or(props) {
return (
<View
style={[tw('w-full flex flex-row justify-between items-center my-3')]}>
<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,62 @@
import React from "react";
import { TouchableOpacity, Text, ActivityIndicator } from "react-native";
import { connect } from "react-redux";
//style
import tw from "tailwind-rn";
import fontSize from "../constants/fontSize";
function Pressable1({
title,
backgroundColor,
color,
border,
width,
onPress,
loading,
mobile,
theme,
textFontSize,
}) {
return (
<TouchableOpacity
onPress={() => onPress()}
style={[
tw("rounded-sm py-3 flex flex-row justify-center mb-3"),
{
backgroundColor: backgroundColor,
borderWidth: border.width,
borderColor: border.color,
width: width,
},
]}
>
{loading ? (
<ActivityIndicator size="small" color={color} />
) : (
<Text
style={{
fontSize: mobile
? textFontSize
? textFontSize
: fontSize.tiny
: textFontSize
? textFontSize
: fontSize.xl,
color: color,
fontFamily: "bold",
}}
>
{title}
</Text>
)}
</TouchableOpacity>
);
}
const mapStateToProps = (state) => ({
mobile: state.publicApi.mobile,
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Pressable1);

@ -0,0 +1,38 @@
import React from "react";
import { View } from "react-native";
import {connect} from "react-redux";
//assets
import tw from "tailwind-rn";
import Colors from "../constants/Colors";
function Progress({ percent, alignItems, theme }) {
return (
<></>
// <View
// style={[
// tw(
// `w-full h-1.5 rounded-full overflow-hidden my-3 flex ${alignItems}`
// ),
// { backgroundColor: Colors.theme1.green79 + "22" },
// ]}
// >
// <View
// style={[
// tw("h-full rounded-full"),
// {
// backgroundColor: Colors.theme1.greenCF,
// width: percent + "%",
// // backgroundColor: Color.theme1.light.blue4,
// },
// ]}
// ></View>
// </View>
);
}
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
})
export default connect(mapStateToProps)(Progress);

@ -0,0 +1,32 @@
import React from "react";
import { View, Text, Dimensions, Image } from "react-native";
import tw from "tailwind-rn";
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("w-full flex flex-row-reverse items-center p-4 rounded-md mb-5"),
{ backgroundColor: "#196EC0" },
]}
>
<View style={tw("flex-1 flex ")}>
<Text
style={[
tw("font-medium text-right"),
{ fontSize: width / 30, color: "white" },
]}
>
{text}
</Text>
</View>
<View style={tw("p-0")}>
<Image source={leftIcon} style={{ width: 24, height: 24 }} />
</View>
</View>
);
}

@ -0,0 +1,39 @@
import React, { useState, useEffect } from "react";
import { Text, View, StyleSheet, Button } from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === "granted");
})();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={{ width: "100%", height: 300 }}
/>
{scanned ? (
<Button title={"Tap to Scan Again"} onPress={() => setScanned(false)} />
) : null}
</>
);
}

@ -0,0 +1,63 @@
import React, { useState } from "react";
import { TextInput, View, StyleSheet, Pressable } from "react-native";
import { connect } from "react-redux";
import tw from "tailwind-rn";
import { AntDesign } from "@expo/vector-icons";
//style
import Colors from "../constants/Colors";
import fontSize from "../constants/fontSize";
const Search = ({
placeholder,
textAlign,
direction,
onChange,
value,
theme,
}) => {
const styles = StyleSheet.create({
inputStyle: {
fontSize: fontSize.tiny,
color: theme === "light" ? Colors.theme1.gray2077 : Colors.theme1.white,
borderWidth: 0.5,
borderColor: Colors.theme1.gray20 + "88",
paddingVertical: 10,
paddingHorizontal: 10,
direction: direction,
textAlign: textAlign,
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.gray2077,
fontFamily: "regular",
},
});
return (
<View style={[{ marginTop: 18 }, tw("w-full relative")]}>
<TextInput
style={[styles.inputStyle, tw("rounded-sm")]}
onChangeText={(text) => onChange(text)}
placeholder={placeholder}
placeholderTextColor={
theme === "light"
? Colors.theme1.gray20 + "88"
: Colors.theme1.white + "aa"
}
value={value}
/>
<Pressable style={tw("absolute left-3 top-3")}>
<AntDesign name="search1" size={20} color="#52796F" />
</Pressable>
</View>
);
};
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Search);
Search.defaultProps = {
direction: "rtl",
textAlign: "right",
};

@ -0,0 +1,91 @@
import React from "react";
import { connect } from "react-redux";
import Svg, { Path } from "react-native-svg";
import SelectDropdown from "react-native-select-dropdown";
//styles
import fontSize from "../constants/fontSize";
import Colors from "../constants/Colors";
function Select({
iconPosition,
options,
onChange,
name,
width,
defaultValue,
theme,
disabled,
}) {
return (
<SelectDropdown
data={options}
disabled={disabled}
buttonStyle={{
width: width,
borderWidth: 1,
borderColor: Colors.theme1.gray2077 + "66",
borderRadius: 2,
height: 48,
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.gray2077,
fontFamily: "regular",
}}
rowTextStyle={{
fontSize: fontSize.sm,
fontFamily: "regular",
color: theme === "light" ? Colors.theme1.gray20 : Colors.theme1.grayF9,
}}
defaultButtonText={defaultValue}
statusBarTranslucent={true}
buttonTextStyle={{
textAlign: "center",
justifyContent: "flex-end",
flex: 0,
fontSize: fontSize.tiny,
color: theme === "light" ? Colors.theme1.gray2077 + (disabled ? "aa" : "") : Colors.theme1.white + (disabled ? "aa" : ""),
fontFamily: "regular",
// display: 'inline'
}}
dropdownIconPosition={iconPosition}
onSelect={(selectedItem) => {
onChange(name, selectedItem);
}}
renderDropdownIcon={() => (
<Svg
data-name="vuesax/linear/arrow-down"
xmlns="http://www.w3.org/2000/svg"
width={16.081}
height={16.081}
>
<Path
d="m13.347 5.997-4.368 4.369a1.331 1.331 0 0 1-1.876 0L2.734 5.997"
fill="none"
stroke={
theme === "light"
? Colors.theme1.gray2077 + "66"
: Colors.theme1.white + (disabled ? "aa" : "")
}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
/>
</Svg>
)}
dropdownStyle={{
backgroundColor:
theme === "light" ? Colors.theme1.white : Colors.theme1.gray2077,
}}
/>
);
}
const mapStateToProps = (state) => ({
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Select);
Select.defaultProps = {
options: ["1", "2", "3"],
iconPosition: "left",
};

@ -0,0 +1,46 @@
const Colors = {
theme1: {
//green
green79: "#52796F",
greenBA: "#06BAC0",
greenC8: "#76C893",
greenCF: "#12CF7F",
greenD9: "#99D98C",
greenDD: "#D5DDBC",
greenFF: "#00FF80",
greenFF1: "#DEFFF1",
//blue
blue90: "#235A90",
blueCB: "#98B2CB",
blueEB: "#2B8DEB",
blueFA: "#F8F9FA",
blueFA1: "#9CF1FA",
blueFD: "#F6F9FD",
blueFD1: "#F4F8FD",
blueFDOP: "rgba(6, 146, 255, 0.36)",
blueFF: "#E8FCFF",
blueFF1: "#E9F0FF",
//gray
gray20: "#202020",
gray2077: "#2F3E46",
grayE3: "#E3E3E3",
grayF9: "#F9F9F9",
grayCC: "#CCC",
//red
redC0: "#C01919",
redFF: "#FFE6E6",
redFF1: "#FF2020",
//yellow
yellow2: "#FDFFDA",
yellow3: "#EFFF00",
yellow4: "#FFEE00",
//orange
orange1: "#FF6600",
//black
black: "#000000",
white: "#FFFFFF",
dark : '#061B30',
},
};
export default Colors;

@ -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',
};

@ -0,0 +1,21 @@
import { Dimensions } from "react-native"
import { fontSizeHandler } from "../utils/fontSizeResponsive"
const {width} = Dimensions.get("window");
const minWidth = 320;
const maxWidth = 1200;
const fontSize = {
xs : fontSizeHandler(width, 10, 12, minWidth, maxWidth),
sm : fontSizeHandler(width,12, 14, minWidth, maxWidth),
base : fontSizeHandler(width, 14, 16, minWidth, maxWidth),
lg : fontSizeHandler(width, 16 , 18, minWidth, maxWidth),
xl : fontSizeHandler(width, 18, 20, minWidth, maxWidth),
xl2 : fontSizeHandler(width, 20, 22, minWidth, maxWidth),
xl3 : fontSizeHandler(width, 22, 24, minWidth, maxWidth),
xl4 : fontSizeHandler(width, 24, 26, minWidth, maxWidth),
xl5 : fontSizeHandler(width, 26, 28, minWidth, maxWidth),
xl6 : fontSizeHandler(width, 28, 30, minWidth, maxWidth)
};
export default fontSize;

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

@ -0,0 +1,13 @@
import proxy from "../proxy";
const blog = {
list:
(data = {}) =>
async (dispatch) =>
await proxy.get("public/blogList", data, { dispatch }),
info: (data) => async (dispatch) =>
await proxy.get("public/blogInfo", data, { dispatch }),
setHashtag: (data) => async (dispatch) =>
await dispatch({ type: "public/setHashtag", data }),
};
export default blog;

@ -0,0 +1,18 @@
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 }),
setFilterOptions: (data) => async (dispatch) => {
dispatch({ type: "book/setFilterOptions", data: data });
},
};
export default book;

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

@ -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,8 @@
const form = {
setTicket:
(data = {}) =>
async (dispatch) =>
await dispatch({ type: "form/ticket", data }),
};
export default form;

@ -0,0 +1,19 @@
// @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";
export { default as qr } from "./qr";
export {default as userAddress} from "./userAddress";
export {default as userFavorite} from "./userFavorite";
export { default as transport } from "./transport";
export { default as activation } from "./activation";
export { default as form } from "./form";
export { default as comment } from "./comment";
export { default as vote } from "./vote";

@ -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,54 @@
import proxy from "../proxy";
const publicApi = {
setLTR: (data) => async (dispatch) =>
await dispatch({ type: "public/setLtr", data: data }),
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 = {}, data2 = {}) =>
async (dispatch) => {
await proxy.get("public/vod/bookCourse", data, { dispatch });
await proxy.get("book/info", data2, { 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 }),
getArList: (data, history) => async (dispatch) =>
await proxy.get("public/ar", data, { history, dispatch }),
};
export default publicApi;

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

@ -0,0 +1,17 @@
import proxy from "../proxy";
const transport = {
list:
(data = {}) =>
async (dispatch) => {
await proxy.get("transport/list", data, { dispatch });
},
set:
(data = {}, data2 = {}, data3 = {}) =>
async (dispatch) => {
await proxy.post("transport/setTransport", data, { dispatch });
await proxy.get("userFactor/info", data2, { dispatch });
},
};
export default transport;

@ -0,0 +1,61 @@
import proxy from "../proxy";
const user = {
getStatus: () => async (dispatch) => {
await proxy.getStatus({ dispatch });
},
otp: (data) => async (dispatch) => {
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 }),
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 });
},
setProfileFields:
(data = {}) =>
async (dispatch) => {
await dispatch({ type: "user/setProfileFields", data });
},
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,36 @@
import proxy from "../proxy";
const userAddress = {
list:
(data = {}) =>
async (dispatch) => {
await proxy.get("userAddress/list", data, { dispatch });
},
info:
(data = {}) =>
async (dispatch) => {
await dispatch({ type: "userAddress/info", data });
},
update:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.put("userAddress/update", data);
await proxy.get("userAddress/list", data2, { dispatch });
},
add:
(data = {}, data2 = {}, data3 = {}) =>
async (dispatch) => {
await proxy.post("userAddress/add", data);
setTimeout(() => {
proxy.get("userAddress/list", data2, { dispatch });
}, 600);
},
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userAddress/delete", data);
await proxy.get("userAddress/list", data2, { dispatch });
},
};
export default userAddress;

@ -0,0 +1,59 @@
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 });
},
fullList:
(data = {}) =>
async (dispatch) =>
await proxy.get("userFactor/fullList", data, { dispatch }),
};
export default userFactor;

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

@ -0,0 +1,42 @@
import proxy from "../proxy";
const userProduct = {
arList:
(data = {}) =>
async (dispatch) => {
await proxy.get("userProduct/arList", data, { dispatch });
},
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("userFactor/info", data3, { dispatch });
},
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userProduct/delete", data);
await proxy.get("userProduct/list", data2, { dispatch });
},
myList:
(data = {}) =>
async (dispatch) => {
await proxy.get("userProduct/myList", data, { dispatch });
},
};
export default userProduct;

@ -0,0 +1,11 @@
import proxy from "../proxy";
const vote = {
add:
(data = {}, data2) =>
async (dispatch) => {
await proxy.post("userVote/add", data, { dispatch });
},
};
export default vote;

@ -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,153 @@
import { ApiConfig } from "../constants/defaultValues";
import axios from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { useNavigation } from "@react-navigation/native";
import { asyncAwesomeAlert } from "../utils/AsyncWrappers";
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) {}
};
post = (url, params, opt, data) => {
try {
this.check(url, opt, () => Axios.post(url, params, opt), data || params);
} catch (error) {}
};
put = (url, params, opt, data) => {
try {
this.check(url, opt, () => Axios.put(url, params, opt), data || params);
} catch (error) {}
};
delete = (url, params, opt, data) => {
try {
this.check(
url,
opt,
() => Axios.delete(url, { ...opt, data: params }),
data || params
);
} catch (error) {}
};
check = async (url, { dispatch }, fetch, params) => {
try {
dispatch = dispatch || (() => {});
dispatch({ type: url.split("/")[0] + "/" + "loading" });
let response = await 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;
}
return;
case 403:
asyncAwesomeAlert("", 'خطای ورود اطلاعات', {
showCancelButton: false,
});
default:
dispatch({
type: url.split("/")[0] + "/" + "error",
data: response.data,
params,
});
}
return false;
} catch (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) {}
};
login = (url, params, { dispatch }) => {
try {
this.post(url, params, {
dispatch: (obj) => {
let login = obj.data;
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) {}
};
logout = (url, params, { dispatch }) => {
try {
this.post(url, params, {
dispatch: (obj) => {
const keys = ["refresh", "access", "userData"];
AsyncStorage.multiRemove(keys);
dispatch(obj);
},
});
} catch (error) {}
};
status = async () => {
try {
let refresh = await AsyncStorage.getItem("refresh");
let userData = await 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) {
return nulll;
}
};
getStatus = async ({ dispatch }) => {
let status = await this.status();
dispatch({ type: "user/getStatus", data: { status } });
};
}
const _proxy = new Proxy();
export default _proxy;

@ -0,0 +1,39 @@
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers";
const initialState = {
loading: false,
error: null,
list: [],
message: null,
};
export default function activation(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "activation/list":
return { ...state, loading: false, list: data, error: null };
case "activation/update":
return { ...state, loading: false, error: null, message: data.message };
case "activation/add":
asyncAwesomeAlert("نتیجه", data.message, {
showCancelButton: false,
});
return { ...state, loading: false, error: null };
case "activation/delete":
return { ...state, loading: false, error: null };
case "loading":
return { ...state, loading: true };
case "error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return {
...state,
loading: false,
error: data.message,
message: data.message,
};
default:
return state;
}
}

@ -0,0 +1,36 @@
const initialState = {
loading: false,
error: null,
list: [],
info: null,
hashtags : [],
hashtag : null,
};
export default function blog(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "public/setHashtag":
return {
...state,
loading: false,
hashtag: data,
error: null,
};
case "public/blogList":
return {
...state,
loading: false,
list: data,
hashtags: [...new Set(data.map((object) => object.tag))],
error: null,
};
case "public/blogInfo":
return { ...state, loading: false, error: null, blog: data };
case "blog/loading":
return { ...state, loading: true };
case "blog/error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,96 @@
import {asyncAwesomeAlert} from '../../utils/AsyncWrappers';
const initialState = {
loading: false,
error: null,
list: [],
info: null,
searchResult: [],
filterResult: [],
subjects: [],
levels: [],
sortFilters: ["مرتب سازی", "محبوب ترین", "جدیدترین"],
selectedVideo: null,
gradeFilterBooks: null,
sortFilterCourse: null,
selectedGrade: null,
selectedSort: "پربازدید ترین ها",
filterOptions: {
grade: "",
subject: "",
productType: '',
available: false,
sort: null,
search: "",
},
productTypes: [
"نوع محصول",
"کتاب فیزیکی",
"کتاب دیجیتال",
"دوره ویدئویی",
"بسته های آموزشی",
],
};
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
);
itemsSubject.unshift("نام کتاب");
let itemsLevel = (Array.isArray(data) ? data : [])
.map((item) => item.gradeId * 1)
.sort((a, b) => a - b)
.map((e) => grades[e]);
itemsLevel.unshift("پایه تحصیلی");
return {
...state,
loading: false,
list: data,
subjects: Array.from(new Set(itemsSubject)),
levels: Array.from(new Set(itemsLevel)),
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/setFilterOptions":
return { ...state, loading: false, error: null, filterOptions: data };
case "book/loading":
return { ...state, loading: true };
case "book/error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,37 @@
const initialState = {
loading: false,
error: null,
list: null,
};
export default function comment(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "comment/list":
return { ...state, loading: false, error: null };
case "comment/update":
return { ...state, loading: false, error: null };
case "comment/add":
return { ...state, loading: false, error: null };
case "comment/delete":
return { ...state, loading: false, error: null };
case "comment/info":
return {
...state,
loading: false,
list: data,
error: null,
};
case "comment/loading":
return { ...state, loading: true };
case "comment/error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,55 @@
const initialState = {
loading: false,
error: null,
list: [],
searchResult: [],
search: "",
};
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":
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,24 @@
const initialState = {
loading: false,
error: null,
ticket: {},
};
export default function form(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "form/ticket":
return {
...state,
loading: false,
ticket: { ...state.ticket, [data.name]: data.value },
error: null,
};
case "form/loading":
return { ...state, loading: true };
case "form/error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,18 @@
// @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";
import { default as qr } from "./qr";
export { default as userAddress } from "./userAddress";
export { default as userFavorite } from "./userFavorite";
export { default as transport } from "./transport";
export { default as activation } from "./activation";
export { default as form } from "./form";
export { default as comment } from "./comment";
export { default as vote } from "./vote";

@ -0,0 +1,31 @@
import {asyncAwesomeAlert} from '../../utils/AsyncWrappers';
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":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,190 @@
import { Dimensions } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
const width = Dimensions.get("window").width;
const initialState = {
ltr: false,
theme: null,
mobile: width < 720,
homeData: [],
newProducts: [],
levels: [],
loading: false,
error: null,
searchResult: [],
arList: [],
blogList: [],
blog: null,
provinces: [],
cities: [],
province: ["استان"],
city: ["شهرستان"],
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: "پایه تحصیلی",
// _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/setLtr":
return { ...state, ltr: true };
case "public/setIsDark":
AsyncStorage.setItem("theme", data);
return { ...state, location: false, error: null, theme: 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))
);
allCats.sort((a, b) => a - b);
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/ar":
return { ...state, loading: false, error: null, arList: 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: [...state.province, ...data.map((item) => item.name)],
provinces: data,
};
case "public/city":
return {
...state,
loading: false,
error: null,
city: [...data.map((item) => item.name)],
cities: 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,33 @@
const initialState = {
loading: false,
error: null,
list: null,
};
export default function qr(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "qr/list":
return { ...state, loading: false, error: null };
case "qr/update":
return { ...state, loading: false, error: null };
case "qr/add":
return { ...state, loading: false, error: null };
case "qr/delete":
return { ...state, loading: false, error: null };
case "qr/info":
return {
...state,
loading: false,
list: data,
error: null,
};
/////////////
case "loading":
return { ...state, loading: true };
case "error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,25 @@
const initialState = {
loading: false,
error: null,
list: [],
};
export default function transport(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "transport/list":
return {
...state,
loading: false,
list: data,
error: null,
};
case "transport/info":
return { ...state, loading: false, error: null};
case "transport/loading":
return { ...state, loading: true };
case "transport/error":
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,75 @@
import proxy from "../proxy";
import AsyncStorage from "@react-native-async-storage/async-storage";
import {asyncAwesomeAlert} from '../../utils/AsyncWrappers';
let initialState = {
status: null,
loading: false,
error: null,
list: null,
domains: [],
mothers: [],
profileStatus: false,
setDone: false,
setLogin: false,
check: "check",
profileFields : {
},
};
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/getStatus":
return { ...state, status: JSON.parse(data.status), 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) {
("user/getProfile", error);
}
return {
...state,
loading: false,
status: data,
error: null,
setDone: false,
};
case "user/logout":
return { ...state, loading: false, status: null, error: null };
case "user/getUserRole":
return { ...state, loading: false, userRoles: data, error: null };
case "user/setProfile":
return { ...state, loading: false, error: null, setDone: true };
case "user/setProfileFields":
return { ...state, loading: false, error: null, profileFields: data };
case "user/loading":
return { ...state, loading: true };
case "user/error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, error : true };
default:
return state;
}
};
export default user;

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

@ -0,0 +1,67 @@
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers";
const initialState = {
loading: false,
error: null,
list: null,
info: null,
sum: null,
checkEmpty: false,
isVerified: null,
fullList: [],
};
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/fullList":
return {
...state,
loading: false,
fullList: data,
error: null,
};
case "userFactor/info":
return { ...state, loading: false, info: data, error: null };
case "userFactor/add":
return { ...state, loading: false, error: null, sum: data.payPrice };
case "userFactor/delete":
return { ...state, loading: false, error: null };
case "userFactor/payment":
return { ...state, loading: false, error: null };
//vod
case "userFactor/myList":
return { ...state, loading: false, list: data, error: null };
case "userFactor/update":
return { ...state, loading: false, error: null };
case "userFactor/deleteUserOffCode":
return { ...state, loading: false, error: null };
case "userFactor/paymentVOD":
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":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,41 @@
import { toastMessage } from "../../utils/message";
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers";
const initialState = {
loading: false,
error: null,
list: [],
};
export default function userFavorite(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userFavorite/list":
return {
...state,
loading: false,
list: data,
error: null,
};
case "userFavorite/update":
return { ...state, loading: false, error: null };
case "userFavorite/add":
return {
...state,
list: data.userFavorites,
loading: false,
error: null,
};
case "userFavorite/delete":
return { ...state, list : data.userFavorites, loading: false, error: null };
case "userFavorite/loading":
return { ...state, loading: true };
case "userFavorite/error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,62 @@
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers";
const initialState = {
loading: false,
error: null,
list: [],
myList: [],
info: null,
sum: null,
checkEmpty: false,
hasPhysical: false,
arList : [],
};
export default function userFactor(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userProduct/arList":
return { ...state, loading: false, arList: data, error: null };
case "userProduct/myList":
return { ...state, loading: false, myList: data, error: null };
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":
return {
...state,
loading: false,
error: null,
list: data.products,
sum: data.payPrice,
};
case "userProduct/delete":
return { ...state, loading: false, error: null };
case "userProduct/loading":
return { ...state, loading: true };
case "userProduct/error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,27 @@
import { asyncApiAwesomeAlert } from "../../utils/AsyncWrappers";
const initialState = {
loading: false,
error: null,
};
export default function vote(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userVote/add":
asyncAwesomeAlert("نتیجه", "رای شما با موفقیت ثبت شد.", {
showCancelButton: false,
});
return { ...state, loading: false, error: null };
case "userVote/loading":
return { ...state, loading: true };
case "userVote/error":
asyncAwesomeAlert("خطا", data.message, {
showCancelButton: false,
confirmText: "باشه"
});
return { ...state, loading: false, error: data.message };
default:
return state;
}
}

@ -0,0 +1,65 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import { applyMiddleware, createStore, compose, combineReducers } from "redux";
import thunk from "redux-thunk";
import { persistStore, persistReducer } from "redux-persist";
import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2";
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";
import qr from "./reducers/qr";
import userAddress from "./reducers/userAddress";
import transport from "./reducers/transport";
import comment from "./reducers/comment";
import form from "./reducers/form";
import userFavorite from "./reducers/userFavorite";
import vote from "./reducers/vote";
const persistConfig = {
key: "root",
storage: AsyncStorage,
stateReconciler: autoMergeLevel2, // see "Merge Process" section for details.
whitelist: ["profile"],
};
const initialState = {};
const middleWare = [thunk];
const persistedReducer = persistReducer(
persistConfig,
combineReducers({
publicApi,
user,
book,
blog,
product,
faq,
file,
userFactor,
userProduct,
qr,
userAddress,
transport,
comment,
form,
userFavorite,
vote,
})
);
console.disableYellowBox = true;
export const store = createStore(
persistedReducer,
initialState,
compose(applyMiddleware(...middleWare))
);
export const persistor = persistStore(store);

@ -0,0 +1,55 @@
import { Pressable, Text, Image, Dimensions } from "react-native";
import React from "react";
import { connect } from "react-redux";
import * as Linking from "expo-linking";
//style
import tw from "tailwind-rn";
import fontSize from "../../../constants/fontSize";
import Colors from "../../../constants/Colors";
const { width, height } = Dimensions.get("window");
const Book = ({ book, mobile, theme }) => {
return (
<Pressable
style={[
tw("flex items-end rounded-md p-2 my-2"),
{ width: mobile ? "48%" : width / 4.2 },
]}
onPress={() => Linking.openURL(`https://ar.dnvn.ir/lunch?id=${book.id}`)}
>
<Image
source={{ uri: `https://dnvn.ir/api/v1/file/${book.fileId}` }}
resizeMode="contain"
style={[
tw("rounded-sm w-full"),
{
height: mobile ? (width - 32) / 1.5 : 200,
flex: 1,
},
]}
/>
<Text
style={[
{
fontFamily: "bold",
fontSize: fontSize.lg,
marginTop: 10,
color:
theme === "light" ? Colors.theme1.green79 : Colors.theme1.white,
},
]}
>
{book.title}
</Text>
</Pressable>
);
};
const mapStateToProps = (state) => ({
mobile: state.publicApi.mobile,
theme: state.publicApi.theme,
});
export default connect(mapStateToProps)(Book);

@ -0,0 +1,111 @@
import React, { useState, useEffect } from "react";
import {
SafeAreaView,
ScrollView,
StatusBar,
LayoutAnimation,
Platform,
Dimensions,
View,
} from "react-native";
import { connect } from "react-redux";
import { userProduct } from "../../redux/actions";
//components
import Navbar from "../../components/Navbar";
import Drawer from "../../components/Drawer";
import Book from "./components/Book";
import Empty from "../../components/Empty";
//style
import tw from "tailwind-rn";
const { height } = Dimensions.get("window");
const ios = Platform.OS === "ios";
function AR({ getArList, arList, mobile, theme }) {
const [position, setPosition] = useState("100%");
useEffect(() => {
getArList();
StatusBar.setBarStyle(
`${theme === "light" ? "dark" : "light"}-content`,
true
);
}, []);
useEffect(() => {
StatusBar.setBarStyle(
`${theme === "light" ? "dark" : "light"}-content`,
true
);
}, [theme]);
const setBoxPosition = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setPosition(position === "100%" ? "0%" : "100%");
};
return (
<SafeAreaView
style={{
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
position: "relative",
flex: 1,
}}
>
<Navbar
setBoxPosition={setBoxPosition}
headerOptions={{
logo: false,
menu: false,
hamburgerMenu: false,
title: "واقعیت افزوده",
bookmark: false,
qr: false,
back: true,
}}
/>
<Drawer setBoxPosition={setBoxPosition} position={position} />
{arList?.length ? (
<ScrollView
style={{
paddingHorizontal: 16,
height: height,
}}
contentContainerStyle={{ paddingBottom: 60 }}
>
<View
style={tw(
`flex justify-between flex-wrap ${
ios ? "flex-row-reverse" : "flex-row"
}`
)}
>
{arList?.map((book, index) => (
<Book book={book} key={index} />
))}
</View>
</ScrollView>
) : (
<Empty
text="هیچ موردی برای شما وجود ندارد."
buttonText={"رفتن به فروشگاه"}
buttonAction={() => navigation.push("Products")}
/>
)}
</SafeAreaView>
);
}
const mapStateToProps = (state) => ({
arList: state.userProduct.arList,
mobile: state.publicApi.mobile,
theme: state.publicApi.theme
});
const mapDispatchToProps = {
getArList: userProduct.arList,
};
export default connect(mapStateToProps, mapDispatchToProps)(AR);

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

@ -0,0 +1,618 @@
import {
View,
Text,
SafeAreaView,
ScrollView,
StyleSheet,
StatusBar,
Platform,
Dimensions,
Appearance,
KeyboardAvoidingView,
TextInput,
TouchableWithoutFeedback,
} from "react-native";
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { publicApi, user, userAddress } from "../../redux/actions";
import onInput from "../../utils/onInput";
import { useNavigation } from "@react-navigation/native";
import { asyncAwesomeAlert } from "../../utils/AsyncWrappers";
//components
import Navbar from "../../components/Navbar";
import CustomPressable from "../../components/Pressable";
import CustomTextInput from "../../components/CustomTextInput";
import Select from "../../components/Select";
import MapSelector from "../../components/MapSelector";
//style
import tw from "tailwind-rn";
import Colors from "../../constants/Colors";
import fontSize from "../../constants/fontSize";
//variables
const ios = Platform.OS === "ios";
const { height } = Dimensions.get("window");
const Address = ({
user,
route,
city,
province,
getCity,
getProvince,
provinces,
cities,
createAddress,
profileFields,
setProfileFields,
setProfile,
loading,
setPhase,
cityLoading,
mobile,
theme,
}) => {
const [addressFields, setAddressFields] = useState({});
const [mapAddress, setMapAddress] = useState(null);
const colorScheme = Appearance.getColorScheme();
const navigation = useNavigation();
const profilePage = React.useMemo(() => {
return route.params?.type === "profile";
});
useEffect(() => {
getProvince();
setProfileFields({
file: user?.picFileId,
picFileId: user?.picFileId,
docFileIds: user?.docFileIds,
cellphone: user?.cellphone,
firstName: user?.firstName,
lastName: user?.lastName,
password: user?.password,
username: user?.username,
address: user?.address,
email: user?.email,
birthDate: user?.birthDate,
gender: user?.gender,
status: user?.status,
nationalId: user?.nationalId,
phone: user?.phone,
schools: user?.schools,
zoneId: user?.zoneId,
schoolId: user?.schoolId,
postalCode: user?.postalCode,
gradeIds: user?.gradeIds,
provinceId: user?.provinceId,
cityId: user?.cityId,
});
}, []);
useEffect(() => {
StatusBar.setBarStyle(
`${theme === "light" ? "dark" : "light"}-content`,
true
);
}, [theme]);
useEffect(() => {
if (addressFields?.provinceId) {
getCity({
provinceId: provinces.filter(
(province) => province.name === addressFields?.provinceId
)[0].id,
});
}
}, [addressFields]);
const onChange = (name, value) => {
setAddressFields({ ...addressFields, [name]: value });
};
const submit = () => {
const {
firstName,
lastName,
cellphone,
phone,
address,
provinceId,
cityId,
postalCode,
} = addressFields;
if (!firstName) {
return asyncAwesomeAlert("خطا", "نام خود را وارد کنید.", {
showCancelButton: false,
confirmText: "باشه",
});
}
if (!lastName) {
return asyncAwesomeAlert("خطا", "نام خانوادگی خود را وارد کنید", {
showCancelButton: false,
confirmText: "باشه",
});
}
if (!cellphone) {
return asyncAwesomeAlert("خطا", "شماره موبایل خود را وارد کنید.", {
showCancelButton: false,
confirmText: "باشه",
});
} else {
if (cellphone.slice(0, 2) !== "09") {
return asyncAwesomeAlert(
"خطا",
"فرمت شماره موبایل وارد شده اشتباه است.",
{
showCancellphoneButton: false,
confirmText: "باشه",
}
);
}
if (cellphone.length !== 11) {
return asyncAwesomeAlert(
"خطا",
"شماره موبایل میبایست یازده رقم باشد.",
{
showCancelButton: false,
confirmText: "باشه",
}
);
}
}
if (!phone) {
return asyncAwesomeAlert("خطا", "شماره تلفن خود را وارد کنید.", {
showCancelButton: false,
confirmText: "باشه",
});
} else {
if (phone.slice(0, 1) !== "0") {
return asyncAwesomeAlert(
"خطا",
"فرمت شماره تلفن وارد شده اشتباه است.",
{
showCancelButton: false,
confirmText: "باشه",
}
);
}
if (phone.length !== 11) {
return asyncAwesomeAlert("خطا", "شماره تلفن میبایست یازده رقم باشد.", {
showCancelButton: false,
confirmText: "باشه",
});
}
}
if (!provinceId) {
return asyncAwesomeAlert("خطا", "نام استان خود را وارد کنید.", {
showCancelButton: false,
confirmText: "باشه",
});
}
if (!cityId) {
return asyncAwesomeAlert("خطا", "نام شهرستان خود را وارد کنید.", {
showCancelButton: false,
confirmText: "باشه",
});
}
if (!postalCode) {
return asyncAwesomeAlert("خطا", "کد پستی خود را وارد کنید.", {
showCancelButton: false,
confirmText: "باشه",
});
} else {
if (postalCode.length !== 10) {
return asyncAwesomeAlert("خطا", "کد ملی میبایست ده رقم باشد.", {
showCancelButton: false,
confirmText: "باشه",
});
}
}
if (!mapAddress) {
return asyncAwesomeAlert("خطا", "آدرس خود را از روی نقشه انتخاب کن", {
showCancelButton: false,
confirmText: "باشه",
});
}
createAddress({
firstName,
lastName,
cellphone,
phone,
address: mapAddress,
provinceId: provinces.filter(
(province) => province.name === provinceId
)[0].id,
cityId: cities.filter((city) => city.name === cityId)[0]?.id,
postalCode,
location: null,
});
navigation.goBack();
};
const submitProfile = () => {
const {
firstName,
lastName,
username,
password,
postalCode,
address,
email,
phone,
picFileId,
gender,
nationalId,
birthDate,
schools,
gradeIds,
status,
provinceId,
cityId,
docFileIds,
} = profileFields;
if (phone) {
if (phone.slice(0, 1) !== "0") {
return asyncAwesomeAlert(
"خطا",
"فرمت شماره تلفن وارد شده اشتباه است.",
{
showCancelButton: false,
confirmText: "باشه",
}
);
}
if (phone.length !== 11) {
return asyncAwesomeAlert("خطا", "شماره تلفن میبایست یازده رقم باشد.", {
showCancelButton: false,
confirmText: "باشه",
});
}
}
const data = {
firstName: firstName,
lastName: lastName,
username: username,
cellphone: user.cellphone,
password: password,
postalCode: postalCode,
address: address,
email: email,
phone: phone,
nationalId: nationalId,
picFileId: picFileId,
gender: gender,
birthDate: birthDate,
schools: schools,
gradeIds: gradeIds,
status: status,
provinceId: provinceId,
cityId: cityId,
docFileIds: docFileIds,
};
setProfile(data);
navigation.goBack();
};
const Header = ({ title, text }) => {
return (
<View style={tw(`flex ${mobile ? "mt-2" : "mt-8"}`)}>
<Text
style={{
fontFamily: "bold",
fontSize: mobile ? fontSize.lg : fontSize.xl2,
color:
theme === "light" ? Colors.theme1.gray20 : Colors.theme1.white,
textAlign: ios ? "right" : "auto",
}}
>
{title}
</Text>
<Text
style={{
fontFamily: "regular",
fontSize: mobile ? fontSize.sm : fontSize.base,
color:
theme === "light"
? Colors.theme1.gray20 + "aa"
: Colors.theme1.white + "aa",
textAlign: ios ? "right" : "auto",
}}
>
{text}
</Text>
</View>
);
};
console.log(mapAddress);
return (
<SafeAreaView
style={{
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
// position: "relative",
flex: 1,
}}
>
<Navbar
headerOptions={{
logo: false,
menu: profilePage ? false : false,
hamburgerMenu: false,
title: profilePage ? "اطلاعات کاربری" : "",
bookmark: profilePage ? false : false,
qr: false,
back: true,
}}
/>
<ScrollView style={tw("flex-1 px-4")}>
<KeyboardAvoidingView>
<TouchableWithoutFeedback>
<View style={tw("flex-1")}>
<Header
title="اطلاعات هویتی"
text="( لطفا نام و نام خانوادگی خود را به طور کامل وارد نمایید )"
/>
<CustomTextInput
label={profilePage ? "نام" : "نام تحویل گیرنده"}
placeholder=""
textAlign="right"
name="firstName"
maxlength="40"
value={
profilePage
? profileFields.firstName
: addressFields?.firstName
}
onChange={(name, value) =>
profilePage
? setProfileFields({ ...profileFields, firstName: value })
: onChange(name, value)
}
autoFocus={false}
regex={(val) => val}
/>
<CustomTextInput
label={
profilePage ? "نام خانوادگی" : "نام خانوادگی تحویل گیرنده"
}
placeholder=""
textAlign="right"
name="lastName"
maxlength="60"
value={
profilePage ? profileFields.lastName : addressFields?.lastName
}
onChange={(name, value) =>
profilePage
? setProfileFields({ ...profileFields, lastName: value })
: onChange(name, value)
}
autoFocus={false}
regex={(val) => val}
/>
{profilePage ? (
<CustomTextInput
keyboardType="numeric"
label="کد ملی"
placeholder=""
textAlign="left"
name="nationalId"
maxLength={10}
value={profileFields.nationalId}
onChange={(name, value) =>
setProfileFields({ ...profileFields, nationalId: value })
}
autoFocus={false}
regex={(text) => onInput.numberOnly(text)}
/>
) : null}
<View style={tw("mt-4")}></View>
<Header
title="شماره تماس"
text="( شماره موبایل و شماره تلفن ثابت خود را
به همراه پیش شماره وارد کنید )"
/>
<CustomTextInput
keyboardType="numeric"
label={
profilePage ? "شماره موبایل" : "شماره موبایل تحویل گیرنده"
}
placeholder=""
textAlign="left"
name="cellphone"
maxLength={11}
value={
profilePage
? profileFields.cellphone
: addressFields?.cellphone
}
onChange={(name, value) =>
profilePage
? setProfileFields({ ...profileFields, cellphone: value })
: onChange(name, value)
}
autoFocus={false}
regex={(text) => onInput.numberOnly(text)}
/>
<CustomTextInput
keyboardType="numeric"
label={profilePage ? "شماره تلفن" : "شماره تلفن تحویل گیرنده"}
placeholder=""
textAlign="left"
name="phone"
maxLength={11}
value={profilePage ? profileFields.phone : addressFields?.phone}
onChange={(name, value) =>
profilePage
? setProfileFields({ ...profileFields, phone: value })
: onChange(name, value)
}
autoFocus={false}
regex={(text) => onInput.numberOnly(text)}
/>
<View style={tw("mt-4")}></View>
<Header
title="آدرس"
text="( لطفا نام استان و شهرستان و آدرس
خود را با دقت تکمیل نمایید )"
/>
<View style={tw("w-full mt-4")}>
<Select
defaultValue={
profilePage
? provinces?.filter(
(province) => province.id === profileFields.provinceId
)[0]?.name || province[0]
: province[0]
}
onChange={(name, value) =>
value === "استان" ? {} : onChange(name, value)
}
options={province}
width={"100%"}
name="provinceId"
/>
</View>
<View style={tw("w-full mt-4")}>
<Select
defaultValue={
profilePage
? cities?.filter(
(city) => city.id === profileFields.cityId
)[0]?.name || city[0]
: city[0]
}
onChange={(name, value) =>
value === "شهرستان" ? {} : onChange(name, value)
}
options={city}
width={"100%"}
name="cityId"
/>
</View>
{!profilePage ? (
<TextInput
style={[
tw("w-full mt-4 py-4 px-2 rounded-md h-40"),
{
backgroundColor:
theme === "light" ? Colors.theme1.grayF9 : null,
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.white,
fontSize: fontSize.tiny,
textAlign: "right",
fontFamily: "light",
borderWidth: 1,
borderColor:
theme === "light"
? Colors.theme1.grayE3
: Colors.theme1.white + "55",
},
]}
value={mapAddress}
multiline={true}
textAlignVertical="top"
placeholder="آدرس مورد نظر ..."
onChangeText={(text) => setMapAddress(text)}
placeholderTextColor={
theme === "light"
? Colors.theme1.gray2077
: Colors.theme1.white + "aa"
}
/>
) : null}
<View style={tw("mb-4")}>
<CustomTextInput
keyboardType="numeric"
label="کد پستی"
placeholder=""
textAlign="left"
name="postalCode"
maxLength={10}
value={
profilePage
? profileFields.postalCode
: addressFields?.postalCode
}
onChange={(name, value) =>
profilePage
? setProfileFields({
...profileFields,
postalCode: value,
})
: onChange(name, value)
}
autoFocus={false}
regex={(text) => onInput.numberOnly(text)}
/>
</View>
<CustomPressable
title={
profilePage
? "ذخیره اطلاعات و بازگشت به صفحه قبل"
: "ثبت آدرس"
}
backgroundColor={Colors.theme1.greenCF}
color={"white"}
border={{ color: "#196EC0", width: 0 }}
width={"100%"}
onPress={() => (profilePage ? submitProfile() : submit())}
/>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
contentContainerStyle: {
paddingBottom: 0,
},
container: {
flexDirection: "column",
paddingVertical: 5,
paddingHorizontal: 16,
flex: 1,
},
});
const mapStateToProps = (state) => ({
provinces: state.publicApi.provinces,
province: state.publicApi.province,
cities: state.publicApi.cities,
city: state.publicApi.city,
loading: state.userAddress.loading,
cityLoading: state.publicApi.loading,
user: state.user.status,
profileFields: state.user.profileFields,
mobile: state.publicApi.mobile,
theme: state.publicApi.theme,
});
const mapDispatchToProps = {
getProvince: publicApi.getProvince,
getCity: publicApi.getCity,
createAddress: userAddress.add,
setProfileFields: user.setProfileFields,
setProfile: user.setProfile,
};
export default connect(mapStateToProps, mapDispatchToProps)(Address);

@ -0,0 +1,323 @@
import React, { useEffect } from "react";
import {
View,
Text,
FlatList,
Image,
SafeAreaView,
ScrollView,
StyleSheet,
Platform,
Dimensions,
StatusBar,
} from "react-native";
import { connect } from "react-redux";
import { blog, publicApi } from "../../redux/actions";
import { LinearGradient } from "expo-linear-gradient";
import HTMLView from "react-native-htmlview";
import moment from "jalali-moment";
//components
import Header from "../Blogs/layouts/Header";
import New from "../Blogs/layouts/New";
import Navbar from "../../components/Navbar";
//assets
import tw from "tailwind-rn";
import fontSize from "../../constants/fontSize";
import Colors from "../../constants/Colors";
//variables
const ios = Platform.OS === "ios";
const { width } = Dimensions.get("window");
//func
const renderNode = (node, index, siblings, parent, defaultRenderer) => {
if (node.name == "img") {
const a = node.attribs;
return (
<Image
style={{ width: 300, height: 300 }}
source={{ uri: node.attribs.src }}
/>
);
}
};
export const Blog = ({ getInfo, blog, getList, blogs, route, theme }) => {
useEffect(() => {
getInfo({ id: route.params.id });
if (blogs.length === 0) {
getList();
}
}, []);
useEffect(() => {
StatusBar.setBarStyle(
`${theme === "light" ? "dark" : "light"}-content`,
true
);
}, [theme]);
console.log(blog);
return (
<SafeAreaView
style={{
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
position: "relative",
}}
>
<Navbar
headerOptions={{
logo: false,
menu: false,
hamburgerMenu: false,
title: "",
bookmark: true,
qr: false,
back: true,
bookmarkItem: { contentId: blog?.id },
}}
/>
<ScrollView
contentContainerStyle={styles.contentContainerStyle}
style={[styles.container, tw("flex")]}
>
<View style={tw("flex px-4 pb-24")}>
<View
style={[
tw("w-full rounded-sm overflow-hidden relative"),
{ height: ((width - 32) / 4) * 2.8 },
]}
>
<Image
source={{ uri: `https:dnvn.ir/api/v1/file/${blog?.fileIds}` }}
resizeMode="contain"
style={tw("w-full h-full absolute left-0 top-0")}
/>
<LinearGradient
colors={["transparent", "rgba(0,0,0,0.9)"]}
start={{ x: 0.0, y: 0.0 }}
end={{ x: 0.0, y: 1.1 }}
style={tw(
"flex justify-end absolute top-0 left-0 z-10 w-full h-full pb-2 px-0"
)}
>
<View
style={tw(
"flex justify-end absolute top-0 left-0 z-10 w-full h-full pb-0 px-2"
)}
>
<View
style={tw(
"w-full flex flex-row-reverse items-center justify-between"
)}
>
<View style={tw("flex")}>
<View style={tw("flex py-2 justify-center")}>
<Text
style={{
fontFamily: "regular",
color: Colors.theme1.white,
fontSize: fontSize.tiny,
textAlign: ios ? "right" : "auto",
}}
>
{/* {"نوشته از:" + " " + "کامران ایزدی"} */}
</Text>
<Text
style={{
fontFamily: "regular",
color: Colors.theme1.white,
fontSize: fontSize.tiny,
textAlign: ios ? "right" : "auto",
}}
>
{"سردبیر بخش وبلاگ دانوین"}
</Text>
</View>
</View>
<View style="flex justify-center items-end">
{
blog.duration ? <Text
style={{
fontFamily: "regular",
color: Colors.theme1.white,
fontSize: fontSize.sm,
textAlign: ios ? "left" : "left",
}}
>
{"زمان مطالعه" + " " + blog.duration + " دقیقه"}
</Text> : null
}
<Text
style={{
fontFamily: "regular",
color: Colors.theme1.white,
fontSize: fontSize.sm,
textAlign: ios ? "left" : "left",
}}
>
{
moment(blog.createdAt).format('jYYYY/jMM/jDD')
}
</Text>
</View>
</View>
</View>
</LinearGradient>
</View>
<View
style={[tw("flex my-5"), { textAlign: "right", marginBottom: 50 }]}
>
<Text
style={{
fontFamily: "bold",
fontSize: fontSize.base,
textAlign: ios ? "right" : "auto",
marginBottom: 60,
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
}}
>
{blog?.title}
</Text>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<HTMLView
value={blog?.text}
renderNode={renderNode}
stylesheet={{
h1 : {
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
textAlign: "right",
fontFamily: "bold",
lineHeight: 25,
fontSize: fontSize.xl4,
marginVertical: -15,
paddingTop: 5,
},
h2 : {
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
textAlign: "right",
fontFamily: "bold",
lineHeight: 25,
fontSize: fontSize.xl,
marginVertical: -10,
},
h3 : {
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
textAlign: "right",
fontFamily: "bold",
lineHeight: 25,
fontSize: fontSize.lg,
marginVertical: -10,
},
p: {
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
textAlign: "right",
fontFamily: "light",
lineHeight: 25,
marginVertical: -20,
},
strong: {
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
textAlign: "right",
fontFamily: "bold",
lineHeight: 25,
},
ul: {
textAlign: "right",
marginVertical: -35,
},
li: {
color:
theme === "light"
? Colors.theme1.gray20
: Colors.theme1.grayF9,
textAlign: "right",
fontFamily: "light",
lineHeight: 25,
},
span : {
color : 'red'
}
}}
/>
</View>
</View>
<Header title={"پیشنهادی "} />
{blogs.length ? (
<FlatList
showsHorizontalScrollIndicator={false}
horizontal={true}
inverted={true}
style={[tw("flex flex-row mt-3 pb-3")]}
data={blogs.filter((blog) => blog.id !== route.params.id)}
renderItem={({ item }) => <New blog={item} />}
keyExtractor={(item, index) => {
return item.id;
}}
/>
) : null}
</View>
</ScrollView>
</SafeAreaView>
);
};
const mapStateToProps = (state) => ({
blog: state.blog.blog,
blogs: state.blog.list,
theme: state.publicApi.theme,
});
const mapDispatchToProps = {
getInfo: blog.info,
getList: blog.list,
setHeaderOptions: publicApi.setHeaderOptions,
};
const Tag = ({ tag }) => {
return;
};
export default connect(mapStateToProps, mapDispatchToProps)(Blog);
const styles = StyleSheet.create({
contentContainerStyle: {
paddingBottom: 40,
},
container: {
paddingVertical: 0,
paddingHorizontal: 0,
},
font: {
textAlign: "center",
fontFamily: "render",
},
});

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save