UNPKG

react-native-altcha

Version:
275 lines (274 loc) 7.29 kB
"use strict"; import { useEffect, useRef, useState } from 'react'; import { View, Text, Image, TextInput, TouchableOpacity, ActivityIndicator, StyleSheet, Keyboard, Alert } from 'react-native'; import { useAudioPlayer, useAudioPlayerStatus } from 'expo-audio'; import { AudioSvg, AudioStopSvg, ReloadSvg } from "./svg.js"; import { applyColorOpacity } from "./helpers.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; export const AltchaCodeChallenge = ({ audio, codeLength, image, payload, theme, onCancel, onReload, onSubmit, t }) => { const player = useAudioPlayer(); const playerStatus = useAudioPlayerStatus(player); const inputRef = useRef(null); const [isAudioLoading, setIsAudioLoading] = useState(false); const [currentAudioUri, setCurrentAudioUri] = useState(null); const [code, setCode] = useState(''); useEffect(() => { return () => { if (isAudioLoading && playerStatus.duration !== null && playerStatus.playing) { setIsAudioLoading(false); } }; }, [isAudioLoading, playerStatus]); async function fetchAudioAsDataUrl() { if (!audio) { throw new Error('Audio if not available.'); } const resp = await fetch(audio); if (resp.status !== 200) { throw new Error(`Server responded with ${resp.status}.`); } const blob = await resp.blob(); return new Promise(resolve => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); } function onAudioPress() { if (player.playing) { setIsAudioLoading(false); player.pause(); } else if (audio) { setIsAudioLoading(true); if (currentAudioUri !== audio) { setCurrentAudioUri(audio); fetchAudioAsDataUrl().then(uri => { player.replace({ uri: uri }); player.play(); }); } else { player.seekTo(0); player.play(); } } } function onVerifyPress() { const codeTrimmed = code.trim(); if (!codeTrimmed) { inputRef?.current?.focus(); Alert.alert(t.enterCode); return; } onSubmit(payload, codeTrimmed); Keyboard.dismiss(); } return /*#__PURE__*/_jsxs(View, { style: styles.container, accessibilityLabel: t.enterCode, children: [/*#__PURE__*/_jsx(View, { style: [styles.imageContainer, { borderColor: theme.borderColor }], children: /*#__PURE__*/_jsx(Image, { source: { uri: image }, style: styles.image, resizeMode: "contain", accessibilityRole: "image" }) }), /*#__PURE__*/_jsx(View, { style: styles.inputContainer, children: /*#__PURE__*/_jsx(TextInput, { ref: inputRef, value: code, onChangeText: setCode, placeholder: t.enterCode, placeholderTextColor: applyColorOpacity(theme.textColor, 0.6), style: [styles.input, { borderColor: theme.borderColor, color: theme.textColor }], maxLength: codeLength, autoCapitalize: "characters", autoCorrect: false, autoFocus: true, returnKeyType: "done", accessibilityLabel: t.enterCodeAria, importantForAccessibility: "yes", onSubmitEditing: onVerifyPress, onKeyPress: ({ nativeEvent }) => { if (nativeEvent.key === ' ') { onAudioPress(); } } }) }), /*#__PURE__*/_jsxs(View, { style: styles.controlsContainer, children: [/*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.iconButton, { borderColor: theme.borderColor }], onPress: onAudioPress, hitSlop: { top: 10, bottom: 10, left: 10, right: 10 }, accessibilityRole: "button", accessibilityLabel: t.getAudioChallenge, children: isAudioLoading ? /*#__PURE__*/_jsx(ActivityIndicator, { size: "small", color: theme.textColor }) : playerStatus.playing ? /*#__PURE__*/_jsx(AudioStopSvg, { color: theme.textColor }) : /*#__PURE__*/_jsx(AudioSvg, { color: theme.textColor }) }), onReload && /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.iconButton, { borderColor: theme.borderColor }], onPress: onReload, hitSlop: { top: 10, bottom: 10, left: 10, right: 10 }, accessibilityRole: "button", accessibilityLabel: t.reload, children: /*#__PURE__*/_jsx(ReloadSvg, { color: theme.textColor }) })] }), /*#__PURE__*/_jsxs(View, { children: [/*#__PURE__*/_jsx(View, { children: /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.verifyButton], onPress: onVerifyPress, accessibilityRole: "button", children: /*#__PURE__*/_jsx(Text, { style: styles.verifyText, children: t.verify }) }) }), onCancel && /*#__PURE__*/_jsx(View, { style: styles.cancelButtonContainer, children: /*#__PURE__*/_jsx(TouchableOpacity, { style: [styles.cancelButton], onPress: () => { onCancel?.(); }, accessibilityRole: "button", hitSlop: { top: 10, bottom: 10, left: 10, right: 10 }, children: /*#__PURE__*/_jsx(Text, { style: [styles.cancelButtonText, { color: theme.textColor }], children: t.cancel }) }) })] })] }); }; const styles = StyleSheet.create({ container: { width: '100%', alignSelf: 'center' }, imageContainer: { backgroundColor: '#fff', borderColor: '#ddd', borderRadius: 5, borderWidth: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginBottom: 12 }, image: { width: 180, height: 60, backgroundColor: '#ffffff' }, controlsContainer: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 12 }, iconButton: { borderColor: '#ddd', borderRadius: 5, borderWidth: 1, width: 40, height: 40, alignItems: 'center', justifyContent: 'center', padding: 8 }, inputContainer: { marginBottom: 12 }, input: { borderWidth: 1, borderColor: '#ddd', borderRadius: 5, paddingHorizontal: 12, paddingVertical: 10, fontSize: 16 }, verifyButton: { marginTop: 12, backgroundColor: '#007AFF', borderRadius: 5, paddingVertical: 12, alignItems: 'center', justifyContent: 'center' }, verifyText: { color: '#fff', fontWeight: '600', fontSize: 16 }, buttonDisabled: { opacity: 0.6 }, cancelButtonContainer: { marginTop: 24 }, cancelButton: { opacity: 0.7, alignItems: 'center', justifyContent: 'center' }, cancelButtonText: { fontSize: 16 }, errorText: { marginTop: 8, color: '#b00020' } }); //# sourceMappingURL=AltchaCodeChallenge.js.map