Commit 6efbfc0e by tungnq

TODO: CodeBase

parent b2e1fac1
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
.yarn
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/
/ios/Podfile.lock
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, {useEffect} from 'react';
import {View, Text} from 'react-native';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import rootReducer from './src/reducers/index';
import RootView from './src/RootView';
import createSagaMiddleware from 'redux-saga';
import rootSaga from './src/saga/rootSaga';
// import FirebaseNotification from "./src/helper/FirebaseNotification";
import SplashScreen from 'react-native-splash-screen';
const sagaMiddleware = createSagaMiddleware();
let store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
const App = () => {
// useEffect(async () => {
// SplashScreen.hide();
// }, []);
return (
<Provider store={store}>
<RootView />
</Provider>
);
};
export default App;
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React from 'react';
import type {PropsWithChildren} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
type SectionProps = PropsWithChildren<{
title: string;
}>;
function Section({children, title}: SectionProps): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: isDarkMode ? Colors.white : Colors.black,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: isDarkMode ? Colors.light : Colors.dark,
},
]}>
{children}
</Text>
</View>
);
}
function App(): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={backgroundStyle.backgroundColor}
/>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<Header />
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
}}>
<Section title="Step One">
Edit <Text style={styles.highlight}>App.tsx</Text> to change this
screen and then come back to see your edits.
</Section>
<Section title="See Your Changes">
<ReloadInstructions />
</Section>
<Section title="Debug">
<DebugInstructions />
</Section>
<Section title="Learn More">
Read the docs to discover what to do next:
</Section>
<LearnMoreLinks />
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
});
export default App;
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
......@@ -10,8 +10,66 @@
"test": "jest"
},
"dependencies": {
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/checkbox": "^0.5.9",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/netinfo": "^7.1.7",
"@react-native-community/picker": "^1.8.1",
"@react-native-community/slider": "^4.1.12",
"@react-navigation/bottom-tabs": "^6.0.9",
"@react-navigation/material-top-tabs": "^6.0.6",
"@react-navigation/native": "^6.0.6",
"@react-navigation/stack": "^6.0.11",
"async": "^3.2.3",
"axios": "0.21.4",
"js-sha256": "^0.9.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"react": "18.2.0",
"react-native": "0.74.2"
"react-hook-form": "^7.24.2",
"react-native": "0.74.2",
"react-native-autocomplete-input": "^5.0.2",
"react-native-calendars": "^1.1260.0",
"react-native-confirmation-code-field": "^7.1.0",
"react-native-datepicker": "^1.7.2",
"react-native-device-info": "^8.1.7",
"react-native-dropdown-picker": "^5.1.23",
"react-native-dropdownalert": "^4.3.0",
"react-native-elements": "^3.4.1",
"react-native-gesture-handler": "^1.10.3",
"react-native-gifted-charts": "^1.2.41",
"react-native-i18n": "^2.0.15",
"react-native-image-crop-picker": "^0.36.2",
"react-native-indicators": "^0.17.0",
"react-native-linear-gradient": "^2.6.2",
"react-native-material-textfield": "^0.16.1",
"react-native-modal": "^12.0.2",
"react-native-modal-dropdown": "^1.0.1",
"react-native-pager-view": "^5.4.0",
"react-native-permissions": "^3.6.1",
"react-native-progress": "^5.0.0",
"react-native-qrcode-scanner": "^1.5.5",
"react-native-reanimated": "^3.12.1",
"react-native-rename": "^2.9.0",
"react-native-render-html": "^6.1.0",
"react-native-responsive-fontsize": "^0.5.1",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.1.1",
"react-native-share": "^7.0.0",
"react-native-simple-radio-button": "^2.7.4",
"react-native-sound": "^0.11.1",
"react-native-splash-screen": "^3.2.0",
"react-native-svg": "12.1.1",
"react-native-svg-charts": "^5.4.0",
"react-native-swipe-list-view": "2.5.0",
"react-native-swiper": "^1.6.0",
"react-native-tab-view": "^3.0.1",
"react-native-touch-id": "^4.4.1",
"react-native-vector-icons": "^8.1.0",
"react-native-webview": "^13.12.2",
"react-redux": "^7.2.4",
"redux": "^4.1.0",
"redux-saga": "^1.1.3"
},
"devDependencies": {
"@babel/core": "^7.20.0",
......
import React, {useEffect, useRef, useState} from 'react';
import StackNavigation from './routers/StackNavigation';
import {connect} from 'react-redux';
import DropdownAlert from 'react-native-dropdownalert';
import DropdownManager from './components/DropdownAlert/DropdownManager';
import R from './assets/R';
import {HEIGHTXD, WIDTHXD} from './config/Functions';
import {SkypeIndicator} from 'react-native-indicators';
import Modal from 'react-native-modal';
import {saveUserToRedux} from './actions/users';
import I18n, {setLocation} from './helper/i18/i18n';
import KEY from './assets/AsynStorage';
import {changeLanguage} from './actions/language';
import AsyncStorage from '@react-native-community/async-storage';
import NoInternetComponent from './components/NoInternet';
const RootView = props => {
useEffect(() => {
setInitLanguage();
DropdownManager.register(
dropDownAlertRef.current,
dropDownAlertLongTimeRef.current,
);
}, []);
const dropDownAlertRef = useRef(null);
const dropDownAlertLongTimeRef = useRef(null);
const setInitLanguage = async () => {
// const laguage = await AsyncStorage.getItem(KEY.LANGUAGE);
const laguage = 'vi';
if (laguage) props.changeLanguage(laguage);
setLocation(I18n, laguage);
};
return (
<>
<StackNavigation isLoggedIn={props.isLoggedIn} />
<Modal isVisible={props.loadingModal.isVisible}>
<SkypeIndicator color={'white'} />
</Modal>
<DropdownAlert
inactiveStatusBarBackgroundColor={R.colors.main}
activeStatusBarBackgroundColor={R.colors.main}
warnImageSrc={R.images.iconWarn}
successImageSrc={R.images.iconSuccess}
errorImageSrc={R.images.iconError}
titleStyle={{color: '#fff'}}
messageStyle={{color: '#fff'}}
updateStatusBar={false}
closeInterval={1000}
ref={dropDownAlertRef}
warnColor={R.colors.orange400}
defaultContainer={{
borderBottomRightRadius: WIDTHXD(30),
borderBottomLeftRadius: WIDTHXD(30),
paddingTop: HEIGHTXD(30),
paddingVertical: HEIGHTXD(30),
paddingHorizontal: WIDTHXD(20),
}}
/>
<DropdownAlert
updateStatusBar={false}
inactiveStatusBarBackgroundColor={R.colors.colorMain}
activeStatusBarBackgroundColor={R.colors.colorMain}
warnImageSrc={R.images.iconWarn}
successImageSrc={R.images.iconSuccess}
errorImageSrc={R.images.iconError}
titleStyle={{color: '#fff'}}
messageStyle={{color: '#fff'}}
closeInterval={600000}
ref={dropDownAlertLongTimeRef}
warnColor={R.colors.orange400}
defaultContainer={{
borderBottomRightRadius: WIDTHXD(30),
borderBottomLeftRadius: WIDTHXD(30),
paddingTop: HEIGHTXD(30),
paddingVertical: HEIGHTXD(30),
paddingHorizontal: WIDTHXD(20),
}}
/>
<NoInternetComponent />
</>
);
};
const mapStateToProps = state => {
return {
loadingModal: state.ModalLoadingReducer,
};
};
export default connect(mapStateToProps, {
saveUserToRedux,
changeLanguage,
})(RootView);
import {
UPDATE_NOTIFICATION
} from './actionTypes';
export const updateNotification = () => {
return {
type: UPDATE_NOTIFICATION,
};
};
import {
UPDATE_REPORT
} from './actionTypes';
export const updateReport = () => {
return {
type: UPDATE_REPORT,
};
};
import {NEW_SCREEN} from './actionTypes';
export const newScreenInit = (body) => {
return {
type: NEW_SCREEN,
body,
};
};
import {PUSHNOTI, HIDENOTI} from './actionTypes';
export const showNotificaton = (data) => {
return {
type: PUSHNOTI,
data,
};
};
export const hideNotification = () => {
return {
type: HIDENOTI,
};
};
import { UPDATE_SYSTEM_CONFIG } from "./actionTypes";
export function updateSystemConfig(data) {
return {
type: UPDATE_SYSTEM_CONFIG,
data,
};
}
export const UPDATE_USER_INFO = "UPDATE_USER_INFO";
export const UPDATE_USER_SUCCESS = "UPDATE_USER_SUCCESS";
export const UPDATE_USER_DATA = "UPDATE_USER_DATA";
export const LOGIN = "LOGIN";
export const UPDATE_INFOR = "UPDATE_INFOR";
export const SHOWLOADING = "SHOWLOADING";
export const HIDELOADING = "HIDELOADING";
export const PUSHNOTI = "PUSHNOTI";
export const HIDENOTI = "HIDENOTI";
export const UPDATE_NOTIFICATION = "UPDATE_NOTIFICATION";
export const UPDATE_NOTIFICATION_SUCCESSED = "UPDATE_NOTIFICATION_SUCCESSED";
export const UPDATE_NOTIFICATION_FAIL = "UPDATE_NOTIeFICATION_FAIL";
export const UPDATE_REPORT_SUCCESSED = "UPDATE_REPORT_SUCCESSED";
export const UPDATE_REPORT = "UPDATE_REPORT";
export const SAVENAVIGATE = "SAVENAVIGATE";
export const NEW_SCREEN = "NEW_SCREEN";
export const CLEAR_SCREEN = "CLEAR_SCREEN";
export const CHANGE_LANGUAGE = "CHANGE_LANGUAGE";
export const WALLET_INFO = "WALLET_INFO";
export const UPDATE_WALLET = "UPDATE_WALLET";
export const UPDATE_WALLET_SUCCESS = "UPDATE_WALLET_SUCCESS";
export const UPDATE_SYSTEM_CONFIG = "UPDATE_SYSTEM_CONFIG";
export const ADD_PRODUCT = "ADD_PRODUCT";
export const REMOVE_PRODUCT = "REMOVE_PRODUCT";
export const CLEAR_CART = "CLEAR_CART";
import { REMOVE_PRODUCT, ADD_PRODUCT, CLEAR_CART } from "./actionTypes";
export const addProduct = (item) => {
return {
type: ADD_PRODUCT,
data: item,
};
};
export const removeProduct = (id) => {
return {
type: REMOVE_PRODUCT,
data: id,
};
};
export const clearCart = () => {
return {
type: CLEAR_CART,
};
};
import { CHANGE_LANGUAGE } from "./actionTypes";
export const changeLanguage = (language) => {
return {
type: CHANGE_LANGUAGE,
language,
};
};
import {
SHOWLOADING,
HIDELOADING
} from './actionTypes';
export const showLoading = () => {
return {
type: SHOWLOADING,
};
};
export const hideLoading = () => {
return {
type: HIDELOADING
};
};
import { LOGIN, WALLET_INFO, UPDATE_INFOR } from "./actionTypes";
export function saveUserToRedux(data) {
return {
type: LOGIN,
data,
};
}
export function saveWalletInfo(data) {
return {
type: WALLET_INFO,
data,
};
}
export function updateUser() {
return {
type: UPDATE_INFOR,
};
}
import { UPDATE_WALLET } from "./actionTypes";
export function updateWalletInfo() {
return {
type: UPDATE_WALLET,
};
}
import {PostLogin, PostData, GetData, PostFormData} from '../helpers';
import url from '../url';
export const listProvince = async params =>
GetData(url.listProvince, params)
.then(res => res)
.catch(err => err);
export const dropdownBank = async params =>
GetData(url.dropdownBank, params)
.then(res => res)
.catch(err => err);
export const dropdownBankCredit = async params =>
GetData(url.dropdownBankCredit, params)
.then(res => res)
.catch(err => err);
export const dropdownCreditType = async id =>
GetData(`${url.dropdownCreditType}/${id}`, {})
.then(res => res)
.catch(err => err);
import {
PostLogin,
PostData,
GetData,
PostFormData,
PostHaveKey,
} from '../helpers';
import url from '../url';
export const getInforGeneral = async params =>
GetData(url.getInforGeneral, params)
.then(res => res)
.catch(err => err);
export const getListInvestPackage = async params =>
GetData(url.getListInvestPackage, params)
.then(res => res)
.catch(err => err);
export const getConfigPoint = async params =>
GetData(url.getConfigPoint, params)
.then(res => res)
.catch(err => err);
export const changePoint = async params =>
PostData(url.changePoint, params)
.then(res => res)
.catch(err => err);
export const getListNoti = async params =>
PostData(url.getListNoti, params)
.then(res => res)
.catch(err => err);
export const detailNoti = async id =>
GetData(`${url.detailNoti}/${id}`, {})
.then(res => res)
.catch(err => err);
export const decryptData = async (body, key) =>
PostHaveKey(url.urlDecryptData, body, key)
.then(res => res)
.catch(err => null);
export const getKey = async body =>
GetData(url.getKey, body)
.then(res => res)
.catch(err => null);
export const listRanking = async params =>
GetData(url.listRanking, params)
.then(res => res)
.catch(err => err);
export const detailRanking = async id =>
GetData(`${url.detailRanking}/${id}`, {})
.then(res => res)
.catch(err => err);
export const getNewestVersionInfo = async id =>
GetData(`${url.getNewestVersionInfo}/${id}`, {})
.then(res => res)
.catch(err => err);
export const listBannerAPI = async params =>
PostData(url.listBanner, params)
.then(res => res)
.catch(err => err);
export const getInforSetting = async params =>
GetData(url.inforSetting, params)
.then(res => res)
.catch(err => err);
export const changeSetting = async params =>
PostData(url.changeSetting, params)
.then(res => res)
.catch(err => err);
export const systemConfig = async params =>
GetData(url.systemConfig, params)
.then(res => res)
.catch(err => err);
import {PostLogin, PostData, GetData, PostFormData} from '../helpers';
import url from '../url';
export const checkPhoneNumber = async params =>
PostLogin(url.checkPhoneNumber, params)
.then(res => res)
.catch(err => err);
export const verifyOTP = async params =>
PostLogin(url.verifyOTP, params)
.then(res => res)
.catch(err => err);
export const signUp = async body =>
PostLogin(url.signUp, body)
.then(res => res)
.catch(err => err);
export const login = async body =>
PostData(url.login, body)
.then(res => res)
.catch(err => err);
export const requestSendOTP = async body =>
PostData(url.urlrequestSendOTP, body)
.then(res => res)
.catch(err => err);
export const confirmOTP = async body =>
PostData(url.urlConfirmOTP, body)
.then(res => res)
.catch(err => err);
export const uploadFontIdentify = async body =>
PostFormData(url.urlFontIdentify, body)
.then(res => res)
.catch(err => err);
export const uploadBackIdentify = async body =>
PostFormData(url.urlBackIdentify, body)
.then(res => res)
.catch(err => err);
export const verifyCustomer = async body =>
PostData(url.verifyCustomer, body)
.then(res => res)
.catch(err => err);
export const logoutAPI = async body =>
PostData(url.logout, body)
.then(res => res)
.catch(err => err);
export const changePass = async body =>
PostData(url.changePass, body)
.then(res => res)
.catch(err => err);
export const myTeam = async body =>
PostData(url.myTeam, body)
.then(res => res)
.catch(err => err);
export const sendCodeChangePass = async param =>
GetData(url.sendCodeChangePass, param)
.then(res => res)
.catch(err => err);
//Secretcode
export const createSecretCode = async body =>
PostData(url.createSecretCode, body)
.then(res => res)
.catch(err => err);
export const updateSecretCode = async body =>
PostData(url.updateSecretCode, body)
.then(res => res)
.catch(err => err);
export const sendCodeForgetSecretKey = async params =>
GetData(url.sendCodeSecret, params)
.then(res => res)
.catch(err => err);
export const renewSecret = async body =>
PostData(url.renewSecret, body)
.then(res => res)
.catch(err => err);
export const getTeams = async body =>
PostData(url.renewSecret, body)
.then(res => res)
.catch(err => err);
export const myContractAPI = async params =>
GetData(url.myContract, params)
.then(res => res)
.catch(err => err);
export const reportCustomer = async body =>
PostData(url.reportCustomer, body)
.then(res => res)
.catch(err => err);
export const changePhone = async body =>
PostData(url.changePhone, body)
.then(res => res)
.catch(err => err);
export const sendOTPChangePhone = async body =>
PostData(url.sendOTPChangePhone, body)
.then(res => res)
.catch(err => err);
export const updateUserInfo = async body =>
PostData(url.updateCusInfor, body)
.then(res => res)
.catch(err => err);
export const changeAvatart = async body =>
PostData(url.changeAvatart, body)
.then(res => res)
.catch(err => err);
export const sendCodeForgetPassword = async body =>
PostData(url.sendCodeForgetPassword, body)
.then(res => res)
.catch(err => err);
export const updateCusForgetPassword = async body =>
PostData(url.updateCusForgetPassword, body)
.then(res => res)
.catch(err => err);
//Previous
export const getUserInfo = async param =>
GetData(url.getUserInfo, param)
.then(res => res)
.catch(err => err);
export const getProvinceList = async () =>
PostData(url.getProvinceList, {addressLevel: 1})
.then(res => res)
.catch(err => err);
export const getMyTeam = async params =>
PostData(url.myTeam, params)
.then(res => res)
.catch(err => err);
export const uploadAvatarAPI = async body =>
PostFormData(url.uploadAvatar, body)
.then(res => res)
.catch(err => err);
import {GetData, PostData} from '../helpers';
import url from '../url';
export const getWalletInfo = async params =>
GetData(url.getWalletInfo, params)
.then(res => res)
.catch(err => err);
export const depositsRequest = async params =>
PostData(url.depositsRequest, params)
.then(res => res)
.catch(err => err);
export const withdrawRequest = async params =>
PostData(url.withdrawRequest, params)
.then(res => res)
.catch(err => err);
export const getListTrans = async params =>
PostData(url.getListTrans, params)
.then(res => res)
.catch(err => err);
export const detailTrans = async id =>
GetData(`${url.detailTrans}/${id}`, {})
.then(res => res)
.catch(err => err);
export const inforBankTrans = async params =>
GetData(url.inforBankTrans, params)
.then(res => res)
.catch(err => err);
import KEY from '../assets/AsynStorage';
import axios from 'axios';
import AsyncStorage from '@react-native-community/async-storage';
import {DeviceEventEmitter} from 'react-native';
import {DEVICE_EVENT_KEY} from '../config/constants';
const API_KEY =
'eue823478uwuishdsfhjsd8939827389273897987wr837r98we7r8w9erwer7w9er7we8rw98er7';
axios.defaults.timeout = 10000;
export async function GetData(url, data) {
const token = await AsyncStorage.getItem(KEY.TOKEN);
let myRequest = {
method: 'get',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token,
'x-api-key': API_KEY,
},
params: {
...data,
},
timeout: 30 * 1000,
// withCredentials: true,
};
console.log('My request', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
console.log(error);
if (error.request.status === 403 || error.request.status === 401) {
DeviceEventEmitter.emit(DEVICE_EVENT_KEY.LOGOUT_EVENT);
} else {
const data = JSON.parse(error.request._response);
const err = {
message: data.message
? data.message
: 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
}
});
}
export async function PostLogin(url, json) {
let myRequest = {
method: 'post',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'x-api-key': API_KEY,
},
timeout: 30 * 1000,
data: JSON.stringify(json),
};
console.log('post data mobile', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
console.log('error', error);
const err = {
message: data.message ? data.message : 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
});
}
export async function PostData(url, json, data) {
const token = await AsyncStorage.getItem(KEY.TOKEN);
let myRequest = {
method: 'post',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token,
'x-api-key': API_KEY,
},
timeout: 30 * 1000,
data: JSON.stringify(json),
params: {
...data,
},
};
console.log('post data mobile', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
if (error.request.status === 401) {
DeviceEventEmitter.emit(DEVICE_EVENT_KEY.LOGOUT_EVENT);
} else {
const data = JSON.parse(error.request._response);
const err = {
message: data.message
? data.message
: 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
}
});
}
export async function PostFormData(url, data) {
const token = await AsyncStorage.getItem(KEY.TOKEN);
let myRequest = {
method: 'post',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + token,
'x-api-key': API_KEY,
},
timeout: 30 * 1000,
data: data,
};
console.log('post data mobile', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
if (error.request.status === 401) {
DeviceEventEmitter.emit(DEVICE_EVENT_KEY.LOGOUT_EVENT);
} else {
const data = JSON.parse(error.request._response);
const err = {
message: data.message
? data.message
: 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
}
});
}
/**
*
* @param {*} url is link api
* @param {*} json is input format json to request server
* @param {*} isAuth is state auth
*/
export async function PutData(url, json, param) {
const token = await AsyncStorage.getItem(KEY.TOKEN);
let myRequest = {
method: 'put',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token,
'x-api-key': API_KEY,
},
data: JSON.stringify(json),
params: {
...param,
},
};
console.log('PutData', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
if (error.request.status === 401) {
DeviceEventEmitter.emit(DEVICE_EVENT_KEY.LOGOUT_EVENT);
} else {
const data = JSON.parse(error.request._response);
const err = {
message: data.message
? data.message
: 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
}
});
}
/**
*
* @param {*} url is link api
* @param {*} json is input format json to request server
* @param {*} isAuth is state auth
*/
export async function DeleteData(url, json, param) {
const token = await AsyncStorage.getItem(KEY.TOKEN);
let myRequest = {
method: 'delete',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token,
'x-api-key': API_KEY,
},
data: JSON.stringify(json),
params: {
...param,
},
};
console.log('DeleteData', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
if (error.request.status === 401) {
DeviceEventEmitter.emit(DEVICE_EVENT_KEY.LOGOUT_EVENT);
} else {
const data = JSON.parse(error.request._response);
const err = {
message: data.message
? data.message
: 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
}
});
}
export async function GetDataCommon(url, data) {
let myRequest = {
method: 'get',
url,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
params: {
...data,
},
timeout: 30 * 1000,
};
console.log('My request', myRequest);
return await axios(myRequest)
.then(response => response)
.then(response => response)
.catch(error => {
console.log('error', error);
if (error.request.status === 403 || error.request.status === 401) {
DeviceEventEmitter.emit(DEVICE_EVENT_KEY.LOGOUT_EVENT);
} else {
const data = JSON.parse(error.request._response);
const err = {
message: data.message
? data.message
: 'Có lỗi trong qúa trình xử lý!',
status: error.request.status,
};
return err;
}
});
}
export * from './helpers';
export * from './Status';
export * from './url';
export const root = 'https://apigw.dcvfinance.com/api/';
export default {
// user
checkPhoneNumber: `${root}app/auth/checkPhone`,
verifyOTP: `${root}app/auth/checkOtp`,
signUp: `${root}app/auth/loginNewUser`,
login: `${root}app/auth/login`,
logout: `${root}app/auth/logout`,
};
const KEY = {
TOKEN: '@TOKEN',
FIREBASE: '@Firebase',
ACCOUNT: '@ACCOUNT',
LANGUAGE: '@LANGUAGE',
TODOLIST: '@TODOLIST',
};
export default KEY;
import images from './images';
import colors from './colors';
import fonts from './fonts';
import fontsize from './fontsize';
const R = {
images,
colors,
fonts,
fontsize,
};
export default R;
const colors = {
main: '#00139B',
txtMain: '#006938',
label: '#5D5D5D',
color777: '#777777',
colorMainLight: '#5173B1',
colorBackground: '#E2E8F2',
borderGray: '#bbc2ce',
borderGraym: '#c9cfd9',
placeHolder: '#8D8D8D',
backgrPicker: '#E2E8F2',
dollar: '#07BA00',
colorBg: '#E8E8E8',
accent: '#A60014',
primary: '#0AC4BA',
secondary: '#00b33c',
black: '#000000',
white: '#FFFFFF',
orange: '#Fb9736',
lightBlue: '#1a8cff',
lightBlue1: '#008ae6',
lightBlue2: '#22AEFB',
rgbaBtn: '#79F8B5',
yellow: '#e6e600',
red: '#E3434F',
bgMain: '#9EF8C9',
colorButton1: '#43D75B',
colorTextLine: '#FFA412',
colorBgScreen: '#F7F8FA',
colorBgInputText: '#F2F2F2',
};
export default colors;
const fonts = {
RobotoThin: 'Roboto-Thin',
RobotoThinItalic: 'Roboto-ThinItalic',
RobotoItalic: 'Roboto-Italic',
RobotoBlack: 'Roboto-Black',
RobotoBlackItalic: 'Roboto-BlackItalic',
RobotoBold: 'Roboto-Bold',
RobotoBoldItalic: 'Roboto-BoldItalic',
RobotoLight: 'Roboto-Light',
RobotoLightItalic: 'Roboto-LightItalic',
RobotoMedium: 'Roboto-Medium',
RobotoMediumItalic: 'Roboto-MediumItalic',
RobotoRegular: 'Roboto-Regular',
MontserratRegular: 'Montserrat-Regular',
MontserratMedium: 'Montserrat-Medium',
MontserratSemiBold: 'Montserrat-SemiBold',
MontserratItalic: 'Montserrat-Italic',
MontserratMediumItalic: 'Montserrat-MediumItalic',
MontserratSemiBoldItalic: 'Montserrat-SemiBoldItalic',
};
export default fonts;
const fontsize = {
fontSizeLabel: 14,
fontSizeContent: 14,
fontSizeInputText: 16,
};
export default fontsize;
const images = {
iconWarn: require('./images/iconWarn.png'),
iconSuccess: require('./images/iconSuccess.png'),
iconError: require('./images/iconError.png'),
iconCamera: require('./images/iconCamera.png'),
icHome: require('./images/icHome.png'),
icAccount: require('./images/icAccount.png'),
bg_cannot_connect: require('./images/bg_cannot_connect.png'),
icGallery: require('./images/icGallery.png'),
};
export default images;
const sizes = {
// global sizes
small: 5,
base: 16,
font: 14,
radius: 6,
padding: 25,
// font sizes
big: 34,
h1: 26,
h2: 20,
h3: 18,
title: 16,
body: 14,
caption: 12,
};
export default sizes;
import sizes from './sizes';
import colors from './colors';
export {sizes, colors};
import {Alert} from 'react-native';
import I18n from '../helper/i18/i18n';
export const NotificationAlert = (string) => {
Alert.alert(I18n.t('Notification'), string);
};
export const confirmAlert = (content, callback) => {
Alert.alert(
I18n.t('Notification'),
content,
[
{
text: I18n.t('Cancel'),
style: 'cancel',
},
{
text: I18n.t('Ok'),
onPress: () => {
callback();
},
},
],
{cancelable: false},
);
};
import React, {PureComponent} from 'react';
import {Text} from 'react-native';
import {connect} from 'react-redux';
import I18n from '../helper/i18/i18n';
class AppText extends React.Component {
constructor(props) {
super(props);
this.state = {
i18n: I18n,
};
}
componentWillMount() {
const {language} = this.props;
if (language) this.setMainLocaleLanguage(language);
}
componentWillReceiveProps = (nextProps) => {
const {language} = nextProps;
if (language) this.setMainLocaleLanguage(language);
};
setMainLocaleLanguage = (language) => {
let i18n = this.state.i18n;
i18n.locale = language;
this.setState({i18n});
};
render() {
const {i18nKey, style} = this.props;
const {i18n} = this.state;
return (
<Text style={style}>
{i18nKey ? i18n.t(i18nKey) : this.props.children}
</Text>
);
}
}
const mapStateToProps = (state) => {
return {
language: state.languageReducer.language,
};
};
export default connect(mapStateToProps, null)(AppText);
import React, {Component} from 'react';
import {
StyleSheet,
TouchableOpacity,
View,
Text,
ImageBackground,
} from 'react-native';
import R from '../assets/R';
import {colors, sizes} from '../assets/theme';
import {
getFontSize,
getFontXD,
getWidth,
HEIGHT,
WIDTH,
} from '../config/Functions';
const Button = props => {
const {title, onPress, containerStyle, txtStyle, backgroundColor} = props;
return (
<TouchableOpacity
style={[
{
height: HEIGHT(40),
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F2B60D',
marginHorizontal: WIDTH(15),
borderRadius: HEIGHT(6),
marginTop: HEIGHT(30),
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.22,
shadowRadius: 2.22,
elevation: 3,
},
{...containerStyle},
]}
disabled={props.disabled}
onPress={onPress}>
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<Text
style={[
{
fontSize: getFontSize(18),
color: R.colors.white,
fontWeight: 'bold',
},
{...txtStyle},
]}>
{title}
</Text>
</View>
</TouchableOpacity>
);
};
export default Button;
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TouchableOpacity,
Linking,
} from 'react-native';
import QRCodeScanner from 'react-native-qrcode-scanner';
import {RNCamera} from 'react-native-camera';
const ScanScreen = props => {
const onSuccess = e => {
console.log(e.data);
};
return (
<QRCodeScanner
onRead={onSuccess}
topContent={<Text style={styles.centerText}>Quét QR</Text>}
/>
);
};
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 ScanScreen;
class DropdownManager {
_defaultDropdown = null;
_defaultDropdownLongTime = null;
register(_ref, _refLongTime) {
if (!this._defaultDropdown) {
this._defaultDropdown = _ref;
}
if (!this._defaultDropdownLongTime) {
this._defaultDropdownLongTime = _refLongTime;
}
}
unregister(_ref, _refLongTime) {
if (!!this._defaultDropdown && this._defaultDropdown._id === _ref._id) {
this._defaultDropdown = null;
}
if (
!!this._defaultDropdownLongTime &&
this._defaultDropdownLongTime._id === _refLongTime._id
) {
this._defaultDropdownLongTime = null;
}
}
getDefault(isLongMessage = false) {
return isLongMessage
? this._defaultDropdownLongTime
: this._defaultDropdown;
}
}
export default new DropdownManager();
import DropdownManager from "./DropdownManager";
// Type display dropdown
export const TYPE = {
SUCCESS: "success",
INFO: "info",
WARN: "warn",
ERROR: "error",
};
/**
* To display dropdown Alert in top screen
* @param type type of Alert (check it in TYPE above)
* @param title title of Alert
* @param description description of Alert
*/
export function showAlert(type, title, description) {
const ref = DropdownManager.getDefault(description.length > 60);
if (!!ref) {
ref.alertWithType(type, title, description);
}
}
/**
* To hide dropdown Alert in top screen
*/
export function hideAlert() {
const ref = DropdownManager.getDefault();
if (!!ref) {
ref.closeAction();
}
}
import * as React from 'react';
import { StatusBar } from 'react-native';
import { useIsFocused } from '@react-navigation/native';
export function FocusAwareStatusBar(props) {
const isFocused = useIsFocused();
return isFocused ? <StatusBar {...props} /> : null;
}
import React, {useState} from 'react';
import {
Image,
Platform,
SafeAreaView,
StatusBar,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import R from '../../assets/R';
import {
getWidth,
HEIGHTXD,
WIDTHXD,
WIDTHXDICON,
HEIGHT,
getFontSize,
WIDTH,
} from '../../config/Functions';
import Icon from 'react-native-vector-icons/AntDesign';
import {useNavigation} from '@react-navigation/native';
import SnackBar from '../SnackBar';
const Header = props => {
const {title, isBack} = props;
const navigate = useNavigation();
return (
<View style={styles.headerContainer}>
<Text numberOfLines={1} style={styles.txtTitle}>
{title}
</Text>
{isBack && (
<TouchableOpacity
style={styles.btnBack}
onPress={() => navigate.goBack()}>
<Icon color={R.colors.black} name={'arrowleft'} size={22} />
</TouchableOpacity>
)}
</View>
);
};
export default Header;
const styles = StyleSheet.create({
headerContainer: {
height: HEIGHT(45),
width: '100%',
flexDirection: 'row',
alignItems: 'center',
marginBottom: 2,
justifyContent: 'center',
backgroundColor: R.colors.white,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 5,
},
shadowOpacity: 0.1,
shadowRadius: 5,
elevation: 5,
},
txtTitle: {
flex: 1,
fontSize: getFontSize(16),
textAlign: 'center',
fontWeight: 'bold',
color: R.colors.black,
},
btnBack: {
position: 'absolute',
left: WIDTH(10),
width: WIDTH(35),
height: HEIGHT(30),
alignItems: 'center',
justifyContent: 'center',
},
});
import React from 'react';
import {View, Text, TextInput} from 'react-native';
import {WIDTHXD, getFontXD, WIDTH, HEIGHT} from '../../config/Functions';
import R from '../../assets/R';
import {RFValue} from 'react-native-responsive-fontsize';
const TextField = props => {
const {
title,
onChangeText,
isPassword,
maxLength,
isNumber,
value,
editable,
error,
} = props;
const renderMess = () => {
if (value && value.trim().length > 0) return `${title} không hợp lệ`;
return `Vui lòng nhập ${title ? title.toLowerCase() : messageError} `;
};
return (
<View style={{marginVertical: 5, marginHorizontal: WIDTH(15)}}>
<Text
style={{
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
}}>
{title ? title : ''}
</Text>
<TextInput
maxLength={maxLength ? maxLength : 256}
placeholderTextColor={R.colors.placeHolder}
editable={editable != null ? editable : true}
secureTextEntry={isPassword}
autoCapitalize="none"
value={value}
keyboardType={isNumber ? 'number-pad' : 'default'}
onChangeText={val => onChangeText(val)}
style={{
height: HEIGHT(35),
color: 'black',
borderRadius: HEIGHT(6),
fontSize: 16,
paddingVertical: 5,
paddingHorizontal: 10,
backgroundColor: '#EFF3F5',
}}
/>
<View
style={{
height: HEIGHT(20),
marginTop: 5,
}}>
{error && !error.ref?.value && (
<Text
ellipsizeMode={'tail'}
numberOfLines={1}
style={{
flex: 1,
color: R.colors.red,
fontSize: RFValue(10),
}}>
{error.message ? error.message : renderMess()}
</Text>
)}
</View>
</View>
);
};
export default React.memo(TextField);
import React from 'react';
import {View, Text, TextInput} from 'react-native';
import {HEIGHTXD, WIDTHXD, getFontXD} from '../../config/Functions';
import R from '../../assets/R';
const TextField = props => {
const {title, onChangeText, maxLength, value, editable} = props;
return (
<View style={{marginVertical: 5}}>
<Text
style={{
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
}}>
{title ? title : ''}
</Text>
<TextInput
maxLength={maxLength}
textAlign={'left'}
editable={editable != null ? editable : true}
value={value}
onChangeText={val => onChangeText(val)}
multiline={true}
numberOfLines={3}
placeholderTextColor={R.colors.placeHolder}
autoCapitalize="none"
style={{
textAlignVertical: 'top',
textAlign: 'left',
color: 'black',
maxHeight: HEIGHTXD(259),
minHeight: HEIGHTXD(169),
borderRadius: 7,
borderWidth: 0.7,
borderColor: '#DBDBDB',
fontSize: 16,
paddingVertical: 10,
paddingHorizontal: 10,
backgroundColor: 'white',
shadowColor: '#AFA9A9',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.25,
shadowRadius: 1.84,
elevation: 1,
}}
/>
</View>
);
};
export default React.memo(TextField);
import React, {useState} from 'react';
import {View, Text, TextInput, TouchableOpacity} from 'react-native';
import {HEIGHTXD, WIDTHXD, getFontXD} from '../../config/Functions';
import R from '../../assets/R';
import I18n from '../../helper/i18/i18n';
import Icon from 'react-native-vector-icons/Feather';
import {Image} from 'react-native';
import {NotificationAlert} from '../Aleart';
const TextField = props => {
const [showPassword, setShowPassword] = useState(false);
const {
title,
onChangeText,
isPassword,
maxLength,
isNumber,
value,
editable,
error,
onBlur,
placeholder,
keyboardType,
placeHolderColor,
textColor,
tinColor,
fontSize,
borderBottomColor,
required,
autoCapitalize,
} = props;
return (
<View>
{title ? (
<Text
style={{
fontSize: R.fontsize.fontSizeLabel,
fontWeight: '700',
color: R.colors.black,
marginBottom: 8,
}}>
<Text>{title}</Text>
<TouchableOpacity
onPress={() => {
NotificationAlert(
'Đối với các ngân hàng Techcombank, SeaBank,Vietcombank, OCB, TPBANK cần nhập thông tin số tài khoản tín dụng.',
);
}}>
<Image
source={R.images.iconWarn}
style={{
width: 22,
height: 20,
marginLeft: 10,
marginTop: 10,
resizeMode: 'cover',
}}
/>
</TouchableOpacity>
</Text>
) : null}
<View style={{justifyContent: 'center'}}>
<TextInput
onBlur={onBlur}
maxLength={maxLength ? maxLength : 256}
placeholderTextColor={placeHolderColor ? placeHolderColor : '#8E8E8E'}
editable={editable != null ? editable : true}
placeholder={placeholder ? placeHolderColor : ''}
secureTextEntry={isPassword && !showPassword}
autoCapitalize={autoCapitalize ? autoCapitalize : 'none'}
value={value}
fontSize={13}
keyboardType={keyboardType}
onChangeText={val => {
if (keyboardType === 'number-pad') {
const text = val.replace(/[^0-9]/g, '');
onChangeText(text);
} else {
onChangeText(val);
}
}}
style={{
height: 42,
color: textColor ? textColor : R.colors.black,
borderBottomWidth: 0.5,
fontSize: fontSize ? fontSize : R.fontsize.fontSizeInputText,
paddingVertical: 5,
fontWeight: '400',
paddingHorizontal: 17,
backgroundColor: R.colors.colorBgInputText,
borderRadius: 10,
borderBottomColor: 'transparent',
}}
/>
{isPassword && (
<TouchableOpacity
style={{position: 'absolute', right: 17}}
onPress={() => setShowPassword(!showPassword)}>
<Icon
name={showPassword ? 'eye' : 'eye-off'}
size={20}
color={'#4B4B4B'}
/>
</TouchableOpacity>
)}
</View>
<View
style={{
height: 20,
marginTop: 5,
}}>
{error && (
<Text
style={{
color: tinColor ? tinColor : R.colors.red1,
fontSize: getFontXD(32),
}}>
{I18n.t('PleaseEnterField')}
</Text>
)}
</View>
</View>
);
};
export default React.memo(TextField);
import React from 'react';
import {
Animated,
FlatList,
Image,
StyleSheet,
TouchableHighlight,
View,
} from 'react-native';
import {SwipeListView} from 'react-native-swipe-list-view';
import {WIDTHXD, getWidth, HEIGHTXD, WIDTHXDICON} from '../../config/Functions';
import R from '../../assets/R';
import ItemEmpty from './ItemEmpty';
const rowSwipeAnimatedValues = [];
/**
* Displays a swipe use as FlatList
*@param listIcon list image icon in swipe (for example : [R.image.iconDelete] )
*@param widthListIcon with of list icon
*@callback onPressIcon call when you choice one of list icon return index of icon and index of item
*@param rightOfList end of list icon margin Right screen
*@param styleOfIcon custom style of icon
*@param data is a Array [Object1,Object2]
*/
export default class FlatListSwipe extends React.Component {
indexOfItem = 0;
rowMap = [];
constructor(props) {
super(props);
this.state = {
isDisable: false,
};
}
closeRowItem = () => {
if (this.rowMap[this.indexOfItem]) {
this.rowMap[this.indexOfItem].closeRow();
}
};
closeRow = (rowMap, rowKey) => {
if (rowMap[rowKey]) {
rowMap[rowKey].closeRow();
}
};
renderRightAction = (rowMap, image, indexOfIcon) => {
return (
<View style={{marginRight: indexOfIcon === 0 ? 10 : 0}}>
<TouchableHighlight
underlayColor="transparent"
key={indexOfIcon.toString()}
disabled={this.state.isDisable}
onPress={() => {
this.closeRow(rowMap, this.indexOfItem);
this.setState(
{
isDisable: true,
},
() => {
setTimeout(() => {
if (this.props.isListRequestPartners)
this.props.onPressIcon(indexOfIcon + 1, this.indexOfItem);
else this.props.onPressIcon(indexOfIcon, this.indexOfItem);
this.setState({
isDisable: false,
});
}, 1000);
},
);
}}
style={{
height: 65,
width: 55,
borderRadius: 10,
marginTop: 10,
backgroundColor: indexOfIcon === 0 ? R.colors.gray1 : R.colors.red1,
flex: 0,
justifyContent: 'center',
alignItems: 'center',
}}>
<Image
source={image}
style={[
styles.trash,
this.props.styleOfIcon !== null && this.props.styleOfIcon,
]}
/>
</TouchableHighlight>
</View>
);
};
onRowOpen = (rowKey, rowMap) => {
this.indexOfItem = rowKey;
this.rowMap = rowMap;
};
onSwipeValueChange = swipeData => {
const {key, value} = swipeData;
rowSwipeAnimatedValues[key].setValue(Math.abs(value));
};
convertData = data => {
// if (rowSwipeAnimatedValues['0'] === undefined) {
this.props.data.forEach((_, i) => {
rowSwipeAnimatedValues[`${i}`] = new Animated.Value(0);
});
// }
let dataTmp = [];
data.map((item, index) => {
dataTmp.push({...item, key: index.toString()});
});
return dataTmp;
};
renderHiddenItem = (data, rowMap) => {
return (
<Animated.View
style={[
styles.backRightBtnRight,
this.props.rightOfList && {right: this.props.rightOfList},
{
transform: [
{
translateX: rowSwipeAnimatedValues[data.item.key].interpolate({
inputRange: [0, getWidth()],
outputRange: [getWidth(), 0],
}),
},
],
},
]}>
{this.props.listIcons.map((item, index) =>
this.renderRightAction(rowMap, item, index),
)}
</Animated.View>
);
};
render() {
const data = this.convertData(this.props.data);
const {widthListIcon} = this.props;
return (
<View style={styles.container}>
<SwipeListView
{...this.props}
data={data}
showsVerticalScrollIndicator={false}
renderHiddenItem={this.renderHiddenItem}
rightOpenValue={-widthListIcon || -WIDTHXD(387)}
onRowOpen={this.onRowOpen}
onSwipeValueChange={this.onSwipeValueChange}
disableRightSwipe={true}
swipeToOpenPercent={10}
swipeToClosePercent={10}
ListEmptyComponent={!this.props.isLoading && <ItemEmpty />}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'transparent',
flex: 1,
},
backRightBtnRight: {
flexDirection: 'row',
flex: 1,
// right: 20
},
trash: {
height: 21,
width: 21,
},
});
import React from 'react';
import {Text, View, StyleSheet} from 'react-native';
import {HEIGHT, getFont, getWidth} from '../../config/Functions';
import R from '../../assets/R';
import i18n from '../../helper/i18/i18n';
const ItemEmpty = props => {
let paddingHorizontal = props.paddingHorizontal ? props.paddingHorizontal : 0;
const {title} = props;
return (
<View
style={{...styles.container, width: getWidth() - paddingHorizontal * 2}}>
<View style={{alignItems: 'center'}}>
<Text style={{fontSize: getFont(16), color: R.colors.black}}>
{title || i18n.t('NullDataSearch')}
</Text>
</View>
</View>
);
};
ItemEmpty.defaultProps = {
paddingHorizontal: 0,
};
export default ItemEmpty;
const styles = StyleSheet.create({
container: {
width: getWidth(),
height: HEIGHT(50),
flexDirection: 'row',
paddingTop: HEIGHT(16),
paddingBottom: HEIGHT(10),
paddingRight: HEIGHT(10),
paddingLeft: HEIGHT(10),
alignItems: 'center',
justifyContent: 'center',
},
});
import * as React from 'react';
//@ts-ignore
import { ActivityIndicator, ActivityIndicatorProps, StyleSheet } from 'react-native';
const StyledIndicator: React.FunctionComponent<ActivityIndicatorProps> = (props: ActivityIndicatorProps) => {
return <ActivityIndicator color={'red'} size={'small'} style={styles.container} {...props} />;
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default StyledIndicator;
//@ts-ignore
import React, { useEffect, useRef, useState, useMemo } from 'react';
//@ts-ignore
import { FlatList, FlatListProps, RefreshControl, View, TextStyle, StyleProp, ViewStyle } from 'react-native';
import NoData from './StyledNoData';
import StyledIndicator from './StyledIndicator';
interface Props extends FlatListProps<any> {
[key: string]: any;
FlatListComponent?: React.FunctionComponent<any>;
loading?: boolean;
data: any[];
loadingMore?: boolean;
noDataText?: string;
ListHeaderComponent?: any;
scrollEnabled?: boolean;
noDataCanRefresh?: boolean;
i18Params?: any;
noDataTextI18Key?: any;
noDataStyle?: StyleProp<ViewStyle>;
customStyle?: any;
onLoadMore?(): void;
onNoDataRefresh?(): void;
}
const StyledList = (props: Props, ref: any) => {
const [momentumScrolled, setMomentumScrolled] = useState(false);
const list = useRef<FlatList>(null);
const { loading, loadingMore, data, ListHeaderComponent, refreshing, customStyle } = props;
const contentContainerStyle: StyleProp<ViewStyle> = {};
const hasData = data?.length !== 0;
if (!hasData) {
contentContainerStyle.flex = 1;
// contentContainerStyle.alignItems = 'center'
// contentContainerStyle.justifyContent = 'center'
}
let styles: StyleProp<ViewStyle>;
if (typeof ListHeaderComponent === 'undefined' && !hasData) {
styles = [contentContainerStyle, customStyle];
} else {
styles = customStyle;
}
function keyExtractor(item: any, i: any): string {
return `${i}`;
}
function handleRefresh() {
if (props.onRefresh) props.onRefresh();
}
// Bởi vì onEnReached call nhiều lần nên phải trick để chỉ call 1 lần thôi
useEffect(() => {
if (momentumScrolled) {
setMomentumScrolled(true);
if (props.onLoadMore) props.onLoadMore();
}
}, [momentumScrolled]);
function handleEndReached(info: any) {
if (!momentumScrolled) {
setMomentumScrolled(true);
}
}
function handleNoDataRefresh() {
const { onNoDataRefresh } = props;
if (onNoDataRefresh) onNoDataRefresh();
}
function onMomentumScrollBegin() {
setMomentumScrolled(false);
}
React.useImperativeHandle(ref, () => ({
scrollToTop: () => {
list?.current?.scrollToOffset({ animated: true, offset: 0 });
},
}));
function renderFooter() {
if (hasData && loadingMore) {
return (
<View style={{ alignItems: 'center', marginVertical: 8 }}>
<StyledIndicator size={24} />
</View>
);
}
return null;
}
function renderNoData() {
const { noDataText, noDataTextI18Key, noDataCanRefresh } = props;
return (
<NoData
customStyle={props.noDataStyle}
loading={loading}
text={"No data"}
canRefresh={noDataCanRefresh}
onRefresh={handleNoDataRefresh}
/>
);
}
const FlatListComponent: any = useMemo(() => {
return props?.FlatListComponent || FlatList;
}, [props?.FlatListComponent]);
return (
<FlatListComponent
ref={list}
contentContainerStyle={styles}
keyExtractor={keyExtractor}
initialNumToRender={10}
// onEndReached={handleEndReached}
onEndReachedThreshold={0.01}
onMomentumScrollBegin={onMomentumScrollBegin}
ListEmptyComponent={renderNoData}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl
refreshing={!!refreshing}
colors={['red']}
tintColor={"blue"}
onRefresh={handleRefresh}
/>
}
ListFooterComponent={renderFooter}
keyboardShouldPersistTaps={'never'}
{...props}
/>
);
};
export default React.memo(React.forwardRef(StyledList));
import * as React from 'react';
//@ts-ignore
import { ActivityIndicator,TouchableOpacity, Text,StyleProp, StyleSheet, TextStyle, View, ViewStyle } from 'react-native';
interface StyledListNoDataProps {
text?: string;
canRefresh?: boolean;
loading?: boolean;
onRefresh?(): any;
customStyle?: StyleProp<ViewStyle>;
customStyleText?: StyleProp<TextStyle>;
}
const StyledNoData: React.FunctionComponent<StyledListNoDataProps> = (props: StyledListNoDataProps) => {
return (
<View style={[styles.container, props.customStyle]}>
{props.loading ? (
<View style={{ alignItems: 'center' }}>
<ActivityIndicator />
</View>
) : (
<Text>Khong co data</Text>
)}
{!!props.canRefresh && !props.loading ? (
<TouchableOpacity onPress={props.onRefresh}>
<Text>Reload</Text>
</TouchableOpacity>
) : (
<View />
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
alignItems: 'center',
justifyContent: 'center',
padding: 8,
},
text: {
fontWeight: '600',
fontSize: 14,
color: 'red',
textAlign: 'center',
},
textReload: {
margin: 12,
color: 'red',
},
});
export default StyledNoData;
import React, {useEffect, useState} from 'react';
import {View, Text, StyleSheet, TouchableOpacity, Image} from 'react-native';
import NetInfo from '@react-native-community/netinfo';
import R from '../assets/R';
import AppText from './AppText';
const NoInternetComponent = props => {
const [isConnected, setConnect] = useState(true);
useEffect(() => {
const unsubscribe = NetInfo.addEventListener(state => {
setConnect(state.isConnected);
});
return unsubscribe;
}, []);
return !isConnected ? (
<View style={styles.offlineContainer}>
<Image source={R.images.bg_cannot_connect} style={styles.imageStyle} />
<AppText i18nKey={'No_Internet'} style={styles.textStyle} />
<AppText i18nKey={'Check_Internet_Connect'} style={styles.subTextStyle} />
<TouchableOpacity
onPress={() => {
setTimeout(() => {
NetInfo.fetch().then(state => {
setConnect(state.isConnected);
});
}, 3000);
}}>
<AppText
i18nKey={'Retry'}
style={{alignSelf: 'center', fontSize: 20, color: 'blue'}}
/>
</TouchableOpacity>
</View>
) : (
<View style={{width: 0, height: 0}} />
);
};
const styles = StyleSheet.create({
offlineContainer: {
width: '100%',
height: '100%',
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
},
offlineText: {
color: R.colors.white100,
},
textStyle: {
fontSize: 20,
color: 'black',
marginTop: 30,
},
subTextStyle: {
fontSize: 16,
color: R.colors.borderC,
marginVertical: 10,
},
imageStyle: {
width: '80%',
height: 200,
},
});
export default NoInternetComponent;
import React, {useState} from 'react';
import {
ActivityIndicator,
Image,
StyleSheet,
Text,
TouchableOpacity,
TouchableWithoutFeedback,
View,
} from 'react-native';
import R from '../../assets/R';
import {getFontXD, HEIGHTXD, WIDTHXD} from '../../config/Functions';
import Modal from 'react-native-modal';
import i18n from '../../helper/i18/i18n';
import {connect} from 'react-redux';
import {hideLoading, showLoading} from '../../actions/loadingAction';
import {uploadFile} from '../../apis/Functions/config';
import {showAlert, TYPE} from '../DropdownAlert';
import {saveUserToRedux} from '../../actions/users';
import {ASYNC_STORE_KEY} from '../../config/constants';
import AsyncStorage from '@react-native-community/async-storage';
import PickerImg from './PickerImg';
import {changeAvatart} from '../../apis/Functions/users';
const options = {
title: 'Select Avatar',
customButtons: [{name: 'fb', title: 'Choose Photo from Facebook'}],
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const PickerAvatar = props => {
const [isModalVisible, setModalVisible] = useState(false);
const [imgAvatar, setImgAvatar] = useState(props.userInfo?.avatar);
const [isUploadAvatar, setIsUploadAvatar] = useState(false);
const uploadAvatar = async photo => {
// setIsUploadAvatar(true);
// const data = new FormData();
// let fileName = photo.filename;
// if (!fileName || fileName === undefined) {
// let pathArray = photo.path.split('/');
// fileName = pathArray[pathArray.length - 1];
// }
// data.append('files', {
// name: fileName.replace(/HEIC/g, 'jpg'),
// type: photo.mime,
// size: photo.size,
// uri: photo.path,
// });
// const response = await uploadFile(data);
// if (response.status === 200) {
// if (response.data.code === 'OK' && response.data.data) {
// const res = await changeAvatart({avatar: response.data.data[0]?.url});
// if (res.data.code == 200) {
// setImgAvatar(response.data.data[0].url);
// showAlert(
// TYPE.SUCCESS,
// i18n.t('Notification'),
// i18n.t('ChangeAvatartSuccess'),
// );
// } else {
// showAlert(
// TYPE.ERROR,
// i18n.t('Notification'),
// i18n.t('ChangeAvatartFaild'),
// );
// }
// //call api update
// } else {
// showAlert(
// TYPE.ERROR,
// i18n.t('Notification'),
// response.data.error
// ? i18n.t(response.data.error)
// : i18n.t('CallAPIError'),
// );
// }
// } else {
// showAlert(TYPE.ERROR, i18n.t('Notification'), i18n.t('CallAPIError'));
// }
// setIsUploadAvatar(false);
};
return (
<TouchableOpacity onPress={() => setModalVisible(true)}>
<View style={styles.containerImg}>
<View
style={{
position: 'absolute',
bottom: 0,
width: 70,
height: 70,
borderRadius: 35,
justifyContent: 'center',
alignItems: 'center',
}}>
{imgAvatar ? (
<Image source={{uri: imgAvatar}} style={styles.imgAvatar} />
) : (
<Image source={R.images.icAccount} style={styles.imgAvatar} />
)}
{isUploadAvatar && (
<ActivityIndicator
color={'gray'}
size={'small'}
style={{
position: 'absolute',
}}
/>
)}
</View>
<View style={styles.iconPicker}>
<Image
style={{width: 16, height: 16, tintColor: R.colors.white}}
source={R.images.iconCamera}
/>
</View>
</View>
<PickerImg
isModalVisible={isModalVisible}
setModalVisible={setModalVisible}
cropping={true}
onClickImage={image => {
uploadAvatar(image);
}}
/>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
container: {
width: WIDTHXD(350),
height: HEIGHTXD(280),
backgroundColor: R.colors.white,
borderRadius: 10,
borderWidth: 2,
borderColor: '#DBDBDB',
borderStyle: 'dashed',
justifyContent: 'center',
alignItems: 'center',
},
imgAvatar: {
width: 70,
height: 70,
borderRadius: 35,
borderColor: R.colors.main,
backgroundColor: R.colors.gray1,
},
containerImg: {
width: 75,
height: 75,
},
iconPicker: {
width: 24,
height: 24,
position: 'absolute',
justifyContent: 'center',
alignItems: 'center',
right: 3,
backgroundColor: '#1754C7',
borderRadius: 12,
bottom: 0,
},
txt: {
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
paddingLeft: 10,
},
selectionImg: {
padding: 10,
justifyContent: 'center',
alignItems: 'center',
},
containerSelect: {
backgroundColor: 'white',
paddingTop: 5,
paddingBottom: 30,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
},
line: {
height: 0.5,
backgroundColor: R.colors.gray1,
width: '100%',
marginTop: 5,
},
imgIcon: {
width: 40,
height: 40,
},
txtTitleBtn: {
textAlign: 'center',
fontSize: 14,
color: R.colors.black,
},
});
const mapStateToProps = state => {
return {
userInfo: state.userReducer.userInfo,
};
};
export default connect(mapStateToProps, {
showLoading,
hideLoading,
saveUserToRedux,
})(PickerAvatar);
import React, {useState, useEffect} from 'react';
import {Text, View, StyleSheet, TouchableOpacity} from 'react-native';
import DatePicker from 'react-native-datepicker';
import Icon from 'react-native-vector-icons/AntDesign';
import {HEIGHTXD, WIDTHXD, getFontXD, HEIGHT} from '../../config/Functions';
import R from '../../assets/R';
import I18n from '../../helper/i18/i18n';
import moment from 'moment';
/**
* Note
*
* placeholder: if have not value placeholder is visibled
* defaultValue : if have defaultValue it will be seted for value of date
* other you can make minDate,maxDate... with props of libary react-native-datepicker
*/
const PickerDate = props => {
const [time, setTime] = useState(new Date());
useEffect(() => {
const checkDefaultValue = () => {
if (
props.defaultValue === undefined ||
props.defaultValue === null ||
props.defaultValue == ''
) {
setTime(null);
} else {
// let str = props.defaultValue.split("-");
let date = new Date(moment(props.defaultValue, 'DD/MM/YYYY'));
setTime(date);
}
};
checkDefaultValue();
}, []);
return (
<>
{props.title ? (
<Text
style={{
fontSize: R.fontsize.fontSizeLabel,
fontWeight: '700',
color: R.colors.black,
marginBottom: 8,
}}>
<Text>{props.title}</Text>
{props.required && <Text style={{color: R.colors.red1}}> *</Text>}
</Text>
) : null}
{props.disable ? (
<View
style={{
flexDirection: 'row',
height: HEIGHT(40),
fontWeight: '400',
paddingHorizontal: 17,
borderRadius: 10,
borderBottomColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: R.colors.borderGray,
}}>
<Text
style={{
flex: 1,
color: R.colors.black,
fontSize: R.fontsize.fontSizeContent,
}}>
{props.defaultValue}
</Text>
<Icon name={'calendar'} size={24} color={'#4B4B4B'} />
</View>
) : (
<TouchableOpacity
style={{
flexDirection: 'row',
height: HEIGHT(40),
fontWeight: '400',
paddingHorizontal: 17,
borderRadius: 10,
borderWidth: 1,
borderColor: R.colors.borderGray,
}}>
<DatePicker
date={time}
format="DD/MM/YYYY"
confirmBtnText={I18n.t('Ok')}
cancelBtnText={I18n.t('Cancel')}
locale="vi"
style={{flex: 1}}
mode="date"
iconComponent={
<Icon name={'calendar'} size={24} color={'#4B4B4B'} />
}
placeholder={props.placeholder}
git
customStyles={{
dateIcon: {
position: 'absolute',
top: 4,
right: 10,
marginLeft: 0,
},
dateInput: {
alignItems: 'flex-start',
flex: 1,
width: '100%',
borderWidth: 0,
marginLeft: WIDTHXD(0),
color: R.colors.black,
},
dateText: {
color: R.colors.black,
fontSize: R.fontsize.fontSizeContent,
},
placeholderText: {
color: R.colors.colorNhap,
fontSize: 16,
},
}}
onDateChange={date => {
setTime(date);
props.pickDate(date);
}}
/>
</TouchableOpacity>
)}
<View
style={{
height: 20,
marginTop: 5,
}}>
{props.error ? (
<Text
style={{
color: R.colors.red1,
fontSize: getFontXD(32),
}}>
{`${I18n.t('PleaseSelect')}${props.title.toLowerCase()}`}
</Text>
) : null}
</View>
</>
);
};
export default PickerDate;
import React, {useState, useEffect} from 'react';
import {Text, View, StyleSheet, TouchableOpacity, Image} from 'react-native';
import DatePicker from 'react-native-datepicker';
import Icon from 'react-native-vector-icons/AntDesign';
import {HEIGHTXD, WIDTHXD, getFontXD, getWidth} from '../../config/Functions';
import R from '../../assets/R';
import I18n from '../../helper/i18/i18n';
import moment from 'moment';
/**
* Note
*
* placeholder: if have not value placeholder is visibled
* defaultValue : if have defaultValue it will be seted for value of date
* other you can make minDate,maxDate... with props of libary react-native-datepicker
*/
const PickerDate = props => {
const [time, setTime] = useState(new Date());
useEffect(() => {
const checkDefaultValue = () => {
if (
props.value === undefined ||
props.value === null ||
props.value == ''
) {
setTime(null);
} else {
// let str = props.defaultValue.split("-");
let date = new Date(moment(props.value, 'DD/MM/YYYY'));
setTime(date);
}
};
checkDefaultValue();
}, [props.value]);
return (
<DatePicker
date={time}
format="DD/MM/YYYY"
confirmBtnText={'Đồng ý'}
cancelBtnText={'Huỷ'}
locale="vi"
style={props.containerStyle}
mode="date"
iconComponent={
time ? (
<TouchableOpacity
style={{
marginBottom: 0,
position: 'absolute',
top: 10,
right: 0,
}}
onPress={() => {
setTime();
props.pickDate(null);
}}>
<Image
resizeMode="contain"
source={R.images.icClose}
style={{
width: 18,
height: 18,
tintColor: time ? R.colors.black : '#4B4B4B',
}}
size={22}
/>
</TouchableOpacity>
) : (
<Image
resizeMode="contain"
source={R.images.icDatePicker}
style={{
marginBottom: 0,
position: 'absolute',
top: 10,
right: 0,
width: 18,
height: 18,
}}
size={22}
color={'#4B4B4B'}
/>
)
}
placeholder={props.placeholder}
git
customStyles={{
dateInput: {
alignItems: 'flex-start',
flex: 1,
color: R.colors.black,
justifyContent: 'center',
borderWidth: 0,
},
dateText: {
color: time ? 'black' : '#575757',
fontSize: 16,
},
placeholderText: {
color: '#575757',
fontSize: 16,
},
}}
onDateChange={date => {
setTime(date);
props.pickDate(date);
}}
/>
);
};
export default PickerDate;
import React, {useState, useEffect} from 'react';
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
TouchableWithoutFeedback,
Platform,
PermissionsAndroid,
} from 'react-native';
import R from '../../assets/R';
import {
HEIGHTXD,
WIDTHXD,
getFontXD,
requestCameraPermission,
getWidth,
} from '../../config/Functions';
import Icon from 'react-native-vector-icons/AntDesign';
import Modal from 'react-native-modal';
import ImagePicker from 'react-native-image-crop-picker';
import AppText from '../AppText';
const options = {
title: 'Select Avatar',
customButtons: [{name: 'fb', title: 'Choose Photo from Facebook'}],
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const PickerImgUni = props => {
const {title, height, width, callApi} = props;
const [isModalVisible, setModalVisible] = useState(false);
const [urlImg, setUrlImg] = useState('');
const checkPermissionAndroid = () => {
if (!PermissionsAndroid.check('CAMERA')) {
requestCameraPermission();
}
};
const onchoosGalery = () => {
ImagePicker.openPicker({
mediaType: 'photo',
multiple: false,
height: 350,
width: 575,
cropping: true,
}).then(image => {
setModalVisible(false);
setUrlImg(image.path);
parseData(image);
});
};
const onCapture = () => {
if (Platform.OS == 'android') checkPermissionAndroid();
ImagePicker.openCamera({
mediaType: 'photo',
height: 350,
width: 575,
cropping: true,
}).then(image => {
setModalVisible(false);
setUrlImg(image.path);
parseData(image);
});
};
const parseData = photo => {
const data = new FormData();
let fileName = photo.filename;
if (!fileName || fileName === undefined) {
let pathArray = photo.path.split('/');
fileName = pathArray[pathArray.length - 1];
}
data.append('files', {
name: fileName.replace(/HEIC/g, 'jpg'),
type: photo.mime,
size: photo.size,
uri: photo.path,
});
callApi(data);
};
return (
<View onPress={() => setModalVisible(true)}>
<View style={{marginBottom: 5}}>
<Text style={styles.txt}>{title}:</Text>
</View>
<TouchableOpacity onPress={() => setModalVisible(true)}>
{urlImg ? (
<Image
resizeMode={'contain'}
source={{uri: urlImg}}
style={styles.containerIdentify}
/>
) : (
<View style={styles.containerIdentify}>
<Image source={R.images.icCamera} style={styles.image} />
</View>
)}
</TouchableOpacity>
<Modal
isVisible={isModalVisible}
style={{margin: 0, justifyContent: 'flex-end'}}
onSwipeComplete={() => setModalVisible(false)}
swipeDirection={['up', 'left', 'right', 'down']}>
<TouchableWithoutFeedback onPress={() => setModalVisible(false)}>
<View style={{flex: 1}}></View>
</TouchableWithoutFeedback>
<View style={styles.containerSelect}>
<AppText
i18nKey={'Select_source_image'}
style={{
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
color: '#1473E6',
}}
/>
<View style={styles.line} />
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
<TouchableOpacity style={styles.selectionImg} onPress={onCapture}>
<Image style={styles.imgIcon} source={R.images.iconCamera} />
<AppText i18nKey={'Take_photo'} style={styles.txtTitleBtn} />
</TouchableOpacity>
<TouchableOpacity
style={styles.selectionImg}
onPress={onchoosGalery}>
<Image style={styles.imgIcon} source={R.images.iconImg} />
<AppText i18nKey={'Photo_library'} style={styles.txtTitleBtn} />
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: R.colors.white,
borderRadius: 5,
justifyContent: 'center',
alignItems: 'center',
},
txt: {
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
},
selectionImg: {
padding: 10,
justifyContent: 'center',
alignItems: 'center',
},
containerSelect: {
backgroundColor: 'white',
paddingVertical: 20,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
borderRadius: 8,
},
line: {
height: 1,
backgroundColor: '#929292',
width: '100%',
marginTop: 5,
},
imgIcon: {
width: 40,
height: 40,
},
txtTitleBtn: {
textAlign: 'center',
fontSize: 16,
color: '#1473E6',
},
containerIdentify: {
height: HEIGHTXD(500),
marginHorizontal: 30,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
borderWidth: 0.6,
borderStyle: 'dashed',
borderColor: R.colors.gray1,
backgroundColor: R.colors.colorBgScreen,
},
image: {
height: 48,
width: 48,
},
});
export default React.memo(PickerImgUni);
import React, {useState} from 'react';
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
TouchableWithoutFeedback,
Platform,
PermissionsAndroid,
} from 'react-native';
import R from '../../assets/R';
import {
HEIGHTXD,
WIDTHXD,
getFontXD,
requestCameraPermission,
} from '../../config/Functions';
import Icon from 'react-native-vector-icons/AntDesign';
import Modal from 'react-native-modal';
import ImagePicker from 'react-native-image-crop-picker';
import AppText from '../AppText';
const options = {
title: 'Select Avatar',
customButtons: [{name: 'fb', title: 'Choose Photo from Facebook'}],
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const checkPermissionAndroid = () => {
if (!PermissionsAndroid.check('CAMERA')) {
requestCameraPermission();
}
};
const PickerImg = props => {
const {onClickImage, isModalVisible, setModalVisible} = props;
let option;
if (props.cropping) {
option = {
mediaType: 'photo',
multiple: false,
cropping: true,
width: 300,
height: 300,
};
} else {
option = {
mediaType: 'photo',
multiple: false,
};
}
const onChooseGallery = () => {
ImagePicker.openPicker(option).then(image => {
setModalVisible(false);
onClickImage(image);
});
};
const onCapture = () => {
if (Platform.OS == 'android') checkPermissionAndroid();
let option;
if (props.cropping) {
option = {
mediaType: 'photo',
multiple: false,
cropping: true,
width: 300,
height: 300,
};
} else {
option = {
mediaType: 'photo',
multiple: false,
};
}
ImagePicker.openCamera(option).then(image => {
setModalVisible(false);
onClickImage(image);
});
};
return (
<Modal
isVisible={isModalVisible}
style={{margin: 0, justifyContent: 'flex-end'}}
onSwipeComplete={() => setModalVisible(false)}
swipeDirection={['up', 'left', 'right', 'down']}>
<TouchableWithoutFeedback onPress={() => setModalVisible(false)}>
<View style={{flex: 1}}></View>
</TouchableWithoutFeedback>
<View style={styles.containerSelect}>
<AppText
i18nKey={'Select_source_image'}
style={{
paddingVertical: 15,
fontSize: 16,
color: R.colors.black,
fontWeight: 'bold',
textAlign: 'center',
}}
/>
<View style={styles.line} />
<View
style={{
justifyContent: 'space-around',
flexDirection: 'row',
alignItems: 'center',
}}>
<TouchableOpacity style={styles.selectionImg} onPress={onCapture}>
<Image style={styles.imgIcon} source={R.images.iconCamera} />
<AppText i18nKey={'Take_photo'} style={styles.txtTitleBtn} />
</TouchableOpacity>
<TouchableOpacity
style={styles.selectionImg}
onPress={onChooseGallery}>
<Image style={styles.imgIcon} source={R.images.icGallery} />
<AppText i18nKey={'Photo_library'} style={styles.txtTitleBtn} />
</TouchableOpacity>
</View>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
container: {
width: WIDTHXD(350),
height: HEIGHTXD(280),
backgroundColor: R.colors.white,
borderRadius: 5,
borderWidth: 2,
borderColor: '#DBDBDB',
borderStyle: 'dashed',
justifyContent: 'center',
alignItems: 'center',
},
txt: {
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
paddingLeft: 10,
},
selectionImg: {
padding: 10,
justifyContent: 'center',
alignItems: 'center',
},
containerSelect: {
backgroundColor: 'white',
paddingTop: 5,
paddingBottom: 30,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
},
line: {
height: 0.5,
backgroundColor: R.colors.gray1,
width: '100%',
marginTop: 5,
},
imgIcon: {
width: 40,
height: 40,
},
txtTitleBtn: {
textAlign: 'center',
fontSize: 14,
color: R.colors.black,
},
});
export default React.memo(PickerImg);
import React, {useState, useEffect} from 'react';
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
TouchableWithoutFeedback,
Platform,
PermissionsAndroid,
} from 'react-native';
import R from '../../assets/R';
import {
HEIGHTXD,
WIDTHXD,
getFontXD,
requestCameraPermission,
} from '../../config/Functions';
import Icon from 'react-native-vector-icons/AntDesign';
import Modal from 'react-native-modal';
import Block from '../Block';
import ImagePicker from 'react-native-image-crop-picker';
import AppText from '../AppText';
const options = {
title: 'Select Avatar',
customButtons: [{name: 'fb', title: 'Choose Photo from Facebook'}],
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const PickerImgUni = props => {
const {title, height, width, onSelectImg} = props;
const [isModalVisible, setModalVisible] = useState(false);
const [urlImg, setUrlImg] = useState('');
// const [imgPicker, setImgPicker] = useState('');
const checkPermissionAndroid = () => {
if (!PermissionsAndroid.check('CAMERA')) {
requestCameraPermission();
}
};
const onchoosGalery = () => {
ImagePicker.openPicker({
mediaType: 'photo',
multiple: false,
}).then(image => {
setModalVisible(false);
setUrlImg(image.path);
onSelectImg(image.path);
});
};
const onCapture = () => {
if (Platform.OS == 'android') checkPermissionAndroid();
ImagePicker.openCamera({
mediaType: 'photo',
width: 300,
height: 400,
}).then(image => {
setModalVisible(false);
setUrlImg(image.path);
onSelectImg(image.path);
});
};
return (
<TouchableOpacity
onPress={() => setModalVisible(true)}
style={{
marginTop: 10,
width: WIDTHXD(480),
alignItems: 'center',
}}>
<View style={{width: WIDTHXD(480), marginBottom: 5}}>
<Text style={styles.txt}>{title}:</Text>
</View>
{urlImg ? (
<Image source={{uri: urlImg}} style={styles.container} />
) : (
<View style={styles.container}>
<Icon name={'plus'} size={40} color={'#DBDBDB'} />
</View>
)}
<Modal
isVisible={isModalVisible}
style={{margin: 0, justifyContent: 'flex-end'}}
onSwipeComplete={() => setModalVisible(false)}
swipeDirection={['up', 'left', 'right', 'down']}>
<TouchableWithoutFeedback onPress={() => setModalVisible(false)}>
<View style={{flex: 1}}></View>
</TouchableWithoutFeedback>
<View style={styles.containerSelect}>
<AppText
i18nKey={'Select_source_image'}
style={{
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
color: '#1473E6',
}}
/>
<View style={styles.line} />
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
<TouchableOpacity style={styles.selectionImg} onPress={onCapture}>
<Image style={styles.imgIcon} source={R.images.iconCamera} />
<AppText i18nKey={'Take_photo'} style={styles.txtTitleBtn} />
</TouchableOpacity>
<TouchableOpacity
style={styles.selectionImg}
onPress={onchoosGalery}>
<Image style={styles.imgIcon} source={R.images.iconImg} />
<AppText i18nKey={'Photo_library'} style={styles.txtTitleBtn} />
</TouchableOpacity>
</View>
</View>
</Modal>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
container: {
width: WIDTHXD(350),
height: HEIGHTXD(320),
backgroundColor: R.colors.white,
borderRadius: 5,
justifyContent: 'center',
alignItems: 'center',
},
txt: {
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
},
selectionImg: {
padding: 10,
justifyContent: 'center',
alignItems: 'center',
},
containerSelect: {
height: HEIGHTXD(520),
backgroundColor: 'white',
paddingTop: 10,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
},
line: {
height: 1,
backgroundColor: '#929292',
width: '100%',
marginTop: 5,
},
imgIcon: {
width: 40,
height: 40,
},
txtTitleBtn: {
textAlign: 'center',
fontSize: 16,
color: '#1473E6',
},
});
export default React.memo(PickerImgUni);
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
TouchableHighlight,
Dimensions,
Platform,
} from 'react-native';
import ModalDropdown from 'react-native-modal-dropdown';
import R from '../../assets/R';
import {
WIDTHXD,
getFontXD,
HEIGHTXD,
getHeight,
WIDTHXDICON,
HEIGHT,
WIDTH,
} from '../../config/Functions';
import Icon from 'react-native-vector-icons/AntDesign';
const data = [];
/**
* This Function to show piker with list date (for example [{name:'Picker1'},{name:'Picker2}])
* @callback onValueChange return value of item you choice
* @param value value of picker you choice
* @param defaultIndex defaultIndex of picker you choice
* @param containerStyle custom containerStyle of view
* @param data data value of date
* @param width width of picker
* @param height height of picker
* @param date value of date you choice
* @param heightItem height of picker Item
* @param maxHeight set height of list
* @param iconDropdown to set icon for dropdown
* @param iconDropdownStyle to style icon dropdown
* other you can make minDate,maxDate... with props of libary react-native-datepicker
*/
export default class PickerItem extends Component {
constructor(props) {
super(props);
this._button = null;
this._buttonFrame = null;
this.state = {
value: '',
showInBottom: true,
};
}
componentDidMount() {
this._dropdown.select(0);
}
_dropdownAdjustFrame = style => {
const {showInBottom} = this.state;
// alert(showInBottom);
let stylez = style;
if (!showInBottom) {
stylez.height += HEIGHTXD(99) * (6 - Math.min(this.props.data.length, 5));
} else {
stylez.height += HEIGHTXD(99);
}
// stylez.left += 150;
return stylez;
};
render() {
const {
width,
onValueChange,
containerStyle,
height,
value,
defaultValue,
data,
defaultIndex,
iconDropdown,
iconDropdownStyle,
disabled,
isTriangle,
textStyle,
iconSize,
iconColor,
} = this.props;
return (
<View style={styles.cell}>
<TouchableOpacity
disabled={disabled}
ref={button => {
this._button = button;
}}
onPress={() => {
this._dropdown.show();
// this._updatePosition();
}}
style={[
styles.pickerStyle,
containerStyle !== null && containerStyle,
height && {height},
width && {width},
]}>
<Text
numberOfLines={1}
style={[
styles.dropdown_row_text,
width && {width: width - WIDTHXD(125)},
textStyle ? textStyle : {},
]}>
{defaultValue || this.state.value}
</Text>
{iconDropdown || isTriangle ? (
<Icon
name={'up'}
size={iconSize ? iconSize : 20}
color={iconColor ? iconColor : R.colors.borderGray}
/>
) : (
<Icon
name={'down'}
size={iconSize ? iconSize : 20}
color={iconColor ? iconColor : R.colors.borderGray}
/>
)}
</TouchableOpacity>
<ModalDropdown
showsVerticalScrollIndicator={false}
saveScrollPosition={false}
ref={el => {
this._dropdown = el;
}}
style={[styles.dropdown, width && {width}]}
defaultValue={defaultValue || '0'}
defaultIndex={defaultIndex || 0}
textStyle={styles.dropdown_text}
dropdownStyle={[
styles.dropdown_dropdown,
{maxHeight: HEIGHTXD(99 * Math.min(data.length, 6) + 12)},
width && {width},
]}
options={data !== null && data}
onSelect={value => {
onValueChange && onValueChange(value, data[value]);
this.setState({value: data[value].name});
}}
renderRow={(option, index, isSelected) => (
<View
style={[
styles.dropdown_row,
{
backgroundColor:
option.value == value?.value ? '#C0C0C0' : '#f2f2f2',
},
]}>
<Text
numberOfLines={1}
style={[
styles.dropdown_row_text,
{
marginHorizontal: WIDTHXD(30),
// color: option.value == value?.value ? 'black' : 'black',
// fontWeight: option.value == value?.value ? '700' : '400',
fontWeight: '400',
color: 'black',
},
]}>
{`${option.name}`}
</Text>
</View>
)}
renderButtonText={rowData => this.renderButtonText(rowData)}
// adjustFrame={(style) => this._dropdownAdjustFrame(style)}
// renderSeparator={(sectionID, rowID, adjacentRowHighlighted) => this.renderSeparator(sectionID, rowID, adjacentRowHighlighted)}
/>
</View>
);
}
renderButtonText = () => ' ';
renderSeparator = rowID => {
if (rowID === data.length - 1) {
return [];
}
let key = `spr_${rowID}`;
return <View style={styles.dropdown_separator} key={key} />;
};
}
const styles = StyleSheet.create({
cell: {
flex: 0,
},
dropdown: {
alignSelf: 'center',
width: '100%',
height: HEIGHTXD(0),
},
dropdown_text: {
fontSize: 16,
},
dropdown_dropdown: {
width: '100%',
maxHeight: HEIGHTXD(200),
borderBottomLeftRadius: WIDTHXD(20),
borderBottomRightRadius: WIDTHXD(20),
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.2,
shadowRadius: 1.41,
elevation: 2,
marginTop: Platform.OS == 'ios' ? 0 : -21,
},
dropdown_row: {
flexDirection: 'row',
height: HEIGHTXD(100),
alignItems: 'center',
paddingHorizontal: 5,
},
dropdown_row_text: {
// marginHorizontal: 4,
fontSize: 16,
textAlignVertical: 'center',
},
dropdown_separator: {
borderBottomWidth: 0.3,
borderBottomColor: R.colors.iconGray,
},
pickerStyle: {
width: '100%',
height: HEIGHT(40),
flexDirection: 'row',
paddingHorizontal: WIDTH(10),
justifyContent: 'space-between',
alignItems: 'center',
alignSelf: 'center',
backgroundColor: 'white',
marginTop: 5,
borderRadius: 7,
borderWidth: 1,
borderColor: R.colors.borderGray,
fontSize: 16,
paddingVertical: 5,
paddingHorizontal: 10,
backgroundColor: 'white',
},
});
// @flow
import React, {Component} from 'react';
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import AntDesign from 'react-native-vector-icons/AntDesign';
import R from '../../assets/R';
import {HEIGHTXD, WIDTHXD, getFontXD} from '../../config/Functions';
import ModalSearch from './ModalSearch';
/**
* This Function to show piker search with list date (for example [{name:'Picker1'},{name:'Picker2}])
* This show view with input when touch it show a modal search
* @callback onValueChange return value of item you choice
* @param title title of popup search
* @param containerStyle custom containerStyle of view
* @param data style value of date
* @param width width of picker
* @param date value of date you choice
* @param value value of date you choice
* @param searchPickerStyle custom searchPickerStyle of TouchableOpacity
* @param placeholder value of placeholder
* @param textStyle custom text in Text
* other you can make minDate,maxDate... with props of libary react-native-datepicker
*/
class PickerSearch extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
item: null,
reRender: false,
};
}
componentDidMount = async () => {
const {value} = this.props;
if (value) {
this.setState({value});
}
};
componentWillReceiveProps(nextProps) {
if (
nextProps.data !== this.props.data &&
(nextProps.data.length > 0 || nextProps.isNeedClearData)
) {
this.setState({reRender: this.state.reRender});
}
}
onChangeText = text => {
this.ModalSearch && this.ModalSearch.changeName(text);
};
render() {
const {value, item} = this.state;
const {
textStyle,
containerStyle,
placeholder,
width,
data,
title,
onValueChange,
findData,
disabled,
height,
tempDisabled,
onShowPorm,
style,
} = this.props;
const choosed =
this.props.value && this.props.value != '' && this.props.value !== null
? true
: false;
return (
<View style={[styles.container, style ? style : {}]}>
<TouchableOpacity
disabled={disabled}
onPress={() => {
tempDisabled
? onShowPorm && onShowPorm()
: this.ModalSearch.setModalVisible(true);
}}
style={[
styles.searchPicker,
containerStyle !== null && containerStyle,
width && {width},
height && {height},
]}>
{value === '' && this.props.value && this.props.value === '' ? (
<Text>{placeholder !== null && placeholder}</Text>
) : (
<Text
numberOfLines={1}
style={[
styles.textStyle,
textStyle !== null && textStyle,
width && {width: width - WIDTHXD(150)},
]}>
{this.props.value !== null && this.props.value}
</Text>
)}
<TouchableOpacity
onPress={() => {
this.setState({value: '', item: null});
onValueChange && onValueChange('', null);
}}
hitSlop={{left: 20, top: 20, right: 20, bottom: 20}}
disabled={!choosed || disabled}>
<AntDesign
name={!choosed || disabled ? 'search1' : 'close'}
size={WIDTHXD(43)}
color={R.colors.iconGray}
/>
</TouchableOpacity>
</TouchableOpacity>
<ModalSearch
ref={ref => {
this.ModalSearch = ref;
}}
data={data}
isNeedClearData={this.props.isNeedClearData}
findData={findData !== null && findData}
onValueChange={(Value, item) => {
this.setState({value: Value, item: item});
onValueChange && onValueChange(item.value, item);
}}
title={title}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
borderRadius: HEIGHTXD(8),
flexDirection: 'row',
alignItems: 'center',
width: WIDTHXD(960),
},
searchPicker: {
width: WIDTHXD(960),
borderRadius: HEIGHTXD(20),
paddingHorizontal: WIDTHXD(36),
justifyContent: 'space-between',
flexDirection: 'row',
alignItems: 'center',
height: HEIGHTXD(99),
borderWidth: 0.3,
borderColor: R.colors.iconGray,
color: R.colors.black0,
},
textStyle: {
fontFamily: R.fonts.RobotoRegular,
width: WIDTHXD(800),
fontSize: 16,
},
});
export default PickerSearch;
import React, {useState, useEffect} from 'react';
import {
View,
Text,
Image,
StyleSheet,
TouchableOpacity,
TouchableWithoutFeedback,
Platform,
PermissionsAndroid,
} from 'react-native';
import R from '../../assets/R';
import {
HEIGHTXD,
WIDTHXD,
getFontXD,
requestCameraPermission,
getWidth,
} from '../../config/Functions';
import Icon from 'react-native-vector-icons/AntDesign';
import Modal from 'react-native-modal';
import ImagePicker from 'react-native-image-crop-picker';
import AppText from '../AppText';
const options = {
title: 'Select Avatar',
customButtons: [{name: 'fb', title: 'Choose Photo from Facebook'}],
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const PickerImgUni = props => {
const {title} = props;
const [isModalVisible, setModalVisible] = useState(false);
const [urlImg, setUrlImg] = useState('');
const checkPermissionAndroid = () => {
if (!PermissionsAndroid.check('CAMERA')) {
requestCameraPermission();
}
};
const onchoosGalery = () => {
ImagePicker.openPicker({
mediaType: 'photo',
multiple: false,
height: 350,
width: 575,
cropping: true,
}).then(image => {
setModalVisible(false);
setUrlImg(image.path);
parseData(image);
});
};
const onCapture = () => {
if (Platform.OS == 'android') checkPermissionAndroid();
ImagePicker.openCamera({
mediaType: 'photo',
height: 350,
width: 575,
cropping: true,
}).then(image => {
setModalVisible(false);
setUrlImg(image.path);
parseData(image);
});
};
const parseData = photo => {
const data = new FormData();
let fileName = photo.filename;
if (!fileName || fileName === undefined) {
let pathArray = photo.path.split('/');
fileName = pathArray[pathArray.length - 1];
}
data.append('files', {
name: fileName.replace(/HEIC/g, 'jpg'),
type: photo.mime,
size: photo.size,
uri: photo.path,
});
callApi(data);
};
const callApi = () => {
console.log('call');
};
return (
<View onPress={() => setModalVisible(true)}>
<View style={{marginBottom: 5}}>
<Text style={styles.txt}>{title}:</Text>
</View>
<TouchableOpacity onPress={() => setModalVisible(true)}>
{urlImg ? (
<Image
resizeMode={'contain'}
source={{uri: urlImg}}
style={styles.containerIdentify}
/>
) : (
<View style={styles.containerIdentify}>
<Image source={R.images.icCamera} style={styles.image} />
</View>
)}
</TouchableOpacity>
<Modal
isVisible={isModalVisible}
style={{margin: 0, justifyContent: 'flex-end'}}
onSwipeComplete={() => setModalVisible(false)}
swipeDirection={['up', 'left', 'right', 'down']}>
<TouchableWithoutFeedback onPress={() => setModalVisible(false)}>
<View style={{flex: 1}}></View>
</TouchableWithoutFeedback>
<View style={styles.containerSelect}>
<AppText
i18nKey={'Select_source_image'}
style={{
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
color: '#1473E6',
}}
/>
<View style={styles.line} />
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
<TouchableOpacity style={styles.selectionImg} onPress={onCapture}>
<Image style={styles.imgIcon} source={R.images.iconCamera} />
<AppText i18nKey={'Take_photo'} style={styles.txtTitleBtn} />
</TouchableOpacity>
<TouchableOpacity
style={styles.selectionImg}
onPress={onchoosGalery}>
<Image style={styles.imgIcon} source={R.images.iconImg} />
<AppText i18nKey={'Photo_library'} style={styles.txtTitleBtn} />
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: R.colors.white,
borderRadius: 5,
justifyContent: 'center',
alignItems: 'center',
},
txt: {
fontSize: 16,
color: R.colors.color777,
marginBottom: 5,
},
selectionImg: {
padding: 10,
justifyContent: 'center',
alignItems: 'center',
},
containerSelect: {
backgroundColor: 'white',
paddingVertical: 20,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
borderRadius: 8,
},
line: {
height: 1,
backgroundColor: '#929292',
width: '100%',
marginTop: 5,
},
imgIcon: {
width: 40,
height: 40,
},
txtTitleBtn: {
textAlign: 'center',
fontSize: 16,
color: '#1473E6',
},
containerIdentify: {
height: HEIGHTXD(500),
marginHorizontal: 30,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
borderWidth: 0.6,
borderStyle: 'dashed',
borderColor: R.colors.gray1,
backgroundColor: R.colors.colorBgScreen,
},
image: {
height: 48,
width: 48,
},
});
export default React.memo(PickerImgUni);
import React, {useState, useEffect} from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
StatusBar,
TouchableWithoutFeedback,
} from 'react-native';
import R from '../assets/R';
import {getFontXD, HEIGHTXD} from '../config/Functions';
import LinearGradient from 'react-native-linear-gradient';
import Modal from 'react-native-modal';
import {connect} from 'react-redux';
import {showNotificaton, hideNotification} from '../actions/SnackBarAction';
import {useNavigation} from '@react-navigation/native';
import AppText from '../components/AppText';
const SnackBar = props => {
const navigate = useNavigation();
const {isOpen, title, content, screen, id_record} = props.snackReducer;
useEffect(() => {
if (isOpen)
setTimeout(() => {
props.hideNotification();
}, 6000);
}, [props.snackReducer]);
return (
<Modal
style={{padding: 0, margin: 0}}
animationInTiming={1500}
animationOutTiming={800}
backdropOpacity={0}
animationIn={'slideInDown'}
animationOut={'slideOutUp'}
isVisible={isOpen}>
<View style={styles.container}>
<View style={{flex: 1}}>
<Text style={styles.txtTitle}>{title}</Text>
<Text numberOfLines={2} style={styles.txt}>
{content}
</Text>
</View>
<View style={styles.row}>
<TouchableOpacity
onPress={() => props.hideNotification()}
style={styles.btn}>
<AppText i18nKey={'Close'} style={styles.txtBtn} />
</TouchableOpacity>
{screen && id_record ? (
<TouchableOpacity
onPress={() => {
navigate.navigate(screen, {id: id_record});
}}
style={[styles.btn, {marginLeft: 20}]}>
<AppText i18nKey={'Detail'} style={styles.txtBtn} />
</TouchableOpacity>
) : null}
</View>
</View>
<TouchableWithoutFeedback onPress={() => props.hideNotification()}>
<View style={{flex: 1}}></View>
</TouchableWithoutFeedback>
</Modal>
);
};
const mapStateToProps = state => {
return {
snackReducer: state.SnackReducer,
};
};
export default connect(mapStateToProps, {showNotificaton, hideNotification})(
SnackBar,
);
const styles = StyleSheet.create({
container: {
marginTop: 10,
height: HEIGHTXD(380),
backgroundColor: R.colors.white,
marginHorizontal: 10,
borderRadius: 5,
paddingVertical: 10,
paddingHorizontal: 10,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 3,
},
row: {
flexDirection: 'row',
justifyContent: 'flex-end',
},
txt: {
color: R.colors.black,
},
txtBtn: {
fontSize: 16,
color: R.colors.txtMain,
fontWeight: 'bold',
},
txtTitle: {
fontSize: 16,
color: R.colors.black,
fontWeight: 'bold',
},
});
import React, {useEffect, useState} from 'react';
import {
View,
Text,
Modal,
TouchableOpacity,
StyleSheet,
Image,
TouchableWithoutFeedback,
Linking,
Platform,
} from 'react-native';
import R from '../assets/R';
import {
getFontXD,
getHeight,
getWidth,
HEIGHTXD,
WIDTHXD,
} from '../config/Functions';
import I18n from '../helper/i18/i18n';
import DeviceInfo from 'react-native-device-info';
import {connect} from 'react-redux';
import {getNewestVersionInfo} from '../apis/Functions/home';
import {showLoading, hideLoading} from '../actions/loadingAction';
const VersionChecker = props => {
const [visible, setVisible] = useState(false);
const [isForceUpdate, setIsForceUpdate] = useState(false);
const [version, setVersion] = useState('1.0');
useEffect(() => {
checkVersion();
}, []);
const checkVersion = async () => {
const res = await getNewestVersionInfo(
Platform.OS == 'ios' ? 'ios' : 'android',
);
if (res.data.code == 200 && res.data.data) {
if (
res.data.data.value.version_name != DeviceInfo.getVersion() ||
res.data.data.value.build != DeviceInfo.getBuildNumber()
) {
setVersion(res.data.data.value.version_name);
setVisible(true);
setIsForceUpdate(res.data.data.value.is_require_update);
}
}
};
const onUpdatePressed = async () => {
try {
if (Platform.OS === 'ios') {
Linking.openURL(
'itms-services://?action=download-manifest&url=https://investing.dcvfinance.com/public/assets/app/DCV.plist',
);
setVisible(false);
} else {
Linking.openURL(
'https://play.google.com/store/apps/details?id=com.dcvcard',
);
}
} catch (error) {}
};
const onRequestClose = () => null;
const renderBackdrop = () => {
return (
<View
style={{
backgroundColor: 'rgba(0,0,0,0.30)',
// backgroundColor: 'red',
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
width: getWidth(),
height: getHeight(),
}}
/>
);
};
const cancelUpdate = () => {
setVisible(false);
};
return (
<Modal
onRequestClose={() => onRequestClose()}
transparent
animationType="fade"
style={{position: 'absolute'}}
visible={visible}>
{renderBackdrop()}
<View pointerEvents="box-none" style={styles.containerStyle}>
<View style={styles.imageUpgradeContainer} zIndex={100}>
<Image
source={R.images.iconUpgrade}
style={[styles.imageUpgradeStyle, {tintColor: R.colors.main}]}
/>
</View>
<View style={styles.contentContainerStyle}>
<Text style={styles.titleStyle}>
{props.language.language == 'vi' ? 'Cập nhật' : 'Update'}
</Text>
<Text style={styles.versionLabelStyle}>
{I18n.t('Version')}
{': '}
{version}
</Text>
<Text style={styles.descStyle}>
{' '}
{props.language.language == 'vi'
? 'Đã có phiên bản DCVFinance mới. Cập nhật ngay để tiếp tục sử dụng và trải nghiệm những tính năng mới nhất của hệ thống!'
: 'A new version of DCVFinance is available. Update now to continue using and experiencing the latest system features!'}
</Text>
{isForceUpdate ? (
<TouchableOpacity
onPress={() => onUpdatePressed()}
style={styles.notNowContainerStyle}>
<Text style={[styles.textNotNowStyle, {color: R.colors.main}]}>
{props.language.language == 'vi' ? 'Cập nhật' : 'Update'}
</Text>
</TouchableOpacity>
) : (
<View
style={[
styles.notNowContainerStyle,
{
flexDirection: 'row',
marginHorizontal: WIDTHXD(100),
},
]}>
<TouchableOpacity
onPress={() => cancelUpdate()}
style={[styles.btnButton, {paddingRight: WIDTHXD(60)}]}>
<Text
style={[
styles.textNotNowStyle,
{color: R.colors.color777, textAlign: 'right'},
]}>
{props.language.language == 'vi' ? 'Bỏ qua' : 'Cancel'}
</Text>
</TouchableOpacity>
<View style={styles.dividerStyleVertical}></View>
<TouchableOpacity
onPress={() => onUpdatePressed()}
style={[styles.btnButton, {paddingLeft: WIDTHXD(60)}]}>
<Text
style={[
styles.textNotNowStyle,
{color: R.colors.main, textAlign: 'left'},
]}>
{I18n.t('Update')}
</Text>
</TouchableOpacity>
</View>
)}
</View>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
imageUpgradeStyle: {
width: 50,
height: 50,
tintColor: R.colors.primaryColor,
},
imageUpgradeContainer: {
width: 80,
height: 80,
borderRadius: 40,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
},
containerStyle: {
flex: 1,
width: getWidth() * 0.8,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
contentContainerStyle: {
marginTop: -40,
paddingTop: 40,
width: getWidth() * 0.9,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 15,
},
logoStyle: {
width: 65,
height: 65,
marginVertical: 20,
},
titleStyle: {
fontWeight: '600',
fontSize: 20,
color: 'black',
paddingHorizontal: 8,
textAlign: 'center',
},
versionLabelStyle: {
fontSize: 14,
color: R.colors.grey600,
marginTop: 5,
marginBottom: 15,
paddingHorizontal: 8,
textAlign: 'center',
},
descStyle: {
fontSize: getFontXD(46),
color: R.colors.grey900,
marginBottom: 20,
paddingHorizontal: 10,
textAlign: 'center',
},
notNowContainerStyle: {
height: HEIGHTXD(160),
width: '100%',
alignItems: 'center',
justifyContent: 'center',
},
btnButton: {
flex: 1,
},
textNotNowStyle: {
fontSize: getFontXD(46),
width: '100%',
textAlign: 'center',
color: R.colors.primaryColor,
},
starContainer: {
flexDirection: 'row',
width: '100%',
justifyContent: 'center',
alignItems: 'center',
height: 45,
},
dividerStyle: {
height: 0.5,
width: '100%',
backgroundColor: R.colors.borderC,
},
dividerStyleVertical: {
height: HEIGHTXD(160),
width: 0.5,
backgroundColor: R.colors.borderC,
},
});
const mapStateToProps = state => {
return {
language: state.languageReducer,
};
};
export default connect(mapStateToProps, {showLoading, hideLoading})(
VersionChecker,
);
import i18n from "../helper/i18/i18n";
import R from "../assets/R";
export const HISTORY_STATUS = {
ALL: {
code: "ALL",
color: R.colors.secondary,
icon: R.images.icCompleted,
name: i18n.t("All"),
status: "-1",
},
COMPLETED: {
code: "COMPLETED",
color: R.colors.secondary,
icon: R.images.icCompleted,
name: i18n.t("Completed"),
status: "3",
},
IN_PROCESSING: {
code: "IN_PROCESSING",
color: R.colors.lightBlue,
icon: R.images.icInfo,
name: i18n.t("InProcessing"),
status: "4",
},
FAILED: {
code: "FAILED",
color: R.colors.red1,
icon: R.images.icFailed,
name: i18n.t("Failed"),
status: "7",
},
WATTING: {
code: "TRANS_WAIT_APPROVED",
color: R.colors.orange,
icon: R.images.icInfo,
name: i18n.t("InProcessing"),
status: "4",
},
};
export const SEX = {
MALE: 0,
FEMALE: 1,
};
export const TRANSACTION_TYPE = {
ALL: {
code: "ALL",
color: R.colors.secondary,
backgroundButton: R.images.bgDepositButton,
name: i18n.t("All"),
transferType: -1,
},
DEPOSIT: {
code: "PUSH",
color: R.colors.secondary,
backgroundButton: R.images.bgDepositButton,
name: i18n.t("Deposit"),
transferType: 2,
transferTypeTxt: "PUSH",
},
WITHDRAW: {
code: "PULL",
color: R.colors.red1,
backgroundButton: R.images.bgWithdrawButton,
name: i18n.t("Withdraw"),
transferType: 1,
transferTypeTxt: "PULL",
},
BORROW_REQUEST: {
code: "BORROW_REQUEST",
color: R.colors.gray1,
backgroundButton: R.images.bgBorrowRequest,
name: i18n.t("BorrowRequest"),
transferType: 3,
transferTypeTxt: "3",
},
};
export const ACCOUNT_BANK_TYPE = {
BANK: "Bank",
CREDIT: "Credit",
};
export const CELL_COUNT = 4;
export const SHARE_TYPE = {
ALL: 1,
FACEBOOK: 2,
TWITTER: 3,
};
export const RATINGS_TYPE = {
REFER_FRIEND: 1,
BENEFIT: 2,
};
export const LANGUAGE_LIST = [
{
id: 56,
name: i18n.t("Vietnamese"),
value: "vi",
code: "vi",
},
{
id: 57,
name: i18n.t("English"),
value: "en",
code: "en",
},
];
export const ASYNC_STORE_KEY = {
TOKEN: "@TOKEN",
FIREBASE: "@Firebase",
ACCOUNT: "@ACCOUNT",
LANGUAGE: "@LANGUAGE",
};
export const OTP_TYPE = {
CHECK_PHONE_NUMBER: 0,
FORGOT_PASSWORD: 1,
};
export const PROVINCE_LIST = [
{
id: 1,
code: "AG",
name: "An Giang",
},
{
id: 2,
code: "BR_VT",
name: "Bà Rịa - Vũng Tàu",
},
{
id: 3,
code: "BL",
name: "Bạc Liêu",
},
{
id: 4,
code: "BK",
name: "Bắc Kạn",
},
{
id: 5,
code: "BC",
name: "Bắc Giang",
},
{
id: 6,
code: "BN",
name: "Bắc Ninh",
},
{
id: 7,
code: "BT",
name: "Bến Tre",
},
{
id: 8,
code: "BD",
name: "Bình Dương",
},
{
id: 9,
code: "BD",
name: "Bình Định",
},
{
id: 10,
code: "BP",
name: "Bình Phước",
},
{
id: 11,
code: "HN",
name: "Hà Nội",
},
{
id: 12,
code: "HCM",
name: "Hồ Chí Minh",
},
];
export const DEVICE_EVENT_KEY = {
RELOAD_BALANCE_WALLET: "reloadBalanceWallet",
LOGOUT_EVENT: "logoutEvent",
};
import io from 'socket.io-client/dist/socket.io';
import {NetworkSetting} from './Setting';
export const connectSocket = () => {
const socket = io(NetworkSetting.SOCKETCHAT, {
jsonp: false,
// timeout: 10000,
// // transports: ['websocket'],
// autoConnect: false,
agent: '-',
// path: '/', // Whatever your path is
pfx: '-',
// // key: token, // Using token-based auth.
// // passphrase: cookie, // Using cookie auth.
reconnection: true,
'force new connection': true,
transports: ['websocket', 'polling'],
cert: '-',
ca: '-',
ciphers: '-',
rejectUnauthorized: '-',
perMessageDeflate: '-',
});
return socket;
};
export const SOCKET_EVENTS = {
EVENT: 'event',
CONNECTION: 'connection',
};
export const EVENT_STATUS = {
UNKNOW: 0,
ACTIVE: 1,
INACTIVE: 2,
};
export const ROOMS = {
COMMENT: 'COMMENT_',
};
export const NAMESPACE = {
COMMENT: '/comments',
HOME: '/homes',
SHARE: '/share',
REVIEW_DETAIL: '/review_detail',
COMMENT_REVIEW_DETAIL: '/comment_review_detail',
PROFILE: '/profile',
REPLY_COMMENT: '/reply-comments',
WALLET: '/wallet',
PRIVATE_CHAT: '/private_chat',
THREAD_CHAT: '/thread_chat',
};
export const MESSAGE_TYPE = {
TEXT: 1,
IMAGE: 2,
LOCATION: 3,
ALERT: 4,
};
export const MESSAGE_STATUS = {
SENT: 1,
PENDING: 2,
RECEIVER: 3,
READ: 4,
};
/* eslint-disable no-console */
import React, {useEffect} from 'react';
import {Platform, View, Alert} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import {ASYNC_STORE_KEY} from '../config/constants';
import messaging from '@react-native-firebase/messaging';
import {showNotificaton} from '../actions/SnackBarAction';
import {connect} from 'react-redux';
import {convertScreen} from '../config/Functions';
import {updateWalletInfo} from '../actions/walletAction';
const FirebaseNotification = props => {
// messaging().setBackgroundMessageHandler(async (remoteMessage) => {
// console.log("Message handled in the background!", remoteMessage);
// });
// messaging().onNotificationOpenedApp(async (remoteMessage) => {
// console.log("On notifi open app-----", remoteMessage);
// });
useEffect(() => {
checkPermission();
const unsubscribe = messaging().onMessage(async remoteMessage => {
console.log('A new FCM message arrived!', remoteMessage);
const {body, title} = remoteMessage.notification;
const {action_type, record_id} = remoteMessage.data;
console.log('action_type', action_type);
props.showNotificaton({
title,
content: body,
screen: convertScreen(action_type),
id_record: record_id,
});
props.updateWalletInfo();
});
// messaging().onNotificationOpenedApp((remoteMessage) => {
// console.log(
// 'Notification caused app to open from background state:',
// remoteMessage,
// );
// const {action_type, body, title, record_id} = remoteMessage.data;
// if (action_type == 'REDIRECT') {
// Linking.openURL(remoteMessage.data.redirect_to);
// } else {
// props.newScreenInit({
// screen: convertScreen(action_type),
// id_record: record_id,
// });
// }
// });
// messaging()
// .getInitialNotification()
// .then((remoteMessage) => {
// console.log(remoteMessage);
// if (remoteMessage) {
// console.log(
// 'Notification caused app to open from quit state:',
// remoteMessage.data,
// );
// const {action_type, body, title, record_id} = remoteMessage.data;
// if (action_type == 'REDIRECT') {
// Linking.openURL(remoteMessage.data.redirect_to);
// } else {
// props.newScreenInit({
// screen: convertScreen(action_type),
// id_record: record_id,
// });
// }
// }
// });
return unsubscribe;
}, []);
const checkPermission = async () => {
const enabled = await messaging().hasPermission();
if (enabled == 1) {
getFcmToken();
} else {
requestPermission();
}
};
const requestPermission = async () => {
try {
await messaging().requestPermission();
getFcmToken();
} catch (error) {
// If user do not allow Push Notification
console.log('Rejected');
}
};
const getFcmToken = async () => {
let fcmToken = await AsyncStorage.getItem(ASYNC_STORE_KEY.FIREBASE);
console.log('fcmToken save', fcmToken);
if (!fcmToken) {
fcmToken = await messaging().getToken();
console.log('fcmToken create', fcmToken);
if (fcmToken) {
AsyncStorage.setItem(ASYNC_STORE_KEY.FIREBASE, fcmToken);
}
}
};
return <View />;
};
const mapStateToProps = state => {
return {};
};
export default connect(mapStateToProps, {
showNotificaton,
updateWalletInfo,
})(FirebaseNotification);
import { concat } from "lodash";
import React, { Component, useState, useEffect } from "react";
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
ScrollView,
Alert,
} from "react-native";
import io from "socket.io-client";
class SocketIO extends Component {
constructor(props) {
super(props);
this.socket = io("http://192.168.0.103:9000");
this.state = {
isRegistor: true,
room: "",
text: "",
listRooms: [],
name: "",
user: "",
ListMessage: [],
currentRoom: "",
};
}
componentDidMount() {
this.socket.on("server-send-rooms", (data) => {
this.setState({
listRooms: data,
});
});
this.socket.on("server-send-room-socket", (data) => {
this.setState({
currentRoom: data,
});
});
this.socket.on("server-send-message", (data) => {
const newList = this.state.ListMessage.concat(data);
this.setState({
ListMessage: newList,
});
});
}
onSend = () => {
this.socket.emit("client-send-message", this.state.text);
};
onInitRoom = () => {
this.socket.emit("create-room", this.state.room);
};
render() {
const { isRegistor, currentRoom, listRooms, user, ListMessage } =
this.state;
return (
<View style={{ flex: 1, marginTop: 50, paddingHorizontal: 20 }}>
<View style={styles.footer}>
<TextInput
onChangeText={(val) => this.setState({ room: val })}
style={styles.txtInput}
/>
<TouchableOpacity
onPress={() => this.onInitRoom()}
style={styles.btn}
>
<Text>To room</Text>
</TouchableOpacity>
</View>
<Text style={styles.txtRoom}>{currentRoom}</Text>
<View style={styles.row}>
<View style={styles.wrapLeft}>
{listRooms.map((e) => (
<View style={{ marginTop: 10 }}>
<Text>{e}</Text>
</View>
))}
</View>
<View style={styles.wrapChat}>
{ListMessage.map((e) => (
<View style={{ marginTop: 10 }}>
<Text>{e}</Text>
</View>
))}
</View>
</View>
<View style={styles.footer}>
<TextInput
onChangeText={(val) => this.setState({ text: val })}
style={styles.txtInput}
/>
<TouchableOpacity onPress={() => this.onSend()} style={styles.btn}>
<Text>Send</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
wrapTop: {
height: 50,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
wrap: {
flexDirection: "row",
},
item: {
borderWidth: 0.6,
borderRadius: 5,
marginRight: 10,
paddingHorizontal: 5,
height: 40,
justifyContent: "center",
},
wrapChat: {
borderWidth: 0.6,
marginVertical: 20,
borderRadius: 10,
flex: 2,
},
wrapLeft: {
borderWidth: 0.6,
marginVertical: 20,
borderRadius: 10,
flex: 1,
marginRight: 10,
},
footer: {
flexDirection: "row",
alignItems: "center",
height: 50,
justifyContent: "space-between",
marginBottom: 20,
},
txtInput: {
flex: 1,
borderWidth: 0.6,
borderRadius: 10,
marginRight: 10,
height: 40,
},
btn: {
backgroundColor: "pink",
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 5,
},
row: {
flexDirection: "row",
height: 400,
},
txtRoom: {
textAlign: "center",
fontSize: 22,
fontWeight: "600",
},
});
export default SocketIO;
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment