first commit

This commit is contained in:
NishantRajputRN
2026-04-16 15:23:13 +05:30
commit aa56e08ffd
523 changed files with 229267 additions and 0 deletions
@@ -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",
},
});
+306
View File
@@ -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}>
Im 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
},
});
+641
View File
@@ -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;
}
}
+284
View File
@@ -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;
+3
View File
@@ -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;
+107
View File
@@ -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;
+127
View File
@@ -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>
);
}
+63
View File
@@ -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();} }
]
);
}
+64
View File
@@ -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",
},
})
+30
View File
@@ -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;
}
+255
View File
@@ -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;
+49
View File
@@ -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;
}
};
+13
View File
@@ -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();
}
+16
View File
@@ -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);
}
}