Hi,
I’m experiencing an issue with my claim system. The plan for my system is to let users claim “Verifiables” from a list page. When they click a “Claim” button, the following should occur:
Data Collections:
ClaimedVerifiables:
• Tracks each claim with fields:
_id (auto-generated)
userID (Text – unique user ID)
verifiableID (Text – unique ID of the verifiable)
claimedDate (Date/Time – when the claim was made)
Streaks:
• Tracks the user’s consecutive claim streak with fields:
_id (auto-generated)
userID (Text)
currentStreak (Number)
lastClaimDate (Date/Time – used to determine if the streak continues)
Claim Process:• When a user clicks “Claim”:
Check that the user hasn’t exceeded 3 active claims and hasn’t already claimed that verifiable.
If allowed, insert a record into ClaimedVerifiables.
Then update the user’s streak in the Streaks collection (incrementing if the claim is consecutive or resetting otherwise).
The Issue:I’m using the new backend model with .web.js files (wrapped in a webMethod) to expose the function processClaim from my backend module. However, when I click the claim button, I get this error:
"Error processing claim: TypeError: (0, u.processClaim) is not a function"
Other backend functions are working fine. I’ve republished and cleared caches, yet the error persists. Below is my complete front‑end and back‑end code.
This is the Backend code
import wixData from 'wix-data';
export async function processClaim(userId, verifiableId) {
// Check if the user already has 3 active claims.
const claimsQuery = await wixData.query("ClaimedVerifiables")
.eq("userID", userId)
.find();
if (claimsQuery.items.length >= 3) {
throw new Error("Claim limit reached.");
}
// Check if this verifiable is already claimed by the user.
const duplicateQuery = await wixData.query("ClaimedVerifiables")
.eq("userID", userId)
.eq("verifiableID", verifiableId)
.find();
if (duplicateQuery.items.length > 0) {
throw new Error("Verifiable already claimed.");
}
// Insert a new claim record.
const newClaim = {
userID: userId,
verifiableID: verifiableId,
claimedDate: new Date()
};
const insertedClaim = await wixData.insert("ClaimedVerifiables", newClaim);
// Update the user's streak.
await updateStreak(userId);
return insertedClaim;
}
async function updateStreak(userId) {
const today = new Date();
// Normalize today's date to midnight.
today.setHours(0, 0, 0, 0);
const streakQuery = await wixData.query("Streaks")
.eq("userID", userId)
.find();
if (streakQuery.items.length === 0) {
// No existing streak record; create one.
const newStreak = {
userID: userId,
currentStreak: 1,
lastClaimDate: today
};
await wixData.insert("Streaks", newStreak);
} else {
// Update the existing streak record.
const streakRecord = streakQuery.items[0];
const lastClaimDate = new Date(streakRecord.lastClaimDate);
lastClaimDate.setHours(0, 0, 0, 0);
// Calculate the day difference.
const diffDays = (today.getTime() - lastClaimDate.getTime()) / (1000 * 60 * 60 * 24);
if (diffDays >= 1) {
// If the user claimed exactly yesterday, increment the streak; otherwise, reset to 1.
if (diffDays === 1) {
streakRecord.currentStreak += 1;
} else {
streakRecord.currentStreak = 1;
}
streakRecord.lastClaimDate = today;
await wixData.update("Streaks", streakRecord);
}
}
}
This is the frontend code
import wixData from 'wix-data';
import wixUsers from 'wix-users';
import { authentication } from 'wix-members-frontend';
import { orders } from 'wix-pricing-plans-frontend';
import { processClaim } from 'backend/claimSystem.web'; // Import the claim function.
import { setupRefreshListeners } from 'public/globalRefresh.js';
$w.onReady(async function () {
// Attach the global refresh functionality.
setupRefreshListeners();
console.log("Page Ready - Setting up Repeaters");
// === MEMBERSHIP CHECK FOR GOLDEN VERIFIABLES ===
$w("#goldenRepeater").collapse();
let userTier = "free"; // Default to free tier
if (authentication.loggedIn()) {
try {
const ordersList = await orders.listCurrentMemberOrders();
console.log("User's Active Orders:", ordersList);
const activePlans = ordersList.filter(order => order.status === "ACTIVE");
const hasDiscovery = activePlans.some(order => order.planName === "Discovery Tier");
const hasMastery = activePlans.some(order => order.planName === "Mastery Tier");
if (hasDiscovery) userTier = "discovery";
if (hasMastery) userTier = "mastery";
if (userTier !== "free") {
console.log(`✅ Access Granted - Showing Golden VeriFiables for ${userTier} plan.`);
$w("#goldenRepeater").expand();
} else {
console.log("⛔ Access Denied - Keeping Golden VeriFiables Hidden");
}
} catch (err) {
console.error("Error Checking Membership:", err);
}
}
// Hide or show elements based on membership tier.
if (userTier !== "free") {
$w("#findGoldenButton").hide();
$w("#box3").hide();
} else {
$w("#findGoldenButton").show();
$w("#box3").show();
}
if (userTier === "free") {
$w("#goldenVeriFiablesTitle").hide();
} else {
$w("#goldenVeriFiablesTitle").show();
}
// === VERIFIABLES REPEATER (DYNAMIC DATASET) ===
const currentCategory = $w("#dynamicDataset").getCurrentItem()?.category || "default";
console.log("Current Category Slug:", currentCategory);
$w("#dynamicDataset")
.setFilter(wixData.filter().eq("category", currentCategory))
.then(() => {
console.log(`Filtered dataset for category: ${currentCategory}`);
})
.catch((err) => {
console.error("Error setting filter for Verifiables:", err);
});
// Function to set up each repeater item.
function setupRepeater($item, itemData, isFreeUser) {
console.log("Verifiables Repeater Item Data:", itemData);
const title = itemData.title || "No Title";
const image = itemData.image || "";
const description = itemData.sample || "No Description";
const vScore = itemData.vScore !== undefined ? itemData.vScore : 0;
const vRating = itemData.vRating || "No Rating";
$item("#text1").text = title;
$item("#image").src = image;
$item("#description").text = description;
$item("#vScoreBox").text = vScore.toString();
$item("#vrating").text = vRating;
let ratingColor = "#000000";
switch (vRating) {
case "Veri-Strong":
ratingColor = "#2E7D32";
break;
case "Veri-Lite":
ratingColor = "#F57C00";
break;
case "Veri-Bad":
ratingColor = "#B71C1C";
break;
case "Veri-Fi'd":
ratingColor = "#FFD700";
break;
}
$item("#vrating").style.color = ratingColor;
let backgroundColor = "#B71C1C";
if (vScore >= 20) {
backgroundColor = "#FFD700";
$item("#goldBox").show();
} else if (vScore >= 15) {
backgroundColor = "#2E7D32";
$item("#goldBox").hide();
} else if (vScore >= 13) {
backgroundColor = "#F57C00";
$item("#goldBox").hide();
} else {
$item("#goldBox").hide();
}
}
// Bind repeater items and add claim button functionality.
$w("#listRepeater").onItemReady(($item, itemData) => {
setupRepeater($item, itemData, userTier === "free");
$item("#claimButton").onClick(async () => {
const user = wixUsers.currentUser;
const userId = user.id;
const verifiableId = itemData._id; // Assumes _id is the verifiable's unique ID
try {
const result = await processClaim(userId, verifiableId);
console.log("Claim processed successfully:", result);
$item("#claimButton").label = "Claimed";
$item("#claimButton").disable();
} catch (error) {
console.error("Error processing claim:", error);
}
});
});
// === GOLDEN VERIFIABLES REPEATER FILTER ===
$w("#dataset1").onReady(() => {
$w("#dataset1")
.setFilter(wixData.filter().eq("category", currentCategory))
.then(() => {
console.log(`Filtered dataset for Golden VeriFiables: ${currentCategory}`);
})
.catch((err) => {
console.error("Error setting filter for Golden VeriFiables:", err);
});
});
// === GOLDEN VERIFIABLES REPEATER ===
$w("#goldenRepeater").onItemReady(($item, itemData) => {
console.log("Golden VeriFiables Repeater Item:", itemData);
const categorySlug = itemData.category
? itemData.category.replace(/\s+/g, "-").toLowerCase()
: "default";
const sanitizedTitle = itemData.title
? itemData.title.replace(/\s+/g, "-").toLowerCase()
: "untitled";
const dynamicLink = `/golden-verifiables/${categorySlug}/${sanitizedTitle}`;
console.log("Generated Golden VeriFiables Link:", dynamicLink);
$item("#goldenMoreButton").link = dynamicLink;
$item("#goldenText1").text = itemData.title || "No Title";
$item("#goldenImage").src = itemData.image || "";
$item("#goldenDescription").text = itemData.sample || "No Description";
$item("#goldenVScoreBox").text = itemData.vScore ? `${itemData.vScore}` : "...";
$item("#goldenVRating").text = itemData.vRating || "No Rating";
});
console.log("✅ All verifiables have been set up correctly.");
});
This is my first time ever coding or making a website so I apologize for how bad or unorganized the code probably is to experts. I just want to know if what im going for is possible so I know I'm not wasting my time.
Here is the website: Home | Verifinance
Hi Jacen, The issue is most likely that you are exporting the "processClaim" function directly from a .web.js file and not through a web method. I think you will find this tutorial helpful
Hope that helps. Eitan
Also as a sidenote to get to the page you have to click hub at the top, then specifically crypto and then you will be at the page.