@mundogamernetwork/shared-ui 1.1.75 → 1.1.77
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/locales/de.json +10 -2
- package/locales/en.json +10 -2
- package/locales/pt-BR.json +10 -2
- package/locales/ro.json +10 -2
- package/package.json +1 -1
- package/pages/key-campaigns/[slug].vue +186 -0
- package/pages/key-campaigns/redeem-key-approved.vue +9 -2
- package/services/gamesService.ts +52 -0
package/locales/de.json
CHANGED
|
@@ -133,7 +133,9 @@
|
|
|
133
133
|
"who_redeem": "Who redeemed",
|
|
134
134
|
"created_by": "Published by",
|
|
135
135
|
"no_data": "Campaign not found",
|
|
136
|
-
"title": "Kampagne"
|
|
136
|
+
"title": "Kampagne",
|
|
137
|
+
"about": "Über das Spiel",
|
|
138
|
+
"screenshot_alt": "Spiel-Screenshot"
|
|
137
139
|
},
|
|
138
140
|
"other_campaigns": "Andere Kampagnen",
|
|
139
141
|
"available": "verfügbar",
|
|
@@ -165,7 +167,9 @@
|
|
|
165
167
|
"expired": "Abgelaufen",
|
|
166
168
|
"revoked": "Widerrufen"
|
|
167
169
|
},
|
|
168
|
-
"status_label": "Status"
|
|
170
|
+
"status_label": "Status",
|
|
171
|
+
"error_no_keys": "Derzeit sind keine Schlüssel für diese Kampagne verfügbar.",
|
|
172
|
+
"error_not_approved": "Ihre Anfrage wurde noch nicht genehmigt."
|
|
169
173
|
},
|
|
170
174
|
"materials": {
|
|
171
175
|
"title": "Submit material",
|
|
@@ -189,5 +193,9 @@
|
|
|
189
193
|
"success_message": "Your material was sent for review. Thank you!",
|
|
190
194
|
"success_close": "Close"
|
|
191
195
|
}
|
|
196
|
+
},
|
|
197
|
+
"common": {
|
|
198
|
+
"video_thumbnail": "Video-Vorschaubild",
|
|
199
|
+
"expanded_image": "Vergrößertes Bild"
|
|
192
200
|
}
|
|
193
201
|
}
|
package/locales/en.json
CHANGED
|
@@ -133,7 +133,9 @@
|
|
|
133
133
|
"who_redeem": "Who redeemed",
|
|
134
134
|
"created_by": "Published by",
|
|
135
135
|
"no_data": "Campaign not found",
|
|
136
|
-
"title": "Campaign"
|
|
136
|
+
"title": "Campaign",
|
|
137
|
+
"about": "About the game",
|
|
138
|
+
"screenshot_alt": "Game screenshot"
|
|
137
139
|
},
|
|
138
140
|
"other_campaigns": "Other campaigns",
|
|
139
141
|
"available": "available",
|
|
@@ -165,7 +167,9 @@
|
|
|
165
167
|
"expired": "Expired",
|
|
166
168
|
"revoked": "Revoked"
|
|
167
169
|
},
|
|
168
|
-
"status_label": "Status"
|
|
170
|
+
"status_label": "Status",
|
|
171
|
+
"error_no_keys": "No keys available for this campaign at the moment.",
|
|
172
|
+
"error_not_approved": "Your request has not been approved yet."
|
|
169
173
|
},
|
|
170
174
|
"materials": {
|
|
171
175
|
"title": "Submit material",
|
|
@@ -189,5 +193,9 @@
|
|
|
189
193
|
"success_message": "Your material was sent for review. Thank you!",
|
|
190
194
|
"success_close": "Close"
|
|
191
195
|
}
|
|
196
|
+
},
|
|
197
|
+
"common": {
|
|
198
|
+
"video_thumbnail": "Video thumbnail",
|
|
199
|
+
"expanded_image": "Expanded image"
|
|
192
200
|
}
|
|
193
201
|
}
|
package/locales/pt-BR.json
CHANGED
|
@@ -133,7 +133,9 @@
|
|
|
133
133
|
"who_redeem": "Who redeemed",
|
|
134
134
|
"created_by": "Published by",
|
|
135
135
|
"no_data": "Campaign not found",
|
|
136
|
-
"title": "Campanha"
|
|
136
|
+
"title": "Campanha",
|
|
137
|
+
"about": "Sobre o jogo",
|
|
138
|
+
"screenshot_alt": "Captura de tela do jogo"
|
|
137
139
|
},
|
|
138
140
|
"other_campaigns": "Outras campanhas",
|
|
139
141
|
"available": "disponível",
|
|
@@ -165,7 +167,9 @@
|
|
|
165
167
|
"expired": "Expirado",
|
|
166
168
|
"revoked": "Revogado"
|
|
167
169
|
},
|
|
168
|
-
"status_label": "Status"
|
|
170
|
+
"status_label": "Status",
|
|
171
|
+
"error_no_keys": "Não há chaves disponíveis para esta campanha no momento.",
|
|
172
|
+
"error_not_approved": "Sua solicitação ainda não foi aprovada."
|
|
169
173
|
},
|
|
170
174
|
"materials": {
|
|
171
175
|
"title": "Submit material",
|
|
@@ -189,5 +193,9 @@
|
|
|
189
193
|
"success_message": "Your material was sent for review. Thank you!",
|
|
190
194
|
"success_close": "Close"
|
|
191
195
|
}
|
|
196
|
+
},
|
|
197
|
+
"common": {
|
|
198
|
+
"video_thumbnail": "Miniatura do vídeo",
|
|
199
|
+
"expanded_image": "Imagem ampliada"
|
|
192
200
|
}
|
|
193
201
|
}
|
package/locales/ro.json
CHANGED
|
@@ -133,7 +133,9 @@
|
|
|
133
133
|
"who_redeem": "Who redeemed",
|
|
134
134
|
"created_by": "Published by",
|
|
135
135
|
"no_data": "Campaign not found",
|
|
136
|
-
"title": "Campanie"
|
|
136
|
+
"title": "Campanie",
|
|
137
|
+
"about": "Despre joc",
|
|
138
|
+
"screenshot_alt": "Captură de ecran a jocului"
|
|
137
139
|
},
|
|
138
140
|
"other_campaigns": "Alte campanii",
|
|
139
141
|
"available": "disponibil",
|
|
@@ -165,7 +167,9 @@
|
|
|
165
167
|
"expired": "Expirat",
|
|
166
168
|
"revoked": "Revocat"
|
|
167
169
|
},
|
|
168
|
-
"status_label": "Status"
|
|
170
|
+
"status_label": "Status",
|
|
171
|
+
"error_no_keys": "Nu există chei disponibile pentru această campanie în acest moment.",
|
|
172
|
+
"error_not_approved": "Cererea ta nu a fost aprobată încă."
|
|
169
173
|
},
|
|
170
174
|
"materials": {
|
|
171
175
|
"title": "Submit material",
|
|
@@ -189,5 +193,9 @@
|
|
|
189
193
|
"success_message": "Your material was sent for review. Thank you!",
|
|
190
194
|
"success_close": "Close"
|
|
191
195
|
}
|
|
196
|
+
},
|
|
197
|
+
"common": {
|
|
198
|
+
"video_thumbnail": "Miniatură video",
|
|
199
|
+
"expanded_image": "Imagine mărită"
|
|
192
200
|
}
|
|
193
201
|
}
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
revealKey,
|
|
11
11
|
requestKey,
|
|
12
12
|
} from "../../services/campaignService"
|
|
13
|
+
import { fetchDetailGameImage, fetchDetailGameVideo } from "../../services/gamesService"
|
|
13
14
|
|
|
14
15
|
// Injected by each front — provide in app.vue / a plugin
|
|
15
16
|
const mgPlatform = inject<string>("mgPlatform", "MGTV")
|
|
@@ -111,6 +112,59 @@ const { data: redeemedUsers } = await useAsyncData(
|
|
|
111
112
|
{ watch: [campaign] },
|
|
112
113
|
)
|
|
113
114
|
|
|
115
|
+
// ------------------------------------------------------------------
|
|
116
|
+
// Game gallery (images/videos)
|
|
117
|
+
// ------------------------------------------------------------------
|
|
118
|
+
const { data: gameDetailsImages } = await useAsyncData(
|
|
119
|
+
`campaign-game-images-${slug}`,
|
|
120
|
+
async () => {
|
|
121
|
+
if (!campaign.value?.game_slug) return null
|
|
122
|
+
try {
|
|
123
|
+
const response = await fetchDetailGameImage(locale.value, campaign.value.game_slug)
|
|
124
|
+
return response.data.data || null
|
|
125
|
+
} catch {
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{ watch: [campaign] },
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
const { data: gameDetailsVideos } = await useAsyncData(
|
|
133
|
+
`campaign-game-videos-${slug}`,
|
|
134
|
+
async () => {
|
|
135
|
+
if (!campaign.value?.game_slug) return null
|
|
136
|
+
try {
|
|
137
|
+
const response = await fetchDetailGameVideo(locale.value, campaign.value.game_slug)
|
|
138
|
+
return response.data.data || null
|
|
139
|
+
} catch {
|
|
140
|
+
return null
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{ watch: [campaign] },
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
const showVideoModal = ref(false)
|
|
147
|
+
const selectedVideoUrl = ref("")
|
|
148
|
+
const showImageModal = ref(false)
|
|
149
|
+
const selectedImageUrl = ref("")
|
|
150
|
+
|
|
151
|
+
const openVideoPlayer = (videoUrl: string) => {
|
|
152
|
+
selectedVideoUrl.value = videoUrl
|
|
153
|
+
showVideoModal.value = true
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const openImagePreview = (imageUrl: string) => {
|
|
157
|
+
selectedImageUrl.value = imageUrl
|
|
158
|
+
showImageModal.value = true
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const closeMediaModal = () => {
|
|
162
|
+
showVideoModal.value = false
|
|
163
|
+
showImageModal.value = false
|
|
164
|
+
selectedVideoUrl.value = ""
|
|
165
|
+
selectedImageUrl.value = ""
|
|
166
|
+
}
|
|
167
|
+
|
|
114
168
|
// ------------------------------------------------------------------
|
|
115
169
|
// Countdown
|
|
116
170
|
// ------------------------------------------------------------------
|
|
@@ -570,6 +624,73 @@ onMounted(async () => {
|
|
|
570
624
|
<span>{{ $t("keys.campaigns.campaign.no_data") }}</span>
|
|
571
625
|
</div>
|
|
572
626
|
</div>
|
|
627
|
+
|
|
628
|
+
<div class="gallery" v-if="(gameDetailsImages && gameDetailsImages.length) || (gameDetailsVideos && gameDetailsVideos.length)">
|
|
629
|
+
<template v-if="gameDetailsVideos && gameDetailsVideos.length > 0">
|
|
630
|
+
<div
|
|
631
|
+
v-if="gameDetailsImages"
|
|
632
|
+
v-for="(image, index) in gameDetailsImages.slice(0, 3)"
|
|
633
|
+
:key="'image-' + index"
|
|
634
|
+
class="image-thumbnail"
|
|
635
|
+
@click="openImagePreview('https:' + image.url_image_src)"
|
|
636
|
+
>
|
|
637
|
+
<img :src="'https:' + image.url_image_src" :alt="$t('keys.campaigns.campaign.screenshot_alt')" />
|
|
638
|
+
</div>
|
|
639
|
+
<div
|
|
640
|
+
v-for="(video, index) in gameDetailsVideos.slice(0, 1)"
|
|
641
|
+
:key="'video-' + index"
|
|
642
|
+
class="video-thumbnail"
|
|
643
|
+
@click="openVideoPlayer('https://www.youtube.com/embed/' + video.url_youtube)"
|
|
644
|
+
>
|
|
645
|
+
<img
|
|
646
|
+
:src="'https://img.youtube.com/vi/' + video.url_youtube + '/hqdefault.jpg'"
|
|
647
|
+
:alt="$t('common.video_thumbnail')"
|
|
648
|
+
/>
|
|
649
|
+
<div class="play-icon">
|
|
650
|
+
<MGIcon size="2x" icon="youtube" />
|
|
651
|
+
</div>
|
|
652
|
+
</div>
|
|
653
|
+
</template>
|
|
654
|
+
|
|
655
|
+
<template v-else-if="gameDetailsImages && gameDetailsImages.length > 0">
|
|
656
|
+
<div
|
|
657
|
+
v-for="(image, index) in gameDetailsImages.slice(0, 4)"
|
|
658
|
+
:key="'image-' + index"
|
|
659
|
+
class="image-thumbnail"
|
|
660
|
+
@click="openImagePreview('https:' + image.url_image_src)"
|
|
661
|
+
>
|
|
662
|
+
<img :src="'https:' + image.url_image_src" :alt="$t('keys.campaigns.campaign.screenshot_alt')" />
|
|
663
|
+
</div>
|
|
664
|
+
</template>
|
|
665
|
+
</div>
|
|
666
|
+
|
|
667
|
+
<div class="media-modal" v-if="showVideoModal" @click.self="closeMediaModal">
|
|
668
|
+
<div class="media-modal-content">
|
|
669
|
+
<button class="close-button" @click="closeMediaModal">
|
|
670
|
+
<MGIcon size="1x" icon="close" />
|
|
671
|
+
</button>
|
|
672
|
+
<iframe
|
|
673
|
+
:src="selectedVideoUrl"
|
|
674
|
+
frameborder="0"
|
|
675
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
676
|
+
allowfullscreen
|
|
677
|
+
></iframe>
|
|
678
|
+
</div>
|
|
679
|
+
</div>
|
|
680
|
+
|
|
681
|
+
<div class="media-modal" v-if="showImageModal" @click.self="closeMediaModal">
|
|
682
|
+
<div class="media-modal-content">
|
|
683
|
+
<button class="close-button" @click="closeMediaModal">
|
|
684
|
+
<MGIcon size="1x" icon="close" />
|
|
685
|
+
</button>
|
|
686
|
+
<img :src="selectedImageUrl" :alt="$t('common.expanded_image')" class="expanded-image" />
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
|
|
690
|
+
<div class="game-summary" v-if="campaign?.game_summary">
|
|
691
|
+
<div class="title">{{ $t("keys.campaigns.campaign.about") }}</div>
|
|
692
|
+
<div class="description" v-html="campaign.game_summary"></div>
|
|
693
|
+
</div>
|
|
573
694
|
</div>
|
|
574
695
|
</div>
|
|
575
696
|
|
|
@@ -932,6 +1053,71 @@ onMounted(async () => {
|
|
|
932
1053
|
span { color: var(--card-article-title); }
|
|
933
1054
|
}
|
|
934
1055
|
}
|
|
1056
|
+
|
|
1057
|
+
.gallery {
|
|
1058
|
+
display: grid;
|
|
1059
|
+
grid-template-columns: repeat(4, 1fr);
|
|
1060
|
+
gap: 8px;
|
|
1061
|
+
|
|
1062
|
+
.image-thumbnail, .video-thumbnail {
|
|
1063
|
+
position: relative;
|
|
1064
|
+
aspect-ratio: 16 / 9;
|
|
1065
|
+
overflow: hidden;
|
|
1066
|
+
cursor: pointer;
|
|
1067
|
+
background-color: var(--button-secondary-default-bg);
|
|
1068
|
+
img { width: 100%; height: 100%; object-fit: cover; }
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.video-thumbnail {
|
|
1072
|
+
.play-icon {
|
|
1073
|
+
position: absolute;
|
|
1074
|
+
inset: 0;
|
|
1075
|
+
display: flex;
|
|
1076
|
+
align-items: center;
|
|
1077
|
+
justify-content: center;
|
|
1078
|
+
color: #fff;
|
|
1079
|
+
background: var(--overlay-dark, rgba(0, 0, 0, 0.45));
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
.media-modal {
|
|
1085
|
+
position: fixed;
|
|
1086
|
+
inset: 0;
|
|
1087
|
+
z-index: 1000;
|
|
1088
|
+
display: flex;
|
|
1089
|
+
align-items: center;
|
|
1090
|
+
justify-content: center;
|
|
1091
|
+
background: var(--overlay-dark-strong, rgba(0, 0, 0, 0.75));
|
|
1092
|
+
|
|
1093
|
+
.media-modal-content {
|
|
1094
|
+
position: relative;
|
|
1095
|
+
max-width: 90vw;
|
|
1096
|
+
max-height: 90vh;
|
|
1097
|
+
|
|
1098
|
+
iframe { width: 80vw; height: 45vw; max-height: 80vh; border: none; }
|
|
1099
|
+
.expanded-image { max-width: 90vw; max-height: 90vh; object-fit: contain; }
|
|
1100
|
+
|
|
1101
|
+
.close-button {
|
|
1102
|
+
position: absolute;
|
|
1103
|
+
top: -40px;
|
|
1104
|
+
right: 0;
|
|
1105
|
+
background: transparent;
|
|
1106
|
+
border: none;
|
|
1107
|
+
color: #fff;
|
|
1108
|
+
cursor: pointer;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
.game-summary {
|
|
1114
|
+
display: flex;
|
|
1115
|
+
flex-direction: column;
|
|
1116
|
+
gap: 8px;
|
|
1117
|
+
|
|
1118
|
+
.title { font-size: 14px; font-weight: 600; color: var(--card-article-title); }
|
|
1119
|
+
.description { font-size: 13px; line-height: 1.6; color: var(--secondary-info-fg); }
|
|
1120
|
+
}
|
|
935
1121
|
}
|
|
936
1122
|
}
|
|
937
1123
|
|
|
@@ -52,7 +52,14 @@ async function reveal() {
|
|
|
52
52
|
error.value = $i18n.t("keys.campaigns.error_reveal")
|
|
53
53
|
}
|
|
54
54
|
} catch (e: any) {
|
|
55
|
-
|
|
55
|
+
const code = e?.response?.data?.message || ""
|
|
56
|
+
if (code === "NO_KEYS_AVAILABLE" || code === "KEY_ITEM_NOT_FOUND") {
|
|
57
|
+
error.value = $i18n.t("keys.campaigns.error_no_keys")
|
|
58
|
+
} else if (code === "KEY_NOT_APPROVED") {
|
|
59
|
+
error.value = $i18n.t("keys.campaigns.error_not_approved")
|
|
60
|
+
} else {
|
|
61
|
+
error.value = code || $i18n.t("keys.campaigns.error_reveal")
|
|
62
|
+
}
|
|
56
63
|
} finally {
|
|
57
64
|
revealing.value = false
|
|
58
65
|
}
|
|
@@ -92,7 +99,7 @@ function goBack() {
|
|
|
92
99
|
<div class="skeleton" v-for="i in 2" :key="i" />
|
|
93
100
|
</div>
|
|
94
101
|
|
|
95
|
-
<div v-else-if="error && !
|
|
102
|
+
<div v-else-if="error && !requestData" class="state error">{{ error }}</div>
|
|
96
103
|
|
|
97
104
|
<div v-else class="content">
|
|
98
105
|
<div class="title-bar">
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import axios, { type AxiosInstance } from "axios"
|
|
2
|
+
|
|
3
|
+
// Game catalog service (images, videos, summary) shared across the network.
|
|
4
|
+
// Mirrors tv-frontend's services/games/gameDetails.ts pattern.
|
|
5
|
+
|
|
6
|
+
let _client: AxiosInstance | null = null
|
|
7
|
+
|
|
8
|
+
function getClient(): AxiosInstance {
|
|
9
|
+
if (_client) return _client
|
|
10
|
+
|
|
11
|
+
const baseURL =
|
|
12
|
+
import.meta.env.VITE_BASE_URL_COMMUNITY ||
|
|
13
|
+
import.meta.env.VITE_CAMPAIGN_API_URL ||
|
|
14
|
+
import.meta.env.VITE_BASE_URL_NETWORK ||
|
|
15
|
+
import.meta.env.VITE_API_BASE_URL ||
|
|
16
|
+
""
|
|
17
|
+
|
|
18
|
+
_client = axios.create({ baseURL, withCredentials: true })
|
|
19
|
+
|
|
20
|
+
_client.interceptors.request.use((config) => {
|
|
21
|
+
if (
|
|
22
|
+
import.meta.env.VITE_APP_ENV !== "production" &&
|
|
23
|
+
typeof window !== "undefined" &&
|
|
24
|
+
import.meta.env.VITE_BEARER_TOKEN
|
|
25
|
+
) {
|
|
26
|
+
config.headers.Authorization = `Bearer ${import.meta.env.VITE_BEARER_TOKEN}`
|
|
27
|
+
}
|
|
28
|
+
return config
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return _client
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const client = new Proxy({} as AxiosInstance, {
|
|
35
|
+
get(_t, prop) {
|
|
36
|
+
return (getClient() as any)[prop]
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
export interface GameImage {
|
|
41
|
+
url_image_src: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface GameVideo {
|
|
45
|
+
url_youtube: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const fetchDetailGameImage = (lang: string, slug: string) =>
|
|
49
|
+
client.get<{ data: GameImage[] }>(`/${lang}/games/details/${slug}/images`)
|
|
50
|
+
|
|
51
|
+
export const fetchDetailGameVideo = (lang: string, slug: string) =>
|
|
52
|
+
client.get<{ data: GameVideo[] }>(`/${lang}/games/details/${slug}/videos`)
|