@mundogamernetwork/shared-ui 1.16.6 → 1.16.8

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.
@@ -14,6 +14,7 @@ const { performLogout } = useLogout();
14
14
 
15
15
  const runtimeConfig = useRuntimeConfig();
16
16
  const accountsBaseUrl = runtimeConfig.public.mgSharedUi?.accountsBaseUrl || runtimeConfig.public.accountsBaseUrl;
17
+ const supportUrl = `${accountsBaseUrl}/account/support/new`;
17
18
  const features = runtimeConfig.public.mgSharedUi?.features ?? {};
18
19
  const pricingUrl = runtimeConfig.public.mgSharedUi?.pricingUrl || "";
19
20
  const { locale } = useI18n();
@@ -47,7 +48,10 @@ onUnmounted(() => {
47
48
  });
48
49
 
49
50
  const handleLogout = async () => {
50
- await performLogout(`${accountsBaseUrl}/login`);
51
+ // No explicit redirect — performLogout defaults to the current page,
52
+ // so logging out keeps you on this site (now as a guest) instead of
53
+ // bouncing to accounts' login page. See useLogout.ts.
54
+ await performLogout();
51
55
  };
52
56
 
53
57
  const handleToggleOnline = () => {
@@ -58,6 +62,20 @@ const handleToggleOnline = () => {
58
62
  </script>
59
63
 
60
64
  <template>
65
+ <!--
66
+ The 'signed-in' class below is a reactive :class binding on THIS SAME
67
+ element — it hit the identical never-repatched-after-hydration-mismatch
68
+ symptom the inner v-if/v-else branches did (see the comment above
69
+ MgLoginRegisterMenu/section further down), and unlike that inner swap,
70
+ there's no sibling-vnode :key trick available to fix an ancestor's own
71
+ class binding on itself (verified: a :key on this element does NOT
72
+ force it to re-evaluate — key only affects sibling-vnode comparison,
73
+ not a component's own reactive re-render). The width rule that used to
74
+ key off '.signed-in' now uses :has(.signed-in-menu) instead — real DOM
75
+ structure, correct regardless of whether this class ever catches up.
76
+ The class stays here for anything else that legitimately keys off it
77
+ (e.g. a host's own CSS); just don't rely on it for layout in this file.
78
+ -->
61
79
  <div ref="refDiv" :class="{ 'ui-config-user': true, 'signed-in': signedIn }">
62
80
  <div ref="wrapper" class="ui-config-user__content">
63
81
  <!--
@@ -139,6 +157,12 @@ const handleToggleOnline = () => {
139
157
  </a>
140
158
  </div>
141
159
 
160
+ <div class="row info-row">
161
+ <a :href="supportUrl" target="_blank" class="support-link">
162
+ {{ $t("account_menu.buttons.support", "Support") }}
163
+ </a>
164
+ </div>
165
+
142
166
  <div v-if="features.statusOnline" class="row info-row my-3">
143
167
  <div class="status-toggle">
144
168
  <span>{{ $t("account_menu.buttons.show_online") }}</span>
@@ -189,7 +213,16 @@ const handleToggleOnline = () => {
189
213
  overflow-y: auto;
190
214
  transition: all ease 0.5s;
191
215
 
192
- &:not(.signed-in) {
216
+ // Derived from the actual rendered content (:has), not the .signed-in
217
+ // class this element also carries. That class is a reactive :class
218
+ // binding on THIS SAME element (see the guest→signed-in transition
219
+ // comment above the template's MgLoginRegisterMenu/section) — it hit
220
+ // the identical never-repatched symptom the inner branch did, and
221
+ // unlike the inner v-if/v-else swap, there's no sibling-vnode :key
222
+ // trick available for an ancestor's own class binding on itself.
223
+ // :has(.signed-in-menu) reads real DOM structure instead, so it's
224
+ // correct regardless of whether that class binding ever catches up.
225
+ &:not(:has(.signed-in-menu)) {
193
226
  width: 340px;
194
227
  }
195
228
 
@@ -310,6 +343,26 @@ const handleToggleOnline = () => {
310
343
  }
311
344
  }
312
345
 
346
+ .support-link {
347
+ display: block;
348
+ width: 100%;
349
+ text-align: center;
350
+ font-size: 0.75rem;
351
+ font-weight: 400;
352
+ // Deliberately quieter than .plans-pricing-link — this is a low-key
353
+ // secondary affordance, not a conversion CTA, so it stays on a muted
354
+ // text token instead of each host's accent color.
355
+ color: var(--secondary-info-fg, var(--inactive));
356
+ text-decoration: none;
357
+ padding: 4px 0;
358
+ margin-top: 8px;
359
+
360
+ &:hover {
361
+ text-decoration: underline;
362
+ color: var(--active);
363
+ }
364
+ }
365
+
313
366
  .status-toggle {
314
367
  display: flex;
315
368
  justify-content: space-between;
@@ -23,7 +23,13 @@ export function useLogout() {
23
23
  });
24
24
  }
25
25
 
26
- const target = redirectTo || `${accountsBaseUrl}/login`;
26
+ // Default: stay on the current site, now as a guest — these are mostly
27
+ // publicly-browsable content sites (a job posting, a video, a post),
28
+ // so bouncing to a different domain's login page on every logout is
29
+ // disorienting. accountsBaseUrl/login is still available for a caller
30
+ // that genuinely needs it (e.g. accounts' own logout), just not the
31
+ // default anymore.
32
+ const target = redirectTo || (typeof window !== "undefined" ? window.location.href : `${accountsBaseUrl}/login`);
27
33
 
28
34
  if (typeof document === "undefined" || !apiBase) {
29
35
  if (typeof window !== "undefined") window.location.href = target;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mundogamernetwork/shared-ui",
3
- "version": "1.16.6",
3
+ "version": "1.16.8",
4
4
  "description": "Mundo Gamer Network - Shared UI Layer (Nuxt 3)",
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
package/pages/faq.vue CHANGED
@@ -8,6 +8,36 @@ const { isFaqOpened, faq } = storeToRefs(institutionalStore);
8
8
 
9
9
  const searchTerm = ref("");
10
10
 
11
+ // Same host-agnostic login-redirect construction as MgLoginRegisterMenu's
12
+ // goLogin() — routes through the CURRENT platform's own /login (apiBaseURL
13
+ // host) rather than accountsBaseUrl/login directly, since most platforms'
14
+ // session cookie is scoped to their own API domain, not accounts'. Inlined
15
+ // rather than imported for the same reason as MgLoginRegisterMenu: this
16
+ // file ships as raw TS/Vue inside an npm package, and relative .ts imports
17
+ // from node_modules fail in Vite production builds.
18
+ const runtimeConfig = useRuntimeConfig();
19
+ const apiBase = (
20
+ (runtimeConfig.public.mgSharedUi?.apiBaseURL as string) ||
21
+ (runtimeConfig.public.apiBaseURL as string) ||
22
+ (import.meta.env.VITE_API_BASE_URL as string) ||
23
+ ""
24
+ ).replace(/\/api\/v1\/?$/, "");
25
+ const accountsBaseUrl =
26
+ (runtimeConfig.public.mgSharedUi?.accountsBaseUrl as string) ||
27
+ (runtimeConfig.public.accountsBaseUrl as string) ||
28
+ (import.meta.env.VITE_BASE_ACCOUNTS_URL as string) ||
29
+ "";
30
+ const systemId =
31
+ (runtimeConfig.public.mgSharedUi?.systemId as string) ||
32
+ (runtimeConfig.public.platformId as string) ||
33
+ (import.meta.env.VITE_SYSTEM_ID as string) ||
34
+ "";
35
+ const openTicketUrl = (() => {
36
+ const params: Record<string, string> = { redirect_to: `${accountsBaseUrl}/account/support/new` };
37
+ if (systemId) params.system_id = systemId;
38
+ return `${apiBase}/login?${new URLSearchParams(params)}`;
39
+ })();
40
+
11
41
  const showModal = ref(false);
12
42
  const modalMessage = ref("");
13
43
  const closeModal = () => {
@@ -16,8 +46,6 @@ const closeModal = () => {
16
46
 
17
47
  async function fetchFaqs() {
18
48
  try {
19
- const config = useRuntimeConfig();
20
- const systemId = config.public.mgSharedUi?.systemId || import.meta.env.VITE_SYSTEM_ID;
21
49
  await institutionalStore.fetchFaq({
22
50
  filter: {
23
51
  term: searchTerm.value,
@@ -102,6 +130,9 @@ function toggleFaq(index: number) {
102
130
  </span>
103
131
  </div>
104
132
  </div>
133
+ <a :href="openTicketUrl" class="press__button">
134
+ <span class="press__button--text">{{ $t("more.faq.open_ticket_btn") }}</span>
135
+ </a>
105
136
  </div>
106
137
  </div>
107
138
  </div>
@@ -271,6 +302,26 @@ function toggleFaq(index: number) {
271
302
  }
272
303
  }
273
304
  }
305
+
306
+ &__button {
307
+ background: var(--chip-text);
308
+ display: flex;
309
+ width: 200px;
310
+ height: 32px;
311
+ padding: 0px 12px 0px 8px;
312
+ justify-content: center;
313
+ align-items: center;
314
+ gap: 4px;
315
+ margin-top: 16px;
316
+
317
+ &--text {
318
+ color: var(--chip-background-2);
319
+ text-align: center;
320
+ font-size: 12px;
321
+ font-weight: 400;
322
+ line-height: 16px;
323
+ }
324
+ }
274
325
  }
275
326
  }
276
327