@mundogamernetwork/shared-ui 1.0.0
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/README.md +283 -0
- package/components/PressKit/AssetGallery.vue +349 -0
- package/components/PressKit/Awards.vue +100 -0
- package/components/PressKit/Credits.vue +78 -0
- package/components/PressKit/FactSheet.vue +204 -0
- package/components/PressKit/Hero.vue +143 -0
- package/components/PressKit/Quotes.vue +80 -0
- package/components/PressKit/VideoPlayer.vue +134 -0
- package/components/checkout/MgCartItemList.vue +214 -0
- package/components/checkout/MgCartSummary.vue +204 -0
- package/components/checkout/MgCheckoutSidebar.vue +230 -0
- package/components/checkout/MgGuestEmailForm.vue +97 -0
- package/components/checkout/MgPaymentMethodSelector.vue +162 -0
- package/components/checkout/MgPixQRCode.vue +222 -0
- package/components/indie-wall/IndieWallLeaderboard.vue +208 -0
- package/components/indie-wall/MuralCanvas.vue +481 -0
- package/components/indie-wall/StepBlock.vue +314 -0
- package/components/indie-wall/StepCustomize.vue +530 -0
- package/components/indie-wall/StepGoal.vue +169 -0
- package/components/indie-wall/StepPackage.vue +145 -0
- package/components/indie-wall/StepPay.vue +209 -0
- package/components/indie-wall/SupportStepper.vue +372 -0
- package/components/invoices/MgInvoiceDownload.vue +50 -0
- package/components/pricing/MgBillingToggle.vue +74 -0
- package/components/pricing/MgPricingCard.vue +245 -0
- package/components/ui/Header/MgMessageCard.vue +147 -0
- package/components/ui/Header/MgMessageModal.vue +414 -0
- package/components/ui/Header/MgNotificationCard.vue +200 -0
- package/components/ui/Header/MgNotificationsModal.vue +125 -0
- package/components/ui/MgAnnouncementBanner.vue +147 -0
- package/components/ui/MgBanners.vue +23 -0
- package/components/ui/MgHeaderComponent.vue +283 -0
- package/components/ui/MgHeaderUIConfig.vue +225 -0
- package/components/ui/MgHeaderUIUser.vue +301 -0
- package/components/ui/MgLoginModal.vue +156 -0
- package/components/ui/MgPromotionBanner.vue +185 -0
- package/composables/useLogout.ts +42 -0
- package/composables/useMgCheckout.ts +287 -0
- package/composables/useMgUserNotifications.ts +122 -0
- package/composables/usePaymentMethods.ts +75 -0
- package/composables/useSubscription.ts +163 -0
- package/middleware/auth.global.ts +40 -0
- package/nuxt.config.ts +31 -0
- package/package.json +40 -0
- package/pages/[slug]/index.vue +112 -0
- package/pages/about.vue +133 -0
- package/pages/blog.vue +430 -0
- package/pages/careers.vue +329 -0
- package/pages/contact.vue +339 -0
- package/pages/faq.vue +317 -0
- package/pages/health-check.vue +20 -0
- package/pages/icons.vue +58 -0
- package/pages/magazine/[slug].vue +209 -0
- package/pages/magazine/index.vue +267 -0
- package/pages/media-kit/[slug].vue +625 -0
- package/pages/mural/[slug].vue +1058 -0
- package/pages/partners.vue +290 -0
- package/pages/press.vue +237 -0
- package/pages/presskit/[slug].vue +191 -0
- package/pages/roadmap.vue +355 -0
- package/pages/status.vue +199 -0
- package/pages/team.vue +266 -0
- package/pages/wall/[slug].vue +11 -0
- package/plugins/auth.client.ts +17 -0
- package/plugins/echo.client.ts +132 -0
- package/services/authService.ts +95 -0
- package/services/chatService.ts +53 -0
- package/services/contactService.ts +35 -0
- package/services/documentService.ts +16 -0
- package/services/httpService.ts +95 -0
- package/services/indieWallService.ts +174 -0
- package/services/institutionalService.ts +248 -0
- package/services/mediaKitService.ts +51 -0
- package/services/notificationsService.ts +20 -0
- package/services/pressKitService.ts +55 -0
- package/stores/announcement.ts +129 -0
- package/stores/auth.ts +86 -0
- package/stores/chat.ts +150 -0
- package/stores/contact.ts +28 -0
- package/stores/document.ts +27 -0
- package/stores/index.ts +34 -0
- package/stores/institutional.ts +231 -0
- package/stores/login.ts +27 -0
- package/stores/notifications.ts +133 -0
- package/stores/promotion.ts +154 -0
- package/types/index.ts +135 -0
- package/utils/serialize.ts +29 -0
package/pages/team.vue
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { storeToRefs } from "pinia";
|
|
3
|
+
|
|
4
|
+
definePageMeta({ layout: "default" });
|
|
5
|
+
|
|
6
|
+
const institutionalStore = useInstitutionalStore();
|
|
7
|
+
const { team, operationalArea } = storeToRefs(institutionalStore);
|
|
8
|
+
|
|
9
|
+
const selectedArea = ref<string | number>("");
|
|
10
|
+
|
|
11
|
+
async function fetchTeamData() {
|
|
12
|
+
try {
|
|
13
|
+
const params: any = {
|
|
14
|
+
filter: { status: 1 },
|
|
15
|
+
sort: "name",
|
|
16
|
+
order: "asc",
|
|
17
|
+
per_page: "all",
|
|
18
|
+
};
|
|
19
|
+
if (selectedArea.value) params.filter.operational_area_id = selectedArea.value;
|
|
20
|
+
await institutionalStore.fetchTeam(params);
|
|
21
|
+
} catch {
|
|
22
|
+
// silent
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function fetchAreas() {
|
|
27
|
+
try {
|
|
28
|
+
await institutionalStore.fetchOperationalArea({ per_page: "all" });
|
|
29
|
+
} catch {
|
|
30
|
+
// silent
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function selectArea(areaId: string | number) {
|
|
35
|
+
selectedArea.value = selectedArea.value === areaId ? "" : areaId;
|
|
36
|
+
fetchTeamData();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
onMounted(async () => {
|
|
40
|
+
fetchTeamData();
|
|
41
|
+
fetchAreas();
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<div id="team" class="container team">
|
|
47
|
+
<section>
|
|
48
|
+
<div class="header">
|
|
49
|
+
<div>
|
|
50
|
+
<h1 class="title-4">{{ $t("more.team.title") }}</h1>
|
|
51
|
+
<p>{{ $t("more.team.subtitle") }}</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="container">
|
|
55
|
+
<div class="row">
|
|
56
|
+
<div class="col-8 offset-2">
|
|
57
|
+
<div class="area-tabs" v-if="operationalArea?.data?.data">
|
|
58
|
+
<button
|
|
59
|
+
class="area-tab"
|
|
60
|
+
:class="{ active: selectedArea === '' }"
|
|
61
|
+
@click="selectArea('')"
|
|
62
|
+
>
|
|
63
|
+
{{ $t("more.team.all") }}
|
|
64
|
+
</button>
|
|
65
|
+
<button
|
|
66
|
+
v-for="area in operationalArea.data.data"
|
|
67
|
+
:key="area.id"
|
|
68
|
+
class="area-tab"
|
|
69
|
+
:class="{ active: selectedArea === area.id }"
|
|
70
|
+
@click="selectArea(area.id)"
|
|
71
|
+
>
|
|
72
|
+
{{ area.localized_name || area.name }}
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div v-if="team.status === 'pending'" class="loading">
|
|
77
|
+
<p>{{ $t("components.loading") }}</p>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div v-else-if="team?.data?.data && team.data.data.length > 0" class="team-grid">
|
|
81
|
+
<div
|
|
82
|
+
v-for="member in team.data.data"
|
|
83
|
+
:key="member.id"
|
|
84
|
+
class="team-card"
|
|
85
|
+
>
|
|
86
|
+
<img
|
|
87
|
+
:src="member.avatar_url || '/imgs/default.jpg'"
|
|
88
|
+
:alt="member.name"
|
|
89
|
+
class="team-card__avatar"
|
|
90
|
+
/>
|
|
91
|
+
<div class="team-card__info">
|
|
92
|
+
<h3>{{ member.name }}</h3>
|
|
93
|
+
<p class="role">{{ member.role || member.operational_area?.name }}</p>
|
|
94
|
+
<p class="description" v-if="member.localized_description">
|
|
95
|
+
{{ member.localized_description }}
|
|
96
|
+
</p>
|
|
97
|
+
<div class="team-card__countries" v-if="member.countries?.length">
|
|
98
|
+
<img
|
|
99
|
+
v-for="c in member.countries"
|
|
100
|
+
:key="c.id"
|
|
101
|
+
:src="c.flag_svg_src || c.flag_32_url"
|
|
102
|
+
:alt="c.name"
|
|
103
|
+
class="flag"
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="team-card__social" v-if="member.social_links?.length">
|
|
107
|
+
<a
|
|
108
|
+
v-for="link in member.social_links"
|
|
109
|
+
:key="link.url"
|
|
110
|
+
:href="link.url"
|
|
111
|
+
target="_blank"
|
|
112
|
+
rel="noopener"
|
|
113
|
+
>
|
|
114
|
+
<MGIcon :icon="link.platform || 'link'" />
|
|
115
|
+
</a>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div v-else class="no-data">
|
|
122
|
+
{{ $t("more.team.no_data") }}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</section>
|
|
128
|
+
</div>
|
|
129
|
+
</template>
|
|
130
|
+
|
|
131
|
+
<style lang="scss" scoped>
|
|
132
|
+
.team {
|
|
133
|
+
color: var(--inactive);
|
|
134
|
+
font-size: 0.875rem;
|
|
135
|
+
|
|
136
|
+
.header {
|
|
137
|
+
position: relative;
|
|
138
|
+
height: 200px;
|
|
139
|
+
display: flex;
|
|
140
|
+
justify-content: center;
|
|
141
|
+
align-items: center;
|
|
142
|
+
margin-bottom: 2rem;
|
|
143
|
+
|
|
144
|
+
& > div {
|
|
145
|
+
width: 480px;
|
|
146
|
+
text-align: center;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&:before {
|
|
150
|
+
content: " ";
|
|
151
|
+
display: block;
|
|
152
|
+
position: absolute;
|
|
153
|
+
background: url("@/assets/images/bg-team.png") no-repeat center center / cover;
|
|
154
|
+
width: 100%;
|
|
155
|
+
height: 100%;
|
|
156
|
+
top: 50%;
|
|
157
|
+
transform: translateY(-50%);
|
|
158
|
+
z-index: -1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.area-tabs {
|
|
163
|
+
display: flex;
|
|
164
|
+
flex-wrap: wrap;
|
|
165
|
+
gap: 8px;
|
|
166
|
+
margin-bottom: 24px;
|
|
167
|
+
|
|
168
|
+
.area-tab {
|
|
169
|
+
padding: 6px 16px;
|
|
170
|
+
border: 1px solid var(--search-bar-border-color);
|
|
171
|
+
background: transparent;
|
|
172
|
+
color: var(--inactive);
|
|
173
|
+
font-size: 14px;
|
|
174
|
+
cursor: pointer;
|
|
175
|
+
transition: all 0.2s;
|
|
176
|
+
|
|
177
|
+
&.active {
|
|
178
|
+
background: var(--chip-text);
|
|
179
|
+
color: var(--chip-background-2);
|
|
180
|
+
border-color: var(--chip-text);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.team-grid {
|
|
186
|
+
display: grid;
|
|
187
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
188
|
+
gap: 24px;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.team-card {
|
|
192
|
+
background-color: var(--chip-background-2);
|
|
193
|
+
text-align: center;
|
|
194
|
+
padding: 16px;
|
|
195
|
+
|
|
196
|
+
&__avatar {
|
|
197
|
+
width: 96px;
|
|
198
|
+
height: 96px;
|
|
199
|
+
border-radius: 50%;
|
|
200
|
+
object-fit: cover;
|
|
201
|
+
margin-bottom: 12px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
&__info {
|
|
205
|
+
h3 {
|
|
206
|
+
font-size: 14px;
|
|
207
|
+
font-weight: 600;
|
|
208
|
+
color: var(--card-cover-title);
|
|
209
|
+
margin-bottom: 4px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.role {
|
|
213
|
+
font-size: 12px;
|
|
214
|
+
color: var(--chip-text);
|
|
215
|
+
margin-bottom: 8px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.description {
|
|
219
|
+
font-size: 12px;
|
|
220
|
+
line-height: 16px;
|
|
221
|
+
margin-bottom: 8px;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
&__countries {
|
|
226
|
+
display: flex;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
gap: 4px;
|
|
229
|
+
margin-bottom: 8px;
|
|
230
|
+
|
|
231
|
+
.flag {
|
|
232
|
+
width: 20px;
|
|
233
|
+
height: 14px;
|
|
234
|
+
object-fit: cover;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
&__social {
|
|
239
|
+
display: flex;
|
|
240
|
+
justify-content: center;
|
|
241
|
+
gap: 8px;
|
|
242
|
+
|
|
243
|
+
a {
|
|
244
|
+
color: var(--inactive);
|
|
245
|
+
font-size: 16px;
|
|
246
|
+
|
|
247
|
+
&:hover {
|
|
248
|
+
color: var(--chip-text);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.no-data {
|
|
255
|
+
text-align: center;
|
|
256
|
+
padding: 32px;
|
|
257
|
+
color: var(--secondary-info-fg);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@media screen and (max-width: 768px) {
|
|
262
|
+
.team .team-grid {
|
|
263
|
+
grid-template-columns: repeat(2, 1fr);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const route = useRoute()
|
|
3
|
+
const localePath = useLocalePath()
|
|
4
|
+
const slug = route.params.slug as string
|
|
5
|
+
const qs = Object.keys(route.query).length
|
|
6
|
+
? '?' + new URLSearchParams(route.query as Record<string, string>).toString()
|
|
7
|
+
: ''
|
|
8
|
+
navigateTo(localePath(`/mural/${slug}`) + qs, { replace: true })
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template><div /></template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default defineNuxtPlugin({
|
|
2
|
+
name: "shared-ui-auth",
|
|
3
|
+
enforce: "pre",
|
|
4
|
+
parallel: true,
|
|
5
|
+
async setup() {
|
|
6
|
+
try {
|
|
7
|
+
const authStore = useAuthStore();
|
|
8
|
+
|
|
9
|
+
if (!authStore.signedIn) {
|
|
10
|
+
await authStore.getUser();
|
|
11
|
+
}
|
|
12
|
+
} catch (e) {
|
|
13
|
+
// Auth store may not be available in all extending frontends
|
|
14
|
+
console.warn("[shared-ui Auth] Failed to initialize auth:", e);
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Echo from "laravel-echo";
|
|
2
|
+
import Pusher from "pusher-js";
|
|
3
|
+
import axios from "axios";
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
interface Window {
|
|
7
|
+
Pusher: any;
|
|
8
|
+
Echo: any;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default defineNuxtPlugin({
|
|
13
|
+
name: "shared-ui-echo",
|
|
14
|
+
enforce: "post",
|
|
15
|
+
parallel: true,
|
|
16
|
+
setup(nuxtApp) {
|
|
17
|
+
// Skip if already provided by the extending frontend's own Echo plugin
|
|
18
|
+
if (nuxtApp.$echo || window.Echo) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const pusherKey = import.meta.env.VITE_MIX_PUSHER_APP_KEY;
|
|
23
|
+
const pusherHost = import.meta.env.VITE_MIX_PUSHER_HOST;
|
|
24
|
+
|
|
25
|
+
// Skip if credentials are not configured
|
|
26
|
+
if (!pusherKey || !pusherHost) {
|
|
27
|
+
console.warn("[shared-ui Echo] Pusher credentials not configured, skipping");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const headers: Record<string, string> = {
|
|
32
|
+
Accept: "application/json",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (import.meta.env.VITE_BEARER_TOKEN) {
|
|
36
|
+
headers.Authorization = `Bearer ${import.meta.env.VITE_BEARER_TOKEN}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
window.Pusher = Pusher;
|
|
40
|
+
window.Echo = new Echo({
|
|
41
|
+
broadcaster: "pusher",
|
|
42
|
+
key: import.meta.env.VITE_MIX_PUSHER_APP_KEY,
|
|
43
|
+
cluster: import.meta.env.VITE_MIX_PUSHER_APP_CLUSTER ?? "mt1",
|
|
44
|
+
wsHost: import.meta.env.VITE_MIX_PUSHER_HOST,
|
|
45
|
+
wsPort: import.meta.env.VITE_MIX_PUSHER_PORT ?? 80,
|
|
46
|
+
wssPort: import.meta.env.VITE_MIX_PUSHER_PORT ?? 443,
|
|
47
|
+
forceTLS: (import.meta.env.VITE_MIX_PUSHER_SCHEME ?? "https") === "https",
|
|
48
|
+
enabledTransports: ["ws", "wss"],
|
|
49
|
+
disableStats: true,
|
|
50
|
+
enableLogging: import.meta.env.VITE_APP_ENV !== "production",
|
|
51
|
+
activityTimeout: 30000,
|
|
52
|
+
pongTimeout: 5000,
|
|
53
|
+
authorizer: (channel: any) => {
|
|
54
|
+
return {
|
|
55
|
+
authorize: (socketId: any, callback: any) => {
|
|
56
|
+
axios
|
|
57
|
+
.post(
|
|
58
|
+
import.meta.env.VITE_PUSHER_AUTH,
|
|
59
|
+
{
|
|
60
|
+
socket_id: socketId,
|
|
61
|
+
channel_name: channel.name,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
withCredentials: true,
|
|
65
|
+
headers: headers,
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
.then((response) => {
|
|
69
|
+
callback(false, response.data);
|
|
70
|
+
})
|
|
71
|
+
.catch((error) => {
|
|
72
|
+
callback(true, error);
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
window.Echo.connector.pusher.connection.bind("connected", () => {
|
|
80
|
+
console.log("[WebSocket] Connected", new Date().toISOString());
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
window.Echo.connector.pusher.connection.bind("disconnected", () => {
|
|
84
|
+
console.log("[WebSocket] Disconnected", new Date().toISOString());
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
window.Echo.connector.pusher.connection.bind("error", (error: any) => {
|
|
88
|
+
console.error("[WebSocket] Connection error:", error, new Date().toISOString());
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
let reconnectTimer: number | null = null;
|
|
92
|
+
let reconnectAttempts = 0;
|
|
93
|
+
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
94
|
+
|
|
95
|
+
window.Echo.connector.pusher.connection.bind("state_change", (states: any) => {
|
|
96
|
+
const { previous, current } = states;
|
|
97
|
+
console.log(`[WebSocket] State changed: ${previous} -> ${current}`);
|
|
98
|
+
|
|
99
|
+
if (current === "disconnected" || current === "failed" || current === "unavailable") {
|
|
100
|
+
// Stop reconnecting after max attempts to avoid infinite loop
|
|
101
|
+
// (e.g. when user is not authenticated)
|
|
102
|
+
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
103
|
+
console.log("[WebSocket] Max reconnect attempts reached, stopping.");
|
|
104
|
+
if (reconnectTimer) {
|
|
105
|
+
clearTimeout(reconnectTimer);
|
|
106
|
+
reconnectTimer = null;
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
reconnectAttempts++;
|
|
112
|
+
const delay = Math.min(1000 * Math.pow(2, reconnectAttempts - 1), 30000);
|
|
113
|
+
console.log(`[WebSocket] Reconnecting in ${delay / 1000}s (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
|
|
114
|
+
|
|
115
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
116
|
+
reconnectTimer = window.setTimeout(() => {
|
|
117
|
+
window.Echo.connector.pusher.connect();
|
|
118
|
+
}, delay);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (current === "connected") {
|
|
122
|
+
reconnectAttempts = 0;
|
|
123
|
+
if (reconnectTimer) {
|
|
124
|
+
clearTimeout(reconnectTimer);
|
|
125
|
+
reconnectTimer = null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
nuxtApp.provide("echo", window.Echo);
|
|
131
|
+
},
|
|
132
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import httpService from "./httpService";
|
|
2
|
+
import type { MgUser } from "../types";
|
|
3
|
+
|
|
4
|
+
export class User implements Partial<MgUser> {
|
|
5
|
+
id = null;
|
|
6
|
+
uuid = null;
|
|
7
|
+
name = null;
|
|
8
|
+
nickname = null;
|
|
9
|
+
avatar = null;
|
|
10
|
+
avatar_url = null;
|
|
11
|
+
inviteQrCode = null;
|
|
12
|
+
followHash = null;
|
|
13
|
+
follow_hash = null;
|
|
14
|
+
followers = null;
|
|
15
|
+
following = null;
|
|
16
|
+
followers_count = null;
|
|
17
|
+
following_count = null;
|
|
18
|
+
user_is_following = false;
|
|
19
|
+
coins = null;
|
|
20
|
+
bio = { short: "", long: "" };
|
|
21
|
+
short_bio = "";
|
|
22
|
+
long_bio = "";
|
|
23
|
+
country = {
|
|
24
|
+
id: null,
|
|
25
|
+
name: null,
|
|
26
|
+
localized_name: null,
|
|
27
|
+
originalName: null,
|
|
28
|
+
language_id: null,
|
|
29
|
+
languageId: null,
|
|
30
|
+
isocode: null,
|
|
31
|
+
code2: null,
|
|
32
|
+
code3: null,
|
|
33
|
+
flag: null,
|
|
34
|
+
flag_url: null,
|
|
35
|
+
};
|
|
36
|
+
invite_qr_code = null;
|
|
37
|
+
|
|
38
|
+
constructor(data: object) {
|
|
39
|
+
Object.assign(this, data);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const logout = () =>
|
|
45
|
+
httpService({
|
|
46
|
+
url: "logout",
|
|
47
|
+
method: "POST",
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const instance = new (class AuthService {
|
|
51
|
+
private user: User | null = null;
|
|
52
|
+
|
|
53
|
+
authenticate(options: { fresh?: boolean } = {}): Promise<User | null> {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const params: Record<string, any> = {};
|
|
56
|
+
// Tells the API to bust its cache before computing subscription
|
|
57
|
+
// details — used right after a payment confirmation so the new
|
|
58
|
+
// is_subscriber state propagates without a stale TTL.
|
|
59
|
+
if (options.fresh) params.fresh = 1;
|
|
60
|
+
const xhr = httpService.get("/auth/user", { params });
|
|
61
|
+
xhr.then((response: any) => {
|
|
62
|
+
if (response.status !== 200 || !response.data || response.data === "") {
|
|
63
|
+
resolve(null);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const user = new User(response.data);
|
|
67
|
+
Object.freeze(user);
|
|
68
|
+
this.user = user;
|
|
69
|
+
resolve(user);
|
|
70
|
+
}).catch((error: any) => {
|
|
71
|
+
const status = error?.response?.status;
|
|
72
|
+
if (status === 401 || status === 403 || status === 419) {
|
|
73
|
+
resolve(null);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
reject(error);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async getUser(options: { fresh?: boolean } = {}) {
|
|
82
|
+
const user = await this.authenticate(options);
|
|
83
|
+
if (user) return user;
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async logout() {
|
|
88
|
+
return httpService({
|
|
89
|
+
url: "logout",
|
|
90
|
+
method: "POST",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
94
|
+
|
|
95
|
+
export default instance;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import httpService from "./httpService";
|
|
2
|
+
import { serialize } from "../utils/serialize";
|
|
3
|
+
|
|
4
|
+
function getEndpoints() {
|
|
5
|
+
const config = useRuntimeConfig();
|
|
6
|
+
return (
|
|
7
|
+
config.public.mgSharedUi?.chatEndpoints ?? {
|
|
8
|
+
list: "/api/v1/chats",
|
|
9
|
+
send: "/api/v1/chats/messages/",
|
|
10
|
+
show: "/api/v1/chats/{chatId}",
|
|
11
|
+
unread: "api/v1/chats/messages/unread/count",
|
|
12
|
+
delete: "/api/v1/chats/{chatId}",
|
|
13
|
+
deleteMessage: "/api/v1/chats/messages/{messageId}",
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const getChatList = async (params: any) => {
|
|
19
|
+
const endpoints = getEndpoints();
|
|
20
|
+
const paramsSerialized: string = serialize(params);
|
|
21
|
+
return httpService.get(`${endpoints.list}${paramsSerialized}`);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const postChatMessage = async (params: any) => {
|
|
25
|
+
const endpoints = getEndpoints();
|
|
26
|
+
return httpService.post(endpoints.send, params);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const getChat = async (params: { chat_id: string | number }) => {
|
|
30
|
+
const endpoints = getEndpoints();
|
|
31
|
+
const url = endpoints.show.replace("{chatId}", String(params.chat_id));
|
|
32
|
+
return httpService.get(url);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const getUnreadMessagesCount = async () => {
|
|
36
|
+
const config = useRuntimeConfig();
|
|
37
|
+
const endpoints = getEndpoints();
|
|
38
|
+
const systemId = config.public.mgSharedUi?.systemId || import.meta.env.VITE_SYSTEM_ID;
|
|
39
|
+
const param = { mg_network_system_id: systemId };
|
|
40
|
+
return httpService.get(`${endpoints.unread}${serialize(param)}`);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const deleteUserChat = async (chatId: string | number) => {
|
|
44
|
+
const endpoints = getEndpoints();
|
|
45
|
+
const url = endpoints.delete.replace("{chatId}", String(chatId));
|
|
46
|
+
return httpService.delete(url);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const deleteChatMessage = async (chatMessageId: string | number) => {
|
|
50
|
+
const endpoints = getEndpoints();
|
|
51
|
+
const url = endpoints.deleteMessage.replace("{messageId}", String(chatMessageId));
|
|
52
|
+
return httpService.delete(url);
|
|
53
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import httpService from "./httpService";
|
|
2
|
+
import { serialize } from "../utils/serialize";
|
|
3
|
+
|
|
4
|
+
interface SerializeObject {
|
|
5
|
+
[key: string]: string | { [key: string]: string | string[] };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const getApiBaseUrl = () => {
|
|
9
|
+
const config = useRuntimeConfig();
|
|
10
|
+
return config.public.mgSharedUi?.apiBaseURL || import.meta.env.VITE_API_BASE_URL;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const fetchContactCountry = async (params: SerializeObject): Promise<any> => {
|
|
14
|
+
const paramsSerialized = serialize(params);
|
|
15
|
+
return httpService.get(`/countries${paramsSerialized}`, { baseURL: getApiBaseUrl() });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const fetchSubject = async (params: SerializeObject): Promise<any> => {
|
|
19
|
+
const paramsSerialized = serialize(params);
|
|
20
|
+
return httpService.get(`/contact-subjects${paramsSerialized}`, { baseURL: getApiBaseUrl() });
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const createMessage = async (data: {
|
|
24
|
+
name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
subject_id: number;
|
|
27
|
+
language_slug: string;
|
|
28
|
+
country_id: number;
|
|
29
|
+
message: string;
|
|
30
|
+
privacy_policy: number;
|
|
31
|
+
origin_network_id: number;
|
|
32
|
+
status?: number;
|
|
33
|
+
}): Promise<any> => {
|
|
34
|
+
return httpService.post(`/contact`, data, { baseURL: getApiBaseUrl() });
|
|
35
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import httpService from "./httpService";
|
|
2
|
+
import { serialize } from "../utils/serialize";
|
|
3
|
+
|
|
4
|
+
interface SerializeObject {
|
|
5
|
+
[key: string]: string | { [key: string]: string | string[] };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const getApiBaseUrl = () => {
|
|
9
|
+
const config = useRuntimeConfig();
|
|
10
|
+
return config.public.mgSharedUi?.apiBaseURL || import.meta.env.VITE_API_BASE_URL;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const fetchDocuments = async (params: SerializeObject): Promise<any> => {
|
|
14
|
+
const paramsSerialized = serialize(params);
|
|
15
|
+
return httpService.get(`/document-website-latest${paramsSerialized}`, { baseURL: getApiBaseUrl() });
|
|
16
|
+
};
|