Fix env issue
parent
4457adfbe5
commit
eeb6683b59
|
|
@ -4,12 +4,30 @@ import { useTabConfig } from "@/constants/config";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { RootState } from "@/store";
|
import { RootState } from "@/store";
|
||||||
import { initSocket } from "@/services/socket";
|
import { initSocket } from "@/services/socket";
|
||||||
|
import { useSnackbar } from "@/contexts/Snackbar";
|
||||||
|
import NetInfo from "@react-native-community/netinfo";
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
const { isLoggedIn } = useSelector((state: RootState) => state.auth);
|
const { isLoggedIn } = useSelector((state: RootState) => state.auth);
|
||||||
if (!isLoggedIn) return null;
|
if (!isLoggedIn) return null;
|
||||||
const TAB_CONFIG = useTabConfig();
|
const TAB_CONFIG = useTabConfig();
|
||||||
|
|
||||||
|
const { showSnackbar } = useSnackbar();
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = NetInfo.addEventListener((state) => {
|
||||||
|
const isConnected = state.isConnected;
|
||||||
|
|
||||||
|
if (isConnected === false) {
|
||||||
|
console.log("No internet connection");
|
||||||
|
showSnackbar("No internet connection", "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initSocket();
|
initSocket();
|
||||||
}, [isLoggedIn]);
|
}, [isLoggedIn]);
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,8 @@ export default function HomeScreen() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const [isSupportModalVisible, setIsSupportModalVisible] = useState(false);
|
const [isSupportModalVisible, setIsSupportModalVisible] = useState(false);
|
||||||
const { SoC, SoH, chargingState, lat, lon, loading, error } = useSelector(
|
const { SoC, SoH, chargingState, lat, lon, loading, error, totalDistance } =
|
||||||
(state: RootState) => state.telemetry
|
useSelector((state: RootState) => state.telemetry);
|
||||||
);
|
|
||||||
const [prevPosition, setPrevPosition] = useState<{
|
const [prevPosition, setPrevPosition] = useState<{
|
||||||
lat: number;
|
lat: number;
|
||||||
lon: number;
|
lon: number;
|
||||||
|
|
@ -139,7 +138,7 @@ export default function HomeScreen() {
|
||||||
<MetricCard heading={t("home.battery-health")} value={SoH} unit="%" />
|
<MetricCard heading={t("home.battery-health")} value={SoH} unit="%" />
|
||||||
<MetricCard
|
<MetricCard
|
||||||
heading={t("home.total-distance")}
|
heading={t("home.total-distance")}
|
||||||
value={20009}
|
value={totalDistance}
|
||||||
unit="km"
|
unit="km"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
@ -156,7 +155,7 @@ export default function HomeScreen() {
|
||||||
<LocationOff />
|
<LocationOff />
|
||||||
<Text style={styles.errorText}>Fetching Location...</Text>
|
<Text style={styles.errorText}>Fetching Location...</Text>
|
||||||
</View>
|
</View>
|
||||||
) : lat && lon ? (
|
) : lat != null && lon != null ? (
|
||||||
<>
|
<>
|
||||||
<View style={styles.mapContainer}>
|
<View style={styles.mapContainer}>
|
||||||
<MapView
|
<MapView
|
||||||
|
|
@ -192,10 +191,12 @@ export default function HomeScreen() {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<View style={styles.errorContainer}>
|
error && (
|
||||||
<LocationOff />
|
<View style={styles.errorContainer}>
|
||||||
<Text style={styles.errorText}>Error fetching location</Text>
|
<LocationOff />
|
||||||
</View>
|
<Text style={styles.errorText}>Error fetching location</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import "react-native-reanimated";
|
||||||
import { I18nextProvider } from "react-i18next";
|
import { I18nextProvider } from "react-i18next";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
|
import { PaperProvider } from "react-native-paper";
|
||||||
|
import SnackbarProvider from "@/contexts/Snackbar";
|
||||||
|
|
||||||
export { ErrorBoundary } from "expo-router";
|
export { ErrorBoundary } from "expo-router";
|
||||||
|
|
||||||
|
|
@ -55,17 +57,21 @@ export default function RootLayout() {
|
||||||
|
|
||||||
function RootLayoutNav() {
|
function RootLayoutNav() {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<PaperProvider>
|
||||||
<I18nextProvider i18n={i18next}>
|
<SnackbarProvider>
|
||||||
<Stack
|
<Provider store={store}>
|
||||||
screenOptions={{
|
<I18nextProvider i18n={i18next}>
|
||||||
headerShown: false,
|
<Stack
|
||||||
animation: "fade",
|
screenOptions={{
|
||||||
}}
|
headerShown: false,
|
||||||
>
|
animation: "fade",
|
||||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
}}
|
||||||
</Stack>
|
>
|
||||||
</I18nextProvider>
|
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||||
</Provider>
|
</Stack>
|
||||||
|
</I18nextProvider>
|
||||||
|
</Provider>
|
||||||
|
</SnackbarProvider>
|
||||||
|
</PaperProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import {
|
||||||
TouchableWithoutFeedback,
|
TouchableWithoutFeedback,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
KeyboardAvoidingView,
|
KeyboardAvoidingView,
|
||||||
StatusBar,
|
|
||||||
Linking,
|
Linking,
|
||||||
|
Platform,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
import { Formik } from "formik";
|
import { Formik } from "formik";
|
||||||
|
|
@ -22,16 +22,8 @@ import { RootState } from "../../store";
|
||||||
import { AUTH_STATUSES } from "@/constants/types";
|
import { AUTH_STATUSES } from "@/constants/types";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { SUPPORT } from "@/constants/config";
|
import { SUPPORT } from "@/constants/config";
|
||||||
// import { useNavigation } from "expo-router";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
|
||||||
// type VerifyOTPNavigationProp = StackNavigationProp<
|
|
||||||
// RootStackParamList,
|
|
||||||
// "VerifyOTP"
|
|
||||||
// >;
|
|
||||||
|
|
||||||
// import OTPInputView from "@twotalltotems/react-native-otp-input";
|
|
||||||
//handleblue => when input field looses focus (mark as touched)
|
|
||||||
// handleBlur marks the field as touched, when field looses focus
|
|
||||||
export default function WelcomeScreen() {
|
export default function WelcomeScreen() {
|
||||||
const {
|
const {
|
||||||
status,
|
status,
|
||||||
|
|
@ -42,6 +34,8 @@ export default function WelcomeScreen() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
// const navigation = useNavigation();
|
// const navigation = useNavigation();
|
||||||
|
|
||||||
const phoneValidationSchema = Yup.object().shape({
|
const phoneValidationSchema = Yup.object().shape({
|
||||||
|
|
@ -63,10 +57,13 @@ export default function WelcomeScreen() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView style={styles.container} behavior="padding">
|
<KeyboardAvoidingView
|
||||||
<StatusBar barStyle="dark-content" backgroundColor="#F3F5F8" />
|
style={styles.container}
|
||||||
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||||
|
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 0}
|
||||||
|
>
|
||||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
||||||
<View style={styles.inner}>
|
<View style={[styles.inner, { paddingBottom: insets.bottom }]}>
|
||||||
<Text style={styles.title}>{t("onboarding.welcome")}</Text>
|
<Text style={styles.title}>{t("onboarding.welcome")}</Text>
|
||||||
|
|
||||||
<Formik
|
<Formik
|
||||||
|
|
@ -82,64 +79,70 @@ export default function WelcomeScreen() {
|
||||||
errors,
|
errors,
|
||||||
touched,
|
touched,
|
||||||
}) => (
|
}) => (
|
||||||
<View style={styles.form}>
|
<View style={styles.formContainer}>
|
||||||
<Text style={styles.label}>
|
<View style={styles.inputContainer}>
|
||||||
{t("onboarding.enter-mobile-number")}
|
<Text style={styles.label}>
|
||||||
</Text>
|
{t("onboarding.enter-mobile-number")}
|
||||||
<TextInput
|
</Text>
|
||||||
style={{
|
<TextInput
|
||||||
...styles.input,
|
style={{
|
||||||
color: values.phone ? "black" : "#949CAC",
|
...styles.input,
|
||||||
}}
|
color: values.phone ? "black" : "#949CAC",
|
||||||
onChangeText={(text) => {
|
}}
|
||||||
handleChange("phone")(text);
|
onChangeText={(text) => {
|
||||||
if (sendOTPError) {
|
handleChange("phone")(text);
|
||||||
dispatch(clearSendOTPError());
|
if (sendOTPError) {
|
||||||
}
|
dispatch(clearSendOTPError());
|
||||||
}}
|
}
|
||||||
onBlur={handleBlur("phone")}
|
}}
|
||||||
value={values.phone}
|
onBlur={handleBlur("phone")}
|
||||||
keyboardType="numeric"
|
value={values.phone}
|
||||||
placeholder={t("onboarding.enter-registered-mobile-number")}
|
keyboardType="numeric"
|
||||||
placeholderTextColor={"#949CAC"}
|
placeholder={t("onboarding.enter-registered-mobile-number")}
|
||||||
/>
|
placeholderTextColor={"#949CAC"}
|
||||||
<View style={styles.errorContainer}>
|
/>
|
||||||
{touched.phone && errors.phone && (
|
<View style={styles.errorContainer}>
|
||||||
<Text style={styles.error}>{errors.phone}</Text>
|
{touched.phone && errors.phone && (
|
||||||
)}
|
<Text style={styles.error}>{errors.phone}</Text>
|
||||||
{sendOTPError && (
|
)}
|
||||||
<Text style={styles.error}>{sendOTPError}</Text>
|
{sendOTPError && (
|
||||||
)}
|
<Text style={styles.error}>{sendOTPError}</Text>
|
||||||
</View>
|
)}
|
||||||
<View style={styles.contactContainer}>
|
|
||||||
<View style={{ flexDirection: "row" }}>
|
|
||||||
<Text>For any queries, </Text>
|
|
||||||
<TouchableOpacity onPress={makePhoneCall}>
|
|
||||||
<Text style={styles.link}>contact us.</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<TouchableOpacity
|
|
||||||
onPress={handleSubmit as unknown as () => void}
|
<View style={styles.bottomSection}>
|
||||||
style={{
|
<View style={styles.contactContainer}>
|
||||||
...styles.button,
|
<View style={{ flexDirection: "row" }}>
|
||||||
backgroundColor:
|
<Text>For any queries, </Text>
|
||||||
values.phone.length === 10 &&
|
<TouchableOpacity onPress={makePhoneCall}>
|
||||||
!errors.phone &&
|
<Text style={styles.link}>contact us.</Text>
|
||||||
status !== AUTH_STATUSES.LOADING
|
</TouchableOpacity>
|
||||||
? "#008761"
|
</View>
|
||||||
: "#B0B7C5",
|
</View>
|
||||||
}}
|
|
||||||
disabled={
|
<TouchableOpacity
|
||||||
values.phone.length !== 10 ||
|
onPress={handleSubmit as unknown as () => void}
|
||||||
!!errors.phone ||
|
style={{
|
||||||
status === AUTH_STATUSES.LOADING
|
...styles.button,
|
||||||
}
|
backgroundColor:
|
||||||
>
|
values.phone.length === 10 &&
|
||||||
<Text style={styles.buttonText}>
|
!errors.phone &&
|
||||||
{t("onboarding.send-otp")}
|
status !== AUTH_STATUSES.LOADING
|
||||||
</Text>
|
? "#008761"
|
||||||
</TouchableOpacity>
|
: "#B0B7C5",
|
||||||
|
}}
|
||||||
|
disabled={
|
||||||
|
values.phone.length !== 10 ||
|
||||||
|
!!errors.phone ||
|
||||||
|
status === AUTH_STATUSES.LOADING
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>
|
||||||
|
{t("onboarding.send-otp")}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|
@ -150,12 +153,29 @@ export default function WelcomeScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: "#F3F5F8",
|
||||||
|
},
|
||||||
|
inner: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
formContainer: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
inputContainer: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
bottomSection: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
contactContainer: {
|
contactContainer: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
position: "absolute",
|
marginBottom: 16,
|
||||||
bottom: 110, // slightly above the "Send OTP" button
|
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
@ -175,24 +195,12 @@ const styles = StyleSheet.create({
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
lineHeight: 20,
|
lineHeight: 20,
|
||||||
},
|
},
|
||||||
inner: {
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
height: "90%",
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
button: {
|
button: {
|
||||||
height: 48,
|
height: 48,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
marginTop: 20,
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
position: "absolute",
|
|
||||||
bottom: 50,
|
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
color: "#FCFCFC",
|
color: "#FCFCFC",
|
||||||
|
|
@ -201,12 +209,6 @@ const styles = StyleSheet.create({
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
lineHeight: 20,
|
lineHeight: 20,
|
||||||
},
|
},
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
padding: 16,
|
|
||||||
backgroundColor: "#F3F5F8",
|
|
||||||
paddingTop: 0,
|
|
||||||
},
|
|
||||||
title: {
|
title: {
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@ import React, { useEffect, useState } from "react";
|
||||||
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
||||||
import { setLanguage } from "../../services/i18n/index";
|
import { setLanguage } from "../../services/i18n/index";
|
||||||
import { useRouter, useNavigation } from "expo-router";
|
import { useRouter, useNavigation } from "expo-router";
|
||||||
|
import { StatusBar } from "expo-status-bar";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
|
||||||
const LanguageScreen = () => {
|
const LanguageScreen = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const [selectedLang, setSelectedLang] = useState<string | null>(null);
|
const [selectedLang, setSelectedLang] = useState<string | null>(null);
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.setOptions({ headerShown: false });
|
navigation.setOptions({ headerShown: false });
|
||||||
|
|
@ -24,41 +27,47 @@ const LanguageScreen = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<>
|
||||||
<Text style={styles.title}>Select Language</Text>
|
<StatusBar style="dark" />
|
||||||
<Text style={styles.subtitle}>Please select your preferred language</Text>
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>Select Language</Text>
|
||||||
|
<Text style={styles.subtitle}>
|
||||||
|
Please select your preferred language
|
||||||
|
</Text>
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
styles.languageCard,
|
styles.languageCard,
|
||||||
selectedLang === "en" && styles.selectedCard,
|
selectedLang === "en" && styles.selectedCard,
|
||||||
]}
|
]}
|
||||||
onPress={() => handleLanguagePress("en")}
|
onPress={() => handleLanguagePress("en")}
|
||||||
>
|
>
|
||||||
<Text style={styles.languageText}>English</Text>
|
<Text style={styles.languageText}>English</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
styles.languageCard,
|
styles.languageCard,
|
||||||
selectedLang === "hi" && styles.selectedCard,
|
selectedLang === "hi" && styles.selectedCard,
|
||||||
]}
|
]}
|
||||||
onPress={() => handleLanguagePress("hi")}
|
onPress={() => handleLanguagePress("hi")}
|
||||||
>
|
>
|
||||||
<Text style={styles.languageText}>हिन्दी</Text>
|
<Text style={styles.languageText}>हिन्दी</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
styles.selectButton,
|
styles.selectButton,
|
||||||
selectedLang ? styles.selectEnabled : styles.selectDisabled,
|
selectedLang ? styles.selectEnabled : styles.selectDisabled,
|
||||||
]}
|
{ marginBottom: insets.bottom + 16 },
|
||||||
onPress={handleSelect}
|
]}
|
||||||
disabled={!selectedLang}
|
onPress={handleSelect}
|
||||||
>
|
disabled={!selectedLang}
|
||||||
<Text style={styles.selectButtonText}>Select</Text>
|
>
|
||||||
</TouchableOpacity>
|
<Text style={styles.selectButtonText}>Select</Text>
|
||||||
</View>
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -68,7 +77,6 @@ const styles = StyleSheet.create({
|
||||||
backgroundColor: "#f3f5f8",
|
backgroundColor: "#f3f5f8",
|
||||||
paddingTop: 108,
|
paddingTop: 108,
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
paddingBottom: 80,
|
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
|
|
@ -91,7 +99,7 @@ const styles = StyleSheet.create({
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
},
|
},
|
||||||
selectedCard: {
|
selectedCard: {
|
||||||
borderColor: "#008000",
|
borderColor: "#009E71",
|
||||||
},
|
},
|
||||||
languageText: {
|
languageText: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
|
@ -99,6 +107,7 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
selectButton: {
|
selectButton: {
|
||||||
marginTop: "auto",
|
marginTop: "auto",
|
||||||
|
marginBottom: 16,
|
||||||
padding: 16,
|
padding: 16,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|
|
||||||
|
|
@ -8,56 +8,68 @@ import {
|
||||||
ScrollView,
|
ScrollView,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { MaterialIcons } from "@expo/vector-icons";
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
import LanguageModal from "@/components/Profile/LangaugeModal";
|
||||||
|
|
||||||
export default function ProfileScreen() {
|
export default function ProfileScreen() {
|
||||||
|
const [isLangaugeModalVisible, setLanguageModalVisible] =
|
||||||
|
React.useState(false);
|
||||||
|
|
||||||
|
const toggleLanguageModal = () => {
|
||||||
|
setLanguageModalVisible(!isLangaugeModalVisible);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
<>
|
||||||
<View style={styles.avatarContainer}>
|
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||||
<Image
|
<View style={styles.avatarContainer}>
|
||||||
source={require("../../assets/images/user_image.jpg")}
|
<Image
|
||||||
style={styles.avatar}
|
source={require("../../assets/images/user_image.jpg")}
|
||||||
/>
|
style={styles.avatar}
|
||||||
<TouchableOpacity style={styles.editAvatar}>
|
/>
|
||||||
<MaterialIcons name="edit" size={20} color="#FDFDFD" />
|
<TouchableOpacity style={styles.editAvatar}>
|
||||||
</TouchableOpacity>
|
<MaterialIcons name="edit" size={20} color="#FDFDFD" />
|
||||||
</View>
|
|
||||||
<View style={styles.card}>
|
|
||||||
<View style={styles.row}>
|
|
||||||
<View style={styles.textGroup}>
|
|
||||||
<Text style={styles.label}>Name</Text>
|
|
||||||
<Text style={styles.value}>Amar Kesari</Text>
|
|
||||||
</View>
|
|
||||||
<TouchableOpacity>
|
|
||||||
<MaterialIcons name="edit" size={20} color="#555C70" />
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.divider} />
|
<View style={styles.card}>
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<View style={styles.textGroup}>
|
<View style={styles.textGroup}>
|
||||||
<Text style={styles.label}>Mobile Number</Text>
|
<Text style={styles.label}>Name</Text>
|
||||||
<Text style={styles.value}>9876543210</Text>
|
<Text style={styles.value}>Amar Kesari</Text>
|
||||||
|
</View>
|
||||||
|
<TouchableOpacity>
|
||||||
|
<MaterialIcons name="edit" size={20} color="#555C70" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
<View style={styles.divider} />
|
||||||
|
<View style={styles.row}>
|
||||||
|
<View style={styles.textGroup}>
|
||||||
|
<Text style={styles.label}>Mobile Number</Text>
|
||||||
|
<Text style={styles.value}>9876543210</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Other Menu Items */}
|
<View style={styles.card}>
|
||||||
<View style={styles.card}>
|
{menuItem("My Vehicle")}
|
||||||
{menuItem("My Vehicle")}
|
<View style={styles.divider} />
|
||||||
<View style={styles.divider} />
|
{menuItem("Language", () => toggleLanguageModal())}
|
||||||
{menuItem("Language")}
|
</View>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.card}>
|
<View style={styles.card}>
|
||||||
{menuItem("About App")}
|
{menuItem("About App")}
|
||||||
<View style={styles.divider} />
|
<View style={styles.divider} />
|
||||||
{menuItem("Logout")}
|
{menuItem("Logout")}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
<LanguageModal
|
||||||
|
onClose={() => setLanguageModalVisible(false)}
|
||||||
|
visible={isLangaugeModalVisible}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const menuItem = (title: string) => (
|
const menuItem = (title: string, onPress?: () => void) => (
|
||||||
<TouchableOpacity style={styles.menuRow}>
|
<TouchableOpacity style={styles.menuRow} onPress={onPress}>
|
||||||
<Text style={styles.menuText}>{title}</Text>
|
<Text style={styles.menuText}>{title}</Text>
|
||||||
<MaterialIcons name="chevron-right" size={20} color="#555C70" />
|
<MaterialIcons name="chevron-right" size={20} color="#555C70" />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = function (api) {
|
||||||
|
api.cache(true);
|
||||||
|
return {
|
||||||
|
presets: ["babel-preset-expo"],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
import BottomSheetModal from "@/components/common/BottomSheetModal"; // adjust path
|
||||||
|
|
||||||
|
import { StyleSheet, Text, TouchableOpacity } from "react-native";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { getLanguage, setLanguage } from "@/services/i18n";
|
||||||
|
|
||||||
|
interface CustomerSupportProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function LanguageModal({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
}: CustomerSupportProps) {
|
||||||
|
const [selectedLang, setSelectedLang] = useState<"en" | "hi">("en");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const lang = await getLanguage();
|
||||||
|
setSelectedLang(lang === "hi" ? "hi" : "en");
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleLanguagePress = (lang: "en" | "hi") => {
|
||||||
|
setSelectedLang(lang);
|
||||||
|
setLanguage(lang);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<BottomSheetModal
|
||||||
|
visible={visible}
|
||||||
|
onClose={onClose}
|
||||||
|
heading="Select Language"
|
||||||
|
>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[
|
||||||
|
styles.languageCard,
|
||||||
|
selectedLang === "en" && styles.selectedCard,
|
||||||
|
]}
|
||||||
|
onPress={() => handleLanguagePress("en")}
|
||||||
|
>
|
||||||
|
<Text style={styles.languageText}>English</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[
|
||||||
|
styles.languageCard,
|
||||||
|
selectedLang === "hi" && styles.selectedCard,
|
||||||
|
]}
|
||||||
|
onPress={() => handleLanguagePress("hi")}
|
||||||
|
>
|
||||||
|
<Text style={styles.languageText}>हिन्दी</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</BottomSheetModal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
languageText: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: "#2f465e",
|
||||||
|
},
|
||||||
|
selectedCard: {
|
||||||
|
borderColor: "#009E71",
|
||||||
|
},
|
||||||
|
languageCard: {
|
||||||
|
width: "100%",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#d8dde7",
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 16,
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: "row",
|
||||||
|
gap: 16,
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
secondaryButton: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
paddingVertical: 8,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor: "#F3F5F8",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#D8DDE7",
|
||||||
|
width: 156,
|
||||||
|
gap: 8,
|
||||||
|
},
|
||||||
|
fullButton: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: "500",
|
||||||
|
color: "#252A34",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
StyleSheet,
|
||||||
|
Modal,
|
||||||
|
Pressable,
|
||||||
|
StyleProp,
|
||||||
|
ViewStyle,
|
||||||
|
} from "react-native";
|
||||||
|
import { StatusBar } from "expo-status-bar";
|
||||||
|
import CloseIcon from "../../assets/icons/close.svg";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
heading: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
containerStyle?: StyleProp<ViewStyle>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const BottomSheetModal: React.FC<Props> = ({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
heading,
|
||||||
|
children,
|
||||||
|
containerStyle,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Modal visible={visible} animationType="fade" transparent>
|
||||||
|
<StatusBar style="dark" />
|
||||||
|
<View style={styles.overlay}>
|
||||||
|
<View style={[styles.modalContainer, containerStyle]}>
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Text style={styles.headerText}>{heading}</Text>
|
||||||
|
<Pressable onPress={onClose} style={styles.iconButton}>
|
||||||
|
<CloseIcon />
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
<View style={styles.content}>{children}</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BottomSheetModal;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
backgroundColor: "rgba(0,0,0,0.5)",
|
||||||
|
},
|
||||||
|
modalContainer: {
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderTopLeftRadius: 12,
|
||||||
|
borderTopRightRadius: 12,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 16,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: "#E5E9F0",
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 8,
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
headerText: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#252A34",
|
||||||
|
},
|
||||||
|
iconButton: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
padding: 10,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
paddingVertical: 16,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -31,7 +31,7 @@ const CustomSnackbar: React.FC<CustomSnackbarProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Snackbar
|
<Snackbar
|
||||||
visible={true}
|
visible={visible}
|
||||||
onDismiss={onDismiss}
|
onDismiss={onDismiss}
|
||||||
style={[
|
style={[
|
||||||
styles.snackbar,
|
styles.snackbar,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const BatteryStatus: React.FC<BatteryStatusProps> = ({ status, style }) => {
|
||||||
case 1:
|
case 1:
|
||||||
return {
|
return {
|
||||||
text: "Charging",
|
text: "Charging",
|
||||||
backgroundColor: "#006C4D",
|
backgroundColor: "#DAF5ED",
|
||||||
textColor: "#006C4D",
|
textColor: "#006C4D",
|
||||||
};
|
};
|
||||||
case -1:
|
case -1:
|
||||||
|
|
@ -28,20 +28,14 @@ const BatteryStatus: React.FC<BatteryStatusProps> = ({ status, style }) => {
|
||||||
case 0:
|
case 0:
|
||||||
return {
|
return {
|
||||||
text: "Idle",
|
text: "Idle",
|
||||||
backgroundColor: "#565F70",
|
backgroundColor: "#D8DDE7",
|
||||||
textColor: "#565F70",
|
textColor: "#565F70",
|
||||||
};
|
};
|
||||||
case null:
|
|
||||||
return {
|
|
||||||
text: "---",
|
|
||||||
backgroundColor: "#e2e3e5",
|
|
||||||
textColor: "#6c757d",
|
|
||||||
};
|
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
text: "Unknown",
|
text: "---",
|
||||||
backgroundColor: "#f8f9fa",
|
backgroundColor: "#D8DDE7",
|
||||||
textColor: "#6c757d",
|
textColor: "#565F70",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,23 @@
|
||||||
import React from "react";
|
import BottomSheetModal from "@/components/common/BottomSheetModal"; // adjust path
|
||||||
import {
|
|
||||||
View,
|
|
||||||
Text,
|
|
||||||
StyleSheet,
|
|
||||||
Pressable,
|
|
||||||
Linking,
|
|
||||||
Modal,
|
|
||||||
} from "react-native";
|
|
||||||
import WhatsappIcon from "../../assets/icons/whatsapp.svg";
|
import WhatsappIcon from "../../assets/icons/whatsapp.svg";
|
||||||
import CallIcon from "../../assets/icons/call.svg";
|
import CallIcon from "../../assets/icons/call.svg";
|
||||||
import EmailIcon from "../../assets/icons/mail.svg";
|
import EmailIcon from "../../assets/icons/mail.svg";
|
||||||
import CloseIcon from "../../assets/icons/close.svg";
|
import { Linking, Pressable, StyleSheet, Text, View } from "react-native";
|
||||||
|
|
||||||
import { SUPPORT } from "@/constants/config";
|
import { SUPPORT } from "@/constants/config";
|
||||||
import { StatusBar } from "expo-status-bar";
|
|
||||||
|
|
||||||
type Props = {
|
interface CustomerSupportProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
};
|
}
|
||||||
|
|
||||||
const CustomerSupportModal: React.FC<Props> = ({ visible, onClose }) => {
|
export default function CustomerSupport({
|
||||||
const openWhatsApp = async () => {
|
visible,
|
||||||
|
onClose,
|
||||||
|
}: CustomerSupportProps) {
|
||||||
|
const openWhatsApp = () => {
|
||||||
const url = `https://wa.me/${
|
const url = `https://wa.me/${
|
||||||
SUPPORT.WHATSAPP_NUMBER
|
SUPPORT.WHATSAPP_NUMBER
|
||||||
}?text=${encodeURIComponent(SUPPORT.WHATSAPP_PLACEHOLDER)}`;
|
}?text=${encodeURIComponent(SUPPORT.WHATSAPP_PLACEHOLDER)}`;
|
||||||
|
|
||||||
Linking.openURL(url).catch((err) =>
|
Linking.openURL(url).catch((err) =>
|
||||||
console.log("Failed to open WhatsApp:", err)
|
console.log("Failed to open WhatsApp:", err)
|
||||||
);
|
);
|
||||||
|
|
@ -43,84 +35,33 @@ const CustomerSupportModal: React.FC<Props> = ({ visible, onClose }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal visible={visible} animationType="fade" transparent>
|
<BottomSheetModal
|
||||||
<StatusBar style="dark" />
|
visible={visible}
|
||||||
<View style={styles.overlay}>
|
onClose={onClose}
|
||||||
<View style={styles.modalContainer}>
|
heading="Customer Support"
|
||||||
{/* Header */}
|
>
|
||||||
<View style={styles.header}>
|
<View style={styles.row}>
|
||||||
<Text style={styles.headerText}>Customer Support</Text>
|
<Pressable style={styles.secondaryButton} onPress={openWhatsApp}>
|
||||||
<Pressable onPress={onClose} style={styles.iconButton}>
|
<WhatsappIcon />
|
||||||
<CloseIcon />
|
<Text style={styles.buttonText}>Whatsapp</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
<Pressable style={styles.secondaryButton} onPress={makePhoneCall}>
|
||||||
|
<CallIcon />
|
||||||
{/* Buttons */}
|
<Text style={styles.buttonText}>Call Us</Text>
|
||||||
<View style={styles.content}>
|
</Pressable>
|
||||||
<View style={styles.row}>
|
|
||||||
<Pressable style={styles.secondaryButton} onPress={openWhatsApp}>
|
|
||||||
<WhatsappIcon />
|
|
||||||
<Text style={styles.buttonText}>Whatsapp</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable style={styles.secondaryButton} onPress={makePhoneCall}>
|
|
||||||
<CallIcon />
|
|
||||||
<Text style={styles.buttonText}>Call Us</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
<Pressable
|
|
||||||
style={[styles.secondaryButton, styles.fullButton]}
|
|
||||||
onPress={sendEmail}
|
|
||||||
>
|
|
||||||
<EmailIcon />
|
|
||||||
<Text style={styles.buttonText}>Email</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</Modal>
|
<Pressable
|
||||||
|
style={[styles.secondaryButton, styles.fullButton]}
|
||||||
|
onPress={sendEmail}
|
||||||
|
>
|
||||||
|
<EmailIcon />
|
||||||
|
<Text style={styles.buttonText}>Email</Text>
|
||||||
|
</Pressable>
|
||||||
|
</BottomSheetModal>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default CustomerSupportModal;
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
overlay: {
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
backgroundColor: "rgba(0,0,0,0.5)",
|
|
||||||
},
|
|
||||||
modalContainer: {
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
borderTopLeftRadius: 12,
|
|
||||||
borderTopRightRadius: 12,
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
paddingVertical: 16,
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: "#E5E9F0",
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
paddingVertical: 8,
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
},
|
|
||||||
headerText: {
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: "600",
|
|
||||||
color: "#252A34",
|
|
||||||
},
|
|
||||||
iconButton: {
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
padding: 10,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
paddingVertical: 16,
|
|
||||||
gap: 16,
|
|
||||||
},
|
|
||||||
row: {
|
row: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
gap: 16,
|
gap: 16,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const MetricCard: React.FC<MetricCardProps> = ({ heading, value, unit }) => {
|
||||||
<View style={styles.textContainer}>
|
<View style={styles.textContainer}>
|
||||||
<Text style={styles.heading}>{heading}</Text>
|
<Text style={styles.heading}>{heading}</Text>
|
||||||
<Text style={styles.value}>
|
<Text style={styles.value}>
|
||||||
{value ?? "---"} {unit}
|
{value?.toFixed(2) ?? "---"} {unit}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
4
eas.json
4
eas.json
|
|
@ -3,13 +3,13 @@
|
||||||
"development": {
|
"development": {
|
||||||
"env": {
|
"env": {
|
||||||
"ENV": "development",
|
"ENV": "development",
|
||||||
"BASE_URL": "https://dev-api-service.vecmocon.com/service-buddy"
|
"BASE_URL": "https://dev-driver-saathi-api.vecmocon.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"env": {
|
"env": {
|
||||||
"ENV": "production",
|
"ENV": "production",
|
||||||
"BASE_URL": "https://dev-api-service.vecmocon.com/service-buddy"
|
"BASE_URL": "https://dev-driver-saathi-api.vecmocon.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.1.0",
|
"@expo/vector-icons": "^14.1.0",
|
||||||
"@react-native-async-storage/async-storage": "^2.2.0",
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
||||||
|
"@react-native-community/netinfo": "^11.4.1",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"@react-navigation/stack": "^7.4.2",
|
"@react-navigation/stack": "^7.4.2",
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@reduxjs/toolkit": "^2.8.2",
|
||||||
|
|
@ -30,9 +31,9 @@
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-i18next": "^15.5.3",
|
"react-i18next": "^15.5.3",
|
||||||
"react-native": "0.79.4",
|
"react-native": "0.79.4",
|
||||||
"react-native-dotenv": "^3.4.11",
|
|
||||||
"react-native-maps": "^1.24.3",
|
"react-native-maps": "^1.24.3",
|
||||||
"react-native-otp-entry": "^1.8.5",
|
"react-native-otp-entry": "^1.8.5",
|
||||||
|
"react-native-paper": "^5.14.5",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "~3.17.4",
|
||||||
"react-native-safe-area-context": "^5.4.0",
|
"react-native-safe-area-context": "^5.4.0",
|
||||||
"react-native-screens": "~4.11.1",
|
"react-native-screens": "~4.11.1",
|
||||||
|
|
@ -1537,6 +1538,28 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@callstack/react-theme-provider": {
|
||||||
|
"version": "3.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz",
|
||||||
|
"integrity": "sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"deepmerge": "^3.2.0",
|
||||||
|
"hoist-non-react-statics": "^3.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@callstack/react-theme-provider/node_modules/deepmerge": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@egjs/hammerjs": {
|
"node_modules/@egjs/hammerjs": {
|
||||||
"version": "2.0.17",
|
"version": "2.0.17",
|
||||||
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
||||||
|
|
@ -3324,6 +3347,15 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-native-community/netinfo": {
|
||||||
|
"version": "11.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-11.4.1.tgz",
|
||||||
|
"integrity": "sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": ">=0.59"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-native/assets-registry": {
|
"node_modules/@react-native/assets-registry": {
|
||||||
"version": "0.79.4",
|
"version": "0.79.4",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.4.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.4.tgz",
|
||||||
|
|
@ -11816,18 +11848,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-native-dotenv": {
|
|
||||||
"version": "3.4.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-native-dotenv/-/react-native-dotenv-3.4.11.tgz",
|
|
||||||
"integrity": "sha512-6vnIE+WHABSeHCaYP6l3O1BOEhWxKH6nHAdV7n/wKn/sciZ64zPPp2NUdEUf1m7g4uuzlLbjgr+6uDt89q2DOg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"dotenv": "^16.4.5"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@babel/runtime": "^7.20.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-native-edge-to-edge": {
|
"node_modules/react-native-edge-to-edge": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-edge-to-edge/-/react-native-edge-to-edge-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-edge-to-edge/-/react-native-edge-to-edge-1.6.0.tgz",
|
||||||
|
|
@ -11896,6 +11916,51 @@
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-paper": {
|
||||||
|
"version": "5.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.14.5.tgz",
|
||||||
|
"integrity": "sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"workspaces": [
|
||||||
|
"example",
|
||||||
|
"docs"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@callstack/react-theme-provider": "^3.0.9",
|
||||||
|
"color": "^3.1.2",
|
||||||
|
"use-latest-callback": "^0.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-safe-area-context": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-paper/node_modules/color": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^1.9.3",
|
||||||
|
"color-string": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-paper/node_modules/color-convert": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-paper/node_modules/color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/react-native-reanimated": {
|
"node_modules/react-native-reanimated": {
|
||||||
"version": "3.17.5",
|
"version": "3.17.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.17.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^14.1.0",
|
"@expo/vector-icons": "^14.1.0",
|
||||||
"@react-native-async-storage/async-storage": "^2.2.0",
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
||||||
|
"@react-native-community/netinfo": "^11.4.1",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"@react-navigation/stack": "^7.4.2",
|
"@react-navigation/stack": "^7.4.2",
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@reduxjs/toolkit": "^2.8.2",
|
||||||
|
|
@ -35,9 +36,9 @@
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-i18next": "^15.5.3",
|
"react-i18next": "^15.5.3",
|
||||||
"react-native": "0.79.4",
|
"react-native": "0.79.4",
|
||||||
"react-native-dotenv": "^3.4.11",
|
|
||||||
"react-native-maps": "^1.24.3",
|
"react-native-maps": "^1.24.3",
|
||||||
"react-native-otp-entry": "^1.8.5",
|
"react-native-otp-entry": "^1.8.5",
|
||||||
|
"react-native-paper": "^5.14.5",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "~3.17.4",
|
||||||
"react-native-safe-area-context": "^5.4.0",
|
"react-native-safe-area-context": "^5.4.0",
|
||||||
"react-native-screens": "~4.11.1",
|
"react-native-screens": "~4.11.1",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue