@mundogamernetwork/shared-ui 1.1.44 → 1.1.46

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.
@@ -0,0 +1,291 @@
1
+ <script setup lang="ts">
2
+ import { trackPressKitEvent } from '../../services/pressKitService';
3
+
4
+ definePageMeta({ layout: 'blank' });
5
+
6
+ const route = useRoute();
7
+ const slug = route.params.slug as string;
8
+
9
+ const runtimeConfig = useRuntimeConfig();
10
+ const cfg = (runtimeConfig.public?.mgSharedUi || {}) as Record<string, any>;
11
+ // Consuming apps may set apiBaseURL at public root (agency/community/tv pattern)
12
+ // or inside mgSharedUi. pressKitApiUrl overrides both (e.g. community points to agency API).
13
+ const apiBase: string =
14
+ cfg.pressKitApiUrl ||
15
+ (runtimeConfig.public as any)?.pressKitApiUrl ||
16
+ cfg.apiBaseURL ||
17
+ (runtimeConfig.public as any)?.apiBaseURL ||
18
+ '';
19
+
20
+ const agencyBase: string =
21
+ cfg.agencyBaseUrl ||
22
+ (runtimeConfig.public as any)?.agencyBaseUrl ||
23
+ '';
24
+
25
+ const SUPPORTED_LOCALES = ['en', 'pt-BR', 'es', 'de', 'ro', 'ar-AE'];
26
+ const routePath = route.path.split('/');
27
+ const lang = SUPPORTED_LOCALES.find(l => routePath.includes(l)) || 'en';
28
+
29
+ const { data: kitData, error: fetchError, pending } = await useAsyncData(
30
+ `press-kit-${slug}`,
31
+ () => $fetch<any>(`${apiBase}/public/press-kits/${slug}`, {
32
+ params: { include: 'assets,videos,credits,awards,quotes', lang },
33
+ }),
34
+ { lazy: false },
35
+ );
36
+
37
+ const kit = computed(() => kitData.value?.data || kitData.value || null);
38
+ const loading = pending;
39
+ const error = computed(() => !!fetchError.value || (!pending.value && !kit.value));
40
+
41
+ onMounted(() => {
42
+ if (kit.value) {
43
+ trackPressKitEvent(slug, {
44
+ event_type: 'view',
45
+ referrer: document.referrer || undefined,
46
+ }).catch(() => {});
47
+ }
48
+ });
49
+
50
+ // Fractal include shape: relation -> { data: [...] }
51
+ const list = (rel: any) => rel?.data || rel || [];
52
+ const assets = computed(() => list(kit.value?.assets));
53
+ const videos = computed(() => list(kit.value?.videos));
54
+ const awards = computed(() => list(kit.value?.awards));
55
+ const quotes = computed(() => list(kit.value?.quotes));
56
+ const team = computed(() => list(kit.value?.credits));
57
+ const features = computed(() => kit.value?.key_features || []);
58
+ // New, optional blocks (rendered only when the API provides them)
59
+ const articles = computed(() => list(kit.value?.articles));
60
+ const coverage = computed(() => list(kit.value?.coverage));
61
+ const showcases = computed(() => list(kit.value?.showcases));
62
+ const hasEcosystem = computed(() => showcases.value.length || kit.value?.ventures_url || kit.value?.magazine_feature || kit.value?.community_url);
63
+
64
+ const screenshots = computed(() => assets.value.filter((a: any) => ['screenshot', 'artwork', 'gif'].includes(a.type)));
65
+ const brandAssets = computed(() => assets.value.filter((a: any) => ['logo', 'document'].includes(a.type)));
66
+
67
+ const tpl = computed(() => kit.value?.theme || null);
68
+ const layout = computed(() => kit.value?.layout || 'classic');
69
+ const allowDownload = computed(() => kit.value?.allow_asset_download !== false);
70
+
71
+ const keyPoolsVisible = ref(false);
72
+ function onPoolsReady(count: number) {
73
+ keyPoolsVisible.value = count > 0;
74
+ }
75
+
76
+ const socials = computed(() => {
77
+ const s = kit.value?.social_links || {};
78
+ return Object.entries(s).filter(([, v]) => v).map(([k, v]) => ({ platform: k, url: v as string }));
79
+ });
80
+
81
+ const facts = computed(() => {
82
+ const k = kit.value || {};
83
+ const out: { label: string; value: string; accent?: boolean; href?: string }[] = [];
84
+ if (k.developer) out.push({ label: 'kit.press.developer', value: k.developer });
85
+ if (k.publisher) out.push({ label: 'kit.press.publisher', value: k.publisher });
86
+ if (k.release_date_tba) out.push({ label: 'kit.press.release', value: 'TBA', accent: true });
87
+ else if (k.release_date) out.push({ label: 'kit.press.release', value: k.release_date, accent: true });
88
+ if (k.release_status) out.push({ label: 'kit.press.status', value: String(k.release_status).replace(/_/g, ' ') });
89
+ if (k.price) out.push({ label: 'kit.press.price', value: `${k.price}${k.currency ? ' ' + k.currency : ''}` });
90
+ if (k.website_url) out.push({ label: 'kit.press.website', value: k.website_url, accent: true, href: k.website_url });
91
+ if (k.steam_url) out.push({ label: 'Steam', value: k.steam_url, href: k.steam_url });
92
+ if (k.press_contact_email) out.push({ label: 'kit.press.contact', value: k.press_contact_email, href: `mailto:${k.press_contact_email}` });
93
+ return out;
94
+ });
95
+
96
+ function track(type: 'click' | 'download' | 'contact') {
97
+ trackPressKitEvent(slug, { event_type: type, referrer: document.referrer || undefined }).catch(() => {});
98
+ }
99
+
100
+ const requestUrl = useRequestURL();
101
+ useHead(() => ({
102
+ title: kit.value ? `${kit.value.name} — Press Kit` : 'Press Kit',
103
+ meta: [
104
+ { name: 'description', content: kit.value?.tagline || '' },
105
+ { property: 'og:title', content: kit.value?.name || 'Press Kit' },
106
+ { property: 'og:description', content: kit.value?.tagline || '' },
107
+ { property: 'og:image', content: kit.value?.hero_image_url || kit.value?.logo_url || '' },
108
+ { property: 'og:type', content: 'article' },
109
+ { property: 'og:url', content: requestUrl.href },
110
+ ],
111
+ }));
112
+ </script>
113
+
114
+ <template>
115
+ <div class="kit-press" :data-tpl="tpl" :data-layout="layout">
116
+ <div v-if="loading" class="kit-state">{{ $t('kit.loading') }}</div>
117
+ <div v-else-if="error || !kit" class="kit-state">
118
+ <h2>{{ $t('kit.press.not_found') }}</h2>
119
+ </div>
120
+
121
+ <template v-else>
122
+ <!-- CAPA / COVER -->
123
+ <header class="kit-cover">
124
+ <img v-if="kit.hero_image_url" class="kit-cover-art" :src="kit.hero_image_url" :alt="kit.name" />
125
+ <div class="kit-cover-inner">
126
+ <img v-if="kit.cover_image_url" class="kit-cover-poster" :src="kit.cover_image_url" :alt="kit.name" />
127
+ <div class="kit-cover-text">
128
+ <span v-if="kit.release_status" class="kit-eyebrow">{{ String(kit.release_status).replace(/_/g, ' ') }}</span>
129
+ <img v-if="kit.logo_url" class="kit-cover-logo-img" :src="kit.logo_url" :alt="kit.name" />
130
+ <h1 v-else>{{ kit.name }}</h1>
131
+ <p v-if="kit.tagline" class="kit-tagline">{{ kit.tagline }}</p>
132
+ <p v-if="kit.developer" class="kit-kicker">{{ kit.developer }}</p>
133
+ <div class="kit-actions">
134
+ <a v-if="allowDownload" class="kit-btn kit-btn-primary" @click="track('download')">{{ $t('kit.press.download_assets') }}</a>
135
+ <a v-if="kit.press_contact_email" class="kit-btn kit-btn-ghost" :href="`mailto:${kit.press_contact_email}`" @click="track('contact')">{{ $t('kit.press.request_key') }}</a>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </header>
140
+
141
+ <div class="kit-wrap">
142
+ <div class="kit-layout">
143
+ <aside class="kit-sidebar">
144
+ <div class="kit-card kit-factsheet">
145
+ <h3 class="kit-fact-title">{{ $t('kit.press.fact_sheet') }}</h3>
146
+ <div v-for="f in facts" :key="f.label" class="kit-fact">
147
+ <span class="k">{{ $te(f.label) ? $t(f.label) : f.label }}</span>
148
+ <a v-if="f.href" class="v accent" :href="f.href" target="_blank" rel="noopener" @click="track('click')">{{ f.value }}</a>
149
+ <span v-else class="v" :class="{ accent: f.accent }">{{ f.value }}</span>
150
+ </div>
151
+ <div v-if="socials.length" class="kit-fact">
152
+ <span class="k">{{ $t('kit.press.social') }}</span>
153
+ <div class="kit-socials">
154
+ <a v-for="s in socials" :key="s.platform" :href="s.url" target="_blank" rel="noopener" @click="track('click')">{{ s.platform.charAt(0).toUpperCase() }}</a>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </aside>
159
+
160
+ <main class="kit-main">
161
+ <section v-if="kit.description" class="kit-block">
162
+ <h2>{{ $t('kit.press.about') }}</h2>
163
+ <div class="kit-lead" v-html="kit.description" />
164
+ </section>
165
+
166
+ <section v-if="features.length" class="kit-block">
167
+ <h2>{{ $t('kit.press.features') }}</h2>
168
+ <div class="kit-features">
169
+ <div v-for="(f, i) in features" :key="i" class="kit-feature"><span class="m">▸</span>{{ f }}</div>
170
+ </div>
171
+ </section>
172
+
173
+ <section v-if="videos.length" class="kit-block">
174
+ <h2>{{ $t('kit.press.videos') }}</h2>
175
+ <PressKitVideoPlayer :videos="videos" />
176
+ </section>
177
+
178
+ <section v-if="screenshots.length" class="kit-block">
179
+ <div class="kit-shead"><h2>{{ $t('kit.press.screenshots') }}</h2><a v-if="allowDownload" class="kit-dl" @click="track('download')">{{ $t('kit.press.download_all') }}</a></div>
180
+ <div class="kit-gallery">
181
+ <a v-for="(s, i) in screenshots" :key="i" class="kit-shot" :href="s.url" target="_blank" rel="noopener"><img :src="s.thumbnail_url || s.url" :alt="s.title || ''" /></a>
182
+ </div>
183
+ </section>
184
+
185
+ <section v-if="brandAssets.length" class="kit-block">
186
+ <div class="kit-shead"><h2>{{ $t('kit.press.logo_icons') }}</h2></div>
187
+ <div class="kit-logos">
188
+ <a v-for="(b, i) in brandAssets" :key="i" class="kit-logo-tile" :href="b.url" target="_blank" rel="noopener" @click="track('download')">
189
+ <span class="ic">◆</span>{{ b.title || b.type }}
190
+ </a>
191
+ </div>
192
+ </section>
193
+
194
+ <!-- NEW: Conteúdos & Artigos (community + external) -->
195
+ <section v-if="articles.length" class="kit-block">
196
+ <div class="kit-shead"><h2>{{ $t('kit.press.articles') }}</h2></div>
197
+ <div class="kit-articles">
198
+ <a v-for="(a, i) in articles" :key="i" class="kit-article" :href="a.url" target="_blank" rel="noopener" @click="track('click')">
199
+ <div class="thumb" :style="a.image ? { backgroundImage: `url(${a.image})` } : {}"><span class="src" :class="{ ext: a.external }">{{ a.external ? $t('kit.press.external') : 'Mundo Gamer' }}</span></div>
200
+ <div class="a-body"><h4>{{ a.title }}</h4><div class="meta">{{ a.source }}<span v-if="a.date"> · {{ a.date }}</span></div></div>
201
+ </a>
202
+ </div>
203
+ </section>
204
+
205
+ <!-- NEW: Cobertura de Criadores -->
206
+ <section v-if="coverage.length" class="kit-block">
207
+ <h2>{{ $t('kit.press.coverage') }}</h2>
208
+ <div class="kit-creators">
209
+ <a v-for="(c, i) in coverage" :key="i" class="kit-creator" :href="c.url || undefined" target="_blank" rel="noopener">
210
+ <div class="av" :style="c.avatar ? { backgroundImage: `url(${c.avatar})` } : {}" />
211
+ <div class="cn">{{ c.name }}</div>
212
+ <div class="cp">{{ c.platform }}<span v-if="c.followers"> · {{ c.followers }}</span></div>
213
+ <div v-if="c.label" class="cv">{{ c.label }}</div>
214
+ </a>
215
+ </div>
216
+ </section>
217
+
218
+ <section v-if="awards.length" class="kit-block">
219
+ <h2>{{ $t('kit.press.awards') }}</h2>
220
+ <PressKitAwards :awards="awards" />
221
+ </section>
222
+
223
+ <section v-if="quotes.length" class="kit-block">
224
+ <h2>{{ $t('kit.press.press') }}</h2>
225
+ <PressKitQuotes :quotes="quotes" />
226
+ </section>
227
+
228
+ <!-- Créditos -> Equipe -->
229
+ <section v-if="team.length" class="kit-block">
230
+ <h2>{{ $t('kit.press.team') }}</h2>
231
+ <div class="kit-team">
232
+ <div v-for="(m, i) in team" :key="i" class="kit-member"><span>{{ m.name }}</span><span class="role">{{ m.role }}</span></div>
233
+ </div>
234
+ </section>
235
+
236
+ <!-- NEW: Ecossistema Mundo Gamer -->
237
+ <section v-if="hasEcosystem" class="kit-block">
238
+ <h2>{{ $t('kit.press.ecosystem') }}</h2>
239
+ <div class="kit-eco">
240
+ <div v-if="showcases.length" class="kit-eco-card full">
241
+ <div class="kit-eco-h"><span class="ic">★</span>{{ $t('kit.press.showcases') }}</div>
242
+ <div class="kit-sbadges">
243
+ <span v-for="(s, i) in showcases" :key="i" class="kit-sbadge" :class="{ feat: s.featured }"><span class="medal">{{ s.featured ? '🏵️' : '🎮' }}</span>{{ s.name }}<span v-if="s.year"> {{ s.year }}</span></span>
244
+ </div>
245
+ </div>
246
+ <div v-if="kit.ventures_url" class="kit-eco-card">
247
+ <div class="kit-eco-h"><span class="ic">◈</span>MGN Ventures</div>
248
+ <a class="kit-vrow" :href="kit.ventures_url" target="_blank" rel="noopener" @click="track('click')"><span class="vlogo">VENTURES</span><span class="vtxt">{{ $t('kit.press.ventures_text') }}</span></a>
249
+ </div>
250
+ <a v-if="kit.magazine_feature" class="kit-eco-card kit-mag" :href="kit.magazine_feature.url" target="_blank" rel="noopener" @click="track('click')">
251
+ <div class="kit-eco-h" style="width:100%"><span class="ic">▤</span>MGN Magazine</div>
252
+ <div class="kit-mag-row"><div class="mcover" :style="kit.magazine_feature.cover ? { backgroundImage: `url(${kit.magazine_feature.cover})` } : {}" /><div><div class="mtitle">{{ kit.magazine_feature.title }}</div><div class="mmeta">{{ kit.magazine_feature.issue }}</div></div></div>
253
+ </a>
254
+ <div v-if="kit.community_url" class="kit-eco-card full">
255
+ <div class="kit-ccta">
256
+ <div><div class="ctitle">{{ $t('kit.press.follow_community', { name: kit.name }) }}</div><div v-if="kit.community_followers" class="cmeta">{{ kit.community_followers }} {{ $t('kit.press.followers') }}</div></div>
257
+ <a class="kit-btn kit-btn-primary" :href="kit.community_url" target="_blank" rel="noopener" @click="track('click')">{{ $t('kit.press.follow') }}</a>
258
+ </div>
259
+ </div>
260
+ </div>
261
+ </section>
262
+
263
+ <!-- Key pools embed — shown when game has active pools -->
264
+ <section v-if="kit.game_id" v-show="keyPoolsVisible" class="kit-block kit-keys-section">
265
+ <h2 class="kit-keys-title">{{ $t('kit.press.get_key_title') }}</h2>
266
+ <p class="kit-keys-desc">{{ $t('kit.press.get_key_desc') }}</p>
267
+ <KeyBrowser
268
+ requester-context="user"
269
+ :game-id="kit.game_id"
270
+ @pools-ready="onPoolsReady"
271
+ />
272
+ </section>
273
+
274
+ <section v-if="kit.press_contact_email" class="kit-block">
275
+ <div class="kit-cta">
276
+ <h2>{{ $t('kit.press.covering', { name: kit.name }) }}</h2>
277
+ <p>{{ $t('kit.press.cta_text') }}</p>
278
+ <a class="kit-btn kit-btn-primary" :href="`mailto:${kit.press_contact_email}`" @click="track('contact')">{{ $t('kit.press.contact_btn') }}</a>
279
+ </div>
280
+ </section>
281
+
282
+ <p class="kit-madewith">
283
+ {{ $t('kit.press.made_with') }} <strong>Mundo Gamer</strong> —
284
+ <a :href="kit.create_kit_url || `${agencyBase}/presskit`" target="_blank" rel="noopener">{{ $t('kit.press.create_yours') }}</a>
285
+ </p>
286
+ </main>
287
+ </div>
288
+ </div>
289
+ </template>
290
+ </div>
291
+ </template>
@@ -55,7 +55,7 @@ export default defineNuxtPlugin({
55
55
  authorize: (socketId: any, callback: any) => {
56
56
  axios
57
57
  .post(
58
- import.meta.env.VITE_PUSHER_AUTH,
58
+ (import.meta.env.VITE_PUSHER_AUTH ?? '').replace(/^["']|["']$/g, ''),
59
59
  {
60
60
  socket_id: socketId,
61
61
  channel_name: channel.name,
@@ -0,0 +1,45 @@
1
+ import httpService from './httpService'
2
+
3
+ export type KeyPool = {
4
+ id: number
5
+ name: string
6
+ slug: string
7
+ access_policy: string
8
+ available_count: number
9
+ already_requested: boolean
10
+ game: { id: number; name: string } | null
11
+ cover: string | null
12
+ }
13
+
14
+ export type KeyRequest = {
15
+ id: number
16
+ pool_id: number
17
+ pool_name: string
18
+ pool_slug: string
19
+ status_slug: string
20
+ status_name: string
21
+ platforms: string[]
22
+ revealed_at: string | null
23
+ created_at: string
24
+ }
25
+
26
+ export type RevealResult = {
27
+ code: string
28
+ platform: string | null
29
+ revealed_at: string
30
+ }
31
+
32
+ export const fetchAvailablePools = (params: Record<string, any> = {}) =>
33
+ httpService.get<{ data: KeyPool[] }>('/key-pools/available', { params })
34
+
35
+ export const fetchMyRequests = () =>
36
+ httpService.get<{ data: KeyRequest[] }>('/key-requests/mine')
37
+
38
+ export const requestKey = (poolId: number, body: Record<string, any>) =>
39
+ httpService.post(`/key-pools/${poolId}/request`, body)
40
+
41
+ export const revealKey = (requestId: number, body: Record<string, any> = {}) =>
42
+ httpService.post<{ data: RevealResult }>(`/key-requests/${requestId}/reveal`, body)
43
+
44
+ export const fetchPlatforms = () =>
45
+ httpService.get<{ data: { id: number; name: string }[] }>('/showcase-studio-dashboard/platforms')