@playbasis-ai/qwikcard-sdk 2.3.16 → 2.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -79,6 +79,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
79
79
 
80
80
  - Improved empty-state guidance and skeletons in dashboard quest/badge/leaderboard panels.
81
81
 
82
+ ## [2.3.17] - 2026-01-30
83
+
84
+ ### Fixed
85
+
86
+ - Use quest catalog when player progress is empty so quests render immediately.
87
+ - Support array responses for player quests/badges.
88
+
89
+ ## [2.3.18] - 2026-01-30
90
+
91
+ ### Fixed
92
+
93
+ - Accept top-level leaderboard entries in API responses.
94
+
95
+ ## [2.3.19] - 2026-01-31
96
+
97
+ ### Fixed
98
+
99
+ - Normalize leaderboard entries across `entries/items/leaderboard` response shapes.
100
+ - Restore badge detail modal header styling in the embedded widget.
101
+
82
102
  ## [2.3.11] - 2026-01-29
83
103
 
84
104
  ### Changed
@@ -1 +1 @@
1
- {"version":3,"file":"QwikCardApp.d.ts","sourceRoot":"","sources":["../src/QwikCardApp.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAwRD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CAMlD"}
1
+ {"version":3,"file":"QwikCardApp.d.ts","sourceRoot":"","sources":["../src/QwikCardApp.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAqSD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CAMlD"}
@@ -31,10 +31,11 @@ function AppContent({ leaderboardId }) {
31
31
  if (!playerId) {
32
32
  throw new Error('Missing playerId for widget bootstrap');
33
33
  }
34
- const [player, balances, quests, allBadges, playerBadges, rewards] = await Promise.all([
34
+ const [player, balances, playerQuests, questCatalog, allBadges, playerBadges, rewards] = await Promise.all([
35
35
  client.getPlayer(playerId),
36
36
  client.getBalances(playerId),
37
37
  client.getPlayerQuests(playerId),
38
+ client.getQuests(),
38
39
  client.getBadges(),
39
40
  client.getPlayerBadges(playerId),
40
41
  client.getRewards().catch(() => []), // Gracefully handle if rewards endpoint doesn't exist
@@ -72,23 +73,33 @@ function AppContent({ leaderboardId }) {
72
73
  earnedDelta: 0,
73
74
  qwikCoins,
74
75
  },
75
- goals: quests.map((q) => ({
76
- goalId: q.id,
77
- type: 'financial',
78
- target: q.target,
79
- current: q.progress,
80
- progressPct: q.target > 0 ? Math.round((q.progress / q.target) * 100) : 0,
81
- startDate: new Date().toISOString().slice(0, 10),
82
- endDate: q.expiresAt ?? new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
83
- status: q.status === 'completed' ? 'completed' : q.status === 'expired' ? 'at_risk' : 'on_track',
84
- rewards: {
85
- xp: q.rewards?.find((r) => r.type === 'points')?.amount || 100,
86
- badges: (q.rewards
87
- ?.filter((r) => r.type === 'badge')
88
- .map((r) => r.badgeId)
89
- .filter(Boolean) || []),
90
- },
91
- })),
76
+ goals: (() => {
77
+ const quests = playerQuests.length > 0 ? playerQuests : questCatalog;
78
+ const nowIso = new Date().toISOString().slice(0, 10);
79
+ return quests.map((q) => ({
80
+ goalId: q.id,
81
+ type: 'financial',
82
+ target: q.target ?? 1,
83
+ current: q.progress ?? 0,
84
+ progressPct: q.target && q.target > 0
85
+ ? Math.round(((q.progress ?? 0) / q.target) * 100)
86
+ : 0,
87
+ startDate: nowIso,
88
+ endDate: q.expiresAt ?? new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
89
+ status: q.status === 'completed'
90
+ ? 'completed'
91
+ : q.status === 'expired'
92
+ ? 'at_risk'
93
+ : 'on_track',
94
+ rewards: {
95
+ xp: q.rewards?.find((r) => r.type === 'points')?.amount || 100,
96
+ badges: (q.rewards
97
+ ?.filter((r) => r.type === 'badge')
98
+ .map((r) => r.badgeId)
99
+ .filter(Boolean) || []),
100
+ },
101
+ }));
102
+ })(),
92
103
  badges: allBadges.map((b) => ({
93
104
  id: b.id,
94
105
  name: b.name,
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -162,6 +162,8 @@ export class PlaybasisClient {
162
162
  }
163
163
  async getPlayerQuests(playerId) {
164
164
  const data = await this.request('GET', `/players/${encodeURIComponent(playerId)}/quests`);
165
+ if (Array.isArray(data))
166
+ return data;
165
167
  return data.quests || data.items || [];
166
168
  }
167
169
  async getQuestProgress(playerId, questId) {
@@ -177,6 +179,8 @@ export class PlaybasisClient {
177
179
  }
178
180
  async getPlayerBadges(playerId) {
179
181
  const data = await this.request('GET', `/players/${encodeURIComponent(playerId)}/badges`);
182
+ if (Array.isArray(data))
183
+ return data;
180
184
  return data.badges || data.items || [];
181
185
  }
182
186
  // ─────────────────────────────────────────────────────────────────────────
@@ -204,9 +208,40 @@ export class PlaybasisClient {
204
208
  if (options?.cursor)
205
209
  params.set('cursor', options.cursor);
206
210
  const data = await this.request('GET', `/leaderboards/${encodeURIComponent(leaderboardId)}?${params}`);
211
+ const leaderboardData = data;
212
+ const entries = 'entries' in data
213
+ ? data.entries
214
+ : 'items' in data
215
+ ? data.items
216
+ : leaderboardData.leaderboard?.entries;
217
+ const total = 'total' in data && typeof data.total === 'number'
218
+ ? data.total
219
+ : leaderboardData.leaderboard?.total ?? entries?.length ?? 0;
220
+ const normalizedEntries = (entries || []).map((entry, index) => {
221
+ const raw = entry;
222
+ const score = typeof raw.score === 'number'
223
+ ? raw.score
224
+ : typeof raw.balance === 'number'
225
+ ? raw.balance
226
+ : typeof raw.points === 'number'
227
+ ? raw.points
228
+ : typeof raw.value === 'number'
229
+ ? raw.value
230
+ : 0;
231
+ const rank = typeof raw.rank === 'number' ? raw.rank : index + 1;
232
+ const displayName = raw.displayName || raw.name || raw.playerId || 'Player';
233
+ const playerId = raw.playerId || raw.id || displayName;
234
+ return {
235
+ playerId,
236
+ displayName,
237
+ rank,
238
+ score,
239
+ metadata: raw.metadata,
240
+ };
241
+ });
207
242
  return {
208
- entries: data.leaderboard?.entries || [],
209
- total: data.leaderboard?.total || 0,
243
+ entries: normalizedEntries,
244
+ total,
210
245
  };
211
246
  }
212
247
  async getPlayerRank(leaderboardId, playerId) {