@mundogamernetwork/shared-ui 1.13.4 → 1.13.5
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/components/ui/MgXpLevelBar.vue +36 -14
- package/package.json +1 -1
- package/services/httpService.ts +13 -3
|
@@ -5,13 +5,15 @@ import { fetchGamificationSummary, type GamificationSummary } from "../../servic
|
|
|
5
5
|
const props = withDefaults(
|
|
6
6
|
defineProps<{
|
|
7
7
|
/**
|
|
8
|
-
* Where to send the user to see and claim their tasks.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Where to send the user to see and claim their tasks. The missions
|
|
9
|
+
* list is centralized on network-accounts (one page, every platform,
|
|
10
|
+
* with cross-vertical filters) — leaving this unset points there,
|
|
11
|
+
* which is the right destination from every front. A front that still
|
|
12
|
+
* has its own local missions page should pass its own internal route
|
|
13
|
+
* here to avoid a full page load; most no longer do.
|
|
12
14
|
*/
|
|
13
15
|
missionsUrl?: string;
|
|
14
|
-
/** Locale segment for the default
|
|
16
|
+
/** Locale segment for the default network-accounts destination. */
|
|
15
17
|
locale?: string;
|
|
16
18
|
/** Renders without the title line, for tight spaces. */
|
|
17
19
|
compact?: boolean;
|
|
@@ -23,14 +25,25 @@ const props = withDefaults(
|
|
|
23
25
|
mgcBalance?: number | null;
|
|
24
26
|
/** Hide the balance where the host already shows it elsewhere. */
|
|
25
27
|
showBalance?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Pre-fetched summary from a call the host already makes elsewhere
|
|
30
|
+
* (e.g. its own dashboard composable, through its own configured HTTP
|
|
31
|
+
* client). When set — even to `null` while the host's own fetch is
|
|
32
|
+
* still resolving — this component skips its internal fetch entirely,
|
|
33
|
+
* avoiding a second request to the same endpoint through a second,
|
|
34
|
+
* independently-configured base URL that can drift from the host's
|
|
35
|
+
* own over time. Leave unset (`undefined`) to keep the original
|
|
36
|
+
* self-fetching behaviour.
|
|
37
|
+
*/
|
|
38
|
+
summary?: GamificationSummary | null;
|
|
26
39
|
}>(),
|
|
27
|
-
{ missionsUrl: "", locale: "", compact: false, mgcBalance: null, showBalance: true },
|
|
40
|
+
{ missionsUrl: "", locale: "", compact: false, mgcBalance: null, showBalance: true, summary: undefined },
|
|
28
41
|
);
|
|
29
42
|
|
|
30
43
|
const emit = defineEmits<{ (e: "navigate"): void }>();
|
|
31
44
|
|
|
32
|
-
/**
|
|
33
|
-
const
|
|
45
|
+
/** The centralized missions page lives on network-accounts for the whole ecosystem. */
|
|
46
|
+
const ACCOUNTS_URL = "https://accounts.mundogamer.network";
|
|
34
47
|
|
|
35
48
|
/**
|
|
36
49
|
* Dig out the payload regardless of how many envelopes wrap it.
|
|
@@ -53,8 +66,15 @@ function unwrapSummary(payload: any): GamificationSummary | null {
|
|
|
53
66
|
return null;
|
|
54
67
|
}
|
|
55
68
|
|
|
56
|
-
const
|
|
57
|
-
const
|
|
69
|
+
const fetchedSummary = ref<GamificationSummary | null>(null);
|
|
70
|
+
const selfLoaded = ref(false);
|
|
71
|
+
|
|
72
|
+
/** The host manages this prop as soon as it's bound, even before its own fetch resolves — `undefined` only when the prop was never passed at all. */
|
|
73
|
+
const isHostManaged = computed(() => props.summary !== undefined);
|
|
74
|
+
const summary = computed(() => (isHostManaged.value ? props.summary ?? null : fetchedSummary.value));
|
|
75
|
+
// Host-managed: loaded once the host's data actually arrives (an unresolved
|
|
76
|
+
// host fetch must keep showing the skeleton, not the empty/hidden state).
|
|
77
|
+
const loaded = computed(() => (isHostManaged.value ? summary.value !== null : selfLoaded.value));
|
|
58
78
|
|
|
59
79
|
const level = computed(() => summary.value?.level ?? null);
|
|
60
80
|
const claimable = computed(() => summary.value?.missions?.claimable_count ?? 0);
|
|
@@ -70,7 +90,7 @@ const destination = computed(() => {
|
|
|
70
90
|
(typeof document !== "undefined" ? document.documentElement.lang : "") ||
|
|
71
91
|
"en";
|
|
72
92
|
|
|
73
|
-
return `${
|
|
93
|
+
return `${ACCOUNTS_URL}/${locale}/account/missions`;
|
|
74
94
|
});
|
|
75
95
|
|
|
76
96
|
const balance = computed(() => {
|
|
@@ -95,18 +115,20 @@ const percent = computed(() => {
|
|
|
95
115
|
});
|
|
96
116
|
|
|
97
117
|
onMounted(async () => {
|
|
118
|
+
if (isHostManaged.value) return; // host supplies (and reactively updates) props.summary itself
|
|
119
|
+
|
|
98
120
|
try {
|
|
99
121
|
const response = await fetchGamificationSummary();
|
|
100
|
-
|
|
122
|
+
fetchedSummary.value = unwrapSummary(response?.data);
|
|
101
123
|
} catch (error) {
|
|
102
124
|
// Never let a gamification hiccup break the header it sits in — but say
|
|
103
125
|
// so. Swallowing this silently made a deployed bar that renders nothing
|
|
104
126
|
// indistinguishable from a bar that was never deployed, and cost hours
|
|
105
127
|
// of bundle forensics to tell apart.
|
|
106
128
|
console.warn("[MgXpLevelBar] gamification dashboard unavailable", error);
|
|
107
|
-
|
|
129
|
+
fetchedSummary.value = null;
|
|
108
130
|
} finally {
|
|
109
|
-
|
|
131
|
+
selfLoaded.value = true;
|
|
110
132
|
}
|
|
111
133
|
});
|
|
112
134
|
</script>
|
package/package.json
CHANGED
package/services/httpService.ts
CHANGED
|
@@ -37,6 +37,19 @@ export function getHttpService(): AxiosInstance {
|
|
|
37
37
|
withCredentials: true,
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
// Dev-only bearer token injection lives on `defaults.headers.common` rather
|
|
41
|
+
// than inside the request interceptor below: axios 1.19's `mergeConfig`
|
|
42
|
+
// (invoked on every dispatch via resolveConfig.js) converts an AxiosHeaders
|
|
43
|
+
// instance to a plain object via `{ ...thing }` before merging, and an
|
|
44
|
+
// Authorization value set inside a request interceptor does not survive
|
|
45
|
+
// that spread — it never reaches the server. Already discovered and fixed
|
|
46
|
+
// the same way in jobs-frontend's own httpService.ts; this file had the
|
|
47
|
+
// same bug independently. `defaults.headers.common` goes through axios's
|
|
48
|
+
// own default-header merge path instead, which does not hit it.
|
|
49
|
+
if (import.meta.env.VITE_APP_ENV !== "production" && import.meta.env.VITE_BEARER_TOKEN) {
|
|
50
|
+
_httpService.defaults.headers.common.Authorization = `Bearer ${import.meta.env.VITE_BEARER_TOKEN}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
_httpService.interceptors.response.use(
|
|
41
54
|
(response) => response,
|
|
42
55
|
(error) => {
|
|
@@ -88,9 +101,6 @@ export function getHttpService(): AxiosInstance {
|
|
|
88
101
|
config.params = { ...config.params, lang };
|
|
89
102
|
|
|
90
103
|
if (import.meta.env.VITE_APP_ENV !== "production" && typeof window !== "undefined") {
|
|
91
|
-
if (import.meta.env.VITE_BEARER_TOKEN) {
|
|
92
|
-
config.headers.Authorization = `Bearer ${import.meta.env.VITE_BEARER_TOKEN}`;
|
|
93
|
-
}
|
|
94
104
|
config.headers.set("X-Timezone", Intl.DateTimeFormat().resolvedOptions().timeZone);
|
|
95
105
|
}
|
|
96
106
|
|