added rider application
This commit is contained in:
parent
054db872ef
commit
fa225eccd0
|
@ -0,0 +1,115 @@
|
|||
import { ApolloProvider } from '@apollo/react-hooks'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import * as Font from 'expo-font'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import * as SplashScreen from 'expo-splash-screen'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Platform, StatusBar } from 'react-native'
|
||||
import FlashMessage from 'react-native-flash-message'
|
||||
import i18n from './i18n'
|
||||
import setupApolloClient from './src/apollo/index'
|
||||
import { AuthContext } from './src/context/auth'
|
||||
import { ConfigurationProvider } from './src/context/configuration'
|
||||
import AppContainer from './src/routes/index'
|
||||
|
||||
export default function App() {
|
||||
const [fontLoaded, setFontLoaded] = useState(false)
|
||||
const [client, setClient] = useState(null)
|
||||
const [token, setToken] = useState(false)
|
||||
const [appIsReady, setAppIsReady] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
const token = await AsyncStorage.getItem('rider-token')
|
||||
if (token) setToken(token)
|
||||
setAppIsReady(true)
|
||||
})()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
try {
|
||||
await SplashScreen.preventAutoHideAsync()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
})()
|
||||
loadData()
|
||||
}, [])
|
||||
|
||||
const setTokenAsync = async token => {
|
||||
await AsyncStorage.setItem('rider-token', token)
|
||||
setToken(token)
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
try {
|
||||
await AsyncStorage.removeItem('rider-token')
|
||||
setToken(null)
|
||||
} catch (e) {
|
||||
console.log('Logout Error: ', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
await i18n.initAsync()
|
||||
await Font.loadAsync({
|
||||
MuseoSans300: require('./assets/font/MuseoSans/MuseoSans300.ttf'),
|
||||
MuseoSans500: require('./assets/font/MuseoSans/MuseoSans500.ttf'),
|
||||
MuseoSans700: require('./assets/font/MuseoSans/MuseoSans700.ttf'),
|
||||
icomoon: require('./assets/font/icomoon.ttf')
|
||||
})
|
||||
const client = await setupApolloClient()
|
||||
await permissionForPushNotificationsAsync()
|
||||
setClient(client)
|
||||
setFontLoaded(true)
|
||||
await SplashScreen.hideAsync()
|
||||
}
|
||||
|
||||
async function permissionForPushNotificationsAsync() {
|
||||
const { status: existingStatus } = await Notifications.getPermissionsAsync()
|
||||
let finalStatus = existingStatus
|
||||
// only ask if permissions have not already been determined, because
|
||||
// iOS won't necessarily prompt the user a second time.
|
||||
if (existingStatus !== 'granted') {
|
||||
// Android remote notification permissions are granted during the app
|
||||
// install, so this will only ask on iOS
|
||||
const { status } = await Notifications.requestPermissionsAsync()
|
||||
finalStatus = status
|
||||
}
|
||||
|
||||
// Stop here if the user did not grant permissions
|
||||
if (finalStatus !== 'granted') {
|
||||
return
|
||||
}
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
Notifications.setNotificationChannelAsync('default', {
|
||||
name: 'default',
|
||||
sound: true,
|
||||
priority: 'max',
|
||||
importance: Notifications.AndroidImportance.HIGH,
|
||||
vibrate: [0, 250, 250, 250]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (fontLoaded && client && appIsReady) {
|
||||
return (
|
||||
<ApolloProvider client={client}>
|
||||
<StatusBar
|
||||
translucent
|
||||
backgroundColor={'transparent'}
|
||||
barStyle="dark-content"
|
||||
/>
|
||||
<ConfigurationProvider>
|
||||
<AuthContext.Provider value={{ token, setTokenAsync, logout }}>
|
||||
<AppContainer />
|
||||
</AuthContext.Provider>
|
||||
</ConfigurationProvider>
|
||||
<FlashMessage duration={2000} position="center" />
|
||||
</ApolloProvider>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"expo": {
|
||||
"name": "Enatega Rider",
|
||||
"description": "Enatega is a starter kit food ordering app built in React Native using Expo for IOS and Android. It's made keeping good aesthetics in mind as well keeping the best coding practices in mind. Its fully customisable to easily help you in your next food delivery project. https://market.nativebase.io/view/react-native-food-delivery-backend-app",
|
||||
"version": "4.2.2",
|
||||
"slug": "food-delivery-rider",
|
||||
"privacy": "public",
|
||||
"androidStatusBar": {
|
||||
"backgroundColor": "#000"
|
||||
},
|
||||
"platforms": [
|
||||
"ios",
|
||||
"android"
|
||||
],
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "cover",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"updates": {
|
||||
"fallbackToCacheTimeout": 0
|
||||
},
|
||||
"assetBundlePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
"notification": {
|
||||
"iosDisplayInForeground": true,
|
||||
"color": "#d83765",
|
||||
"icon": "./assets/not-icon.png",
|
||||
"androidMode": "default",
|
||||
"androidCollapsedTitle": "Enatega Rider"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.enatega.driver",
|
||||
"config": {
|
||||
"googleMapsApiKey": "AIzaSyD0vSz1qjsn_RSPBB9HRD1Eqztm7DyuKw8"
|
||||
},
|
||||
"infoPlist": {
|
||||
"NSLocationWhenInUseUsageDescription": "Allow $(PRODUCT_NAME) to use location to determine the delivery address for your orders.",
|
||||
"NSLocationAlwaysUsageDescription": "For a better experience, while using our Service, we may require you to provide us Location Permissions",
|
||||
"UIBackgroundModes": [
|
||||
"location",
|
||||
"fetch"
|
||||
]
|
||||
}
|
||||
},
|
||||
"android": {
|
||||
"versionCode": 13,
|
||||
"googleServicesFile": "./google-services.json",
|
||||
"useNextNotificationsApi": true,
|
||||
"permissions":[
|
||||
"ACCESS_COARSE_LOCATION",
|
||||
"ACCESS_FINE_LOCATION"
|
||||
],
|
||||
"config": {
|
||||
"googleMaps": {
|
||||
"apiKey": "AIzaSyBt9S6e7ig5EkNiSXw3sCyX7kgo1gzPxl4"
|
||||
}
|
||||
},
|
||||
"package": "com.enatega.rider"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,48 @@
|
|||
import * as React from 'react'
|
||||
import Svg, { G, Path, Text, TSpan } from 'react-native-svg'
|
||||
/* SVGR has dropped some elements not supported by react-native-svg: style */
|
||||
|
||||
function Logo(props) {
|
||||
return (
|
||||
<Svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={132}
|
||||
height={78.635}
|
||||
viewBox="0 0 132 78.635"
|
||||
{...props}>
|
||||
<G id="prefix__Group_371" transform="translate(-122 -367)">
|
||||
<Path
|
||||
id="prefix__Path_27625"
|
||||
fill="#febb2c"
|
||||
d="M10 0h122l-10 43H0z"
|
||||
transform="translate(122 402.635)"
|
||||
/>
|
||||
<Text
|
||||
id="prefix__enatega"
|
||||
fill="#0b0b0b"
|
||||
fontSize={32}
|
||||
fontStyle="italic"
|
||||
fontWeight={700}
|
||||
className="prefix__cls-2"
|
||||
transform="translate(188 394)">
|
||||
<TSpan x={-62.4} y={0}>
|
||||
{'enatega'}
|
||||
</TSpan>
|
||||
</Text>
|
||||
<Text
|
||||
id="prefix__rider"
|
||||
fill="#0b0b0b"
|
||||
fontSize={32}
|
||||
fontStyle="italic"
|
||||
fontWeight={700}
|
||||
transform="translate(188 435)">
|
||||
<TSpan x={-36.752} y={0}>
|
||||
{'rider'}
|
||||
</TSpan>
|
||||
</Text>
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Logo)
|
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
After Width: | Height: | Size: 696 B |
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
|
@ -0,0 +1,7 @@
|
|||
module.exports = function (api) {
|
||||
api.cache(true)
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
plugins: ['react-native-reanimated/plugin']
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*****************************
|
||||
* environment.js
|
||||
* path: '/environment.js' (root of your project)
|
||||
******************************/
|
||||
|
||||
import Constants from 'expo-constants'
|
||||
|
||||
const ENV = {
|
||||
development: {
|
||||
GRAPHQL_URL: 'http://192.168.100.90:8000/graphql',
|
||||
WS_GRAPHQL_URL: 'ws://192.168.100.90:8000/graphql'
|
||||
},
|
||||
staging: {
|
||||
GRAPHQL_URL: 'https://staging-enatega-single-api.herokuapp.com/graphql',
|
||||
WS_GRAPHQL_URL: 'wss://staging-enatega-single-api.herokuapp.com/graphql'
|
||||
},
|
||||
production: {
|
||||
GRAPHQL_URL: 'https://prod-enatega-single-api.herokuapp.com/graphql',
|
||||
WS_GRAPHQL_URL: 'wss://prod-enatega-single-api.herokuapp.com/graphql'
|
||||
}
|
||||
}
|
||||
|
||||
const getEnvVars = (env = Constants.manifest.releaseChannel) => {
|
||||
// What is __DEV__ ?
|
||||
// This variable is set to true when react-native is running in Dev mode.
|
||||
// __DEV__ is true when run locally, but false when published.
|
||||
// eslint-disable-next-line no-undef
|
||||
if (__DEV__) {
|
||||
return ENV.development
|
||||
} else if (env === 'production') {
|
||||
return ENV.production
|
||||
} else {
|
||||
return ENV.production
|
||||
}
|
||||
}
|
||||
|
||||
export default getEnvVars
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "94983896797",
|
||||
"firebase_url": "https://enatega-production.firebaseio.com",
|
||||
"project_id": "enatega-production",
|
||||
"storage_bucket": "enatega-production.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:94983896797:android:ec37b623e2579690112534",
|
||||
"android_client_info": {
|
||||
"package_name": "com.enatega.rider"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "94983896797-9e36v3edasjt9t9r5q9uvkth700nn0nn.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyBt9S6e7ig5EkNiSXw3sCyX7kgo1gzPxl4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "94983896797-9e36v3edasjt9t9r5q9uvkth700nn0nn.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "94983896797-m8ri1dftjkik9etuid39top8g2c3ode3.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.enatega.driver"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:94983896797:android:5b28fe2925a51512112534",
|
||||
"android_client_info": {
|
||||
"package_name": "com.enatega.vendor"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "94983896797-9e36v3edasjt9t9r5q9uvkth700nn0nn.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyBt9S6e7ig5EkNiSXw3sCyX7kgo1gzPxl4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "94983896797-9e36v3edasjt9t9r5q9uvkth700nn0nn.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "94983896797-m8ri1dftjkik9etuid39top8g2c3ode3.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.enatega.driver"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import * as Localization from 'expo-localization'
|
||||
import { AsyncStorage, Platform } from 'react-native'
|
||||
import i18n from 'i18n-js'
|
||||
import { en } from './languages/en'
|
||||
import { fr } from './languages/fr'
|
||||
import { km } from './languages/km'
|
||||
import { zh } from './languages/zh'
|
||||
import { de } from './languages/de'
|
||||
|
||||
i18n.initAsync = async () => {
|
||||
i18n.fallbacks = true
|
||||
i18n.translations = { fr, en, km, zh, de }
|
||||
// i18n.locale = 'km'
|
||||
if (Platform.OS === 'android') {
|
||||
const lang = await AsyncStorage.getItem('enatega-language')
|
||||
i18n.locale = lang || 'en'
|
||||
} else {
|
||||
i18n.locale = Localization.locale
|
||||
}
|
||||
}
|
||||
|
||||
export default i18n
|
|
@ -0,0 +1,115 @@
|
|||
export const de = {
|
||||
title0: 'Gewählte Sprache',
|
||||
subtitle0: 'English',
|
||||
description0:
|
||||
'Wählen Sie eine Sprache Ihrer Wahl, um den Inhalt der App in die gewünschte Sprache zu ändern.',
|
||||
title1: 'Lecker',
|
||||
subtitle1: 'Frühstück',
|
||||
description1:
|
||||
'Frühstück ist alles. Der Anfang, das Erste. Es ist der Mundvoll, der die Verpflichtung zu einem neuen Tag, einem fortwährenden Leben ist.',
|
||||
title2: 'Erfrischend',
|
||||
subtitle2: 'Getränke',
|
||||
description2:
|
||||
'Wahre Stille ist der Rest des Geistes und ist für den Geist das, was Schlaf für den Körper ist, Nahrung und Erfrischung.',
|
||||
title3: 'Köstlich',
|
||||
subtitle3: 'Eis',
|
||||
description3:
|
||||
'Das Alter mindert nicht die extreme Enttäuschung darüber, dass eine Kugel Eis vom Kegel fällt',
|
||||
getStarted: 'Loslegen!',
|
||||
welcome: 'Willkommen',
|
||||
loginBtn: 'Anmeldung',
|
||||
registerBtn: 'Registrieren',
|
||||
name: 'Name',
|
||||
phone: 'Telefon',
|
||||
email: 'Email',
|
||||
emailphone: 'E-Mail oder Telefon',
|
||||
username: 'Nutzername',
|
||||
password: 'Passwort',
|
||||
deliveryAddress: 'Lieferadresse',
|
||||
registerText: 'Oder registriere dich bei',
|
||||
forgotPassword: 'Passwort vergessen?',
|
||||
loginText: 'Oder Einloggen mit',
|
||||
deliveryLocation:
|
||||
'Stellen Sie Ihren Lieferort so ein, dass wir Ihnen einen unendlichen Geschmack köstlichen Essens zusenden können.',
|
||||
locationBtn: 'Standort einschalten',
|
||||
locationPermissionDenied:
|
||||
'Die Berechtigung zum Zugriff auf den Speicherort wurde verweigert',
|
||||
locationOff: 'Ort einschalten und erneut versuchen',
|
||||
titleLanguage: 'Sprache ändern',
|
||||
titleMenu: 'Speisekarte',
|
||||
titleOrders: 'meine Bestellungen',
|
||||
titleNotifications: 'Benachrichtigungen',
|
||||
titleReviews: 'Bewertungen',
|
||||
titleSettings: 'die Einstellungen',
|
||||
titleHelp: 'Hilfe',
|
||||
titleLogout: 'Ausloggen',
|
||||
titleCart: 'Mein Warenkorb',
|
||||
titlePayment: 'Zahlung',
|
||||
orderId: 'Auftragsnummer',
|
||||
totalOrderAmount: 'Gesamtbestellmenge',
|
||||
reOrder: 'Nachbestellen',
|
||||
unReadNotifications: 'Keine ungelesenen Benachrichtigungen',
|
||||
upload: 'Hochladen',
|
||||
saveBtn: 'sparen',
|
||||
emailUs: 'Mailen Sie uns an',
|
||||
question1: 'Wo finden wir das Essen?',
|
||||
question2: 'Wie treten wir in Kontakt?',
|
||||
question3: 'Wie kann ich den Zusteller bezahlen?',
|
||||
question4: 'Ist der Dienst in meiner Stadt verfügbar?',
|
||||
answer1:
|
||||
'Sie finden das Essen in einem Geschäft in Ihrer Nähe, ohne den Kundenservice zu belasten. Unsere Gebühren sind im Vergleich zu anderen extrem niedrig.',
|
||||
answer2:
|
||||
'Sie können uns über unsere E-Mail, Telefonnummer oder unsere Website kontaktieren.',
|
||||
answer3:
|
||||
'Sie können den Zusteller persönlich bezahlen oder auch online mit Kredit- oder Debitkarte bezahlen.',
|
||||
answer4:
|
||||
'Derzeit ist dieser Service in den Städten Islamabad und Karachi verfügbar. Sie können uns kontaktieren, um diesen Service in Ihrer Stadt in Anspruch zu nehmen.',
|
||||
add: 'HINZUFÜGEN',
|
||||
quantity: 'Menge',
|
||||
size: 'Größe',
|
||||
addToCart: 'in den Warenkorb legen',
|
||||
orderNow: 'Jetzt bestellen',
|
||||
addToCartMessage: 'Zum Warenkorb hinzugefügt',
|
||||
emptyCart: 'Keine Artikel im Warenkorb',
|
||||
itemTotal: 'Artikel Gesamt',
|
||||
delvieryCharges: 'Versandkosten',
|
||||
total: 'Gesamt',
|
||||
contactInfo: 'Kontaktinformation',
|
||||
deliveryAddressmessage: 'Lieferadresse einstellen',
|
||||
proceedCheckout: 'Zur Kasse',
|
||||
paymentText: 'Wie möchten Sie bezahlen?',
|
||||
checkout: 'Auschecken',
|
||||
header_title1: 'Kreditkarte Debitkarte',
|
||||
header_subscript1: 'Bezahlen Sie mit Kredit- oder Debitkarte',
|
||||
header_title2: 'Paypal',
|
||||
header_subscipt2: 'Zahlen Sie online mit Paypal',
|
||||
header_title3: 'Nachnahme',
|
||||
header_subscript3: 'Zahlen Sie, wenn Sie den Artikel erhalten',
|
||||
thankYou: 'Danke dir!',
|
||||
orderConfirmed: 'Ihre Bestellung wird bestätigt',
|
||||
orderAmount: 'Ihre Bestellmenge',
|
||||
orderDetail: 'Bestelldetails',
|
||||
paymentMethod: 'Zahlungsmethode',
|
||||
trackOrder: 'Versandverfolgung',
|
||||
backToMenu: 'Zurück zum Menü',
|
||||
foodItem: 'Essensgegenstand',
|
||||
deliveredTo: 'Geliefert an',
|
||||
writeAReview: 'Eine Rezension schreiben',
|
||||
orderReceived: 'Bestellung erhalten',
|
||||
cancelled: 'Abgebrochen',
|
||||
foodPreparing: 'Essen wird zubereitet',
|
||||
delivered: 'Geliefert',
|
||||
rateAndReview: 'Bewerten und bewerten',
|
||||
reviewPlaceholder: 'Detaillierte Bewertungen erhalten mehr Sichtbarkeit ...',
|
||||
submit: 'einreichen',
|
||||
noWorriesText: 'Keine Sorge, lassen Sie sich von uns helfen!',
|
||||
yourEmail: 'Deine E-Mail',
|
||||
send: 'Senden',
|
||||
apply: 'Sich bewerben',
|
||||
checkEmail:
|
||||
'Überprüfen Sie Ihre E-Mail-Adresse auf den Link zum Zurücksetzen des Kennworts',
|
||||
languageText: 'Bitte wählen Sie Ihre gewünschte Sprache',
|
||||
countryCodePickerTranslation: 'deu',
|
||||
countryCodeSelect: 'Ländercode auswählen',
|
||||
paymentNotSupported: 'Diese Zahlungsmethode unterstützt diese Währung nicht'
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
export const en = {
|
||||
title0: 'Selected Language',
|
||||
subtitle0: 'English',
|
||||
description0:
|
||||
'Select any language of your choice to change the content of the app to your required language.',
|
||||
title1: 'Tasty',
|
||||
subtitle1: 'BreakFast',
|
||||
description1:
|
||||
'Breakfast is everything. The beginning, the first thing. It is the mouthful that is the commitment to a new day, a continuing life.',
|
||||
title2: 'Refreshing',
|
||||
subtitle2: 'Drinks',
|
||||
description2:
|
||||
'True silence is the rest of the mind, and is to the spirit what sleep is to the body, nourishment and refreshment.',
|
||||
title3: 'Delicous',
|
||||
subtitle3: 'Icecream',
|
||||
description3:
|
||||
'Age does not diminish the extreme disappointment of having a scoop of ice cream fall from the cone',
|
||||
getStarted: 'Get Started!',
|
||||
welcome: 'Welcome',
|
||||
loginBtn: 'Login',
|
||||
registerBtn: 'Register',
|
||||
name: 'Name',
|
||||
phone: 'Phone',
|
||||
email: 'Email',
|
||||
emailphone: 'Email or Phone',
|
||||
username: 'Username',
|
||||
password: 'Password',
|
||||
deliveryAddress: 'Delivery Address',
|
||||
registerText: 'Or Register With',
|
||||
forgotPassword: 'Forgot Password?',
|
||||
loginText: 'Or Login With',
|
||||
deliveryLocation:
|
||||
'Turn on location so we could send you endless taste of delicious food.',
|
||||
locationBtn: 'Turn on Location',
|
||||
locationPermissionDenied: 'Permission to access location was denied',
|
||||
cameraRollPermissionDenied: 'Permission to access Camera Roll was denied',
|
||||
locationOff: 'Turn on location and try again',
|
||||
titleLanguage: 'Change Language',
|
||||
titleMenu: 'Menu',
|
||||
titleOrders: 'My Orders',
|
||||
NewOrders: 'New Orders',
|
||||
titleNotifications: 'Notifications',
|
||||
titleReviews: 'Reviews',
|
||||
titleSettings: 'Settings',
|
||||
titleHelp: 'Help',
|
||||
titleLogout: 'Logout',
|
||||
titleCart: 'My Cart',
|
||||
titlePayment: 'Payment',
|
||||
orderId: 'Order ID',
|
||||
totalOrderAmount: 'Total Order Amount',
|
||||
reOrder: 'Reorder',
|
||||
unReadNotifications: 'No unread notifications',
|
||||
upload: 'Upload',
|
||||
saveBtn: 'Save',
|
||||
emailUs: 'Email us at',
|
||||
question1: 'Where do we find the food?',
|
||||
question2: 'How do we contact?',
|
||||
question3: 'How can I pay the delivery person?',
|
||||
question4: 'Is the service available in my city?',
|
||||
answer1:
|
||||
'You can find the food at your nearest store without paying anything to customer service.Our charges are extremely low as compared to others.',
|
||||
answer2: 'You can contact us through our email, phone number or our website.',
|
||||
answer3:
|
||||
'You can pay the delivery person in person or pay online as well through credit or debit card.',
|
||||
answer4:
|
||||
'Currently this service is available in cities Islamabad and Karachi you can contact us to avail this service in your city.',
|
||||
add: 'ADD',
|
||||
quantity: 'Quantity',
|
||||
size: 'Size',
|
||||
addToCart: 'Add to Cart',
|
||||
orderNow: 'Order Now',
|
||||
addToCartMessage: 'Added to cart',
|
||||
emptyCart: 'No items in cart',
|
||||
itemTotal: 'Item Total',
|
||||
delvieryCharges: 'Delivery Charges',
|
||||
total: 'Total',
|
||||
contactInfo: 'Contact Info',
|
||||
deliveryAddressmessage: 'Set delivery address',
|
||||
proceedCheckout: 'Proceed to Checkout',
|
||||
paymentText: 'How do you wish to pay?',
|
||||
checkout: 'Checkout',
|
||||
header_title1: 'Credit Card/Debit Card',
|
||||
header_subscript1: 'Pay with Credit or Debit Card',
|
||||
header_title2: 'PayPal',
|
||||
header_subscript2: 'Pay online with PayPal',
|
||||
header_title3: 'Cash on delivery',
|
||||
header_subscript3: 'Pay when you recieve the item',
|
||||
thankYou: 'Thank You!',
|
||||
orderConfirmed: 'Your Order is confirmed',
|
||||
orderAmount: 'Your Order Amount',
|
||||
orderDetail: 'Order Detail',
|
||||
paymentMethod: 'Payment Method',
|
||||
trackOrder: 'Track Order',
|
||||
backToMenu: 'Back To Menu',
|
||||
foodItem: 'Food item',
|
||||
deliveredTo: 'Delivered to',
|
||||
writeAReview: 'Write a Review',
|
||||
orderReceived: 'Order Received',
|
||||
cancelled: 'Cancelled',
|
||||
foodPreparing: 'Food is being prepared',
|
||||
delivered: 'Delivered',
|
||||
rateAndReview: 'Rate and Review',
|
||||
reviewPlaceholder: 'More detailed reviews get more visibility...',
|
||||
submit: 'Submit',
|
||||
noWorriesText: 'No worries, let us help you out!',
|
||||
yourEmail: 'Your Email',
|
||||
send: 'Send',
|
||||
apply: 'Apply',
|
||||
checkEmail: 'Check your email for reset password link',
|
||||
languageText: 'Please select your required language',
|
||||
countryCodePickerTranslation: 'eng',
|
||||
countryCodeSelect: 'Select Country Code',
|
||||
paymentNotSupported: 'This payment method does not support this Currency',
|
||||
Orders: 'Orders',
|
||||
deliveryTime: 'Delivery Time',
|
||||
myOrders: 'My Orders',
|
||||
newOrders: 'New Orders',
|
||||
titleChat: 'Chat'
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
export const fr = {
|
||||
title0: 'Langue sélectionnée',
|
||||
subtitle0: 'English',
|
||||
description0:
|
||||
"Sélectionnez la langue de votre choix pour modifier le contenu de l'application dans la langue de votre choix.",
|
||||
title1: 'Savoureux',
|
||||
subtitle1: 'Petit déjeuner',
|
||||
description1:
|
||||
"Le petit déjeuner est tout. Le début, la première chose. C'est la bouchée qui est l'engagement pour un nouveau jour, une vie continue.",
|
||||
title2: 'Rafraîchissant',
|
||||
subtitle2: 'Boissons',
|
||||
description2:
|
||||
"Le vrai silence est le reste de l'esprit, et à l'esprit ce que le sommeil est pour le corps, nourriture et rafraîchissement.",
|
||||
title3: 'Délicieux',
|
||||
subtitle3: 'Crème glacée',
|
||||
description3:
|
||||
"L'âge ne diminue en rien l'extrême déception d'avoir une boule de glace tombée du cône.",
|
||||
getStarted: 'Commencer!',
|
||||
welcome: 'Bienvenue',
|
||||
loginBtn: "S'identifier",
|
||||
registerBtn: 'registre',
|
||||
name: 'prénom',
|
||||
phone: 'Téléphone',
|
||||
email: 'Email',
|
||||
emailphone: 'Email ou téléphone',
|
||||
username: "Nom d'utilisateur",
|
||||
password: 'Mot de passe',
|
||||
deliveryAddress: 'Adresse de livraison',
|
||||
registerText: "Ou s'inscrire avec",
|
||||
forgotPassword: 'Mot de passe oublié?',
|
||||
loginText: 'Ou connectez-vous avec',
|
||||
deliveryLocation:
|
||||
'Définissez votre lieu de livraison afin que nous puissions vous envoyer un goût infini de plats délicieux.',
|
||||
locationBtn: "Activer l'emplacement",
|
||||
locationPermissionDenied:
|
||||
"La permission d'accéder à l'emplacement a été refusée",
|
||||
locationOff: "Activer l'emplacement et réessayer",
|
||||
titleLanguage: 'Changer de langue',
|
||||
titleMenu: 'Menu',
|
||||
titleOrders: 'Mes commandes',
|
||||
titleNotifications: 'Les notifications',
|
||||
titleReviews: 'Avis',
|
||||
titleSettings: 'Réglages',
|
||||
titleHelp: 'Aidez-moi',
|
||||
titleLogout: 'Connectez - Out',
|
||||
titleCart: 'Mon panier',
|
||||
titlePayment: 'Paiement',
|
||||
orderId: 'numéro de commande',
|
||||
totalOrderAmount: 'Total de la commande',
|
||||
reOrder: 'Réorganiser',
|
||||
unReadNotifications: 'Pas de notifications non lues',
|
||||
upload: 'Télécharger',
|
||||
saveBtn: 'sauvegarder',
|
||||
emailUs: 'écrivez-nous à',
|
||||
question1: 'Où trouvons-nous la nourriture?',
|
||||
question2: 'Comment pouvons-nous contacter?',
|
||||
question3: 'Comment puis-je payer le livreur?',
|
||||
question4: 'Le service est-il disponible dans ma ville?',
|
||||
answer1:
|
||||
'Vous pouvez trouver la nourriture dans le magasin le plus proche sans rien payer au service client. Nos frais sont extrêmement bas comparés aux autres.',
|
||||
answer2:
|
||||
'Vous pouvez nous contacter via notre email, numéro de téléphone ou notre site web.',
|
||||
answer3:
|
||||
'Vous pouvez payer le livreur en personne ou en ligne, par carte de crédit ou de débit.',
|
||||
answer4:
|
||||
"Actuellement, ce service est disponible dans les villes d'Islamabad et de Karachi. Vous pouvez nous contacter pour bénéficier de ce service dans votre ville.",
|
||||
add: 'AJOUTER',
|
||||
quantity: 'Quantité',
|
||||
size: 'Taille',
|
||||
addToCart: 'Ajouter au panier',
|
||||
orderNow: 'Commandez maintenant',
|
||||
addToCartMessage: 'Ajouté au panier',
|
||||
emptyCart: 'Aucun article dans le panier',
|
||||
itemTotal: 'Objet total',
|
||||
delvieryCharges: 'Frais de livraison',
|
||||
total: 'Total',
|
||||
contactInfo: 'Informations de contact',
|
||||
deliveryAddressmessage: "Définir l'adresse de livraison",
|
||||
proceedCheckout: 'Passer à la caisse',
|
||||
paymentText: 'Comment souhaitez-vous payer?',
|
||||
checkout: 'Check-out',
|
||||
header_title1: 'Carte de crédit carte de débit',
|
||||
header_subscript1: 'Payer avec une carte de crédit ou de débit',
|
||||
header_title2: 'PayPal',
|
||||
header_subscript2: 'Payez en ligne avec PayPal',
|
||||
header_title3: 'Paiement à la livraison',
|
||||
header_subscript3: "Payer quand vous recevez l'article",
|
||||
thankYou: 'Je vous remercie!',
|
||||
orderConfirmed: 'Votre commande est confirmée',
|
||||
orderAmount: 'Le montant de votre commande',
|
||||
orderDetail: 'Détails de la commande',
|
||||
paymentMethod: 'Mode de paiement',
|
||||
trackOrder: 'Suivi de commande',
|
||||
backToMenu: 'Suivi de commande',
|
||||
foodItem: 'Produit alimentaire',
|
||||
deliveredTo: 'livré à',
|
||||
writeAReview: 'Écrire une critique',
|
||||
orderReceived: 'Ordre reçu',
|
||||
cancelled: 'Annulé',
|
||||
foodPreparing: 'La nourriture est en cours de préparation',
|
||||
delivered: 'Livré',
|
||||
rateAndReview: 'Notez et évaluez',
|
||||
reviewPlaceholder: 'Des revues plus détaillées ont plus de visibilité ...',
|
||||
submit: 'Soumettre',
|
||||
noWorriesText: 'Pas de soucis, laissez-nous vous aider!',
|
||||
yourEmail: 'Votre email',
|
||||
send: 'Envoyer',
|
||||
apply: 'Appliquer',
|
||||
checkEmail:
|
||||
'Vérifiez votre email pour le lien de réinitialisation du mot de passe',
|
||||
languageText: "S'il vous plaît sélectionnez votre langue requise",
|
||||
countryCodePickerTranslation: 'fra',
|
||||
countryCodeSelect: 'Sélectionnez le code pays',
|
||||
paymentNotSupported: 'Ce mode de paiement ne prend pas en charge cette devise'
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
export const km = {
|
||||
title0: 'ភាសាដែលបានជ្រើស',
|
||||
subtitle0: 'English',
|
||||
description0:
|
||||
'ជ្រើសរើសភាសាណាមួយនៃជម្រើសរបស់អ្នកដើម្បីប្តូរមាតិកានៃកម្មវិធីទៅភាសាដែលអ្នកត្រូវការ។',
|
||||
title1: 'ហ៊ាន',
|
||||
subtitle1: 'អាហារពេលព្រឹក',
|
||||
description1:
|
||||
'អាហារពេលព្រឹកគឺជាអ្វីគ្រប់យ៉ាង។ ការចាប់ផ្តើមរឿងដំបូង។ វាគឺជាមាត់ដែលជាការប្តេជ្ញាចិត្តចំពោះថ្ងៃថ្មីនិងជីវិតដែលនៅតែបន្ត។',
|
||||
title2: 'ធ្វើឱ្យស្រស់',
|
||||
subtitle2: 'ភេសជ្ជៈ',
|
||||
description2:
|
||||
'ភាពស្ងៀមស្ងាត់ពិតគឺជាគំនិតដែលនៅសល់ហើយជាវិញ្ញាណដែលជាការដេកលក់ដល់រាងកាយការថែទាំនិងការសំរាក។',
|
||||
title3: 'ឆ្ងាញ់',
|
||||
subtitle3: 'ការ៉េម',
|
||||
description3:
|
||||
'អាយុមិនបន្ថយនូវការខកចិត្តយ៉ាងខ្លាំងនៃការធ្លាក់ចុះនៃការ៉េមពីកោណទេ',
|
||||
getStarted: 'ចាប់ផ្ដើម!',
|
||||
welcome: 'សូមស្វាគមន៏ទៅ',
|
||||
loginBtn: 'ចូល',
|
||||
registerBtn: 'ចុះឈ្មោះ',
|
||||
name: 'ឈ្មោះ',
|
||||
phone: 'ទូរស័ព្ទ',
|
||||
email: 'អ៊ីមែល',
|
||||
emailphone: 'អីុម៉ែលឬទូរស័ព្ទ',
|
||||
username: 'ឈ្មោះអ្នកប្រើប្រាស់',
|
||||
password: 'ពាក្យសម្ងាត់',
|
||||
deliveryAddress: 'អាស័យដ្ឋានសំរាប់ការដឹកជញ្ជូន',
|
||||
registerText: 'ឬចុះឈ្មោះជាមួយ',
|
||||
forgotPassword: 'ភ្លេចលេខសំងាត់?',
|
||||
loginText: 'ឬចូលជាមួយ',
|
||||
deliveryLocation:
|
||||
'កំណត់ទីតាំងដឹកជញ្ជូនរបស់អ្នកដូច្នេះយើងអាចផ្ញើឱ្យអ្នកនូវរសជាតិអាហារឆ្ងាញ់គ្មានទីបញ្ចប់។',
|
||||
locationBtn: 'បើកទីតាំង',
|
||||
locationPermissionDenied: 'ការអនុញ្ញាតចូលទៅកាន់ទីតាំងត្រូវបានបដិសេធ',
|
||||
locationOff: 'បើកទីតាំងហើយព្យាយាមម្តងទៀត',
|
||||
titleLanguage: 'ប្ដូរភាសា',
|
||||
titleMenu: 'ម៉ឺនុយ',
|
||||
titleOrders: 'ការបញ្ជាទិញរបស់ខ្ញុំ',
|
||||
titleNotifications: 'ការជូនដំណឹង',
|
||||
titleReviews: 'ពិនិត្យ',
|
||||
titleSettings: 'ការកំណត់',
|
||||
titleHelp: 'ជំនួយ',
|
||||
titleLogout: 'ចាកចេញ',
|
||||
titleCart: 'កន្ត្រករបស់ខ្ញុំ',
|
||||
titlePayment: 'ការទូទាត់',
|
||||
orderId: 'លេខសម្គាល់លំដាប់',
|
||||
totalOrderAmount: 'បរិមាណសរុប',
|
||||
reOrder: 'តម្រៀបឡើងវិញ',
|
||||
unReadNotifications: 'គ្មានការជូនដំណឹងមិនទាន់អាន',
|
||||
upload: 'ផ្ទុកឡើង',
|
||||
saveBtn: 'រក្សាទុក',
|
||||
emailUs: 'អ៊ីម៉ែលមកយើងនៅ',
|
||||
question1: 'តើយើងរកម្ហូបបាននៅឯណា?',
|
||||
question2: 'តើយើងទាក់ទងយ៉ាងដូចម្តេច?',
|
||||
question3: 'តើខ្ញុំអាចបង់ប្រាក់ដល់មនុស្សដែលត្រូវដឹកជញ្ជូន?',
|
||||
question4: 'តើសេវាកម្មនេះមាននៅក្នុងទីក្រុងរបស់ខ្ញុំដែរឬទេ?',
|
||||
answer1:
|
||||
'អ្នកអាចរកឃើញម្ហូបអាហារនៅហាងដែលនៅជិតបំផុតរបស់អ្នកដោយមិនបង់អ្វីឱ្យសេវាកម្មបំរើអតិថិជន។ ការចោទប្រកាន់របស់យើងមានកម្រិតទាបខ្លាំងបើប្រៀបធៀបទៅនឹងអ្នកដទៃ។',
|
||||
answer2: 'អ្នកអាចទាក់ទងយើងតាមរយៈអ៊ីម៉ែលលេខទូរស័ព្ទឬវេបសាយរបស់យើង។',
|
||||
answer3:
|
||||
'អ្នកអាចបង់ប្រាក់ទៅកាន់បុគ្គលដឹកជញ្ជូនដោយផ្ទាល់ឬបង់ប្រាក់តាមរយៈអ៊ីនធឺណេតតាមរយៈប័ណ្ណឥណទានឬឥណពន្ធផងដែរ។',
|
||||
answer4:
|
||||
'បច្ចុប្បន្នសេវាកម្មនេះអាចរកបាននៅក្នុងទីក្រុងអ៊ីស្លាម៉ាបាតនិងការ៉ាជីដែលអ្នកអាចទាក់ទងមកយើងដើម្បីទទួលបានសេវាកម្មនេះនៅក្នុងទីក្រុងរបស់អ្នក។',
|
||||
add: 'បន្ថែម',
|
||||
quantity: 'បរិមាណ',
|
||||
size: 'ទំហំ',
|
||||
addToCart: 'បន្ថែមទៅកន្ត្រក',
|
||||
orderNow: 'បញ្ជាទិញឥឡូវ',
|
||||
addToCartMessage: 'បានបន្ថែមទៅរទេះ',
|
||||
emptyCart: 'គ្មានធាតុក្នុងរទេះទេ',
|
||||
itemTotal: 'ធាតុសរុប',
|
||||
delvieryCharges: 'ការដឹកជញ្ជូន',
|
||||
total: 'សរុប',
|
||||
contactInfo: 'ព័ត៌មានទំនាក់ទំនង',
|
||||
deliveryAddressmessage: 'កំណត់អាសយដ្ឋានបញ្ជូន',
|
||||
proceedCheckout: 'បន្តដើម្បីពិនិត្យចេញ',
|
||||
paymentText: 'តើអ្នកចង់បង់ប្រាក់ដោយរបៀបណា?',
|
||||
checkout: 'ពិនិត្យមុនពេលចេញ',
|
||||
header_title1: 'ប័ណ្ណឥណទាន / ប័ណ្ណឥណពន្ធ',
|
||||
header_subscript1: 'ទូទាត់ជាមួយកាតឥណទានឬឥណពន្ធ',
|
||||
header_title2: 'PayPal',
|
||||
header_subscript2: 'ទូទាត់លើបណ្តាញ PayPal',
|
||||
header_title3: 'សាច់ប្រាក់នៅពេលប្រគល់',
|
||||
header_subscript3: 'បង់ពេលអ្នកទទួលបានធាតុ',
|
||||
thankYou: 'សូមអរគុណ!',
|
||||
orderConfirmed: 'បញ្ជាទិញរបស់អ្នកត្រូវបានបញ្ជាក់',
|
||||
orderAmount: 'ចំនួនទឹកប្រាក់នៃការបញ្ជាទិញរបស់អ្នក',
|
||||
orderDetail: 'លំអិតលំដាប់',
|
||||
paymentMethod: 'វិធីសាស្រ្តទូទាត់',
|
||||
trackOrder: 'លំដាប់តាមបទ',
|
||||
backToMenu: 'លំដាប់តាមបទ',
|
||||
foodItem: 'ម្ហូបអាហារ',
|
||||
deliveredTo: 'បញ្ជូនទៅ',
|
||||
writeAReview: 'សរសេរសង្ខេបឡើងវិញ',
|
||||
orderReceived: 'បញ្ជាទិញដែលទទួលបាន',
|
||||
cancelled: 'បានបោះបង់',
|
||||
foodPreparing: 'ម្ហូបកំពុងត្រូវបានរៀបចំ',
|
||||
delivered: 'បានបញ្ជូន',
|
||||
rateAndReview: 'វាយតម្លៃនិងពិនិត្យ',
|
||||
reviewPlaceholder: 'ការពិនិត្យលម្អិតបន្ថែមទៀតទទួលបានភាពមើលឃើញកាន់តែច្រើន ...',
|
||||
submit: 'ដាក់ស្នើ',
|
||||
noWorriesText: 'គ្មានការព្រួយបារម្ភសូមឱ្យយើងជួយអ្នកចេញ!',
|
||||
yourEmail: 'អ៊ីមែលរបស់អ្នក',
|
||||
send: 'ផ្ញើ',
|
||||
apply: 'អនុវត្ត',
|
||||
checkEmail: 'ពិនិត្យអ៊ីមែលរបស់អ្នកសម្រាប់តំណពាក្យសម្ងាត់ឡើងវិញ',
|
||||
languageText: 'សូមជ្រើសរើសភាសាដែលអ្នកត្រូវការ',
|
||||
countryCodePickerTranslation: 'eng',
|
||||
countryCodeSelect: 'ជ្រើសរើសលេខកូដប្រទេស',
|
||||
paymentNotSupported: 'វិធីសាស្ត្រទូទាត់នេះមិនគាំទ្ររូបិយប័ណ្ណនេះទេ',
|
||||
deliveryTime: 'ពេលវេលាដឹកជញ្ជូន',
|
||||
myOrders: 'ការបញ្ជាទិញរបស់ខ្ញុំ',
|
||||
newOrders: 'ការបញ្ជាទិញថ្មី'
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
export const zh = {
|
||||
title0: '选定的语言',
|
||||
subtitle0: 'English',
|
||||
description0: '选择您选择的任何语言,将应用内容更改为您所需的语言。',
|
||||
title1: '可口',
|
||||
subtitle1: '早餐',
|
||||
description1:
|
||||
'早餐就是一切。一开始,第一件事。这是对新的一天,持续生活的承诺。',
|
||||
title2: '清爽',
|
||||
subtitle2: '饮料',
|
||||
description2:
|
||||
'真正的沉默是心灵的其余部分,对于精神来说,睡眠对身体,营养和茶点来说都是如此。',
|
||||
title3: '美味的',
|
||||
subtitle3: '冰淇淋',
|
||||
description3: '年龄不会减少从冰锥中舀出一勺冰淇淋的极度失望',
|
||||
getStarted: '开始吧!',
|
||||
welcome: '欢迎来到',
|
||||
loginBtn: '登录',
|
||||
registerBtn: '寄存器',
|
||||
name: '名称',
|
||||
phone: '电话',
|
||||
email: '电子邮件',
|
||||
emailphone: '邮件或者电话',
|
||||
username: '用户名',
|
||||
password: '密码',
|
||||
deliveryAddress: '邮寄地址',
|
||||
registerText: '或注册',
|
||||
forgotPassword: '忘记密码?',
|
||||
loginText: '或登录',
|
||||
deliveryLocation: '设置您的送货地点,以便我们可以向您发送无尽的美味食物。',
|
||||
locationBtn: '打开位置',
|
||||
locationPermissionDenied: '访问位置的权限被拒绝',
|
||||
locationOff: '访问位置的权限被拒绝',
|
||||
titleLanguage: '改变语言',
|
||||
titleMenu: '菜单',
|
||||
titleOrders: '我的订单',
|
||||
titleNotifications: '通知',
|
||||
titleReviews: '评测',
|
||||
titleSettings: '设置',
|
||||
titleHelp: '救命',
|
||||
titleLogout: '登出',
|
||||
titleCart: '我的车',
|
||||
titlePayment: '付款',
|
||||
orderId: '订单ID',
|
||||
totalOrderAmount: '总订单金额',
|
||||
reOrder: '重新排序',
|
||||
unReadNotifications: '没有未读通知',
|
||||
upload: '上传',
|
||||
saveBtn: '保存',
|
||||
emailUs: '给我们发电子邮件',
|
||||
question1: '我们在哪里找到食物?',
|
||||
question2: '我们如何联系?',
|
||||
question3: '我该如何付款给送货人?',
|
||||
question4: '我的城市有这项服务吗?',
|
||||
answer1:
|
||||
'您可以在离您最近的商店找到食物,而无需向客户支付任何费用。与其他人相比,我们的收费极低。',
|
||||
answer2: '您可以通过我们的电子邮件,电话号码或我们的网站联系我们。',
|
||||
answer3: '您可以亲自向付款人付款或使用信用卡或借记卡在线付款。',
|
||||
answer4:
|
||||
'目前,这项服务在伊斯兰堡和卡拉奇市提供,您可以联系我们以便在您所在的城市使用此服务。',
|
||||
add: '加',
|
||||
quantity: '数量',
|
||||
size: '尺寸',
|
||||
addToCart: '添加到购物车',
|
||||
orderNow: '现在下单',
|
||||
addToCartMessage: '已添加到购物车',
|
||||
emptyCart: '购物车中没有商品',
|
||||
itemTotal: '项目总计',
|
||||
delvieryCharges: '送货费',
|
||||
total: '总',
|
||||
contactInfo: '联系信息',
|
||||
deliveryAddressmessage: '设置送货地址',
|
||||
proceedCheckout: '进行结算',
|
||||
paymentText: '你想怎么付钱?',
|
||||
checkout: '查看',
|
||||
header_title1: '信用卡/借记卡',
|
||||
header_subscript1: '使用信用卡或借记卡付款',
|
||||
header_title2: '贝宝',
|
||||
header_subscript2: '使用PayPal在线支付',
|
||||
header_title3: '货到付款',
|
||||
header_subscript3: '收到物品时付款',
|
||||
thankYou: 'ស谢谢!',
|
||||
orderConfirmed: '您的订单已确认',
|
||||
orderAmount: '您的订单金额',
|
||||
orderDetail: '订单详情',
|
||||
paymentMethod: '付款方法',
|
||||
trackOrder: '跟踪订单',
|
||||
backToMenu: '跟踪订单',
|
||||
foodItem: '食品',
|
||||
deliveredTo: '送到了(送去了',
|
||||
writeAReview: '写评论',
|
||||
orderReceived: '订单已经收到',
|
||||
cancelled: '取消',
|
||||
foodPreparing: '食物正在准备中',
|
||||
delivered: '交付',
|
||||
rateAndReview: '打分和评论',
|
||||
reviewPlaceholder: '更详细的评论获得更多可见性......',
|
||||
submit: '提交',
|
||||
noWorriesText: '不用担心,让我们帮帮你吧!',
|
||||
yourEmail: '你的邮件',
|
||||
send: '发送',
|
||||
apply: '应用',
|
||||
checkEmail: '查看您的电子邮件以重置密码链接',
|
||||
languageText: '请选择您需要的语言',
|
||||
countryCodePickerTranslation: 'zho',
|
||||
countryCodeSelect: '选择国家代码',
|
||||
paymentNotSupported: '此付款方式不支持此货币'
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
"name": "enatega-rider-app",
|
||||
"version": "5.0.0",
|
||||
"main": "node_modules/expo/AppEntry.js",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"eject": "expo eject",
|
||||
"format": "prettier --write '**/*.js'",
|
||||
"lint:fix": "eslint . --ext .js --fix",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"npm run format",
|
||||
"npm run lint:fix"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/react-hooks": "^3.1.3",
|
||||
"@expo/vector-icons": "^12.0.0",
|
||||
"@react-native-async-storage/async-storage": "~1.15.0",
|
||||
"@react-native-community/masked-view": "0.1.10",
|
||||
"@react-navigation/bottom-tabs": "^5.11.11",
|
||||
"@react-navigation/drawer": "^5.12.5",
|
||||
"@react-navigation/native": "^5.5.1",
|
||||
"@react-navigation/stack": "^5.14.5",
|
||||
"apollo-boost": "^0.4.3",
|
||||
"apollo-cache-inmemory": "^1.6.2",
|
||||
"apollo-client": "^2.6.3",
|
||||
"apollo-link": "^1.2.12",
|
||||
"apollo-link-context": "^1.0.18",
|
||||
"apollo-link-state": "^0.4.2",
|
||||
"apollo-link-ws": "^1.0.20",
|
||||
"apollo-upload-client": "^10.0.1",
|
||||
"expo": "^44.0.0",
|
||||
"expo-constants": "~13.0.1",
|
||||
"expo-font": "~10.0.4",
|
||||
"expo-localization": "~12.0.0",
|
||||
"expo-location": "~14.0.1",
|
||||
"expo-notifications": "~0.14.0",
|
||||
"expo-splash-screen": "~0.14.1",
|
||||
"expo-task-manager": "~10.1.0",
|
||||
"expo-updates": "~0.11.6",
|
||||
"graphql": "^14.3.1",
|
||||
"graphql-tag": "^2.10.1",
|
||||
"i18n-js": "^3.3.0",
|
||||
"patch-package": "^6.2.2",
|
||||
"react": "17.0.1",
|
||||
"react-apollo": "^2.5.8",
|
||||
"react-native": "0.64.3",
|
||||
"react-native-animatable": "^1.3.2",
|
||||
"react-native-flash-message": "^0.1.13",
|
||||
"react-native-gesture-handler": "~2.1.0",
|
||||
"react-native-gifted-chat": "^0.16.3",
|
||||
"react-native-maps": "0.29.4",
|
||||
"react-native-maps-directions": "^1.8.0",
|
||||
"react-native-material-textfield": "^0.16.1",
|
||||
"react-native-modal": "^11.5.6",
|
||||
"react-native-reanimated": "~2.3.1",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "~3.10.1",
|
||||
"react-native-svg": "12.1.1",
|
||||
"react-native-webview": "11.15.0",
|
||||
"subscriptions-transport-ws": "^0.9.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-expo": "9.0.2",
|
||||
"eslint": "^7.1.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.20.0",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.7",
|
||||
"prettier": "2.0.5",
|
||||
"prettier-config-standard": "^1.0.1"
|
||||
},
|
||||
"private": true
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
diff --git a/node_modules/react-native-material-textfield/src/components/affix/index.js b/node_modules/react-native-material-textfield/src/components/affix/index.js
|
||||
index 0f85022..c12b3a6 100644
|
||||
--- a/node_modules/react-native-material-textfield/src/components/affix/index.js
|
||||
+++ b/node_modules/react-native-material-textfield/src/components/affix/index.js
|
||||
@@ -11,7 +11,7 @@ export default class Affix extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
numberOfLines: PropTypes.number,
|
||||
- style: Animated.Text.propTypes.style,
|
||||
+ style: PropTypes.object,
|
||||
|
||||
color: PropTypes.string.isRequired,
|
||||
fontSize: PropTypes.number.isRequired,
|
||||
diff --git a/node_modules/react-native-material-textfield/src/components/field/index.js b/node_modules/react-native-material-textfield/src/components/field/index.js
|
||||
index 494bbaa..9bbf2e2 100644
|
||||
--- a/node_modules/react-native-material-textfield/src/components/field/index.js
|
||||
+++ b/node_modules/react-native-material-textfield/src/components/field/index.js
|
||||
@@ -221,6 +221,7 @@ export default class TextField extends PureComponent {
|
||||
|
||||
let options = {
|
||||
toValue: this.focusState(),
|
||||
+ useNativeDriver: false,
|
||||
duration,
|
||||
};
|
||||
|
||||
diff --git a/node_modules/react-native-material-textfield/src/components/helper/index.js b/node_modules/react-native-material-textfield/src/components/helper/index.js
|
||||
index 6060f9f..fe9d9c4 100644
|
||||
--- a/node_modules/react-native-material-textfield/src/components/helper/index.js
|
||||
+++ b/node_modules/react-native-material-textfield/src/components/helper/index.js
|
||||
@@ -11,7 +11,7 @@ export default class Helper extends PureComponent {
|
||||
|
||||
disabled: PropTypes.bool,
|
||||
|
||||
- style: Animated.Text.propTypes.style,
|
||||
+ style: PropTypes.object,
|
||||
|
||||
baseColor: PropTypes.string,
|
||||
errorColor: PropTypes.string,
|
||||
diff --git a/node_modules/react-native-material-textfield/src/components/label/index.js b/node_modules/react-native-material-textfield/src/components/label/index.js
|
||||
index 82eaf03..809fcdd 100644
|
||||
--- a/node_modules/react-native-material-textfield/src/components/label/index.js
|
||||
+++ b/node_modules/react-native-material-textfield/src/components/label/index.js
|
||||
@@ -43,7 +43,7 @@ export default class Label extends PureComponent {
|
||||
y1: PropTypes.number,
|
||||
}),
|
||||
|
||||
- style: Animated.Text.propTypes.style,
|
||||
+ style: PropTypes.object,
|
||||
label: PropTypes.string,
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"hostType": "lan",
|
||||
"lanType": "ip",
|
||||
"dev": true,
|
||||
"minify": false,
|
||||
"urlRandomness": null
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
export const order = `fragment orderItem on Order{
|
||||
_id
|
||||
order_id
|
||||
delivery_address{
|
||||
latitude
|
||||
longitude
|
||||
delivery_address
|
||||
details
|
||||
label
|
||||
}
|
||||
delivery_charges
|
||||
items {
|
||||
_id
|
||||
food {
|
||||
_id
|
||||
title
|
||||
}
|
||||
quantity
|
||||
variation{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
addons{
|
||||
_id
|
||||
title
|
||||
options{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
user {
|
||||
_id
|
||||
name
|
||||
phone
|
||||
email
|
||||
}
|
||||
order_status
|
||||
payment_status
|
||||
payment_method
|
||||
paid_amount
|
||||
order_amount
|
||||
createdAt
|
||||
}`
|
|
@ -0,0 +1,84 @@
|
|||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { ApolloLink, split, concat, Observable } from 'apollo-link'
|
||||
import { createHttpLink } from 'apollo-link-http'
|
||||
import { WebSocketLink } from 'apollo-link-ws'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
// import { withClientState } from 'apollo-link-state'
|
||||
|
||||
import getEnvVars from '../../environment'
|
||||
const { GRAPHQL_URL, WS_GRAPHQL_URL } = getEnvVars()
|
||||
|
||||
export let clientRef = null
|
||||
|
||||
function setupApolloClient() {
|
||||
const cache = new InMemoryCache()
|
||||
|
||||
const httpLink = createHttpLink({
|
||||
uri: GRAPHQL_URL
|
||||
})
|
||||
const wsLink = new WebSocketLink({
|
||||
uri: WS_GRAPHQL_URL,
|
||||
options: {
|
||||
reconnect: true
|
||||
}
|
||||
})
|
||||
|
||||
// const stateLink = withClientState({
|
||||
// cache
|
||||
// })
|
||||
|
||||
const request = async operation => {
|
||||
const token = await AsyncStorage.getItem('rider-token')
|
||||
|
||||
operation.setContext({
|
||||
// get the authentication token from local storage if it exists
|
||||
// return the headers to the context so httpLink can read them
|
||||
headers: {
|
||||
authorization: token ? `Bearer ${token}` : ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const requestLink = new ApolloLink(
|
||||
(operation, forward) =>
|
||||
new Observable(observer => {
|
||||
// console.log(observer)
|
||||
let handle
|
||||
Promise.resolve(operation)
|
||||
.then(oper => request(oper))
|
||||
.then(() => {
|
||||
handle = forward(operation).subscribe({
|
||||
next: observer.next.bind(observer),
|
||||
error: observer.error.bind(observer),
|
||||
complete: observer.complete.bind(observer)
|
||||
})
|
||||
})
|
||||
.catch(observer.error.bind(observer))
|
||||
|
||||
return () => {
|
||||
if (handle) handle.unsubscribe()
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const terminatingLink = split(
|
||||
({ query }) => {
|
||||
const { kind, operation } = getMainDefinition(query)
|
||||
return kind === 'OperationDefinition' && operation === 'subscription'
|
||||
},
|
||||
wsLink
|
||||
// httpLink,
|
||||
)
|
||||
|
||||
const client = new ApolloClient({
|
||||
// link: ApolloLink.from([stateLink, authLink.concat(httpLink)]),
|
||||
link: concat(ApolloLink.from([terminatingLink, requestLink]), httpLink),
|
||||
cache,
|
||||
resolvers: {}
|
||||
})
|
||||
clientRef = client
|
||||
return client
|
||||
}
|
||||
export default setupApolloClient
|
|
@ -0,0 +1,29 @@
|
|||
export const riderLogin = `mutation RiderLogin($username:String,$password:String,$notificationToken:String){
|
||||
riderLogin(username:$username,password:$password,notificationToken:$notificationToken){
|
||||
userId
|
||||
token
|
||||
}
|
||||
}`
|
||||
|
||||
export const updateOrderStatusRider = `mutation UpdateOrderStatusRider($id:String!,$status:String!){
|
||||
updateOrderStatusRider(id:$id,status:$status){
|
||||
_id
|
||||
order_status
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const assignOrder = `mutation AssignOrder($id:String!){
|
||||
assignOrder(id:$id){
|
||||
_id
|
||||
rider{
|
||||
_id
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
export const updateLocation = `mutation UpdateRiderLocation($latitude:String!,$longitude:String!){
|
||||
updateRiderLocation(latitude:$latitude,longitude:$longitude){
|
||||
_id
|
||||
}
|
||||
}`
|
|
@ -0,0 +1,231 @@
|
|||
export const profile = `
|
||||
query Rider($id:String){
|
||||
rider(id:$id){
|
||||
_id
|
||||
name
|
||||
username
|
||||
available
|
||||
}
|
||||
}`
|
||||
export const assignedOrders = `query AssignedOrders($id:String){
|
||||
assignedOrders(id:$id){
|
||||
_id
|
||||
rider{
|
||||
_id
|
||||
}
|
||||
order_id
|
||||
delivery_address{
|
||||
latitude
|
||||
longitude
|
||||
delivery_address
|
||||
details
|
||||
label
|
||||
}
|
||||
delivery_charges
|
||||
payment_method
|
||||
order_amount
|
||||
paid_amount
|
||||
order_status
|
||||
payment_status
|
||||
user{
|
||||
_id
|
||||
name
|
||||
phone
|
||||
email
|
||||
}
|
||||
items{
|
||||
_id
|
||||
food{
|
||||
_id
|
||||
title
|
||||
}
|
||||
quantity
|
||||
variation{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
addons{
|
||||
title
|
||||
options{
|
||||
title
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
createdAt
|
||||
}
|
||||
}`
|
||||
|
||||
export const subscriptionAssignRider = `subscription SubscriptionAssignRider($riderId:String!){
|
||||
subscriptionAssignRider(riderId:$riderId){
|
||||
userId
|
||||
origin
|
||||
order{
|
||||
_id
|
||||
rider{
|
||||
_id
|
||||
}
|
||||
order_id
|
||||
delivery_address{
|
||||
latitude
|
||||
longitude
|
||||
delivery_address
|
||||
details
|
||||
label
|
||||
}
|
||||
delivery_charges
|
||||
payment_method
|
||||
order_amount
|
||||
paid_amount
|
||||
order_status
|
||||
payment_status
|
||||
user{
|
||||
_id
|
||||
name
|
||||
phone
|
||||
email
|
||||
}
|
||||
items{
|
||||
_id
|
||||
food{
|
||||
_id
|
||||
title
|
||||
}
|
||||
quantity
|
||||
variation{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
addons{
|
||||
_id
|
||||
title
|
||||
options{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
export const configuration = `query Configuration{
|
||||
configuration{
|
||||
_id
|
||||
currency
|
||||
currency_symbol
|
||||
delivery_charges
|
||||
}
|
||||
}`
|
||||
|
||||
export const unassignedOrders = `query UnAssignedOrders{
|
||||
unassignedOrders{
|
||||
_id
|
||||
rider{
|
||||
_id
|
||||
}
|
||||
order_id
|
||||
delivery_address{
|
||||
latitude
|
||||
longitude
|
||||
delivery_address
|
||||
details
|
||||
label
|
||||
}
|
||||
delivery_charges
|
||||
payment_method
|
||||
order_amount
|
||||
paid_amount
|
||||
order_status
|
||||
payment_status
|
||||
user{
|
||||
_id
|
||||
name
|
||||
phone
|
||||
email
|
||||
}
|
||||
items{
|
||||
_id
|
||||
food{
|
||||
_id
|
||||
title
|
||||
}
|
||||
quantity
|
||||
variation{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
addons{
|
||||
_id
|
||||
title
|
||||
options{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
createdAt
|
||||
}
|
||||
}`
|
||||
|
||||
export const subscriptionUnAssignedOrder = `subscription SubscriptionUnAssignedOrder{
|
||||
unassignedOrder{
|
||||
userId
|
||||
origin
|
||||
order{
|
||||
_id
|
||||
rider{
|
||||
_id
|
||||
}
|
||||
order_id
|
||||
delivery_address{
|
||||
latitude
|
||||
longitude
|
||||
delivery_address
|
||||
details
|
||||
label
|
||||
}
|
||||
delivery_charges
|
||||
payment_method
|
||||
order_amount
|
||||
paid_amount
|
||||
order_status
|
||||
payment_status
|
||||
user{
|
||||
_id
|
||||
name
|
||||
phone
|
||||
email
|
||||
}
|
||||
items{
|
||||
_id
|
||||
food{
|
||||
_id
|
||||
title
|
||||
}
|
||||
quantity
|
||||
variation{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
addons{
|
||||
_id
|
||||
title
|
||||
options{
|
||||
_id
|
||||
title
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}`
|
|
@ -0,0 +1,56 @@
|
|||
import React, { useContext } from 'react'
|
||||
import { FlatList } from 'react-native'
|
||||
import Spinner from '../Spinner/Spinner'
|
||||
import Order from '../Order/Order'
|
||||
import ConfigurationContext from '../../context/configuration'
|
||||
import UserContext from '../../context/user'
|
||||
import TextError from '../Text/TextError/TextError'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { verticalScale } from '../../utilities/scaling'
|
||||
|
||||
export default function Orders() {
|
||||
const navigation = useNavigation()
|
||||
const configuration = useContext(ConfigurationContext)
|
||||
const {
|
||||
loadingAssigned,
|
||||
errorAssigned,
|
||||
assignedOrders,
|
||||
refetchAssigned,
|
||||
networkStatusAssigned
|
||||
} = useContext(UserContext)
|
||||
|
||||
if (loadingAssigned) return <Spinner />
|
||||
if (errorAssigned) return <TextError text="Something is worng" />
|
||||
|
||||
function emptyView() {
|
||||
return <TextError text="No Orders Assigned yet!" />
|
||||
}
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
keyExtractor={item => item._id}
|
||||
data={assignedOrders.length > 0 ? assignedOrders.slice().reverse() : []}
|
||||
refreshing={networkStatusAssigned === 4}
|
||||
onRefresh={() => refetchAssigned()}
|
||||
initialNumToRender={3}
|
||||
ListEmptyComponent={emptyView}
|
||||
style={{ marginTop: verticalScale(-80) }}
|
||||
renderItem={({ item }) => (
|
||||
<Order
|
||||
key={item._id}
|
||||
orderId={item.order_id}
|
||||
orderStatus={item.order_status}
|
||||
orderAmount={`${configuration.currency_symbol}${item.order_amount}`}
|
||||
orderDatetime={item.createdAt}
|
||||
paymentMethod={item.payment_method}
|
||||
onPress={() => {
|
||||
navigation.navigate('OrderDetail', {
|
||||
id: item._id,
|
||||
orderId: item.order_id
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { createIconSetFromIcoMoon } from '@expo/vector-icons'
|
||||
import icoMoonConfig from './selection.json'
|
||||
|
||||
export const CustomIcon = createIconSetFromIcoMoon(
|
||||
icoMoonConfig,
|
||||
'icomoon',
|
||||
'icomoon.ttf'
|
||||
)
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
import { Image } from 'react-native'
|
||||
|
||||
import styles from './styles'
|
||||
|
||||
const FdFullLogo = () => {
|
||||
return (
|
||||
<Image
|
||||
style={styles.logo_image}
|
||||
source={require('../../../assets/images/ui/transparent-icon.png')}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default FdFullLogo
|
|
@ -0,0 +1,8 @@
|
|||
export default {
|
||||
logo_image: {
|
||||
height: '17%',
|
||||
width: '55%',
|
||||
alignSelf: 'center',
|
||||
marginBottom: '50%'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import React from 'react'
|
||||
import { TouchableOpacity } from 'react-native'
|
||||
import { View } from 'react-native-animatable'
|
||||
import PropTypes from 'prop-types'
|
||||
import colors from '../../utilities/colors'
|
||||
import styles from './styles'
|
||||
|
||||
const DEFAULT_SIZE_MULTIPLIER = 0.7
|
||||
|
||||
export default function RadioButton(props) {
|
||||
const { size, innerColor, outerColor, isSelected, onPress } = props
|
||||
const outerStyle = {
|
||||
borderColor: outerColor,
|
||||
width: size + size * DEFAULT_SIZE_MULTIPLIER,
|
||||
height: size + size * DEFAULT_SIZE_MULTIPLIER,
|
||||
borderRadius: (size + size * DEFAULT_SIZE_MULTIPLIER) / 2,
|
||||
borderWidth: isSelected ? size / 2 : 1
|
||||
}
|
||||
|
||||
const innerStyle = {
|
||||
width: size / 2,
|
||||
height: size / 2,
|
||||
borderRadius: size / 2,
|
||||
backgroundColor: innerColor
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={[styles.radio, outerStyle]} onPress={onPress}>
|
||||
{isSelected ? <View style={innerStyle} {...props} /> : null}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
RadioButton.propTypes = {
|
||||
size: PropTypes.number,
|
||||
innerColor: PropTypes.string,
|
||||
outerColor: PropTypes.string,
|
||||
isSelected: PropTypes.bool,
|
||||
onPress: PropTypes.func
|
||||
}
|
||||
|
||||
RadioButton.defaultProps = {
|
||||
size: 16,
|
||||
innerColor: colors.radioColor,
|
||||
outerColor: colors.radioOuterColor,
|
||||
isSelected: false,
|
||||
onPress: () => null
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
radio: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { showMessage } from 'react-native-flash-message'
|
||||
import PropTypes from 'prop-types'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
import { textStyles } from '../../utilities/textStyles'
|
||||
|
||||
export const FlashMessage = props => {
|
||||
showMessage({
|
||||
backgroundColor: '#323232',
|
||||
message: props.message,
|
||||
type: 'info',
|
||||
position: 'bottom',
|
||||
titleStyle: {
|
||||
fontSize: scale(12),
|
||||
...textStyles.Bold
|
||||
}
|
||||
})
|
||||
}
|
||||
FlashMessage.propTypes = {
|
||||
message: PropTypes.string.isRequired
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { fontStyles } from '../../utilities/fontStyles'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
|
||||
export default {
|
||||
text: {
|
||||
fontSize: scale(14),
|
||||
fontFamily: fontStyles.MuseoSans500,
|
||||
paddingTop: 6
|
||||
},
|
||||
container: {
|
||||
borderRadius: 50
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
import {
|
||||
CommonActions,
|
||||
useNavigation,
|
||||
useTheme
|
||||
} from '@react-navigation/native'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { Pressable, View } from 'react-native'
|
||||
import colors from '../../../utilities/colors'
|
||||
import { ICONS_NAME } from '../../../utilities/constant'
|
||||
import { scale } from '../../../utilities/scaling'
|
||||
import { CustomIcon } from '../../CustomIcon'
|
||||
import styles from './styles'
|
||||
|
||||
function HeaderIcon({ icon, iconColor, iconSize = scale(25) }) {
|
||||
return (
|
||||
<CustomIcon
|
||||
name={icon}
|
||||
size={iconSize}
|
||||
color={iconColor || colors.fontSecondColor}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function LeftButton(props) {
|
||||
const { icon, outerView, iconColor } = props
|
||||
const navigation = useNavigation()
|
||||
const { colors } = useTheme()
|
||||
|
||||
switch (icon) {
|
||||
case ICONS_NAME.Menu:
|
||||
return (
|
||||
<View style={[styles.btnContainer, outerView]}>
|
||||
<Pressable
|
||||
hitSlop={50}
|
||||
pressRetentionOffset={50}
|
||||
android_ripple={{
|
||||
borderless: true,
|
||||
color: colors.rippleColor,
|
||||
radius: 23
|
||||
}}
|
||||
style={({ pressed }) => [
|
||||
{
|
||||
opacity: pressed ? 0.7 : 1
|
||||
}
|
||||
]}
|
||||
onPress={() => navigation.toggleDrawer()}>
|
||||
<HeaderIcon iconColor={iconColor} icon={icon} />
|
||||
</Pressable>
|
||||
</View>
|
||||
)
|
||||
case ICONS_NAME.Back:
|
||||
return (
|
||||
<View style={[styles.btnContainer, outerView]}>
|
||||
<Pressable
|
||||
hitSlop={50}
|
||||
pressRetentionOffset={50}
|
||||
android_ripple={{
|
||||
borderless: true,
|
||||
color: colors.rippleColor,
|
||||
radius: 23
|
||||
}}
|
||||
style={({ pressed }) => [
|
||||
{
|
||||
opacity: pressed ? 0.7 : 1
|
||||
}
|
||||
]}
|
||||
onPress={() => navigation.goBack()}>
|
||||
<HeaderIcon iconColor={iconColor} icon={icon} />
|
||||
</Pressable>
|
||||
</View>
|
||||
)
|
||||
case ICONS_NAME.Cross:
|
||||
return (
|
||||
<View style={[styles.btnContainer, outerView]}>
|
||||
<Pressable
|
||||
hitSlop={50}
|
||||
pressRetentionOffset={50}
|
||||
android_ripple={{
|
||||
borderless: true,
|
||||
color: colors.rippleColor,
|
||||
radius: 23
|
||||
}}
|
||||
style={({ pressed }) => [
|
||||
{
|
||||
opacity: pressed ? 0.7 : 1
|
||||
}
|
||||
]}
|
||||
onPress={() =>
|
||||
navigation.dispatch(state => {
|
||||
const routes = state.routes.filter(r => r.name === 'Menu')
|
||||
return CommonActions.reset({
|
||||
...state,
|
||||
routes,
|
||||
index: 0
|
||||
})
|
||||
})
|
||||
}>
|
||||
<HeaderIcon iconColor={iconColor} icon={icon} />
|
||||
</Pressable>
|
||||
</View>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
HeaderIcon.propTypes = {
|
||||
outerView: PropTypes.object,
|
||||
icon: PropTypes.string,
|
||||
iconColor: PropTypes.string,
|
||||
iconSize: PropTypes.number
|
||||
}
|
||||
LeftButton.propTypes = {
|
||||
outerView: PropTypes.object,
|
||||
icon: PropTypes.string,
|
||||
iconColor: PropTypes.string
|
||||
}
|
||||
|
||||
export { HeaderIcon, LeftButton }
|
|
@ -0,0 +1,18 @@
|
|||
import { StyleSheet } from 'react-native'
|
||||
import { alignment } from '../../../utilities/alignment'
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
leftIconPadding: {
|
||||
...alignment.PLsmall,
|
||||
...alignment.PRlarge
|
||||
},
|
||||
btnContainer: {
|
||||
backgroundColor: 'rgba(255, 255, 255,0.01)',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: 80
|
||||
}
|
||||
})
|
||||
|
||||
export default styles
|
|
@ -0,0 +1,3 @@
|
|||
import { HeaderIcon, LeftButton } from './HeaderIcons/HeaderIcons'
|
||||
|
||||
export { HeaderIcon, LeftButton }
|
|
@ -0,0 +1,59 @@
|
|||
import React, { useContext } from 'react'
|
||||
import { FlatList } from 'react-native'
|
||||
import Spinner from '../Spinner/Spinner'
|
||||
import Order from '../Order/Order'
|
||||
import ConfigurationContext from '../../context/configuration'
|
||||
import UserContext from '../../context/user'
|
||||
import TextError from '../Text/TextError/TextError'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { verticalScale } from '../../utilities/scaling'
|
||||
|
||||
export default function Orders() {
|
||||
const navigation = useNavigation()
|
||||
const configuration = useContext(ConfigurationContext)
|
||||
const {
|
||||
loadingUnAssigned,
|
||||
errorUnAssigned,
|
||||
unAssignedOrders,
|
||||
refetchUnAssigned,
|
||||
networkStatusUnAssigned
|
||||
} = useContext(UserContext)
|
||||
|
||||
function emptyView() {
|
||||
return <TextError text="No New Order" />
|
||||
}
|
||||
|
||||
if (loadingUnAssigned) return <Spinner />
|
||||
if (errorUnAssigned) return <TextError text="Something is worng" />
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
keyExtractor={item => item._id}
|
||||
data={
|
||||
unAssignedOrders.length > 0 ? unAssignedOrders.slice().reverse() : []
|
||||
}
|
||||
style={{ marginTop: verticalScale(-80) }}
|
||||
refreshing={networkStatusUnAssigned === 4}
|
||||
onRefresh={refetchUnAssigned}
|
||||
initialNumToRender={3}
|
||||
ListEmptyComponent={emptyView}
|
||||
renderItem={({ item }) => (
|
||||
<Order
|
||||
key={item._id}
|
||||
orderId={item.order_id}
|
||||
orderStatus={item.order_status}
|
||||
orderAmount={`${configuration.currency_symbol}${item.order_amount}`}
|
||||
orderDatetime={item.createdAt}
|
||||
paymentMethod={item.payment_method}
|
||||
onPress={() => {
|
||||
console.log('item', item)
|
||||
navigation.navigate('OrderDetail', {
|
||||
id: item._id,
|
||||
orderId: item.order_id
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
const styles = {
|
||||
flex: {
|
||||
flex: 1
|
||||
}
|
||||
}
|
||||
|
||||
export default styles
|
|
@ -0,0 +1,206 @@
|
|||
import React from 'react'
|
||||
import { View, TouchableOpacity } from 'react-native'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
import colors from '../../utilities/colors'
|
||||
import styles from './style'
|
||||
import i18n from '../../../i18n'
|
||||
import TextDefault from '../Text/TextDefault/TextDefault'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import { AntDesign } from '@expo/vector-icons'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
export const orderStatuses = [
|
||||
{
|
||||
key: 'PENDING',
|
||||
color: '#518ef8'
|
||||
},
|
||||
{
|
||||
key: 'ACCEPTED',
|
||||
color: '#518ef8'
|
||||
},
|
||||
{
|
||||
key: 'PICKED',
|
||||
color: '#febb2c'
|
||||
},
|
||||
{
|
||||
key: 'DELIVERED',
|
||||
color: '#28b446'
|
||||
},
|
||||
{
|
||||
key: 'COMPLETED',
|
||||
color: '#f14336'
|
||||
}
|
||||
]
|
||||
|
||||
function Order(props) {
|
||||
// const cardHeight = props.height
|
||||
// ? props.height
|
||||
// : PixelRatio.getFontScale() * verticalScale(150)
|
||||
|
||||
const checkStatus = status => {
|
||||
const obj = orderStatuses.filter(x => {
|
||||
return x.key === status
|
||||
})
|
||||
return obj[0]
|
||||
}
|
||||
|
||||
const statusColor = checkStatus(props.orderStatus).color
|
||||
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={1} onPress={props.onPress}>
|
||||
<View style={[styles.card_container]}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<View style={{ width: '50%' }}>
|
||||
<TextDefault
|
||||
numberOfLines={2}
|
||||
bold
|
||||
textColor={colors.placeHolderColor}>
|
||||
Your {i18n.t('orderId')}
|
||||
</TextDefault>
|
||||
<TextDefault H4 bolder>
|
||||
{props.orderId}
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<View
|
||||
style={[
|
||||
styles.cardStatusContainer,
|
||||
{ borderColor: statusColor, borderWidth: 1 }
|
||||
]}>
|
||||
<TextDefault
|
||||
textColor={statusColor}
|
||||
bold
|
||||
uppercase
|
||||
style={{ ...alignment.PLxSmall, ...alignment.PRxSmall }}>
|
||||
{props.orderStatus}
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={{ paddingLeft: '5%' }}>
|
||||
<AntDesign
|
||||
name="arrowright"
|
||||
size={scale(20)}
|
||||
color={colors.fontMainColor}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '90%'
|
||||
}}>
|
||||
<View>
|
||||
<TextDefault
|
||||
style={alignment.MTmedium}
|
||||
textColor={colors.placeHolderColor}
|
||||
bold>
|
||||
{i18n.t('totalOrderAmount')}
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bold
|
||||
style={{ ...alignment.MTxSmall }}>
|
||||
Payment method
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bold
|
||||
style={{ ...alignment.MTxSmall }}>
|
||||
Delivery Time
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View>
|
||||
<TextDefault
|
||||
style={alignment.MTmedium}
|
||||
textColor={colors.fontMainColor}
|
||||
bolder>
|
||||
{props.orderAmount}
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
textColor={colors.fontMainColor}
|
||||
bolder
|
||||
style={{ ...alignment.MTxSmall }}>
|
||||
{props.paymentMethod}
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
textColor={colors.fontMainColor}
|
||||
bolder
|
||||
style={{ ...alignment.MTxSmall }}>
|
||||
{new Date(props.orderDatetime).toLocaleDateString()}{' '}
|
||||
{new Date(props.orderDatetime).toLocaleTimeString()}{' '}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
{/* <View style={[styles.card_container__left]}>
|
||||
<View style={[styles.left_toptextLine]}>
|
||||
<TextDefault center H5 bold textColor={colors.placeHolderColor}>
|
||||
Your {i18n.t('orderId')}
|
||||
</TextDefault>
|
||||
<TextDefault H3 bolder>
|
||||
{props.orderId}
|
||||
</TextDefault>
|
||||
</View> */}
|
||||
{/* <TextDefault style={alignment.MTmedium} textColor={colors.placeHolderColor} bold>
|
||||
{i18n.t('totalOrderAmount')} - {props.orderAmount}
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bold
|
||||
style={{ ...alignment.MTxSmall }}>
|
||||
{new Date(props.orderDatetime).toDateString()}{' '}
|
||||
{new Date(props.orderDatetime).toTimeString()}
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bold
|
||||
style={{ ...alignment.MTxSmall }}>
|
||||
Payment method: {props.paymentMethod}
|
||||
</TextDefault> */}
|
||||
{/* </View> */}
|
||||
{/* <View style={styles.card_container__right}> */}
|
||||
{/* <View style={styles.cardSubContainerRight}>
|
||||
<View
|
||||
style={[
|
||||
styles.cardStatusContainer,
|
||||
{ borderColor: statusColor, borderWidth:1 }
|
||||
]}>
|
||||
<TextDefault
|
||||
textColor={statusColor}
|
||||
bold
|
||||
uppercase
|
||||
style={{ ...alignment.PLxSmall, ...alignment.PRxSmall }}>
|
||||
{props.orderStatus}
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.cardRightArrow}>
|
||||
<AntDesign
|
||||
name="arrowright"
|
||||
size={scale(25)}
|
||||
color={colors.fontMainColor}
|
||||
/>
|
||||
</View>
|
||||
</View> */}
|
||||
{/* </View> */}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
Order.propTypes = {
|
||||
height: PropTypes.oneOf([PropTypes.string, PropTypes.number]),
|
||||
orderStatus: PropTypes.string.isRequired,
|
||||
onPress: PropTypes.func,
|
||||
orderId: PropTypes.string.isRequired,
|
||||
orderAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
orderDatetime: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.instanceOf(Date)
|
||||
]),
|
||||
paymentMethod: PropTypes.string
|
||||
}
|
||||
export default Order
|
|
@ -0,0 +1,59 @@
|
|||
import { scale, verticalScale } from '../../utilities/scaling'
|
||||
|
||||
const Styles = {
|
||||
card_container: {
|
||||
elevation: 10,
|
||||
width: '90%',
|
||||
padding: 20,
|
||||
justifyContent: 'center',
|
||||
height: verticalScale(170),
|
||||
alignSelf: 'center',
|
||||
borderRadius: scale(20),
|
||||
backgroundColor: '#fff',
|
||||
marginBottom: scale(20),
|
||||
shadowOffset: { width: 0, height: scale(2) },
|
||||
shadowColor: 'black',
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: scale(2),
|
||||
borderWidth: 0.4,
|
||||
borderColor: '#e1e1e1'
|
||||
},
|
||||
card_container__left: {
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
height: '70%',
|
||||
width: '58%',
|
||||
paddingLeft: '5%'
|
||||
},
|
||||
card_container__right: {
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'flex-end',
|
||||
height: '80%',
|
||||
width: '35%'
|
||||
},
|
||||
left_toptextLine: {
|
||||
alignSelf: 'flex-start',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
cardSubContainerRight: {
|
||||
width: '100%',
|
||||
height: '30%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-around',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
cardStatusContainer: {
|
||||
padding: scale(8),
|
||||
paddingHorizontal: scale(12),
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: verticalScale(5)
|
||||
},
|
||||
cardRightArrow: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}
|
||||
}
|
||||
|
||||
export default Styles
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react'
|
||||
import { TouchableOpacity, View } from 'react-native'
|
||||
import styles from './styles.js'
|
||||
import TextDefault from '../../Text/TextDefault/TextDefault.js'
|
||||
import { Entypo, FontAwesome } from '@expo/vector-icons'
|
||||
import { scale } from '../../../utilities/scaling.js'
|
||||
import colors from '../../../utilities/colors.js'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const NavItem = props => (
|
||||
<View style={styles.Flex}>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
style={styles.container}
|
||||
onPress={props.onPress}>
|
||||
<View style={styles.leftContainer}>
|
||||
{props.icon === 'shopping-bag' ? (
|
||||
<Entypo
|
||||
name={props.icon}
|
||||
size={scale(20)}
|
||||
color={colors.fontSecondColor}
|
||||
/>
|
||||
) : (
|
||||
<FontAwesome
|
||||
name={props.icon}
|
||||
size={scale(20)}
|
||||
color={colors.fontSecondColor}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.rightContainer}>
|
||||
<TextDefault bolder H5 textColor={colors.fontSecondColor}>
|
||||
{props.title}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
NavItem.propTypes = {
|
||||
onPress: PropTypes.func,
|
||||
icon: PropTypes.string,
|
||||
title: PropTypes.string.isRequired
|
||||
}
|
||||
export default NavItem
|
|
@ -0,0 +1,22 @@
|
|||
export default {
|
||||
Flex: {
|
||||
flex: 1
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-evenly',
|
||||
alignItems: 'center'
|
||||
},
|
||||
leftContainer: {
|
||||
height: '100%',
|
||||
width: '15%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
rightContainer: {
|
||||
height: '80%',
|
||||
width: '75%',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
import gql from 'graphql-tag'
|
||||
import Spinner from '../../Spinner/Spinner'
|
||||
import styles from './styles'
|
||||
import { profile } from '../../../apollo/queries'
|
||||
import { useQuery } from '@apollo/react-hooks'
|
||||
import TextDefault from '../../Text/TextDefault/TextDefault'
|
||||
import colors from '../../../utilities/colors'
|
||||
import TextError from '../../Text/TextError/TextError'
|
||||
import i18n from '../../../../i18n'
|
||||
|
||||
const PROFILE = gql`
|
||||
${profile}
|
||||
`
|
||||
|
||||
function Profile() {
|
||||
const { data, loading, error } = useQuery(PROFILE)
|
||||
if (loading) return <Spinner />
|
||||
if (error) return <TextError text="Something is worng" />
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.leftContainer}>
|
||||
{data.rider.name && (
|
||||
<View style={styles.imgContainer}>
|
||||
<TextDefault textColor={colors.themeBackground} bold H1>
|
||||
{data.rider.name.substr(0, 1).toUpperCase()}
|
||||
</TextDefault>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.rightContainer}>
|
||||
<TextDefault H5 bold textColor={colors.fontSecondColor}>
|
||||
{i18n.t('welcome')}
|
||||
</TextDefault>
|
||||
<TextDefault H3 textColor={colors.fontSecondColor} bolder>
|
||||
{data.rider.username}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default Profile
|
|
@ -0,0 +1,28 @@
|
|||
import colors from '../../../utilities/colors'
|
||||
import { scale } from '../../../utilities/scaling'
|
||||
import { alignment } from '../../../utilities/alignment'
|
||||
|
||||
export default {
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
paddingLeft: '10%',
|
||||
borderColor: colors.horizontalLine
|
||||
},
|
||||
leftContainer: {
|
||||
justifyContent: 'center',
|
||||
...alignment.MRsmall
|
||||
},
|
||||
imgContainer: {
|
||||
width: scale(70),
|
||||
height: scale(70),
|
||||
borderRadius: scale(20),
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.tagColor
|
||||
},
|
||||
rightContainer: {
|
||||
justifyContent: 'center',
|
||||
...alignment.MTmedium
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import React, { useContext } from 'react'
|
||||
import { Platform, View } from 'react-native'
|
||||
import i18n from '../../../i18n'
|
||||
import { AuthContext } from '../../context/auth'
|
||||
import { NAVIGATION_SCREEN } from '../../utilities/constant'
|
||||
import NavItem from './NavItem/NavItem'
|
||||
import Profile from './Profile/Profile'
|
||||
import styles from './styles'
|
||||
|
||||
// constants
|
||||
const datas = [
|
||||
{
|
||||
title: 'titleOrders',
|
||||
// icon:'linode',
|
||||
icon: 'shopping-bag',
|
||||
navigateTo: NAVIGATION_SCREEN.Orders
|
||||
},
|
||||
{
|
||||
title: 'titleLanguage',
|
||||
icon: 'language',
|
||||
navigateTo: NAVIGATION_SCREEN.Language
|
||||
},
|
||||
|
||||
{
|
||||
title: 'titleHelp',
|
||||
icon: 'exclamation-circle',
|
||||
navigateTo: NAVIGATION_SCREEN.Help
|
||||
}
|
||||
// {
|
||||
// title: 'titleChat',
|
||||
// icon: 'comments-o',
|
||||
// navigateTo: NAVIGATION_SCREEN.Chat
|
||||
// }
|
||||
// {
|
||||
// title: 'titleLogout',
|
||||
// icon: 'sign-out',
|
||||
// navigateTo: 'Login'
|
||||
// }
|
||||
]
|
||||
|
||||
function SidebBar({ navigation }) {
|
||||
const { logout } = useContext(AuthContext)
|
||||
|
||||
// if (loading) return <Spinner />
|
||||
return (
|
||||
<>
|
||||
<View style={styles.flex}>
|
||||
<View style={styles.topContainer}>
|
||||
<Profile />
|
||||
</View>
|
||||
<View style={styles.botContainer}>
|
||||
{datas.map((data, ind) =>
|
||||
(Platform.OS === 'ios' && ind === 0) ||
|
||||
(Platform.OS === 'ios' && ind === 1) ? null : (
|
||||
<View key={ind} style={styles.item}>
|
||||
<NavItem
|
||||
onPress={async () => {
|
||||
if (data.navigateTo === 'Login') {
|
||||
await logout()
|
||||
navigation.closeDrawer()
|
||||
} else {
|
||||
navigation.navigate(data.navigateTo)
|
||||
}
|
||||
}}
|
||||
icon={data.icon}
|
||||
title={i18n.t(data.title)}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={styles.item}>
|
||||
<NavItem
|
||||
onPress={async () => {
|
||||
await logout()
|
||||
navigation.closeDrawer()
|
||||
}}
|
||||
icon={'sign-out'}
|
||||
title={i18n.t('titleLogout')}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
SidebBar.propTypes = {
|
||||
navigation: PropTypes.object
|
||||
}
|
||||
export default SidebBar
|
|
@ -0,0 +1,27 @@
|
|||
const styles = {
|
||||
flex: {
|
||||
flex: 1
|
||||
},
|
||||
topContainer: {
|
||||
height: '40%'
|
||||
},
|
||||
botContainer: {
|
||||
flex: 1,
|
||||
marginTop: '4%',
|
||||
marginBottom: 70,
|
||||
height: '40%'
|
||||
},
|
||||
item: {
|
||||
height: '20%',
|
||||
marginBottom: '2%'
|
||||
},
|
||||
spinnerBackgorund: {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: 'rgba(166,158,149,0.5)',
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
export default styles
|
|
@ -0,0 +1,18 @@
|
|||
import React from 'react'
|
||||
import { ActivityIndicator } from 'react-native'
|
||||
import colors from '../../utilities/colors'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
function Spinner(props) {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color={props.spinnerColor ?? colors.spinnerColor}
|
||||
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Spinner.propTypes = {
|
||||
spinnerColor: PropTypes.string
|
||||
}
|
||||
export default Spinner
|
|
@ -0,0 +1,61 @@
|
|||
import React from 'react'
|
||||
import { Text, StyleSheet } from 'react-native'
|
||||
import color from './styles'
|
||||
import { textStyles } from '../../../utilities/textStyles'
|
||||
import colors from '../../../utilities/colors'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
function TextDefault(props) {
|
||||
const textColor = props.textColor ? props.textColor : colors.fontMainColor
|
||||
const defaultStyle = StyleSheet.flatten([
|
||||
color(textColor).color,
|
||||
textStyles.Regular,
|
||||
textStyles.Normal
|
||||
])
|
||||
var customStyles = [defaultStyle]
|
||||
|
||||
if (props.bold) customStyles.push(textStyles.Bold)
|
||||
if (props.bolder) customStyles.push(textStyles.Bolder)
|
||||
if (props.center) customStyles.push(textStyles.Center)
|
||||
if (props.right) customStyles.push(textStyles.Right)
|
||||
if (props.small) customStyles.push(textStyles.Small)
|
||||
if (props.xSmall) customStyles.push(textStyles.xSmall)
|
||||
if (props.H5) customStyles.push(textStyles.H5)
|
||||
if (props.H4) customStyles.push(textStyles.H4)
|
||||
if (props.H3) customStyles.push(textStyles.H3)
|
||||
if (props.H2) customStyles.push(textStyles.H2)
|
||||
if (props.H1) customStyles.push(textStyles.H1)
|
||||
if (props.uppercase) customStyles.push(textStyles.UpperCase)
|
||||
if (props.lineOver) customStyles.push(textStyles.LineOver)
|
||||
|
||||
customStyles = StyleSheet.flatten([customStyles, props.style])
|
||||
return (
|
||||
<Text
|
||||
numberOfLines={props.numberOfLines ? props.numberOfLines : 0}
|
||||
style={customStyles}>
|
||||
{props.children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
TextDefault.propTypes = {
|
||||
textColor: PropTypes.string,
|
||||
bold: PropTypes.bool,
|
||||
bolder: PropTypes.bool,
|
||||
center: PropTypes.bool,
|
||||
right: PropTypes.bool,
|
||||
small: PropTypes.bool,
|
||||
xSmall: PropTypes.bool,
|
||||
H5: PropTypes.bool,
|
||||
H4: PropTypes.bool,
|
||||
H3: PropTypes.bool,
|
||||
H2: PropTypes.bool,
|
||||
H1: PropTypes.bool,
|
||||
uppercase: PropTypes.bool,
|
||||
lineOver: PropTypes.bool,
|
||||
numberOfLines: PropTypes.number,
|
||||
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
children: PropTypes.node.isRequired
|
||||
}
|
||||
|
||||
export default TextDefault
|
|
@ -0,0 +1,10 @@
|
|||
import { StyleSheet } from 'react-native'
|
||||
|
||||
const color = textColor =>
|
||||
StyleSheet.create({
|
||||
color: {
|
||||
color: textColor
|
||||
}
|
||||
})
|
||||
|
||||
export default color
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
import TextDefault from '../TextDefault/TextDefault'
|
||||
import colors from '../../../utilities/colors'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
function TextError(props) {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: props.backColor ? props.backColor : 'transparent'
|
||||
}}>
|
||||
<TextDefault
|
||||
textColor={props.textColor ? props.textColor : colors.lightBackground}
|
||||
bold
|
||||
H4
|
||||
center>
|
||||
{props.text}{' '}
|
||||
</TextDefault>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
TextError.propTypes = {
|
||||
text: PropTypes.string,
|
||||
backColor: PropTypes.string,
|
||||
textColor: PropTypes.string
|
||||
}
|
||||
export default TextError
|
|
@ -0,0 +1,4 @@
|
|||
import TextDefault from './TextDefault/TextDefault'
|
||||
import TextError from './TextError/TextError'
|
||||
|
||||
export { TextDefault, TextError }
|
|
@ -0,0 +1,24 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { View, Image } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import useStyle from './styles'
|
||||
|
||||
const BACKGROUND_IMAGE = require('../../../assets/images/ui/BG.png')
|
||||
function MainWrapper({ children }) {
|
||||
const styles = useStyle()
|
||||
const inset = useSafeAreaInsets()
|
||||
|
||||
return (
|
||||
<View style={[styles.flex, { paddingBottom: inset.bottom }]}>
|
||||
<Image style={styles.imageContainer} source={BACKGROUND_IMAGE} />
|
||||
{children}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
MainWrapper.propTypes = {
|
||||
children: PropTypes.node
|
||||
}
|
||||
|
||||
export default React.memo(MainWrapper)
|
|
@ -0,0 +1,16 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { View } from 'react-native'
|
||||
import useStyle from './styles'
|
||||
|
||||
function WrapperView({ children }) {
|
||||
const styles = useStyle()
|
||||
|
||||
return <View style={[styles.flex, styles.wrapperView]}>{children}</View>
|
||||
}
|
||||
|
||||
WrapperView.propTypes = {
|
||||
children: PropTypes.node
|
||||
}
|
||||
|
||||
export default React.memo(WrapperView)
|
|
@ -0,0 +1,4 @@
|
|||
import MainWrapper from './MainWrapper'
|
||||
import WrapperView from './WrapperView'
|
||||
|
||||
export { MainWrapper, WrapperView }
|
|
@ -0,0 +1,30 @@
|
|||
import { useHeaderHeight } from '@react-navigation/stack'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import colors from '../../utilities/colors'
|
||||
import { verticalScale } from '../../utilities/scaling'
|
||||
|
||||
const useStyle = () => {
|
||||
const inset = useSafeAreaInsets()
|
||||
const headerHeight = useHeaderHeight()
|
||||
|
||||
return StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.cartContainer
|
||||
},
|
||||
wrapperView: {
|
||||
backgroundColor: colors.themeBackground,
|
||||
paddingTop: headerHeight,
|
||||
paddingBottom: inset.bottom
|
||||
},
|
||||
imageContainer: {
|
||||
backgroundColor: colors.cartContainer,
|
||||
width: '100%',
|
||||
height: verticalScale(130),
|
||||
alignSelf: 'center'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default useStyle
|
|
@ -0,0 +1,18 @@
|
|||
import AssignedOrders from './AssignedOrders/AssignedOrders'
|
||||
import { HeaderIcon, LeftButton } from './Header'
|
||||
import NewOrders from './NewOrders/NewOrders'
|
||||
import { MainWrapper, WrapperView } from './WrapperView'
|
||||
import { TextDefault, TextError } from './Text'
|
||||
import Spinner from './Spinner/Spinner'
|
||||
|
||||
export {
|
||||
MainWrapper,
|
||||
WrapperView,
|
||||
HeaderIcon,
|
||||
NewOrders,
|
||||
LeftButton,
|
||||
AssignedOrders,
|
||||
TextDefault,
|
||||
TextError,
|
||||
Spinner
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import React from 'react'
|
||||
|
||||
export const AuthContext = React.createContext()
|
|
@ -0,0 +1,25 @@
|
|||
/* eslint-disable react/prop-types */
|
||||
import React from 'react'
|
||||
import { useQuery } from '@apollo/react-hooks'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import { configuration } from '../apollo/queries'
|
||||
|
||||
const GETCONFIGURATION = gql`
|
||||
${configuration}
|
||||
`
|
||||
|
||||
const ConfigurationContext = React.createContext({})
|
||||
|
||||
export const ConfigurationProvider = props => {
|
||||
const { loading, data, error } = useQuery(GETCONFIGURATION)
|
||||
const configuration =
|
||||
loading || error || !data.configuration ? {} : data.configuration
|
||||
return (
|
||||
<ConfigurationContext.Provider value={configuration}>
|
||||
{props.children}
|
||||
</ConfigurationContext.Provider>
|
||||
)
|
||||
}
|
||||
export const ConfigurationConsumer = ConfigurationContext.Consumer
|
||||
export default ConfigurationContext
|
|
@ -0,0 +1,298 @@
|
|||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable react/prop-types */
|
||||
import { useQuery } from '@apollo/react-hooks'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import * as Location from 'expo-location'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { updateLocation } from '../apollo/mutations'
|
||||
import {
|
||||
assignedOrders,
|
||||
profile,
|
||||
subscriptionAssignRider,
|
||||
subscriptionUnAssignedOrder,
|
||||
unassignedOrders
|
||||
} from '../apollo/queries'
|
||||
|
||||
const PROFILE = gql`
|
||||
${profile}
|
||||
`
|
||||
const ASSIGNED_ORDERS = gql`
|
||||
${assignedOrders}
|
||||
`
|
||||
const SUBSCRIPTION_RIDER_ORDER = gql`
|
||||
${subscriptionAssignRider}
|
||||
`
|
||||
const UNASSIGNED_ORDERS = gql`
|
||||
${unassignedOrders}
|
||||
`
|
||||
const SUBSCRIPTION_UNASSIGNED_ORDER = gql`
|
||||
${subscriptionUnAssignedOrder}
|
||||
`
|
||||
|
||||
const UPDATE_LOCATION = gql`
|
||||
${updateLocation}
|
||||
`
|
||||
|
||||
const UserContext = React.createContext({})
|
||||
|
||||
export const UserProvider = props => {
|
||||
const [token, setToken] = useState()
|
||||
const [profile, setProfile] = useState({ isLoggedIn: false })
|
||||
const [assignedOrders, setAssignedOrders] = useState([])
|
||||
const [unAssignedOrders, setUnAssignedOrders] = useState([])
|
||||
const locationListener = useRef()
|
||||
const {
|
||||
client,
|
||||
loading: loadingProfile,
|
||||
error: errorProfile,
|
||||
data: dataProfile
|
||||
} = useQuery(PROFILE, {
|
||||
fetchPolicy: 'network-only',
|
||||
onCompleted,
|
||||
onError
|
||||
})
|
||||
const {
|
||||
loading: loadingAssigned,
|
||||
error: errorAssigned,
|
||||
networkStatus: networkStatusAssigned,
|
||||
subscribeToMore: subscribeToMoreAssigned,
|
||||
refetch: refetchAssigned,
|
||||
data: dataAssigned
|
||||
} = useQuery(ASSIGNED_ORDERS, {
|
||||
onCompleted,
|
||||
onError,
|
||||
fetchPolicy: 'network-only',
|
||||
notifyOnNetworkStatusChange: true
|
||||
})
|
||||
const {
|
||||
loading: loadingUnAssigned,
|
||||
error: errorUnAssigned,
|
||||
networkStatus: networkStatusUnAssigned,
|
||||
subscribeToMore: subscribeToMoreUnAssigned,
|
||||
refetch: refetchUnAssigned,
|
||||
data: dataUnassigned
|
||||
} = useQuery(UNASSIGNED_ORDERS, {
|
||||
onCompleted,
|
||||
onError,
|
||||
fetchPolicy: 'network-only',
|
||||
notifyOnNetworkStatusChange: true
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
locationListener.current && locationListener.current.remove()
|
||||
}
|
||||
}, [])
|
||||
|
||||
// useEffect(() => {
|
||||
// let isSubscribed = true;
|
||||
// (async () => {
|
||||
// const token = await AsyncStorage.getItem('rider-token')
|
||||
// isSubscribed && setToken(token)
|
||||
// })()
|
||||
// return () => {
|
||||
// isSubscribed = false
|
||||
// }
|
||||
// }, [])
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!token) return
|
||||
// let isSubscribed = true
|
||||
// ; (async () => {
|
||||
// isSubscribed && fetchProfile()
|
||||
// isSubscribed && fetchAssigned()
|
||||
// isSubscribed && fetchUnAssigned()
|
||||
// isSubscribed && trackRiderLocation()
|
||||
// })()
|
||||
// return () => {
|
||||
// isSubscribed = false
|
||||
// }
|
||||
// }, [token])
|
||||
let unsubscribeAssignedOrders = null
|
||||
let unsubscribeUnAssignedOrders = null
|
||||
useEffect(() => {
|
||||
if (!dataProfile) return
|
||||
unsubscribeAssignedOrders = subscribeAssignedOrders()
|
||||
unsubscribeUnAssignedOrders = subscribeUnAssignedOrders()
|
||||
trackRiderLocation()
|
||||
|
||||
return () => {
|
||||
unsubscribeAssignedOrders && unsubscribeAssignedOrders()
|
||||
unsubscribeUnAssignedOrders && unsubscribeUnAssignedOrders()
|
||||
}
|
||||
}, [dataProfile])
|
||||
|
||||
function onCompleted({ rider, assignedOrders, unassignedOrders }) {
|
||||
// if (rider) {
|
||||
// setProfile({ ...rider, isLoggedIn: true })
|
||||
// } else if (assignedOrders) {
|
||||
// setAssignedOrders(assignedOrders)
|
||||
// } else if (unassignedOrders) {
|
||||
// setUnAssignedOrders(unassignedOrders)
|
||||
// }
|
||||
// if (dataProfile && dataUnassigned && dataAssigned) {
|
||||
// getNotificationData()
|
||||
// }
|
||||
}
|
||||
|
||||
function onError(error) {
|
||||
console.log('error on fetching context', error)
|
||||
}
|
||||
|
||||
const trackRiderLocation = async () => {
|
||||
const { status } = await Location.requestForegroundPermissionsAsync()
|
||||
if (status === 'granted') {
|
||||
if (locationListener.current) locationListener.current.remove()
|
||||
locationListener.current = await Location.watchPositionAsync(
|
||||
{
|
||||
accuracy: Location.Accuracy.BestForNavigation,
|
||||
timeInterval: 60000,
|
||||
distanceInterval: 20
|
||||
},
|
||||
async ({ coords: { latitude, longitude }, error }) => {
|
||||
try {
|
||||
await client.mutate({
|
||||
mutation: UPDATE_LOCATION,
|
||||
variables: {
|
||||
latitude: latitude.toString(),
|
||||
longitude: longitude.toString()
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('error', JSON.stringify(error))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const subscribeAssignedOrders = () => {
|
||||
try {
|
||||
return subscribeToMoreAssigned({
|
||||
document: SUBSCRIPTION_RIDER_ORDER,
|
||||
variables: { riderId: dataProfile.rider._id },
|
||||
updateQuery: (prev, { subscriptionData }) => {
|
||||
if (!subscriptionData.data) return prev
|
||||
|
||||
if (subscriptionData.data.subscriptionAssignRider.origin === 'new') {
|
||||
setAssignedOrders([
|
||||
subscriptionData.data.subscriptionAssignRider.order,
|
||||
...prev.assignedOrders
|
||||
])
|
||||
return {
|
||||
assignedOrders: [
|
||||
subscriptionData.data.subscriptionAssignRider.order,
|
||||
...prev.assignedOrders
|
||||
]
|
||||
}
|
||||
} else {
|
||||
const { assignedOrders } = prev
|
||||
const {
|
||||
orderStatus,
|
||||
_id
|
||||
} = subscriptionData.data.subscriptionAssignRider.order
|
||||
const orderIndex = assignedOrders.findIndex(o => o._id === _id)
|
||||
if (orderIndex > -1) {
|
||||
if (orderStatus === 'DELIVERED' || orderStatus === 'CANCELLED') {
|
||||
assignedOrders.splice(orderIndex, 1)
|
||||
} else {
|
||||
assignedOrders[orderIndex].orderStatus = orderStatus
|
||||
}
|
||||
}
|
||||
setAssignedOrders([...assignedOrders])
|
||||
return {
|
||||
assignedOrders: [...assignedOrders]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('error subscribe assigned orders', error)
|
||||
}
|
||||
}
|
||||
|
||||
const subscribeUnAssignedOrders = () => {
|
||||
try {
|
||||
return subscribeToMoreUnAssigned({
|
||||
document: SUBSCRIPTION_UNASSIGNED_ORDER,
|
||||
updateQuery: (prev, { subscriptionData }) => {
|
||||
if (!subscriptionData.data) return prev
|
||||
|
||||
if (subscriptionData.data.unassignedOrder.origin === 'new') {
|
||||
setUnAssignedOrders([
|
||||
subscriptionData.data.unassignedOrder.order,
|
||||
...prev.unassignedOrders
|
||||
])
|
||||
return {
|
||||
unassignedOrders: [
|
||||
subscriptionData.data.unassignedOrder.order,
|
||||
...prev.unassignedOrders
|
||||
]
|
||||
}
|
||||
} else {
|
||||
const { _id } = subscriptionData.data.unassignedOrder.order
|
||||
const { unassignedOrders } = prev
|
||||
const orderIndex = unassignedOrders.findIndex(o => o._id === _id)
|
||||
if (orderIndex > -1) {
|
||||
unassignedOrders.splice(orderIndex, 1)
|
||||
}
|
||||
setUnAssignedOrders([...unassignedOrders])
|
||||
return {
|
||||
unassignedOrders: [...unassignedOrders]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const setTokenAsync = async token => {
|
||||
await AsyncStorage.setItem('rider-token', token)
|
||||
setToken(token)
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
try {
|
||||
// await Location.stopLocationUpdatesAsync('RIDER_LOCATION')
|
||||
await AsyncStorage.removeItem('rider-token')
|
||||
setToken(null)
|
||||
setProfile({ isLoggedIn: false })
|
||||
setAssignedOrders([])
|
||||
setUnAssignedOrders([])
|
||||
} catch (error) {
|
||||
console.log('error on logout', error)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<UserContext.Provider
|
||||
value={{
|
||||
loadingProfile: loadingProfile,
|
||||
errorProfile,
|
||||
profile: loadingProfile || errorProfile ? null : dataProfile.rider,
|
||||
logout,
|
||||
setTokenAsync,
|
||||
loadingAssigned,
|
||||
errorAssigned,
|
||||
assignedOrders:
|
||||
loadingAssigned || errorAssigned ? [] : dataAssigned.assignedOrders,
|
||||
refetchAssigned,
|
||||
networkStatusAssigned,
|
||||
loadingUnAssigned,
|
||||
errorUnAssigned,
|
||||
unAssignedOrders:
|
||||
loadingUnAssigned || errorUnAssigned
|
||||
? []
|
||||
: dataUnassigned.unassignedOrders,
|
||||
refetchUnAssigned,
|
||||
networkStatusUnAssigned
|
||||
}}>
|
||||
{props.children}
|
||||
</UserContext.Provider>
|
||||
)
|
||||
}
|
||||
export const UserConsumer = UserContext.Consumer
|
||||
export default UserContext
|
|
@ -0,0 +1,196 @@
|
|||
import { createDrawerNavigator } from '@react-navigation/drawer'
|
||||
import { NavigationContainer } from '@react-navigation/native'
|
||||
import { createStackNavigator } from '@react-navigation/stack'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import React, { useContext, useEffect } from 'react'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import { LeftButton } from '../components/Header/HeaderIcons/HeaderIcons'
|
||||
import Sidebar from '../components/Sidebar/Sidebar'
|
||||
import { AuthContext } from '../context/auth'
|
||||
import { UserProvider } from '../context/user'
|
||||
import {
|
||||
Chat,
|
||||
Help,
|
||||
HelpBrowser,
|
||||
Language,
|
||||
Login,
|
||||
OrderDetail,
|
||||
Orders
|
||||
} from '../screens'
|
||||
import colors from '../utilities/colors'
|
||||
import { ICONS_NAME, NAVIGATION_SCREEN } from '../utilities/constant'
|
||||
import navigationService from './navigationService'
|
||||
import { screenOptions } from './screenOptions'
|
||||
import styles from './styles'
|
||||
|
||||
const Stack = createStackNavigator()
|
||||
const Drawer = createDrawerNavigator()
|
||||
|
||||
function Auth() {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={screenOptions({ textColor: colors.fontMainColor })}>
|
||||
<Stack.Screen name={NAVIGATION_SCREEN.Login} component={Login} />
|
||||
</Stack.Navigator>
|
||||
)
|
||||
}
|
||||
function Main() {
|
||||
let listener = null
|
||||
let animatedStyle = {}
|
||||
let opacity
|
||||
let OuterWindowSlide, InnerWindowSlide
|
||||
useEffect(() => {
|
||||
// if (!loadingProfile && !loadingAssigned && !loadingUnAssigned)
|
||||
listener = Notifications.addNotificationReceivedListener(
|
||||
_handleNotification
|
||||
)
|
||||
return () => {
|
||||
listener && listener.remove()
|
||||
}
|
||||
}, [])
|
||||
|
||||
function _handleNotification(notification) {
|
||||
try {
|
||||
if (notification.origin === 'selected') {
|
||||
if (notification.data.order) {
|
||||
navigationService.navigate('OrderDetail', {
|
||||
id: notification.data._id
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: false,
|
||||
shouldSetBadge: false
|
||||
})
|
||||
})
|
||||
const subscription = Notifications.addNotificationResponseReceivedListener(
|
||||
_handleNotification
|
||||
)
|
||||
return () => subscription.remove()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<UserProvider>
|
||||
<Drawer.Navigator
|
||||
drawerStyle={{
|
||||
flex: 1,
|
||||
backgroundColor: colors.fontMainColor,
|
||||
width: '60%',
|
||||
justifyContent: 'space-between',
|
||||
borderRightWidth: 0,
|
||||
shadowOpacity: 0,
|
||||
elevation: 0
|
||||
}}
|
||||
sceneContainerStyle={{ backgroundColor: colors.fontMainColor }}
|
||||
overlayColor="transparent"
|
||||
drawerType="slide"
|
||||
drawerContent={props => {
|
||||
const scale = Animated.interpolateNode(props.progress, {
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1, 0.7]
|
||||
})
|
||||
const Animatedopacity = Animated.interpolateNode(props.progress, {
|
||||
inputRange: [0, 0.6, 1],
|
||||
outputRange: [0, 0, 1]
|
||||
})
|
||||
const AnimatedOuterSlide = Animated.interpolateNode(props.progress, {
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, -35]
|
||||
})
|
||||
const AnimatedInnerSlide = Animated.interpolateNode(props.progress, {
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, -15]
|
||||
})
|
||||
const borderRadius = Animated.interpolateNode(props.progress, {
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, 20]
|
||||
})
|
||||
animatedStyle = { borderRadius, transform: [{ scale }] }
|
||||
opacity = Animatedopacity
|
||||
OuterWindowSlide = AnimatedOuterSlide
|
||||
InnerWindowSlide = AnimatedInnerSlide
|
||||
return <Sidebar {...props} />
|
||||
}}>
|
||||
<Drawer.Screen name="noDrawer">
|
||||
{props => (
|
||||
<NoDrawer
|
||||
{...props}
|
||||
style={animatedStyle}
|
||||
opacity={opacity}
|
||||
OuterWindowSlide={OuterWindowSlide}
|
||||
InnerWindowSlide={InnerWindowSlide}
|
||||
/>
|
||||
)}
|
||||
</Drawer.Screen>
|
||||
</Drawer.Navigator>
|
||||
</UserProvider>
|
||||
)
|
||||
}
|
||||
function NoDrawer({ style, opacity = 1, OuterWindowSlide, InnerWindowSlide }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Animated.View
|
||||
style={[styles.outerView, style, { marginLeft: OuterWindowSlide }]}
|
||||
/>
|
||||
<Animated.View
|
||||
style={[styles.innerView, style, { marginLeft: InnerWindowSlide }]}
|
||||
/>
|
||||
<Animated.View style={[styles.animatedView, style]}>
|
||||
<Stack.Navigator
|
||||
headerMode="screen"
|
||||
initialRouteName={NAVIGATION_SCREEN.Orders}
|
||||
screenOptions={screenOptions({
|
||||
textColor: colors.fontSecondColor
|
||||
})}>
|
||||
<Stack.Screen
|
||||
name={NAVIGATION_SCREEN.Orders}
|
||||
component={Orders}
|
||||
options={{
|
||||
headerLeft: () => (
|
||||
<LeftButton
|
||||
icon={ICONS_NAME.Menu}
|
||||
iconColor={colors.fontSecondColor}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name={NAVIGATION_SCREEN.OrderDetail}
|
||||
component={OrderDetail}
|
||||
/>
|
||||
<Stack.Screen name={NAVIGATION_SCREEN.Help} component={Help} />
|
||||
<Stack.Screen
|
||||
name={NAVIGATION_SCREEN.Language}
|
||||
component={Language}
|
||||
/>
|
||||
<Stack.Screen name={NAVIGATION_SCREEN.Chat} component={Chat} />
|
||||
<Stack.Screen
|
||||
name={NAVIGATION_SCREEN.HelpBrowser}
|
||||
component={HelpBrowser}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</Animated.View>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
function AppContainer() {
|
||||
const { token } = useContext(AuthContext)
|
||||
return (
|
||||
// <SafeAreaProvider>
|
||||
<NavigationContainer
|
||||
ref={ref => {
|
||||
navigationService.setGlobalRef(ref)
|
||||
}}>
|
||||
{token ? <Main /> : <Auth />}
|
||||
</NavigationContainer>
|
||||
// </SafeAreaProvider>
|
||||
)
|
||||
}
|
||||
export default AppContainer
|
|
@ -0,0 +1,19 @@
|
|||
let navObj = null
|
||||
|
||||
function setGlobalRef(ref) {
|
||||
navObj = ref
|
||||
}
|
||||
|
||||
function navigate(path, props = {}) {
|
||||
navObj.navigate(path, props)
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
navObj.goBack()
|
||||
}
|
||||
|
||||
export default {
|
||||
setGlobalRef,
|
||||
navigate,
|
||||
goBack
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* eslint-disable react/prop-types */
|
||||
import { TransitionPresets } from '@react-navigation/stack'
|
||||
import React from 'react'
|
||||
import { LeftButton } from '../components'
|
||||
import { ICONS_NAME } from '../utilities/constant'
|
||||
import { scale } from '../utilities/scaling'
|
||||
import { textStyles } from '../utilities/textStyles'
|
||||
|
||||
const screenOptions = props => ({
|
||||
headerTitleAlign: 'center',
|
||||
headerBackTitleVisible: false,
|
||||
headerTransparent: true,
|
||||
headerStyle: {
|
||||
elevation: 0,
|
||||
shadowOpacity: 0,
|
||||
borderBottomWidth: 0
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: props && props.textColor,
|
||||
...textStyles.H3,
|
||||
...textStyles.Bold,
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
headerTitleContainerStyle: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: scale(80)
|
||||
},
|
||||
headerLeft: () => <LeftButton icon={ICONS_NAME.Back} />,
|
||||
...TransitionPresets.SlideFromRightIOS
|
||||
})
|
||||
|
||||
export { screenOptions }
|
|
@ -0,0 +1,68 @@
|
|||
import { StyleSheet } from 'react-native'
|
||||
import colors from '../utilities/colors'
|
||||
import { scale } from '../utilities/scaling'
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
badge: {
|
||||
position: 'absolute',
|
||||
right: -scale(6),
|
||||
top: 0,
|
||||
borderRadius: scale(9),
|
||||
width: scale(18),
|
||||
height: scale(18),
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
outerView: {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '80%',
|
||||
top: '10%',
|
||||
left: 10,
|
||||
bottom: 0,
|
||||
backgroundColor: colors.fontMainColor,
|
||||
shadowColor: 'black',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 5
|
||||
},
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 3,
|
||||
elevation: 10
|
||||
},
|
||||
innerView: {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '90%',
|
||||
top: '5%',
|
||||
bottom: 0,
|
||||
backgroundColor: colors.fontMainColor,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 5
|
||||
},
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 3,
|
||||
elevation: 10
|
||||
},
|
||||
animatedView: {
|
||||
flex: 1,
|
||||
overflow: 'hidden',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 5
|
||||
},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 10,
|
||||
elevation: 15
|
||||
},
|
||||
closeView: {
|
||||
position: 'absolute',
|
||||
top: 70,
|
||||
left: 50
|
||||
}
|
||||
})
|
||||
|
||||
export default styles
|
|
@ -0,0 +1,211 @@
|
|||
import { Feather, FontAwesome } from '@expo/vector-icons'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { Keyboard, View } from 'react-native'
|
||||
import {
|
||||
Bubble,
|
||||
GiftedChat,
|
||||
InputToolbar,
|
||||
Send
|
||||
} from 'react-native-gifted-chat'
|
||||
import { MainWrapper, TextDefault } from '../../components'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
import useStyle from './styles'
|
||||
|
||||
const UserInfo = {
|
||||
_id: 1,
|
||||
name: 'Jason',
|
||||
active: true
|
||||
}
|
||||
|
||||
function Chat() {
|
||||
const styles = useStyle()
|
||||
const navigation = useNavigation()
|
||||
const [messages, setMessages] = useState([])
|
||||
const [isTyping, setIsTyping] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
Keyboard.addListener('keyboardDidShow', _keyboardDidShow)
|
||||
Keyboard.addListener('keyboardDidHide', _keyboardDidHide)
|
||||
|
||||
// cleanup function
|
||||
return () => {
|
||||
Keyboard.removeListener('keyboardDidShow', _keyboardDidShow)
|
||||
Keyboard.removeListener('keyboardDidHide', _keyboardDidHide)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const _keyboardDidShow = () => setIsTyping(true)
|
||||
const _keyboardDidHide = () => setIsTyping(false)
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: 'Chat'
|
||||
})
|
||||
setMessages([
|
||||
{
|
||||
_id: 1,
|
||||
text: 'How can I help you?',
|
||||
sent: true,
|
||||
received: true,
|
||||
createdAt: new Date(),
|
||||
user: {
|
||||
_id: 2,
|
||||
name: 'React Native',
|
||||
avatar: 'https://placeimg.com/140/140/any'
|
||||
}
|
||||
}
|
||||
])
|
||||
}, [navigation])
|
||||
|
||||
const onSend = useCallback((messages = []) => {
|
||||
setMessages(previousMessages =>
|
||||
GiftedChat.append(previousMessages, messages)
|
||||
)
|
||||
}, [])
|
||||
|
||||
const renderBubble = props => {
|
||||
return (
|
||||
<Bubble
|
||||
{...props}
|
||||
textStyle={{
|
||||
right: {
|
||||
color: colors.fontMainColor
|
||||
},
|
||||
left: {
|
||||
color: colors.fontMainColor
|
||||
}
|
||||
}}
|
||||
bottomContainerStyle={{
|
||||
right: {
|
||||
...alignment.PTxSmall
|
||||
},
|
||||
left: {
|
||||
...alignment.PTxSmall
|
||||
}
|
||||
}}
|
||||
wrapperStyle={{
|
||||
right: {
|
||||
minWidth: 150,
|
||||
backgroundColor: colors.yellowishOrange,
|
||||
borderTopRightRadius: scale(15),
|
||||
borderTopLeftRadius: scale(15),
|
||||
borderBottomLeftRadius: scale(15),
|
||||
borderBottomRightRadius: 0,
|
||||
...alignment.MVxSmall,
|
||||
...alignment.PVxSmall,
|
||||
shadowColor: colors.black,
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 1
|
||||
},
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 2,
|
||||
elevation: 3
|
||||
},
|
||||
left: {
|
||||
minWidth: 150,
|
||||
backgroundColor: colors.lightBackground,
|
||||
borderTopRightRadius: scale(15),
|
||||
borderTopLeftRadius: scale(15),
|
||||
borderBottomRightRadius: scale(15),
|
||||
borderBottomLeftRadius: 0,
|
||||
...alignment.MVxSmall,
|
||||
...alignment.PVxSmall,
|
||||
shadowColor: colors.black,
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 1
|
||||
},
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 2,
|
||||
elevation: 3
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const renderSend = props => (
|
||||
<Send {...props} containerStyle={styles.sendBtn}>
|
||||
<View style={styles.rightBtn}>
|
||||
<Feather
|
||||
name={'send'}
|
||||
color={colors.buttonText}
|
||||
size={scale(17)}
|
||||
style={{
|
||||
transform: [
|
||||
{ rotateZ: '45deg' },
|
||||
{ translateY: 2 },
|
||||
{ translateX: -1 }
|
||||
]
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Send>
|
||||
)
|
||||
const customtInputToolbar = props => {
|
||||
return (
|
||||
<InputToolbar
|
||||
{...props}
|
||||
containerStyle={styles.inputContainer}
|
||||
renderSend={renderSend}
|
||||
render
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<MainWrapper>
|
||||
<View style={[styles.flex, styles.mainContainer]}>
|
||||
<View style={styles.header}>
|
||||
<FontAwesome
|
||||
name="circle"
|
||||
color={UserInfo.active ? colors.iconPink : colors.fontSecondColor}
|
||||
/>
|
||||
<TextDefault medium H5 style={alignment.PLsmall}>
|
||||
{UserInfo.active ? UserInfo.name : 'Offline'}
|
||||
</TextDefault>
|
||||
</View>
|
||||
<GiftedChat
|
||||
inverted
|
||||
alwaysShowSend
|
||||
user={UserInfo}
|
||||
isTyping={isTyping}
|
||||
messages={messages}
|
||||
onSend={messages => onSend(messages)}
|
||||
renderAvatar={() => null}
|
||||
renderBubble={renderBubble}
|
||||
renderInputToolbar={customtInputToolbar}
|
||||
textInputStyle={styles.inputStyle}
|
||||
minInputToolbarHeight={60}
|
||||
// renderFooter={() =>
|
||||
// isTyping ? (
|
||||
// <TextDefault
|
||||
// textColor={colors.selected}
|
||||
// style={[alignment.PLlarge, alignment.MBsmall]}>
|
||||
// User is typing...
|
||||
// </TextDefault>
|
||||
// ) : null
|
||||
// }
|
||||
timeTextStyle={{
|
||||
left: {
|
||||
width: '100%',
|
||||
color: colors.fontMainColor,
|
||||
fontSize: 11,
|
||||
textAlign: 'right'
|
||||
},
|
||||
right: {
|
||||
color: colors.fontMainColor,
|
||||
fontSize: 11
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</MainWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default Chat
|
|
@ -0,0 +1,63 @@
|
|||
import { Platform, StyleSheet } from 'react-native'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
|
||||
const useStyle = () => {
|
||||
return StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1
|
||||
},
|
||||
mainContainer: {
|
||||
marginTop: 30,
|
||||
backgroundColor: colors.cartContainer,
|
||||
borderTopEndRadius: scale(20),
|
||||
borderTopStartRadius: scale(20),
|
||||
shadowColor: colors.shadowColor,
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: -5
|
||||
},
|
||||
shadowOpacity: 0.4,
|
||||
shadowRadius: 10,
|
||||
elevation: 5,
|
||||
...alignment.Plarge
|
||||
},
|
||||
header: {
|
||||
// backgroundColor: 'blue',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
...alignment.PBmedium,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: colors.horizontalLine
|
||||
},
|
||||
rightBtn: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: colors.buttonBackground,
|
||||
width: scale(30),
|
||||
aspectRatio: 1,
|
||||
borderRadius: scale(10)
|
||||
},
|
||||
sendBtn: {
|
||||
justifyContent: 'center'
|
||||
},
|
||||
inputContainer: {
|
||||
backgroundColor: colors.lightBackground,
|
||||
borderTopWidth: 0,
|
||||
minHeight: scale(48),
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: scale(25),
|
||||
...alignment.PRsmall,
|
||||
...alignment.PLxSmall
|
||||
},
|
||||
inputStyle: {
|
||||
paddingTop: Platform.OS === 'ios' ? 8 : -8,
|
||||
paddingBottom: 0,
|
||||
textAlignVertical: 'center'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default useStyle
|
|
@ -0,0 +1,54 @@
|
|||
import { AntDesign } from '@expo/vector-icons'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import React, { useLayoutEffect } from 'react'
|
||||
import { TouchableOpacity, View } from 'react-native'
|
||||
import i18n from '../../../i18n'
|
||||
import { MainWrapper, TextDefault } from '../../components'
|
||||
import colors from '../../utilities/colors'
|
||||
import { scale, verticalScale } from '../../utilities/scaling'
|
||||
import styles from './styles'
|
||||
|
||||
const links = [
|
||||
{
|
||||
title: 'Product Page',
|
||||
url:
|
||||
'https://market.nativebase.io/view/react-native-food-delivery-backend-app'
|
||||
},
|
||||
{ title: 'Docs', url: 'https://enatega.gitbook.io/enatega-full-app/' },
|
||||
{
|
||||
title: 'Blog',
|
||||
url:
|
||||
'https://blog.nativebase.io/enatega-full-food-delivery-app-is-finally-here-a6039de4a09d'
|
||||
},
|
||||
{ title: 'About Us', url: 'https://ninjascode.com/pages/ourteam.html' }
|
||||
]
|
||||
function Help() {
|
||||
const navigation = useNavigation()
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: null,
|
||||
headerTitle: i18n.t('titleHelp')
|
||||
})
|
||||
}, [navigation])
|
||||
|
||||
return (
|
||||
<MainWrapper>
|
||||
<View style={{ marginTop: verticalScale(20) }} />
|
||||
{links.map(({ title, url }, index) => (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
onPress={() => navigation.navigate('HelpBrowser', { title, url })}
|
||||
style={styles.itemContainer}
|
||||
key={index}>
|
||||
<TextDefault textColor={colors.fontMainColor} H4>
|
||||
{title}
|
||||
</TextDefault>
|
||||
<AntDesign name="arrowright" size={scale(20)} />
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</MainWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default Help
|
|
@ -0,0 +1,33 @@
|
|||
import { StyleSheet } from 'react-native'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { moderateScale, verticalScale } from '../../utilities/scaling'
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.themeBackground
|
||||
},
|
||||
itemContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '90%',
|
||||
alignSelf: 'center',
|
||||
backgroundColor: colors.themeBackground,
|
||||
borderRadius: moderateScale(10),
|
||||
elevation: 2,
|
||||
shadowColor: 'blue',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: verticalScale(2)
|
||||
},
|
||||
borderColor: 'black',
|
||||
shadowOpacity: 0.1,
|
||||
...alignment.PTlarge,
|
||||
...alignment.PBlarge,
|
||||
...alignment.PLlarge,
|
||||
...alignment.PRlarge,
|
||||
...alignment.MBlarge
|
||||
}
|
||||
})
|
||||
export default styles
|
|
@ -0,0 +1,29 @@
|
|||
import { useNavigation, useRoute } from '@react-navigation/native'
|
||||
import React, { useLayoutEffect } from 'react'
|
||||
import { WebView } from 'react-native-webview'
|
||||
import { MainWrapper, Spinner } from '../../components'
|
||||
|
||||
function HelpBrowser() {
|
||||
const navigation = useNavigation()
|
||||
const route = useRoute()
|
||||
const { title, url } = route.params
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: null,
|
||||
headerTitle: title
|
||||
})
|
||||
}, [navigation])
|
||||
|
||||
return (
|
||||
<MainWrapper>
|
||||
<WebView
|
||||
source={{ uri: url }}
|
||||
startInLoadingState={true}
|
||||
renderLoading={() => <Spinner />}
|
||||
/>
|
||||
</MainWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default HelpBrowser
|
|
@ -0,0 +1,139 @@
|
|||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import * as Localization from 'expo-localization'
|
||||
import * as Updates from 'expo-updates'
|
||||
import React, { useEffect, useLayoutEffect, useState } from 'react'
|
||||
import { Platform, TouchableOpacity, View } from 'react-native'
|
||||
import i18n from '../../../i18n'
|
||||
import { MainWrapper } from '../../components'
|
||||
import RadioButton from '../../components/FdRadioBtn/RadioBtn'
|
||||
import TextDefault from '../../components/Text/TextDefault/TextDefault'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
import styles from './styles'
|
||||
|
||||
const languageTypes = [
|
||||
{ value: 'English', code: 'en', index: 0 },
|
||||
{ value: 'français', code: 'fr', index: 1 },
|
||||
{ value: 'ភាសាខ្មែរ', code: 'km', index: 2 },
|
||||
{ value: '中文', code: 'zh', index: 3 },
|
||||
{ value: 'Deutsche', code: 'de', index: 4 }
|
||||
]
|
||||
|
||||
function Language() {
|
||||
const navigation = useNavigation()
|
||||
const [activeRadio, setActiveRadio] = useState(languageTypes[0].index)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [languageName, languageNameSetter] = useState('English')
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: i18n.t('titleLanguage')
|
||||
})
|
||||
}, [navigation])
|
||||
|
||||
useEffect(() => {
|
||||
selectedLanguageFunc()
|
||||
}, [])
|
||||
|
||||
async function selectedLanguageFunc() {
|
||||
const lang = await AsyncStorage.getItem('enatega-language')
|
||||
if (lang) {
|
||||
const defLang = languageTypes.findIndex(el => el.code === lang)
|
||||
const langName = languageTypes[defLang].value
|
||||
setActiveRadio(defLang)
|
||||
languageNameSetter(langName)
|
||||
}
|
||||
}
|
||||
|
||||
async function onSelectedLanguage() {
|
||||
const languageInd = activeRadio
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
const localization = await Localization.getLocalizationAsync()
|
||||
localization.locale = languageTypes[languageInd].code
|
||||
await AsyncStorage.setItem(
|
||||
'enatega-language',
|
||||
languageTypes[languageInd].code
|
||||
)
|
||||
try {
|
||||
Updates.reloadAsync()
|
||||
} catch (error) {
|
||||
console.log('err', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<MainWrapper>
|
||||
<View style={[styles.flex, styles.mainView]}>
|
||||
<View style={[styles.languageContainer]}>
|
||||
{languageTypes.map((item, index) => (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
key={index}
|
||||
onPress={() => setActiveRadio(item.index)}
|
||||
style={[styles.radioContainer]}>
|
||||
<TextDefault
|
||||
numberOfLines={1}
|
||||
textColor={
|
||||
activeRadio === item.index
|
||||
? colors.fontMainColor
|
||||
: colors.placeHolderColor
|
||||
}
|
||||
bold
|
||||
H5
|
||||
style={alignment.MLsmall}>
|
||||
{item.value}
|
||||
</TextDefault>
|
||||
<RadioButton
|
||||
animation={'bounceIn'}
|
||||
size={13}
|
||||
outerColor={colors.tagColor}
|
||||
innerColor={colors.radioColor}
|
||||
isSelected={activeRadio === item.index}
|
||||
onPress={() => setActiveRadio(item.index)}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
onPress={() => onSelectedLanguage()}
|
||||
style={{
|
||||
backgroundColor: colors.tagColor,
|
||||
width: '72%',
|
||||
borderRadius: scale(10),
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center',
|
||||
height: scale(40),
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<TextDefault H5 bold textColor={colors.fontSecondColor}>
|
||||
Done
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
onPress={() => navigation.goBack()}
|
||||
style={{
|
||||
width: '72%',
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center',
|
||||
height: scale(40),
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<TextDefault H5 bold textColor={colors.fontMainColor}>
|
||||
Cancel
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</MainWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default Language
|
|
@ -0,0 +1,73 @@
|
|||
import colors from '../../utilities/colors'
|
||||
import { verticalScale, scale } from '../../utilities/scaling'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import { StyleSheet } from 'react-native'
|
||||
|
||||
export default {
|
||||
flex: {
|
||||
flex: 1
|
||||
},
|
||||
mainView: {
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: colors.cartContainer
|
||||
},
|
||||
headingLanguage: {
|
||||
width: '85%',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
languageContainer: {
|
||||
width: '80%',
|
||||
alignSelf: 'center',
|
||||
...alignment.PRmedium,
|
||||
...alignment.PTsmall,
|
||||
...alignment.PBlarge,
|
||||
...alignment.PLmedium,
|
||||
...alignment.MTmedium
|
||||
},
|
||||
shadow: {
|
||||
shadowOffset: { width: 0, height: scale(2) },
|
||||
shadowColor: 'black',
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: scale(1),
|
||||
elevation: 2,
|
||||
borderWidth: 0.4,
|
||||
borderColor: '#e1e1e1'
|
||||
},
|
||||
changeLanguage: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
height: verticalScale(40)
|
||||
},
|
||||
button: {
|
||||
width: '15%',
|
||||
height: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
modalContainer: {
|
||||
width: '100%',
|
||||
backgroundColor: colors.cartContainer,
|
||||
borderRadius: verticalScale(4),
|
||||
...alignment.Plarge
|
||||
},
|
||||
radioContainer: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: colors.horizontalLine,
|
||||
alignItems: 'center',
|
||||
...alignment.PTxSmall,
|
||||
...alignment.PBmedium,
|
||||
...alignment.MBmedium
|
||||
},
|
||||
modalButtonsContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
modalButtons: {
|
||||
...alignment.Msmall,
|
||||
marginBottom: 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import { View, ActivityIndicator } from 'react-native'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import colors from '../../utilities/colors'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
function Loading() {
|
||||
const navigation = useNavigation()
|
||||
useEffect(() => {
|
||||
loadData()
|
||||
}, [])
|
||||
async function loadData() {
|
||||
// ask permissions for app here
|
||||
await permissionForPushNotificationsAsync()
|
||||
checkAuthenticated()
|
||||
}
|
||||
async function permissionForPushNotificationsAsync() {
|
||||
const { status: existingStatus } = await Notifications.getPermissionsAsync()
|
||||
let finalStatus = existingStatus
|
||||
// only ask if permissions have not already been determined, because
|
||||
// iOS won't necessarily prompt the user a second time.
|
||||
if (existingStatus !== 'granted') {
|
||||
// Android remote notification permissions are granted during the app
|
||||
// install, so this will only ask on iOS
|
||||
const { status } = await Notifications.requestPermissionsAsync()
|
||||
finalStatus = status
|
||||
}
|
||||
|
||||
// Stop here if the user did not grant permissions
|
||||
if (finalStatus !== 'granted') {
|
||||
}
|
||||
}
|
||||
async function checkAuthenticated() {
|
||||
try {
|
||||
const userToken = await AsyncStorage.getItem('rider-token')
|
||||
if (userToken) {
|
||||
navigation.navigate('Drawer')
|
||||
return
|
||||
}
|
||||
} catch (error) {}
|
||||
await AsyncStorage.removeItem('rider-token')
|
||||
navigation.navigate('Auth', { screen: 'Login' })
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<ActivityIndicator size="large" color={colors.spinnerColor} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default Loading
|
|
@ -0,0 +1,186 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import Constants from 'expo-constants'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import {
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native'
|
||||
import { FilledTextField } from 'react-native-material-textfield'
|
||||
import Logo from '../../../assets/images/Svg/Logo'
|
||||
import i18n from '../../../i18n'
|
||||
import { riderLogin } from '../../apollo/mutations'
|
||||
import { Spinner, TextDefault, WrapperView } from '../../components'
|
||||
import { FlashMessage } from '../../components/FlashMessage/FlashMessage'
|
||||
import { AuthContext } from '../../context/auth'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
import useStyle from './styles'
|
||||
|
||||
const RIDER_LOGIN = gql`
|
||||
${riderLogin}
|
||||
`
|
||||
|
||||
export default function Login() {
|
||||
const styles = useStyle()
|
||||
const navigation = useNavigation()
|
||||
const [username, setUsername] = useState('rider')
|
||||
const [password, setPassword] = useState('123123')
|
||||
const [usernameError, setUsernameError] = useState('')
|
||||
const [passwordError, setPasswordError] = useState('')
|
||||
|
||||
const { setTokenAsync } = useContext(AuthContext)
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerLeft: null
|
||||
})
|
||||
}, [])
|
||||
|
||||
const [mutate, { loading }] = useMutation(RIDER_LOGIN, {
|
||||
onCompleted,
|
||||
onError
|
||||
})
|
||||
|
||||
function validateForm() {
|
||||
let res = true
|
||||
setUsernameError('')
|
||||
setPasswordError('')
|
||||
|
||||
if (!username) {
|
||||
setUsernameError('Username is required')
|
||||
res = false
|
||||
}
|
||||
if (!password) {
|
||||
setPasswordError('Password is required')
|
||||
res = false
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async function onCompleted(data) {
|
||||
FlashMessage({
|
||||
message: 'Logged in'
|
||||
})
|
||||
await AsyncStorage.setItem('rider-id', data.riderLogin.userId)
|
||||
setTokenAsync(data.riderLogin.token)
|
||||
}
|
||||
function onError({ networkError, graphQLErrors }) {
|
||||
console.log('errors', networkError, graphQLErrors)
|
||||
// let message = ''
|
||||
// if (!!graphQLErrors && graphQLErrors.length) {
|
||||
// message = graphQLErrors[0].message
|
||||
// }
|
||||
// if (!!networkError) {
|
||||
// message = networkError.result.errors[0].message
|
||||
// }
|
||||
// FlashMessage({
|
||||
// message: message
|
||||
// })
|
||||
}
|
||||
|
||||
return (
|
||||
<WrapperView>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.flex}>
|
||||
<ScrollView
|
||||
style={styles.flex}
|
||||
contentContainerStyle={styles.scrollContent}>
|
||||
<View style={[styles.flex, styles.container]}>
|
||||
<Logo width={scale(130)} height={scale(130)} />
|
||||
<View style={styles.width100}>
|
||||
<TextDefault
|
||||
style={alignment.MBmedium}
|
||||
textColor={colors.placeHolderColor}>
|
||||
Enter your Email and Password
|
||||
</TextDefault>
|
||||
<FilledTextField
|
||||
defaultValue={'rider'}
|
||||
error={usernameError}
|
||||
keyboardType={'email-address'}
|
||||
label={'Email or Phone'}
|
||||
labelFontSize={scale(12)}
|
||||
fontSize={scale(12)}
|
||||
activeLineWidth={0}
|
||||
labelHeight={10}
|
||||
lineWidth={0}
|
||||
textColor={colors.fontMainColor}
|
||||
baseColor={colors.fontMainColor}
|
||||
errorColor={colors.textErrorColor}
|
||||
tintColor={colors.tagColor}
|
||||
labelTextStyle={styles.labelStyle}
|
||||
inputContainerStyle={styles.textContainer}
|
||||
onChangeText={text => {
|
||||
setUsername(text.toLowerCase().trim())
|
||||
}}
|
||||
/>
|
||||
<View style={styles.mt15} />
|
||||
<FilledTextField
|
||||
defaultValue={'123123'}
|
||||
error={passwordError}
|
||||
label={'Password'}
|
||||
secureTextEntry
|
||||
labelFontSize={scale(12)}
|
||||
fontSize={scale(12)}
|
||||
activeLineWidth={0}
|
||||
labelHeight={10}
|
||||
lineWidth={0}
|
||||
textColor={colors.fontMainColor}
|
||||
baseColor={colors.fontMainColor}
|
||||
errorColor={colors.textErrorColor}
|
||||
tintColor={colors.tagColor}
|
||||
labelTextStyle={styles.labelStyle}
|
||||
inputContainerStyle={styles.textContainer}
|
||||
onChangeText={text => {
|
||||
setPassword(text.trim())
|
||||
}}
|
||||
/>
|
||||
<View style={[styles.lower_form]}>
|
||||
{loading && <Spinner />}
|
||||
{!loading && (
|
||||
<TouchableOpacity
|
||||
onPress={async () => {
|
||||
if (validateForm()) {
|
||||
let notificationToken = null
|
||||
if (Constants.isDevice) {
|
||||
const {
|
||||
status: existingStatus
|
||||
} = await Notifications.getPermissionsAsync()
|
||||
if (existingStatus === 'granted') {
|
||||
notificationToken = (
|
||||
await Notifications.getExpoPushTokenAsync()
|
||||
).data
|
||||
}
|
||||
}
|
||||
mutate({
|
||||
variables: {
|
||||
username: username.toLowerCase(),
|
||||
password: password,
|
||||
notificationToken
|
||||
}
|
||||
})
|
||||
}
|
||||
}}
|
||||
activeOpacity={0.5}
|
||||
style={[styles.RContainer]}>
|
||||
<TextDefault textColor={colors.fontMainColor} H5 bold>
|
||||
{i18n.t('loginBtn')}
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
</WrapperView>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import { Dimensions, StyleSheet } from 'react-native'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { moderateScale, scale, verticalScale } from '../../utilities/scaling'
|
||||
import { textStyles } from '../../utilities/textStyles'
|
||||
const { height } = Dimensions.get('window')
|
||||
|
||||
const useStyle = () => {
|
||||
return StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1
|
||||
},
|
||||
width100: { width: '100%' },
|
||||
bgColor: {
|
||||
backgroundColor: colors.themeBackground
|
||||
},
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
backgroundColor: colors.themeBackground
|
||||
},
|
||||
mt15: {
|
||||
marginTop: verticalScale(15)
|
||||
},
|
||||
container: {
|
||||
marginTop: 100,
|
||||
flexGrow: 1,
|
||||
width: '80%',
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingBottom: verticalScale(30)
|
||||
},
|
||||
lower_form: {
|
||||
alignItems: 'center',
|
||||
...alignment.MTlarge
|
||||
},
|
||||
RContainer: {
|
||||
width: '100%',
|
||||
height: height * 0.06,
|
||||
backgroundColor: colors.buttonBackgroundPink,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: moderateScale(10)
|
||||
},
|
||||
textContainer: {
|
||||
borderRadius: 10,
|
||||
borderTopLeftRadius: 10,
|
||||
borderTopRightRadius: 10,
|
||||
backgroundColor: colors.lightBackground,
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden'
|
||||
},
|
||||
labelStyle: {
|
||||
...textStyles.Bold,
|
||||
paddingLeft: 5,
|
||||
paddingTop: scale(1)
|
||||
}
|
||||
})
|
||||
}
|
||||
export default useStyle
|
|
@ -0,0 +1,59 @@
|
|||
import React, { useContext } from 'react'
|
||||
import { View, FlatList } from 'react-native'
|
||||
import Order from '../../components/Order/Order'
|
||||
import ConfigurationContext from '../../context/configuration'
|
||||
import UserContext from '../../context/user'
|
||||
import styles from './style'
|
||||
import { TextError, Spinner } from '../../components'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
export default function Orders() {
|
||||
const navigation = useNavigation()
|
||||
const configuration = useContext(ConfigurationContext)
|
||||
const {
|
||||
loadingUnAssigned,
|
||||
errorUnAssigned,
|
||||
unAssignedOrders,
|
||||
refetchUnAssigned,
|
||||
networkStatusUnAssigned
|
||||
} = useContext(UserContext)
|
||||
|
||||
function emptyView() {
|
||||
return <TextError text="No New Order" />
|
||||
}
|
||||
|
||||
if (loadingUnAssigned) return <Spinner />
|
||||
if (errorUnAssigned) return <TextError text="Something is worng" />
|
||||
|
||||
return (
|
||||
<View style={styles.flex}>
|
||||
<View style={styles.flex}>
|
||||
<FlatList
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
keyExtractor={item => item._id}
|
||||
data={
|
||||
unAssignedOrders.length > 0
|
||||
? unAssignedOrders.slice().reverse()
|
||||
: []
|
||||
}
|
||||
refreshing={networkStatusUnAssigned === 4}
|
||||
onRefresh={refetchUnAssigned}
|
||||
ListEmptyComponent={emptyView}
|
||||
renderItem={({ item }) => (
|
||||
<Order
|
||||
key={item._id}
|
||||
orderId={item.order_id}
|
||||
orderStatus={item.order_status}
|
||||
orderAmount={`${configuration.currency_symbol}${item.order_amount}`}
|
||||
orderDatetime={item.createdAt}
|
||||
paymentMethod={item.payment_method}
|
||||
onPress={() => {
|
||||
navigation.navigate('OrderDetail', { id: item._id })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
const styles = {
|
||||
flex: {
|
||||
flex: 1
|
||||
}
|
||||
}
|
||||
|
||||
export default styles
|
|
@ -0,0 +1,454 @@
|
|||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
||||
import { useNavigation, useRoute } from '@react-navigation/native'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useContext, useLayoutEffect } from 'react'
|
||||
import {
|
||||
Image,
|
||||
Linking,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native'
|
||||
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps'
|
||||
import { assignOrder, updateOrderStatusRider } from '../../apollo/mutations'
|
||||
import { assignedOrders, configuration } from '../../apollo/queries'
|
||||
import { MainWrapper, Spinner, TextDefault, TextError } from '../../components'
|
||||
import { FlashMessage } from '../../components//FlashMessage/FlashMessage'
|
||||
import UserContext from '../../context/user'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { linkToMapsApp } from '../../utilities/links'
|
||||
import { scale } from '../../utilities/scaling'
|
||||
import styles from './styles'
|
||||
|
||||
const CONFIGURATION = gql`
|
||||
${configuration}
|
||||
`
|
||||
const UPDATE_ORDER_STATUS = gql`
|
||||
${updateOrderStatusRider}
|
||||
`
|
||||
const ASSIGN_ORDER = gql`
|
||||
${assignOrder}
|
||||
`
|
||||
const ORDERS = gql`
|
||||
${assignedOrders}
|
||||
`
|
||||
const LATITUDE_DELTA = 0.0022
|
||||
const LONGITUDE_DELTA = 0.0021
|
||||
|
||||
function OrderDetail() {
|
||||
const navigation = useNavigation()
|
||||
const route = useRoute()
|
||||
const {
|
||||
unAssignedOrders,
|
||||
assignedOrders,
|
||||
loadingAssigned,
|
||||
loadingUnAssigned
|
||||
} = useContext(UserContext)
|
||||
|
||||
// const [selectedOrder, setOrder] = useState(selectedOrder)
|
||||
const selectedOrder =
|
||||
unAssignedOrders.find(o => o._id === route.params?.id) ||
|
||||
assignedOrders.find(o => o._id === route.params?.id) ||
|
||||
null
|
||||
const { data, loading: loadingConfig, error: errorConfig } = useQuery(
|
||||
CONFIGURATION
|
||||
)
|
||||
const [mutate, { loading: loadingMutation }] = useMutation(
|
||||
UPDATE_ORDER_STATUS,
|
||||
{
|
||||
onCompleted,
|
||||
onError,
|
||||
refetchQueries: [{ query: ORDERS }]
|
||||
}
|
||||
)
|
||||
const [mutateAssignOrder, { loading }] = useMutation(ASSIGN_ORDER, {
|
||||
onCompleted,
|
||||
onError
|
||||
})
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!selectedOrder) return
|
||||
navigation.setOptions({
|
||||
title: `Order ${selectedOrder.order_id}`
|
||||
})
|
||||
}, [selectedOrder])
|
||||
async function onCompleted({ updateOrderStatusRider, assignOrder }) {
|
||||
if (updateOrderStatusRider) {
|
||||
FlashMessage({
|
||||
message: `Order marked as ${updateOrderStatusRider.order_status}`
|
||||
})
|
||||
if (updateOrderStatusRider.order_status === 'DELIVERED') {
|
||||
navigation.goBack()
|
||||
return
|
||||
}
|
||||
// setOrder({ ...order, order_status: updateOrderStatusRider.order_status })
|
||||
}
|
||||
if (assignOrder) {
|
||||
// setOrder({ ...order, ...assignOrder })
|
||||
}
|
||||
}
|
||||
|
||||
function onError({ graphQLErrors, networkError }) {
|
||||
let message = 'Unknown error occured'
|
||||
if (networkError) message = 'Internal Server Error'
|
||||
if (graphQLErrors) message = graphQLErrors.map(o => o.message).join(', ')
|
||||
|
||||
FlashMessage({
|
||||
message: message
|
||||
})
|
||||
}
|
||||
|
||||
function getAddons(addons, currencySymbol) {
|
||||
return addons.map((addon, index) => {
|
||||
return addon.options.map((option, indexOption) => (
|
||||
<View key={`${index}${indexOption}`} style={[styles.orderContent]}>
|
||||
<View style={[styles.orderSubContent]}>
|
||||
<View style={styles.orderTextLeftContainer}></View>
|
||||
<View style={styles.orderTextCenterContainer}>
|
||||
<TextDefault
|
||||
bolder
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
{addon.title}:{option.title}
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderTextRightContainer}>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bolder
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
{currencySymbol}
|
||||
{option.price.toFixed(2)}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
function getOrderItems(items, currencySymbol) {
|
||||
return items.map((item, index) => {
|
||||
return (
|
||||
<View key={index}>
|
||||
<View style={styles.orderContent}>
|
||||
<View style={styles.orderSubContent}>
|
||||
<View style={styles.orderTextLeftContainer}>
|
||||
<TextDefault
|
||||
textColor={colors.fontMainColor}
|
||||
bolder
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
{item.quantity}x
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderTextCenterContainer}>
|
||||
<TextDefault
|
||||
bolder
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
{item.food.title}({item.variation.title})
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderTextRightContainer}>
|
||||
<TextDefault
|
||||
numberOfLines={1}
|
||||
textColor={colors.placeHolderColor}
|
||||
bolder
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
{currencySymbol}
|
||||
{(item.variation.price * item.quantity).toFixed(2)}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
{!item.addons ? null : getAddons(item.addons, currencySymbol)}
|
||||
</View>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if (loadingAssigned || loadingUnAssigned) {
|
||||
return <TextError text="Loading orders" />
|
||||
}
|
||||
if (loadingConfig) {
|
||||
return <Spinner />
|
||||
}
|
||||
if (errorConfig) {
|
||||
return <TextError text="Something is worng" />
|
||||
}
|
||||
if (!selectedOrder) {
|
||||
return (
|
||||
<TextError text="Order assgined to other rider,(something like that)" />
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<MainWrapper>
|
||||
<ScrollView
|
||||
style={styles.flex}
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
showsVerticalScrollIndicator={false}>
|
||||
<View style={styles.customerCard}>
|
||||
<View style={styles.customerSubCard}>
|
||||
<View style={styles.customerHeader}>
|
||||
<TextDefault
|
||||
H3
|
||||
bolder
|
||||
textColor={colors.tagColor}
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Customer Details
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.customerContent}>
|
||||
<View style={styles.customerSubContent}>
|
||||
<View style={styles.customerContentRow}>
|
||||
<View style={styles.customerTextContainer}>
|
||||
<TextDefault
|
||||
bolder
|
||||
textColor={colors.placeHolderColor}
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Name
|
||||
</TextDefault>
|
||||
<TextDefault bolder style={{ ...alignment.PBxSmall }}>
|
||||
{selectedOrder.user.name}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.customerContentRow}>
|
||||
<View style={styles.customerTextContainer}>
|
||||
<TextDefault
|
||||
bolder
|
||||
textColor={colors.placeHolderColor}
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Contact
|
||||
</TextDefault>
|
||||
<TextDefault bolder style={{ ...alignment.PBxSmall }}>
|
||||
{selectedOrder.user.phone}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.customerContentRow}>
|
||||
<View style={styles.customerAddContainer}>
|
||||
<TextDefault
|
||||
bolder
|
||||
textColor={colors.placeHolderColor}
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Delviery Location
|
||||
</TextDefault>
|
||||
<TextDefault
|
||||
numberOfLines={2}
|
||||
bolder
|
||||
style={{ ...alignment.PBxSmall }}>
|
||||
{`${selectedOrder.delivery_address.delivery_address}`}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.orderContainer}>
|
||||
<View style={styles.orderSubContainer}>
|
||||
<View style={styles.orderHeader}>
|
||||
<TextDefault
|
||||
H3
|
||||
bolder
|
||||
textColor={colors.tagColor}
|
||||
style={{ ...alignment.PTmedium }}>
|
||||
Order Details
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderSpacer} />
|
||||
{getOrderItems(
|
||||
selectedOrder.items,
|
||||
data.configuration.currency_symbol
|
||||
)}
|
||||
|
||||
<View style={styles.orderSpacer} />
|
||||
<View style={styles.orderRow}>
|
||||
<View style={styles.orderSubRow}>
|
||||
<View style={styles.orderTextLeft}>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bolder
|
||||
style={{ ...alignment.PTmedium, ...alignment.PLmedium }}>
|
||||
Subtotal
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderTextRight}>
|
||||
<TextDefault
|
||||
numberOfLines={1}
|
||||
textColor={colors.placeHolderColor}
|
||||
bolder
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PTmedium }}>
|
||||
{data.configuration.currency_symbol}
|
||||
{(
|
||||
selectedOrder.order_amount -
|
||||
selectedOrder.delivery_charges
|
||||
).toFixed(2)}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.orderRow2}>
|
||||
<View style={styles.orderSubRow}>
|
||||
<View style={styles.orderTextLeft}>
|
||||
<TextDefault
|
||||
textColor={colors.placeHolderColor}
|
||||
bolder
|
||||
style={{ ...alignment.PLmedium }}>
|
||||
Delivery Charges
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderTextRight}>
|
||||
<TextDefault
|
||||
numberOfLines={1}
|
||||
textColor={colors.placeHolderColor}
|
||||
bolder>
|
||||
{data.configuration.currency_symbol}
|
||||
{selectedOrder.delivery_charges.toFixed(2)}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.line} />
|
||||
<View style={styles.orderRow}>
|
||||
<View style={styles.orderSubRow}>
|
||||
<View style={styles.orderTextLeft}>
|
||||
<TextDefault H4 bolder>
|
||||
Total
|
||||
</TextDefault>
|
||||
</View>
|
||||
<View style={styles.orderTextRight}>
|
||||
<TextDefault
|
||||
numberOfLines={1}
|
||||
textColor={colors.fontMainColor}
|
||||
H4
|
||||
bolder>
|
||||
{data.configuration.currency_symbol}
|
||||
{selectedOrder.order_amount.toFixed(2)}
|
||||
</TextDefault>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.orderSpacer}></View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.baseSpacer} />
|
||||
<View style={styles.mapContainer}>
|
||||
<MapView
|
||||
style={styles.flex}
|
||||
scrollEnabled={false}
|
||||
zoomEnabled={false}
|
||||
loadingBackgroundColor={colors.tagColor}
|
||||
zoomControlEnabled={false}
|
||||
rotateEnabled={false}
|
||||
cacheEnabled={true}
|
||||
initialRegion={{
|
||||
latitude: parseFloat(selectedOrder.delivery_address.latitude),
|
||||
latitudeDelta: LATITUDE_DELTA,
|
||||
longitude: parseFloat(selectedOrder.delivery_address.longitude),
|
||||
longitudeDelta: LONGITUDE_DELTA
|
||||
}}
|
||||
provider={PROVIDER_GOOGLE}
|
||||
onPress={() => {
|
||||
linkToMapsApp(
|
||||
{
|
||||
latitude: selectedOrder.delivery_address.latitude,
|
||||
longitude: selectedOrder.delivery_address.longitude
|
||||
},
|
||||
'Destination'
|
||||
)
|
||||
}}>
|
||||
<Marker
|
||||
title="Delivery Address"
|
||||
coordinate={{
|
||||
latitude: parseFloat(selectedOrder.delivery_address.latitude),
|
||||
longitude: parseFloat(selectedOrder.delivery_address.longitude)
|
||||
}}
|
||||
onPress={() =>
|
||||
Linking.openURL(
|
||||
`google.navigation:q=${parseFloat(
|
||||
selectedOrder.delivery_address.longitude
|
||||
)}+${parseFloat(selectedOrder.delivery_address.longitude)}`
|
||||
)
|
||||
}>
|
||||
<Image
|
||||
source={require('../../../assets/images/ui/markerEnatega.png')}
|
||||
style={{ width: scale(40), height: scale(40) }}
|
||||
/>
|
||||
</Marker>
|
||||
</MapView>
|
||||
</View>
|
||||
<View style={styles.actionContainer}>
|
||||
{selectedOrder.order_status === 'ACCEPTED' && !selectedOrder.rider && (
|
||||
<TouchableOpacity
|
||||
disabled={loading}
|
||||
style={[
|
||||
styles.cancelBtnStyle,
|
||||
{ backgroundColor: colors.buttonBackground }
|
||||
]}
|
||||
onPress={() => {
|
||||
mutateAssignOrder({ variables: { id: selectedOrder._id } })
|
||||
}}>
|
||||
{loading ? (
|
||||
<Spinner spinnerColor={colors.buttonText} />
|
||||
) : (
|
||||
<TextDefault
|
||||
textColor={colors.fontMainColor}
|
||||
H4
|
||||
bold
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Assign to me
|
||||
</TextDefault>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{loadingMutation && <Spinner />}
|
||||
{!loadingMutation && selectedOrder.rider && (
|
||||
<View style={styles.actionSubContainer}>
|
||||
{selectedOrder.order_status === 'ACCEPTED' && (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.cancelBtnStyle,
|
||||
{ backgroundColor: colors.tagColor }
|
||||
]}
|
||||
onPress={() => {
|
||||
mutate({
|
||||
variables: { id: selectedOrder._id, status: 'PICKED' }
|
||||
})
|
||||
}}>
|
||||
<TextDefault
|
||||
textColor={colors.fontMainColor}
|
||||
H4
|
||||
bold
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Picked
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{selectedOrder.order_status === 'PICKED' && (
|
||||
<TouchableOpacity
|
||||
style={styles.acceptBtnStyle}
|
||||
onPress={() => {
|
||||
mutate({
|
||||
variables: { id: selectedOrder._id, status: 'DELIVERED' }
|
||||
})
|
||||
}}>
|
||||
<TextDefault
|
||||
textColor={colors.fontMainColor}
|
||||
H4
|
||||
bold
|
||||
style={{ ...alignment.PTxSmall, ...alignment.PBxSmall }}>
|
||||
Delivered
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</MainWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrderDetail
|
|
@ -0,0 +1,197 @@
|
|||
import { Dimensions, StyleSheet } from 'react-native'
|
||||
import { alignment } from '../../utilities/alignment'
|
||||
import colors from '../../utilities/colors'
|
||||
import { scale, verticalScale } from '../../utilities/scaling'
|
||||
const { height } = Dimensions.get('window')
|
||||
|
||||
export default {
|
||||
flex: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.themeBackground
|
||||
},
|
||||
line: {
|
||||
width: '80%',
|
||||
height: StyleSheet.hairlineWidth,
|
||||
backgroundColor: colors.horizontalLine,
|
||||
alignSelf: 'center',
|
||||
...alignment.MTmedium,
|
||||
...alignment.MBmedium
|
||||
},
|
||||
customerCard: {
|
||||
width: '100%',
|
||||
height: height * 0.4,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
|
||||
customerSubCard: {
|
||||
width: '85%',
|
||||
height: '90%',
|
||||
borderWidth: 2,
|
||||
borderStyle: 'dashed',
|
||||
backgroundColor: '#F3FAFE',
|
||||
borderRadius: scale(10),
|
||||
borderColor: colors.horizontalLine
|
||||
},
|
||||
customerHeader: {
|
||||
width: '100%',
|
||||
height: '30%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
customerContent: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-start'
|
||||
},
|
||||
customerSubContent: {
|
||||
width: '80%',
|
||||
height: '95%',
|
||||
justifyContent: 'space-around'
|
||||
},
|
||||
customerContentRow: {
|
||||
width: '100%',
|
||||
height: '50%',
|
||||
flexDirection: 'row',
|
||||
paddingLeft: '8%'
|
||||
},
|
||||
customerImgContainer: {
|
||||
width: '20%',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
customerTextContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
customerAddContainer: {
|
||||
justifyContent: 'center',
|
||||
width: '90%'
|
||||
},
|
||||
orderContainer: {
|
||||
width: '100%',
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...alignment.PTxSmall,
|
||||
...alignment.PBxSmall
|
||||
},
|
||||
orderSubContainer: {
|
||||
width: '85%',
|
||||
minHeight: height * 0.3,
|
||||
borderWidth: 2,
|
||||
borderStyle: 'dashed',
|
||||
borderRadius: scale(20),
|
||||
backgroundColor: '#F3FAFE',
|
||||
borderColor: colors.horizontalLine
|
||||
},
|
||||
orderHeader: {
|
||||
width: '100%',
|
||||
height: height * 0.08,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
orderContent: {
|
||||
width: '100%',
|
||||
alignItems: 'center'
|
||||
},
|
||||
orderSubContent: {
|
||||
width: '90%',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
orderTextLeftContainer: {
|
||||
width: '10%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
orderTextCenterContainer: {
|
||||
width: '65%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
orderTextRightContainer: {
|
||||
width: '25%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-end'
|
||||
},
|
||||
orderSpacer: {
|
||||
width: '100%',
|
||||
height: height * 0.02
|
||||
},
|
||||
orderRow: {
|
||||
width: '100%',
|
||||
height: height * 0.05,
|
||||
alignItems: 'center'
|
||||
},
|
||||
orderRow2: {
|
||||
width: '100%',
|
||||
height: height * 0.07,
|
||||
alignItems: 'center',
|
||||
...alignment.PBlarge
|
||||
},
|
||||
orderSubRow: {
|
||||
width: '90%',
|
||||
height: '100%',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
orderTextLeft: {
|
||||
width: '50%',
|
||||
height: '100%',
|
||||
paddingLeft: '5%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
orderTextRight: {
|
||||
width: '50%',
|
||||
height: '100%',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
actionContainer: {
|
||||
width: '100%',
|
||||
height: height * 0.1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...alignment.MTmedium,
|
||||
...alignment.MBlarge
|
||||
},
|
||||
actionSubContainer: {
|
||||
width: '90%',
|
||||
height: '80%',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
borderRadius: scale(10),
|
||||
...alignment.MBlarge
|
||||
},
|
||||
cancelBtnStyle: {
|
||||
width: '80%',
|
||||
height: '70%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: scale(10)
|
||||
},
|
||||
acceptBtnStyle: {
|
||||
backgroundColor: colors.tagColor,
|
||||
width: '80%',
|
||||
height: '70%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: scale(10)
|
||||
},
|
||||
removeBtnStyle: {
|
||||
backgroundColor: colors.tagColor,
|
||||
width: '45%',
|
||||
height: '70%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
baseSpacer: {
|
||||
marginTop: verticalScale(15)
|
||||
},
|
||||
mapContainer: {
|
||||
width: '85%',
|
||||
alignSelf: 'center',
|
||||
height: verticalScale(200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import {
|
||||
ImageBackground,
|
||||
StatusBar,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native'
|
||||
import i18n from '../../../i18n'
|
||||
import { AssignedOrders, NewOrders, TextDefault } from '../../components'
|
||||
import colors from '../../utilities/colors'
|
||||
import useStyle from './style'
|
||||
|
||||
const BACKGROUND_IMAGE = require('../../../assets/images/ui/BG.png')
|
||||
|
||||
export default function Orders() {
|
||||
const styles = useStyle()
|
||||
const [isNewOrderSelected, setIsNewOrderSelected] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
StatusBar.setBarStyle('light-content')
|
||||
}, [isNewOrderSelected])
|
||||
|
||||
return (
|
||||
<View style={[styles.flex, styles.bottom]}>
|
||||
<ImageBackground style={styles.imageContainer} source={BACKGROUND_IMAGE}>
|
||||
<View style={styles.toggleContainer}>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
onPress={() => setIsNewOrderSelected(false)}
|
||||
style={[
|
||||
styles.toggleBtn,
|
||||
{
|
||||
backgroundColor: !isNewOrderSelected
|
||||
? colors.buttonBackgroundPink
|
||||
: 'transparent'
|
||||
}
|
||||
]}>
|
||||
<TextDefault bold H5 numberOfLines={1}>
|
||||
{i18n.t('myOrders')}
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.8}
|
||||
onPress={() => setIsNewOrderSelected(true)}
|
||||
style={[
|
||||
styles.toggleBtn,
|
||||
{
|
||||
backgroundColor: isNewOrderSelected
|
||||
? colors.buttonBackgroundPink
|
||||
: 'transparent'
|
||||
}
|
||||
]}>
|
||||
<TextDefault bold H5 numberOfLines={1}>
|
||||
{i18n.t('newOrders')}
|
||||
</TextDefault>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
{!isNewOrderSelected ? <AssignedOrders /> : <NewOrders />}
|
||||
</View>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import { useHeaderHeight } from '@react-navigation/stack'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { scale, verticalScale } from '../../utilities/scaling'
|
||||
|
||||
const useStyle = () => {
|
||||
const inset = useSafeAreaInsets()
|
||||
const headerHeight = useHeaderHeight()
|
||||
|
||||
return StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1
|
||||
},
|
||||
bottom: {
|
||||
paddingBottom: inset.bottom
|
||||
},
|
||||
imageContainer: {
|
||||
width: '100%',
|
||||
paddingTop: headerHeight,
|
||||
height: verticalScale(270)
|
||||
},
|
||||
headerContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '65%',
|
||||
padding: '5%'
|
||||
},
|
||||
toggleContainer: {
|
||||
width: '65%',
|
||||
borderRadius: scale(10),
|
||||
justifyContent: 'space-between',
|
||||
height: verticalScale(50),
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: scale(10),
|
||||
backgroundColor: 'white',
|
||||
marginTop: verticalScale(20),
|
||||
alignSelf: 'center'
|
||||
},
|
||||
toggleBtn: {
|
||||
justifyContent: 'center',
|
||||
height: '70%',
|
||||
alignItems: 'center',
|
||||
width: '47%',
|
||||
borderRadius: scale(10)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default useStyle
|
|
@ -0,0 +1,19 @@
|
|||
import Chat from './Chat/Chat'
|
||||
import Help from './Help/Help'
|
||||
import HelpBrowser from './HelpBrowser/HelpBrowser'
|
||||
import Language from './Language/Language'
|
||||
import Login from './Login/Login'
|
||||
import NewOrders from './NewOrders/NewOrders'
|
||||
import OrderDetail from './OrderDetail/OrderDetail'
|
||||
import Orders from './Orders/Orders'
|
||||
|
||||
export {
|
||||
Chat,
|
||||
Help,
|
||||
HelpBrowser,
|
||||
Language,
|
||||
Login,
|
||||
NewOrders,
|
||||
OrderDetail,
|
||||
Orders
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
import { scale } from './scaling'
|
||||
|
||||
const XSMALL = 5
|
||||
const SMALL = 10
|
||||
const MEDIUM = 15
|
||||
const LARGE = 20
|
||||
export const alignment = {
|
||||
MxSmall: {
|
||||
margin: scale(XSMALL)
|
||||
},
|
||||
MBxSmall: {
|
||||
marginBottom: scale(XSMALL)
|
||||
},
|
||||
MTxSmall: {
|
||||
marginTop: scale(XSMALL)
|
||||
},
|
||||
MRxSmall: {
|
||||
marginRight: scale(XSMALL)
|
||||
},
|
||||
MLxSmall: {
|
||||
marginLeft: scale(XSMALL)
|
||||
},
|
||||
|
||||
Msmall: {
|
||||
margin: scale(SMALL)
|
||||
},
|
||||
MBsmall: {
|
||||
marginBottom: scale(SMALL)
|
||||
},
|
||||
MTsmall: {
|
||||
marginTop: scale(SMALL)
|
||||
},
|
||||
MRsmall: {
|
||||
marginRight: scale(SMALL)
|
||||
},
|
||||
MLsmall: {
|
||||
marginLeft: scale(SMALL)
|
||||
},
|
||||
|
||||
Mmedium: {
|
||||
margin: scale(MEDIUM)
|
||||
},
|
||||
MBmedium: {
|
||||
marginBottom: scale(MEDIUM)
|
||||
},
|
||||
MTmedium: {
|
||||
marginTop: scale(MEDIUM)
|
||||
},
|
||||
MRmedium: {
|
||||
marginRight: scale(MEDIUM)
|
||||
},
|
||||
MLmedium: {
|
||||
marginLeft: scale(MEDIUM)
|
||||
},
|
||||
Mlarge: {
|
||||
margin: scale(LARGE)
|
||||
},
|
||||
MBlarge: {
|
||||
marginBottom: scale(LARGE)
|
||||
},
|
||||
MTlarge: {
|
||||
marginTop: scale(LARGE)
|
||||
},
|
||||
MRlarge: {
|
||||
marginRight: scale(LARGE)
|
||||
},
|
||||
MLlarge: {
|
||||
marginLeft: scale(LARGE)
|
||||
},
|
||||
|
||||
// Padding
|
||||
PxSmall: {
|
||||
padding: scale(XSMALL)
|
||||
},
|
||||
PBxSmall: {
|
||||
paddingBottom: scale(XSMALL)
|
||||
},
|
||||
PTxSmall: {
|
||||
paddingTop: scale(XSMALL)
|
||||
},
|
||||
PRxSmall: {
|
||||
paddingRight: scale(XSMALL)
|
||||
},
|
||||
PLxSmall: {
|
||||
paddingLeft: scale(XSMALL)
|
||||
},
|
||||
|
||||
Psmall: {
|
||||
padding: scale(SMALL)
|
||||
},
|
||||
PBsmall: {
|
||||
paddingBottom: scale(SMALL)
|
||||
},
|
||||
PTsmall: {
|
||||
paddingTop: scale(SMALL)
|
||||
},
|
||||
PRsmall: {
|
||||
paddingRight: scale(SMALL)
|
||||
},
|
||||
PLsmall: {
|
||||
paddingLeft: scale(SMALL)
|
||||
},
|
||||
|
||||
Pmedium: {
|
||||
padding: scale(MEDIUM)
|
||||
},
|
||||
PBmedium: {
|
||||
paddingBottom: scale(MEDIUM)
|
||||
},
|
||||
PTmedium: {
|
||||
paddingTop: scale(MEDIUM)
|
||||
},
|
||||
PRmedium: {
|
||||
paddingRight: scale(MEDIUM)
|
||||
},
|
||||
PLmedium: {
|
||||
paddingLeft: scale(MEDIUM)
|
||||
},
|
||||
|
||||
Plarge: {
|
||||
padding: scale(LARGE)
|
||||
},
|
||||
PBlarge: {
|
||||
paddingBottom: scale(LARGE)
|
||||
},
|
||||
PTlarge: {
|
||||
paddingTop: scale(LARGE)
|
||||
},
|
||||
PRlarge: {
|
||||
paddingRight: scale(LARGE)
|
||||
},
|
||||
PLlarge: {
|
||||
paddingLeft: scale(LARGE)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
const colors = {
|
||||
black: '#000',
|
||||
themeBackground: '#FFFFFF',
|
||||
iconColor: '#333333',
|
||||
tagColor: '#febb2c',
|
||||
iconPink: '#d83765',
|
||||
radioColor: '#FFF',
|
||||
radioOuterColor: '#d83765',
|
||||
spinnerColor: '#febb2c',
|
||||
orderComplete: '#518ef8',
|
||||
orderUncomplete: '#f14336',
|
||||
horizontalLine: '#B8B8B8',
|
||||
buttonBackground: '#febb2c',
|
||||
buttonText: '#FFF',
|
||||
buttonBackgroundPink: '#febb2c',
|
||||
buttonTextPink: '#FFF',
|
||||
textErrorColor: '#FA7751',
|
||||
headerBackground: '#FFF',
|
||||
headerText: '#2a2a2a',
|
||||
fontMainColor: '#000',
|
||||
fontSecondColor: '#FFFFFF',
|
||||
cartContainer: '#FFF',
|
||||
placeHolderColor: '#a5a5a5',
|
||||
lightBackground: '#f8f9fa',
|
||||
yellowishOrange: '#fff1d4'
|
||||
}
|
||||
|
||||
export default colors
|
|
@ -0,0 +1,40 @@
|
|||
const NAVIGATION_SCREEN = {
|
||||
Chat: 'Chat',
|
||||
Login: 'Login',
|
||||
Orders: 'Orders',
|
||||
OrderDetail: 'OrderDetail',
|
||||
Help: 'Help',
|
||||
Language: 'Language',
|
||||
HelpBrowser: 'HelpBrowser'
|
||||
}
|
||||
|
||||
const ICONS_NAME = {
|
||||
Logo: 'logo',
|
||||
Menu: 'menu',
|
||||
Back: 'back',
|
||||
Exit: 'exit',
|
||||
Cash: 'cash',
|
||||
Visa: 'visa',
|
||||
Home: 'home',
|
||||
Cart: 'cart',
|
||||
Info: 'info',
|
||||
Plus: 'plus',
|
||||
Radio: 'radio',
|
||||
Cross: 'cross',
|
||||
Minus: 'minus',
|
||||
Trash: 'trash',
|
||||
Clock: 'clock',
|
||||
Reload: 'reload',
|
||||
Pencil: 'pencil',
|
||||
Target: 'target',
|
||||
Filter: 'filter',
|
||||
Paypal: 'paypal',
|
||||
Message: 'message',
|
||||
Setting: 'setting',
|
||||
Checked: 'checked',
|
||||
Refresh: 'refresh',
|
||||
Location: 'location',
|
||||
RadioSelect: 'radioSelect'
|
||||
}
|
||||
|
||||
export { NAVIGATION_SCREEN, ICONS_NAME }
|
|
@ -0,0 +1,5 @@
|
|||
export const fontStyles = {
|
||||
MuseoSans300: 'MuseoSans300',
|
||||
MuseoSans500: 'MuseoSans500',
|
||||
MuseoSans700: 'MuseoSans700'
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { Platform, Linking } from 'react-native'
|
||||
|
||||
export function linkToMapsApp({ latitude, longitude }, label) {
|
||||
const scheme = Platform.select({ ios: 'maps:0,0?q=', android: 'geo:0,0?q=' })
|
||||
const latLng = `${latitude},${longitude}`
|
||||
// const label = label;
|
||||
const url = Platform.select({
|
||||
ios: `${scheme}${label}@${latLng}`,
|
||||
android: `${scheme}${latLng}(${label})`
|
||||
})
|
||||
|
||||
Linking.openURL(url)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import * as TaskManager from 'expo-task-manager'
|
||||
import { clientRef } from '../apollo/index'
|
||||
import { updateLocation } from '../apollo/mutations'
|
||||
import gql from 'graphql-tag'
|
||||
const UPDATE_LOCATION = gql`
|
||||
${updateLocation}
|
||||
`
|
||||
|
||||
TaskManager.defineTask(
|
||||
'RIDER_LOCATION',
|
||||
async ({ data: { locations }, error }) => {
|
||||
try {
|
||||
if (error) {
|
||||
console.log('rider location error')
|
||||
return
|
||||
}
|
||||
if (locations.length > 0) {
|
||||
const {
|
||||
coords: { latitude, longitude }
|
||||
} = locations[locations.length - 1]
|
||||
await clientRef.mutate({
|
||||
mutation: UPDATE_LOCATION,
|
||||
variables: {
|
||||
latitude: latitude.toString(),
|
||||
longitude: longitude.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('error', error)
|
||||
}
|
||||
}
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
import { Dimensions } from 'react-native'
|
||||
|
||||
const { width, height } = Dimensions.get('window')
|
||||
// Guideline sizes are based on standard ~5" screen mobile device
|
||||
const guidelineBaseWidth = 350
|
||||
const guidelineBaseHeight = 680
|
||||
const scale = size => (width / guidelineBaseWidth) * size
|
||||
const verticalScale = size => (height / guidelineBaseHeight) * size
|
||||
const moderateScale = (size, factor = 0.5) =>
|
||||
size + (scale(size) - size) * factor
|
||||
|
||||
export { scale, verticalScale, moderateScale }
|
|
@ -0,0 +1,50 @@
|
|||
import { scale } from './scaling'
|
||||
import { fontStyles } from './fontStyles'
|
||||
|
||||
export const textStyles = {
|
||||
H1: {
|
||||
fontSize: scale(35)
|
||||
},
|
||||
H2: {
|
||||
fontSize: scale(24)
|
||||
},
|
||||
H3: {
|
||||
fontSize: scale(20)
|
||||
},
|
||||
H4: {
|
||||
fontSize: scale(16)
|
||||
},
|
||||
H5: {
|
||||
fontSize: scale(14)
|
||||
},
|
||||
Normal: {
|
||||
fontSize: scale(12)
|
||||
},
|
||||
Small: {
|
||||
fontSize: scale(10)
|
||||
},
|
||||
xSmall: {
|
||||
fontSize: scale(8)
|
||||
},
|
||||
Regular: {
|
||||
fontFamily: fontStyles.MuseoSans300
|
||||
},
|
||||
Bold: {
|
||||
fontFamily: fontStyles.MuseoSans500
|
||||
},
|
||||
Bolder: {
|
||||
fontFamily: fontStyles.MuseoSans700
|
||||
},
|
||||
Center: {
|
||||
textAlign: 'center'
|
||||
},
|
||||
Right: {
|
||||
textAlign: 'right'
|
||||
},
|
||||
UpperCase: {
|
||||
textTransform: 'uppercase'
|
||||
},
|
||||
LineOver: {
|
||||
textDecorationLine: 'line-through'
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue