From 9c3c626c46f589a00fcec8e70065ad0c9e3a3cc4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 18 Feb 2026 12:45:07 +0000 Subject: [PATCH] feat: add user job listing and summary helpers for dashboard flows --- src/lib/engine.js | 23 +++++++++++++++++++++++ test/engine.test.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/lib/engine.js b/src/lib/engine.js index b4bf62e..a78d568 100644 --- a/src/lib/engine.js +++ b/src/lib/engine.js @@ -120,6 +120,29 @@ class XArtAudioEngine { return this.jobs.get(jobId) || null; } + listJobsForUser(userId) { + if (!userId) { + return []; + } + + return Array.from(this.jobs.values()) + .filter((job) => job.callerUserId === userId) + .sort((a, b) => Number(b.id) - Number(a.id)); + } + + getUserSummary(userId) { + const jobs = this.listJobsForUser(userId); + const completed = jobs.filter((job) => job.status === "completed").length; + const totalCreditsSpent = jobs.reduce((sum, job) => sum + job.creditsCharged, 0); + + return { + balance: this.getWalletBalance(userId), + totalJobs: jobs.length, + completedJobs: completed, + totalCreditsSpent, + }; + } + getAsset(assetId) { return this.assets.get(String(assetId)) || null; } diff --git a/test/engine.test.js b/test/engine.test.js index d25eef2..9a7e113 100644 --- a/test/engine.test.js +++ b/test/engine.test.js @@ -118,3 +118,39 @@ test("non-owner must pay same credits to unlock, then has permanent access", () engine.unlockAudio(result.job.assetId, "u2"); assert.equal(engine.getWalletBalance("u2"), 4); }); + +test("lists jobs for user newest first and provides summary", () => { + const engine = createEngine(); + engine.topUpCredits("u1", 10, "topup-5"); + + engine.processMention({ + mentionPostId: "m5a", + callerUserId: "u1", + parentPost: { + id: "p5a", + authorId: "author-a", + article: { id: "a5a", title: "One", body: "x" }, + }, + }); + + engine.processMention({ + mentionPostId: "m5b", + callerUserId: "u1", + parentPost: { + id: "p5b", + authorId: "author-b", + article: { id: "a5b", title: "Two", body: "y" }, + }, + }); + + const jobs = engine.listJobsForUser("u1"); + assert.equal(jobs.length, 2); + assert.equal(jobs[0].mentionPostId, "m5b"); + assert.equal(jobs[1].mentionPostId, "m5a"); + + const summary = engine.getUserSummary("u1"); + assert.equal(summary.totalJobs, 2); + assert.equal(summary.completedJobs, 2); + assert.equal(summary.totalCreditsSpent, 2); + assert.equal(summary.balance, 8); +});