This weekend, I implemented the payment methods loading functionality for the payment information tab in my e-commerce website. The main task was to create an asynchronous function that loads payment method information, including bank accounts and credit card accounts, from Firebase.
The Implementation
The core of this implementation is the loadPaymentMethods
function that retrieves payment information from Firebase. Here's a detailed breakdown of how it works:
async function loadPaymentMethods(userData) {
if (!userData) return null;
try {
// user profile reference
const userProfileRef = doc(db, "userProfiles", userData.email);
// references to bank and credit card documents
const bankAccountsRef = collection(userProfileRef, "bankAccounts");
const creditCardsRef = collection(userProfileRef, "creditCards");
// fetch bank and credit card information at the same time
const [bankAccountSnapshot, creditCardsSnapshot] = await Promise.all([
getDocs(bankAccountsRef),
getDocs(creditCardsRef)
]);
// map bank information to an object
const bankAccounts = bankAccountSnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data()
}));
// map credit card information to an object
const creditCardAccounts = creditCardsSnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data()
}));
return { bankAccounts, creditCardAccounts };
} catch (error) {
console.error("Error happened when fetching payment information");
throw error;
}
}
Key Components Explained
User Data Validation
The function starts with a simple but important check:
if (!userData) return null;
This ensures we have valid user data before proceeding. In a production environment, we could enhance this by returning a UI component to inform users when no data is available.
Firebase Document References
The function creates necessary references to access the Firebase documents:
User Profile Reference:
const userProfileRef = doc(db, "userProfiles", userData.email);
This creates a reference to the user's profile document using their email as the identifier.
Payment Method References:
const bankAccountsRef = collection(userProfileRef, "bankAccounts");
const creditCardsRef = collection(userProfileRef, "creditCards");
These references point to the subcollections containing bank and credit card information.
Parallel Data Fetching
One of the key optimizations is the use of Promise.all()
to fetch both bank and credit card data simultaneously:
const [bankAccountSnapshot, creditCardsSnapshot] = await Promise.all([
getDocs(bankAccountsRef),
getDocs(creditCardsRef)
]);
This approach is more efficient than sequential fetching as both requests are processed in parallel.
Data Mapping
The retrieved snapshots are then mapped to more usable objects:
const bankAccounts = bankAccountSnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data()
}));
This transformation makes the data easier to work with in the rest of the application, combining the document ID with its data.
Error Handling
The entire operation is wrapped in a try-catch block to handle potential errors gracefully:
try {
// ... implementation
} catch (error) {
console.error("Error happened when fetching payment information");
throw error;
}
Next Steps
In upcoming implementations, I'll be adding functionality to:
Handle credit card and bank account transactions
Update the UI to display payment method information
Implement error states and loading indicators
Stay tuned for the next post where I'll cover the transaction implementation details!
Top comments (0)