340 lines
8.2 KiB
TypeScript
340 lines
8.2 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import {
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
TextInput,
|
|
TouchableOpacity,
|
|
Alert,
|
|
ActivityIndicator,
|
|
SafeAreaView,
|
|
StatusBar
|
|
} from 'react-native';
|
|
import { WebView } from 'react-native-webview';
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
|
const STORAGE_KEY = '@condomob_url';
|
|
const DEFAULT_URL = 'https://condopay.fcarra.mywire.org';
|
|
|
|
export default function App() {
|
|
const [url, setUrl] = useState('');
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [isValidating, setIsValidating] = useState(false);
|
|
const [showWebView, setShowWebView] = useState(false);
|
|
|
|
useEffect(() => {
|
|
loadSavedUrl();
|
|
}, []);
|
|
|
|
const loadSavedUrl = async () => {
|
|
try {
|
|
const savedUrl = await AsyncStorage.getItem(STORAGE_KEY);
|
|
if (savedUrl) {
|
|
setUrl(savedUrl);
|
|
setShowWebView(true);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading saved URL:', error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
const validateUrl = (urlString: string): boolean => {
|
|
try {
|
|
const parsedUrl = new URL(urlString);
|
|
return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
|
|
} catch {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const isCondoPayUrl = (urlString: string): boolean => {
|
|
// Check if URL contains 'condopay' in the hostname
|
|
const lowerUrl = urlString.toLowerCase();
|
|
return lowerUrl.includes('condopay');
|
|
};
|
|
|
|
const handleConnect = async () => {
|
|
if (!url.trim()) {
|
|
Alert.alert('Errore', 'Inserisci un URL valido');
|
|
return;
|
|
}
|
|
|
|
// Add https:// if no protocol is provided
|
|
let finalUrl = url.trim();
|
|
if (!finalUrl.startsWith('http://') && !finalUrl.startsWith('https://')) {
|
|
finalUrl = 'https://' + finalUrl;
|
|
}
|
|
|
|
// Validate URL format
|
|
if (!validateUrl(finalUrl)) {
|
|
Alert.alert('Errore', 'L\'URL inserito non è valido');
|
|
return;
|
|
}
|
|
|
|
// Check if it's a CondoPay URL
|
|
if (!isCondoPayUrl(finalUrl)) {
|
|
Alert.alert(
|
|
'URL non valido',
|
|
'L\'URL deve puntare a un\'istanza di CondoPay (deve contenere "condopay" nel dominio)'
|
|
);
|
|
return;
|
|
}
|
|
|
|
setIsValidating(true);
|
|
|
|
// Try to validate by checking if the URL is reachable
|
|
try {
|
|
const response = await fetch(finalUrl, {
|
|
method: 'HEAD',
|
|
signal: AbortSignal.timeout(10000)
|
|
});
|
|
|
|
if (response.ok || response.status === 200 || response.status === 301 || response.status === 302) {
|
|
// Save URL and show WebView
|
|
await AsyncStorage.setItem(STORAGE_KEY, finalUrl);
|
|
setUrl(finalUrl);
|
|
setShowWebView(true);
|
|
} else {
|
|
Alert.alert('Errore', 'Impossibile connettersi all\'istanza di CondoPay');
|
|
}
|
|
} catch (error) {
|
|
// If fetch fails, still try to show the WebView - it might work
|
|
console.log('Validation fetch failed, trying WebView anyway:', error);
|
|
try {
|
|
await AsyncStorage.setItem(STORAGE_KEY, finalUrl);
|
|
setUrl(finalUrl);
|
|
setShowWebView(true);
|
|
} catch (storageError) {
|
|
Alert.alert('Errore', 'Impossibile salvare l\'URL');
|
|
}
|
|
} finally {
|
|
setIsValidating(false);
|
|
}
|
|
};
|
|
|
|
const handleBack = () => {
|
|
setShowWebView(false);
|
|
};
|
|
|
|
// Loading screen while checking for saved URL
|
|
if (isLoading) {
|
|
return (
|
|
<SafeAreaView style={styles.container}>
|
|
<View style={styles.content}>
|
|
<ActivityIndicator size="large" color="#007AFF" />
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
// WebView screen
|
|
if (showWebView) {
|
|
return (
|
|
<SafeAreaView style={styles.webViewContainer}>
|
|
<StatusBar barStyle="dark-content" />
|
|
<View style={styles.webViewHeader}>
|
|
<TouchableOpacity onPress={handleBack} style={styles.backButton}>
|
|
<Text style={styles.backButtonText}>← Indietro</Text>
|
|
</TouchableOpacity>
|
|
<Text style={styles.headerTitle} numberOfLines={1}>
|
|
CondoPay
|
|
</Text>
|
|
<View style={styles.placeholder} />
|
|
</View>
|
|
<WebView
|
|
source={{ uri: url }}
|
|
style={styles.webView}
|
|
startInLoadingState={true}
|
|
renderLoading={() => (
|
|
<View style={styles.loadingContainer}>
|
|
<ActivityIndicator size="large" color="#007AFF" />
|
|
<Text style={styles.loadingText}>Caricamento...</Text>
|
|
</View>
|
|
)}
|
|
/>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
// Configuration screen
|
|
return (
|
|
<SafeAreaView style={styles.container}>
|
|
<StatusBar barStyle="dark-content" />
|
|
<View style={styles.content}>
|
|
<View style={styles.logoContainer}>
|
|
<Text style={styles.logoText}>🏠</Text>
|
|
<Text style={styles.title}>CondoMob</Text>
|
|
<Text style={styles.subtitle}>Connetti al tuo CondoPay</Text>
|
|
</View>
|
|
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>URL Istanza CondoPay</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={url}
|
|
onChangeText={setUrl}
|
|
placeholder="https://condopay.example.com"
|
|
placeholderTextColor="#999"
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
keyboardType="url"
|
|
/>
|
|
<Text style={styles.hint}>
|
|
Inserisci l'URL della tua istanza CondoPay
|
|
</Text>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
style={[styles.button, isValidating && styles.buttonDisabled]}
|
|
onPress={handleConnect}
|
|
disabled={isValidating}
|
|
>
|
|
{isValidating ? (
|
|
<ActivityIndicator color="#fff" />
|
|
) : (
|
|
<Text style={styles.buttonText}>Connetti</Text>
|
|
)}
|
|
</TouchableOpacity>
|
|
|
|
<View style={styles.exampleContainer}>
|
|
<Text style={styles.exampleTitle}>Esempio:</Text>
|
|
<Text style={styles.exampleUrl}>{DEFAULT_URL}</Text>
|
|
</View>
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: '#f5f5f5',
|
|
},
|
|
content: {
|
|
flex: 1,
|
|
padding: 24,
|
|
justifyContent: 'center',
|
|
},
|
|
logoContainer: {
|
|
alignItems: 'center',
|
|
marginBottom: 40,
|
|
},
|
|
logoText: {
|
|
fontSize: 64,
|
|
marginBottom: 16,
|
|
},
|
|
title: {
|
|
fontSize: 32,
|
|
fontWeight: 'bold',
|
|
color: '#333',
|
|
marginBottom: 8,
|
|
},
|
|
subtitle: {
|
|
fontSize: 16,
|
|
color: '#666',
|
|
},
|
|
inputContainer: {
|
|
marginBottom: 24,
|
|
},
|
|
label: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: '#333',
|
|
marginBottom: 8,
|
|
},
|
|
input: {
|
|
backgroundColor: '#fff',
|
|
borderRadius: 12,
|
|
padding: 16,
|
|
fontSize: 16,
|
|
borderWidth: 1,
|
|
borderColor: '#ddd',
|
|
},
|
|
hint: {
|
|
fontSize: 12,
|
|
color: '#999',
|
|
marginTop: 8,
|
|
},
|
|
button: {
|
|
backgroundColor: '#007AFF',
|
|
borderRadius: 12,
|
|
padding: 16,
|
|
alignItems: 'center',
|
|
marginBottom: 24,
|
|
},
|
|
buttonDisabled: {
|
|
backgroundColor: '#99c2ff',
|
|
},
|
|
buttonText: {
|
|
color: '#fff',
|
|
fontSize: 18,
|
|
fontWeight: '600',
|
|
},
|
|
exampleContainer: {
|
|
alignItems: 'center',
|
|
marginTop: 20,
|
|
},
|
|
exampleTitle: {
|
|
fontSize: 14,
|
|
color: '#999',
|
|
marginBottom: 8,
|
|
},
|
|
exampleUrl: {
|
|
fontSize: 14,
|
|
color: '#007AFF',
|
|
fontFamily: 'monospace',
|
|
},
|
|
// WebView styles
|
|
webViewContainer: {
|
|
flex: 1,
|
|
backgroundColor: '#fff',
|
|
},
|
|
webViewHeader: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 12,
|
|
backgroundColor: '#fff',
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: '#ddd',
|
|
},
|
|
backButton: {
|
|
padding: 8,
|
|
},
|
|
backButtonText: {
|
|
fontSize: 16,
|
|
color: '#007AFF',
|
|
},
|
|
headerTitle: {
|
|
fontSize: 18,
|
|
fontWeight: '600',
|
|
color: '#333',
|
|
flex: 1,
|
|
textAlign: 'center',
|
|
},
|
|
placeholder: {
|
|
width: 60,
|
|
},
|
|
webView: {
|
|
flex: 1,
|
|
},
|
|
loadingContainer: {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
backgroundColor: '#fff',
|
|
},
|
|
loadingText: {
|
|
marginTop: 12,
|
|
fontSize: 16,
|
|
color: '#666',
|
|
},
|
|
});
|