326 lines
12 KiB
TypeScript
326 lines
12 KiB
TypeScript
|
import React, { useEffect, useState } from 'react';
|
||
|
import { Alert, BackHandler, StyleSheet, ScrollView, View, TextInput, Text, Button } from 'react-native';
|
||
|
import { useNavigation, NavigationProp, useFocusEffect } from '@react-navigation/native';
|
||
|
import { RootStackParamList } from '@/types';
|
||
|
import { DB } from '@/components/lib/db';
|
||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||
|
import { cfg } from '@/components/lib/cfg';
|
||
|
import Ionicons from '@expo/vector-icons/Ionicons';
|
||
|
import config from '../../components/data/config.json';
|
||
|
|
||
|
const formatTimestamp = () => {
|
||
|
const now = new Date();
|
||
|
const year = now.getFullYear();
|
||
|
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are zero-based
|
||
|
const day = String(now.getDate()).padStart(2, '0');
|
||
|
const hours = String(now.getHours()).padStart(2, '0');
|
||
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||
|
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||
|
};
|
||
|
|
||
|
|
||
|
const ToInsert = function (array: any, table: any, wht: any) {
|
||
|
array = array ? array : [];
|
||
|
wht = wht ? wht : [];
|
||
|
table = table ? table : "example";
|
||
|
let s = array;
|
||
|
if (s.length > 0) {
|
||
|
var y = Object.keys(s[0]);
|
||
|
var x = '';
|
||
|
x += 'INSERT INTO ';
|
||
|
x += table;
|
||
|
x += '(';
|
||
|
x += y.map(function (u) {
|
||
|
return ` ${u} `
|
||
|
}).join(',');
|
||
|
x += ')';
|
||
|
x += '\n';
|
||
|
x += 'SELECT ';
|
||
|
x += y.map(function (g) {
|
||
|
return `a.${g}`;
|
||
|
});
|
||
|
x += ' FROM (';
|
||
|
x += s.map(function (w: any) {
|
||
|
var f = ` SELECT `;
|
||
|
f += y.map(function (q) {
|
||
|
if (w[q] != null) {
|
||
|
if (typeof w[q] === 'boolean') {
|
||
|
return `${w[q]} AS ${q}`;
|
||
|
}
|
||
|
if (typeof w[q] === 'number') {
|
||
|
return `${w[q]} AS ${q}`;
|
||
|
}
|
||
|
if (typeof w[q] === 'object' && w[q] == null) {
|
||
|
return `null AS ${q}`;
|
||
|
}
|
||
|
if (w[q] == 'timestamp') {
|
||
|
return `now() AS ${q}`;
|
||
|
}
|
||
|
return `'${w[q].toString().replace(/\"/g, "\\\"")}' AS ${q}`;
|
||
|
}
|
||
|
else {
|
||
|
return `'-' AS ${q}`;
|
||
|
}
|
||
|
}).join(",");
|
||
|
return f;
|
||
|
}).join("\n UNION ALL \n")
|
||
|
x += ') a';
|
||
|
if (Array.isArray(wht) && wht.length > 0) {
|
||
|
x += ` LEFT JOIN ${table} ON `
|
||
|
x += wht.map(function (whtx) {
|
||
|
return ` ${table}.${whtx} = a.${whtx} `;
|
||
|
}).join(" AND ");
|
||
|
x += ` WHERE `;
|
||
|
x += wht.map(function (whtx) {
|
||
|
return ` ${table}.${whtx} IS NULL `;
|
||
|
}).join(" AND ");
|
||
|
}
|
||
|
return x;
|
||
|
} else {
|
||
|
return [];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
export const SimpanCustomerData = function (data: any) {
|
||
|
let datax: { [key: string]: any }[] = [{ // Changed type to allow multiple elements
|
||
|
name: data.name ? data.name : 'Sales 2'
|
||
|
, company_id: data.company_id ? data.company_id : 1
|
||
|
, email: data.email ? data.email : 'sales2@rumahjo.com'
|
||
|
, contact_address_complete: data.street ? data.street : ''
|
||
|
, street: data.street ? data.street : ''
|
||
|
, street2: data.street2 ? data.street2 : ''
|
||
|
, city: data.city ? data.city : 'Malang'
|
||
|
, zip: data.zip ? data.zip : '65125'
|
||
|
, country_id: data.country_id ? data.country_id : null
|
||
|
, lang: data.lang ? data.lang : 'id_ID'
|
||
|
, tz: data.tz ? data.tz : 'Asia/Jakarta'
|
||
|
, type: data.type ? data.type : 'contact'
|
||
|
, phone: data.phone ? data.phone : ''
|
||
|
, mobile: data.mobile ? data.mobile : ''
|
||
|
, active: data.active ? data.active : true
|
||
|
, is_company: data.is_company ? data.is_company : false
|
||
|
, partner_share: data.partner_share ? data.partner_share : true
|
||
|
, write_date: data.write_date ? data.write_date : 'timestamp'
|
||
|
, email_normalized: data.email_normalized ? data.email_normalized : 'sales2@rumahjo.com'
|
||
|
, supplier_rank: data.supplier_rank ? data.supplier_rank : 0
|
||
|
, customer_rank: data.customer_rank ? data.customer_rank : 0
|
||
|
, invoice_warn: data.invoice_warn ? data.invoice_warn : 'no-message'
|
||
|
, sale_warn: data.sale_warn ? data.sale_warn : 'no-message'
|
||
|
, calendar_last_notif_ack: data.calendar_last_notif_ack ? data.calendar_last_notif_ack : 'timestamp'
|
||
|
, vies_valid: data.vies_valid ? data.vies_valid : false
|
||
|
, l10n_id_kode_transaksi: data.l10n_id_kode_transaksi ? data.l10n_id_kode_transaksi : 10
|
||
|
, l10n_id_pkp: data.l10n_id_pkp ? data.l10n_id_pkp : false
|
||
|
, followup_reminder_type: data.followup_reminder_type ? data.followup_reminder_type : "automatic"
|
||
|
}];
|
||
|
let databaru = datax.map((s: any) => {
|
||
|
let d: { [key: string]: any } = {};
|
||
|
let o = Object.keys(s);
|
||
|
o.forEach((sv: any) => {
|
||
|
if (s[sv] != null) {
|
||
|
d[sv] = s[sv];
|
||
|
}
|
||
|
})
|
||
|
return d;
|
||
|
});
|
||
|
return ToInsert(databaru, "res_partner", [])
|
||
|
}
|
||
|
|
||
|
const FormCustomerScreen = () => {
|
||
|
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
||
|
|
||
|
const [Action, setAction] = useState({});
|
||
|
|
||
|
const [name, setName] = useState('');
|
||
|
const [email, setEmail] = useState('');
|
||
|
const [street, setStreet] = useState('')
|
||
|
const [street2, setStreet2] = useState('')
|
||
|
const [city, setCity] = useState('')
|
||
|
const [zip, setZip] = useState('')
|
||
|
const [country, setCountry] = useState('')
|
||
|
const [countryName, setCountryName] = useState('')
|
||
|
const [phone, setPhone] = useState('')
|
||
|
const [mobile, setMobile] = useState('')
|
||
|
|
||
|
|
||
|
const cekEmail = function(text:any) {
|
||
|
// Ekspresi reguler untuk memeriksa format email
|
||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
|
return emailRegex.test(text);
|
||
|
}
|
||
|
|
||
|
const loadAction = function(){
|
||
|
// cfg.inputAction.customer.negara(100)
|
||
|
|
||
|
setAction({
|
||
|
openMenuAddCustomer: async function (prop: any) {
|
||
|
await AsyncStorage.setItem('contactActive', prop?.email);
|
||
|
await AsyncStorage.setItem('contactActiveData', prop?.data);
|
||
|
if (cfg.action['detailcontactOpen']) {
|
||
|
await cfg.action['detailcontactOpen']()
|
||
|
}
|
||
|
navigation.navigate('detailcontact');
|
||
|
},
|
||
|
SimpanCustomer: function (prop: any) {
|
||
|
let data = SimpanCustomerData({});
|
||
|
DB(data).then(function () {
|
||
|
Alert.alert("Succes", "Data berhasil disimpan");
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
useEffect(() => {
|
||
|
(async function () {
|
||
|
let [ct]:{ id: string; name: string }[] = await DB(`SELECT * FROM res_country
|
||
|
WHERE lower(name->>'en_US') LIKE '%indo%'`) as { id: string; name: string }[];
|
||
|
setCountryName(ct.name["en_US"])
|
||
|
setCountry(ct.id.toString())
|
||
|
loadAction();
|
||
|
})();
|
||
|
|
||
|
}, []
|
||
|
)
|
||
|
|
||
|
|
||
|
useFocusEffect(
|
||
|
React.useCallback(() => {
|
||
|
const onBackPress = () => {
|
||
|
navigation.navigate("customer");
|
||
|
return true; // Prevent default behavior (exit app)
|
||
|
};
|
||
|
|
||
|
BackHandler.addEventListener('hardwareBackPress', onBackPress);
|
||
|
navigation.setOptions({ headerLeft: () => null }); // Remove back button
|
||
|
|
||
|
return () => {
|
||
|
BackHandler.removeEventListener('hardwareBackPress', onBackPress);
|
||
|
};
|
||
|
}, [navigation])
|
||
|
);
|
||
|
|
||
|
cfg.action['formcustomer'] = ()=>{
|
||
|
loadAction()
|
||
|
}
|
||
|
return (
|
||
|
<>
|
||
|
<Text style={[styles.title, {margin:0, paddingTop:30}]}> <Ionicons name='person' color={'white'} size={16}></Ionicons> Tambah Customer</Text>
|
||
|
<ScrollView contentContainerStyle={[styles.container, {padding:10}]}>
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Nama</Text>
|
||
|
<TextInput onChangeText={setName} value={name} style={styles.input} placeholder="..." />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Email</Text>
|
||
|
<TextInput onChangeText={setEmail} value={email} style={styles.input} placeholder="..." keyboardType="email-address" />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Telepon</Text>
|
||
|
<TextInput onChangeText={setPhone} value={phone} style={styles.input} placeholder="..." keyboardType="phone-pad" />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Telepon Mobile</Text>
|
||
|
<TextInput onChangeText={setMobile} value={mobile} style={styles.input} placeholder="..." keyboardType="phone-pad" />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Alamat</Text>
|
||
|
<TextInput onChangeText={setStreet} value={street} style={[styles.input, {marginBottom:10}]} placeholder="..." multiline />
|
||
|
<TextInput onChangeText={setStreet2} value={street2} style={styles.input} placeholder="..." multiline />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Kota</Text>
|
||
|
<TextInput onChangeText={setCity} value={city} style={styles.input} placeholder="..." />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Kode Pos</Text>
|
||
|
<TextInput onChangeText={setZip} value={zip} style={styles.input} placeholder="..." keyboardType="numeric" />
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.inputContainer}>
|
||
|
<Text style={styles.label}>Negara</Text>
|
||
|
<TextInput readOnly={true} value={country} style={[styles.input,{backgroundColor:"#eee", display:"none"}]} placeholder="..." />
|
||
|
<TextInput readOnly={true} value={countryName} style={[styles.input,{backgroundColor:"#eee"}]} placeholder="..." />
|
||
|
</View>
|
||
|
|
||
|
</ScrollView>
|
||
|
<Button title="Simpan" onPress={() => {
|
||
|
if(name === ''){
|
||
|
Alert.alert('Warning','Nama tidak boleh kosong')
|
||
|
}
|
||
|
else if(email === ''){
|
||
|
Alert.alert('Warning','Email tidak boleh kosong')
|
||
|
}
|
||
|
else if(!cekEmail(email)){
|
||
|
Alert.alert('Warning','Format harus email')
|
||
|
}
|
||
|
else if(country === ''){
|
||
|
Alert.alert('Warning','Negara tidak boleh kosong')
|
||
|
}
|
||
|
else{
|
||
|
let data = SimpanCustomerData({
|
||
|
name:name,
|
||
|
country_id : Number(country),
|
||
|
city : city,
|
||
|
street : street,
|
||
|
street2 : street2,
|
||
|
mobile : mobile,
|
||
|
phone : phone,
|
||
|
email_normalized : email,
|
||
|
email : email,
|
||
|
zip:zip
|
||
|
});
|
||
|
DB(data).then(function () {
|
||
|
Alert.alert("Succes", "Data berhasil disimpan");
|
||
|
navigation.navigate('customer');
|
||
|
})
|
||
|
}
|
||
|
}} style={styles.saveButton} />
|
||
|
</>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
const styles = StyleSheet.create({
|
||
|
container: {
|
||
|
flexGrow: 1,
|
||
|
backgroundColor: '#fff',
|
||
|
},
|
||
|
title: {
|
||
|
fontSize: 18,
|
||
|
fontWeight: 'bold',
|
||
|
color: '#fff',
|
||
|
textAlign: 'center',
|
||
|
backgroundColor: config.color.primary,
|
||
|
paddingVertical: 15,
|
||
|
flexDirection:"row",
|
||
|
justifyContent:"center",
|
||
|
alignItems:"center"
|
||
|
},
|
||
|
inputContainer: {
|
||
|
marginBottom: 15,
|
||
|
},
|
||
|
label: {
|
||
|
fontSize: 16,
|
||
|
marginBottom: 5,
|
||
|
},
|
||
|
input: {
|
||
|
borderWidth: 1,
|
||
|
borderColor: '#ddd',
|
||
|
borderRadius: 5,
|
||
|
padding: 10,
|
||
|
fontSize: 16,
|
||
|
backgroundColor: '#f9f9f9',
|
||
|
},
|
||
|
saveButton: {
|
||
|
backgroundColor: config.color.primary,
|
||
|
borderRadius: 50,
|
||
|
marginTop: 20,
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export default FormCustomerScreen;
|