mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-24 21:17:55 +00:00
1f8da810e0
- Fix shadow style deprecation warnings across components (boxShadow) - Add type declaration files (codec.d.ts, modules.d.ts) - Update metro.config.cjs for proper asset extensions - Update tsconfig.json with module resolution settings - Fix TypeScript errors in shared/lib files - Update app icons (optimized PNG files)
347 lines
9.2 KiB
TypeScript
347 lines
9.2 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
Modal,
|
|
View,
|
|
Text,
|
|
TextInput,
|
|
TouchableOpacity,
|
|
StyleSheet,
|
|
Alert,
|
|
ActivityIndicator,
|
|
} from 'react-native';
|
|
import { KurdistanColors } from '../theme/colors';
|
|
import { useTheme } from '../contexts/ThemeContext';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
|
|
interface ChangePasswordModalProps {
|
|
visible: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
const ChangePasswordModal: React.FC<ChangePasswordModalProps> = ({
|
|
visible,
|
|
onClose,
|
|
}) => {
|
|
const { colors } = useTheme();
|
|
const { changePassword, resetPassword, user } = useAuth();
|
|
const [currentPassword, setCurrentPassword] = useState('');
|
|
const [newPassword, setNewPassword] = useState('');
|
|
const [confirmPassword, setConfirmPassword] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const handleSubmit = async () => {
|
|
// Validation
|
|
if (!currentPassword) {
|
|
Alert.alert('Error', 'Please enter your current password');
|
|
return;
|
|
}
|
|
|
|
if (!newPassword || newPassword.length < 6) {
|
|
Alert.alert('Error', 'New password must be at least 6 characters long');
|
|
return;
|
|
}
|
|
|
|
if (newPassword !== confirmPassword) {
|
|
Alert.alert('Error', 'Passwords do not match');
|
|
return;
|
|
}
|
|
|
|
if (currentPassword === newPassword) {
|
|
Alert.alert('Error', 'New password must be different from current password');
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
|
|
// First verify current password by re-authenticating
|
|
const { error: verifyError } = await changePassword(newPassword, currentPassword);
|
|
|
|
setLoading(false);
|
|
|
|
if (verifyError) {
|
|
Alert.alert('Error', verifyError.message || 'Failed to change password');
|
|
} else {
|
|
Alert.alert('Success', 'Password changed successfully');
|
|
setCurrentPassword('');
|
|
setNewPassword('');
|
|
setConfirmPassword('');
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
const handleClose = () => {
|
|
setCurrentPassword('');
|
|
setNewPassword('');
|
|
setConfirmPassword('');
|
|
onClose();
|
|
};
|
|
|
|
const handleForgotPassword = () => {
|
|
if (!user?.email) {
|
|
Alert.alert('Error', 'No email address found for this account');
|
|
return;
|
|
}
|
|
|
|
Alert.alert(
|
|
'Reset Password',
|
|
`A password reset link will be sent to ${user.email}`,
|
|
[
|
|
{ text: 'Cancel', style: 'cancel' },
|
|
{
|
|
text: 'Send Reset Link',
|
|
onPress: async () => {
|
|
const { error } = await resetPassword(user.email!);
|
|
if (error) {
|
|
Alert.alert('Error', error.message || 'Failed to send reset email');
|
|
} else {
|
|
Alert.alert('Success', 'Password reset link sent to your email. Please check your inbox.');
|
|
handleClose();
|
|
}
|
|
},
|
|
},
|
|
]
|
|
);
|
|
};
|
|
|
|
const styles = createStyles(colors);
|
|
|
|
return (
|
|
<Modal
|
|
visible={visible}
|
|
animationType="fade"
|
|
transparent={true}
|
|
onRequestClose={handleClose}
|
|
>
|
|
<View style={styles.overlay}>
|
|
<View style={styles.container}>
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<Text style={styles.headerTitle}>Change Password</Text>
|
|
<TouchableOpacity onPress={handleClose} style={styles.closeButton}>
|
|
<Text style={styles.closeButtonText}>✕</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Content */}
|
|
<View style={styles.content}>
|
|
<Text style={styles.description}>
|
|
To change your password, first enter your current password, then your new password.
|
|
</Text>
|
|
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>Current Password</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={currentPassword}
|
|
onChangeText={setCurrentPassword}
|
|
placeholder="Enter current password"
|
|
placeholderTextColor={colors.textSecondary}
|
|
secureTextEntry
|
|
autoCapitalize="none"
|
|
editable={!loading}
|
|
/>
|
|
</View>
|
|
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>New Password</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={newPassword}
|
|
onChangeText={setNewPassword}
|
|
placeholder="Enter new password"
|
|
placeholderTextColor={colors.textSecondary}
|
|
secureTextEntry
|
|
autoCapitalize="none"
|
|
editable={!loading}
|
|
/>
|
|
</View>
|
|
|
|
<View style={styles.inputContainer}>
|
|
<Text style={styles.label}>Confirm Password</Text>
|
|
<TextInput
|
|
style={styles.input}
|
|
value={confirmPassword}
|
|
onChangeText={setConfirmPassword}
|
|
placeholder="Confirm new password"
|
|
placeholderTextColor={colors.textSecondary}
|
|
secureTextEntry
|
|
autoCapitalize="none"
|
|
editable={!loading}
|
|
/>
|
|
</View>
|
|
|
|
{newPassword.length > 0 && newPassword.length < 6 && (
|
|
<Text style={styles.errorText}>
|
|
Password must be at least 6 characters
|
|
</Text>
|
|
)}
|
|
|
|
{confirmPassword.length > 0 && newPassword !== confirmPassword && (
|
|
<Text style={styles.errorText}>Passwords do not match</Text>
|
|
)}
|
|
|
|
{/* Forgot Password Link */}
|
|
<TouchableOpacity
|
|
onPress={handleForgotPassword}
|
|
style={styles.forgotPasswordButton}
|
|
disabled={loading}
|
|
>
|
|
<Text style={styles.forgotPasswordText}>Forgot Password?</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Footer */}
|
|
<View style={styles.footer}>
|
|
<TouchableOpacity
|
|
style={styles.cancelButton}
|
|
onPress={handleClose}
|
|
disabled={loading}
|
|
>
|
|
<Text style={styles.cancelButtonText}>Cancel</Text>
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={[
|
|
styles.submitButton,
|
|
(loading || !currentPassword || !newPassword || newPassword !== confirmPassword || newPassword.length < 6) &&
|
|
styles.submitButtonDisabled,
|
|
]}
|
|
onPress={handleSubmit}
|
|
disabled={loading || !currentPassword || !newPassword || newPassword !== confirmPassword || newPassword.length < 6}
|
|
>
|
|
{loading ? (
|
|
<ActivityIndicator color={KurdistanColors.spi} />
|
|
) : (
|
|
<Text style={styles.submitButtonText}>Change Password</Text>
|
|
)}
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
const createStyles = (colors: any) => StyleSheet.create({
|
|
overlay: {
|
|
flex: 1,
|
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
container: {
|
|
width: '90%',
|
|
maxWidth: 400,
|
|
backgroundColor: colors.surface,
|
|
borderRadius: 16,
|
|
overflow: 'hidden',
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
padding: 20,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: colors.border,
|
|
},
|
|
headerTitle: {
|
|
fontSize: 20,
|
|
fontWeight: 'bold',
|
|
color: colors.text,
|
|
},
|
|
closeButton: {
|
|
width: 32,
|
|
height: 32,
|
|
borderRadius: 16,
|
|
backgroundColor: colors.background,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
closeButtonText: {
|
|
fontSize: 20,
|
|
color: colors.textSecondary,
|
|
},
|
|
content: {
|
|
padding: 20,
|
|
},
|
|
description: {
|
|
fontSize: 14,
|
|
color: colors.textSecondary,
|
|
marginBottom: 20,
|
|
lineHeight: 20,
|
|
},
|
|
inputContainer: {
|
|
marginBottom: 16,
|
|
},
|
|
label: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: colors.text,
|
|
marginBottom: 8,
|
|
},
|
|
input: {
|
|
height: 48,
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
borderRadius: 8,
|
|
paddingHorizontal: 16,
|
|
fontSize: 16,
|
|
color: colors.text,
|
|
backgroundColor: colors.background,
|
|
},
|
|
errorText: {
|
|
fontSize: 13,
|
|
color: KurdistanColors.sor,
|
|
marginTop: -8,
|
|
marginBottom: 8,
|
|
},
|
|
forgotPasswordButton: {
|
|
marginTop: 8,
|
|
paddingVertical: 8,
|
|
},
|
|
forgotPasswordText: {
|
|
fontSize: 14,
|
|
color: KurdistanColors.kesk,
|
|
fontWeight: '600',
|
|
textAlign: 'center',
|
|
},
|
|
footer: {
|
|
flexDirection: 'row',
|
|
padding: 20,
|
|
borderTopWidth: 1,
|
|
borderTopColor: colors.border,
|
|
gap: 12,
|
|
},
|
|
cancelButton: {
|
|
flex: 1,
|
|
paddingVertical: 14,
|
|
borderRadius: 8,
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
alignItems: 'center',
|
|
},
|
|
cancelButtonText: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
color: colors.text,
|
|
},
|
|
submitButton: {
|
|
flex: 1,
|
|
paddingVertical: 14,
|
|
borderRadius: 8,
|
|
backgroundColor: KurdistanColors.kesk,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
submitButtonDisabled: {
|
|
opacity: 0.5,
|
|
},
|
|
submitButtonText: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
color: KurdistanColors.spi,
|
|
},
|
|
});
|
|
|
|
export default ChangePasswordModal;
|