/*
Предрейсовые осмотры - мобильное приложение
Компонент модального окна с полем ввода
*/
//---------------------
//Подключение библиотек
//---------------------
const React = require('react'); //React
const { Modal, View, TextInput, Pressable, Platform, StyleSheet, BackHandler } = require('react-native'); //Базовые компоненты
const AppText = require('./AppText'); //Общий текстовый компонент
const AppButton = require('./AppButton'); //Кнопка
const styles = require('../../styles/common/InputDialog.styles'); //Стили диалога
const OVERLAY_Z = 9999;
//-----------
//Тело модуля
//-----------
//Модальное окно с полем ввода
function InputDialog(
{
visible,
title = 'Ввод данных',
label,
value = '',
placeholder,
keyboardType = 'default',
autoCapitalize = 'none',
confirmText = 'Сохранить',
cancelText = 'Отмена',
onConfirm,
onCancel,
validator,
errorMessage
},
ref
) {
//Локальное значение для редактирования
const [inputValue, setInputValue] = React.useState(value);
const inputRef = React.useRef(null);
//На Android поле ввода изначально не фокусируемо, чтобы нативный слой видел «нет фокуса» и перехватывал сканер с первого символа (как на остальных экранах)
const [inputFocusable, setInputFocusable] = React.useState(Platform.OS !== 'android');
const focusFirstEditableInput = React.useCallback(() => {
if (inputRef.current && typeof inputRef.current.focus === 'function') {
inputRef.current.focus();
}
}, []);
React.useImperativeHandle(
ref,
function exposeScannerApi() {
return {
setValueFromScanner(val) {
setInputValue(val != null ? String(val) : '');
if (Platform.OS === 'android') setInputFocusable(true);
focusFirstEditableInput();
}
};
},
[focusFirstEditableInput]
);
//После включения фокусируемости на Android — ставим фокус на поле (после setValueFromScanner)
React.useEffect(
function focusWhenFocusable() {
if (Platform.OS !== 'android' || !inputFocusable) return;
focusFirstEditableInput();
},
[inputFocusable, focusFirstEditableInput]
);
const [error, setError] = React.useState('');
const [isFocused, setIsFocused] = React.useState(false);
//Сброс значения и фокусируемости только при открытии диалога
const prevVisibleRef = React.useRef(false);
React.useEffect(() => {
const justOpened = visible && !prevVisibleRef.current;
prevVisibleRef.current = visible;
if (justOpened) {
setInputValue(value);
setError('');
if (Platform.OS === 'android') setInputFocusable(false);
}
}, [visible, value]);
//Кнопка «Назад» на Android при overlay (без Modal) закрывает диалог
React.useEffect(
function backHandler() {
if (Platform.OS !== 'android' || !visible) return;
const sub = BackHandler.addEventListener('hardwareBackPress', function onBack() {
handleCancel();
return true;
});
return function remove() {
sub.remove();
};
},
[visible, handleCancel]
);
//Обработчик фокуса
const handleFocus = React.useCallback(() => {
setIsFocused(true);
}, []);
//Обработчик потери фокуса
const handleBlur = React.useCallback(() => {
setIsFocused(false);
}, []);
//Обработчик изменения текста
const handleChangeText = React.useCallback(text => {
setInputValue(text);
setError('');
}, []);
//Валидация введённого значения
const validateInput = React.useCallback(() => {
if (typeof validator === 'function') {
const validationResult = validator(inputValue);
if (validationResult !== true) {
setError(validationResult || errorMessage || 'Некорректное значение');
return false;
}
}
return true;
}, [inputValue, validator, errorMessage]);
//Обработчик подтверждения
const handleConfirm = React.useCallback(() => {
if (!validateInput()) {
return;
}
if (typeof onConfirm === 'function') {
onConfirm(inputValue.trim());
}
}, [inputValue, validateInput, onConfirm]);
//Обработчик отмены
const handleCancel = React.useCallback(() => {
if (typeof onCancel === 'function') {
onCancel();
}
}, [onCancel]);
//Обработчик закрытия по кнопке "Назад" (Android)
const handleRequestClose = React.useCallback(() => {
handleCancel();
}, [handleCancel]);
const preventKeyActions = Platform.OS === 'android';
const closePressableProps = preventKeyActions ? { focusable: false } : {};
const cancelButtonFocusable = preventKeyActions ? false : undefined;
const confirmButtonFocusable = preventKeyActions ? false : undefined;
const dialogContent = (
{title}
×
{label ? (
{label}
) : null}
{error ? (
{error}
) : null}
);
if (!visible) return null;
if (Platform.OS === 'android') {
return (
{dialogContent}
);
}
return (
{dialogContent}
);
}
//----------------
//Интерфейс модуля
//----------------
module.exports = React.forwardRef(InputDialog);