@mundogamernetwork/shared-ui 1.17.5 → 1.17.7
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/MediaKit/MgRateCardBundleEditor.vue +11 -1
- package/components/MediaKit/MgRateCardEditor.vue +26 -0
- package/components/keys/KeyBrowser.vue +8 -0
- package/components/keys/KeyCampaignDashboardCard.vue +22 -1
- package/components/keys/KeyRevealModal.vue +27 -1
- package/package.json +1 -1
- package/pages/key-campaigns/index.vue +3 -2
- package/pages/presskit/game/[slug].vue +3 -3
- package/services/campaignService.ts +1 -1
- package/services/mediaKitService.ts +2 -0
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
/>
|
|
44
44
|
<div class="card-checkbox-content">
|
|
45
45
|
<span class="card-name">{{ card.content_format?.name || card.label }}</span>
|
|
46
|
+
<span v-if="card.platform?.name" class="card-platform">{{ card.platform.name }}</span>
|
|
46
47
|
<span class="card-channel">{{ card.ad_channel?.name }}</span>
|
|
47
48
|
<span class="card-price">{{ formatPrice(card.price_min, card.currency) }}</span>
|
|
48
49
|
</div>
|
|
@@ -144,7 +145,7 @@
|
|
|
144
145
|
<p v-if="bundle.description" class="bundle-desc">{{ bundle.description }}</p>
|
|
145
146
|
<div class="bundle-items">
|
|
146
147
|
<span v-for="item in bundle.rate_cards?.data || bundle.rate_cards || []" :key="item.id" class="bundle-item-tag">
|
|
147
|
-
{{ item.content_format?.name || item.label }}
|
|
148
|
+
{{ item.content_format?.name || item.label }}<template v-if="item.platform?.name"> · {{ item.platform.name }}</template>
|
|
148
149
|
</span>
|
|
149
150
|
</div>
|
|
150
151
|
<div class="bundle-pricing">
|
|
@@ -183,6 +184,7 @@ interface RateCard {
|
|
|
183
184
|
description?: string;
|
|
184
185
|
content_format?: { id: number; name: string };
|
|
185
186
|
ad_channel?: { id: number; name: string };
|
|
187
|
+
platform?: { id: number; name: string };
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
interface Bundle {
|
|
@@ -563,6 +565,14 @@ async function removeBundle(id: number) {
|
|
|
563
565
|
flex: 1;
|
|
564
566
|
|
|
565
567
|
.card-name { color: #FFF; font-size: 13px; font-weight: 600; }
|
|
568
|
+
.card-platform {
|
|
569
|
+
background: rgba(253, 178, 21, 0.12);
|
|
570
|
+
color: #FDB215;
|
|
571
|
+
padding: 2px 8px;
|
|
572
|
+
border-radius: 20px;
|
|
573
|
+
font-size: 11px;
|
|
574
|
+
font-weight: 500;
|
|
575
|
+
}
|
|
566
576
|
.card-channel { color: #888; font-size: 12px; }
|
|
567
577
|
.card-price { color: #FDB215; font-size: 13px; font-weight: 600; margin-left: auto; }
|
|
568
578
|
}
|
|
@@ -32,6 +32,15 @@
|
|
|
32
32
|
</option>
|
|
33
33
|
</select>
|
|
34
34
|
</div>
|
|
35
|
+
<div class="form-group">
|
|
36
|
+
<label>{{ $t("media_kit.editor.platform") }}</label>
|
|
37
|
+
<select v-model="form.platform_id">
|
|
38
|
+
<option value="">{{ $t("media_kit.editor.select") }}</option>
|
|
39
|
+
<option v-for="platform in platforms" :key="platform.id" :value="platform.id">
|
|
40
|
+
{{ platform.name }}
|
|
41
|
+
</option>
|
|
42
|
+
</select>
|
|
43
|
+
</div>
|
|
35
44
|
</div>
|
|
36
45
|
<div class="form-row">
|
|
37
46
|
<div class="form-group">
|
|
@@ -111,6 +120,7 @@
|
|
|
111
120
|
<div class="card-info">
|
|
112
121
|
<span class="format">{{ card.content_format?.name || card.label }}</span>
|
|
113
122
|
<span class="channel">{{ card.ad_channel?.name }}</span>
|
|
123
|
+
<span v-if="card.platform?.name" class="platform-tag">{{ card.platform.name }}</span>
|
|
114
124
|
<span class="price">{{ formatPrice(card.price_min, card.price_max, card.currency) }}</span>
|
|
115
125
|
</div>
|
|
116
126
|
<!-- Two-step delete rather than a modal: this component ships to
|
|
@@ -150,6 +160,7 @@ interface RateCard {
|
|
|
150
160
|
id: number;
|
|
151
161
|
content_format_id: number;
|
|
152
162
|
ad_channel_id: number;
|
|
163
|
+
platform_id?: number | null;
|
|
153
164
|
label?: string;
|
|
154
165
|
price_min: string;
|
|
155
166
|
price_max?: string;
|
|
@@ -159,6 +170,7 @@ interface RateCard {
|
|
|
159
170
|
is_active: boolean;
|
|
160
171
|
content_format?: { id: number; name: string };
|
|
161
172
|
ad_channel?: { id: number; name: string };
|
|
173
|
+
platform?: { id: number; name: string };
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
interface LookupItem {
|
|
@@ -172,6 +184,7 @@ const props = withDefaults(
|
|
|
172
184
|
influencerProInfoId: number;
|
|
173
185
|
contentFormats: LookupItem[];
|
|
174
186
|
adChannels: LookupItem[];
|
|
187
|
+
platforms?: LookupItem[];
|
|
175
188
|
isEnabled?: boolean;
|
|
176
189
|
/** MGN commission % for the current plan (host app resolves this, e.g. from feature_limits). */
|
|
177
190
|
commissionPercent?: number;
|
|
@@ -184,6 +197,7 @@ const props = withDefaults(
|
|
|
184
197
|
}>(),
|
|
185
198
|
{
|
|
186
199
|
isEnabled: true,
|
|
200
|
+
platforms: () => [],
|
|
187
201
|
commissionPercent: 20,
|
|
188
202
|
planName: "Free",
|
|
189
203
|
isSubscriber: false,
|
|
@@ -212,6 +226,7 @@ const saving = ref(false);
|
|
|
212
226
|
const defaultForm = {
|
|
213
227
|
content_format_id: '',
|
|
214
228
|
ad_channel_id: '',
|
|
229
|
+
platform_id: '',
|
|
215
230
|
price_min: '',
|
|
216
231
|
price_max: '',
|
|
217
232
|
currency: 'USD',
|
|
@@ -281,6 +296,7 @@ const editCard = (card: RateCard) => {
|
|
|
281
296
|
form.value = {
|
|
282
297
|
content_format_id: String(card.content_format_id),
|
|
283
298
|
ad_channel_id: String(card.ad_channel_id),
|
|
299
|
+
platform_id: card.platform_id ? String(card.platform_id) : '',
|
|
284
300
|
price_min: card.price_min,
|
|
285
301
|
price_max: card.price_max || '',
|
|
286
302
|
currency: card.currency,
|
|
@@ -309,6 +325,7 @@ const saveRateCard = async () => {
|
|
|
309
325
|
influencer_professional_info_id: props.influencerProInfoId,
|
|
310
326
|
content_format_id: Number(form.value.content_format_id),
|
|
311
327
|
ad_channel_id: Number(form.value.ad_channel_id),
|
|
328
|
+
platform_id: form.value.platform_id ? Number(form.value.platform_id) : null,
|
|
312
329
|
price_min: Number(form.value.price_min),
|
|
313
330
|
price_max: form.value.price_max ? Number(form.value.price_max) : null,
|
|
314
331
|
delivery_time_days: form.value.delivery_time_days ? Number(form.value.delivery_time_days) : null,
|
|
@@ -594,6 +611,15 @@ const netDisplay = computed(() => {
|
|
|
594
611
|
font-size: 12px;
|
|
595
612
|
}
|
|
596
613
|
|
|
614
|
+
.platform-tag {
|
|
615
|
+
background: rgba(253, 178, 21, 0.12);
|
|
616
|
+
color: #FDB215;
|
|
617
|
+
padding: 2px 8px;
|
|
618
|
+
border-radius: 20px;
|
|
619
|
+
font-size: 11px;
|
|
620
|
+
font-weight: 500;
|
|
621
|
+
}
|
|
622
|
+
|
|
597
623
|
.price {
|
|
598
624
|
color: #FDB215;
|
|
599
625
|
font-size: 14px;
|
|
@@ -46,6 +46,11 @@ const isAuthenticated = ref(true) // assume true; set false on 401
|
|
|
46
46
|
const requestForms = ref<Record<number, { platform_ids: number[]; description: string }>>({})
|
|
47
47
|
const revealingId = ref<number | null>(null)
|
|
48
48
|
const revealResult = ref<RevealResult | null>(null)
|
|
49
|
+
// revealingId resets to null in the reveal() finally block, before the modal
|
|
50
|
+
// ever renders (it only shows once revealResult is set) — this holds onto
|
|
51
|
+
// the id long enough for the modal's "send your coverage" link to build
|
|
52
|
+
// /key-campaigns/key-materials?requestId=.
|
|
53
|
+
const revealedRequestId = ref<number | null>(null)
|
|
49
54
|
|
|
50
55
|
const notifPromptVisible = ref(false)
|
|
51
56
|
const notifSaving = ref(false)
|
|
@@ -219,6 +224,7 @@ async function revealCode(reqId: number) {
|
|
|
219
224
|
if (props.accessToken) body.access_token = props.accessToken
|
|
220
225
|
const res = await apiRevealKey(reqId, body)
|
|
221
226
|
revealResult.value = (res as any)?.data?.data ?? null
|
|
227
|
+
if (revealResult.value) revealedRequestId.value = reqId
|
|
222
228
|
} catch (err: any) {
|
|
223
229
|
if (err?.response?.status === 401) isAuthenticated.value = false
|
|
224
230
|
} finally {
|
|
@@ -228,6 +234,7 @@ async function revealCode(reqId: number) {
|
|
|
228
234
|
|
|
229
235
|
function closeReveal() {
|
|
230
236
|
revealResult.value = null
|
|
237
|
+
revealedRequestId.value = null
|
|
231
238
|
}
|
|
232
239
|
|
|
233
240
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -274,6 +281,7 @@ function statusColor(slug: string): string {
|
|
|
274
281
|
:code="revealResult.code"
|
|
275
282
|
:platform="revealResult.platform"
|
|
276
283
|
:revealed-at="revealResult.revealed_at"
|
|
284
|
+
:key-request-id="revealedRequestId"
|
|
277
285
|
@close="closeReveal"
|
|
278
286
|
/>
|
|
279
287
|
|
|
@@ -25,6 +25,7 @@ const props = defineProps<{
|
|
|
25
25
|
streamer_type?: number | null;
|
|
26
26
|
type?: string | null;
|
|
27
27
|
platforms?: Array<{ id: number; name: string; slug?: string | null; alternative_name?: string | null } | string>;
|
|
28
|
+
networkSystems?: string[];
|
|
28
29
|
};
|
|
29
30
|
publicMode?: boolean;
|
|
30
31
|
baseRoute?: string;
|
|
@@ -46,7 +47,7 @@ const locale = $i18n.locale;
|
|
|
46
47
|
|
|
47
48
|
const cardCover = computed(() => {
|
|
48
49
|
const c = props.card as any;
|
|
49
|
-
return c.cover || c.cover_src || c.game?.url_cover_src || c.game_cover || "/imgs/no-cover-img.jpg";
|
|
50
|
+
return c.cover || c.cover_src || c.game?.url_cover_src || c.game?.cover_url || c.game?.url_cover || c.game_cover || "/imgs/no-cover-img.jpg";
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
// Only apply the campaign's own focal point to its own cover — a game-cover/no-cover
|
|
@@ -202,6 +203,9 @@ const detailRoute = computed(() =>
|
|
|
202
203
|
</div>
|
|
203
204
|
|
|
204
205
|
<div class="kc-card__body">
|
|
206
|
+
<div v-if="card.networkSystems?.length" class="kc-card__networks">
|
|
207
|
+
<span v-for="network in card.networkSystems" :key="network" class="kc-card__network-tag">{{ network }}</span>
|
|
208
|
+
</div>
|
|
205
209
|
<div v-if="card.platforms?.length" class="kc-card__platforms">
|
|
206
210
|
<span v-for="p in card.platforms" :key="typeof p === 'string' ? p : p.id" class="kc-card__platform-tag">
|
|
207
211
|
{{ platformAbbr(p) }}
|
|
@@ -295,6 +299,23 @@ const detailRoute = computed(() =>
|
|
|
295
299
|
text-align: center;
|
|
296
300
|
}
|
|
297
301
|
|
|
302
|
+
&__networks {
|
|
303
|
+
display: flex;
|
|
304
|
+
flex-wrap: wrap;
|
|
305
|
+
gap: 4px;
|
|
306
|
+
margin-bottom: 6px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
&__network-tag {
|
|
310
|
+
border: 1px solid color-mix(in srgb, var(--primary, #D297FF) 55%, transparent);
|
|
311
|
+
border-radius: 999px;
|
|
312
|
+
padding: 2px 7px;
|
|
313
|
+
color: var(--primary, #D297FF);
|
|
314
|
+
font-size: 0.68rem;
|
|
315
|
+
line-height: 1.2;
|
|
316
|
+
white-space: nowrap;
|
|
317
|
+
}
|
|
318
|
+
|
|
298
319
|
&__exclusive-badge {
|
|
299
320
|
position: absolute;
|
|
300
321
|
bottom: 6px;
|
|
@@ -7,13 +7,22 @@ const props = defineProps<{
|
|
|
7
7
|
code: string
|
|
8
8
|
platform: string | null
|
|
9
9
|
revealedAt: string
|
|
10
|
+
// Absent for reveal paths outside the request flow (e.g. an admin grant
|
|
11
|
+
// with no key_request row) — the CTA below only renders when present.
|
|
12
|
+
keyRequestId?: number | null
|
|
10
13
|
}>()
|
|
11
14
|
|
|
12
15
|
const emit = defineEmits<{ (e: 'close'): void }>()
|
|
13
16
|
|
|
17
|
+
const { locale } = useI18n()
|
|
18
|
+
|
|
14
19
|
function copyCode() {
|
|
15
20
|
navigator.clipboard?.writeText(props.code)
|
|
16
21
|
}
|
|
22
|
+
|
|
23
|
+
const materialsUrl = computed(() =>
|
|
24
|
+
props.keyRequestId ? `/${locale.value}/key-campaigns/key-materials?requestId=${props.keyRequestId}` : null
|
|
25
|
+
)
|
|
17
26
|
</script>
|
|
18
27
|
|
|
19
28
|
<template>
|
|
@@ -34,6 +43,10 @@ function copyCode() {
|
|
|
34
43
|
|
|
35
44
|
<p class="krm__warning">{{ $t('keys.reveal.warning') }}</p>
|
|
36
45
|
|
|
46
|
+
<a v-if="materialsUrl" :href="materialsUrl" class="krm__materials-btn">
|
|
47
|
+
{{ $t('keys.reveal.submit_materials_cta') }}
|
|
48
|
+
</a>
|
|
49
|
+
|
|
37
50
|
<button class="krm__close-btn" @click="emit('close')">
|
|
38
51
|
{{ $t('common.close') }}
|
|
39
52
|
</button>
|
|
@@ -127,8 +140,21 @@ function copyCode() {
|
|
|
127
140
|
margin: 0;
|
|
128
141
|
}
|
|
129
142
|
|
|
130
|
-
&
|
|
143
|
+
&__materials-btn {
|
|
131
144
|
margin-top: 6px;
|
|
145
|
+
padding: 10px 28px;
|
|
146
|
+
background: var(--accent, #00d4ff);
|
|
147
|
+
border: 1px solid var(--accent, #00d4ff);
|
|
148
|
+
color: #000;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
font-size: 0.9rem;
|
|
151
|
+
font-weight: 600;
|
|
152
|
+
text-decoration: none;
|
|
153
|
+
transition: opacity 0.15s;
|
|
154
|
+
&:hover { opacity: 0.85; }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
&__close-btn {
|
|
132
158
|
padding: 10px 28px;
|
|
133
159
|
background: var(--surface-raised, #1e1e1e);
|
|
134
160
|
border: 1px solid var(--border-color, #2a2a2a);
|
package/package.json
CHANGED
|
@@ -622,7 +622,7 @@ async function loadFeaturedCampaigns() {
|
|
|
622
622
|
.filter((item: any) => (truthyFlag(item.featured) || truthyFlag(item.highlight)) && truthyFlag(item.is_open))
|
|
623
623
|
.map((item: any) => ({
|
|
624
624
|
id: item.id,
|
|
625
|
-
cover: item.cover_src || item.game?.url_banner_src || item.game?.url_cover_src || "/imgs/no-cover-img.jpg",
|
|
625
|
+
cover: item.cover_src || item.game?.url_banner_src || item.game?.url_cover_src || item.game?.cover_url || item.game?.url_cover || "/imgs/no-cover-img.jpg",
|
|
626
626
|
coverFocalX: item.cover_src ? (item.cover_focal_x ?? 0.5) : 0.5,
|
|
627
627
|
coverFocalY: item.cover_src ? (item.cover_focal_y ?? 0.5) : 0.5,
|
|
628
628
|
name: item.name,
|
|
@@ -682,7 +682,7 @@ async function loadCampaigns(page = 1) {
|
|
|
682
682
|
id: item.id,
|
|
683
683
|
type: item.type?.name,
|
|
684
684
|
typeId: item.type?.id,
|
|
685
|
-
cover: item.cover_src || item.game?.url_cover_src || item.game?.url_banner_src || "/imgs/no-cover-img.jpg",
|
|
685
|
+
cover: item.cover_src || item.game?.url_cover_src || item.game?.cover_url || item.game?.url_cover || item.game?.url_banner_src || "/imgs/no-cover-img.jpg",
|
|
686
686
|
coverFocalX: item.cover_src ? (item.cover_focal_x ?? 0.5) : 0.5,
|
|
687
687
|
coverFocalY: item.cover_src ? (item.cover_focal_y ?? 0.5) : 0.5,
|
|
688
688
|
text: item.name,
|
|
@@ -700,6 +700,7 @@ async function loadCampaigns(page = 1) {
|
|
|
700
700
|
available_at_for_user: item.available_at_for_user || null,
|
|
701
701
|
max_keys_for_user: item.max_keys_for_user || 1,
|
|
702
702
|
platforms: (item.platforms || []).map((p: any) => p.name),
|
|
703
|
+
networkSystems: (item.mg_network_systems || []).map((s: any) => s.name).filter(Boolean),
|
|
703
704
|
gameName: item.game?.name || null,
|
|
704
705
|
genres: (item.game?.genres || []).map((g: any) => g.name).filter(Boolean).slice(0, 2),
|
|
705
706
|
studioName: item.company?.name || null,
|
|
@@ -600,7 +600,7 @@ useHead(() => ({
|
|
|
600
600
|
|
|
601
601
|
<section v-if="videos.length" id="trailers" class="kit-block">
|
|
602
602
|
<h2>{{ $t('kit.press.videos') }}</h2>
|
|
603
|
-
<
|
|
603
|
+
<VideoPlayer :videos="videos" />
|
|
604
604
|
</section>
|
|
605
605
|
|
|
606
606
|
<section v-if="screenshots.length || brandAssets.length" id="media" class="kit-block">
|
|
@@ -683,12 +683,12 @@ useHead(() => ({
|
|
|
683
683
|
|
|
684
684
|
<section v-if="awards.length" id="awards" class="kit-block">
|
|
685
685
|
<h2>{{ $t('kit.press.awards') }}</h2>
|
|
686
|
-
<
|
|
686
|
+
<Awards :awards="awards" />
|
|
687
687
|
</section>
|
|
688
688
|
|
|
689
689
|
<section v-if="quotes.length" class="kit-block">
|
|
690
690
|
<h2>{{ $t('kit.press.press') }}</h2>
|
|
691
|
-
<
|
|
691
|
+
<Quotes :quotes="quotes" />
|
|
692
692
|
</section>
|
|
693
693
|
|
|
694
694
|
<!-- Créditos -> Equipe -->
|
|
@@ -374,7 +374,7 @@ export const fetchCampaignBySlug = async (slug: string) => {
|
|
|
374
374
|
cover: k.cover_src,
|
|
375
375
|
cover_focal_x: k.cover_focal_x ?? 0.5,
|
|
376
376
|
cover_focal_y: k.cover_focal_y ?? 0.5,
|
|
377
|
-
game_cover: k.game?.url_cover_src,
|
|
377
|
+
game_cover: k.game?.url_cover_src || k.game?.cover_url || k.game?.url_cover,
|
|
378
378
|
game_slug: k.game?.slug,
|
|
379
379
|
game_name: k.game?.name ?? null,
|
|
380
380
|
// Creator feedback. The can_* flags are computed server-side by
|
|
@@ -99,3 +99,5 @@ export const fetchMediaKitContentFormats = () =>
|
|
|
99
99
|
mk.get("media-kit-lookups/content-formats")
|
|
100
100
|
export const fetchMediaKitAdChannels = () =>
|
|
101
101
|
mk.get("media-kit-lookups/ad-channels")
|
|
102
|
+
export const fetchMediaKitPlatforms = () =>
|
|
103
|
+
mk.get("media-kit-lookups/platforms")
|