diff --git a/packages/ponder/src/api/admin.ts b/packages/ponder/src/api/admin.ts index 0c2a1a8..a1e0bf6 100644 --- a/packages/ponder/src/api/admin.ts +++ b/packages/ponder/src/api/admin.ts @@ -1,5 +1,5 @@ import { ponder } from "@/generated"; -import { eq } from "@ponder/core"; +import { countDistinct, eq, inArray } from "@ponder/core"; import { type Address, isAddress } from "viem"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -78,6 +78,86 @@ ponder.get("/admin/:wallet/campaigns", async (ctx) => { }); // Get all the campaign stats for a wallet +ponder.get("/admin/:wallet/campaignsStats", async (ctx) => { + // Extract wallet + const wallet = ctx.req.param("wallet") as Address; + if (!isAddress(wallet)) { + return ctx.text("Invalid wallet address", 400); + } + + // Get the tables we will query + const { + ProductAdministrator, + Campaign, + ReferralCampaignStats, + InteractionEvent, + ProductInteractionContract, + } = ctx.tables; + + // Perform the sql query + const campaignsStats = await ctx.db + .select({ + productId: ProductAdministrator.productId, + isOwner: ProductAdministrator.isOwner, + roles: ProductAdministrator.roles, + id: Campaign.id, + name: Campaign.name, + bank: Campaign.bankingContractId, + totalInteractions: ReferralCampaignStats.totalInteractions, + openInteractions: ReferralCampaignStats.openInteractions, + readInteractions: ReferralCampaignStats.readInteractions, + referredInteractions: ReferralCampaignStats.referredInteractions, + createReferredLinkInteractions: + ReferralCampaignStats.createReferredLinkInteractions, + purchaseStartedInteractions: + ReferralCampaignStats.purchaseStartedInteractions, + purchaseCompletedInteractions: + ReferralCampaignStats.purchaseCompletedInteractions, + totalRewards: ReferralCampaignStats.totalRewards, + }) + .from(ProductAdministrator) + .innerJoin( + Campaign, + eq(ProductAdministrator.productId, Campaign.productId) + ) + .innerJoin( + ReferralCampaignStats, + eq(Campaign.id, ReferralCampaignStats.campaignId) + ) + .where(eq(ProductAdministrator.user, wallet)); + + // Get the unique wallet on this product + if (campaignsStats.length === 0) { + return ctx.json({ stats: [] }); + } + + // Get all the product ids for this admin + const campaignProductIds = campaignsStats.map((c) => c.productId); + const uniqueProductIds = [...new Set(campaignProductIds)]; + + // Get the total number of unique users per product + const totalPerProducts = await ctx.db + .select({ + productId: ProductInteractionContract.productId, + wallets: countDistinct(InteractionEvent.user), + }) + .from(InteractionEvent) + .innerJoin( + ProductInteractionContract, + eq(InteractionEvent.interactionId, ProductInteractionContract.id) + ) + .where(inArray(ProductInteractionContract.productId, uniqueProductIds)) + .groupBy(ProductInteractionContract.productId); + + // Return the result as json + return ctx.json({ + stats: campaignsStats, + users: totalPerProducts, + }); +}); + +// Get all the campaign stats for a wallet +// todo: For legacy purpose only, to be removed once prod is updated ponder.get("/admin/:wallet/campaigns/stats", async (ctx) => { // Extract wallet const wallet = ctx.req.param("wallet") as Address; @@ -103,8 +183,10 @@ ponder.get("/admin/:wallet/campaigns/stats", async (ctx) => { referredInteractions: ReferralCampaignStats.referredInteractions, createReferredLinkInteractions: ReferralCampaignStats.createReferredLinkInteractions, - purchaseStartedInteractions: ReferralCampaignStats.purchaseStartedInteractions, - purchaseCompletedInteractions: ReferralCampaignStats.purchaseCompletedInteractions, + purchaseStartedInteractions: + ReferralCampaignStats.purchaseStartedInteractions, + purchaseCompletedInteractions: + ReferralCampaignStats.purchaseCompletedInteractions, totalRewards: ReferralCampaignStats.totalRewards, }) .from(ProductAdministrator)