import React from 'react'; import { Alert, Button, FlatList, Linking, Platform, Text, TextInput, TouchableOpacity, View, } from 'react-native'; import { openComposer } from 'react-native-email-link'; // Reduxs import { connect } from 'react-redux'; import { deleteContact, setContact } from '../Store/Actions/contacts'; // Helpers import Helpers from '../Lib/Helpers'; // Translations import i18n from '../../I18n'; // Icons import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'; // Flash Messages import { showMessage } from 'react-native-flash-message'; // Overlay import { Overlay } from '@rneui/themed'; // Picker import { Picker } from '@react-native-picker/picker'; // Style import styles from '../../Resources/Styles/ContactStyle'; function mapStateToProps(state) { return { users: state.users.users, contacts: state.contacts, documents: state.documents, currentUser: state.app.currentUser, mainColor: state.app.mainColor, }; } /** * @typedef {(user: import('./../Models/User').User, data: import('./../Models/Contact').Contact) => void} setContact * @typedef {(user: import('./../Models/User').User, uuid: string ) => void} deleteContact * @typedef {(email: string ) => void} sendBrochure */ const mapDispatchToProps = dispatch => { return { setContact: (user, data) => dispatch(setContact(user, data)), deleteContact: (user, id) => dispatch(deleteContact(user, id)), sendBrochure: email => dispatch({ type: 'SEND_BROCHURE', data: email }), }; }; class ContactScreen extends React.Component { state = { contacts: [], sortType: 'asc', sortField: 'name', searchTxt: '', showSendBrochure: false, selectedDocument: -1, sendDocumentList: [], selectedSendBrochureEmail: -1, tmpSendBrochureEmail: '', tmpSendBrochureSubject: '', tmpSendBrochureMessage: '', sortedDocuments: [], sortedEmails: [], /** @type {number} The user index selected for transfert */ selectedTransferUserIndex: 0, /** @type {import('./../Models/Contact').Contact|null} The contact to transfert */ contactToTransfer: null, /** @type {boolean} Is tranfert contact model display ? */ showTransferContact: false, }; // * --- ACTIONS sendBrochure() { // FIXME: Si on n'a pas consulté les documents la liste des documents est vide apres initialisation if ( this.state.tmpSendBrochureEmail !== '' && this.state.tmpSendBrochureSubject !== '' && this.state.tmpSendBrochureMessage !== '' && this.state.sendDocumentList.length > 0 && Helpers.isEmailValid(this.state.tmpSendBrochureEmail) ) { /** @type {sendBrochure} */ const sendBrochure = this.props.sendBrochure; const email = { email: this.state.tmpSendBrochureEmail, subject: this.state.tmpSendBrochureSubject, message: this.state.tmpSendBrochureMessage, documents: JSON.stringify(this.state.sendDocumentList), app_user_id: this.props.currentUser.id, }; sendBrochure(email); this.setState({ showSendBrochure: false, tmpSendBrochureEmail: '', tmpSendBrochureSubject: '', tmpSendBrochureMessage: '', selectedSendBrochureEmail: -1, selectedDocument: -1, sendDocumentList: [], }); showMessage({ message: i18n.t('global.message_sent') + '.', description: i18n.t('global.message_will_be_sent_after_sync') + '.', type: 'success', duration: 1500, }); } else { Alert.alert( i18n.t('error.incomplete_form'), i18n.t('error.fill_all_fields_and_1_doc_min') + '.', ); } } transferContact() { /** @type {import('./../Models/User').User} */ const nextUser = this.props.users.filter( user => user.id !== this.props.currentUser.id, )[this.state.selectedTransferUserIndex]; /** @type {import('./../Models/Contact').ContactData} cloned contact */ const transferContact = this.state.contactToTransfer.toJSON(); if (transferContact === null) { throw new Error('No selected contact to transfert'); } // * Assign cloned contact to another user transferContact.send_to_app_user_id = nextUser.id; transferContact.timestamp = new Date(); transferContact.synced = false; /** @type {setContact} */ const setContactHook = this.props.setContact; setContactHook(this.props.currentUser, transferContact); this.setState({ showTransferContact: false, contactToTransfer: null }); showMessage({ message: i18n.t('contact_s.contact_transferred') + '.', description: i18n.t('contact_s.contact_will_be_sent_after_sync') + '.', type: 'success', duration: 1500, }); } /** * Delete contact * @param {import('../Models/Contact').Contact} contact */ deleteContactAction(contact) { Alert.alert( i18n.t('global.confirmation'), i18n.t('contact_s.confirm_contact_delete'), [ { text: i18n.t('global.no'), onPress: () => console.debug('Cancel Pressed'), style: 'cancel', }, { text: i18n.t('global.yes'), onPress: () => { this.setState({ contacts: [], sortedEmails: [] }); /** @type {setContact} */ const setContactHook = this.props.setContact; /** @type {import('./../Models/Contact').ContactData} */ const contactToDelete = contact.toJSON(); contactToDelete.to_delete = true; setContactHook(this.props.currentUser, contactToDelete); showMessage({ message: i18n.t('contact_s.contact_deleted') + '.', type: 'success', duration: 500, }); }, }, ], { cancelable: false }, ); } /** * Try to call the number * * @param {string} phone */ callNumberIfSupported(phone) { let phoneNumber = phone; if (Platform.OS !== 'android') { phoneNumber = `telprompt:${phone}`; } else { phoneNumber = `tel:${phone}`; } Linking.canOpenURL(phoneNumber) .then(supported => { if (supported) { return Linking.openURL(phoneNumber); } }) .catch(err => console.error(err)); } /** * Write a new email to * * @param {string} email */ composeNewEmailTo(email) { openComposer({ to: email, }); } // * END --- ACTIONS /** * Render the table header * @returns {JSX.Element} */ HeaderItem() { return ( { this.sortContacts('lastname'); }}> {i18n.t('global.lastname')} { this.sortContacts('email'); }}> {i18n.t('global.email')} { this.sortContacts('phone'); }}> {i18n.t('global.phone')} ); } /** * Render a line of contact * @param {import('../Models/Contact').Contact} contact * @returns */ Item(contact) { const displayName = String(contact.lastname ?? '').toUpperCase() + ' ' + (contact.firstname ?? ''); return ( this.props.navigation.navigate('ContactDetailsScreen', { action: 'edit', contactId: contact.id, }) }> {contact.lastname || contact.firstname ? displayName : contact.id} this.composeNewEmailTo(contact.email)}> {contact.email} contact.phone ? this.callNumberIfSupported(contact.phone) : false }> {contact.phone} { this.deleteContactAction(contact); }}> { this.setState({ showTransferContact: true, contactToTransfer: contact, }); }}> ); } sortContacts(field) { let sort; if (field !== this.state.sortField) { sort = 'asc'; } else { if (this.state.sortType === 'asc') { sort = 'desc'; } else { sort = 'asc'; } } this.setState({ contacts: this.state.contacts.sort(Helpers.compareValues(field, sort)), sortType: sort, sortField: field, }); } handleSearchBtn() { if (this.state.searchTxt.length > 0) { let obj = this.props.contacts; let array = Object.keys(obj).map(function (key) { return obj[key]; }); this.setState({ contacts: array.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc', searchTxt: '', }); } } handleSearchTxt(text) { this.setState({ searchTxt: text }); /** @type {Array} */ const contacts = this.props.contacts; if (text.length > 0) { const tmpContactsLastname = contacts.filter( item => item.lastname?.toLowerCase()?.indexOf(text.toLowerCase()) >= 0, ); const tmpContactsFirstname = contacts.filter( item => item.firstname?.toLowerCase()?.indexOf(text.toLowerCase()) >= 0, ); const tmpContactsEmail = contacts.filter( item => item.email.toLowerCase().indexOf(text.toLowerCase()) >= 0, ); const tmpContactsPhone = contacts.filter( item => item.phone?.toLowerCase()?.indexOf(text.toLowerCase()) >= 0, ); const resSearch = new Map(); tmpContactsLastname.forEach(contact => resSearch.set(contact.id, contact), ); tmpContactsFirstname.forEach(contact => resSearch.set(contact.id, contact), ); tmpContactsEmail.forEach(contact => resSearch.set(contact.id, contact)); tmpContactsPhone.forEach(contact => resSearch.set(contact.id, contact)); this.setState({ contacts: [...resSearch.values()].sort( Helpers.compareValues('name', 'asc'), ), sortType: 'asc', }); } else { let obj = this.props.contacts; let array = Object.keys(obj).map(function (key) { return obj[key]; }); this.setState({ contacts: array.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc', }); } } componentDidMount() { this.init(); } componentDidUpdate(prevProps, prevState, snapshot) { if (prevProps.contacts !== this.props.contacts) { this.init(); } } init() { let objContacts = this.props.contacts; let objDocs = this.props.documents; let arrayContacts = Object.keys(objContacts).map(function (key) { return objContacts[key]; }); let arrayEmails = Object.keys(objContacts).map(function (key) { return objContacts[key]; }); let arrayDocs = Object.keys(objDocs).map(function (key) { return objDocs[key]; }); const { action } = this.props.route.params; if (action === 'add') { this.props.navigation.navigate('ContactDetailsScreen', { action: 'add', }); } this.setState({ contacts: arrayContacts.sort(Helpers.compareValues('timestamp', 'desc')), sortedDocuments: arrayDocs.sort(Helpers.compareValues('title', 'asc')), sortedEmails: arrayEmails.sort(Helpers.compareValues('email', 'asc')), sortType: 'asc', sortField: 'name', }); } render() { const { contactAdded } = this.props.route.params; if (contactAdded === true) { this.props.navigation.setParams({ contactAdded: false }); showMessage({ message: i18n.t('contact_s.contact_added') + '.', type: 'success', duration: 500, }); } return ( {/* ACTIONS */}