first commit
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
import React from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
Modal,
|
||||
StyleSheet,
|
||||
} from "react-native";
|
||||
import Share from "react-native-share";
|
||||
import RNFS from "react-native-fs";
|
||||
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
|
||||
export default function AndroidShareModal({ visible, imageUri, onClose }) {
|
||||
const moveToExternal = async (uri) => {
|
||||
const filename = "shared_image.jpg"; // or png
|
||||
const dest = RNFS.PicturesDirectoryPath + "/" + filename; // public folder
|
||||
// Copy file
|
||||
await RNFS.copyFile(uri.replace("file://", ""), dest);
|
||||
return "file://" + dest; // add file:// for sharing
|
||||
};
|
||||
const shareOptions = [
|
||||
{
|
||||
name: "Instagram",
|
||||
social: Share.Social.INSTAGRAM,
|
||||
icon: "instagram",
|
||||
color: "#E1306C",
|
||||
package: "com.instagram.android"
|
||||
},
|
||||
{
|
||||
name: "WhatsApp",
|
||||
social: Share.Social.WHATSAPP,
|
||||
icon: "whatsapp", // MaterialCommunityIcons name
|
||||
color: "#25D366", // WhatsApp green
|
||||
package: "com.whatsapp"
|
||||
},
|
||||
{
|
||||
name: "Facebook",
|
||||
social: Share.Social.FACEBOOK,
|
||||
icon: "facebook",
|
||||
color: "#1877F2",
|
||||
package: "com.facebook.katana"
|
||||
},
|
||||
{
|
||||
name: "Twitter / X",
|
||||
social: Share.Social.TWITTER,
|
||||
icon: "twitter",
|
||||
color: "#000",
|
||||
package: "com.twitter.android"
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
const shareTo = async (socialApp) => {
|
||||
try {
|
||||
// Copy file from cache → external
|
||||
const finalUri = await moveToExternal(imageUri);
|
||||
console.log("finalUri", socialApp)
|
||||
await Share.shareSingle({
|
||||
url: imageUri,
|
||||
social: Share.Social.WHATSAPP,
|
||||
type: "image/jpeg",
|
||||
});
|
||||
onClose();
|
||||
} catch (e) {
|
||||
console.log("Share Error:", e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal visible={visible} transparent animationType="slide">
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.modal}>
|
||||
|
||||
<View style={styles.handle} />
|
||||
|
||||
<Text style={styles.title}>Share your Selfie</Text>
|
||||
|
||||
<View style={styles.optionsRow}>
|
||||
{shareOptions.map((opt, index) => (
|
||||
<TouchableOpacity
|
||||
key={index}
|
||||
style={styles.option}
|
||||
onPress={() => shareTo(opt.social)}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name={opt.icon}
|
||||
size={45}
|
||||
color={opt.color}
|
||||
/>
|
||||
<Text style={styles.optionText}>{opt.name}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.cancelBtn} onPress={onClose}>
|
||||
<Text style={styles.cancelText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
justifyContent: "flex-end",
|
||||
backgroundColor: "rgba(0,0,0,0.5)",
|
||||
},
|
||||
modal: {
|
||||
backgroundColor: "#fff",
|
||||
borderTopLeftRadius: 25,
|
||||
borderTopRightRadius: 25,
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 15,
|
||||
paddingBottom: 25,
|
||||
},
|
||||
handle: {
|
||||
width: 45,
|
||||
height: 5,
|
||||
backgroundColor: "#ccc",
|
||||
borderRadius: 3,
|
||||
alignSelf: "center",
|
||||
marginBottom: 15,
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
marginBottom: 20,
|
||||
},
|
||||
optionsRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-around",
|
||||
marginBottom: 15,
|
||||
},
|
||||
option: {
|
||||
alignItems: "center",
|
||||
width: 90,
|
||||
},
|
||||
optionText: {
|
||||
marginTop: 6,
|
||||
fontSize: 15,
|
||||
fontWeight: "500",
|
||||
textAlign: "center",
|
||||
},
|
||||
cancelBtn: {
|
||||
backgroundColor: "#f2f2f2",
|
||||
paddingVertical: 12,
|
||||
borderRadius: 10,
|
||||
},
|
||||
cancelText: {
|
||||
color: "red",
|
||||
fontSize: 17,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,306 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import {
|
||||
Modal,
|
||||
View,
|
||||
Text,
|
||||
Image,
|
||||
TouchableOpacity,
|
||||
StyleSheet, ActionSheetIOS,
|
||||
} from "react-native";
|
||||
import * as ImagePicker from "react-native-image-crop-picker";
|
||||
import ViewShot from "react-native-view-shot";
|
||||
import { Ionicons } from "./icons";
|
||||
import Share from "react-native-share";
|
||||
import AndroidShareModal from "./AndroidShareModal";
|
||||
|
||||
export default function BadgeModal({ visible, onClose, onSave }) {
|
||||
// Android share modal state
|
||||
const [shareUri, setShareUri] = useState(null);
|
||||
const [showShareModal, setShowShareModal] = useState(false);
|
||||
const [photo, setPhoto] = useState(null);
|
||||
const shotRef = useRef(null);
|
||||
|
||||
const openCamera = () => {
|
||||
ImagePicker.openCamera({
|
||||
width: 300, // crop width
|
||||
height: 400,
|
||||
cropping: true,
|
||||
//freeStyleCropEnabled: true, // allows user to crop any way they want
|
||||
cropperToolbarTitle: "Crop your selfie", // optional
|
||||
compressImageQuality: 0.8, // optional
|
||||
mediaType: 'photo',
|
||||
useFrontCamera: true, // selfie only
|
||||
})
|
||||
.then(image => {
|
||||
console.log(image.path);
|
||||
setPhoto(image.path); // set captured & cropped photo
|
||||
})
|
||||
.catch(e => {
|
||||
if (e.code === 'E_PICKER_CANCELLED') {
|
||||
console.log('User cancelled image picker');
|
||||
} else {
|
||||
console.log('Error: ', e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const sharePhoto = async () => {
|
||||
try {
|
||||
if (!shotRef.current) return;
|
||||
setTimeout(async () => {
|
||||
const uri = await shotRef.current.capture();
|
||||
onSave(uri);
|
||||
// setShareUri(uri);
|
||||
// setShowShareModal(true);
|
||||
onClose();
|
||||
setTimeout(() => {
|
||||
setPhoto(null);
|
||||
}, 1000);
|
||||
const options = {
|
||||
title: "Share Image",
|
||||
url: uri, // file:// or base64
|
||||
type: "image/jpeg",
|
||||
};
|
||||
await Share.open(options);
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
console.log("Share Error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal visible={visible} transparent animationType="fade">
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.card}>
|
||||
|
||||
{/* CLOSE */}
|
||||
<TouchableOpacity style={styles.closeBtn} onPress={onClose}>
|
||||
<Text style={styles.closeText}>×</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* The layout that will be exported */}
|
||||
<ViewShot ref={shotRef} options={{ format: "png", quality: 1, backgroundColor: "#FFFFFF", }}>
|
||||
<View style={styles.badgeContainer}>
|
||||
|
||||
{/* Badge frame + photo */}
|
||||
<View style={styles.centerWrapper}>
|
||||
<Image
|
||||
source={require("../assets/badge.png")}
|
||||
style={styles.badgeFrame}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
|
||||
{photo && (
|
||||
<Image
|
||||
source={{ uri: photo }}
|
||||
style={styles.profilePhoto}
|
||||
onLoadEnd={() => console.log("Photo loaded")}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
{!photo ? (
|
||||
<Text
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
fontSize: 20,
|
||||
lineHeight: 28,
|
||||
fontWeight: '500',
|
||||
paddingHorizontal: 20,
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontWeight: '900', color: 'black' }}>
|
||||
Smile, Click, Celebrate!
|
||||
</Text>
|
||||
{'\n'}
|
||||
Take your Retail Day selfie!
|
||||
{'\n'}
|
||||
Share it on Instagram and tag
|
||||
{'\n'}
|
||||
<Text style={{ color: '#1a73e8', fontWeight: '600' }}>
|
||||
@cpmindiasm
|
||||
</Text>
|
||||
</Text>
|
||||
|
||||
) : (
|
||||
<Text style={styles.subtext}>
|
||||
I’m a <Text style={styles.blue}>Retail Star</Text> with{"\n"}CPM India
|
||||
</Text>
|
||||
)}
|
||||
|
||||
</View>
|
||||
</ViewShot>
|
||||
|
||||
{/* ACTION BUTTONS */}
|
||||
|
||||
{!photo ? (
|
||||
<TouchableOpacity style={[styles.shareBtn, { backgroundColor: "" }]} onPress={openCamera}>
|
||||
<Ionicons name="camera" size={20} color="#000" style={{ marginRight: 8 }} />
|
||||
<Text style={styles.shareText}>Take a Selfie</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
) : (
|
||||
<View>
|
||||
<TouchableOpacity style={[styles.shareBtn, { backgroundColor: "" }]} onPress={sharePhoto}>
|
||||
<Ionicons name="share" size={20} color="#000" style={{ marginRight: 8 }} />
|
||||
<Text style={styles.shareText}>Share with friends</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={[styles.retakeBtn, { backgroundColor: "#EDF7FF", marginTop: 20, padding: 5 }]} onPress={openCamera}>
|
||||
<Ionicons name="camera" size={20} color="#000" style={{ marginRight: 8 }} />
|
||||
<Text style={styles.shareText}>Click Selfie again</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
<AndroidShareModal
|
||||
visible={showShareModal}
|
||||
imageUri={shareUri}
|
||||
onClose={() => setShowShareModal(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: "rgba(0,0,0,0.6)",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 5,
|
||||
},
|
||||
|
||||
card: {
|
||||
width: "95%",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 20,
|
||||
paddingBottom: 25,
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
closeBtn: {
|
||||
alignSelf: "flex-end",
|
||||
padding: 10,
|
||||
},
|
||||
|
||||
closeText: {
|
||||
fontSize: 30,
|
||||
width: 40, // circle width
|
||||
height: 40, // circle height
|
||||
borderRadius: 20, // half of width/height = circle
|
||||
backgroundColor: "#F2F2F2", // optional
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 4,
|
||||
textAlign: "center",
|
||||
},
|
||||
|
||||
badgeContainer: {
|
||||
width: "100%",
|
||||
padding: 15,
|
||||
alignItems: "center",
|
||||
backgroundColor: "white"
|
||||
},
|
||||
|
||||
bgImage: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
opacity: 0.25,
|
||||
borderRadius: 20,
|
||||
},
|
||||
|
||||
centerWrapper: {
|
||||
width: 300,
|
||||
height: 300,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 15,
|
||||
position: "relative",
|
||||
overflow: "hidden", // clip the photo within the badge
|
||||
},
|
||||
|
||||
badgeFrame: {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
},
|
||||
|
||||
profilePhoto: {
|
||||
width: 125,
|
||||
height: 125,
|
||||
borderRadius: 60,
|
||||
position: "absolute",
|
||||
top: "52.5%", // move to center vertically
|
||||
left: "49%",
|
||||
transform: [{ translateX: -60 }, { translateY: -60 }], // offset half of width/height
|
||||
resizeMode: "cover",
|
||||
},
|
||||
|
||||
subtextWithout: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
textAlign: "center",
|
||||
color: "#000",
|
||||
},
|
||||
subtext: {
|
||||
fontSize: 25,
|
||||
fontWeight: "900",
|
||||
textAlign: "center",
|
||||
color: "#000",
|
||||
lineHeight: 30,
|
||||
},
|
||||
|
||||
blue: {
|
||||
color: "#1E73FF", // same bright blue as your sample
|
||||
fontWeight: "900",
|
||||
},
|
||||
|
||||
btn: {
|
||||
width: "90%",
|
||||
backgroundColor: "#1A73E8",
|
||||
paddingVertical: 14,
|
||||
borderRadius: 10,
|
||||
marginTop: 20,
|
||||
},
|
||||
|
||||
btnText: {
|
||||
color: "#fff",
|
||||
fontSize: 18,
|
||||
textAlign: "center",
|
||||
},
|
||||
|
||||
shareBtn: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 18,
|
||||
borderWidth: 1,
|
||||
borderColor: "#E0E0E0",
|
||||
borderRadius: 10,
|
||||
alignSelf: "center",
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
|
||||
retakeBtn: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 10,
|
||||
borderWidth: 1,
|
||||
borderColor: "#EDF7FF",
|
||||
borderRadius: 15,
|
||||
alignSelf: "center",
|
||||
backgroundColor: "#EDF7FF",
|
||||
},
|
||||
|
||||
shareText: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
color: "#000", // same black text
|
||||
},
|
||||
|
||||
});
|
||||
@@ -0,0 +1,641 @@
|
||||
import React, { useRef, useCallback, useState, useEffect, useMemo } from "react";
|
||||
import { Dimensions, Image, Platform, StatusBar, Text, TouchableOpacity, View, Animated, Alert, StyleSheet } from "react-native";
|
||||
import Reanimated, {
|
||||
Extrapolate, interpolate, runOnJS, useAnimatedProps, useAnimatedReaction, useSharedValue,
|
||||
} from 'react-native-reanimated';
|
||||
|
||||
import { customCamera, customStyles, deffontfamily, GetPageTheme, WP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { useCameraDevice, useCameraDevices, useFrameProcessor } from 'react-native-vision-camera';
|
||||
import PropTypes from 'prop-types';
|
||||
import { notify } from "./notify";
|
||||
import { hasCameraPermission } from "./geolocation";
|
||||
import { AntDesign, Entypo, MaterialCommunityIcons, MaterialIcons } from "./icons";
|
||||
import { connect } from 'react-redux';
|
||||
import { mapStateToProps, mapDispatchToProps } from '../reducers/contextProvider';
|
||||
import { launchImageLibrary } from 'react-native-image-picker';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
import { PORTRAIT } from "react-native-orientation-locker";
|
||||
import moment from "moment";
|
||||
import * as RNFS from 'react-native-fs';
|
||||
import ViewShot, { CaptureOptions, captureRef } from "react-native-view-shot";
|
||||
import { Gesture, PinchGestureHandler } from 'react-native-gesture-handler';
|
||||
import CustomModal from "./CustomModal";
|
||||
const { width, height } = Dimensions.get('window');
|
||||
//import { Camera } from "react-native-vision-camera-v3-image-labeling";
|
||||
import { Camera } from "react-native-vision-camera";
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
//useImageLabeler
|
||||
const VC_OR = {
|
||||
"landscapeLeft": "landscapeLeft",
|
||||
"landscapeRight": "landscapeRight",
|
||||
"portraitUpsideDown": "portraitUpsideDown",
|
||||
"portrait": "portrait",
|
||||
}
|
||||
|
||||
function CustomCamera(props) {
|
||||
const cameraRef = useRef(null);
|
||||
const route = useRoute();
|
||||
const navigation = useNavigation();
|
||||
const PageTheme = GetPageTheme(props.DarkTheme, route.name);
|
||||
const cameraStyle = customCamera(props.DarkMode, route.name);
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
const camera = useRef(null)
|
||||
const viewShotRef = useRef();
|
||||
const devices = useCameraDevices();
|
||||
const supportsCameraFlipping = useMemo(() => devices.back != null && devices.front != null, [devices.back, devices.front]);
|
||||
const dim = Dimensions.get("window");
|
||||
const [barcode, setBarcode] = React.useState({});
|
||||
const [qrCodeEnable, setQRCodeEnable] = useState(false);
|
||||
const orAnim = useRef(new Animated.Value(0)).current;
|
||||
const [showImage, setshowImage] = useState(false);
|
||||
const [imgurl, setimgurl] = useState('');
|
||||
const [temp_imgurl, setTemp_imgurl] = useState('');
|
||||
const [BottomText, setBottomText] = useState(props.BottomText || '');
|
||||
const [TopText, setTopText] = useState('');
|
||||
const [photoObj, setPhotoObj] = useState({});
|
||||
const [isActive, setisActive] = useState(false);
|
||||
const [isPhotoTaken, setIsPhotoTaken] = useState(false);
|
||||
const [isCameraActive, setIsCameraActive] = useState(false);
|
||||
const [activeFlashMode, setActiveFlashMode] = useState('off');
|
||||
|
||||
const [orientation, setOrientation] = useState(PORTRAIT.toLowerCase());
|
||||
const [islandscape, setIslandscape] = useState(false);
|
||||
const [showCameraForScreen, setShowCameraForScreen] = useState(true);
|
||||
const [gridEnable, setGridEnable] = useState(false);
|
||||
const [showCapLandsImgAlert, setShowCapLandsImgAlert] = useState(false);
|
||||
const [count, setCount] = useState(0);
|
||||
const [ImageExtraSPace, setImageExtraSPace] = useState(1.06);
|
||||
const [cameraPosition, setCameraPosition] = useState((props.cameraType == 'front' ? 'front' : 'back'));
|
||||
const devices1 = useCameraDevice(props.cameraType == 'front' ? 'front' : 'back');
|
||||
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera)
|
||||
////detect object
|
||||
const alertShown = useRef(false);
|
||||
const TARGET_LABELS = [
|
||||
'Mobile phone',
|
||||
'TV',
|
||||
'Television',
|
||||
'Tablet',
|
||||
'Laptop',
|
||||
'Computer',
|
||||
'Musical instrument'
|
||||
];
|
||||
|
||||
const onDataReceived = useCallback((data) => {
|
||||
// console.log("data_new", data)
|
||||
// if (alertShown.current) return;
|
||||
|
||||
// const filtered = data.filter(item =>
|
||||
// TARGET_LABELS.includes(item.label)
|
||||
// );
|
||||
// if (filtered.length > 0) {
|
||||
// console.log("filtered_new", filtered)
|
||||
// alertShown.current = true;
|
||||
// Alert.alert(
|
||||
// '⚠️ Warning!',
|
||||
// 'Fake image detected!',
|
||||
// [{
|
||||
// text: 'OK', onPress: () => {
|
||||
// console.log("ddlfkdff")
|
||||
// navigation.goBack();
|
||||
// }
|
||||
// }]
|
||||
// );
|
||||
// }
|
||||
}, []);
|
||||
|
||||
Reanimated.addWhitelistedNativeProps({
|
||||
zoom: true,
|
||||
})
|
||||
const zoom = useSharedValue(0)
|
||||
zoom.value = 0
|
||||
// const minZoom = device?.minZoom ?? 1;
|
||||
const minZoom = devices1?.minZoom ?? 1;
|
||||
const maxZoom = Math.min(devices1?.maxZoom ?? 1, 20);
|
||||
const onZoomPress = useCallback(() => {
|
||||
// setCount(count+1)
|
||||
zoom.value = withSpring(count)
|
||||
}, [count])
|
||||
const SCALE_FULL_ZOOM = 3;
|
||||
// const zoom = useSharedValue(1);
|
||||
const startZoom = useSharedValue(1);
|
||||
const onPinchGesture = Gesture.Pinch()
|
||||
.onBegin(() => {
|
||||
startZoom.value = zoom.value;
|
||||
})
|
||||
.onUpdate((event) => {
|
||||
// Map pinch scale to linear zoom
|
||||
const scale = interpolate(
|
||||
event.scale,
|
||||
[1 - 1 / SCALE_FULL_ZOOM, 1, SCALE_FULL_ZOOM],
|
||||
[-1, 0, 1],
|
||||
Extrapolate.CLAMP
|
||||
);
|
||||
zoom.value = interpolate(
|
||||
scale,
|
||||
[-1, 0, 1],
|
||||
[minZoom, startZoom.value, maxZoom],
|
||||
Extrapolate.CLAMP
|
||||
);
|
||||
});
|
||||
|
||||
const animatedProps = useAnimatedProps(
|
||||
() => ({ zoom: zoom.value }),
|
||||
[zoom]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
let showGrid = props.gridEnable != null ? (props.gridEnable) : false;
|
||||
setGridEnable(showGrid);
|
||||
}, [props.gridEnable])
|
||||
|
||||
useEffect(() => {
|
||||
let showQRCam = props.QRCodeEnable != null ? (props.QRCodeEnable) : false;
|
||||
setQRCodeEnable(showQRCam);
|
||||
}, [props.QRCodeEnable])
|
||||
|
||||
useEffect(() => {
|
||||
console.log('CameraGallery in camera :', props.CameraGallery, 'for screen:', props.enableGallerForScreen);
|
||||
let showScreenCam = props.enableGallerForScreen != null ? (props.enableGallerForScreen) : true;
|
||||
setShowCameraForScreen(showScreenCam);
|
||||
hasCameraPermission();
|
||||
Orientation.addDeviceOrientationListener((orientation) => {
|
||||
let or = orientation.toLowerCase();
|
||||
if (or == 'unknown') or = 'portrait';
|
||||
let isLS = (or == 'landscape-left' || or == 'landscape-right' || or == 'landscape');
|
||||
let or_VC = or == 'landscape-left' ? VC_OR.landscapeRight : (or == 'landscape-right' ? VC_OR.landscapeLeft : (or == 'portrait-upside-down' ? VC_OR.portraitUpsideDown : VC_OR.portrait));
|
||||
setOrientation(or_VC);
|
||||
setIslandscape(isLS);
|
||||
Animated.timing(orAnim, {
|
||||
toValue: isLS ? 1 : 0,
|
||||
duration: 400,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
|
||||
console.log("onchange:", orientation, or_VC);
|
||||
});
|
||||
|
||||
return () => {
|
||||
Orientation.removeOrientationListener((orientation) => { console.log("or listener removed") });
|
||||
Orientation.removeAllListeners();
|
||||
}
|
||||
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('showCamera changed:', props.showCamera);
|
||||
alertShown.current = false;
|
||||
if (props.showCamera == true) {
|
||||
showCamera();
|
||||
}
|
||||
else {
|
||||
hideCamera();
|
||||
}
|
||||
}, [props.showCamera]);
|
||||
|
||||
function showCamera() {
|
||||
console.log('showCamera customcamera');
|
||||
if (props.cameraType != 'front') {
|
||||
setShowCapLandsImgAlert(true);
|
||||
setTimeout(() => {
|
||||
setShowCapLandsImgAlert(false);
|
||||
}, 1500);
|
||||
}
|
||||
setIsCameraActive(true);
|
||||
setisActive(true);
|
||||
}
|
||||
|
||||
async function hideCamera(type = '') {
|
||||
setIsCameraActive(false);
|
||||
setisActive(false);
|
||||
setimgurl('');
|
||||
setIsPhotoTaken(false);
|
||||
setshowImage(true);
|
||||
console.log("isCameraScreen", props.isCameraScreen, type)
|
||||
if (props.isCameraScreen != null && props.isCameraScreen == true) {
|
||||
// Don't call onHideCamera if it is a camera screen
|
||||
if (type == 'cancel') {
|
||||
props.onHideCamera();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (props.onHideCamera != null && typeof props.onHideCamera == 'function') {
|
||||
props.onHideCamera();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeCamera() {
|
||||
setIsCameraActive(false);
|
||||
}
|
||||
const onFlipCameraPressed = useCallback(() => {
|
||||
setCameraPosition((p) => (p === 'back' ? 'front' : 'back'));
|
||||
}, []);
|
||||
|
||||
async function takePhoto() {
|
||||
console.log("Take foto")
|
||||
if (camera.current != null && typeof camera.current === 'object') {
|
||||
const photo = await camera.current.takePhoto({
|
||||
flash: activeFlashMode,
|
||||
})
|
||||
// console.log("taken photo params:",photo)
|
||||
if (photo != null) {
|
||||
let path = 'file://' + photo.path;
|
||||
let picture_clicked_time = moment().format('DD-MM-YYYY HH:mm:ss');
|
||||
console.log(path);
|
||||
// required larger height of image for landscape image
|
||||
let ExtraSpace = 1.1; // portrait image def
|
||||
if (photo.width > photo.height) {
|
||||
// landscape image
|
||||
ExtraSpace = 1.2
|
||||
}
|
||||
|
||||
console.log("takephhoto:w x h", photo.width, photo.height, photo);
|
||||
let obj = { uri: path, original_path: photo.path, width: parseInt(photo.width), height: parseInt(photo.height), ExtendedHeight: parseInt(photo.height * ExtraSpace), or_Mode: orientation };
|
||||
setImageExtraSPace(ExtraSpace);
|
||||
setPhotoObj(obj);
|
||||
setTemp_imgurl(path)
|
||||
let bText = props.BottomText + " | Date: " + picture_clicked_time;
|
||||
setBottomText(bText);
|
||||
setTopText(picture_clicked_time);
|
||||
setIsPhotoTaken(true);
|
||||
}
|
||||
else {
|
||||
notify('Something went wrong! Cannot take picture.');
|
||||
setisActive(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
notify('Camera not found!.');
|
||||
setisActive(false);
|
||||
}
|
||||
|
||||
closeCamera();
|
||||
}
|
||||
|
||||
async function onRetake() {
|
||||
await RNFS.unlink(temp_imgurl);
|
||||
// setTemp_imgurl('');
|
||||
setIsPhotoTaken(false);
|
||||
setshowImage(false);
|
||||
setIsCameraActive(true);
|
||||
setisActive(true);
|
||||
}
|
||||
async function onCameraImgOk() {
|
||||
zoom.value = 0
|
||||
let obj = photoObj;
|
||||
obj.viewShotRef = viewShotRef;
|
||||
setPhotoObj(obj);
|
||||
setisActive(false);
|
||||
setIsPhotoTaken(false);
|
||||
setshowImage(true);
|
||||
if (props.onImageCaptured != null && typeof props.onImageCaptured == 'function') {
|
||||
props.onImageCaptured(obj);
|
||||
}
|
||||
|
||||
hideCamera();
|
||||
}
|
||||
|
||||
async function onQRScanned(qrData) {
|
||||
console.log("qrData:", qrData.data);
|
||||
setisActive(false);
|
||||
if (props.onImageCaptured != null && typeof props.onImageCaptured == 'function') {
|
||||
let QR_withValidChars = qrData.data != null && qrData.data != '' ? qrData.data.replace(/["']/g, '') : '';
|
||||
props.onImageCaptured(QR_withValidChars);
|
||||
}
|
||||
hideCamera();
|
||||
}
|
||||
|
||||
function flashOnOff(type = '') {
|
||||
console.log('setflashmode:', type);
|
||||
if (type != '' && type != null) {
|
||||
setActiveFlashMode(type);
|
||||
if (type == 'on') {
|
||||
|
||||
}
|
||||
else if (type == 'off') {
|
||||
|
||||
}
|
||||
else if (type == 'auto') {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pickGalleryImage(img) {
|
||||
console.log('pickGalleryImage:', img, typeof img.assets);
|
||||
if (img != null && img.assets != null && typeof img.assets == 'object' && img.assets.length > 0 && img.assets[0].uri != null) {
|
||||
let photo = img.assets[0];
|
||||
let path = photo.uri;
|
||||
console.log(path);
|
||||
let times = photo.timestamp != null && photo.timestamp != '' ? photo.timestamp : new Date();
|
||||
let obj = { uri: path, width: photo.width, height: photo.height, 'fromGallery': true, 'datetime': times };
|
||||
setPhotoObj(obj);
|
||||
setTemp_imgurl(path)
|
||||
let picture_clicked_time = moment().format('DD-MM-YYYY HH:mm:ss');
|
||||
let bText = props.BottomText + " | " + picture_clicked_time;
|
||||
|
||||
setTopText(picture_clicked_time);
|
||||
setBottomText(bText);
|
||||
setIsPhotoTaken(true);
|
||||
}
|
||||
else {
|
||||
notify('Something went wrong! Cannot take picture.');
|
||||
setisActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
function getImageFromGallery() {
|
||||
launchImageLibrary({ mediaType: 'photo', selectionLimit: 1, includeExtra: true, cameraType: 'front' }, pickGalleryImage)
|
||||
}
|
||||
|
||||
function _renderCaptureBtn() {
|
||||
return (
|
||||
<>
|
||||
<TouchableOpacity style={cameraStyle.customCamera_capbtn} onPress={() => { takePhoto(); }}>
|
||||
<View style={cameraStyle.customCamera_capbtn_Outer}><View style={cameraStyle.customCamera_capbtn_Inner}></View></View>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderGalleryBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.customCamera_Gallerybtn} onPress={() => { getImageFromGallery() }}>
|
||||
<View style={cameraStyle.customCamera_Gallerybtn_Outer}>
|
||||
<View style={cameraStyle.customCamera_Gallerybtn_Inner}>
|
||||
<Entypo name='images' size={32} color={PageTheme.$text_color} style={cameraStyle.customCamera_Gallerybtn_Icon} />
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderBottomControls() {
|
||||
return (
|
||||
<View style={(cameraStyle.customCamera_bottomBar)}>
|
||||
{_renderCaptureBtn()}
|
||||
{props.CameraGallery == true && showCameraForScreen == true &&
|
||||
_renderGalleryBtn()
|
||||
}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
function _renderOrientationIcon() {
|
||||
let deg = 0;
|
||||
if (orAnim != null) {
|
||||
deg = orAnim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['0deg', '90deg'],
|
||||
});
|
||||
}
|
||||
return (
|
||||
<Animated.View style={[cameraStyle.or_icon, { transform: [{ rotate: deg }], }]}>
|
||||
<AntDesign name='mobile1' color={'#ffffffdb'} size={18} />
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderCancelBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.imgControls_btnCon} onPress={() => { hideCamera('cancel') }}>
|
||||
<View style={cameraStyle.imgControls_btn}>
|
||||
<MaterialCommunityIcons name='cancel' color={'#fff'} size={18} />
|
||||
<Text style={[cameraStyle.imgControls_btnText, cameraStyle.icbtTop]}>Cancel</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderRetakeBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.imgControls_centerBtn} onPress={() => { onRetake() }}>
|
||||
<View style={cameraStyle.imgControls_btn}>
|
||||
<View style={cameraStyle.imgControls_retakeBtn}>
|
||||
<MaterialCommunityIcons name='camera-retake' color={'#000'} size={30} />
|
||||
</View>
|
||||
<Text style={[cameraStyle.imgControls_btnText, cameraStyle.icbtTop]}>Retake</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _renderSaveImgBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.imgControls_btnCon} onPress={() => { onCameraImgOk() }}>
|
||||
<View style={cameraStyle.imgControls_btn}>
|
||||
<MaterialCommunityIcons name='check' color={'#fff'} size={18} />
|
||||
<Text style={[cameraStyle.imgControls_btnText, cameraStyle.icbtTop]}>Ok</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _renderImageControls() {
|
||||
return (
|
||||
<SafeAreaView style={cameraStyle.customCamera_bottomBar2}>
|
||||
<View style={cameraStyle.imgControls}>
|
||||
{_renderCancelBtn()}
|
||||
{_renderRetakeBtn()}
|
||||
{_renderSaveImgBtn()}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderFlashBtn(type = 'on') {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.flashBtn} onPress={() => { flashOnOff(type) }}>
|
||||
{type == 'on' && <MaterialCommunityIcons name='flash' color={(activeFlashMode == 'on' ? '#ffe600' : '#fff')} size={24} />}
|
||||
{type == 'off' && <MaterialCommunityIcons name='flash-off' color={(activeFlashMode == 'off' ? '#ffe600' : '#fff')} size={24} />}
|
||||
{type == 'auto' && <MaterialCommunityIcons name='flash-auto' color={(activeFlashMode == 'auto' ? '#ffe600' : '#fff')} size={24} />}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderCameraSwapMode() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.flashBtn} onPress={() => { onFlipCameraPressed() }}>
|
||||
{cameraPosition == 'front' && <MaterialIcons name='flip-camera-ios' color={'#ffe600'} size={24} />}
|
||||
{cameraPosition == 'back' && <MaterialIcons name='flip-camera-android' color={'#fff'} size={24} />}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderTopControls() {
|
||||
return (
|
||||
<View style={cameraStyle.topControls}>
|
||||
<View style={cameraStyle.topControlsInner}>
|
||||
{_renderFlashBtn('on')}
|
||||
{_renderFlashBtn('off')}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderSideControls() {
|
||||
|
||||
let enableCameraFlip = props.enableCameraFlip != null ? (props.enableCameraFlip) : false;
|
||||
return (
|
||||
<View style={(cameraStyle.sideControls)}>
|
||||
<View style={cameraStyle.sideControlsInner}>
|
||||
{_renderFlashBtn('on')}
|
||||
{_renderFlashBtn('off')}
|
||||
{supportsCameraFlipping && enableCameraFlip == true &&
|
||||
_renderCameraSwapMode()
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
const cameraAnimatedProps = useAnimatedProps(() => {
|
||||
const z = Math.max(Math.min(zoom.value, maxZoom), minZoom);
|
||||
return {
|
||||
zoom: z,
|
||||
};
|
||||
}, [maxZoom, minZoom, zoom]);
|
||||
|
||||
|
||||
|
||||
const cameraView = () => {
|
||||
// return (
|
||||
// <QRCodeScanner
|
||||
// onRead={onQRScanned}
|
||||
// showMarker={true}
|
||||
// cameraStyle={[cameraStyle.customCamera, (islandscape || props.cameraType == 'front' ? cameraStyle.customCameraLS : {})]} //(props.cameraType!='front'?{}:cameraStyle.customCameraTop)
|
||||
// />
|
||||
// )
|
||||
}
|
||||
|
||||
function _render_AutoAlertModal() {
|
||||
return (
|
||||
<CustomModal
|
||||
style={customStyle.storelVisitM_Style}
|
||||
title={"Please click image in landscape mode!"}
|
||||
titleStyle={customStyle.storelVisitM_titleStyle}
|
||||
showModal={showCapLandsImgAlert}
|
||||
>
|
||||
<View></View>
|
||||
</CustomModal>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderSCreenSHotView() {
|
||||
let is_photo_mode_LS = (photoObj.or_Mode == VC_OR.landscapeLeft || photoObj.or_Mode == VC_OR.landscapeRight)
|
||||
let imgSIze = (photoObj.or_Mode != null && photoObj.or_Mode != '' ? (is_photo_mode_LS ? { width: '100%' } : { height: '100%' }) : {});
|
||||
let vieshotStyle = {};
|
||||
let itemW = photoObj.width, itemH = photoObj.height;
|
||||
|
||||
let hR = (itemH / itemW) * 100;
|
||||
let screenWidth = WP('100%');
|
||||
let ht = screenWidth * (hR / 100);
|
||||
vieshotStyle = { width: '100%', height: ht };
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<View style={[cameraStyle.customCamera_Wrap, { justifyContent: 'center', alignItems: 'center' }]}>
|
||||
{temp_imgurl != null && temp_imgurl != '' &&
|
||||
<View style={[vieshotStyle]} >
|
||||
{/* (props.cameraType == 'front' && Platform.OS=='ios' ? { transform: [{ scaleX: -1 }] } : {}) */}
|
||||
<Image source={{ uri: temp_imgurl }} style={[imgSIze, cameraStyle.cameraImgCaptured]} resizeMode={'contain'} />
|
||||
</View>}
|
||||
{_renderImageControls()}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[cameraStyle.CameraWrapper, (props.showCamera == true && isActive == true ? {} : cameraStyle.CameraWrapperHide)]} >
|
||||
{temp_imgurl != null && temp_imgurl != '' &&
|
||||
<View style={{ position: 'absolute', left: 0, top: 0, opacity: 0 }}>
|
||||
<ViewShot ref={viewShotRef} options={{ format: "jpg", quality: 1.0 }} >
|
||||
<View collapsable={false} style={{ width: photoObj.width, height: parseInt(photoObj.height * ImageExtraSPace), backgroundColor: '#fff' }} >
|
||||
<Image source={{ uri: temp_imgurl }} style={[{ width: photoObj.width, height: photoObj.height }, cameraStyle.cameraImgCaptured, (props.cameraType == 'front' ? { transform: [{ scaleX: -1 }] } : {})]} />
|
||||
{TopText != null && TopText != '' && <Text style={{ position: 'absolute', left: 10, top: 10, fontFamily: deffontfamily, color: 'red', fontSize: parseInt(photoObj.width * 0.04) }} >{TopText}</Text>}
|
||||
{BottomText != null && BottomText != '' && <Text style={{ position: 'absolute', left: 0, paddingHorizontal: 5, top: (photoObj.height + 5), fontFamily: deffontfamily, color: 'red', fontSize: parseInt(photoObj.width * 0.03), flexWrap: 'wrap' }} >{BottomText}</Text>}
|
||||
</View>
|
||||
</ViewShot>
|
||||
</View>
|
||||
}
|
||||
{props.showCamera == true && isActive == true &&
|
||||
<View style={cameraStyle.scrollMain}>
|
||||
<StatusBar translucent={true} hidden={true} />
|
||||
{
|
||||
Platform.OS == 'ios' &&
|
||||
<View style={cameraStyle.IOS_StatusBar}>
|
||||
</View>
|
||||
}
|
||||
{devices1 != null && isActive &&
|
||||
<View style={[cameraStyle.customCamera_Wrap]} ref={cameraRef}>
|
||||
{qrCodeEnable == true ? cameraView() :
|
||||
<>
|
||||
{_render_AutoAlertModal()}
|
||||
<PinchGestureHandler onGestureEvent={onPinchGesture} enabled={isActive}>
|
||||
<Reanimated.View style={StyleSheet.absoluteFill}>
|
||||
{/* <ReanimatedCamera
|
||||
ref={camera}
|
||||
style={[cameraStyle.customCamera, { width: '100%', height: '100%' }, (islandscape || props.cameraType == 'front' ? cameraStyle.customCameraLS : {})]} //(props.cameraType!='front'?{}:cameraStyle.customCameraTop)
|
||||
device={devices1}
|
||||
isActive={isCameraActive}
|
||||
photo={true}
|
||||
focusable={true}
|
||||
torch={activeFlashMode == 'on' ? FlashModeAction : 'off'}
|
||||
orientation={orientation}
|
||||
enableZoomGesture={true}
|
||||
animatedProps={cameraAnimatedProps}
|
||||
frameProcessor={frameProcessor}
|
||||
frameProcessorFps={2}
|
||||
// fps={60}
|
||||
// zoom={zoom.value}
|
||||
/> */}
|
||||
|
||||
<ReanimatedCamera
|
||||
key={isCameraActive ? 'active' : 'inactive'}
|
||||
ref={camera}
|
||||
style={[cameraStyle.customCamera, { width: '100%', height: '100%' }, (islandscape || props.cameraType == 'front' ? cameraStyle.customCameraLS : {})]} //(props.cameraType!='front'?{}:cameraStyle.customCameraTop)
|
||||
device={devices1}
|
||||
isActive={isCameraActive}
|
||||
photo={true}
|
||||
focusable={true}
|
||||
torch={activeFlashMode === 'on' ? 'on' : 'off'}
|
||||
orientation={orientation}
|
||||
enableZoomGesture={true}
|
||||
animatedProps={cameraAnimatedProps}
|
||||
//options={{minConfidence: 0.6}}
|
||||
//callback={onDataReceived}
|
||||
/>
|
||||
</Reanimated.View>
|
||||
</PinchGestureHandler>
|
||||
{_renderOrientationIcon()}
|
||||
{_renderBottomControls()}
|
||||
{props.cameraType != 'front' && _renderSideControls()}
|
||||
</>
|
||||
}
|
||||
</View>
|
||||
}
|
||||
{devices1 != null && (temp_imgurl != null && temp_imgurl != '') && isPhotoTaken &&
|
||||
_renderSCreenSHotView()
|
||||
}
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CustomCamera);
|
||||
|
||||
CustomCamera.propTypes = {
|
||||
cameraType: PropTypes.oneOf(['front', 'back']),
|
||||
showCamera: PropTypes.bool,
|
||||
onImageCaptured: PropTypes.func,
|
||||
onHideCamera: PropTypes.func,
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,517 @@
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import { Dimensions, Image, Platform, ScrollView, StatusBar, Text, TouchableOpacity, View } from "react-native";
|
||||
import { customCamera, customStyles, GetPageTheme, HP, WP } from "../styles/Global";
|
||||
import { customCamera_LS } from "../styles/Global_LS";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { Camera, useCameraDevices } from 'react-native-vision-camera';
|
||||
import PropTypes from 'prop-types';
|
||||
import { notify } from "./notify";
|
||||
import { hasCameraPermission } from "./geolocation";
|
||||
import { Entypo, MaterialCommunityIcons } from "./icons";
|
||||
import { useOrientation, useOrientation2 } from "../controller/functions";
|
||||
import { connect } from 'react-redux';
|
||||
import { mapStateToProps, mapDispatchToProps } from '../reducers/contextProvider';
|
||||
import { launchCamera, launchImageLibrary, CameraOptions } from 'react-native-image-picker';
|
||||
// import Orientation from 'react-native-orientation';
|
||||
import Orientation from 'react-native-orientation-locker';
|
||||
import { OrientationLocker, PORTRAIT, LANDSCAPE } from "react-native-orientation-locker";
|
||||
import moment from "moment";
|
||||
import * as RNFS from 'react-native-fs';
|
||||
import ViewShot from "react-native-view-shot";
|
||||
import { AllKpiImg } from "../../src(Camera&img)/constants/constants";
|
||||
import CustomModal from "./CustomModal";
|
||||
|
||||
function CustomCamera(props) {
|
||||
const route = useRoute();
|
||||
const PageTheme = GetPageTheme(props.DarkTheme, route.name);
|
||||
const cameraStyle = customCamera(props.DarkMode, route.name);
|
||||
// const [cameraStyle, setCameraStyle] = useState(customCamera(props.DarkMode,route.name));
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
|
||||
const camera = useRef(null)
|
||||
const viewShort = useRef();
|
||||
const devices = useCameraDevices('wide-angle-camera');
|
||||
const device = props.cameraType == 'front' ? devices.front : devices.back;
|
||||
const dim = Dimensions.get("window");
|
||||
// const [camera,setcamera]=useState(null);
|
||||
const [showImage, setshowImage] = useState(false);
|
||||
const [imgurl, setimgurl] = useState('');
|
||||
const [temp_imgurl, setTemp_imgurl] = useState('');
|
||||
const [photoObj, setPhotoObj] = useState({});
|
||||
const [isActive, setisActive] = useState(false);
|
||||
const [isPhotoTaken, setIsPhotoTaken] = useState(false);
|
||||
const [isCameraActive, setIsCameraActive] = useState(false);
|
||||
const [activeFlashMode, setActiveFlashMode] = useState('off');
|
||||
const [orientation, setOrientation] = useState(useOrientation(dim.width, dim.height));
|
||||
const [currentOr, setCurrentOr] = useState("");
|
||||
const [showCameraForScreen, setShowCameraForScreen] = useState(true);
|
||||
const [gridEnable, setGridEnable] = useState(false);
|
||||
const [showCapLandsImgAlert, setShowCapLandsImgAlert] = useState(false);
|
||||
|
||||
|
||||
|
||||
// useEffect(()=>{
|
||||
// if(device != null && (temp_imgurl != null && temp_imgurl != '') && isPhotoTaken){
|
||||
// console.log('take screenshot now2!!',photoObj.or_Mode,photoObj);
|
||||
// screenShort();
|
||||
// }
|
||||
// },[isPhotoTaken])
|
||||
|
||||
function screenShort(){
|
||||
setTimeout(function (){
|
||||
console.log('after 10 sec');
|
||||
},20*1000)
|
||||
}
|
||||
|
||||
async function screenShort2(){
|
||||
console.log('in screenShort2');
|
||||
let test = await viewShort.current.capture()
|
||||
let FileName = 'abc146.png';
|
||||
let tst = RNFS.PicturesDirectoryPath+"/Telegram"+FileName
|
||||
console.log("album--",tst, " --",test)
|
||||
|
||||
await RNFS.copyFile(test, tst).then(res=>console.log("passssedd"))
|
||||
setCurrentOr("")
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let showGrid = props.gridEnable != null ? (props.gridEnable) : false;
|
||||
|
||||
console.log("props.gridEnable-----------",props.gridEnable, " ---",showGrid)
|
||||
setGridEnable(showGrid);
|
||||
},[props.gridEnable])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
console.log('CameraGallery in camera :', props.CameraGallery, 'for screen:', props.enableGallerForScreen);
|
||||
let showScreenCam = props.enableGallerForScreen != null ? (props.enableGallerForScreen) : true;
|
||||
setShowCameraForScreen(showScreenCam);
|
||||
hasCameraPermission();
|
||||
|
||||
|
||||
// Dimensions.addEventListener('change', ({window:{width,height}})=>{
|
||||
// let or=useOrientation(width,height);
|
||||
// setOrientation(or);
|
||||
// });
|
||||
// const initial = Orientation.getInitialOrientation();
|
||||
// console.log('initial:',initial);
|
||||
Orientation.addDeviceOrientationListener((orientation) => {
|
||||
let or = useOrientation2(orientation)
|
||||
// console.log("or ------")
|
||||
setOrientation(or);
|
||||
|
||||
});
|
||||
|
||||
return () => {
|
||||
Orientation.removeOrientationListener((orientation) => {
|
||||
console.log('orientation: listener removed:', orientation);
|
||||
});
|
||||
Orientation.removeAllListeners();
|
||||
}
|
||||
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('showCamera changed:', props.showCamera);
|
||||
if (props.showCamera == true) {
|
||||
showCamera();
|
||||
}
|
||||
else {
|
||||
hideCamera();
|
||||
}
|
||||
}, [props.showCamera]);
|
||||
|
||||
function showCamera() {
|
||||
console.log('showCamera customcamera');
|
||||
if(props.cameraType != 'front' ){
|
||||
setShowCapLandsImgAlert(true);
|
||||
setTimeout(() => {
|
||||
setShowCapLandsImgAlert(false);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
setIsCameraActive(true);
|
||||
setisActive(true);
|
||||
}
|
||||
|
||||
async function hideCamera() {
|
||||
|
||||
if(temp_imgurl!=null && temp_imgurl!='')
|
||||
{
|
||||
await RNFS.unlink(temp_imgurl);
|
||||
}
|
||||
setIsCameraActive(false);
|
||||
setisActive(false);
|
||||
setPhotoObj({});
|
||||
setimgurl('');
|
||||
setIsPhotoTaken(false);
|
||||
setshowImage(true);
|
||||
setTemp_imgurl('');
|
||||
if (props.onHideCamera != null && typeof props.onHideCamera == 'function') {
|
||||
props.onHideCamera();
|
||||
}
|
||||
}
|
||||
|
||||
function closeCamera() {
|
||||
setIsCameraActive(false);
|
||||
}
|
||||
|
||||
async function takePhoto() {
|
||||
// let test = await viewShort.current.capture()
|
||||
// let FileName = 'abc143.png';
|
||||
// let tst = RNFS.PicturesDirectoryPath+"/Telegram"+FileName
|
||||
// console.log("album--",tst, " --",test)
|
||||
|
||||
// await RNFS.copyFile(test, tst).then(res=>console.log("passssedd"))
|
||||
if (camera.current != null && typeof camera.current === 'object') {
|
||||
console.log("orientation---------------current--",orientation)
|
||||
// setCurrentOr(orientation)
|
||||
const photo = await camera.current.takePhoto({
|
||||
// flash: 'on',
|
||||
})
|
||||
|
||||
// console.log("file://------1",photo)
|
||||
if (photo != null) {
|
||||
let path = 'file://' + photo.path;
|
||||
|
||||
console.log(path);
|
||||
let obj = { uri: path, width: photo.width, height: photo.height,or_Mode:orientation };
|
||||
setPhotoObj(obj);
|
||||
setTemp_imgurl(path)
|
||||
setIsPhotoTaken(true);
|
||||
}
|
||||
else {
|
||||
notify('Something went wrong! Cannot take picture.');
|
||||
setisActive(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
notify('Camera not found!.');
|
||||
setisActive(false);
|
||||
}
|
||||
closeCamera();
|
||||
}
|
||||
|
||||
async function onRetake() {
|
||||
await RNFS.unlink(temp_imgurl);
|
||||
setTemp_imgurl('');
|
||||
setIsPhotoTaken(false);
|
||||
setshowImage(false);
|
||||
setIsCameraActive(true);
|
||||
setisActive(true);
|
||||
}
|
||||
async function onCameraImgOk() {
|
||||
let test = await viewShort.current.capture()
|
||||
let obj = photoObj;
|
||||
if( gridEnable){
|
||||
obj.uri = test;
|
||||
}else{
|
||||
obj.uri = temp_imgurl;
|
||||
}
|
||||
setPhotoObj(obj);
|
||||
setimgurl(temp_imgurl);
|
||||
setisActive(false);
|
||||
setIsPhotoTaken(false);
|
||||
setshowImage(true);
|
||||
setTemp_imgurl('');
|
||||
|
||||
if (props.onImageCaptured != null && typeof props.onImageCaptured == 'function') {
|
||||
console.log('call onImageCaptured');
|
||||
props.onImageCaptured(obj);
|
||||
|
||||
}
|
||||
hideCamera();
|
||||
}
|
||||
|
||||
function flashOnOff(type = '') {
|
||||
console.log('setflashmode:', type);
|
||||
if (type != '' && type != null) {
|
||||
setActiveFlashMode(type);
|
||||
if (type == 'on') {
|
||||
|
||||
}
|
||||
else if (type == 'off') {
|
||||
|
||||
}
|
||||
else if (type == 'auto') {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pickGalleryImage(img) {
|
||||
console.log('pickGalleryImage:', img, typeof img.assets);
|
||||
if (img != null && img.assets != null && typeof img.assets == 'object' && img.assets.length > 0 && img.assets[0].uri != null) {
|
||||
let photo = img.assets[0];
|
||||
let path = photo.uri;
|
||||
console.log(path);
|
||||
let times = photo.timestamp != null && photo.timestamp != '' ? photo.timestamp : new Date();
|
||||
let obj = { uri: path, width: photo.width, height: photo.height, 'fromGallery': true, 'datetime': times };
|
||||
setPhotoObj(obj);
|
||||
setTemp_imgurl(path)
|
||||
setIsPhotoTaken(true);
|
||||
}
|
||||
else {
|
||||
notify('Something went wrong! Cannot take picture.');
|
||||
setisActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
function getImageFromGallery() {
|
||||
launchImageLibrary({ mediaType: 'photo', selectionLimit: 1, includeExtra: true, cameraType: 'front' }, pickGalleryImage)
|
||||
}
|
||||
|
||||
function _renderCaptureBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.customCamera_capbtn} onPress={() => { takePhoto(); }}>
|
||||
<View style={cameraStyle.customCamera_capbtn_Outer}><View style={cameraStyle.customCamera_capbtn_Inner}></View></View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderGalleryBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.customCamera_Gallerybtn} onPress={() => { getImageFromGallery() }}>
|
||||
<View style={cameraStyle.customCamera_Gallerybtn_Outer}>
|
||||
<View style={cameraStyle.customCamera_Gallerybtn_Inner}>
|
||||
<Entypo name='images' size={32} color={PageTheme.$text_color} style={cameraStyle.customCamera_Gallerybtn_Icon} />
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderBottomControls() {
|
||||
return (
|
||||
<View style={cameraStyle.customCamera_bottomBar}>
|
||||
{_renderCaptureBtn()}
|
||||
{props.CameraGallery == true && showCameraForScreen == true &&
|
||||
_renderGalleryBtn()
|
||||
}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderCancelBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.imgControls_btnCon} onPress={() => { hideCamera() }}>
|
||||
<View style={cameraStyle.imgControls_btn}>
|
||||
<MaterialCommunityIcons name='cancel' color={'#fff'} size={18} />
|
||||
<Text style={[cameraStyle.imgControls_btnText, cameraStyle.icbtTop]}>Cancel</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderRetakeBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.imgControls_centerBtn} onPress={() => { onRetake() }}>
|
||||
<View style={cameraStyle.imgControls_btn}>
|
||||
<View style={cameraStyle.imgControls_retakeBtn}>
|
||||
<MaterialCommunityIcons name='camera-retake' color={'#000'} size={30} />
|
||||
</View>
|
||||
<Text style={[cameraStyle.imgControls_btnText, cameraStyle.icbtTop]}>Retake</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _renderSaveImgBtn() {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.imgControls_btnCon} onPress={() => { onCameraImgOk() }}>
|
||||
<View style={cameraStyle.imgControls_btn}>
|
||||
<MaterialCommunityIcons name='check' color={'#fff'} size={18} />
|
||||
<Text style={[cameraStyle.imgControls_btnText, cameraStyle.icbtTop]}>Ok</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _renderImageControls() {
|
||||
return (
|
||||
<View style={cameraStyle.customCamera_bottomBar2}>
|
||||
<View style={cameraStyle.imgControls}>
|
||||
{_renderCancelBtn()}
|
||||
{_renderRetakeBtn()}
|
||||
{_renderSaveImgBtn()}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderFlashBtn(type = 'on') {
|
||||
return (
|
||||
<TouchableOpacity style={cameraStyle.flashBtn} onPress={() => { flashOnOff(type) }}>
|
||||
{type == 'on' && <MaterialCommunityIcons name='flash' color={(activeFlashMode == 'on' ? '#ffe600' : '#fff')} size={24} />}
|
||||
{type == 'off' && <MaterialCommunityIcons name='flash-off' color={(activeFlashMode == 'off' ? '#ffe600' : '#fff')} size={24} />}
|
||||
{type == 'auto' && <MaterialCommunityIcons name='flash-auto' color={(activeFlashMode == 'auto' ? '#ffe600' : '#fff')} size={24} />}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderTopControls() {
|
||||
return (
|
||||
<View style={cameraStyle.topControls}>
|
||||
<View style={cameraStyle.topControlsInner}>
|
||||
{_renderFlashBtn('on')}
|
||||
{_renderFlashBtn('off')}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderSideControls() {
|
||||
return (
|
||||
<View style={cameraStyle.sideControls}>
|
||||
<View style={cameraStyle.sideControlsInner}>
|
||||
{_renderFlashBtn('on')}
|
||||
{_renderFlashBtn('off')}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function _renderSCreenSHotView(){
|
||||
let imgSIze=(photoObj.or_Mode!=null && photoObj.or_Mode!='' ?(photoObj.or_Mode==='LANDSCAPE'?{width:'100%'}:{height:'100%'}):{});
|
||||
let vieshotStyle={};
|
||||
let itemW=photoObj.width,itemH=photoObj.height;
|
||||
if(photoObj.or_Mode==='LANDSCAPE'){
|
||||
if(photoObj.or_Mode===orientation){
|
||||
vieshotStyle ={width:'100%',height:'100%'};
|
||||
}
|
||||
else{
|
||||
let hR=(itemH/itemW )*100;
|
||||
let screenWidth=WP('100%');
|
||||
let ht=screenWidth*(hR/100);
|
||||
vieshotStyle ={width:'100%',height:ht};
|
||||
}
|
||||
|
||||
}
|
||||
else{
|
||||
if(photoObj.or_Mode===orientation){
|
||||
vieshotStyle ={width:'100%',height:'100%'};
|
||||
}
|
||||
else{
|
||||
let wR=(itemW/itemH )*100;
|
||||
let screenHt=WP('100%');
|
||||
let wd=screenHt*(wR/100);
|
||||
vieshotStyle ={width:wd,height:'100%'};
|
||||
}
|
||||
}
|
||||
|
||||
console.log('vieshotStyle',vieshotStyle);
|
||||
|
||||
return(
|
||||
<View style={[cameraStyle.customCamera_Wrap,{justifyContent:'center',alignItems:'center'}]}>
|
||||
<ViewShot ref={viewShort} style={[vieshotStyle,]} >
|
||||
{console.log('image is showing :')}
|
||||
<Image source={{ uri: temp_imgurl }} style={[imgSIze,cameraStyle.cameraImgCaptured, (props.cameraType == 'front' && Platform.OS == 'ios' ? { transform: [{ scaleX: -1 }] } : {})]} resizeMode={(photoObj.or_Mode===orientation?'cover':'contain')}/>
|
||||
{
|
||||
gridEnable &&
|
||||
<View style={[vieshotStyle]}>
|
||||
<View style={[{ width:"100%", height:'100%'},(orientation =="LANDSCAPE" ? {alignItems:"center"}:{justifyContent:"center"} )]}>
|
||||
<View style={[vieshotStyle,{borderColor:'#B69367',borderWidth:1}]} >
|
||||
<View style={{height:'33%',borderBottomColor:'#B69367',width:'100%',borderBottomWidth:1}}></View>
|
||||
<View style={{height:'33%',borderBottomColor:'#B69367',width:'100%',borderBottomWidth:1}}></View>
|
||||
<View style={{flexDirection:'row',position:'absolute',top:0,left:0,width:'100%',height:'100%'}}>
|
||||
<View style={{height:'100%',borderRightColor:'#B69367',width:'33%',borderRightWidth:1}}></View>
|
||||
<View style={{height:'100%',borderRightColor:'#B69367',width:'33%',borderRightWidth:1}}></View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
</ViewShot>
|
||||
{_renderImageControls()}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function _render_AutoAlertModal(){
|
||||
console.log('_render_AutoAlertModal2',showCapLandsImgAlert);
|
||||
return (
|
||||
<CustomModal
|
||||
style={customStyle.storelVisitM_Style}
|
||||
title={"Please click image in Landscape mode!"}
|
||||
titleStyle={customStyle.storelVisitM_titleStyle}
|
||||
showModal={showCapLandsImgAlert}
|
||||
>
|
||||
<View></View>
|
||||
</CustomModal>
|
||||
)
|
||||
}
|
||||
|
||||
if (props.showCamera == true && isActive == true) {
|
||||
|
||||
return (
|
||||
<View style={cameraStyle.scrollMain}>
|
||||
<OrientationLocker
|
||||
orientation={currentOr !=""? (currentOr):(orientation == 'LANDSCAPE' ? LANDSCAPE : PORTRAIT)}
|
||||
onChange={orientation => console.log('onChange', orientation)}
|
||||
onDeviceChange={orientation => console.log('onDeviceChange', orientation)}
|
||||
/>
|
||||
<StatusBar translucent={true} hidden={true} />
|
||||
|
||||
{Platform.OS == 'ios' && <View style={cameraStyle.IOS_StatusBar}></View>}
|
||||
{device != null && isActive &&
|
||||
<View style={cameraStyle.customCamera_Wrap}>
|
||||
{_render_AutoAlertModal()}
|
||||
{console.log('activeFlashMode:', activeFlashMode)}
|
||||
<Camera
|
||||
ref={camera}
|
||||
style={[cameraStyle.customCamera, (orientation == 'LANDSCAPE' || props.cameraType == 'front' ? cameraStyle.customCameraLS : {})]} //(props.cameraType!='front'?{}:cameraStyle.customCameraTop)
|
||||
device={device}
|
||||
isActive={isCameraActive}
|
||||
photo={true}
|
||||
focusable={true}
|
||||
torch={activeFlashMode}
|
||||
// enableZoomGesture={true}
|
||||
fps={60}
|
||||
/>
|
||||
{
|
||||
gridEnable &&
|
||||
<View style={[{ width:"100%",marginBottom:100},(orientation==='LANDSCAPE'?{height:'100%'}:{})]}>
|
||||
<View style={[{ width:"100%", height:'100%'},(orientation =="LANDSCAPE" ? {alignItems:"center"}:{justifyContent:"center"} )]}>
|
||||
<View style={[{ width:"100%", height:'100%',borderColor:'#B69367',borderWidth:1}]} >
|
||||
<View style={{height:'33%',borderBottomColor:'#B69367',width:'100%',borderBottomWidth:1}}></View>
|
||||
<View style={{height:'33%',borderBottomColor:'#B69367',width:'100%',borderBottomWidth:1}}></View>
|
||||
<View style={{flexDirection:'row',position:'absolute',top:0,left:0,width:'100%',height:'100%'}}>
|
||||
<View style={{height:'100%',borderRightColor:'#B69367',width:'33%',borderRightWidth:1}}></View>
|
||||
<View style={{height:'100%',borderRightColor:'#B69367',width:'33%',borderRightWidth:1}}></View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
|
||||
</View>
|
||||
}
|
||||
|
||||
{_renderBottomControls()}
|
||||
{props.cameraType != 'front' && _renderSideControls()}
|
||||
</View>
|
||||
}
|
||||
{device != null && (temp_imgurl != null && temp_imgurl != '') && isPhotoTaken &&
|
||||
_renderSCreenSHotView()
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (<View></View>)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CustomCamera);
|
||||
|
||||
CustomCamera.propTypes = {
|
||||
cameraType: PropTypes.oneOf(['front', 'back']),
|
||||
showCamera: PropTypes.bool,
|
||||
onImageCaptured: PropTypes.func,
|
||||
onHideCamera: PropTypes.func,
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
import React from 'react';
|
||||
import { Modal, View, Text, StyleSheet, TouchableOpacity, Image } from 'react-native';
|
||||
import Like from '../assets/image/Like.svg'
|
||||
import DeleteIcon from '../assets/image/delete.svg'
|
||||
import RightIcon from '../assets/image/RightIcon.svg'
|
||||
import { SvgXml } from 'react-native-svg';
|
||||
|
||||
const CompletionModal = ({ visible, onClose, correct, wrong, total, PlayerObj }) => {
|
||||
const percentage = total > 0 ? (correct / total) * 100 : 0;
|
||||
const getMessage = () => {
|
||||
if (percentage === 100) {
|
||||
return "Congrats! Perfect score!!!";
|
||||
} else if (percentage >= 71) {
|
||||
return "Well done - just a bit more !";
|
||||
} else {
|
||||
return "Can do better !";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal visible={visible} transparent animationType="fade">
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.modalContent}>
|
||||
<Like width={150} height={150}/>
|
||||
{/* <Text style={styles.title}>Congratulations!</Text> */}
|
||||
{/* <Text style={styles.subtitle}>
|
||||
Great job! You're doing fantastic.{"\n"}Keep up the excellent work!
|
||||
</Text> */}
|
||||
|
||||
<Text style={styles.subtitle}>
|
||||
{getMessage()}
|
||||
</Text>
|
||||
|
||||
<Text style={[styles.total, { marginBottom: "10%" }]}>
|
||||
TOTAL QUESTIONS: <Text style={{ fontWeight: 'bold', fontSize: 17 }}>{total}</Text>
|
||||
</Text>
|
||||
|
||||
<View style={styles.statsRow}>
|
||||
<View style={styles.statBox}>
|
||||
<View style={{ flexDirection: "row", marginBottom: 5 }} >
|
||||
<RightIcon width={20} height={20} />
|
||||
<Text style={styles.statValue}>{correct}</Text>
|
||||
</View>
|
||||
<Text style={styles.total}>CORRECT</Text>
|
||||
</View>
|
||||
<View style={styles.statBox}>
|
||||
<View style={{ flexDirection: "row", marginBottom: 5 }} >
|
||||
<DeleteIcon width={20} height={20} />
|
||||
<RightIcon width={20} height={20} />
|
||||
<Text style={styles.statValue}>{wrong}</Text>
|
||||
</View>
|
||||
<Text style={styles.total}>WRONG</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity onPress={onClose} style={styles.okButton}>
|
||||
<Text style={styles.okText}>Okay</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 16,
|
||||
padding: 24,
|
||||
alignItems: 'center',
|
||||
width: '85%',
|
||||
},
|
||||
image: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
marginBottom: 16,
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 8,
|
||||
color: '#333',
|
||||
},
|
||||
subtitle: {
|
||||
textAlign: 'center',
|
||||
fontSize: 20,
|
||||
color: '#666',
|
||||
marginBottom: 16,
|
||||
},
|
||||
total: {
|
||||
fontSize: 14,
|
||||
marginBottom: 12,
|
||||
color: '#000',
|
||||
},
|
||||
statsRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '80%',
|
||||
marginBottom: 20,
|
||||
},
|
||||
statBox: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
correctIcon: {
|
||||
fontSize: 24,
|
||||
color: 'green',
|
||||
},
|
||||
wrongIcon: {
|
||||
fontSize: 24,
|
||||
color: 'red',
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
marginLeft: 10
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: 12,
|
||||
color: '#555',
|
||||
},
|
||||
okButton: {
|
||||
backgroundColor: '#007bff',
|
||||
borderRadius: 30,
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 40,
|
||||
},
|
||||
okText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
|
||||
export default CompletionModal;
|
||||
@@ -0,0 +1,118 @@
|
||||
import React from 'react';
|
||||
import { Modal, View, Text, TouchableOpacity, StyleSheet,Image } from 'react-native';
|
||||
import CamIcon from '../assets/image/cam_icon.svg'
|
||||
import GalleryIcon from '../assets/image/gallery_icon.svg'
|
||||
|
||||
|
||||
const CustomImagePickerModal = ({ visible, onClose, onCamera, onGallery }) => {
|
||||
return (
|
||||
<Modal
|
||||
transparent
|
||||
animationType="slide"
|
||||
visible={visible}
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.sheet}>
|
||||
<Text style={styles.title}>Select Image Source</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.option}
|
||||
onPress={() => {
|
||||
onClose();
|
||||
onCamera();
|
||||
}}
|
||||
>
|
||||
{/* <Text style={styles.optionText}>📷 Take Photo</Text> */}
|
||||
<View style={styles.row}>
|
||||
|
||||
<CamIcon style={styles.icon} width={20} height={20} />
|
||||
{/* <Image
|
||||
source={require('../assets/image/camera.png')} // <-- Your PNG icon
|
||||
style={styles.icon}
|
||||
/> */}
|
||||
<Text style={styles.optionText}>Take Photo</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.option}
|
||||
onPress={() => {
|
||||
onClose();
|
||||
onGallery();
|
||||
}}
|
||||
>
|
||||
{/* <Text style={styles.optionText}>🖼️ Choose from Gallery</Text> */}
|
||||
<View style={styles.row}>
|
||||
<GalleryIcon style={styles.icon} width={20} height={20} />
|
||||
{/* <Image
|
||||
source={require('../assets/image/image-gallery.png')} // <-- Your PNG icon
|
||||
style={styles.icon}
|
||||
/> */}
|
||||
<Text style={styles.optionText}>Choose from Gallery</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.cancel} onPress={onClose}>
|
||||
<Text style={styles.optionText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomImagePickerModal;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
sheet: {
|
||||
backgroundColor: '#fff',
|
||||
padding: 20,
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20,
|
||||
elevation: 10,
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 12,
|
||||
textAlign: 'center',
|
||||
},
|
||||
option: {
|
||||
backgroundColor: '#D0ECFF',
|
||||
padding: 14,
|
||||
borderRadius: 10,
|
||||
marginVertical: 6,
|
||||
},
|
||||
cancel: {
|
||||
backgroundColor: '#f9f8f8ff',
|
||||
padding: 14,
|
||||
borderRadius: 10,
|
||||
marginTop: 10,
|
||||
borderColor:'#ADBFD8',
|
||||
borderWidth: 0.5,
|
||||
|
||||
},
|
||||
optionText: {
|
||||
color: 'black',
|
||||
fontSize: 14,
|
||||
textAlign: 'center',
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent:'center',
|
||||
|
||||
},
|
||||
icon: {
|
||||
width: 22,
|
||||
height: 22,
|
||||
marginRight: 10,
|
||||
resizeMode: 'contain',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import React from "react";
|
||||
import { Text, TouchableOpacity ,View,Image,ImageBackground,ActivityIndicator, StatusBar, Platform} from "react-native";
|
||||
import { customeButtons,GetPageTheme,customStyles,globalStyles, HP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
|
||||
const CustomLoader = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const htStyle=props.fullHeight?{height:HP('100%')+StatusBar.currentHeight}:{};
|
||||
|
||||
return (
|
||||
<View style={[customStyle.loaderBackdrop2]}>
|
||||
<View style={customStyle.loaderCon}>
|
||||
{
|
||||
Platform.OS==='ios' &&
|
||||
<View style={customStyle.spinnerCon}>
|
||||
<ActivityIndicator style={customStyle.spinner} size="large" color={PageTheme.$primary_color} />
|
||||
</View>
|
||||
}
|
||||
{
|
||||
Platform.OS!=='ios' &&
|
||||
<View style={customStyle.spinnerCon}>
|
||||
<ActivityIndicator style={customStyle.spinner} size="large" color={PageTheme.$primary_color} />
|
||||
<ActivityIndicator style={customStyle.spinnerInner2} size={32} color={PageTheme.$secondary_color_light} />
|
||||
<ActivityIndicator style={customStyle.spinnerInner} size={28} color={PageTheme.$primary_color} />
|
||||
</View>
|
||||
}
|
||||
{props.title && <Text style={customStyle.loaderTitle}>{props.title}</Text>}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default CustomLoader;
|
||||
@@ -0,0 +1,32 @@
|
||||
import React,{useRef,useEffect} from "react";
|
||||
import { Text, TouchableOpacity ,View,Image,Animated,ActivityIndicator,StatusBar} from "react-native";
|
||||
import { customeButtons,GetPageTheme,customStyles,globalStyles,HP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
|
||||
const CustomModal = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const htStyle={height:HP('100%')+StatusBar.currentHeight};
|
||||
|
||||
if(props.showModal==true){
|
||||
return (
|
||||
<View style={[customStyle.loaderBackdrop]}>
|
||||
<View style={[customStyle.customModal,props.style?props.style:{}]}>
|
||||
{(props.title!=null) && <Text style={[customStyle.customModal_Title,(props.titleStyle?props.titleStyle:{})]}>{props.title}</Text>}
|
||||
{(props.message!=null) && <Text style={[customStyle.customModal_Message,(props.messageStyle?props.messageStyle:{})]}>{props.message}</Text>}
|
||||
{props.children}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return <View></View>;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
export default CustomModal;
|
||||
@@ -0,0 +1,33 @@
|
||||
import React,{useRef,useEffect} from "react";
|
||||
import { Text, TouchableOpacity ,View,Image,Animated,ActivityIndicator,StatusBar, Keyboard, KeyboardAvoidingView} from "react-native";
|
||||
import { customeButtons,GetPageTheme,customStyles,globalStyles,HP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
|
||||
const CustomModal2 = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const htStyle={height:HP('100%')+StatusBar.currentHeight};
|
||||
|
||||
if(props.showModal==true){
|
||||
return (
|
||||
<TouchableOpacity activeOpacity={1} onPress={()=>{Keyboard.dismiss()}} style={[customStyle.loaderBackdrop,htStyle,{width:'100%'}]}>
|
||||
<View style={[customStyle.customModal,props.style?props.style:{}]}>
|
||||
{(props.title!=null) && <Text style={[customStyle.customModal_Title,(props.titleStyle?props.titleStyle:{})]}>{props.title}</Text>}
|
||||
{(props.message!=null) && <Text style={[customStyle.customModal_Message,(props.messageStyle?props.messageStyle:{})]}>{props.message}</Text>}
|
||||
{props.children}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
);
|
||||
}
|
||||
else {
|
||||
return <View></View>;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
export default CustomModal2;
|
||||
@@ -0,0 +1,180 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { customStyles, deffontfamily, GetPageTheme } from '../styles/Global';
|
||||
import ModalSelector from 'react-native-modal-selector';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
export function CustomPicker(props,Pickerdata,label_key,value_key,onchangeKeyLbl,onchangeKey,onChange=()=>{},selected_data={},selectStyle={},InputStyle={},appendIdInName='',routeParam=null,isDisable=false){
|
||||
try{
|
||||
const ST=props.StaticText || {};
|
||||
const route =routeParam!=null && routeParam.name!=null?routeParam:{name:'ABCScreen'};//useRoute();
|
||||
|
||||
// get all theme styles acc to current theme set
|
||||
const PageTheme=GetPageTheme(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
let otherData=selected_data?.otherData?selected_data?.otherData:{};
|
||||
var data=[];
|
||||
|
||||
let selectedFName='';
|
||||
Pickerdata?.map((item,index)=>{
|
||||
let label1=(item[label_key]+(appendIdInName && item[value_key]!=""?(` (${item[value_key]})`):''));
|
||||
let obj={ key: index, label: label1,value:item[value_key],item };
|
||||
if((appendIdInName==false && selected_data?.value==item[label_key]) || (appendIdInName && selected_data?.value==item[value_key])){
|
||||
selectedFName=label1;
|
||||
obj['component']= <View style={customStyle.addvis_selectedOpStyle}><Text style={customStyle.addvis_selectedOpTextStyle}>{label1}</Text></View>;
|
||||
}
|
||||
data.push(obj);
|
||||
});
|
||||
|
||||
return (
|
||||
<ModalSelector
|
||||
data={data}
|
||||
touchableActiveOpacity={0.8}
|
||||
style={[customStyle.addVisPickerStyle,selectStyle!=null?selectStyle:{}]}
|
||||
onChange={(option)=>{onChange(option,onchangeKeyLbl,onchangeKey,otherData) }}
|
||||
overlayStyle={customStyle.addVisPickerOverlay}
|
||||
cancelContainerStyle={customStyle.addVisPicker_OptionContainerStyle}
|
||||
optionStyle={customStyle.addvis_opStyle}
|
||||
optionTextStyle={customStyle.addvis_opTextStyle}
|
||||
optionContainerStyle={customStyle.addVisPicker_OptionContainerStyle}
|
||||
selectedKey={'1'}
|
||||
cancelText={ST.Cancel}
|
||||
disabled={isDisable}
|
||||
cancelStyle={{fontFamily:deffontfamily}}
|
||||
cancelTextStyle={{fontFamily:deffontfamily}}
|
||||
>
|
||||
<Text style={[customStyle.addVisPicker_InputStyle,InputStyle!=null?InputStyle:{}]}>{(selectedFName || '-'+ST.select+'-')}</Text>
|
||||
</ModalSelector>
|
||||
)
|
||||
}
|
||||
catch(err){
|
||||
console.log("CustomPicker error:",err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function CustomPickerStock(props, Pickerdata, label_key, value_key, onchangeKeyLbl, onchangeKey, onChange = () => { }, selected_data = {}, selectStyle = {}, InputStyle = {}, appendIdInName = '', routeParam = null, isDisable = false) {
|
||||
try {
|
||||
const ST = props.StaticText || {};
|
||||
const route = routeParam != null && routeParam.name != null ? routeParam : { name: 'ABCScreen' };//useRoute();
|
||||
|
||||
// get all theme styles acc to current theme set
|
||||
const PageTheme = GetPageTheme(props.DarkMode, route.name);
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
let otherData = selected_data?.otherData ? selected_data?.otherData : {};
|
||||
var data = [];
|
||||
|
||||
let selectedFName = '';
|
||||
Pickerdata?.map((item, index) => {
|
||||
let label1 = (item[label_key] + (appendIdInName && item[value_key] != "" ? (` (${item[value_key]})`) : ''));
|
||||
let obj = { key: index, label: label1, value: item[value_key], item };
|
||||
if ((appendIdInName == false && selected_data?.value == item[label_key]) || (appendIdInName && selected_data?.value == item[value_key])) {
|
||||
selectedFName = label1;
|
||||
obj['component'] = <View style={customStyle.addvis_selectedOpStyle}><Text style={customStyle.addvis_selectedOpTextStyle}>{label1}</Text></View>;
|
||||
}
|
||||
data.push(obj);
|
||||
});
|
||||
|
||||
return (
|
||||
<ModalSelector
|
||||
data={data}
|
||||
touchableActiveOpacity={0.8}
|
||||
|
||||
style={[
|
||||
props.bgColor
|
||||
? [customStyle.addVisPickerStyle, { width: '50%',height:33, backgroundColor: props.bgColor }]
|
||||
: customStyle.addVisPickerStyle,
|
||||
selectStyle != null ? selectStyle : {}
|
||||
]}
|
||||
onChange={(option) => { onChange(option, onchangeKeyLbl, onchangeKey, otherData) }}
|
||||
overlayStyle={customStyle.addVisPickerOverlay}
|
||||
cancelContainerStyle={customStyle.addVisPicker_OptionContainerStyle}
|
||||
optionStyle={customStyle.addvis_opStyle}
|
||||
optionTextStyle={customStyle.addvis_opTextStyle}
|
||||
optionContainerStyle={customStyle.addVisPicker_OptionContainerStyle}
|
||||
selectedKey={'1'}
|
||||
cancelText={ST.Cancel}
|
||||
disabled={isDisable}
|
||||
cancelStyle={{ fontFamily: deffontfamily }}
|
||||
cancelTextStyle={{ fontFamily: deffontfamily }}
|
||||
>
|
||||
<View style={[{ backgroundColor: props.bgColor || '#fff', borderRadius: 8, padding: 8 }]}>
|
||||
<Text
|
||||
style={[
|
||||
props.bgColor ? { color: "black" ,textAlign: "center", textAlignVertical: "center" } : customStyle.addVisPicker_InputStyle,
|
||||
InputStyle || {},
|
||||
props.bgColor ? { backgroundColor: props.bgColor } : {},
|
||||
|
||||
]}
|
||||
>
|
||||
{selectedFName || `-${ST.select}-`}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
</ModalSelector>
|
||||
)
|
||||
}
|
||||
catch (err) {
|
||||
console.log("CustomPicker error:", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function CustomPicker2(props) {
|
||||
try {
|
||||
const ST = props.StaticText || {};
|
||||
const route = useRoute();
|
||||
|
||||
// get all theme styles acc to current theme set
|
||||
const PageTheme = GetPageTheme(props.DarkMode, route.name);
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
let { Pickerdata, label_key, value_key, onchangeKeyLbl, onchangeKey, onChange, selected_data, isDisable } = props;
|
||||
let otherData = selected_data?.otherData ? selected_data?.otherData : {};
|
||||
|
||||
const [data, setdata] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
let arr = []
|
||||
Pickerdata?.map((item, index) => {
|
||||
let obj = { key: index, label: item[label_key], value: item[value_key] };
|
||||
|
||||
if (selected_data?.value == item[label_key])
|
||||
obj['component'] = <View style={customStyle.addvis_selectedOpStyle}><Text style={customStyle.addvis_selectedOpTextStyle}>{item[label_key]}</Text></View>;
|
||||
|
||||
arr.push(obj);
|
||||
if (index == Pickerdata.length - 1) {
|
||||
setdata(arr);
|
||||
}
|
||||
});
|
||||
}, [props.Pickerdata]);
|
||||
|
||||
|
||||
return (
|
||||
<ModalSelector
|
||||
data={data}
|
||||
|
||||
touchableActiveOpacity={0.8}
|
||||
style={[customStyle.addVisPickerStyle, props.selectStyle != null ? props.selectStyle : {}]}
|
||||
onChange={(option) => { onChange(option, onchangeKeyLbl, onchangeKey, otherData) }}
|
||||
overlayStyle={customStyle.addVisPickerOverlay}
|
||||
cancelContainerStyle={customStyle.addVisPicker_OptionContainerStyle}
|
||||
optionStyle={customStyle.addvis_opStyle}
|
||||
optionTextStyle={customStyle.addvis_opTextStyle}
|
||||
optionContainerStyle={customStyle.addVisPicker_OptionContainerStyle}
|
||||
selectedKey={'1'}
|
||||
cancelText={ST.Cancel}
|
||||
disabled={isDisable}
|
||||
cancelStyle={{ fontFamily: deffontfamily }}
|
||||
cancelTextStyle={{ fontFamily: deffontfamily }}
|
||||
>
|
||||
<Text style={[customStyle.addVisPicker_InputStyle, props.InputStyle != null ? props.InputStyle : {}, (props.ShowError != null && props.ShowError == true && props.ErrorStyle != null ? props.ErrorStyle : {})]}>{(selected_data?.value || '-' + ST.select + '-')}</Text>
|
||||
</ModalSelector>
|
||||
)
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
console.log("CustomPicker2 error:", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// import React from "react";
|
||||
// import { Text, TouchableOpacity,View,ScrollView } from "react-native";
|
||||
// import { customStyles,GetPageTheme } from "../styles/Global";
|
||||
// import { useRoute } from '@react-navigation/native';
|
||||
// const HeaderTabs = (props) => {
|
||||
// const route = useRoute();
|
||||
// const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
// const customStyle=customStyles(props.DarkMode,route.name);
|
||||
// const ST=props.StaticText || {};
|
||||
// const isAdhocScreen=props.isAdhocScreen;
|
||||
// const isBeatPlan=props.isBeatPlan;
|
||||
// const isDBPOSMScreen=props.isDBPOSMScreen;
|
||||
// const isAddStoreScreen=props.isAddStoreScreen;
|
||||
// const isNonMerchan=props.isNonMerchans;
|
||||
// const isNonProgs=props.isNonProgs;
|
||||
// const isStoreSearch=props.isStoreSearch;
|
||||
// return (
|
||||
// <View style={customStyle.storeTab_Con}>
|
||||
// <ScrollView style={customStyle.storeTab_MenuCon} contentContainerStyle={customStyle.storeTab_Menu} horizontal={true}>
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,((!isAdhocScreen && !isBeatPlan && !isDBPOSMScreen && !isAddStoreScreen && !isNonMerchan && !isNonProgs && !isStoreSearch)?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.pop();props.navigation.push('StoreList')}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,((!isAdhocScreen && !isBeatPlan && !isDBPOSMScreen && !isAddStoreScreen && !isNonMerchan && !isNonProgs&& !isStoreSearch)?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{ST.Planned}</Text>
|
||||
// </TouchableOpacity>
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isAdhocScreen?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.pop();props.navigation.push('StoreList',{'isAdhoc': true,'isBeat':false,'isNonMerchans':false,'isNonProgs':false,'isStoreSearch':false})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isAdhocScreen?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{ST.Adhoc}</Text>
|
||||
// </TouchableOpacity>
|
||||
// {props.ShowBeatPlanList==true &&
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isBeatPlan?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.pop();props.navigation.push('StoreList',{'isAdhoc': false,'isBeat':true})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isBeatPlan?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{'Beat Plan'}</Text>
|
||||
// </TouchableOpacity>
|
||||
// }
|
||||
// {props.ShowStoreAdd==true &&
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isAddStoreScreen?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.navigate('AddStoreScreen',{})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isAddStoreScreen?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{'Add Store'}</Text>
|
||||
// </TouchableOpacity>
|
||||
// }
|
||||
// {props.ShowNonMerList==true &&
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isNonMerchan?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.pop();props.navigation.push('StoreList',{'isAdhoc': false,'isBeat':false,'isNonMerchans':true,'isNonProgs':false,'isStoreSearch':false})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isNonMerchan?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{'Non Merch.'}</Text>
|
||||
// </TouchableOpacity>
|
||||
// }
|
||||
// {props.ShowNonProgram==true &&
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isNonProgs?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.pop();props.navigation.push('StoreList',{'isAdhoc': false,'isBeat':false,'isNonMerchans':false, 'isNonProgs':true,'isStoreSearch':false})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isNonProgs?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{props.NonProgramLabel}</Text>
|
||||
// </TouchableOpacity>
|
||||
// }
|
||||
|
||||
// {props.ShowStoreSearch==true &&
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isStoreSearch?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.pop();props.navigation.push('StoreList',{'isAdhoc': false,'isBeat':false,'isNonMerchans':false, 'isNonProgs':false,'isStoreSearch':true})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isStoreSearch?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{props.ShowStoreSearchLabel}</Text>
|
||||
// </TouchableOpacity>
|
||||
// }
|
||||
|
||||
// {props.ShowDBPOSM==true &&
|
||||
// <TouchableOpacity style={[customStyle.storeTab_pill,(isDBPOSMScreen?customStyle.storeTab_pillActive:{})]} onPress={()=>{props.navigation.navigate('DistributorList',{})}}>
|
||||
// <Text style={[customStyle.storeTab_pillText,(isDBPOSMScreen?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{'Distributors'}</Text>
|
||||
// </TouchableOpacity>
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// </ScrollView>
|
||||
// </View>
|
||||
// );
|
||||
// };
|
||||
// export default HeaderTabs;
|
||||
|
||||
|
||||
import React from "react";
|
||||
import { Text, TouchableOpacity,View,ScrollView } from "react-native";
|
||||
import { customStyles,GetPageTheme } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
|
||||
const HeaderTabs = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme = GetPageTheme(props.DarkTheme, route.name);
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
|
||||
const ST = props.StaticText || {};
|
||||
|
||||
const isAdhocScreen = props.isAdhocScreen;
|
||||
const isBeatPlan = props.isBeatPlan;
|
||||
const isDBPOSMScreen = props.isDBPOSMScreen;
|
||||
const isAddStoreScreen = props.isAddStoreScreen;
|
||||
const isNonMerchan = props.isNonMerchans;
|
||||
const isNonProgs = props.isNonProgs;
|
||||
const isStoreSearch = props.isStoreSearch;
|
||||
|
||||
// 🔹 helper to avoid duplicate navigation
|
||||
const navigateIfNotActive = (isActive, routeName, params = {}, useNavigate = false) => {
|
||||
if (isActive) return;
|
||||
props.navigation.pop();
|
||||
if (useNavigate) {
|
||||
props.navigation.navigate(routeName, params);
|
||||
} else {
|
||||
props.navigation.push(routeName, params);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<View style={customStyle.storeTab_Con}>
|
||||
<ScrollView
|
||||
style={customStyle.storeTab_MenuCon}
|
||||
contentContainerStyle={customStyle.storeTab_Menu}
|
||||
horizontal={true}
|
||||
>
|
||||
{/* Planned */}
|
||||
<TouchableOpacity
|
||||
disabled={!isAdhocScreen && !isBeatPlan && !isDBPOSMScreen && !isAddStoreScreen && !isNonMerchan && !isNonProgs && !isStoreSearch}
|
||||
style={[
|
||||
customStyle.storeTab_pill,
|
||||
((!isAdhocScreen && !isBeatPlan && !isDBPOSMScreen && !isAddStoreScreen && !isNonMerchan && !isNonProgs && !isStoreSearch)
|
||||
? customStyle.storeTab_pillActive
|
||||
: {})
|
||||
]}
|
||||
onPress={() => navigateIfNotActive(
|
||||
(!isAdhocScreen && !isBeatPlan && !isDBPOSMScreen && !isAddStoreScreen && !isNonMerchan && !isNonProgs && !isStoreSearch),
|
||||
'StoreList'
|
||||
)}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
((!isAdhocScreen && !isBeatPlan && !isDBPOSMScreen && !isAddStoreScreen && !isNonMerchan && !isNonProgs && !isStoreSearch)
|
||||
? customStyle.storeTab_pillActiveText
|
||||
: { color: PageTheme.$text_color })
|
||||
]}>
|
||||
{ST.Planned}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Adhoc */}
|
||||
<TouchableOpacity
|
||||
disabled={isAdhocScreen}
|
||||
style={[customStyle.storeTab_pill, isAdhocScreen ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isAdhocScreen, 'StoreList', {
|
||||
isAdhoc: true,
|
||||
isBeat: false,
|
||||
isNonMerchans: false,
|
||||
isNonProgs: false,
|
||||
isStoreSearch: false
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isAdhocScreen ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
{ST.Adhoc}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Beat Plan */}
|
||||
{props.ShowBeatPlanList && (
|
||||
<TouchableOpacity
|
||||
disabled={isBeatPlan}
|
||||
style={[customStyle.storeTab_pill, isBeatPlan ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isBeatPlan, 'StoreList', {
|
||||
isAdhoc: false,
|
||||
isBeat: true
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isBeatPlan ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
Beat Plan
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* Add Store */}
|
||||
{props.ShowStoreAdd && (
|
||||
<TouchableOpacity
|
||||
disabled={isAddStoreScreen}
|
||||
style={[customStyle.storeTab_pill, isAddStoreScreen ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isAddStoreScreen, 'AddStoreScreen', {}, true)
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isAddStoreScreen ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
Add Store
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* Non Merch */}
|
||||
{props.ShowNonMerList && (
|
||||
<TouchableOpacity
|
||||
disabled={isNonMerchan}
|
||||
style={[customStyle.storeTab_pill, isNonMerchan ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isNonMerchan, 'StoreList', {
|
||||
isAdhoc: false,
|
||||
isBeat: false,
|
||||
isNonMerchans: true,
|
||||
isNonProgs: false,
|
||||
isStoreSearch: false
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isNonMerchan ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
Non Merch.
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* Non Program */}
|
||||
{props.ShowNonProgram && (
|
||||
<TouchableOpacity
|
||||
disabled={isNonProgs}
|
||||
style={[customStyle.storeTab_pill, isNonProgs ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isNonProgs, 'StoreList', {
|
||||
isAdhoc: false,
|
||||
isBeat: false,
|
||||
isNonMerchans: false,
|
||||
isNonProgs: true,
|
||||
isStoreSearch: false
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isNonProgs ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
{props.NonProgramLabel}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* Store Search */}
|
||||
{props.ShowStoreSearch && (
|
||||
<TouchableOpacity
|
||||
disabled={isStoreSearch}
|
||||
style={[customStyle.storeTab_pill, isStoreSearch ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isStoreSearch, 'StoreList', {
|
||||
isAdhoc: false,
|
||||
isBeat: false,
|
||||
isNonMerchans: false,
|
||||
isNonProgs: false,
|
||||
isStoreSearch: true
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isStoreSearch ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
{props.ShowStoreSearchLabel}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* Distributors */}
|
||||
{props.ShowDBPOSM && (
|
||||
<TouchableOpacity
|
||||
disabled={isDBPOSMScreen}
|
||||
style={[customStyle.storeTab_pill, isDBPOSMScreen ? customStyle.storeTab_pillActive : {}]}
|
||||
onPress={() =>
|
||||
navigateIfNotActive(isDBPOSMScreen, 'DistributorList', {}, true)
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
customStyle.storeTab_pillText,
|
||||
isDBPOSMScreen ? customStyle.storeTab_pillActiveText : { color: PageTheme.$text_color }
|
||||
]}>
|
||||
Distributors
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default HeaderTabs;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { NativeModules } from 'react-native';
|
||||
const { IRLogin } = NativeModules;
|
||||
export default IRLogin;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { NativeModules } from 'react-native';
|
||||
const { ImageMarkText } = NativeModules;
|
||||
export default ImageMarkText;
|
||||
@@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import { Pressable, Text, View, StyleSheet } from "react-native";
|
||||
|
||||
export default function MoreInfoCheckbox({ checked, onToggle, label = "More Info" }) {
|
||||
return (
|
||||
<Pressable
|
||||
onPress={onToggle}
|
||||
style={({ pressed }) => [
|
||||
styles.container,
|
||||
pressed && { opacity: 0.8 }
|
||||
]}
|
||||
hitSlop={10}
|
||||
>
|
||||
<View style={[styles.checkbox, checked && styles.checkedBox]}>
|
||||
{checked ? <Text style={styles.checkmark}>✓</Text> : null}
|
||||
</View>
|
||||
<Text style={styles.label}>{label}</Text>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#fff",
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 20,
|
||||
borderRadius: 12,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.1,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 4,
|
||||
},
|
||||
checkbox: {
|
||||
width: 22,
|
||||
height: 22,
|
||||
borderRadius: 6,
|
||||
borderWidth: 2,
|
||||
borderColor: "#4A90E2",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
checkedBox: {
|
||||
backgroundColor: "#4A90E2",
|
||||
},
|
||||
checkmark: {
|
||||
color: "#fff",
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
},
|
||||
label: {
|
||||
marginLeft: 15,
|
||||
fontSize: 15,
|
||||
fontWeight: "500",
|
||||
color: "#333",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
import React, { useRef,useEffect } from "react";
|
||||
import { Text ,View,Animated, Platform} from "react-native";
|
||||
import { customeButtons,GetPageTheme,customStyles,globalStyles, HP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
|
||||
const NetworkStatusBar = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const NSBarAnim=useRef(new Animated.Value(0)).current;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
showAnim()
|
||||
}, [props.isInternetAvailable]);
|
||||
|
||||
function showAnim(){
|
||||
console.log('show con change:',props.showConnChange,props.isInternetAvailable)
|
||||
if(props.showConnChange==true){
|
||||
animateView()
|
||||
}
|
||||
}
|
||||
|
||||
function animateView(){
|
||||
// show
|
||||
Animated.timing(NSBarAnim, {
|
||||
toValue: 1,
|
||||
duration: 500,
|
||||
useNativeDriver:(Platform.OS=='ios'?false:true),
|
||||
}).start();
|
||||
|
||||
if(props.isInternetAvailable==true){
|
||||
// hide NS bar
|
||||
setTimeout(()=>{
|
||||
console.log('hidebar')
|
||||
Animated.timing(NSBarAnim, {
|
||||
toValue: 0,
|
||||
duration: 500,
|
||||
useNativeDriver:(Platform.OS=='ios'?false:true),
|
||||
}).start();
|
||||
},2500)
|
||||
props.show_ConnChange({showConnChange:false})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
const tY=NSBarAnim.interpolate({
|
||||
inputRange:[0,1],
|
||||
outputRange:[50,0],
|
||||
});
|
||||
|
||||
return (
|
||||
<Animated.View style={[customStyle.netSBar,(props.isInternetAvailable==true ?customStyle.netSBarGreen:customStyle.netSBarGrey),
|
||||
{transform:[{translateY:tY}]}
|
||||
]}>
|
||||
<Text style={[customStyle.netSBarText,(props.isInternetAvailable==true ?customStyle.netSBarGreen_Text:customStyle.netSBarGrey_Text)]}>{(props.isInternetAvailable==true?'Back Online':'No Connection! You are offline')}</Text>
|
||||
</Animated.View>
|
||||
)
|
||||
};
|
||||
export default NetworkStatusBar;
|
||||
@@ -0,0 +1,23 @@
|
||||
import React,{useState,useEffect,useRef} from "react";
|
||||
import { Text, TouchableOpacity ,View,Image,StatusBar} from "react-native";
|
||||
import { GetPageTheme,customStyles,globalStyles } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { FontAwesome } from "./icons";
|
||||
|
||||
function NoDataComponent(props) {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const ST=props.StaticText || {};
|
||||
return (
|
||||
<View style={customStyle.nodownloaddata_con}>
|
||||
<View style={customStyle.nodownloaddata_row}>
|
||||
<FontAwesome name='cloud-download' size={45} color={PageTheme.$text_color_light} />
|
||||
<Text style={customStyle.nodownloaddata_text}>{ST.NoDataFoundPleaseDownloadDataFirst}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
export default NoDataComponent;
|
||||
@@ -0,0 +1,97 @@
|
||||
// components/QRCodeScannerKit.js
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
StyleSheet,
|
||||
BackHandler,
|
||||
Modal,
|
||||
} from 'react-native';
|
||||
import { Camera } from 'react-native-camera-kit';
|
||||
import { Ionicons } from './icons'; // tumhara icon wrapper
|
||||
|
||||
function QRCodeScannerKit({ visible, onClose, onQRScanned }) {
|
||||
// 🔙 Android hardware back button handle
|
||||
useEffect(() => {
|
||||
if (!visible) return;
|
||||
|
||||
const backHandler = BackHandler.addEventListener(
|
||||
'hardwareBackPress',
|
||||
() => {
|
||||
onClose && onClose();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
return () => backHandler.remove();
|
||||
}, [visible, onClose]);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
const handleReadCode = (event) => {
|
||||
const value = event?.nativeEvent?.codeStringValue ?? '';
|
||||
console.log('QR Value:', value);
|
||||
if (!value) return;
|
||||
|
||||
onQRScanned && onQRScanned(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
animationType="slide"
|
||||
transparent={false}
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<Camera
|
||||
style={styles.camera}
|
||||
scanBarcode={true}
|
||||
onReadCode={handleReadCode}
|
||||
showFrame={true}
|
||||
laserColor="red"
|
||||
frameColor="white"
|
||||
/>
|
||||
|
||||
{/* Top overlay bar with close button */}
|
||||
<View style={styles.topBar}>
|
||||
<TouchableOpacity onPress={onClose} style={styles.closeBtn}>
|
||||
<Ionicons name="close" size={26} color="#fff" />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.title}>Scan QR Code</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
camera: {
|
||||
flex: 1,
|
||||
},
|
||||
topBar: {
|
||||
position: 'absolute',
|
||||
top: 40,
|
||||
left: 0,
|
||||
right: 0,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
closeBtn: {
|
||||
padding: 8,
|
||||
marginRight: 12,
|
||||
},
|
||||
title: {
|
||||
color: '#fff',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
|
||||
export default QRCodeScannerKit;
|
||||
@@ -0,0 +1,107 @@
|
||||
'use strict';
|
||||
|
||||
import React, { Component, useEffect, useState } from 'react';
|
||||
|
||||
// import QRCodeScanner from 'react-native-qrcode-scanner';
|
||||
import Container from '../components/container';
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { globalStyles,customStyles,GetPageTheme } from "../styles/Global";
|
||||
import {StatusBar,Image,TextInput,View,Text,ScrollView,TouchableOpacity,Platform,PermissionsAndroid,FlatList, Alert, Animated, DeviceEventEmitter,StyleSheet} from 'react-native';
|
||||
import { ReactReduxContext,connect,useSelector, useDispatch } from 'react-redux';
|
||||
import { mapStateToProps,mapDispatchToProps } from '../reducers/contextProvider';
|
||||
import {notify} from '../components/notify';
|
||||
import moment from 'moment';
|
||||
|
||||
function QRScanner (props){
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
// get all theme styles acc to current theme set
|
||||
const PageTheme=GetPageTheme(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const [loaderTitle, setLoaderTitle] = useState('loading...');
|
||||
const [params, setParams] = useState({'cameraType':'back'});
|
||||
const [showCamera, setShowCamera] = useState(true);
|
||||
const [hasUnsavedChanges,setHasUnsavedChanges] = useState(false);
|
||||
|
||||
const d1=new Date();
|
||||
const d2=moment(d1).format('MM/DD/YYYY');
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
// let params1=props.route.params? props.route.params:{};
|
||||
// setParams(params1);
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
console.log('QR Page:', props.showCamera);
|
||||
|
||||
},[props.showCamera]);
|
||||
|
||||
async function hideCamera() {
|
||||
if (props.onHideCamera != null && typeof props.onHideCamera == 'function') {
|
||||
props.onHideCamera();
|
||||
}
|
||||
props.navigation.goBack();
|
||||
}
|
||||
|
||||
async function onImageCaptured(imgData){
|
||||
console.log('on data rec:',imgData.data);
|
||||
console.log('onImageCaptured in camera screen');
|
||||
// imgData['storeData']=params.storeData
|
||||
// emit onImageCaptured in the screen from where this screen is opened
|
||||
DeviceEventEmitter.emit("OnQRSuccess",imgData.data);
|
||||
props.navigation.goBack();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Container {...props} pt={0} avoidSafeArea={(Platform.OS=='ios'?true:false)}>
|
||||
|
||||
{/* <QRCodeScanner
|
||||
onRead={onImageCaptured}
|
||||
cameraStyle
|
||||
// flashMode={RNCamera.Constants.FlashMode.torch}
|
||||
topContent={
|
||||
<Text style={styles.centerText}>
|
||||
scan the QR code.
|
||||
</Text>
|
||||
}
|
||||
bottomContent={
|
||||
<TouchableOpacity style={styles.buttonTouchable}>
|
||||
<Text style={styles.buttonText}>OK. Got it!</Text>
|
||||
</TouchableOpacity>
|
||||
}
|
||||
/> */}
|
||||
</Container>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
centerText: {
|
||||
flex: 1,
|
||||
fontSize: 18,
|
||||
padding: 32,
|
||||
color: '#777'
|
||||
},
|
||||
textBold: {
|
||||
fontWeight: '500',
|
||||
color: '#000'
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 21,
|
||||
color: 'rgb(0,122,255)'
|
||||
},
|
||||
buttonTouchable: {
|
||||
padding: 16
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(QRScanner);
|
||||
@@ -0,0 +1,129 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Text, TouchableOpacity,View,ScrollView } from "react-native";
|
||||
import { customStyles,GetPageTheme } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
import { notify } from "./notify";
|
||||
|
||||
const SamplingHeaderTab = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
|
||||
const currentMenu=props.currentMenu;
|
||||
const SamplingData=props.SamplingData || {};
|
||||
const SamplingTabObj=props.SamplingTabObj || {};
|
||||
const AllTabDisabled=props.AllTabDisabled!=null?props.AllTabDisabled:false;
|
||||
|
||||
let storeData=props.storeData;
|
||||
let hasUnsavedChanges=props.hasUnsavedChanges
|
||||
let setShowAlert=props.setShowAlert
|
||||
let setSaveModalDObj=props.setSaveModalDObj
|
||||
let isSaleDependEnable=Boolean(SamplingTabObj.isSaleDependEnable)
|
||||
|
||||
// const isCustomerConversionRequired=( SamplingData && SamplingData.CustomerConversionRequired!=""?SamplingData.CustomerConversionRequired : false);
|
||||
// const isCustomerTrackingRequired=SamplingData && SamplingData.CustomerTrackingRequired!=""?SamplingData.CustomerTrackingRequired : false;
|
||||
// const isSaleRequired=SamplingData && SamplingData.SaleRequired!=""?SamplingData.SaleRequired : false;
|
||||
// const isStockRequired=SamplingData && SamplingData.StockRequird!=""?SamplingData.StockRequird : false;
|
||||
// const isInventoryRequired=SamplingData && SamplingData.InventoryRequired!=""?SamplingData.InventoryRequired : false;
|
||||
|
||||
const isInventoryRequired=SamplingData.InventoryRequired==true || SamplingData.InventoryRequired=="true"?1:0;
|
||||
const isCustomerTrackingRequired=SamplingData.CustomerTrackingRequired==true || SamplingData.CustomerTrackingRequired=="true"?1:0;
|
||||
const isCustomerConversionRequired=SamplingData.CustomerConversionRequired==true || SamplingData.CustomerConversionRequired=="true"?1:0;
|
||||
const isSaleRequired=SamplingData.SaleRequired==true || SamplingData.SaleRequired=="true"?1:0;
|
||||
const isStockRequired=SamplingData.StockRequird==true || SamplingData.StockRequird=="true"?1:0;
|
||||
|
||||
|
||||
// let inventoryDis= AllTabDisabled || SamplingTabObj ?false:(SamplingTabObj && SamplingTabObj.inventoryIsAvlbl==true );
|
||||
// let converDis=(SamplingTabObj && SamplingTabObj.allTabDisable) ?false:true;
|
||||
// let trackDis=(SamplingTabObj && SamplingTabObj.allTabDisable) ?false:(SamplingTabObj && SamplingTabObj.trackIsAvlbl==true );
|
||||
// let SaleDis=(SamplingTabObj && SamplingTabObj.allTabDisable) ?false:(SamplingTabObj && SamplingTabObj.SaleIsAvlbl==true );
|
||||
// let stockDis=(SamplingTabObj && SamplingTabObj.allTabDisable) ?false:(SamplingTabObj && SamplingTabObj.StockIsAvlbl==true );
|
||||
|
||||
|
||||
let inventoryDis= AllTabDisabled || SamplingTabObj.inventoryIsAvlbl==false?true:false;
|
||||
let converDis=AllTabDisabled;
|
||||
let trackDis= AllTabDisabled || SamplingTabObj.trackIsAvlbl==false?true:false;
|
||||
let SaleDis= AllTabDisabled || SamplingTabObj.SaleIsAvlbl==false?true:( isSaleDependEnable && SamplingTabObj.StockAvil==false && isStockRequired==true? true:false);
|
||||
// let SaleDis= AllTabDisabled || SamplingTabObj.SaleIsAvlbl==false?true:false;
|
||||
let stockDis=AllTabDisabled || SamplingTabObj.StockIsAvlbl==false?true:false;
|
||||
|
||||
const commonPageParams={'SamplingData':SamplingData,'storeData':storeData,'menu':currentMenu};
|
||||
const SalePageParams={'SamplingData':SamplingData,'storeData':storeData,'menu':currentMenu,"SamplingSaleFlag":true};
|
||||
const ContactConvPageParams={'SamplingData':SamplingData,'storeData':storeData,'menu':currentMenu,"SamplingFlag":true,'showTotalSampled':true};
|
||||
|
||||
function goToPage(screenName,params){
|
||||
if(hasUnsavedChanges){
|
||||
setSaveModalDObj({screenName,params});
|
||||
setShowAlert(true);
|
||||
}
|
||||
else{
|
||||
let movetoScreen=true;
|
||||
if(screenName=="SamplingStock"){
|
||||
if(SamplingTabObj.SaleIsDone==true){
|
||||
movetoScreen=false;
|
||||
notify("Sampling Sale has been filled! You cannot change stock now")
|
||||
}
|
||||
}
|
||||
|
||||
if(movetoScreen){
|
||||
props.navigation.navigate(screenName,params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[customStyle.storeTab_Con,customStyle.Sampling_HdrTWrap,customStyle.Samling_borderB,customStyle.pb10]}>
|
||||
{
|
||||
(isInventoryRequired==true) &&
|
||||
<TouchableOpacity style={[customStyle.storeTab_pill,{marginTop:10},(!inventoryDis?customStyle.storeTab_pillActive:{})]} disabled={inventoryDis} onPress={()=>{goToPage('SamplingInventory',commonPageParams); }}>
|
||||
<Text style={[customStyle.storeTab_pillText,(!inventoryDis?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{"INVENTORY"}</Text>
|
||||
{ ( SamplingTabObj.inventoryIsDone==true) &&
|
||||
<View style={customStyle.Sampling_menu_done}><AntDesign color={(inventoryDis?PageTheme.$text_color_light:'green')} size={14} name='checkcircle'/></View>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
}
|
||||
{
|
||||
(isCustomerTrackingRequired==true) &&
|
||||
<TouchableOpacity style={[customStyle.storeTab_pill,{marginTop:10},(!trackDis?customStyle.storeTab_pillActive:{})]} disabled={trackDis} onPress={()=>{goToPage('SamplingCustTrack',commonPageParams); }}>
|
||||
<Text style={[customStyle.storeTab_pillText,(!trackDis?customStyle.storeTab_pillActiveText:{color:PageTheme.$text_color})]}>{"CUST-TRACK"}</Text>
|
||||
{ ( SamplingTabObj.trackIsDone==true) &&
|
||||
<View style={customStyle.Sampling_menu_done}><AntDesign color={(trackDis?PageTheme.$text_color_light:'green')} size={14} name='checkcircle'/></View>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
}
|
||||
{
|
||||
(isStockRequired==true) &&
|
||||
<TouchableOpacity style={[customStyle.storeTab_pill,{marginTop:10},(!stockDis?customStyle.storeTab_pillActive:{})]} disabled={stockDis} onPress={()=>{goToPage('SamplingStock',commonPageParams); }}>
|
||||
<Text style={[customStyle.storeTab_pillText,(!stockDis?customStyle.storeTab_pillActiveText:{})]}>{"STOCK"}</Text>
|
||||
{ ( SamplingTabObj.StockIsDone==true) &&
|
||||
<View style={customStyle.Sampling_menu_done}><AntDesign color={(stockDis?PageTheme.$text_color_light:'green')} size={14} name='checkcircle'/></View>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
}
|
||||
{
|
||||
(isSaleRequired==true) &&
|
||||
<TouchableOpacity style={[customStyle.storeTab_pill,{marginTop:10},(!SaleDis?customStyle.storeTab_pillActive:{})]} disabled={SaleDis} onPress={()=>{goToPage('SamplingStock',SalePageParams); }}>
|
||||
<Text style={[customStyle.storeTab_pillText,(!SaleDis?customStyle.storeTab_pillActiveText:{})]}>{"SALE"}</Text>
|
||||
{ ( SamplingTabObj.SaleIsDone==true) &&
|
||||
<View style={customStyle.Sampling_menu_done}><AntDesign color={(SaleDis?PageTheme.$text_color_light:'green')} size={14} name='checkcircle'/></View>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
}
|
||||
|
||||
{
|
||||
(isCustomerConversionRequired==true) &&
|
||||
<TouchableOpacity style={[customStyle.storeTab_pill,{marginTop:10},(!converDis?customStyle.storeTab_pillActive:{})]} disabled={converDis} onPress={()=>{goToPage('ContactConversion',ContactConvPageParams); }}>
|
||||
<Text style={[customStyle.storeTab_pillText,(!converDis?customStyle.storeTab_pillActiveText:{})]}>{"CONVERSION"}</Text>
|
||||
{ ( SamplingTabObj.ContactIsDone==true) &&
|
||||
<View style={customStyle.Sampling_menu_done}><AntDesign color={(converDis?PageTheme.$text_color_light:'green')} size={14} name='checkcircle'/></View>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
}
|
||||
|
||||
{/* </ScrollView> */}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default SamplingHeaderTab;
|
||||
@@ -0,0 +1,99 @@
|
||||
import React, { useState } from 'react';
|
||||
import { View, TextInput, FlatList, Text, TouchableOpacity, Modal, StyleSheet } from 'react-native';
|
||||
|
||||
const SearchableSelector = ({ data, placeholder,customStyle,selectedVal,setSelectedVal }) => {
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [selectedItem, setSelectedItem] = useState(null);
|
||||
|
||||
const filteredData = data.filter(item =>
|
||||
item?.StockistName?.toLowerCase().includes(searchQuery?.toLowerCase())
|
||||
);
|
||||
|
||||
const handleSelect = (item) => {
|
||||
setSelectedItem(item);
|
||||
setSelectedVal(item)
|
||||
setModalVisible(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={() => setModalVisible(true)} style={[customStyle.openStk_prd_inputStyle,customStyle.openStk_prd_flex_inputStyle,customStyle.openStk_prd_inplBlue]} >
|
||||
<Text style={styles.selectedText}>{selectedItem?.StockistName || selectedVal?.StockistName || placeholder}</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<Modal
|
||||
transparent={true}
|
||||
visible={modalVisible}
|
||||
animationType="slide"
|
||||
>
|
||||
<View style={styles.modalContainer}>
|
||||
<TextInput
|
||||
style={styles.searchInput}
|
||||
placeholder="Search..."
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
/>
|
||||
<FlatList
|
||||
data={filteredData}
|
||||
keyExtractor={(item) => item}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity onPress={() => handleSelect(item)} style={styles.item}>
|
||||
<Text>{item?.StockistName}</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setModalVisible(false)} style={styles.closeButton}>
|
||||
<Text style={styles.closeButtonText}>Close</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
// margin: 20,
|
||||
width:"100%"
|
||||
},
|
||||
selector: {
|
||||
padding: 10,
|
||||
borderWidth: 1,
|
||||
borderColor: '#ccc',
|
||||
borderRadius: 5,
|
||||
},
|
||||
selectedText: {
|
||||
color: '#333',
|
||||
},
|
||||
modalContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'white',
|
||||
padding: 20,
|
||||
},
|
||||
searchInput: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#ccc',
|
||||
borderRadius: 5,
|
||||
padding: 10,
|
||||
marginBottom: 10,
|
||||
},
|
||||
item: {
|
||||
padding: 10,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#ccc',
|
||||
},
|
||||
closeButton: {
|
||||
marginTop: 20,
|
||||
padding: 10,
|
||||
backgroundColor: '#007BFF',
|
||||
borderRadius: 5,
|
||||
alignItems: 'center',
|
||||
},
|
||||
closeButtonText: {
|
||||
color: 'white',
|
||||
},
|
||||
});
|
||||
|
||||
export default SearchableSelector;
|
||||
@@ -0,0 +1,127 @@
|
||||
|
||||
import { WebView } from "react-native-webview";
|
||||
import { useIsFocused } from "@react-navigation/native";
|
||||
import Modal from "react-native-modal";
|
||||
|
||||
|
||||
const [surveydata, setSurveyData] = useState({});
|
||||
const [modalVisiblesurvey, setModalVisibleSurvey] = useState(false);
|
||||
const [surveyloader, setSurveyLoader] = useState(false);
|
||||
const [isWebViewReady, setWebViewReady] = useState(false);
|
||||
const webViewRef = useRef(null);
|
||||
const isFocused = useIsFocused();
|
||||
|
||||
const ShowSurveyPopup = async () => {
|
||||
try {
|
||||
setSurveyLoader(true);
|
||||
const raw = JSON.stringify({
|
||||
ProjectId: "0",
|
||||
UserId: user?.emp_code,
|
||||
// UserId: "80307",
|
||||
|
||||
});
|
||||
let res = await fetch(
|
||||
"https://api1.parinaam.in/api/cpminternal/GetPopupWeburl",
|
||||
{
|
||||
method: "POST",
|
||||
body: raw,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
let responseJson = await res.json();
|
||||
if (responseJson) {
|
||||
setSurveyData(responseJson?.GetPopupWeburl || {});
|
||||
// console.log("responseJson?.GetPopupWeburl[0]?.Status",responseJson?.GetPopupWeburl[0])
|
||||
if (responseJson?.GetPopupWeburl[0]?.Status) {
|
||||
setModalVisibleSurvey(false);
|
||||
} else {
|
||||
setModalVisibleSurvey(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
setSurveyData({});
|
||||
}
|
||||
} catch (error) {
|
||||
alert("Survey Popup:" + error);
|
||||
} finally {
|
||||
setSurveyLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
ShowSurveyPopup();
|
||||
}, [isFocused]);
|
||||
|
||||
let webUrl = surveydata[0]?.WebUrl;
|
||||
|
||||
|
||||
const injectedJS = `
|
||||
(function() {
|
||||
const element = document.getElementById('cpminternalclose');
|
||||
console.log(element, "element")
|
||||
if (element) {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({ id: element.id }));
|
||||
} else {
|
||||
// window.ReactNativeWebView.postMessage(JSON.stringify({ message: "Element not found" }));
|
||||
}
|
||||
})();
|
||||
true;
|
||||
`;
|
||||
|
||||
const handleMessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.nativeEvent.data);
|
||||
if (data.error) {
|
||||
alert(data.error);
|
||||
} else {
|
||||
console.log('Element data:', data);
|
||||
if (data?.id == 'cpminternalclose') {
|
||||
setTimeout(() => {
|
||||
setModalVisibleSurvey(false);
|
||||
ShowSurveyPopup();
|
||||
}, 2000);
|
||||
} else {
|
||||
alert("Id not found");
|
||||
}
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error parsing message:', error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
{
|
||||
<Modal
|
||||
animationType="slide"
|
||||
transparent={true}
|
||||
visible={modalVisiblesurvey}
|
||||
// visible={true}
|
||||
onRequestClose={() => setModalVisibleSurvey(false)}
|
||||
>
|
||||
<View style={styles.modalContainer}>
|
||||
<View style={styles.modalContent}>
|
||||
<ActivityIndicatior visible={surveyloader} />
|
||||
<WebView
|
||||
style={styles.webView}
|
||||
source={{ uri: webUrl }}
|
||||
cacheEnabled={false} // Disable cache
|
||||
incognito={true}
|
||||
onLoadStart={() => setSurveyLoader(true)}
|
||||
onLoadEnd={() => {
|
||||
setSurveyLoader(false);
|
||||
// setWebViewReady(true);
|
||||
console.log("ENd Loadingggg...---");
|
||||
}}
|
||||
ref={webViewRef}
|
||||
injectedJavaScript={injectedJS}
|
||||
onMessage={handleMessage}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Modal,
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
StyleSheet,
|
||||
Image,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
|
||||
const TrainingPromptModal = ({ visible, onDoIt, onNotNow, dueDate, item }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
<Modal visible={visible} transparent animationType="fade">
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.imageWrapper}>
|
||||
{loading && (
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color="#0000ff"
|
||||
style={styles.loader}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Image
|
||||
source={{ uri: item?.ImageIcon }}
|
||||
style={styles.bear}
|
||||
onLoadStart={() => setLoading(true)}
|
||||
onLoadEnd={() => setLoading(false)}
|
||||
onError={() => setLoading(false)} // in case image fails
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Text style={styles.title}>{item?.Subject}</Text>
|
||||
<Text style={styles.desc}>{item?.Message}</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.doItBtn}
|
||||
onPress={() => onDoIt(item)}
|
||||
>
|
||||
<Text style={styles.doItText}>Let's do it</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{item?.PopupId != 1 && (
|
||||
<TouchableOpacity
|
||||
style={styles.notNowBtn}
|
||||
onPress={() => onNotNow(item)}
|
||||
>
|
||||
<Text style={styles.notNowText}>Not now</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.2)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
container: {
|
||||
width: 320,
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 20,
|
||||
alignItems: 'center',
|
||||
padding: 24,
|
||||
elevation: 8,
|
||||
},
|
||||
bear: {
|
||||
width: 140,
|
||||
height: 140,
|
||||
marginBottom: 10,
|
||||
resizeMode: 'contain',
|
||||
},
|
||||
imageWrapper: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
loader: {
|
||||
position: 'absolute', // overlay on top of image
|
||||
},
|
||||
title: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 8,
|
||||
color: '#222',
|
||||
},
|
||||
desc: {
|
||||
fontSize: 14,
|
||||
color: '#444',
|
||||
textAlign: 'center',
|
||||
marginBottom: 24,
|
||||
},
|
||||
date: {
|
||||
fontWeight: 'bold',
|
||||
color: '#1793d1',
|
||||
},
|
||||
doItBtn: {
|
||||
backgroundColor: '#1793d1',
|
||||
borderRadius: 24,
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
marginBottom: 10,
|
||||
},
|
||||
doItText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
notNowBtn: {
|
||||
borderColor: '#1793d1',
|
||||
borderWidth: 1,
|
||||
borderRadius: 24,
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
},
|
||||
notNowText: {
|
||||
color: '#1793d1',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
|
||||
export default TrainingPromptModal;
|
||||
@@ -0,0 +1,68 @@
|
||||
import React, { useRef, useEffect } from "react";
|
||||
import { View, Text, TouchableOpacity, Animated } from "react-native";
|
||||
import { customStyles } from "../styles/Global";
|
||||
|
||||
export default function YesNoToggle({
|
||||
label,
|
||||
value, // 1 or 0
|
||||
onChange,
|
||||
styles,
|
||||
yesLabel = "Yes",
|
||||
noLabel = "No",
|
||||
}) {
|
||||
|
||||
// const customStyle=customStyles(props.DarkMode,route.name);
|
||||
const animatedChoice = useRef(new Animated.Value(value ? 1 : 0)).current;
|
||||
|
||||
// Animate when value changes
|
||||
useEffect(() => {
|
||||
Animated.timing(animatedChoice, {
|
||||
toValue: value ? 1 : 0,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
}, [value]);
|
||||
|
||||
const xpos = animatedChoice.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, -75], // match your original movement
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={[styles?.container,{marginTop:"4%"}]}>
|
||||
{label ? (
|
||||
<Text style={[styles?.label]}>{label}</Text>
|
||||
) : null}
|
||||
|
||||
<View style={styles?.choiceBoxCon}>
|
||||
<View style={styles?.choiceBox}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles?.bg,
|
||||
value ? styles?.bgYes : styles?.bgNo,
|
||||
{ transform: [{ translateX: xpos }] },
|
||||
]}
|
||||
/>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles?.choice}
|
||||
onPress={() => onChange(1)}
|
||||
>
|
||||
<Text style={[styles?.choiceText, value ? styles?.choiceTextActive : {}]}>
|
||||
{yesLabel}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles?.choice}
|
||||
onPress={() => onChange(0)}
|
||||
>
|
||||
<Text style={[styles?.choiceText, value === 0 ? styles?.choiceTextActive : {}]}>
|
||||
{noLabel}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import {Platform,ToastAndroid,Alert,View,TouchableOpacity,Text} from 'react-native';
|
||||
import CustomModal from './CustomModal';
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { customStyles, GetPageTheme } from '../styles/Global';
|
||||
|
||||
export const CustomAlert = (title='',msg='',onCancel=function (){},onDone=function (){}) => {
|
||||
Alert.alert(
|
||||
title,
|
||||
msg,
|
||||
[
|
||||
{
|
||||
text: "Cancel",
|
||||
onPress: () => console.log('tw'),
|
||||
style: "cancel"
|
||||
},
|
||||
{ text: "OK", onPress: () => console.log('jhdh') }
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
export function ConfirmSaveAlert(props,showAlert=false,onCancelCallBack=()=>{},onYesCallBack=()=>{},msg='Do you really want to save data?'){
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
const ST= props.StaticText || {};
|
||||
|
||||
|
||||
return (
|
||||
<CustomModal
|
||||
style={customStyle.storelVisitM_Style}
|
||||
titleStyle={customStyle.storelVisitM_titleStyle}
|
||||
title={msg}
|
||||
showModal={showAlert}
|
||||
>
|
||||
<View style={customStyle.storelVisitM_options}>
|
||||
<TouchableOpacity style={customStyle.storelVisitM_op_btn} onPress={()=>{onCancelCallBack()}}>
|
||||
<Text style={customStyle.storelVisitM_op_btnText}>{ST.Cancel}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={customStyle.storelVisitM_op_btn} onPress={()=>{onYesCallBack()}}>
|
||||
<Text style={customStyle.storelVisitM_op_btnText}>{ST.Yes}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</CustomModal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export function ExitScreenAlert(props,callback){
|
||||
Alert.alert(
|
||||
"",
|
||||
"Do you really want to exit the screen?",
|
||||
[
|
||||
{
|
||||
text: "Cancel",
|
||||
onPress: () => {},
|
||||
style: "cancel"
|
||||
},
|
||||
{ text: "OK", onPress: () => {props.navigation.goBack();} }
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import * as React from "react";
|
||||
import { View, Alert } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { globalStyles, customStyles } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import NetworkStatusBar from "./NetworkStatusBar";
|
||||
import RNExitApp from 'react-native-exit-app';
|
||||
import moment from "moment";
|
||||
import { db } from "../constants/constants";
|
||||
import {isDeviceTimeValid } from '../controller/functions';
|
||||
|
||||
|
||||
function onRemoveScreen(e) {
|
||||
Alert.alert(
|
||||
"",
|
||||
"Your Device Date and Time is not correct. Please correct and restart App.",
|
||||
[
|
||||
{
|
||||
text: "OK", onPress: async () => {
|
||||
RNExitApp.exitApp();
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
const Container = (props) => {
|
||||
const route = useRoute();
|
||||
const globalStyle = globalStyles(props.DarkMode, route.name);
|
||||
const paddingS = props.pt != null ? { paddingTop: props.pt } : {};
|
||||
|
||||
let d1 = new Date();
|
||||
let d2 = moment(d1).format('MM/DD/YYYY');
|
||||
|
||||
React.useEffect(() => {
|
||||
///this function for date and time match
|
||||
isDeviceTimeValid();
|
||||
// comment becuase server date table not coming from backent
|
||||
// CheckVisitDate()
|
||||
}, [])
|
||||
|
||||
const CheckVisitDate = async () => {
|
||||
db.transaction(function (txn) {
|
||||
txn.executeSql(`select * from ServerTime`, [], function (txn1, txnres) {
|
||||
let data = txnres.rows.item(0);
|
||||
console.log('check to show DT alert', route.name, d2 != data.ServerDate);
|
||||
if (d2 != data.ServerDate && route.name != "MpinLogin" && route.name != "PrevStoreReason" && route.name != "initialScreen" && route.name != "Project" && route.name != "Login" && route.name != "Mpin" && route.name != "One_QAD" && route.name != "Notice Board" && route.name != "NoticeBoard") {
|
||||
console.log('show DT alert', route.name);
|
||||
onRemoveScreen()
|
||||
}
|
||||
}, function (txnE, txnerr) {
|
||||
console.log(txnerr);
|
||||
});
|
||||
});
|
||||
}
|
||||
return (
|
||||
<SafeAreaView edges={['bottom']} style={[globalStyle.container, paddingS]}>
|
||||
{props.children}
|
||||
<NetworkStatusBar {...props} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default Container;
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
import { Text, TouchableOpacity } from "react-native";
|
||||
import { customeButtons,GetPageTheme } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
|
||||
const CustomButton = (props) => {
|
||||
const route = useRoute();
|
||||
// const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const customeButton=customeButtons(props.DarkMode,route.name);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.6}
|
||||
onPress={props.onPress}
|
||||
style={customeButton.buttonStyle}>
|
||||
<Text style={customeButton.textStyle}>{props.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
export default CustomButton;
|
||||
@@ -0,0 +1,137 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Text, View, Image, StatusBar, StyleSheet, TouchableOpacity } from "react-native";
|
||||
// import { TouchableOpacity } from "react-native-gesture-handler";
|
||||
import { customeButtons, GetPageTheme, customStyles, globalStyles } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign, Entypo, Fontisto, MaterialCommunityIcons, FontAwesome } from "./icons";
|
||||
import moment from 'moment';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
|
||||
function CustomHeader(props) {
|
||||
const route = useRoute();
|
||||
const isCancelled = useRef(false);
|
||||
const PageTheme = GetPageTheme(props.DarkTheme, route.name);
|
||||
const globalStyle = globalStyles(props.DarkMode, route.name);
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
const [currentTime, setCurrentTime] = useState('');
|
||||
const [currentDate, setCurrentDate] = useState('');
|
||||
|
||||
|
||||
const goBack = () => {
|
||||
props.navigation.goBack();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
setTimer();
|
||||
|
||||
return () => {
|
||||
isCancelled.current = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
function setTimer() {
|
||||
if (!isCancelled.current) {
|
||||
let d1 = new Date();
|
||||
let now = moment(d1).format('hh:mm:ss a');
|
||||
let ndate = moment(d1).format('DD/MM/YYYY');
|
||||
setCurrentTime(now);
|
||||
setCurrentDate(ndate);
|
||||
setTimeout(() => { setTimer(); }, 1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<LinearGradient colors={[PageTheme.$gradient1, PageTheme.$primary_color]}
|
||||
start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={[globalStyle.drawerScreenHdr_bg, { zIndex: 1000 }, styles.linearGradient]}>
|
||||
<StatusBar barStyle={"light-content"} backgroundColor={'transparent'} translucent={true} />
|
||||
<View style={[globalStyle.dScreenHdr_Content, { zIndex: 1000 }]}>
|
||||
<Text style={globalStyle.drawerScreenHdr_title}>{props.title}</Text>
|
||||
<View style={globalStyle.dScreen_LeftContainer}>
|
||||
<TouchableOpacity
|
||||
style={[customStyle.toggleDrawerBtn, customStyle.headerLeftIcon]} onPress={() => { props.onPress != null ? props.onPress() : goBack() }}>
|
||||
<AntDesign color={PageTheme.$accent_color} size={20} name='arrowleft' />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
{props.hideBellIcon != true &&
|
||||
<View style={globalStyle.dScreen_RightContainer}>
|
||||
{props.projectCode != null && <Text style={globalStyle.drawerProjectId}>{(props.projectCode != null ? (props.projectCode.length > 15 ? props.projectCode.substring(0, 15) + '...' : props.projectCode) : '')}</Text>}
|
||||
{
|
||||
props?.screen === "AddStoreInfo" ? (
|
||||
<TouchableOpacity activeOpacity={0.6} style={globalStyle.drawerNotifIcon} onPress={() => props.navigation.navigate('StoreInfoList')}>
|
||||
<Entypo name='dots-three-vertical' size={20} color={PageTheme.$accent_color} />
|
||||
</TouchableOpacity>
|
||||
) : props?.screen !== "NotificationList" && props?.screen !== "NotificationListDetail" ? (
|
||||
|
||||
<TouchableOpacity activeOpacity={0.6} style={[globalStyle.drawerNotifIcon, styles.button]} onPress={() => props.navigation.navigate('NotificationList')} >
|
||||
<View style={{}}>
|
||||
<MaterialCommunityIcons name='bell-ring-outline' size={20} color={PageTheme.$accent_color} />
|
||||
|
||||
<View style={styles.itemCountContainer}>
|
||||
<Text style={styles.itemCountText}>{props?.badgeCount ? props?.badgeCount : 0 }</Text>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
) : null
|
||||
}
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
{
|
||||
props.hideTimer != true &&
|
||||
<View style={[
|
||||
customStyle.clocktimerWrap,
|
||||
{flexDirection:'row', justifyContent:'space-between', }]}>
|
||||
<View
|
||||
style={customStyle.clocktimerRow}
|
||||
>
|
||||
<Entypo name='calendar' color={PageTheme.$primary_color} size={14} /><Text style={[customStyle.clocktimerText, customStyle.mr10]}>{currentDate}</Text>
|
||||
<Fontisto name='clock' color={PageTheme.$primary_color} size={14} /><Text style={customStyle.clocktimerText}>{currentTime}</Text>
|
||||
</View>
|
||||
{/* AddNewStoreInJCP */}
|
||||
{props.showaddstore != true && props.AddNewStoreInJCP==true &&
|
||||
<TouchableOpacity activeOpacity={0.4} style={[customStyle.addstorebtn, { width:'35%'}]} onPress={() => props.navigation.navigate('AddStore')} >
|
||||
<Text style={[customStyle.vlEmplSearchBtnText, {color:'#1f7dbc'}]}>{"Add Store"}</Text>
|
||||
</TouchableOpacity> }
|
||||
{props.screen == 'AddStore' && props.ShowAddNewStore==true &&
|
||||
<TouchableOpacity activeOpacity={0.4} style={[customStyle.addstorebtn, { width:'35%'}]} onPress={() => props.navigation.navigate('AddedStoreList')} >
|
||||
<Text style={[customStyle.vlEmplSearchBtnText, {color:'#1f7dbc'}]}>{"Added Stores"}</Text>
|
||||
</TouchableOpacity> }
|
||||
</View>
|
||||
}
|
||||
|
||||
|
||||
|
||||
</LinearGradient>
|
||||
);
|
||||
}
|
||||
export default CustomHeader;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
paddingRight: 20
|
||||
},
|
||||
itemCountContainer: {
|
||||
position: "absolute",
|
||||
height: 19,
|
||||
width: 20,
|
||||
borderRadius: 15,
|
||||
backgroundColor: "#FF7D7D",
|
||||
left: 20,
|
||||
bottom: 6,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 5000,
|
||||
},
|
||||
itemCountText: {
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
},
|
||||
linearGradient: {
|
||||
position: 'relative', // Ensure the linear gradient container has a position style set
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
import * as React from "react";
|
||||
import { TextInput } from "react-native";
|
||||
import { globalStyle } from "../styles/Global";
|
||||
import { PrimaryTheme } from "../styles/Themes";
|
||||
|
||||
const CustomInput = (props) => {
|
||||
return (
|
||||
<TextInput placeholder={props.placeholder} autoComplete='off' placeholderTextColor={PrimaryTheme.$text_color_500} style={globalStyle.inputStyle}>
|
||||
</TextInput>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomInput;
|
||||
@@ -0,0 +1,57 @@
|
||||
import React,{useRef,useEffect} from "react";
|
||||
import { Text, TouchableOpacity ,View,Image,Animated,ActivityIndicator,StatusBar} from "react-native";
|
||||
import { customeButtons,GetPageTheme,customStyles,globalStyles,HP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
|
||||
// import LoadingSVG from '../assets/image/loader.svg'
|
||||
// import { SvgXml } from "react-native-svg";
|
||||
// import { heightPercentageToDP } from "react-native-responsive-screen";
|
||||
|
||||
const DownloadAPKModal = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const downloadAnimated = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const htStyle={height:HP('100%')+StatusBar.currentHeight};
|
||||
let dc=props.downloadCount;
|
||||
let tc=props.totalCount;
|
||||
let p=tc==0?0:((dc/tc)*100);
|
||||
|
||||
const bar_width=(p=='Infinity')?'0%':(p>100?'100%':p+'%');
|
||||
|
||||
// downloadAnimated.setValue(0);
|
||||
// Animated.timing(downloadAnimated, {
|
||||
// toValue: 1,
|
||||
// duration:100,
|
||||
// useNativeDriver:false,
|
||||
// }).start();
|
||||
// let prev_dc=dc<1?dc-1:dc;
|
||||
// const bar_width=downloadAnimated.interpolate({
|
||||
// inputRange:[prev_dc,dc],
|
||||
// outputRange:[((prev_dc/tc)*100)+'%',((dc/tc)*100)+'%'],
|
||||
// });
|
||||
|
||||
return (
|
||||
<View style={[customStyle.loaderBackdrop]}>
|
||||
<View style={customStyle.download_loaderCon}>
|
||||
{(props.title!=null) && <Text style={customStyle.downloadAPk_Title}>{props.title}</Text>}
|
||||
{(props.downloadCount!=null && props.totalCount!=null) && props.hideCounter!=true && <Text style={customStyle.download_count}>{(dc+1)+'/'+(tc+1)}</Text>}
|
||||
|
||||
<View style={customStyle.downloadAPkProgress}>
|
||||
<Image source={require('../assets/image/loader.gif')} style={customStyle.downloadAPkProgress_gif} />
|
||||
</View>
|
||||
{props.subtitle!=null &&
|
||||
<View style={customStyle.downloadAPk_subtitleWrap}>
|
||||
{<ActivityIndicator size={'small'} color={PageTheme.$primary_color} style={customStyle.downloadAPKModal_spin}/>}
|
||||
{(props.subtitle!=null) && <Text style={customStyle.downloadAPk_subTitle}>{props.subtitle}</Text>}
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default DownloadAPKModal;
|
||||
@@ -0,0 +1,61 @@
|
||||
import React,{useRef,useEffect} from "react";
|
||||
import { Text, TouchableOpacity ,View,Image,Animated,ActivityIndicator,StatusBar} from "react-native";
|
||||
import { customeButtons,GetPageTheme,customStyles,globalStyles,HP } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { AntDesign } from "./icons";
|
||||
|
||||
const DownloadDataModal = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const globalStyle=globalStyles(props.DarkMode,route.name);
|
||||
const customStyle=customStyles(props.DarkMode,route.name);
|
||||
|
||||
const downloadAnimated = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const htStyle={height:HP('100%')+StatusBar.currentHeight};
|
||||
let dc=props.downloadCount;
|
||||
let tc=props.totalCount;
|
||||
let p=((dc/tc)*100);
|
||||
|
||||
const bar_width=p>p?'100%':p+'%';
|
||||
|
||||
let showProgresssBar=(props.showProgresssBar!=null && props.showProgresssBar!='')?props.showProgresssBar:(props.showProgresssBar===false?false:true);
|
||||
|
||||
// downloadAnimated.setValue(0);
|
||||
// Animated.timing(downloadAnimated, {
|
||||
// toValue: 1,
|
||||
// duration:100,
|
||||
// useNativeDriver:false,
|
||||
// }).start();
|
||||
// let prev_dc=dc<1?dc-1:dc;
|
||||
// const bar_width=downloadAnimated.interpolate({
|
||||
// inputRange:[prev_dc,dc],
|
||||
// outputRange:[((prev_dc/tc)*100)+'%',((dc/tc)*100)+'%'],
|
||||
// });
|
||||
|
||||
return (
|
||||
<View style={[customStyle.loaderBackdrop]}>
|
||||
<View style={customStyle.download_loaderCon}>
|
||||
{(props.title!=null) && <Text style={customStyle.download_Title}>{props.title}</Text>}
|
||||
{(props.downloadCount!=null && props.totalCount!=null) && props.hideCounter!=true && showProgresssBar && <Text style={customStyle.download_count}>{(dc+1)+'/'+(tc+1)}</Text>}
|
||||
{(props.downloadCount!=null && props.totalCount!=null && showProgresssBar) &&
|
||||
<View style={customStyle.downloadProgress}>
|
||||
<View style={customStyle.downloadProgress_bg}></View>
|
||||
<Animated.View style={[customStyle.downloadProgress_filled,{width:bar_width}]}></Animated.View>
|
||||
</View>
|
||||
}
|
||||
{(props.subtitle!=null) && <Text style={[customStyle.download_subTitle,(props.subTextStyle!=null && props.subTextStyle!=''?props.subTextStyle:{})]}>{props.subtitle}</Text>}
|
||||
{(props.showOkButton!=true) && <ActivityIndicator size={'small'} color={PageTheme.$primary_color} style={customStyle.downloadModal_spin}/>}
|
||||
|
||||
{(props.showOkButton==true && props.OnOKClick!=null) &&
|
||||
<View style={customStyle.downloadModal_btnWrap}>
|
||||
<TouchableOpacity style={customStyle.downloadModal_OkBtn} onPress={()=>{props.OnOKClick()}}>
|
||||
<Text style={customStyle.downloadModal_OkBtnText}>Ok</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
export default DownloadDataModal;
|
||||
@@ -0,0 +1,855 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import moment from 'moment';
|
||||
import { get_item, set_item, clear_item } from '../components/localStorage';
|
||||
import { db } from '../constants/constants';
|
||||
import { getMethodName, METHODS } from '../constants/methodNames';
|
||||
import { getDownloadJson1 } from '../controller/functions';
|
||||
import { AppName, PerformicsIRAppName } from '../../../AppSpecificContant';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
export const PJP_colList = ['MID', 'ChannelId', 'StoreId', 'StoreCode', 'EmpId', 'VisitDate', 'ChainId', 'ChainName', 'StoreName', 'Address', 'Location', 'Landmark', 'CityId', 'CityName', 'StateId', 'StateName', 'RegionId', 'StoreTypeId', 'StoreType', 'Pincode', 'Latitude', 'Longitude', 'Phone', 'Mobile', 'ContactPerson', 'Email', 'UploadStatus', 'GeoTag', 'GeoFenceRadius', 'ExpiryStock', 'InTime', 'OutTime', 'CameraAllow', 'AddVisiAllow', 'LastVisitDate', 'Score', 'MinTimeTaken', 'StoreCategoryId', 'StoreCategory', 'StoreClassId', 'StoreClass', 'TaxType', 'GSTno', 'GSTImage', 'MTDMerchandised', 'DistributorId'];
|
||||
|
||||
export function getDownloadDataTask() {
|
||||
var DownloadTasks = ["Table_Structure"]; // not required in redownload
|
||||
DownloadTasks.push("Mapping_JourneyPlan"); // not required in redownload
|
||||
DownloadTasks.push("Adhoc_JourneyPlan"); // not required in redownload
|
||||
DownloadTasks.push("NonProgram_JourneyPlan"); // not required in redownload
|
||||
DownloadTasks.push("Master_Distributor"); // not required in redownload
|
||||
// DownloadTasks.push("Master_Route"); // not required in redownload
|
||||
DownloadTasks.push("Master_MenuAppDashboard");
|
||||
|
||||
DownloadTasks.push("Product_Master");
|
||||
DownloadTasks.push("Report_AferCheckIn"),
|
||||
|
||||
DownloadTasks.push("Non_Working_Reason"); // not required in redownload
|
||||
DownloadTasks.push("Menu_Master"); // not required in redownload
|
||||
DownloadTasks.push("Mapping_Menu");
|
||||
DownloadTasks.push("Mapping_MenuConfiguration"); // not required in redownload
|
||||
DownloadTasks.push("Mapping_MenuDistributorPoint");
|
||||
DownloadTasks.push("Master_Category"); // not required in redownload
|
||||
DownloadTasks.push("Master_Competitor"); // not required in redownload && only used in competition vis, comp promo, sampling
|
||||
DownloadTasks.push("Master_NonVisibility"); // not required in redownload
|
||||
DownloadTasks.push("Master_Display"); // not required in redownload
|
||||
DownloadTasks.push("Mapping_ProductAssortmentStorewise");
|
||||
DownloadTasks.push("Mapping_ProductAssortment");
|
||||
DownloadTasks.push("Mapping_Visibility");
|
||||
DownloadTasks.push("LastVisit_ClosingStock");
|
||||
|
||||
DownloadTasks.push("Master_Feedback"); // not required in redownload
|
||||
DownloadTasks.push("Master_IssueCategory");
|
||||
DownloadTasks.push("Master_IssueType"); // not required in redownload
|
||||
DownloadTasks.push("Master_PromoType"); // not required in redownload
|
||||
DownloadTasks.push("Master_WindowDefinition");
|
||||
DownloadTasks.push("Mapping_StoreWindow");
|
||||
DownloadTasks.push("Master_WindowQuestion");
|
||||
DownloadTasks.push("Mapping_WindowQuestion");
|
||||
DownloadTasks.push("Master_WindowReason");
|
||||
DownloadTasks.push("Master_WindowStockDefinition");
|
||||
DownloadTasks.push("Master_POSMDefinition");
|
||||
DownloadTasks.push("Mapping_StorePOSM");
|
||||
DownloadTasks.push("Master_POSMReason");
|
||||
DownloadTasks.push("Master_POSMQuestion");
|
||||
DownloadTasks.push("Mapping_POSMQuestion");
|
||||
// DownloadTasks.push("User_CurrentPosmStock");
|
||||
DownloadTasks.push("Master_VisibilityDefinition");
|
||||
DownloadTasks.push("Mapping_StoreVisibility");
|
||||
DownloadTasks.push("Master_VisibilityQuestion");
|
||||
DownloadTasks.push("Mapping_VisibilityQuestion");
|
||||
DownloadTasks.push("Master_VisibilityStockDefinition");
|
||||
DownloadTasks.push("Master_VisibilityReason");
|
||||
DownloadTasks.push("Master_PromotionDefinition");
|
||||
DownloadTasks.push("Mapping_StorePromotion");
|
||||
DownloadTasks.push("Master_PromotionQuestion");
|
||||
DownloadTasks.push("Mapping_PromotionQuestion");
|
||||
DownloadTasks.push("Master_PromotionStockDefinition");
|
||||
DownloadTasks.push("Master_PromotionReason");
|
||||
DownloadTasks.push("Master_ShareOfShelfDefinition");
|
||||
DownloadTasks.push("Mapping_StoreShareOfShelf");
|
||||
DownloadTasks.push("Mapping_ShareOfShelfTarget");
|
||||
DownloadTasks.push("Mapping_StoreShareOfShelfTarget");
|
||||
DownloadTasks.push("Master_ImageType"); // not required in redownload
|
||||
DownloadTasks.push("Report_PromoterMerchandiserPerformance"); // not required in redownload
|
||||
DownloadTasks.push("Master_Checklist");
|
||||
DownloadTasks.push("Mapping_DisplayChecklist");
|
||||
DownloadTasks.push("Master_SurveyQuestion");
|
||||
DownloadTasks.push("Master_FeedbackQuestion");
|
||||
DownloadTasks.push("Mapping_Survey");
|
||||
DownloadTasks.push("Master_CategoryDefinition");
|
||||
DownloadTasks.push("Mapping_StoreCategory");
|
||||
DownloadTasks.push("Master_CategoryQuestion");
|
||||
DownloadTasks.push("Mapping_CategoryQuestion");
|
||||
DownloadTasks.push("Master_CategoryStockDefinition");
|
||||
DownloadTasks.push("Master_CategoryReason");
|
||||
DownloadTasks.push("Master_PosSaleDefinition");
|
||||
DownloadTasks.push("Mapping_PosSaleDefinition");
|
||||
DownloadTasks.push("Mapping_StorePosSaleDefinition");
|
||||
DownloadTasks.push("Master_PosSaleReason");
|
||||
DownloadTasks.push("Report_ComplianceScore"); // not required in redownload
|
||||
DownloadTasks.push("Master_Document"); // not required in redownload
|
||||
DownloadTasks.push("Master_StoreChecklist");
|
||||
DownloadTasks.push("Master_MenuReports"); // not required in redownload
|
||||
DownloadTasks.push("Master_City"); // not required in redownload
|
||||
DownloadTasks.push("Master_StoreType"); // not required in redownload
|
||||
DownloadTasks.push("Master_Chain"); // not required in redownload
|
||||
DownloadTasks.push("Master_StoreCategory"); // not required in redownload
|
||||
DownloadTasks.push("Master_StoreClass"); // not required in redownload
|
||||
DownloadTasks.push("Non_Working_ReasonDistributor"); // not required in redownload
|
||||
DownloadTasks.push("Master_Channel"); // not required in redownload
|
||||
DownloadTasks.push("PriviousVisit_Orders");
|
||||
DownloadTasks.push("NonMerchandising_JourneyPlan"); // not required in redownload
|
||||
DownloadTasks.push("Master_VisitorFeedbackQuestion");
|
||||
DownloadTasks.push("Master_VisitorLoginQuestion");
|
||||
DownloadTasks.push("Mapping_StoreVisibilitySpecific");
|
||||
DownloadTasks.push("Master_SamplingDefinition");
|
||||
DownloadTasks.push("Master_SamplingStockDefinition");
|
||||
DownloadTasks.push("Mapping_StoreSampling");
|
||||
DownloadTasks.push("Master_SamplingQuestion");
|
||||
DownloadTasks.push("Mapping_SamplingQuestion");
|
||||
DownloadTasks.push("Master_SamplingReason");
|
||||
DownloadTasks.push("Master_Program");
|
||||
DownloadTasks.push("Master_ProgramDefinition");
|
||||
DownloadTasks.push("Mapping_StoreProgram");
|
||||
DownloadTasks.push("Master_ProgramQuestion");
|
||||
DownloadTasks.push("Mapping_ProgramQuestion");
|
||||
DownloadTasks.push("Master_ProgramStockDefinition");
|
||||
DownloadTasks.push("Master_ProgramReason");
|
||||
DownloadTasks.push("Mapping_StoreAuditGrading");
|
||||
DownloadTasks.push("Mapping_StoreTargetBased");
|
||||
DownloadTasks.push("Master_TargetBasedQuestion");
|
||||
DownloadTasks.push("Mapping_TargetBasedQuestion");
|
||||
DownloadTasks.push("Master_ContractFormQuestion");
|
||||
DownloadTasks.push("Mapping_ContractForm");
|
||||
DownloadTasks.push("Master_NonContractFromReason");
|
||||
DownloadTasks.push("Master_ShareOfShelfEyeLevelDefinition");
|
||||
DownloadTasks.push("Mapping_StoreShareOfShelfEyeLevel");
|
||||
DownloadTasks.push("Master_DistributorFilter");
|
||||
DownloadTasks.push("Master_CityFilter");
|
||||
DownloadTasks.push("Master_StoreTypeFilter");
|
||||
DownloadTasks.push("Master_DetailerContent"); // not required in redownload
|
||||
DownloadTasks.push("Master_UserHomeLocation");
|
||||
// DownloadTasks.push("Mapping_WarehouseItem");
|
||||
DownloadTasks.push("Master_WarehouseItem");
|
||||
DownloadTasks.push("Master_WarehouseItemQuestion");
|
||||
DownloadTasks.push("Mapping_WarehouseItemQuestion");
|
||||
DownloadTasks.push("Master_WarehouseNonDeployReason");
|
||||
DownloadTasks.push("Mapping_WarehouseCampaignItem");
|
||||
DownloadTasks.push("Mapping_WarehouseCampaignItemQuestion");
|
||||
DownloadTasks.push("Mapping_WarehouseCampaignDeployment");
|
||||
DownloadTasks.push("Mapping_WarehousePrimaryItem");
|
||||
DownloadTasks.push("Report_WarehouseStockInHand");
|
||||
DownloadTasks.push("Warehouse_InwardData");
|
||||
DownloadTasks.push("Master_WarehouseReason");
|
||||
DownloadTasks.push("Master_StockPromoType");
|
||||
DownloadTasks.push("Training_Document");
|
||||
DownloadTasks.push("Mapping_AddStoreConfiguration");
|
||||
|
||||
DownloadTasks.push("KYC_StoreList");
|
||||
DownloadTasks.push("Mapping_KYCConfiguration");
|
||||
DownloadTasks.push("KYC_StoreListRejected");
|
||||
DownloadTasks.push("Mapping_KYCUploaded");
|
||||
let DownloadTasks1 = [];
|
||||
for (let i = 0; i < DownloadTasks.length; i++) {
|
||||
let key = DownloadTasks[i];
|
||||
let index = i + 1;
|
||||
let IsMandatory = (key == 'Table_Structure' || key == 'Mapping_JourneyPlan') ? true : false;
|
||||
let obj = { "KeyId": index, "DownloadKey": key, "IsMandatory": IsMandatory, "DevActive": true, "ProdActive": true, "DownloadSequence": index };
|
||||
DownloadTasks1.push(obj);
|
||||
if (i == DownloadTasks.length - 1) {
|
||||
return DownloadTasks1;
|
||||
}
|
||||
}
|
||||
// return DownloadTasks;
|
||||
}
|
||||
|
||||
export const devDownloadKeys = (availableTables = []) => {
|
||||
const allDevKeys = [
|
||||
// "Master_MenuReportStoreWise",
|
||||
// "Mapping_SideMenuMiscellaneous",
|
||||
// "StoreList_OfflineOrder",
|
||||
// "Master_NonOrderReason",
|
||||
// "Mapping_AdditionalVisibilityProduct",
|
||||
// "Gyancast_TrainingContent",
|
||||
// "Gyancast_TrainingContentQuestion",
|
||||
// "Gyancast_PopupMessage"
|
||||
];
|
||||
|
||||
// ✅ Filter only those keys which exist in Table_Structure
|
||||
const filteredKeys = allDevKeys.filter(key => availableTables.includes(key));
|
||||
|
||||
return filteredKeys.map((key, index) => {
|
||||
const IsMandatory = (key === 'Table_Structure' || key === 'Mapping_JourneyPlan');
|
||||
return {
|
||||
KeyId: index + 1,
|
||||
DownloadKey: key,
|
||||
IsMandatory,
|
||||
DevActive: true,
|
||||
ProdActive: true,
|
||||
DownloadSequence: index + 1
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// export const devDownloadKeys = (availableTables = []) => {
|
||||
// const allDevKeys = [
|
||||
// "Mapping_ProductPTR"
|
||||
// ];
|
||||
|
||||
// const shouldFilter = Array.isArray(availableTables) && availableTables.length > 0;
|
||||
// console.log("AvailbleFilterTable:",shouldFilter)
|
||||
|
||||
// const filteredKeys = shouldFilter
|
||||
// ? allDevKeys.filter(key => availableTables.includes(key))
|
||||
// : allDevKeys; // 🔥 fallback
|
||||
|
||||
// return filteredKeys.map((key, index) => ({
|
||||
// KeyId: index + 1000,
|
||||
// DownloadKey: key,
|
||||
// IsMandatory: false,
|
||||
// DevActive: true,
|
||||
// ProdActive: true,
|
||||
// DownloadSequence: index + 100
|
||||
// }));
|
||||
// };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export async function getReDDownloadTask(AddKeys = []) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
let myd = [];
|
||||
myd.push("Mapping_ProductAssortmentStorewise");
|
||||
myd.push("Mapping_ProductAssortment");
|
||||
myd.push("LastVisit_ClosingStock");
|
||||
myd.push("Mapping_StoreWindow");
|
||||
myd.push("Mapping_WindowQuestion");
|
||||
myd.push("Mapping_StorePOSM");
|
||||
myd.push("Mapping_POSMQuestion");
|
||||
myd.push("Mapping_StoreVisibility");
|
||||
myd.push("Mapping_VisibilityQuestion");
|
||||
myd.push("Mapping_StorePromotion");
|
||||
myd.push("Mapping_PromotionQuestion");
|
||||
myd.push("Mapping_StoreShareOfShelf");
|
||||
myd.push("Mapping_DisplayChecklist");
|
||||
myd.push("Mapping_Survey");
|
||||
myd.push("Mapping_StoreCategory");
|
||||
myd.push("Mapping_CategoryQuestion");
|
||||
myd.push("Mapping_StoreVisibilitySpecific");
|
||||
myd.push("Mapping_ShareOfShelfTarget");
|
||||
myd.push("Product_Master");
|
||||
myd.push("Mapping_Menu");
|
||||
myd.push("Mapping_MenuDistributorPoint");
|
||||
myd.push("Master_WindowDefinition");
|
||||
myd.push("Master_WindowQuestion");
|
||||
myd.push("Master_WindowReason");
|
||||
myd.push("Master_WindowStockDefinition");
|
||||
myd.push("Master_POSMDefinition");
|
||||
myd.push("Master_POSMReason");
|
||||
myd.push("Master_POSMQuestion");
|
||||
myd.push("User_CurrentPosmStock");
|
||||
myd.push("Master_VisibilityDefinition");
|
||||
myd.push("Master_VisibilityQuestion");
|
||||
myd.push("Master_VisibilityStockDefinition");
|
||||
myd.push("Master_VisibilityReason");
|
||||
myd.push("Master_PromotionDefinition");
|
||||
myd.push("Master_PromotionQuestion");
|
||||
myd.push("Master_PromotionStockDefinition");
|
||||
myd.push("Master_PromotionReason");
|
||||
myd.push("Master_ShareOfShelfDefinition");
|
||||
myd.push("Master_Checklist");
|
||||
myd.push("Master_SurveyQuestion");
|
||||
myd.push("Master_FeedbackQuestion");
|
||||
myd.push("Master_CategoryDefinition");
|
||||
myd.push("Master_CategoryQuestion");
|
||||
myd.push("Master_CategoryStockDefinition");
|
||||
myd.push("Master_CategoryReason");
|
||||
myd.push("Master_PosSaleDefinition");
|
||||
myd.push("Mapping_PosSaleDefinition");
|
||||
myd.push("Master_PosSaleReason");
|
||||
myd.push("Master_StoreChecklist");
|
||||
myd.push("PriviousVisit_Orders");
|
||||
myd.push("Master_VisitorFeedbackQuestion");
|
||||
myd.push("Master_SamplingDefinition");
|
||||
myd.push("Master_SamplingStockDefinition");
|
||||
myd.push("Mapping_StoreSampling");
|
||||
myd.push("Master_SamplingQuestion");
|
||||
myd.push("Master_Program");
|
||||
myd.push("Master_ProgramDefinition");
|
||||
myd.push("Mapping_StoreProgram");
|
||||
myd.push("Master_ProgramQuestion");
|
||||
myd.push("Mapping_ProgramQuestion");
|
||||
myd.push("Master_ProgramStockDefinition");
|
||||
myd.push("Mapping_StoreTargetBased");
|
||||
myd.push("Master_TargetBasedQuestion");
|
||||
myd.push("Mapping_TargetBasedQuestion");
|
||||
var DownloadTasks = AddKeys.concat(myd);
|
||||
|
||||
let DownloadTasks1 = [];
|
||||
for (let i = 0; i < DownloadTasks.length; i++) {
|
||||
let key = DownloadTasks[i];
|
||||
let index = i + 1;
|
||||
let IsMandatory = (key == 'Table_Structure' || key == 'Mapping_JourneyPlan') ? true : false;
|
||||
let obj = { "KeyId": index, "DownloadKey": key, "IsMandatory": IsMandatory, "DevActive": true, "ProdActive": true, "DownloadSequence": index };
|
||||
DownloadTasks1.push(obj);
|
||||
if (i == DownloadTasks.length - 1) {
|
||||
// console.log('DownloadTasks1:',DownloadTasks1);
|
||||
resolve(DownloadTasks1);
|
||||
}
|
||||
}
|
||||
}).catch((Err) => {
|
||||
console.log(Err);
|
||||
return [];
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
export async function getReDownloadTasks1(props) {
|
||||
console.log('getReDownloadTasks1');
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var DownloadTasks1 = [];
|
||||
console.log('chekc 1', props.DownloadKey);
|
||||
if (props.DownloadKey != null && props.DownloadKey != '') {
|
||||
console.log('props.DownloadKey');
|
||||
let prop_dk = JSON.parse(props.DownloadKey);
|
||||
let AllDTs = prop_dk['DownloadKey'] || [];
|
||||
console.log('set server d keys', AllDTs.length);
|
||||
if (AllDTs.length > 0) {
|
||||
for (let i = 0; i < AllDTs.length; i++) {
|
||||
let item = AllDTs[i];
|
||||
if (item.ReDownload == 1 || item.ReDownload == 'true' || item.ReDownload == '1') {
|
||||
DownloadTasks1.push(item);
|
||||
}
|
||||
if (i == AllDTs.length - 1) {
|
||||
console.log('set server d2 keys', DownloadTasks1.length);
|
||||
let sortedDTs = await SortDownloadkeys(DownloadTasks1);
|
||||
resolve(sortedDTs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
resolve([]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DownloadTasks1 = getDownloadDataTask();
|
||||
resolve(DownloadTasks1);
|
||||
}
|
||||
|
||||
}).catch((Err) => {
|
||||
console.log('getDTasks err', Err);
|
||||
return [];
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
export async function SortDownloadkeys(AllDTs) {
|
||||
return await new Promise.all(AllDTs.sort((a, b) => {
|
||||
if (a.DownloadSequence < b.DownloadSequence) {
|
||||
return -1;
|
||||
}
|
||||
if (a.DownloadSequence > b.DownloadSequence) {
|
||||
return 1;
|
||||
}
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
})).then((val) => {
|
||||
return AllDTs;
|
||||
});
|
||||
}
|
||||
|
||||
export async function getBeatDownloadTask() {
|
||||
let DownloadTasks = ["JourneyPlan_RouteWise"];
|
||||
return await getReDDownloadTask(DownloadTasks);
|
||||
}
|
||||
|
||||
export async function getNewStoresDownloadTask(PJP_Table) {
|
||||
let DownloadTasks = ["Mapping_JourneyPlan", "Adhoc_JourneyPlan"];
|
||||
return await getReDDownloadTask(DownloadTasks);
|
||||
}
|
||||
|
||||
|
||||
export async function onNoData(data = [], shouldStop = false, tbname = '', props, showErrorModal = () => { }, res) {
|
||||
console.log("res on no data in ReDownloadTask:", res);
|
||||
const ST = props.StaticText || {};
|
||||
if (tbname != '') {
|
||||
db.transaction(function (txn) {
|
||||
// delete all today data
|
||||
txn.executeSql(`delete from ${tbname} where 1=1`, [], function (txn1, txnres) {
|
||||
console.log('deleted all data for ' + tbname);
|
||||
}, function (Etxn, err) {
|
||||
console.log('err:', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (shouldStop == true) {
|
||||
let msg = '';
|
||||
// res should be set only when there is network or other related issue
|
||||
if (res == '') {
|
||||
msg = ST.Nodatafoundfor + tbname + '';
|
||||
if (tbname == 'Mapping_JourneyPlan') {
|
||||
msg = ST.Youhavenojourneyplanfortoday;
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg = res + " Please ensure you are connected to the internet and retry downloading! ";
|
||||
}
|
||||
console.log("msg :", msg);
|
||||
// set is Data downloaded to false so that no other parts of app can be accessed if data is not downloaded
|
||||
// update download status on local async storage
|
||||
let dateWiseDataDownload = await get_item('dateWiseDataDownload');
|
||||
let dateWiseDataDownload1 = dateWiseDataDownload != null ? JSON.parse(dateWiseDataDownload) : {};
|
||||
let todayDate = moment(new Date()).format('DD/MM/YYYY');
|
||||
dateWiseDataDownload1[todayDate] = false;
|
||||
set_item('dateWiseDataDownload', JSON.stringify(dateWiseDataDownload1));
|
||||
// update downloaed status on redux props
|
||||
props.setTodayDataExists(false);
|
||||
props.setGlobalData({ isDataDownloaded: false })
|
||||
// notify(msg);
|
||||
// show error msg
|
||||
let obj = { "ErrorMsg": "!! Error in downloading data !!", "ErrorSubMsg": tbname, "ErrorDetail": msg }
|
||||
props.set_startDownload({ startDownload: false });
|
||||
//hide download modal and show Error in Download modal with details
|
||||
showErrorModal(obj);
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export async function insert_TaskDownloadedData(
|
||||
res,
|
||||
D_key,
|
||||
D_ColList = [],
|
||||
props,
|
||||
showErrorModal = () => {},
|
||||
setTaskResponse = () => {}
|
||||
) {
|
||||
console.log('insert_TaskDownloadedData:', D_key);
|
||||
let r_obj = { r: false, data_arr: [] };
|
||||
|
||||
try {
|
||||
if (res && typeof res === 'object' && res[D_key] != null && res[D_key] !== '') {
|
||||
const jsonData = res[D_key] || [];
|
||||
|
||||
if (!Array.isArray(jsonData) || jsonData.length === 0) {
|
||||
console.warn(`⚠️ No data to insert in table: ${D_key}`);
|
||||
return { r: true, data_arr: [] };
|
||||
}
|
||||
|
||||
const columns = Array.from(
|
||||
new Set(jsonData.flatMap(row => Object.keys(row)))
|
||||
);
|
||||
|
||||
const normalizedData = jsonData.map(row => {
|
||||
const normalizedRow = {};
|
||||
columns.forEach(col => {
|
||||
normalizedRow[col] = row.hasOwnProperty(col) ? row[col] : null;
|
||||
});
|
||||
return normalizedRow;
|
||||
});
|
||||
|
||||
console.log("normalizedData", normalizedData);
|
||||
|
||||
const valuesArray = normalizedData.map(row => {
|
||||
const valueList = columns.map(col => {
|
||||
const val = row[col];
|
||||
if (val === null || val === undefined) return 'NULL';
|
||||
if (typeof val === 'number') return val;
|
||||
if (typeof val === 'boolean') return val ? 1 : 0;
|
||||
|
||||
return `'${val.toString().replace(/'/g, "")}'`;
|
||||
|
||||
});
|
||||
return `(${valueList.join(',')})`;
|
||||
});
|
||||
|
||||
const sql = `INSERT INTO ${D_key} (${columns.join(',')}) VALUES ${valuesArray.join(',')};`;
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
db.transaction((txn) => {
|
||||
txn.executeSql(`DELETE FROM ${D_key}`, [], () => {
|
||||
txn.executeSql(sql, [], () => {
|
||||
setTaskResponse(jsonData);
|
||||
console.log(`✅ Inserted data into table: ${D_key}`);
|
||||
resolve();
|
||||
}, (tx, error) => {
|
||||
console.error(`❌ Insert failed in table: ${D_key}`, error);
|
||||
reject(error);
|
||||
});
|
||||
}, (tx, error) => {
|
||||
console.error(`❌ Delete failed in table: ${D_key}`, error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return { r: true, data_arr: jsonData };
|
||||
}
|
||||
|
||||
if (res && typeof res === 'object' && res[0]?.Result === "No Data") {
|
||||
console.log('No data found');
|
||||
return { r: true, data_arr: [] };
|
||||
}
|
||||
|
||||
if (res && typeof res === 'object' && res.success === false) {
|
||||
console.log('Error in downloading network', res);
|
||||
return { r: false, data_arr: [] };
|
||||
}
|
||||
|
||||
console.log('Error in downloading else', res);
|
||||
return { r: false, data_arr: [] };
|
||||
|
||||
} catch (err) {
|
||||
console.log('err:', err);
|
||||
return { r: false, data_arr: [] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export async function checkIfDataAvlbl(storeData, D_key, cols = 'StoreId') {
|
||||
console.log('checkIfDataAvlbl', D_key)
|
||||
let { StoreId, ChannelId, RegionId, StoreTypeId } = storeData;
|
||||
let colsToCompare = cols.split(',');
|
||||
if (cols != '' && cols != null && storeData != null && colsToCompare.length > 0) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let q = '', whereq = '';
|
||||
q = `Select * from ${D_key}`;
|
||||
for (let i = 0; i < colsToCompare.length; i++) {
|
||||
let column = colsToCompare[i];
|
||||
if (column != null && column != '' && storeData[column] != null && storeData[column] != '') {
|
||||
whereq += whereq == '' ? ` Where ` : ' and ';
|
||||
whereq += ` ${column}=${storeData[column]} `;
|
||||
}
|
||||
}
|
||||
q += ' ' + whereq;
|
||||
console.log('query to check store data:', q)
|
||||
db.transaction(function (txn) {
|
||||
// delete all today data
|
||||
txn.executeSql(q, [], function (txn1, txnres) {
|
||||
console.log(D_key + ' data length:', txnres.rows.length);
|
||||
if (txnres.rows.length > 0) {
|
||||
resolve(true);
|
||||
}
|
||||
else {
|
||||
resolve(false);
|
||||
}
|
||||
}, function (txnE, txnerr) {
|
||||
console.log(txnerr);
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log('error:', err);
|
||||
return false;
|
||||
})
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//************************** download functionallity*******************
|
||||
export async function startRedownload(props, DownloadTasks, dowloadedCount, totalCount, setDowloadedCount = () => { }, setTotalCount = () => { }) {
|
||||
console.log('startRedownload', DownloadTasks);
|
||||
if (totalCount == (DownloadTasks.length - 1) && totalCount > 0) {
|
||||
console.log('setDowloadedCount', dowloadedCount, 0);
|
||||
setDowloadedCount(0);
|
||||
}
|
||||
else {
|
||||
console.log('setTotalCount', totalCount, (DownloadTasks.length - 1));
|
||||
setTotalCount((DownloadTasks.length - 1));
|
||||
}
|
||||
return DownloadTasks;
|
||||
}
|
||||
|
||||
export async function executeTasks(props, storeData, DownloadTasks, dowloadedCount, totalCount, setDowloadedCount = () => { }, setDownloadingText = () => { }, onDownloadComplete = () => { }, setTaskResponse = () => { }, showErrorModal = () => { }) {
|
||||
// var DownloadTasks=getDownloadDataTask();
|
||||
let loginInfo = await get_item('loginInfo');
|
||||
const loginDetails = JSON.parse(loginInfo);
|
||||
var currentIndex = dowloadedCount;
|
||||
console.log('currentIndex:', currentIndex);
|
||||
if (currentIndex >= 0) {
|
||||
let dk_data = DownloadTasks[currentIndex];
|
||||
console.log('dk_data', dk_data);
|
||||
let key = dk_data.DownloadKey || '';
|
||||
setDownloadingText(key);
|
||||
let IsDataExists = await CheckIfRequiredDownload(storeData, currentIndex, DownloadTasks);
|
||||
if (!IsDataExists) {
|
||||
var data = await getPostData(DownloadTasks, currentIndex);
|
||||
var url = props.baseurl + getMethodName(METHODS.DOWNLOADJSON_METHOD);
|
||||
console.log(url, data);
|
||||
await getDownloadJson1(url, data)
|
||||
.then(async (res) => {
|
||||
console.log('res of download get');
|
||||
let isAdded = await updateTaskRes(props, storeData, res, currentIndex, DownloadTasks, setTaskResponse, true, showErrorModal);
|
||||
if (isAdded == true) {
|
||||
if (currentIndex == DownloadTasks.length - 1) {
|
||||
console.log('last found all downloaded');
|
||||
onDownloadComplete();
|
||||
}
|
||||
else {
|
||||
console.log('all downloaded but last not found ');
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('Cannot download all Data');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('onPage Team error', err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
let isAdded = await updateTaskRes(props, storeData, [{ "Result": "No Data" }], currentIndex, DownloadTasks, setTaskResponse, false, showErrorModal);
|
||||
if (isAdded == true) {
|
||||
if (currentIndex == DownloadTasks.length - 1) {
|
||||
console.log('last found all downloaded');
|
||||
onDownloadComplete();
|
||||
}
|
||||
else {
|
||||
console.log('all downloaded but last not found ');
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('Cannot download all Data');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
////need to optimize this function
|
||||
export async function CheckIfRequiredDownload(storeData, index, DownloadTasks) {
|
||||
let dk_data = DownloadTasks[index];
|
||||
let key = dk_data.DownloadKey || '';
|
||||
return new Promise(async (resolve, reject) => {
|
||||
switch (key) {
|
||||
case 'Mapping_Menu': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'ChannelId,RegionId,StoreTypeId,StoreCategoryId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_Visibility': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_Promotion': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StateId,ChainId,StoreTypeId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_ProductAssortmentStorewise': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId,ProductId,MSL,MBQ');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_ProductAssortment': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId,ProductId,MSL,MBQ');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'LastVisit_ClosingStock': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_StoreWindow': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StorePOSM': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreShelfTalker': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_StoreVisibility': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_StorePromotion': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_StoreShareOfShelf': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_Survey': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreCategory': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreVisibilitySpecific': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_ShareOfShelfTarget': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StateId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Mapping_MenuDistributorPoint': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'MenuId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'PriviousVisit_Orders': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreSampling': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreAuditGrading': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreProgram': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
case 'Mapping_StoreTargetBased': {
|
||||
let IsDataAvlbl = await checkIfDataAvlbl(storeData, key, 'StoreId');
|
||||
console.log('IsDataAvlbl:', IsDataAvlbl);
|
||||
resolve(IsDataAvlbl);
|
||||
break;
|
||||
}
|
||||
|
||||
default: resolve(false); break;
|
||||
|
||||
}
|
||||
|
||||
}).catch((err) => {
|
||||
console.log('error in check', err);
|
||||
return false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
////need to optimize this function
|
||||
export async function updateTaskRes(
|
||||
props,
|
||||
storeData,
|
||||
res,
|
||||
index,
|
||||
DownloadTasks,
|
||||
setTaskResponse = () => {},
|
||||
isDownloadExists = true,
|
||||
showErrorModal = () => {}
|
||||
) {
|
||||
try {
|
||||
const dk_data = DownloadTasks[index];
|
||||
const key = dk_data?.DownloadKey || '';
|
||||
const IsMandatory = dk_data?.IsMandatory === 'true' || dk_data?.IsMandatory === 1;
|
||||
console.log("res-------", key);
|
||||
const i_res = await insert_TaskDownloadedData(res, key, {}, props, showErrorModal);
|
||||
const { data_arr, r } = i_res;
|
||||
if (r) {
|
||||
setTaskResponse(data_arr);
|
||||
}
|
||||
console.log('r:', r);
|
||||
return r;
|
||||
} catch (err) {
|
||||
console.log('error in downloading', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function getPostData(DownloadTasks, index = 0) {
|
||||
// var DownloadTasks=getDownloadDataTask();
|
||||
// let token=await get_item('loginToken');
|
||||
let dk_data = DownloadTasks[index];
|
||||
let key = dk_data.DownloadKey || '';
|
||||
let loginInfo = await get_item('loginInfo');
|
||||
const loginDetails = JSON.parse(loginInfo);
|
||||
const todate = new Date();
|
||||
const today = moment(todate).format("HH:mm:ss");
|
||||
let projectInfo = await get_item('projectInfo');
|
||||
let projectDetails = projectInfo != null ? JSON.parse(projectInfo) : {};
|
||||
var postdata = {};
|
||||
if (index >= 0) {
|
||||
postdata = {
|
||||
Downloadtype: key,
|
||||
Username: loginDetails.UserId,
|
||||
Param1: '',
|
||||
Param2: (key == "Gyancast_TrainingContent" || key == "Gyancast_PopupMessage") ? projectDetails?.ProjectCode : (Platform.OS == "ios" ? "iOS" : "Android"),
|
||||
|
||||
};
|
||||
}
|
||||
return postdata;
|
||||
}
|
||||
|
||||
export async function getPostData2(key = '') {
|
||||
let loginInfo = await get_item('loginInfo');
|
||||
const loginDetails = JSON.parse(loginInfo);
|
||||
var postdata = {};
|
||||
if (key != '') {
|
||||
postdata = {
|
||||
Downloadtype: key,
|
||||
Username: loginDetails.UserId,
|
||||
Param1: '',
|
||||
Param2: Platform.OS == "ios" ? "iOS" : "Android",
|
||||
};
|
||||
}
|
||||
|
||||
return postdata;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Text, TouchableOpacity, View, Image, StatusBar, StyleSheet } from "react-native";
|
||||
|
||||
import { GetPageTheme, customStyles, globalStyles } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import {Entypo, Fontisto, MaterialCommunityIcons, FontAwesome } from "./icons";
|
||||
import moment from 'moment';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import { DevType } from "../constants/constants";
|
||||
|
||||
function DrawerHeader(props) {
|
||||
const route = useRoute();
|
||||
const isCancelled = useRef(false);
|
||||
const PageTheme = GetPageTheme(props.DarkTheme, route.name);
|
||||
const globalStyle = globalStyles(props.DarkMode, route.name);
|
||||
const customStyle = customStyles(props.DarkMode, route.name);
|
||||
const [currentTime, setCurrentTime] = useState('');
|
||||
const [currentDate, setCurrentDate] = useState('');
|
||||
const [isRed, setIsRed] = useState(true);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setTimer();
|
||||
return () => { isCancelled.current = true; };
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
var interval
|
||||
if (props?.TrainingOrg2?.length > 0) {
|
||||
interval = setInterval(() => {
|
||||
setIsRed(prev => !prev);
|
||||
}, 500); // changes every 500ms
|
||||
}
|
||||
return () => clearInterval(interval); // cleanup
|
||||
}, [props?.TrainingOrg2]);
|
||||
|
||||
function setTimer() {
|
||||
if (!isCancelled.current) {
|
||||
let d1 = new Date();
|
||||
let now = moment(d1).format('hh:mm:ss a');
|
||||
let ndate = moment(d1).format('DD/MM/YYYY');
|
||||
setCurrentTime(now);
|
||||
setCurrentDate(ndate);
|
||||
setTimeout(() => { setTimer(); }, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toggleDrawer() {
|
||||
props.navigation.toggleDrawer();
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<LinearGradient colors={[PageTheme.$gradient1, PageTheme.$primary_color]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={globalStyle.drawerScreenHdr_bg}>
|
||||
<StatusBar backgroundColor={PageTheme.$primary_color} translucent={true} {...props} barStyle={"light-content"} />
|
||||
<View style={globalStyle.dScreenHdr_Content}>
|
||||
<Text style={globalStyle.drawerScreenHdr_title}>{props.drawer_title != null ? props.drawer_title : route.name}</Text>
|
||||
<View style={globalStyle.dScreen_LeftContainer}>
|
||||
<TouchableOpacity activeOpacity={0.6} style={globalStyle.toggleDrawerBtn} onPress={() => { toggleDrawer() }}>
|
||||
<FontAwesome name='bars' size={20} color={PageTheme.$accent_color} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={globalStyle.dScreen_RightContainer}>
|
||||
<Text style={globalStyle.drawerProjectId}>{'Id : ' + (DevType == "Prod" ? (props.projectCode != null ? props.projectCode : '') : props?.projectCode + "_Dev")}</Text>
|
||||
<TouchableOpacity activeOpacity={0.6} style={[globalStyle.drawerNotifIcon, styles.button]} onPress={() => props.navigation.navigate('NotificationList')} >
|
||||
<View style={{}}>
|
||||
<MaterialCommunityIcons name='bell-ring-outline' size={20} color={PageTheme.$accent_color} />
|
||||
<View style={styles.itemCountContainer}>
|
||||
<Text style={styles.itemCountText}>{props?.badgeCount ? props?.badgeCount : 0}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
{/* <View style={customStyle.clocktimerRow}>
|
||||
<Entypo name='calendar' color={PageTheme.$primary_color} size={14}/><Text style={[customStyle.clocktimerText,customStyle.mr10]}>{currentDate}</Text>
|
||||
<Fontisto name='clock' color={PageTheme.$primary_color} size={14}/><Text style={customStyle.clocktimerText}>{currentTime}</Text>
|
||||
</View> */}
|
||||
</View>
|
||||
|
||||
</View>
|
||||
<View style={[customStyle.clocktimerWrap, { flexDirection: "row", justifyContent: "space-between", alignItems: 'center' }]}>
|
||||
<View style={[customStyle.clocktimerRow, props.Gyancast && { height: "50%" }]}>
|
||||
<Entypo name='calendar' color={PageTheme.$primary_color} size={14} /><Text style={[customStyle.clocktimerText, customStyle.mr10]}>{currentDate}</Text>
|
||||
<Fontisto name='clock' color={PageTheme.$primary_color} size={14} /><Text style={customStyle.clocktimerText}>{currentTime}</Text>
|
||||
</View>
|
||||
|
||||
{props.Gyancast &&
|
||||
<TouchableOpacity style={[globalStyle.toggleDrawerBtn, { alignItems: "center" }]} onPress={() => { props.navigation.navigate('Gyancasts') }}>
|
||||
{/* <SvgXml width={45} height={45} xml={props?.TrainingOrg2?.length>0?Gyancastsicon_red:Mic}/> */}
|
||||
<View style={customStyle.NB_quickL_IconS2}>
|
||||
<Image
|
||||
source={require('../assets/image/Gyancast.gif')}
|
||||
style={{ "width": 50, "height": 50 }}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
{props?.TrainingOrg2?.length > 0 && <Text style={{ color: isRed ? 'red' : 'green', fontSize: 40, fontWeight: "bold", position: "absolute", top: -23, left: 0 }}>{'\u2022'}</Text>}
|
||||
</View>
|
||||
<Text style={{ color: "#FFF", fontSize: 10, fontWeight: "bold", marginTop: 3 }} >GyanCast</Text>
|
||||
</TouchableOpacity>}
|
||||
</View>
|
||||
</LinearGradient>
|
||||
)
|
||||
}
|
||||
|
||||
export default DrawerHeader;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
marginRight: 20,
|
||||
},
|
||||
itemCountContainer: {
|
||||
position: "absolute",
|
||||
height: 20,
|
||||
width: 20,
|
||||
borderRadius: 15,
|
||||
backgroundColor: "#FF7D7D",
|
||||
left: 18,
|
||||
bottom: 10,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 2000,
|
||||
},
|
||||
itemCountText: {
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import base64 from 'base-64';
|
||||
import utf8 from 'utf8';
|
||||
|
||||
const SALT = 'ć92😳☕ĸ♊ǛƶÃƱzÙŒwŷygƃ☈8ò☢¯♓ǰ';
|
||||
const PREPENDING_STR = '__enc__';
|
||||
|
||||
export function encodeCredential(input) {
|
||||
if (input // if the input exists
|
||||
&& typeof input === 'string' // and it's a string
|
||||
) {
|
||||
const newInput = `${input}${SALT}`; // add salt to the input
|
||||
const utf8Bytes = utf8.encode(newInput); // utf8 encode it
|
||||
const encoded = base64.encode(utf8Bytes); // base64 encode it
|
||||
return `${PREPENDING_STR}${encoded}`; // add a prepending string
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
export function decodeCredential(input) {
|
||||
if (input // if the input exists
|
||||
&& typeof input === 'string' // and it's a string
|
||||
&& input.startsWith(PREPENDING_STR) === true // and it's encoded yet
|
||||
) {
|
||||
const newInput = input.replace(PREPENDING_STR, ''); // remove the prepending string
|
||||
const utf8Bytes = base64.decode(newInput); // base64 decode it
|
||||
const output = utf8.decode(utf8Bytes); // utf8 decode it
|
||||
return output.replace(SALT, '');
|
||||
}
|
||||
return input;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
import {PermissionsAndroid,Platform} from 'react-native';
|
||||
import { notify } from "./notify";
|
||||
import Permissions, { PERMISSIONS, RESULTS } from 'react-native-permissions'
|
||||
|
||||
export async function CheckAndAskForPermission(Permm){
|
||||
if (Platform.OS === 'ios') {
|
||||
console.log('CheckAndAskForPermission ios');
|
||||
let IOS_hasPermission = await Permissions.check(Permm)
|
||||
if (IOS_hasPermission==RESULTS.GRANTED) return true;
|
||||
let IOS_status = await Permissions.request(Permm);
|
||||
console.log('IOS_status:',IOS_status);
|
||||
if (IOS_status === RESULTS.GRANTED) return true;
|
||||
if (IOS_status === RESULTS.DENIED) {
|
||||
notify('Location permission denied by user.');
|
||||
} else if (RESULTS === RESULTS.UNAVAILABLE) {
|
||||
notify('Location permission not available.');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (Platform.OS === 'android') {
|
||||
const hasPermission = await PermissionsAndroid.check(Permm);
|
||||
if (hasPermission) return true;
|
||||
const status = await PermissionsAndroid.request(Permm);
|
||||
if (status === PermissionsAndroid.RESULTS.GRANTED) return true;
|
||||
if (status === PermissionsAndroid.RESULTS.DENIED) {
|
||||
notify('Location permission denied by user.');
|
||||
} else if (status === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
|
||||
notify('Location permission revoked by user.');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function CheckAndAskForMulitplePermissions(Permms=[]){
|
||||
let hasPermission = await Permissions.checkMultiple(Permms)
|
||||
let k_IOSLoc='ios.permission.LOCATION_WHEN_IN_USE',k_IOSCamera='ios.permission.CAMERA',k_IOSStorage='ios.permission.PHOTO_LIBRARY',k_IOSMic=PERMISSIONS.IOS.MICROPHONE,k_IOSmedia=PERMISSIONS.IOS.MEDIA_LIBRARY;
|
||||
let k_Loc='android.permission.ACCESS_FINE_LOCATION',k_Camera='android.permission.CAMERA',k_Storage='android.permission.WRITE_EXTERNAL_STORAGE',k_StorageRead='android.permission.READ_EXTERNAL_STORAGE',k_Mic=PERMISSIONS.ANDROID.RECORD_AUDIO;
|
||||
if (Platform.OS === 'ios') {
|
||||
if (hasPermission[k_IOSLoc]==RESULTS.GRANTED && hasPermission[k_IOSCamera]==RESULTS.GRANTED && hasPermission[k_IOSStorage]==RESULTS.GRANTED && hasPermission[k_IOSMic]==RESULTS.GRANTED && hasPermission[k_IOSmedia]==RESULTS.GRANTED) return true;
|
||||
}
|
||||
else{
|
||||
if (hasPermission[k_Loc]==RESULTS.GRANTED && hasPermission[k_Camera]==RESULTS.GRANTED && hasPermission[k_Storage]==RESULTS.GRANTED && hasPermission[k_StorageRead]==RESULTS.GRANTED && hasPermission[k_Mic]==RESULTS.GRANTED) return true;
|
||||
}
|
||||
|
||||
let statuses = await Permissions.requestMultiple(Permms);
|
||||
let denies=[];
|
||||
let notavlbl=[];
|
||||
console.log(statuses);
|
||||
if (Platform.OS === 'ios') {
|
||||
if (statuses[k_IOSLoc]==RESULTS.GRANTED && statuses[k_IOSCamera]==RESULTS.GRANTED && statuses[k_IOSStorage]==RESULTS.GRANTED && statuses[k_IOSMic]==RESULTS.GRANTED && statuses[k_IOSmedia]==RESULTS.GRANTED) return true;
|
||||
if (statuses[k_IOSLoc]=== RESULTS.DENIED) {
|
||||
denies.push('Location');
|
||||
} else if (statuses[k_IOSLoc] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Location');
|
||||
}
|
||||
|
||||
if (statuses[k_IOSCamera]=== RESULTS.DENIED) {
|
||||
denies.push('Camera');
|
||||
} else if (statuses[k_IOSCamera] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Camera');
|
||||
}
|
||||
|
||||
if (statuses[k_IOSStorage]=== RESULTS.DENIED) {
|
||||
denies.push('Photo Library');
|
||||
} else if (statuses[k_IOSStorage] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Photo Library');
|
||||
}
|
||||
|
||||
if (statuses[k_IOSMic]=== RESULTS.DENIED) {
|
||||
denies.push('Microphone');
|
||||
} else if (statuses[k_IOSMic] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Microphone');
|
||||
}
|
||||
|
||||
if (statuses[k_IOSmedia]=== RESULTS.DENIED) {
|
||||
denies.push('Media Library');
|
||||
} else if (statuses[k_IOSmedia] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Media Library');
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (statuses[k_Loc]==RESULTS.GRANTED && statuses[k_Camera]==RESULTS.GRANTED && statuses[k_Storage]==RESULTS.GRANTED && statuses[k_StorageRead]==RESULTS.GRANTED && statuses[k_Mic]==RESULTS.GRANTED) return true;
|
||||
if (statuses[k_Loc]=== RESULTS.DENIED) {
|
||||
denies.push('Location');
|
||||
} else if (statuses[k_Loc] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Location');
|
||||
}
|
||||
|
||||
if (statuses[k_Camera]=== RESULTS.DENIED) {
|
||||
denies.push('Camera');
|
||||
} else if (statuses[k_Camera] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Camera');
|
||||
}
|
||||
|
||||
if (statuses[k_StorageRead]=== RESULTS.DENIED) {
|
||||
denies.push('Read External Storage');
|
||||
} else if (statuses[k_StorageRead] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Read External Storage');
|
||||
}
|
||||
|
||||
if (statuses[k_Storage]=== RESULTS.DENIED) {
|
||||
denies.push('Photo Library');
|
||||
} else if (statuses[k_Storage] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Photo Library');
|
||||
}
|
||||
|
||||
if (statuses[k_Mic]=== RESULTS.DENIED) {
|
||||
denies.push('Record Audio');
|
||||
} else if (statuses[k_Mic] === RESULTS.UNAVAILABLE) {
|
||||
notavlbl.push('Record Audio');
|
||||
}
|
||||
}
|
||||
|
||||
let msg='';
|
||||
if(denies.length>0){
|
||||
msg+='User denied '+denies.join(', ')+(denies.length>1?' permissions':' permission');
|
||||
}
|
||||
if(notavlbl.length>0){
|
||||
msg+=msg!=''?', ':'';
|
||||
msg+=notavlbl.join(', ')+(notavlbl.length>1?' permissions':' permission')+' not available';
|
||||
}
|
||||
|
||||
if(denies.length>0 || notavlbl.length>0){
|
||||
notify(msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export const hasLocationPermission = async () => {
|
||||
if (Platform.OS === 'android' && Platform.Version < 21) {
|
||||
return true;
|
||||
}
|
||||
else if(Platform.OS === 'ios'){
|
||||
let status=await CheckAndAskForPermission(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
|
||||
return status;
|
||||
}
|
||||
else if(Platform.OS === 'android'){
|
||||
let status=await CheckAndAskForPermission(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
|
||||
return status;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export const hasCameraPermission = async () => {
|
||||
if (Platform.OS === 'android' && Platform.Version < 21) {
|
||||
return true;
|
||||
}
|
||||
else if(Platform.OS === 'ios'){
|
||||
let status=await CheckAndAskForPermission(PERMISSIONS.IOS.CAMERA);
|
||||
return status;
|
||||
}
|
||||
else if(Platform.OS === 'android'){
|
||||
let status=await CheckAndAskForPermission(PermissionsAndroid.PERMISSIONS.CAMERA);
|
||||
return status;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export const hasStoragePermission = async () => {
|
||||
if (Platform.OS === 'android' && Platform.Version < 21) {
|
||||
return true;
|
||||
}
|
||||
else if(Platform.OS === 'ios'){
|
||||
let status=await CheckAndAskForPermission(PERMISSIONS.IOS.PHOTO_LIBRARY);
|
||||
return status;
|
||||
}
|
||||
else if(Platform.OS === 'android'){
|
||||
let status=await CheckAndAskForPermission(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
|
||||
return status;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export const requestMultiplePerms = async () => {
|
||||
console.log('requestMultiplePerms');
|
||||
if (Platform.OS === 'android' && Platform.Version < 21) {
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
let OSPer=Platform.OS === 'ios'?PERMISSIONS.IOS:PERMISSIONS.ANDROID;
|
||||
let IOSPERMS=[OSPer.LOCATION_WHEN_IN_USE,OSPer.CAMERA,OSPer.PHOTO_LIBRARY,OSPer.MICROPHONE,OSPer.MEDIA_LIBRARY];
|
||||
let ANDROIDPERMS=[OSPer.ACCESS_FINE_LOCATION,OSPer.CAMERA,OSPer.READ_EXTERNAL_STORAGE,OSPer.WRITE_EXTERNAL_STORAGE,OSPer.RECORD_AUDIO];
|
||||
let allperms=Platform.OS === 'ios'?IOSPERMS:ANDROIDPERMS;
|
||||
let status=await CheckAndAskForMulitplePermissions(allperms);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const _checkLocationPermission = async () => {
|
||||
if(Platform.OS === 'android' && Platform.Version < 21){
|
||||
return true;
|
||||
}
|
||||
else if (Platform.OS === 'ios' ){
|
||||
let IOS_hasPermission = await Permissions.check(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
|
||||
let IOS_P=IOS_hasPermission==RESULTS.GRANTED?true:false;
|
||||
return IOS_P;
|
||||
}
|
||||
else if (Platform.OS === 'android') {
|
||||
const hasPermission = await PermissionsAndroid.check(
|
||||
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
|
||||
);
|
||||
|
||||
if (hasPermission) return true;
|
||||
|
||||
const granted = await PermissionsAndroid.request(
|
||||
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
|
||||
);
|
||||
|
||||
return granted === PermissionsAndroid.RESULTS.GRANTED;
|
||||
}
|
||||
else{return true;}
|
||||
}
|
||||
|
||||
export const _checkCameraPermission = async () => {
|
||||
if(Platform.OS === 'android' && Platform.Version < 21){
|
||||
return true;
|
||||
}
|
||||
else if (Platform.OS === 'ios' ){
|
||||
let IOS_hasPermission = await Permissions.check(PERMISSIONS.IOS.CAMERA);
|
||||
let IOS_P=IOS_hasPermission==RESULTS.GRANTED?true:false;
|
||||
return IOS_P;
|
||||
}
|
||||
else if(Platform.OS === 'android' ){
|
||||
const hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.CAMERA);
|
||||
return hasPermission;
|
||||
}
|
||||
else{return true;}
|
||||
}
|
||||
|
||||
export const _checkStoragePermission = async () => {
|
||||
if(Platform.OS === 'android' && Platform.Version < 21){
|
||||
return true;
|
||||
}
|
||||
else if (Platform.OS === 'ios' ){
|
||||
let IOS_hasPermission = await Permissions.check(PERMISSIONS.IOS.PHOTO_LIBRARY);
|
||||
let IOS_P=IOS_hasPermission==RESULTS.GRANTED?true:false;
|
||||
return IOS_P;
|
||||
}
|
||||
else if(Platform.OS === 'android' ){
|
||||
const hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
|
||||
return hasPermission;
|
||||
}
|
||||
else{return true;}
|
||||
}
|
||||
|
||||
export async function checkPermissions(){
|
||||
await hasLocationPermission();
|
||||
await hasCameraPermission();
|
||||
await hasStoragePermission();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import { Text, TouchableOpacity } from "react-native";
|
||||
import { customeButtons,GetPageTheme } from "../styles/Global";
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
|
||||
const GradientButton = (props) => {
|
||||
const route = useRoute();
|
||||
const PageTheme=GetPageTheme(props.DarkTheme,route.name);
|
||||
const customeButton=customeButtons(props.DarkMode,route.name);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.6}
|
||||
onPress={props.onPress}
|
||||
disabled={props.disabled!=null?props.disabled:false}
|
||||
style={[customeButton.g_buttonStyle]}>
|
||||
<LinearGradient colors={(props.colors!=null ? props.colors: [PageTheme.$secondary_color_light,PageTheme.$gradient2, PageTheme.$primary_color])} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={[customeButton.g_linearGradient,props.style!=null?props.style:{}]}>
|
||||
<Text style={customeButton.g_textStyle}>{props.title}</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
export default GradientButton;
|
||||
@@ -0,0 +1,49 @@
|
||||
import MaterialCommunityIconsI from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import SimpleLineIconsI from 'react-native-vector-icons/SimpleLineIcons'
|
||||
import AntDesignI from 'react-native-vector-icons/AntDesign'
|
||||
import MaterialIconsI from 'react-native-vector-icons/MaterialIcons'
|
||||
import FontAwesomeI from 'react-native-vector-icons/FontAwesome'
|
||||
import FontAwesome5I from 'react-native-vector-icons/FontAwesome5';
|
||||
import FoundationI from 'react-native-vector-icons/Foundation'
|
||||
import EvilIconsI from 'react-native-vector-icons/EvilIcons'
|
||||
import OcticonsI from 'react-native-vector-icons/Octicons'
|
||||
import IoniconsI from 'react-native-vector-icons/Ionicons'
|
||||
import FeatherI from 'react-native-vector-icons/Feather'
|
||||
import EntypoI from 'react-native-vector-icons/Entypo'
|
||||
import ZocialI from 'react-native-vector-icons/Zocial'
|
||||
import FontistoI from 'react-native-vector-icons/Fontisto'
|
||||
import React from 'react'
|
||||
|
||||
export const MaterialCommunityIcons = props => (
|
||||
<MaterialCommunityIconsI {...props} />
|
||||
)
|
||||
const SimpleLineIcons = props => <SimpleLineIconsI {...props} />
|
||||
const MaterialIcons = props => <MaterialIconsI {...props} />
|
||||
const AntDesign = props => <AntDesignI {...props} />
|
||||
const FontAwesome = props => <FontAwesomeI {...props} />
|
||||
const FontAwesome5 = props => <FontAwesome5I {...props} />
|
||||
const Foundation = props => <FoundationI {...props} />
|
||||
const EvilIcons = props => <EvilIconsI {...props} />
|
||||
const Ionicons = props => <IoniconsI {...props} />
|
||||
const Octicons = props => <OcticonsI {...props} />
|
||||
const Feather = props => <FeatherI {...props} />
|
||||
const Entypo = props => <EntypoI {...props} />
|
||||
const Zocial = props => <ZocialI {...props} />
|
||||
const Fontisto = props => <FontistoI {...props} />
|
||||
|
||||
export {
|
||||
SimpleLineIcons,
|
||||
MaterialIcons,
|
||||
FontAwesome,
|
||||
FontAwesome5,
|
||||
Foundation,
|
||||
AntDesign,
|
||||
EvilIcons,
|
||||
Ionicons,
|
||||
Fontisto,
|
||||
Octicons,
|
||||
Feather,
|
||||
Entypo,
|
||||
Zocial,
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// import * as Keychain from 'react-native-keychain';
|
||||
|
||||
// const OPTIONS = {
|
||||
// accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
|
||||
// securityLevel: Keychain.SECURITY_LEVEL.ANY, // 🔥 critical fix
|
||||
// storage: Keychain.STORAGE_TYPE.AES, // 🔥 avoids keystore issues
|
||||
// };
|
||||
|
||||
|
||||
// export const set_item = async (key, data) => {
|
||||
// if (key && data) {
|
||||
// try {
|
||||
// await Keychain.setInternetCredentials(
|
||||
// key,
|
||||
// key,
|
||||
// data,
|
||||
// OPTIONS // 👈 FIX
|
||||
// );
|
||||
// } catch (err) {
|
||||
// console.log('Cannot save:', key, err);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
// export const get_item = async (key) => {
|
||||
// try {
|
||||
// const creds = await Keychain.getInternetCredentials(key);
|
||||
// return creds ? creds.password : null;
|
||||
// } catch (err) {
|
||||
// console.log('Cannot get:', key, err);
|
||||
// return null;
|
||||
// }
|
||||
// };
|
||||
|
||||
// export const clear_item = async (key) => {
|
||||
// try {
|
||||
// await Keychain.resetInternetCredentials({
|
||||
// server: key, // 👈 yaha object dena zaroori hai
|
||||
// });
|
||||
// console.log('Credentials reset for:', key);
|
||||
// } catch (err) {
|
||||
// console.log('Cannot reset:', key, err);
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
// export const clear_all = async () => {
|
||||
// // Retrieve the credentials
|
||||
// const allkeys = await Keychain.getAllGenericPasswordServices();
|
||||
// console.log(allkeys);
|
||||
// }
|
||||
|
||||
import { createMMKV } from 'react-native-mmkv'
|
||||
|
||||
export const storage = createMMKV({
|
||||
id: `user-storage`,
|
||||
encryptionKey: 'hunter2',
|
||||
encryptionType: 'AES-256',
|
||||
mode: 'multi-process',
|
||||
readOnly: false,
|
||||
compareBeforeSet: false,
|
||||
})
|
||||
|
||||
/**
|
||||
* Save item
|
||||
* @param {string} key
|
||||
* @param {any} data
|
||||
*/
|
||||
export const set_item = async (key, data) => {
|
||||
try {
|
||||
if (!key) return;
|
||||
|
||||
// Convert non-string data to JSON
|
||||
const value =
|
||||
typeof data === 'string' ? data : JSON.stringify(data);
|
||||
|
||||
storage.set(key, value);
|
||||
//console.log("set_data",key,value)
|
||||
} catch (err) {
|
||||
console.log('❌ Cannot save:', key, err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get item
|
||||
* @param {string} key
|
||||
* @returns {any}
|
||||
*/
|
||||
export const get_item = async (key) => {
|
||||
try {
|
||||
if (!key) return null;
|
||||
|
||||
const value = storage.getString(key);
|
||||
|
||||
if (value === undefined) return null;
|
||||
|
||||
// Try parsing JSON
|
||||
try {
|
||||
return (value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('❌ Cannot get:', key, err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete single item
|
||||
* @param {string} key
|
||||
*/
|
||||
export const clear_item = async (key) => {
|
||||
try {
|
||||
if (!key) return;
|
||||
|
||||
storage.remove(key);
|
||||
console.log('✅ Deleted:', key);
|
||||
} catch (err) {
|
||||
console.log('❌ Cannot delete:', key, err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear all storage
|
||||
*/
|
||||
export const clear_all = async () => {
|
||||
try {
|
||||
storage.clearAll();
|
||||
console.log('✅ All storage cleared');
|
||||
} catch (err) {
|
||||
console.log('❌ Cannot clear all:', err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all keys (extra utility)
|
||||
*/
|
||||
export const get_all_keys = () => {
|
||||
try {
|
||||
return storage.getAllKeys();
|
||||
} catch (err) {
|
||||
console.log('❌ Cannot get keys:', err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if key exists (extra utility)
|
||||
*/
|
||||
export const has_key = (key) => {
|
||||
try {
|
||||
return storage.contains(key);
|
||||
} catch (err) {
|
||||
console.log('❌ Cannot check key:', key, err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
import {get_item,set_item,clear_item} from '../components/localStorage';
|
||||
import { mapStateToProps,mapDispatchToProps } from '../reducers/contextProvider';
|
||||
import { connect} from 'react-redux';
|
||||
import {BackHandler} from 'react-native';
|
||||
import RNExitApp from 'react-native-exit-app';
|
||||
|
||||
export async function logout(props){
|
||||
|
||||
const pdata={islogin:false,SecurityToken:''};
|
||||
RNExitApp.exitApp();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import {Platform,ToastAndroid,Text} from 'react-native';
|
||||
// import {Snackbar} from 'react-native-paper';
|
||||
import Snackbar from 'react-native-snackbar';
|
||||
|
||||
export const notify = (message='',type='SHORT') => {
|
||||
if (Platform.OS != 'android') {
|
||||
Snackbar.show({
|
||||
text:message,
|
||||
duration: Snackbar.LENGTH_SHORT,//(type=='SHORT'?Snackbar.LENGTH_SHORT:Snackbar.LENGTH_LONG),
|
||||
});
|
||||
} else {
|
||||
const toast_time=ToastAndroid.SHORT;//type=='SHORT'?ToastAndroid.SHORT:ToastAndroid.LONG;
|
||||
ToastAndroid.show(message, toast_time);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user