Overview
Today, I completed the implementation of user profile data loading, including profile pictures, stats, personal information, and shipping details. The next phase focused on updating the client-side payment tab and integrating it with Firebase to manage payout history. Here's how I tackled the challenge.
Firebase Structure
The existing database structure handled wallet balances and upcoming payouts but lacked functionality for viewing complete payout history. Users needed the ability to view and filter their payout history, including:
Payment status
Transaction amount
Order ID
Processing date
To address this, I created a subcollection within the userProfiles collection. This approach ensures users can access their payment methods, activity, reviews, and payout history through a single authenticated route.
Creating the Payouts Subcollection
To organize payout data, I:
Added a new subcollection named
/payouts
to theuserProfiles
collection.Implemented Firebase's auto-generated unique IDs for each payout record.
Defined the following fields for each payout:
amount
: Transaction valuedate
: Deposit dateorderId
: Unique order identifierprocessingDate
: Transaction processing timestampstatus
: Current state ("pending", "completed", "processing")type
: Payment method (credit card, debit card, online payment)
Firebase Rules Update
With the subcollection in place, I needed to update Firebase rules to grant users access to their payout data. Here's the updated rules configuration:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /userProfiles/{email} {
allow read: if request.auth != null && request.auth.token.email == email;
allow write: if request.auth != null && request.auth.token.email == email;
match /{subcollection}/{document=**} {
allow read, write: if request.auth != null && request.auth.token.email == email;
}
}
}
}
Key Points:
match /{subcollection}/{document=**}
: Grants access to all documents within the subcollection.allow read, write
: Ensures only authenticated users can access their data.Email Verification: Confirms the user's email matches the
userProfiles
document.
These rules ensure:
Users can only access their own data.
Subcollections (like payment information) are protected.
Unauthorized access attempts are blocked.
Loading Firebase Data To Client-side
After setting the rules correctly, now it was time to test, create the code to load the data from the backend to the frontend. I decide create async functon to call whenever the userData
is loaded from the checkUserStatus()
, once the data is loaded, then the function would run to have the data loaded, below is the code I implemented to do so.
async function loadProfileData() {
try {
const userData = await checkUserStatus();
console.log("User Data imported:", userData);
if (userData) {
loadPaymentInfoData(userData);
}
} catch (error) {
console.error("Error happened when loading userData from auth.js", error);
throw error;
}
}
Implementing loadPaymentInfoData
The loadPaymentInfoData
function handles loading and displaying payout information. Here's the breakdown:
async function loadPaymentInfoData(userData, filter = "all") {
if (userData) {
const walletData = userData.wallet;
// load wallet info
document.querySelector(
"#act-wallet-balance"
).textContent = `$${walletData.balance.toFixed(2)}`;
// ... rest of wallet data loading ...
try {
const payoutsRef = collection(
db,
"userProfiles",
userData.email,
"payouts"
);
let baseQuery = payoutsRef;
if (["pending", "completed", "processing"].includes(filter)) {
baseQuery = query(payoutsRef, where("status", "==", filter));
}
const querySnapShot = await getDocs(baseQuery);
const payoutDocs = Array.from(querySnapshot.docs);
let completedPayouts = 0;
let processingPayouts = 0;
let pendingPayouts = 0;
let totalPayoutAmount = 0;
// filters by today, this-week, or this-month
if (["today", "this-week", "this-month"].includes(filter)) {
}
const payoutItems = document.querySelectorAll(".payouts-item");
payoutDocs.forEach((doc) => {
if (doc.data().status == "completed") {
completedPayouts++;
} else if (doc.data().status == "pending") {
pendingPayouts++;
} else if (doc.data().status == "processing") {
processingPayouts++;
}
totalPayoutAmount += doc.data().amount;
});
payoutDocs.forEach((doc, index) => {
const currentItem = payoutItems[index];
const data = doc.data();
console.log("current index", currentItem);
currentItem.querySelector(".payout-id").textContent = data.payoutId;
// ... rest of payout data fields ...
document.querySelector(
"#totalPayoutAmount"
).textContent = `$${totalPayoutAmount}`;
// ... rest of pending, complete, and processing payouts ...
} catch (error) {
console.error("Error occured when fetching payouts:", error);
}
}
}
How It Works:
Fetching Data: The function queries the
/payouts
subcollection based on the user's email and optional filters.Counting Payouts: It iterates through the payout documents to count completed, pending, and processing payouts.
Updating the DOM: The function populates the client-side elements with the fetched data.
Challenges and Next Steps
While the implementation works, there are still a few areas to improve:
Filtering by Date: Implementing filters for "today," "this-week," and "this-month."
Dynamic Payout Loading: Generating payout items dynamically instead of relying on static elements.
Error Handling: Enhancing error handling for a smoother user experience.
I'll cover these updates in my next post, so stay tuned!
Conclusion
Building the payout history feature was a challenging but rewarding experience. By leveraging Firebase's powerful tools and structuring the data effectively, I was able to create a seamless experience for users to track their transactions. As I continue to refine this feature, I'm excited to see how it enhances the overall user experience for my startup.
Top comments (0)