@mundogamernetwork/shared-ui 1.13.3 → 1.13.4
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.
|
@@ -32,6 +32,27 @@ const emit = defineEmits<{ (e: "navigate"): void }>();
|
|
|
32
32
|
/** Missions and the reward store live on Community for the whole ecosystem. */
|
|
33
33
|
const COMMUNITY_URL = "https://mundogamer.community";
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Dig out the payload regardless of how many envelopes wrap it.
|
|
37
|
+
*
|
|
38
|
+
* The API nests deeper than its own sendResponse() suggests — the gateway adds
|
|
39
|
+
* a second {message,data,status_code} layer on top, so the payload sits at
|
|
40
|
+
* response.data.data.data rather than response.data.data. Reading a fixed
|
|
41
|
+
* depth silently returned the inner envelope, which has no `level`, so the bar
|
|
42
|
+
* loaded and vanished on a perfectly good 200. Walking down until the shape
|
|
43
|
+
* appears survives either nesting.
|
|
44
|
+
*/
|
|
45
|
+
function unwrapSummary(payload: any): GamificationSummary | null {
|
|
46
|
+
let node = payload;
|
|
47
|
+
|
|
48
|
+
for (let depth = 0; depth < 4 && node && typeof node === "object"; depth += 1) {
|
|
49
|
+
if (node.level || node.wallet || node.missions) return node as GamificationSummary;
|
|
50
|
+
node = node.data;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
35
56
|
const summary = ref<GamificationSummary | null>(null);
|
|
36
57
|
const loaded = ref(false);
|
|
37
58
|
|
|
@@ -55,7 +76,12 @@ const destination = computed(() => {
|
|
|
55
76
|
const balance = computed(() => {
|
|
56
77
|
const fromHost = props.mgcBalance;
|
|
57
78
|
const value = fromHost !== null && fromHost !== undefined ? fromHost : summary.value?.wallet?.balance;
|
|
58
|
-
|
|
79
|
+
// The API sends the balance as a decimal string ("1801.50"), not a number.
|
|
80
|
+
const numeric = typeof value === "string" ? Number(value) : value;
|
|
81
|
+
|
|
82
|
+
return typeof numeric === "number" && Number.isFinite(numeric)
|
|
83
|
+
? Math.floor(numeric).toLocaleString()
|
|
84
|
+
: null;
|
|
59
85
|
});
|
|
60
86
|
|
|
61
87
|
// progress_percent comes from the API; the local computation is a fallback for
|
|
@@ -71,7 +97,7 @@ const percent = computed(() => {
|
|
|
71
97
|
onMounted(async () => {
|
|
72
98
|
try {
|
|
73
99
|
const response = await fetchGamificationSummary();
|
|
74
|
-
summary.value = response?.data
|
|
100
|
+
summary.value = unwrapSummary(response?.data);
|
|
75
101
|
} catch (error) {
|
|
76
102
|
// Never let a gamification hiccup break the header it sits in — but say
|
|
77
103
|
// so. Swallowing this silently made a deployed bar that renders nothing
|
package/package.json
CHANGED
|
@@ -18,7 +18,8 @@ export interface XpLevel {
|
|
|
18
18
|
|
|
19
19
|
export interface GamificationSummary {
|
|
20
20
|
level: XpLevel;
|
|
21
|
-
|
|
21
|
+
/** The API serialises these as decimal strings, not numbers. */
|
|
22
|
+
wallet: { balance: number | string; lifetime_earned: number | string };
|
|
22
23
|
missions: { active: any[]; claimable_count: number };
|
|
23
24
|
achievements: { total_unlocked: number; recent: any[] };
|
|
24
25
|
}
|