@mundogamernetwork/shared-ui 1.1.60 → 1.1.62

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,389 @@
1
+ import axios, { type AxiosInstance } from "axios"
2
+
3
+ // Campaign service wraps the key-campaigns API used by TV, community, and agency.
4
+ // Two clients:
5
+ // mainClient — public endpoints (/public/keys*), no auth required for listing
6
+ // authClient — authenticated endpoints (/api/v1/*), withCredentials
7
+
8
+ let _mainClient: AxiosInstance | null = null
9
+ let _authClient: AxiosInstance | null = null
10
+
11
+ function getMainClient(): AxiosInstance {
12
+ if (_mainClient) return _mainClient
13
+
14
+ const baseURL =
15
+ import.meta.env.VITE_CAMPAIGN_API_URL ||
16
+ import.meta.env.VITE_API_BASE_URL ||
17
+ ""
18
+
19
+ _mainClient = axios.create({ baseURL })
20
+
21
+ _mainClient.interceptors.request.use((config) => {
22
+ const SUPPORTED_LOCALES = ["en", "pt-BR", "es", "de", "ro", "ar-AE"]
23
+ const seg =
24
+ typeof location === "undefined" ? "" : location.pathname.split("/")[1] || ""
25
+ const lang = SUPPORTED_LOCALES.includes(seg) ? seg : "en"
26
+ config.params = { ...config.params, lang }
27
+ if (
28
+ import.meta.env.VITE_APP_ENV !== "production" &&
29
+ typeof window !== "undefined" &&
30
+ import.meta.env.VITE_BEARER_TOKEN
31
+ ) {
32
+ config.headers.Authorization = `Bearer ${import.meta.env.VITE_BEARER_TOKEN}`
33
+ }
34
+ return config
35
+ })
36
+
37
+ return _mainClient
38
+ }
39
+
40
+ function getAuthClient(): AxiosInstance {
41
+ if (_authClient) return _authClient
42
+
43
+ const baseURL =
44
+ import.meta.env.VITE_CAMPAIGN_API_URL ||
45
+ import.meta.env.VITE_API_BASE_URL ||
46
+ ""
47
+
48
+ _authClient = axios.create({ baseURL, withCredentials: true })
49
+
50
+ _authClient.interceptors.request.use((config) => {
51
+ const SUPPORTED_LOCALES = ["en", "pt-BR", "es", "de", "ro", "ar-AE"]
52
+ const seg =
53
+ typeof location === "undefined" ? "" : location.pathname.split("/")[1] || ""
54
+ const lang = SUPPORTED_LOCALES.includes(seg) ? seg : "en"
55
+ config.params = { ...config.params, lang }
56
+ if (
57
+ import.meta.env.VITE_APP_ENV !== "production" &&
58
+ typeof window !== "undefined" &&
59
+ import.meta.env.VITE_BEARER_TOKEN
60
+ ) {
61
+ config.headers.Authorization = `Bearer ${import.meta.env.VITE_BEARER_TOKEN}`
62
+ }
63
+ return config
64
+ })
65
+
66
+ return _authClient
67
+ }
68
+
69
+ // Lazy proxies so the clients are only initialised when first used
70
+ const mainClient = new Proxy({} as AxiosInstance, {
71
+ get(_t, prop) {
72
+ return (getMainClient() as any)[prop]
73
+ },
74
+ })
75
+
76
+ const authClient = new Proxy({} as AxiosInstance, {
77
+ get(_t, prop) {
78
+ return (getAuthClient() as any)[prop]
79
+ },
80
+ })
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Types
84
+ // ---------------------------------------------------------------------------
85
+
86
+ export interface Campaign {
87
+ id: number
88
+ name: string
89
+ slug: string
90
+ cover_src: string
91
+ featured: boolean
92
+ type: {
93
+ id: number
94
+ name: string
95
+ }
96
+ game: {
97
+ id: number
98
+ url_banner_src: string
99
+ url_cover_src?: string
100
+ slug?: string
101
+ name?: string
102
+ summary?: string
103
+ }
104
+ time_to_expire: string
105
+ end_date?: string
106
+ start_date?: string
107
+ available_count?: number
108
+ is_exclusive?: boolean
109
+ is_tier_locked?: boolean
110
+ access_tier?: string
111
+ early_access_hours?: number
112
+ user_can_access?: boolean
113
+ available_at_for_user?: string | null
114
+ max_keys_for_user?: number
115
+ streamer_type_id?: number
116
+ status?: number | boolean
117
+ quantity?: number
118
+ request_user_status?: number
119
+ platforms?: Array<{ id: number; name: string; slug: string }>
120
+ regions?: Array<{ id: number; name: string; slug: string }>
121
+ requests?: Array<{ id: number; key_item_id?: number; admin_notes?: string }>
122
+ company?: { name: string; email?: string; twitter?: string; thumbnail_url?: string }
123
+ streamer_type?: { description?: string }
124
+ meets_streamer_level?: boolean
125
+ }
126
+
127
+ export interface CampaignRequest {
128
+ id: number
129
+ status_request: {
130
+ id: number
131
+ slug: string
132
+ name: string
133
+ color: string
134
+ }
135
+ key: Campaign
136
+ key_item_id?: number
137
+ }
138
+
139
+ export interface CampaignType {
140
+ id: number
141
+ name: string
142
+ localized_name?: string
143
+ }
144
+
145
+ export interface Platform {
146
+ id: number
147
+ name: string
148
+ slug: string
149
+ }
150
+
151
+ export interface CampaignsResponse {
152
+ data: Campaign[]
153
+ meta: {
154
+ pagination: {
155
+ total: number
156
+ count: number
157
+ per_page: number
158
+ current_page: number
159
+ total_pages: number
160
+ links?: { previous?: string; next?: string }
161
+ }
162
+ }
163
+ status: string
164
+ }
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // Helpers
168
+ // ---------------------------------------------------------------------------
169
+
170
+ function buildListParams(opts: {
171
+ filter?: Record<string, any>
172
+ page?: number
173
+ per_page?: number | string
174
+ sort?: string
175
+ order?: string
176
+ }): Record<string, any> {
177
+ const params: Record<string, any> = {}
178
+ if (opts.page !== undefined) params["page"] = opts.page
179
+ if (opts.per_page !== undefined) params["per_page"] = opts.per_page
180
+ if (opts.sort) params["sort"] = opts.sort
181
+ if (opts.order) params["order"] = opts.order
182
+ if (opts.filter) {
183
+ for (const [k, v] of Object.entries(opts.filter)) {
184
+ params[`filter[${k}]`] = v
185
+ }
186
+ }
187
+ return params
188
+ }
189
+
190
+ // ---------------------------------------------------------------------------
191
+ // Public endpoints (mainClient — no auth)
192
+ // ---------------------------------------------------------------------------
193
+
194
+ /**
195
+ * List campaigns.
196
+ * @param params - filter/page/sort params (may include filter[type_id], filter[platform_id], etc.)
197
+ * @param mgPlatform - platform tag injected as filter[mg_platform] (default: 'MGTV')
198
+ */
199
+ export const fetchCampaigns = (
200
+ params: Record<string, any> = {},
201
+ mgPlatform = "MGTV",
202
+ ) => {
203
+ return mainClient.get<CampaignsResponse>("/public/keys", {
204
+ params: {
205
+ ...buildListParams({
206
+ filter: {
207
+ ...(params.filter || {}),
208
+ include_early_access_locked: true,
209
+ mg_platform: mgPlatform,
210
+ },
211
+ page: params.page || 1,
212
+ per_page: params.per_page || 15,
213
+ sort: params.sort || "id",
214
+ order: params.order || "desc",
215
+ }),
216
+ // pass through any extra flat params (e.g. filter[type_id])
217
+ ...Object.fromEntries(
218
+ Object.entries(params).filter(([k]) => !["page", "per_page", "sort", "order", "filter"].includes(k)),
219
+ ),
220
+ },
221
+ })
222
+ }
223
+
224
+ /**
225
+ * List featured campaigns shown in the hero slider.
226
+ * @param mgPlatform - platform tag (default: 'MGTV')
227
+ */
228
+ export const fetchFeaturedCampaigns = (mgPlatform = "MGTV") => {
229
+ return mainClient.get<CampaignsResponse>("/public/keys", {
230
+ params: buildListParams({
231
+ filter: {
232
+ is_public: true,
233
+ status: 1,
234
+ mg_platform: mgPlatform,
235
+ },
236
+ sort: "id",
237
+ order: "desc",
238
+ per_page: 12,
239
+ }),
240
+ })
241
+ }
242
+
243
+ /**
244
+ * Fetch a single campaign by slug and return a normalised shape.
245
+ */
246
+ export const fetchCampaignBySlug = async (slug: string) => {
247
+ const { data } = await mainClient.get(`/public/keys/${slug}`)
248
+
249
+ if (!data?.data) throw new Error("Campaign data not found")
250
+
251
+ const k = data.data
252
+ return {
253
+ id: k.id,
254
+ name: k.name,
255
+ slug: k.slug,
256
+ cover: k.cover_src,
257
+ game_cover: k.game?.url_cover_src,
258
+ game_slug: k.game?.slug,
259
+ time_to_expire: k.time_to_expire,
260
+ request_status: k.request_user_status,
261
+ end: k.end_date,
262
+ start: k.start_date,
263
+ company: k.company?.name,
264
+ email: k.company?.email,
265
+ twitter: k.company?.twitter,
266
+ logo: k.company?.thumbnail_url,
267
+ status: k.status,
268
+ quantity: k.quantity,
269
+ available_count: k.available_count ?? 0,
270
+ streamer_type: k.streamer_type_id,
271
+ streamer_description: k.streamer_type?.description,
272
+ access_tier: k.access_tier ?? "free",
273
+ is_exclusive: k.is_exclusive ?? false,
274
+ is_tier_locked: k.is_tier_locked ?? false,
275
+ early_access_hours: k.early_access_hours ?? 0,
276
+ user_can_access: k.user_can_access !== false,
277
+ meets_streamer_level: k.meets_streamer_level !== false,
278
+ available_at_for_user: k.available_at_for_user ?? null,
279
+ max_keys_for_user: k.max_keys_for_user ?? 1,
280
+ game_summary: k.game?.summary,
281
+ request_id: k.requests?.[0]?.id,
282
+ request_item_id: k.requests?.[0]?.key_item_id,
283
+ request_admin_notes: k.requests?.[0]?.admin_notes ?? null,
284
+ platforms: (k.platforms || []).map((p: any) => ({ id: p.id, name: p.name, slug: p.slug })),
285
+ regions: (k.regions || []).map((r: any) => ({ id: r.id, name: r.name, slug: r.slug })),
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Fetch platforms for a specific campaign (public).
291
+ */
292
+ export const fetchKeyPlatforms = (keyId: number, params: Record<string, any> = {}) => {
293
+ return mainClient.get(`/public/keys/${keyId}/platforms`, { params })
294
+ }
295
+
296
+ /**
297
+ * Fetch regions for a specific campaign (public).
298
+ */
299
+ export const fetchKeyRegions = (keyId: number, params: Record<string, any> = {}) => {
300
+ return mainClient.get(`/public/keys/${keyId}/regions`, { params })
301
+ }
302
+
303
+ // ---------------------------------------------------------------------------
304
+ // Auth-required endpoints (authClient — withCredentials)
305
+ // ---------------------------------------------------------------------------
306
+
307
+ /**
308
+ * Fetch available campaign types.
309
+ */
310
+ export const fetchCampaignTypes = (params: Record<string, any> = {}) => {
311
+ const queryString = Object.entries(params)
312
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
313
+ .join("&")
314
+ return authClient.get(`/api/v1/public/key-types${queryString ? `?${queryString}` : ""}`)
315
+ }
316
+
317
+ /**
318
+ * Fetch active platforms (for the platform filter select).
319
+ */
320
+ export const fetchCampaignPlatforms = () => {
321
+ return authClient.get("/api/v1/platforms/currently")
322
+ }
323
+
324
+ /**
325
+ * Fetch the authenticated user's own key requests.
326
+ */
327
+ export const fetchMyRequests = (params: Record<string, any> = {}) => {
328
+ const queryString = Object.entries(params)
329
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
330
+ .join("&")
331
+ return authClient.get(`/api/v1/key-requests-me${queryString ? `?${queryString}` : ""}`)
332
+ }
333
+
334
+ /**
335
+ * Fetch users who have redeemed a specific campaign key.
336
+ */
337
+ export const fetchRedeemedUsers = (
338
+ keyId: number,
339
+ params: Record<string, any> = {},
340
+ includeMaterials = false,
341
+ ) => {
342
+ const merged = includeMaterials ? { ...params, include: "materials" } : params
343
+ const queryString = Object.entries(merged)
344
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
345
+ .join("&")
346
+ return authClient.get(`/api/v1/public/keys/${keyId}/redeemed-users${queryString ? `?${queryString}` : ""}`)
347
+ }
348
+
349
+ /**
350
+ * Request a key for a campaign.
351
+ */
352
+ export const requestKey = (data: Record<string, any>) => {
353
+ return authClient.post("/api/v1/public/key-requests", data)
354
+ }
355
+
356
+ /**
357
+ * Reveal a previously granted key.
358
+ */
359
+ export const revealKey = (requestId: number) => {
360
+ return authClient.get(`/api/v1/public/key-requests/${requestId}/reveal`)
361
+ }
362
+
363
+ /**
364
+ * Fetch required actions for a campaign.
365
+ */
366
+ export const fetchKeyActions = (keyId: number) => {
367
+ return authClient.get(`/api/v1/public/keys/${keyId}/actions`)
368
+ }
369
+
370
+ /**
371
+ * Submit a content material for a key request.
372
+ */
373
+ export const submitMaterial = (data: Record<string, any>) => {
374
+ return authClient.post("/api/v1/public/key-materials", data)
375
+ }
376
+
377
+ /**
378
+ * Fetch all materials submitted for a key request.
379
+ */
380
+ export const fetchMaterialsByRequest = (requestId: number) => {
381
+ return authClient.get(`/api/v1/public/key-materials?filter[key_request_id]=${requestId}&per_page=all`)
382
+ }
383
+
384
+ /**
385
+ * Fetch a single key request by ID.
386
+ */
387
+ export const fetchKeyRequestById = (requestId: number) => {
388
+ return authClient.get(`/api/v1/public/key-requests/${requestId}`)
389
+ }
@@ -0,0 +1,161 @@
1
+ import { defineStore } from "pinia"
2
+ import {
3
+ fetchCampaigns,
4
+ fetchFeaturedCampaigns,
5
+ fetchMyRequests,
6
+ fetchCampaignTypes,
7
+ fetchCampaignPlatforms,
8
+ type Campaign,
9
+ type CampaignType,
10
+ type Platform,
11
+ } from "../services/campaignService"
12
+
13
+ interface CampaignListState {
14
+ data: Campaign[]
15
+ status: "init" | "pending" | "success" | "error"
16
+ total: number
17
+ }
18
+
19
+ interface CampaignTypeState {
20
+ data: CampaignType[]
21
+ status: "init" | "pending" | "success" | "error"
22
+ }
23
+
24
+ interface PlatformState {
25
+ data: Platform[]
26
+ status: "init" | "pending" | "success" | "error"
27
+ }
28
+
29
+ interface MyRequestsState {
30
+ data: any[]
31
+ status: "init" | "pending" | "success" | "error"
32
+ }
33
+
34
+ interface FeaturedCampaignsState {
35
+ data: Campaign[]
36
+ status: "init" | "pending" | "success" | "error"
37
+ }
38
+
39
+ export const useCampaignsStore = defineStore("campaigns-store", {
40
+ state: () => ({
41
+ campaigns: {
42
+ data: [] as Campaign[],
43
+ status: "init",
44
+ total: 0,
45
+ } as CampaignListState,
46
+
47
+ featuredCampaigns: {
48
+ data: [] as Campaign[],
49
+ status: "init",
50
+ } as FeaturedCampaignsState,
51
+
52
+ myRequests: {
53
+ data: [] as any[],
54
+ status: "init",
55
+ } as MyRequestsState,
56
+
57
+ campaignTypes: {
58
+ data: [] as CampaignType[],
59
+ status: "init",
60
+ } as CampaignTypeState,
61
+
62
+ platforms: {
63
+ data: [] as Platform[],
64
+ status: "init",
65
+ } as PlatformState,
66
+ }),
67
+
68
+ actions: {
69
+ async fetchCampaigns(params: Record<string, any> = {}, mgPlatform?: string) {
70
+ this.campaigns.status = "pending"
71
+ try {
72
+ const response = await fetchCampaigns(params, mgPlatform)
73
+ this.campaigns.data = response.data.data
74
+ this.campaigns.total = response.data.meta?.pagination?.total ?? response.data.data.length
75
+ this.campaigns.status = "success"
76
+ return response.data
77
+ } catch (error) {
78
+ this.campaigns.status = "error"
79
+ throw error
80
+ }
81
+ },
82
+
83
+ async fetchFeaturedCampaigns(mgPlatform?: string) {
84
+ this.featuredCampaigns.status = "pending"
85
+ try {
86
+ const response = await fetchFeaturedCampaigns(mgPlatform)
87
+ this.featuredCampaigns.data = response.data.data
88
+ this.featuredCampaigns.status = "success"
89
+ return response.data
90
+ } catch (error) {
91
+ this.featuredCampaigns.status = "error"
92
+ throw error
93
+ }
94
+ },
95
+
96
+ async fetchMyRequests(params: Record<string, any> = {}) {
97
+ this.myRequests.status = "pending"
98
+ try {
99
+ const response = await fetchMyRequests(params)
100
+ this.myRequests.data = response.data.data || response.data
101
+ this.myRequests.status = "success"
102
+ return response.data
103
+ } catch (error) {
104
+ this.myRequests.status = "error"
105
+ throw error
106
+ }
107
+ },
108
+
109
+ async fetchCampaignTypes() {
110
+ this.campaignTypes.status = "pending"
111
+ try {
112
+ const response = await fetchCampaignTypes({
113
+ "filter[only_used]": 1,
114
+ page: 1,
115
+ per_page: 50,
116
+ sort: "id",
117
+ order: "asc",
118
+ })
119
+ this.campaignTypes.data = response.data.data || response.data
120
+ this.campaignTypes.status = "success"
121
+ return response.data
122
+ } catch (error) {
123
+ this.campaignTypes.status = "error"
124
+ throw error
125
+ }
126
+ },
127
+
128
+ async fetchCampaignPlatforms() {
129
+ this.platforms.status = "pending"
130
+ try {
131
+ const response = await fetchCampaignPlatforms()
132
+ this.platforms.data = (response.data.data || response.data).map((p: any) => ({
133
+ id: p.id,
134
+ name: p.name,
135
+ slug: p.slug,
136
+ }))
137
+ this.platforms.status = "success"
138
+ return response.data
139
+ } catch (error) {
140
+ this.platforms.status = "error"
141
+ throw error
142
+ }
143
+ },
144
+
145
+ resetCampaigns() {
146
+ this.campaigns.data = []
147
+ this.campaigns.status = "init"
148
+ this.campaigns.total = 0
149
+ },
150
+ },
151
+
152
+ getters: {
153
+ allCampaigns: (state) => state.campaigns.data,
154
+ allFeaturedCampaigns: (state) => state.featuredCampaigns.data,
155
+ allMyRequests: (state) => state.myRequests.data,
156
+ allCampaignTypes: (state) => state.campaignTypes.data,
157
+ allPlatforms: (state) => state.platforms.data,
158
+ isLoading: (state) =>
159
+ state.campaigns.status === "pending" || state.myRequests.status === "pending",
160
+ },
161
+ })