This article will demonstrate how to create a Password Manager Application using React-Native. To assist users in securely storing and managing their passwords, we will develop a Password Manager mobile application using React Native for this project. The application will provide functionalities such as adding, viewing, copying, and deleting stored passwords.
Let’s take a look at how our completed project will look:
Prerequisites
- Introduction to React Native
- React Native Components
- React Hooks
- Node.js and Npm
Steps to Create React Native Application
Step 1: Create a React Native Application
Create a new React Native project for JokesGeneratorApp.
npx create-expo-app PasswordManagerApp
Step 2: Change the directory to the project folder:
cd PasswordManagerApp
Project Structure
Package.json
{
"dependencies": {
"react-native-paper": "4.9.2",
"@expo/vector-icons": "^13.0.0",
"react-native-vector-icons/FontAwesome": "*",
"react-native-vector-icons": "10.0.0"
}
}
Approach
This React Native app serves as a password manager. It allows users to add, edit, copy, and delete passwords for various websites. The app maintains a list of passwords, each containing website details, usernames, and masked passwords. Users can copy website names, usernames, and masked passwords to the clipboard for easy access. The app provides an editing feature, initiated by tapping the “Edit” button, enabling users to modify existing passwords.
Example: This example demonstrate a basic password manager where
- The function “maskPassword” receives a password string as input and returns the same password masked with asterisks.
- This copyText function enables users to effortlessly copy text, such as website URLs, usernames, and passwords, to their clipboard. Additionally, it sets a temporary alert message called “alertVisible” to notify users that the text has been successfully copied.
- The deletePassword function allows users to remove a password entry. It filters the passwords array, eliminating the specified password and providing a success message.
- The editPassword function is invoked when the user intends to modify an existing password entry. It activates the editing flag, consequently altering the behavior of the “Save Password” button.
- The renderPasswordList function generates a list of password entries based on the data in the passwords array. It then maps each password entry to a View, which includes details such as website, username, and a copy button.
Javascript
import React, { useState, useEffect } from "react" ; import { View, Text, TextInput, TouchableOpacity, ScrollView, StyleSheet, Clipboard, } from "react-native" ; import Icon from "react-native-vector-icons/FontAwesome" ; import { styles } from "./styles" ; const App = () => { const [website, setWebsite] = useState( "" ); const [username, setUsername] = useState( "" ); const [password, setPassword] = useState( "" ); const [passwords, setPasswords] = useState([]); const [alertVisible, setAlertVisible] = useState( false ); const [editing, setEditing] = useState( false ); const [editIndex, setEditIndex] = useState( null ); useEffect(() => { showPasswords(); }, []); const maskPassword = (pass) => { let str = "" ; for (let index = 0; index < pass.length; index++) { str += "*" ; } return str; }; const copyText = async (txt) => { try { await Clipboard.setString(txt); setAlertVisible( true ); setTimeout(() => { setAlertVisible( false ); }, 2000); } catch (error) { console.error( "Error copying text:" , error); } }; const deletePassword = (website) => { const updatedPasswords = passwords.filter( (e) => e.website !== website ); setPasswords(updatedPasswords); alert(`Successfully deleted ${website}'s password`); }; const showPasswords = () => { setPasswords([]); setWebsite( "" ); setUsername( "" ); setPassword( "" ); setEditing( false ); setEditIndex( null ); }; const savePassword = () => { // Check if any of the input fields is empty if (!website || !username || !password) { alert( "Please fill in all fields." ); return ; } if (editing && editIndex !== null ) { const updatedPasswords = [...passwords]; updatedPasswords[editIndex] = { website, username, password, }; setPasswords(updatedPasswords); setEditing( false ); setEditIndex( null ); } else { const newPassword = { website, username, password, }; setPasswords([...passwords, newPassword]); } setWebsite( "" ); setUsername( "" ); setPassword( "" ); }; const editPassword = (index) => { setEditing( true ); setEditIndex(index); setWebsite(passwords[index].website); setUsername(passwords[index].username); setPassword(passwords[index].password); }; const renderPasswordList = () => { return passwords.map((item, index) => ( <View style={styles.passwordItem} key={index}> <View style={styles.listItem}> <Text style={styles.listLabel}> Website: </Text> <Text style={styles.listValue}> {item.website} </Text> <TouchableOpacity style={styles.copyIcon} onPress={() => copyText(item.website) }> <Icon name= "copy" size={20} color= "#555" /> </TouchableOpacity> </View> <View style={styles.listItem}> <Text style={styles.listLabel}> Username: </Text> <Text style={styles.listValue}> {item.username} </Text> <TouchableOpacity style={styles.copyIcon} onPress={() => copyText(item.username) }> <Icon name= "copy" size={20} color= "#555" /> </TouchableOpacity> </View> <View style={styles.listItem}> <Text style={styles.listLabel}> Password: </Text> <Text style={styles.listValue}> {maskPassword(item.password)} </Text> <TouchableOpacity style={styles.copyIcon} onPress={() => copyText(item.password) }> <Icon name= "copy" size={20} color= "#555" /> </TouchableOpacity> </View> <View style={styles.buttonsContainer}> <TouchableOpacity style={styles.editButton} onPress={() => editPassword(index)}> <Icon name= "edit" size={20} color= "#fff" /> </TouchableOpacity> <TouchableOpacity style={styles.deleteButton} onPress={() => deletePassword(item.website)}> <Icon name= "trash" size={20} color= "white" /> </TouchableOpacity> </View> </View> )); }; return ( <ScrollView style={styles.container}> <View style={styles.content}> <Text style={styles.heading}> Password Manager </Text> <Text style={styles.subHeading}> Your Passwords {alertVisible && ( <Text id= "alert" > (Copied!)</Text> )} </Text> {passwords.length === 0 ? ( <Text style={styles.noData}> No Data To Show </Text> ) : ( <ScrollView horizontal> <View style={styles.table}> {renderPasswordList()} </View> </ScrollView> )} <Text style={styles.subHeading}> {editing ? "Edit Password" : "Add a Password" } </Text> <TextInput style={styles.input} placeholder= "Website" value={website} onChangeText={(text) => setWebsite(text) }/> <TextInput style={styles.input} placeholder= "Username" value={username} onChangeText={(text) => setUsername(text)}/> <TextInput style={styles.input} placeholder= "Password" secureTextEntry={ true } value={password} onChangeText={(text) => setPassword(text) }/> <TouchableOpacity style={styles.submitButton} onPress={savePassword}> <Text style={styles.submitButtonText}> {editing ? "Update Password" : "Add Password" } </Text> </TouchableOpacity> </View> </ScrollView> ); }; export default App; |
Javascript
// styles.js import { StyleSheet } from "react-native" ; const styles = StyleSheet.create({ container: { flex: 1, margin: 20, }, content: { margin: 15, }, heading: { fontSize: 30, fontWeight: "bold" , marginBottom: 15, textAlign: "center" , color: "#333" , }, subHeading: { fontSize: 23, fontWeight: "bold" , marginBottom: 10, color: "#333" , }, noData: { fontSize: 17, fontStyle: "italic" , marginBottom: 20, color: "#666" , }, table: { flexDirection: "row" , backgroundColor: "white" , borderRadius: 15, elevation: 4, marginBottom: 20, shadowColor: "grey" , shadowOffset: { width: 0, height: 0 }, shadowRadius: 5, shadowOpacity: 1, }, passwordItem: { flexDirection: "column" , alignItems: "center" , borderBottomWidth: 1, borderBottomColor: "#ddd" , padding: 15, }, listItem: { flexDirection: "row" , justifyContent: "space-between" , alignItems: "center" , marginRight: 10, marginBottom: 10, }, listLabel: { fontWeight: "bold" , marginBottom: 5, color: "#333" , fontSize: 19, }, listValue: { flex: 1, fontSize: 18, color: "#444" , paddingLeft: 10, }, copyIcon: { marginRight: 10, paddingLeft: 10, }, deleteButton: { backgroundColor: "red" , borderRadius: 4, padding: 5, marginLeft: 10, }, editButton: { backgroundColor: "blue" , borderRadius: 4, padding: 5, marginRight: 10, }, buttonsContainer: { flexDirection: "row" , }, input: { borderWidth: 2, borderColor: "#eee" , paddingVertical: 10, paddingHorizontal: 15, marginBottom: 20, fontSize: 16, borderRadius: 10, backgroundColor: "white" , shadowColor: "grey" , shadowOffset: { width: 0, height: 0 }, shadowRadius: 10, shadowOpacity: 1, elevation: 4, }, submitButton: { backgroundColor: "green" , color: "white" , fontWeight: "bold" , borderRadius: 10, paddingVertical: 15, paddingHorizontal: 30, shadowColor: "black" , shadowOffset: { width: 2, height: 2 }, shadowRadius: 15, shadowOpacity: 1, elevation: 4, }, submitButtonText: { color: "white" , textAlign: "center" , fontSize: 18, }, }); export { styles }; |
Steps to Run
To run react native application use the following command:
npx expo start
- To run on Android:
npx react-native run-android
- To run on iOS:
npx react-native run-ios
Output: