unioil-loyalty-rn-app/app/screens/myprofile/profile/edit.js

694 lines
27 KiB
JavaScript

import * as React from 'react';
import { KeyboardAvoidingView, ScrollView, TouchableOpacity, View, Text, Alert } from 'react-native';
import { Avatar } from 'react-native-elements';
import { connect } from "react-redux";
import { openModal } from '../../../redux/actions/AlertActions';
import { checkPhoneNumberInput } from '../../../utils/number';
import { launchImageLibrary } from 'react-native-image-picker';
import { saveUserInfo, savePlainUserInfo } from "../../../redux/actions/AppUserInfoActions";
import { ContactOptions, ContactOptionsWithParams } from '../../../components/contact.action';
import CustomHeader from '../../../components/header.js';
import Assets from '../../../components/assets.manager.js';
import Theme from '../../../components/theme.style.js';
import Elements from '../../../components/elements.js';
import moment from 'moment';
import DB from '../../../components/storage/';
import REQUEST from '../../../components/api/';
import RNFETCHBLOB from '../../../components/api/file.manager';
import Utils from './utils';
import CustomSafeArea from '../../../components/safeArea.component';
class EditProfile extends React.PureComponent {
constructor(props) {
super(props)
}
state = {
openChangePhoto: false,
loading: false,
userProfile: null,
focused: false,
editprofileselect: false,
customerserviceselect: false,
currentFocus: null,
opendialog: false,
currentDialog: null,
currentphoto: null,
backModal: false,
newphoto: null,
newmobile: "",
newemail: null,
newaddress: null,
newcity: null,
vehicleType: null,
fuelType: null,
maritalStatus: null,
gender: null,
is_deleted: false,
errors: {},
deleted: false,
openOptions: false
}
componentDidMount() {
this.setState({ loading: false, userProfile: this.props.route.params.data })
}
componentWillUnmount() {
}
onInputFocus = (index) => {
this.setState({ focused: true, currentFocus: index })
}
onSelectPress = (index) => {
this.setState({ opendialog: true, currentDialog: index })
}
getFT = (type) => {
let types = Assets.fueltypes
for(var x=0;x<types.length;x++){if(type == types[x].value){return types[x].string}}
return ""
}
getVT = (type) => {
let types = Assets.vehicletypes
for(var x=0;x<types.length;x++){if(type == types[x].value){return types[x].string}}
return ""
}
getMS = (type) => {
let types = Assets.civilstatus
for(var x=0;x<types.length;x++){if(type == types[x].value){return types[x].string}}
return ""
}
getG = (type) => {
let types = Assets.gender
for(var x=0;x<types.length;x++){if(type == types[x].value){return types[x].string}}
return ""
}
getCN = () => {
}
onDeletePhoto = () => {
this.setState({ is_deleted: true, currentphoto: Assets.logo.profileHolder, openChangePhoto: false })
}
formatBytes = (bytes, decimals = 2) => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return { stringFormat: parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i], decimalFormat: parseFloat((bytes / Math.pow(k, i)).toFixed(dm)), sizeFormat: sizes[i] };
}
onEditPhoto = () => {
let options = {
mediaType: 'photo',
maxHeight: 1500,
maxWidth: 1500,
quality: 0.75
}
launchImageLibrary(options, (response) => {
let filesize = this.formatBytes(response.fileSize)
console.log(filesize.stringFormat.includes('KB'))
if(!filesize.stringFormat.includes('KB') && !filesize.stringFormat.includes('Bytes')) {
Alert.alert("Error", "Image size too large.")
return
}
console.log(response)
if(!response.didCancel){
if(this.state.is_deleted){
this.setState({ is_deleted: false, currentphoto: null })
}
this.setState({ newphoto: response, openChangePhoto: false })
}
})
}
validateEmail = () => {
let regEx = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/
return regEx.test(this.state.email)
}
FormValidate = async () => {
let res = {}
this.setState({ loading: true })
if(this.state.newemail == ""){
res = Object.assign(this.state.errors, {email: ["This field is required"]})
}
if(this.state.newaddress == "" || this.state.newaddress == null && this.state.userProfile.address == ""){
res = Object.assign(this.state.errors, {address: ["This field is required"]})
}
if(!this.state.vehicleType && this.state.userProfile.vo_code == "0"){
res = Object.assign(this.state.errors, {vehicleType: ["This field is required"]})
}
if(!this.state.fuelType && this.state.userProfile.fueltype_code == "0"){
res = Object.assign(this.state.errors, {fuelType : ["This field is required"]})
}
if((this.state.maritalStatus && this.state.maritalStatus.value === "0")) {
res = Object.assign(this.state.errors, {maritalStatus : ["This field is required"]})
}
if((this.state.gender && this.state.gender.value === "0")) {
res = Object.assign(this.state.errors, {gender : ["This field is required"]})
}
this.setState({ errors: res, loading: false })
return Object.keys(this.state.errors).length > 0 ? false : true
}
Body = function() {
return {
image: this.state.newphoto ? this.state.newphoto.uri : null,
mobile: this.state.newmobile,
email: this.state.newemail,
address: this.state.newaddress,
city: this.state.newcity,
vo_code: this.state.vehicleType ? this.state.vehicleType.value : null,
fueltype_code: this.state.fuelType ? this.state.fuelType.value : null,
civilstatus_code: this.state.maritalStatus ? this.state.maritalStatus.value : null,
gender_code: this.state.gender ? this.state.gender.value : null,
is_deleted: this.state.is_deleted
}
}
fetchProfileBlob = async (successCallback, errorCallback) => {
let SESSION = await DB.session()
let params = {
newphoto: this.state.newphoto,
userProfile: this.state.userProfile,
newmobile: this.state.newmobile,
newemail: this.state.newemail,
newaddress: this.state.newaddress,
newcity: this.state.newcity,
vehicleType: this.state.vehicleType,
fuelType: this.state.fuelType,
maritalStatus: this.state.maritalStatus,
gender: this.state.gender,
is_deleted: this.state.is_deleted
}
RNFETCHBLOB("update_profile_no_otp", "POST",
{Authorization: SESSION.token}, {}, Utils.blobBody(params),
(res) => {
if(res.status == 1) {
this.updateProfileInBackground(onSuccess => successCallback(onSuccess), onError => errorCallback(onError))
} else {
Utils.responseHandler(res, () => {
successCallback(res)
}, (errors) => {
console.log(errors)
errorCallback(errors)
})
}
}, (err) => {
errorCallback(err)
})
}
updateProfileBlob = async (successCallback, errorCallback) => {
let SESSION = await DB.session()
let params = {
userProfile: this.state.userProfile,
newmobile: this.state.newmobile,
newemail: this.state.newemail,
newaddress: this.state.newaddress,
newcity: this.state.newcity,
vehicleType: this.state.vehicleType,
fuelType: this.state.fuelType,
maritalStatus: this.state.maritalStatus,
gender: this.state.gender,
is_deleted: this.state.is_deleted
}
await REQUEST("update_profile_no_otp", "post", {
Authorization: SESSION.token,
"Content-Type": "multipart/form-data",
}, {}, Utils.formData(params),
(res) => {
if(res.status == 1) {
this.updateProfileInBackground(onSuccess => successCallback(onSuccess), onError => errorCallback(onError))
} else {
Utils.responseHandler(res, () => {
successCallback(res)
}, (errors) => {
console.log(errors)
errorCallback(errors)
})
}
}, (error) => {
errorCallback(error)
})
}
responseHandler = (res, responseCallback) => {
if(res.status == 1){
setTimeout(() => {
Alert.alert(
"Success",
'\nYour profile is successfully updated\n',
[{
text: 'OK', onPress: () => {
responseCallback()
}
}]
);
}, 700)
} else {
setTimeout(() => {
Alert.alert("Error", res?.email[0]);
}, 700)
}
}
updateProfileInBackground = async (successCallback, errorCallback) => {
const SESSION = await DB.session()
try{
this.props.saveUserInfo({ token: SESSION.token, card_number: SESSION.user.card_number }).then(res => {
DB.updateProfile(res, () => {
successCallback(res)
}, (error) => {
errorCallback(error)
})
})
.catch(error => this.setState({ loading: false }))
} catch(error) {
console.log(error)
}
}
SaveNoOtp = async () => {
this.setState({ loading: true })
if(this.state.newphoto) {
this.fetchProfileBlob(success => {
this.setState({ loading: false })
if(success.status == 0) {
this.setState({ errors: success })
} else {
this.responseHandler(success, handler => {
this.props.route.params.onGoBack(success.data)
this.props.navigation.goBack()
})
}
}, error => {
this.setState({ loading: false })
setTimeout(() => {
if(this.state.newphoto) Alert.alert("Error", "Failed to upload image")
}, 300)
})
} else {
this.setState({ loading: true })
this.updateProfileBlob(success => {
this.setState({ loading: false })
if(success.status == 0) {
this.setState({ errors: success })
} else {
this.responseHandler(success, handler => {
this.props.route.params.onGoBack(success.data);
this.props.navigation.pop(2);
})
}
}, error => {
this.setState({ loading: false })
setTimeout(() => {
if(this.state.newphoto) Alert.alert("Error", "Failed to upload image")
}, 300)
})
}
}
SaveWithOtp = () => {
this.props.navigation.navigate("AccountSendOtp", {
data: {
lcard_uuid: this.state.userProfile.lcard_uuid,
mobile_number: this.state.newmobile.replace("+", "")
},
type: 'edit',
callback: (res) => {
if(res == "valid") this.SaveNoOtp()
},
})
}
onSubmit = async () => {
this.setState({ focused: false })
if(this.hasChanges()){
let validation = await this.FormValidate();
if(!validation) return
if(this.state.newmobile != "" && this.state.newmobile.replace("+", "") != this.state.userProfile.mobile){
this.SaveWithOtp()
}else{
this.SaveNoOtp()
}
}else{
this.props.navigation.goBack()
}
}
hasChanges = () => {
let values = Object.values(this.Body())
console.log(values.length)
for(var x=0;x<values.length;x++){
if(values[x]) return true
if(x == 1 && values[x] !== "") return true
}
return false
}
handleUpdatePhotoOptions = async () => {
this.setState({ openChangePhoto: true })
}
renderProfilePhoto = () => {
if(this.state.currentphoto) return Assets.logo.profileHolder
else if(!this.state.currentphoto && this.state.newphoto || this.state.newphoto) return {uri: this.state.newphoto.uri}
else if(!this.state.currentphoto && !this.state.newphoto && this.state.userProfile && this.state.userProfile.photo) return {uri: this.state.userProfile.photo}
else return Assets.logo.profileHolder
}
render() {
return (
<>
<CustomSafeArea>
<Elements.ActionOption
open={this.state.openChangePhoto}
onClose={() => this.setState({ openChangePhoto: false })}
buttons={[
{
name: 'Edit Photo',
onPress: () => this.onEditPhoto()
},
{
name: 'Delete Photo',
onPress: () => this.onDeletePhoto()
}
]}
/>
<Elements.loaderView
title="Updating Profile"
message="Please wait..."
isDarkMode={this.props.app_theme?.theme.dark}
backgroundColor={this.props.app_theme?.theme.colors.border}
color={this.props.app_theme?.theme.colors.text}
visible={this.state.loading} />
<Elements.checkboxdialog
title="Vehicle Type"
selected={this.state.vehicleType ? this.state.vehicleType.value : this.state.userProfile ? this.state.userProfile.vo_code : 0}
shown={this.state.opendialog && this.state.currentDialog == 1 ? true : false}
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
modalBackgroundColor={this.props.app_theme?.theme.colors.border}
onCancel={() => this.setState({ opendialog: !this.state.opendialog })}
onSelect={(value, string) => {
this.setState({ vehicleType: { value: value, string: string }, opendialog: !this.state.opendialog })
}}
items={Assets.vehicletypes}
/>
<Elements.checkboxdialog
title="Fuel Type"
selected={this.state.fuelType ? this.state.fuelType.value : this.state.userProfile ? this.state.userProfile.fueltype_code : 0}
shown={this.state.opendialog && this.state.currentDialog == 2 ? true : false}
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
modalBackgroundColor={this.props.app_theme?.theme.colors.border}
onCancel={() => this.setState({ opendialog: !this.state.opendialog })}
onSelect={(value, string) => {
this.setState({ fuelType: { value: value, string: string }, opendialog: !this.state.opendialog })
}}
items={Assets.fueltypes}
/>
<Elements.checkboxdialog
title="Marital Status"
selected={this.state.maritalStatus ? this.state.maritalStatus.value : this.state.userProfile ? this.state.userProfile.civilstatus_code : 0}
shown={this.state.opendialog && this.state.currentDialog == 3 ? true : false}
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
modalBackgroundColor={this.props.app_theme?.theme.colors.border}
onCancel={() => this.setState({ opendialog: !this.state.opendialog })}
onSelect={(value, string) => {
this.setState({ maritalStatus: { value: value, string: string }, opendialog: !this.state.opendialog })
}}
items={Assets.civilstatus}
/>
<Elements.checkboxdialog
title="Gender"
selected={this.state.gender ? this.state.gender.value : this.state.userProfile ? this.state.userProfile.gender_code : 0}
shown={this.state.opendialog && this.state.currentDialog == 4 ? true : false}
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
modalBackgroundColor={this.props.app_theme?.theme.colors.border}
onCancel={() => this.setState({ opendialog: !this.state.opendialog })}
onSelect={(value, string) => {
this.setState({ gender: { value: value, string: string }, opendialog: !this.state.opendialog })
}}
items={Assets.gender}
/>
<CustomHeader
title="Edit Profile"
menu={false}
backscreen="MyProfile"
back={true}
onBackPress={() => {
if(this.hasChanges()) {
this.props.openModal({
open: true,
title: "Warning",
body: "You have an unsaved profile information, are you sure you want to navigate back?",
yesCB: () => this.props.navigation.goBack(),
theme: this.props.app_theme
})
} else {
this.props.navigation.goBack();
}
}}
navigation={this.props.navigation}
/>
<KeyboardAvoidingView
style={{flex: 1}}
behavior="padding"
keyboardVerticalOffset={Theme.platform === 'ios' ? 50 : 70}
>
<ScrollView style={{flex: 1}}>
<View style={{flex: 1, flexDirection: 'row', padding: 15}}>
<View style={{flex: 1}}>
<Avatar rounded size="large" source={this.renderProfilePhoto()} />
</View>
<View style={{flex: 2.5, justifyContent: 'center'}}>
{this.state.userProfile && this.state.userProfile.photo && !this.state.is_deleted || this.state.userProfile && !this.state.userProfile.photo && this.state.newphoto && !this.state.is_deleted ?
<TouchableOpacity onPress={() => this.handleUpdatePhotoOptions()}>
<Text style={{fontFamily: 'Arial', fontSize: 15, color: Theme.colors.accent}}>Edit Photo</Text>
</TouchableOpacity> :
<TouchableOpacity onPress={() => this.onEditPhoto()}>
<Text style={{fontFamily: 'Arial', fontSize: 15, color: Theme.colors.accent}}>Add Photo</Text>
</TouchableOpacity>
}
</View>
</View>
<View style={{flex: 1, width: '100%', padding: 5}}>
<View>
<Elements.custominput
type="input"
title="First Name"
placeholder={this.state.userProfile ? this.state.userProfile.firstname : ''}
placeholderColor='gray'
disabled
onChange={null}
bottomOption={true}
onContact={() => this.setState({ openOptions: true })}
error={"This field is required"} />
<Elements.custominput
type="input"
title="Last Name"
placeholder={this.state.userProfile ? this.state.userProfile.lastname : ''}
placeholderColor='gray'
disabled
onChange={null}
bottomOption={true}
onContact={() => this.setState({ openOptions: true })}
error={"This field is required"} />
<Elements.custominput
type="input"
title="Birthday"
placeholder={this.state.userProfile ? new moment(new Date(this.state.userProfile.birthdate)).format("DD MMM YYYY") : ''}
placeholderColor='gray'
disabled
onChange={null}
bottomOption={true}
onContact={() => this.setState({ openOptions: true })}
error={"This field is required"} />
<Elements.custominput
type="input"
title="Mobile Number"
keyboardType="numeric"
maxLength={13}
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
value={this.state.newmobile ? this.state.newmobile.length <= 2 ? '+63' : this.state.newmobile : this.state.userProfile ? "+" + this.state.userProfile.mobile : ''}
placeholder=""
onChangeText={(value) => {
const checker = checkPhoneNumberInput(value);
if(!checker) return;
this.setState({ newmobile: value })
}}
onContact={() => this.setState({ openOptions: true })}
disabled={true}
bottomOption={true}
focused={this.state.focused && this.state.currentFocus == 3 ? true : false}
onFocus={() => this.onInputFocus(3)}
error={"This field is required"} />
<Elements.custominput
type="input"
title="Email Address"
value={this.state.newemail ? this.state.newemail : this.state.userProfile && this.state.newemail != '' ? this.state.userProfile.email : ''}
bottomText="your@email.com"
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
focused={this.state.focused && this.state.currentFocus == 4 || this.state.errors && this.state.errors.email ? true : false}
onFocus={() => this.onInputFocus(4)}
onChangeText={(value) => {
this.setState({ newemail: value })
delete this.state.errors["email"]
}}
hasError={this.state.errors && this.state.errors.email ? true : false}
errorMessage={this.state.errors && this.state.errors.email ? this.state.errors?.email[0] : "Invalid email"}
/>
<Elements.custominput
type="input"
title="Address"
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
value={this.state.newaddress ? this.state.newaddress : this.state.userProfile && this.state.newaddress != '' ? this.state.userProfile.address : ''}
focused={this.state.focused && this.state.currentFocus == 5 || this.state.errors && this.state.errors.address ? true : false}
onFocus={() => this.onInputFocus(5)}
onChangeText={(value) => {
this.setState({ newaddress: value })
delete this.state.errors["address"]
}}
hasError={this.state.errors && this.state.errors.address ? true : false}
errorMessage={this.state.errors && this.state.errors.address ? this.state.errors?.address[0] : "Invalid address"}
/>
<Elements.custominput
type="select"
title="Vehicle Type"
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
value={this.state.vehicleType ? this.state.vehicleType.string : this.state.userProfile ? this.getVT(this.state.userProfile.vo_code) : 'Select'}
focused={this.state.focused && this.state.currentFocus == 7 ? true : false}
onPress={() => {
this.onInputFocus(7)
this.onSelectPress(1)
delete this.state.errors["vehicleType"]
}}
hasError={this.state.errors && this.state.errors.vehicleType ? true : false}
errorMessage={this.state.errors && this.state.errors.vehicleType ? this.state.errors?.vehicleType[0] : "Invalid vehicle type"}
/>
<Elements.custominput
type="select"
title="Fuel Type"
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
value={this.state.fuelType ? this.state.fuelType.string : this.state.userProfile ? this.getFT(this.state.userProfile.fueltype_code) : 'Select'}
focused={this.state.focused && this.state.currentFocus == 8 ? true : false}
onPress={() => {
this.onInputFocus(8)
this.onSelectPress(2)
delete this.state.errors["fuelType"]
}}
hasError={this.state.errors && this.state.errors.fuelType ? true : false}
errorMessage={this.state.errors && this.state.errors.fuelType ? this.state.errors?.fuelType[0] : "Invalid fuel type"}
/>
<Elements.custominput
type="select"
title="Marital Status"
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
value={this.state.maritalStatus ? this.state.maritalStatus.string : this.state.userProfile ? this.getMS(this.state.userProfile.civilstatus_code) : 'Select'}
focused={this.state.focused && this.state.currentFocus == 9 ? true : false}
onPress={() => {
this.onInputFocus(9)
this.onSelectPress(3)
delete this.state.errors["maritalStatus"]
}}
hasError={this.state.errors && this.state.errors.maritalStatus ? true : false}
errorMessage={"This field is required"} />
<Elements.custominput
type="select"
title="Gender"
textColor={this.props.app_theme?.theme.colors.text}
isDarkMode={this.props.app_theme?.theme.dark}
value={this.state.gender ? this.state.gender.string : this.state.userProfile ? this.getG(this.state.userProfile.gender_code) : 'Select'}
focused={this.state.focused && this.state.currentFocus == 10 ? true : false}
onPress={() => {
this.onInputFocus(10)
this.onSelectPress(4)
delete this.state.errors["gender"]
}}
hasError={this.state.errors && this.state.errors.gender ? true : false}
errorMessage={"This field is required"} />
</View>
</View>
<View style={{flex: 1, alignItems: 'center', marginTop: 5, marginBottom: 30}}>
<TouchableOpacity onPress={() => this.props.openModal({
open: true,
title: "Update Profile",
body: "Are you sure you want to save Changes to your profile?",
yesCB: this.onSubmit,
theme: this.props.app_theme
})} style={{width: '92%', padding: 15, borderRadius: 10, backgroundColor: Theme.colors.primary}}>
<Text style={{alignSelf:'center', color: '#fff', fontSize: 16}}>Save Changes</Text>
</TouchableOpacity>
</View>
<ContactOptionsWithParams
params={{ cardnumber: this.state?.userProfile?.data?.card_number }}
isOpen={this.state.openOptions}
onClose={() => this.setState({ openOptions: false })}
/>
</ScrollView>
</KeyboardAvoidingView>
</CustomSafeArea>
</>
)
}
}
const mapStateToProps = (state) => {
return {
userinfo: state.appUserInfoReducer.userinfo,
app_theme: state.appThemeReducer.theme
}
}
const mapDispatchToProps = {
saveUserInfo,
openModal
}
export default connect(mapStateToProps, mapDispatchToProps)(EditProfile);