loan order store not bad
This commit is contained in:
@@ -4,7 +4,7 @@ import * as ImagePicker from 'expo-image-picker';
|
|||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
import { COLORS } from '../constants/colors';
|
import { COLORS } from '../constants/colors';
|
||||||
|
|
||||||
const ImageInput = ({ label, image, onChange }) => {
|
const ImageInput = ({ label, image, onChange, error = false }) => {
|
||||||
const [hasPermission, setHasPermission] = useState(null);
|
const [hasPermission, setHasPermission] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -22,25 +22,20 @@ const ImageInput = ({ label, image, onChange }) => {
|
|||||||
|
|
||||||
const result = await ImagePicker.launchImageLibraryAsync({
|
const result = await ImagePicker.launchImageLibraryAsync({
|
||||||
mediaTypes: ImagePicker.MediaType,
|
mediaTypes: ImagePicker.MediaType,
|
||||||
quality: 0.7,
|
quality: 0.8,
|
||||||
base64: true,
|
base64: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.canceled && result.assets && result.assets.length > 0) {
|
if (!result.canceled && result.assets && result.assets.length > 0) {
|
||||||
const asset = result.assets[0];
|
const asset = result.assets[0];
|
||||||
const fileObj = {
|
onChange && onChange(asset.uri);
|
||||||
uri: asset.uri,
|
|
||||||
name: asset.fileName || `photo_${Date.now()}.jpg`,
|
|
||||||
type: asset.mimeType || 'image/jpeg',
|
|
||||||
};
|
|
||||||
onChange && onChange(fileObj);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{label && <Text style={styles.label}>{label}</Text>}
|
{label && <Text style={styles.label}>{label}</Text>}
|
||||||
<TouchableOpacity style={styles.box} activeOpacity={0.8} onPress={pickImage}>
|
<TouchableOpacity style={[styles.box, error && styles.error]} activeOpacity={0.8} onPress={pickImage}>
|
||||||
{image ? (
|
{image ? (
|
||||||
<Image source={{ uri: image.uri ? image.uri : image }} style={styles.preview} />
|
<Image source={{ uri: image.uri ? image.uri : image }} style={styles.preview} />
|
||||||
) : (
|
) : (
|
||||||
@@ -90,6 +85,9 @@ const styles = StyleSheet.create({
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
},
|
},
|
||||||
|
error: {
|
||||||
|
borderColor: COLORS.error,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ImageInput;
|
export default ImageInput;
|
||||||
@@ -29,6 +29,7 @@ const SelectInput = ({
|
|||||||
onValueChange,
|
onValueChange,
|
||||||
placeholder = 'Select',
|
placeholder = 'Select',
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
error = false,
|
||||||
}) => {
|
}) => {
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ const SelectInput = ({
|
|||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{label && <Text style={styles.label}>{label}</Text>}
|
{label && <Text style={styles.label}>{label}</Text>}
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.selectBox, disabled && styles.disabled]}
|
style={[styles.selectBox, disabled && styles.disabled, error && styles.error]}
|
||||||
onPress={openModal}
|
onPress={openModal}
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
>
|
>
|
||||||
@@ -128,6 +129,9 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: COLORS.gray[100],
|
backgroundColor: COLORS.gray[100],
|
||||||
opacity: 0.6,
|
opacity: 0.6,
|
||||||
},
|
},
|
||||||
|
error: {
|
||||||
|
borderColor: COLORS.error,
|
||||||
|
},
|
||||||
modalOverlay: {
|
modalOverlay: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: 'rgba(0,0,0,0.3)',
|
backgroundColor: 'rgba(0,0,0,0.3)',
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useAuth } from '../../contexts/AuthContext';
|
|||||||
import { useBaseEnums } from '../../contexts/BaseEnumsContext';
|
import { useBaseEnums } from '../../contexts/BaseEnumsContext';
|
||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import ImageInput from '../../components/ImageInput';
|
import ImageInput from '../../components/ImageInput';
|
||||||
|
import authService from '../../services/authService';
|
||||||
|
|
||||||
const CreateLoanOrderScreen = () => {
|
const CreateLoanOrderScreen = () => {
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
@@ -139,47 +140,80 @@ const CreateLoanOrderScreen = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const formData = new FormData();
|
||||||
loan_type: parseInt(loanType),
|
|
||||||
loan_amount: parseInt(loanAmount),
|
const appendField = (key, value) => {
|
||||||
region,
|
if (value !== null && value !== undefined && value !== '') {
|
||||||
branch_id: parseInt(branchId),
|
formData.append(key, String(value));
|
||||||
customer_name: customerName,
|
}
|
||||||
customer_surname: customerSurname,
|
|
||||||
customer_patronic_name: customerPatro || null,
|
|
||||||
education,
|
|
||||||
marriage_status: marriageStatus,
|
|
||||||
passport_address: passportAddress,
|
|
||||||
real_address: realAddress,
|
|
||||||
passport_serie: passportSerie,
|
|
||||||
passport_id: passportId.trim(),
|
|
||||||
passport_given_at: passportGivenAt,
|
|
||||||
passport_given_by: passportGivenBy,
|
|
||||||
born_place: bornPlace,
|
|
||||||
born_at: bornAt,
|
|
||||||
phone: parseInt(phone),
|
|
||||||
email: email || null,
|
|
||||||
phone_additional: phoneAdditional ? parseInt(phoneAdditional) : null,
|
|
||||||
phone_home: phoneHome || null,
|
|
||||||
work_company: workCompany || null,
|
|
||||||
work_company_accountant_number: workCompanyAccNum || null,
|
|
||||||
work_region: workRegion || null,
|
|
||||||
work_province_id: workProvinceId ? parseInt(workProvinceId) : null,
|
|
||||||
work_position: workPosition || null,
|
|
||||||
work_salary: workSalary ? parseInt(workSalary) : null,
|
|
||||||
work_started_at: workStartedAt || null,
|
|
||||||
card_number: rawCardNumber,
|
|
||||||
card_name: cardName,
|
|
||||||
card_month: cardMonth,
|
|
||||||
card_year: cardYear,
|
|
||||||
passport_one: passportOne,
|
|
||||||
passport_two: passportTwo,
|
|
||||||
passport_three: passportThree,
|
|
||||||
passport_four: passportFour,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
appendField('loan_type', parseInt(loanType));
|
||||||
|
appendField('loan_amount', parseInt(loanAmount));
|
||||||
|
appendField('region', region);
|
||||||
|
appendField('branch_id', parseInt(branchId));
|
||||||
|
appendField('customer_name', customerName);
|
||||||
|
appendField('customer_surname', customerSurname);
|
||||||
|
appendField('customer_patronic_name', customerPatro || '');
|
||||||
|
appendField('education', education);
|
||||||
|
appendField('marriage_status', marriageStatus);
|
||||||
|
appendField('passport_address', passportAddress);
|
||||||
|
appendField('real_address', realAddress);
|
||||||
|
appendField('passport_serie', passportSerie);
|
||||||
|
appendField('passport_id', passportId.trim());
|
||||||
|
appendField('passport_given_at', passportGivenAt);
|
||||||
|
appendField('passport_given_by', passportGivenBy);
|
||||||
|
appendField('born_place', bornPlace);
|
||||||
|
appendField('born_at', bornAt);
|
||||||
|
appendField('phone', parseInt(phone));
|
||||||
|
if (email) appendField('email', email);
|
||||||
|
if (phoneAdditional) appendField('phone_additional', parseInt(phoneAdditional));
|
||||||
|
if (phoneHome) appendField('phone_home', phoneHome);
|
||||||
|
if (workCompany) appendField('work_company', workCompany);
|
||||||
|
if (workCompanyAccNum) appendField('work_company_accountant_number', workCompanyAccNum);
|
||||||
|
if (workRegion) appendField('work_region', workRegion);
|
||||||
|
if (workProvinceId) appendField('work_province_id', parseInt(workProvinceId));
|
||||||
|
if (workPosition) appendField('work_position', workPosition);
|
||||||
|
if (workSalary) appendField('work_salary', parseInt(workSalary));
|
||||||
|
if (workStartedAt) appendField('work_started_at', workStartedAt);
|
||||||
|
appendField('card_number', rawCardNumber);
|
||||||
|
appendField('card_name', cardName);
|
||||||
|
appendField('card_month', cardMonth);
|
||||||
|
appendField('card_year', cardYear);
|
||||||
|
|
||||||
|
const addImage = (field, uri) => {
|
||||||
|
if (!uri) return;
|
||||||
|
const fileName = uri.split('/').pop();
|
||||||
|
const fileTypeMatch = fileName.match(/\.([a-zA-Z0-9]+)$/);
|
||||||
|
const type = fileTypeMatch ? `image/${fileTypeMatch[1]}` : 'image/jpeg';
|
||||||
|
formData.append(field, { uri, name: fileName || `${field}.jpg`, type });
|
||||||
|
};
|
||||||
|
|
||||||
|
addImage('passport_one', passportOne);
|
||||||
|
addImage('passport_two', passportTwo);
|
||||||
|
addImage('passport_three', passportThree);
|
||||||
|
addImage('passport_four', passportFour);
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await apiService.createLoanOrder(payload);
|
let res;
|
||||||
|
try {
|
||||||
|
const token = await authService.getStoredToken();
|
||||||
|
const response = await fetch(`${API_CONFIG.BASE_URL}/loan-order`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
const json = await response.json();
|
||||||
|
console.log('[LoanOrder] API status:', response.status, response.ok);
|
||||||
|
console.log('[LoanOrder] API response:', json);
|
||||||
|
res = { success: response.ok, ...(response.ok ? { message: json.message } : { error: json.message }) };
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[LoanOrder] API error', e);
|
||||||
|
res = { success: false, error: e.message };
|
||||||
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
Alert.alert('Success', res.message || 'Order created', [{ text: 'OK', onPress: () => navigation.goBack() }]);
|
Alert.alert('Success', res.message || 'Order created', [{ text: 'OK', onPress: () => navigation.goBack() }]);
|
||||||
|
|||||||
Reference in New Issue
Block a user