NeoScan_Physician/app/modules/Auth/screens/ResetPasswordScreen.tsx

336 lines
9.7 KiB
TypeScript

"use client"
/*
* File: ResetPasswordScreen.tsx
* Description: Password reset screen with gradient background and shared components.
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import type React from "react"
import { useState, useEffect } from "react"
import { View, Text, StyleSheet, TextInput, TouchableOpacity } from "react-native"
import { Button } from "../../../../shared/src/components/Button"
import OnboardingContainer from "../components/OnboardingContainer"
import IconContainer from "../components/IconContainer"
import { Colors, Spacing, Typography } from "../../../../shared/src/theme"
import { showError, showSuccess } from "../../../../shared/src/utils/helpers/Toast"
import Icon from "react-native-vector-icons/Feather"
import { PasswordIconSVG } from "../../../../shared/src/components/Icons/SvgIcons"
import { authAPI } from "../services/authAPI"
import { useDispatch, useSelector } from "react-redux"
import { selectUser } from "../redux"
import { updateOnboarded } from "../redux/authSlice"
interface PasswordScreenProps {
onContinue: (password: string) => void
onBack: () => void
}
interface PasswordRule {
id: string
label: string
validator: (password: string) => boolean
isValid: boolean
}
const ResetPasswordScreen: React.FC = () => {
const [password, setPassword] = useState("")
const [confirmPassword, setConfirmPassword] = useState("")
const [isPasswordVisible, setPasswordVisible] = useState(false)
const [isConfirmPasswordVisible, setConfirmPasswordVisible] = useState(false)
const [loading, setLoading] = useState(false);
const user=useSelector(selectUser);
const dispatch=useDispatch()
const [passwordRules, setPasswordRules] = useState<PasswordRule[]>([
{
id: 'length',
label: 'At least 8 characters',
validator: (pwd: string) => pwd.length >= 8,
isValid: false
},
{
id: 'uppercase',
label: 'One uppercase letter',
validator: (pwd: string) => /[A-Z]/.test(pwd),
isValid: false
},
{
id: 'lowercase',
label: 'One lowercase letter',
validator: (pwd: string) => /[a-z]/.test(pwd),
isValid: false
},
{
id: 'number',
label: 'One number',
validator: (pwd: string) => /\d/.test(pwd),
isValid: false
},
{
id: 'special',
label: 'One special character',
validator: (pwd: string) => /[!@#$%^&*(),.?":{}|<>]/.test(pwd),
isValid: false
},
{
id: 'match',
label: 'Passwords match',
validator: (pwd:string) => {if(pwd.length > 0 && confirmPassword.length > 0 && pwd === confirmPassword){
return true
}else{
return false
}
}, // This will be handled separately
isValid: false
}
])
console.log('password rules',passwordRules)
const validatePassword = (pwd: string): boolean => {
return passwordRules.every(rule => rule.isValid)
}
const updatePasswordRules = (pwd: string) => {
setPasswordRules(prevRules =>
prevRules.map(rule => {
if (rule.id === 'match') {
return {
...rule,
isValid: pwd.length > 0 && confirmPassword.length > 0 && pwd === confirmPassword
}
}
return {
...rule,
isValid: rule.validator(pwd)
}
})
)
}
const updatePasswordMatchRule = () => {
setPasswordRules(prevRules =>
prevRules.map(rule => {
// if (rule.id === 'match') {
// return {
// ...rule,
// isValid: password.length > 0 && confirmPassword.length > 0 && password === confirmPassword
// }
// }
return rule
})
)
}
useEffect(() => {
updatePasswordRules(password)
}, [password,confirmPassword])
// useEffect(() => {
// updatePasswordMatchRule()
// }, [password, confirmPassword])
const handlePasswordChange = (pwd: string) => {
setPassword(pwd)
}
const handleConfirmPasswordChange = (pwd: string) => {
setConfirmPassword(pwd)
}
const handleContinue = () => {
if (!password.trim() || !confirmPassword.trim()) {
showError("Validation Error", "Both password fields are required.")
return
}
console.log('Validation',validatePassword(password))
if (!validatePassword(password)) {
showError("Validation Error", "Please meet all password requirements.")
return
}
if (password !== confirmPassword) {
showError("Validation Error", "Passwords do not match.")
return
}
setLoading(true)
setTimeout(() => {
setLoading(false)
onReset(password)
}, 1000)
}
const onBack=()=>{}
const onReset=async (password:string)=>{
const response :any=await authAPI.changepassword({password,token:user?.access_token});
console.log('reset response',response);
if(response.data&&response.data.message){
if(response.data.success){
showSuccess(response.data.message);
dispatch(updateOnboarded(true))
}else{
showError(response.data.message)
}
}else{
showError('eeror while changing password')
}
}
const renderPasswordRule = (rule: PasswordRule) => (
<View key={rule.id} style={styles.ruleContainer}>
<View style={[styles.checkbox, rule.isValid && styles.checkboxChecked]}>
{rule.isValid && (
<Icon name="check" size={12} color={"#FFFFFF"} />
)}
</View>
<Text style={[styles.ruleText, rule.isValid && styles.ruleTextValid]}>
{rule.label}
</Text>
</View>
)
return (
<OnboardingContainer onBack={onBack} showBackButton={false}>
<IconContainer Icon={()=><PasswordIconSVG/>} />
<Text style={styles.title}>Reset your password</Text>
<Text style={styles.subtitle}>Create a strong password with the following requirements</Text>
<View style={styles.inputContainer}>
<Icon name="lock" size={20} color={Colors.textSecondary} style={styles.inputIcon} />
<TextInput
placeholder="Password"
value={password}
onChangeText={handlePasswordChange}
style={styles.inputField}
secureTextEntry={!isPasswordVisible}
placeholderTextColor={Colors.textMuted}
/>
<TouchableOpacity onPress={() => setPasswordVisible(!isPasswordVisible)} style={styles.eyeIcon}>
<Icon name={isPasswordVisible ? "eye-off" : "eye"} size={22} color={Colors.textSecondary} />
</TouchableOpacity>
</View>
<View style={styles.inputContainer}>
<Icon name="lock" size={20} color={Colors.textSecondary} style={styles.inputIcon} />
<TextInput
placeholder="Confirm Password"
value={confirmPassword}
onChangeText={handleConfirmPasswordChange}
style={styles.inputField}
secureTextEntry={!isConfirmPasswordVisible}
placeholderTextColor={Colors.textMuted}
/>
<TouchableOpacity onPress={() => setConfirmPasswordVisible(!isConfirmPasswordVisible)} style={styles.eyeIcon}>
<Icon name={isConfirmPasswordVisible ? "eye-off" : "eye"} size={22} color={Colors.textSecondary} />
</TouchableOpacity>
</View>
{/* Password Rules Section */}
<View style={styles.rulesContainer}>
<Text style={styles.rulesTitle}>Password Requirements:</Text>
<View style={styles.rulesGrid}>
{passwordRules.map(renderPasswordRule)}
</View>
</View>
<Button title="Reset" onPress={handleContinue} style={styles.button} loading={loading} />
</OnboardingContainer>
)
}
const styles = StyleSheet.create({
title: {
fontFamily: Typography.fontFamily.bold,
fontSize: Typography.fontSize.title,
color: Colors.textPrimary,
textAlign: "center",
marginBottom: Spacing.sm,
},
subtitle: {
fontFamily: Typography.fontFamily.regular,
fontSize: Typography.fontSize.md,
color: Colors.textSecondary,
textAlign: "center",
marginBottom: Spacing.xl,
},
inputContainer: {
flexDirection: "row",
alignItems: "center",
backgroundColor: Colors.inputBackground,
borderWidth: 1,
borderColor: Colors.border,
borderRadius: 12,
marginBottom: Spacing.md,
paddingHorizontal: Spacing.md,
paddingVertical: 2,
},
inputIcon: {
marginRight: Spacing.sm,
},
inputField: {
flex: 1,
paddingVertical: Spacing.md,
fontSize: Typography.fontSize.md,
color: Colors.textPrimary,
},
eyeIcon: {
paddingLeft: Spacing.sm,
},
rulesContainer: {
marginTop: Spacing.sm,
marginBottom: Spacing.lg,
paddingHorizontal: Spacing.sm,
},
rulesTitle: {
fontFamily: Typography.fontFamily.medium,
fontSize: Typography.fontSize.sm,
color: Colors.textPrimary,
marginBottom: Spacing.sm,
},
rulesGrid: {
gap: Spacing.xs,
},
ruleContainer: {
flexDirection: "row",
alignItems: "center",
marginBottom: Spacing.xs,
},
checkbox: {
width: 18,
height: 18,
borderRadius: 4,
borderWidth: 2,
borderColor: Colors.border || "#E5E5E5",
backgroundColor: Colors.inputBackground || "#F8F9FA",
marginRight: Spacing.sm,
alignItems: "center",
justifyContent: "center",
},
checkboxChecked: {
backgroundColor: Colors.primary || "#007AFF",
borderColor: Colors.primary || "#007AFF",
},
ruleText: {
fontFamily: Typography.fontFamily.regular,
fontSize: Typography.fontSize.sm,
color: Colors.textSecondary,
flex: 1,
},
ruleTextValid: {
color: Colors.success || Colors.primary || "#28A745",
},
button: {
marginTop: Spacing.xl,
},
})
export default ResetPasswordScreen
/*
* End of File: ResetPasswordScreen.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/