@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/stores/login.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineStore } from "pinia";
|
|
2
|
+
|
|
3
|
+
export const useLoginStore = defineStore({
|
|
4
|
+
id: "login-store",
|
|
5
|
+
state: () => {
|
|
6
|
+
return {
|
|
7
|
+
showLoginModalComponent: false,
|
|
8
|
+
login: "",
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
actions: {
|
|
12
|
+
toggleLoginModalComponent() {
|
|
13
|
+
this.showLoginModalComponent = !this.showLoginModalComponent;
|
|
14
|
+
},
|
|
15
|
+
toggleObject(val: any) {
|
|
16
|
+
this.showLoginModalComponent = !this.showLoginModalComponent;
|
|
17
|
+
this.login = val.login;
|
|
18
|
+
},
|
|
19
|
+
toggleLogin(val: string) {
|
|
20
|
+
this.login = val;
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (import.meta.hot) {
|
|
26
|
+
import.meta.hot.accept(acceptHMRUpdate(useLoginStore, import.meta.hot));
|
|
27
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { defineStore } from "pinia";
|
|
2
|
+
import { ref } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
getAllNotifications,
|
|
5
|
+
markNotificationAsRead,
|
|
6
|
+
markAllNotificationsAsRead,
|
|
7
|
+
deleteNotification,
|
|
8
|
+
} from "../services/notificationsService";
|
|
9
|
+
import type { MgNotification } from "../types";
|
|
10
|
+
|
|
11
|
+
export const useNotificationsStore = defineStore("notifications-store", () => {
|
|
12
|
+
const notifications = ref<MgNotification[]>([]);
|
|
13
|
+
const notificationCount = ref(0);
|
|
14
|
+
const totalNotifications = ref(0);
|
|
15
|
+
const currentPage = ref(1);
|
|
16
|
+
const loading = ref(false);
|
|
17
|
+
const error = ref<string | null>(null);
|
|
18
|
+
|
|
19
|
+
const fetchNotifications = async (page: number = 1) => {
|
|
20
|
+
loading.value = true;
|
|
21
|
+
try {
|
|
22
|
+
if (page === 1) {
|
|
23
|
+
notifications.value = [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const config = useRuntimeConfig();
|
|
27
|
+
const systemId = config.public.mgSharedUi?.systemId || import.meta.env.VITE_SYSTEM_ID;
|
|
28
|
+
|
|
29
|
+
const response = await getAllNotifications({
|
|
30
|
+
"filter[mg_network_system_id]": systemId,
|
|
31
|
+
sort: "created_at",
|
|
32
|
+
order: "desc",
|
|
33
|
+
per_page: 6,
|
|
34
|
+
page,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
totalNotifications.value = response.data.meta.pagination.total;
|
|
38
|
+
currentPage.value = response.data.meta.pagination.current_page;
|
|
39
|
+
|
|
40
|
+
notifications.value.push(
|
|
41
|
+
...response.data.data.map((notification: any) => ({
|
|
42
|
+
type: notification.mg_network_system_id,
|
|
43
|
+
object: notification.data.object || null,
|
|
44
|
+
id: notification.id || null,
|
|
45
|
+
slug: notification.data.slug || null,
|
|
46
|
+
url: notification.data.url || null,
|
|
47
|
+
title: notification.data.title,
|
|
48
|
+
message: notification.data.message,
|
|
49
|
+
image: notification.data.image,
|
|
50
|
+
read_at: notification.read_at,
|
|
51
|
+
created_at: notification.created_at_diff,
|
|
52
|
+
})),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
await fetchUnreadCount();
|
|
56
|
+
} catch {
|
|
57
|
+
error.value = "Failed to fetch notifications";
|
|
58
|
+
} finally {
|
|
59
|
+
loading.value = false;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const fetchUnreadCount = async () => {
|
|
64
|
+
const config = useRuntimeConfig();
|
|
65
|
+
const systemId = config.public.mgSharedUi?.systemId || import.meta.env.VITE_SYSTEM_ID;
|
|
66
|
+
|
|
67
|
+
const response = await getAllNotifications({
|
|
68
|
+
"filter[mg_network_system_id]": systemId,
|
|
69
|
+
"filter[read]": 0,
|
|
70
|
+
total: 1,
|
|
71
|
+
});
|
|
72
|
+
notificationCount.value = response.data.total;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const markAsRead = async (notificationId: string) => {
|
|
76
|
+
try {
|
|
77
|
+
await markNotificationAsRead(notificationId);
|
|
78
|
+
notifications.value = notifications.value.map((n) =>
|
|
79
|
+
n.id === notificationId ? { ...n, read_at: new Date().toISOString() } : n,
|
|
80
|
+
);
|
|
81
|
+
await fetchUnreadCount();
|
|
82
|
+
} catch {
|
|
83
|
+
error.value = "Failed to mark notification as read";
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const markAllAsRead = async () => {
|
|
88
|
+
try {
|
|
89
|
+
await markAllNotificationsAsRead();
|
|
90
|
+
notificationCount.value = 0;
|
|
91
|
+
notifications.value = notifications.value.map((n) => ({
|
|
92
|
+
...n,
|
|
93
|
+
read_at: new Date().toISOString(),
|
|
94
|
+
}));
|
|
95
|
+
} catch {
|
|
96
|
+
error.value = "Failed to mark all notifications as read";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const removeNotification = async (notificationId: string) => {
|
|
101
|
+
try {
|
|
102
|
+
await deleteNotification(notificationId);
|
|
103
|
+
notifications.value = notifications.value.filter((n) => n.id !== notificationId);
|
|
104
|
+
await fetchUnreadCount();
|
|
105
|
+
} catch {
|
|
106
|
+
error.value = "Failed to delete notification";
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const addNotification = (notification: MgNotification) => {
|
|
111
|
+
notifications.value.unshift(notification);
|
|
112
|
+
notificationCount.value++;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
notifications,
|
|
117
|
+
notificationCount,
|
|
118
|
+
totalNotifications,
|
|
119
|
+
currentPage,
|
|
120
|
+
loading,
|
|
121
|
+
error,
|
|
122
|
+
fetchNotifications,
|
|
123
|
+
fetchUnreadCount,
|
|
124
|
+
markAsRead,
|
|
125
|
+
markAllAsRead,
|
|
126
|
+
removeNotification,
|
|
127
|
+
addNotification,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (import.meta.hot) {
|
|
132
|
+
import.meta.hot.accept(acceptHMRUpdate(useNotificationsStore, import.meta.hot));
|
|
133
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { defineStore } from "pinia";
|
|
2
|
+
|
|
3
|
+
export interface PromotionBanner {
|
|
4
|
+
id: number;
|
|
5
|
+
title: string;
|
|
6
|
+
message: string;
|
|
7
|
+
link_url: string | null;
|
|
8
|
+
link_text: string | null;
|
|
9
|
+
image_url: string | null;
|
|
10
|
+
type: "info" | "warning" | "success" | "danger" | "promo";
|
|
11
|
+
bg_color: string | null;
|
|
12
|
+
text_color: string | null;
|
|
13
|
+
priority: number;
|
|
14
|
+
platform_ids: number[];
|
|
15
|
+
language_id: number | null;
|
|
16
|
+
country_id: number | null;
|
|
17
|
+
is_global: boolean;
|
|
18
|
+
is_active: boolean;
|
|
19
|
+
impressions: number;
|
|
20
|
+
clicks: number;
|
|
21
|
+
max_impressions: number | null;
|
|
22
|
+
starts_at: string | null;
|
|
23
|
+
ends_at: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DISMISSED_PREFIX = "mg_promotion_dismissed_";
|
|
27
|
+
const CACHE_KEY = "mg_promotion_banner_cache";
|
|
28
|
+
const CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes
|
|
29
|
+
|
|
30
|
+
interface CacheEntry {
|
|
31
|
+
banner: PromotionBanner | null;
|
|
32
|
+
cachedAt: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readCache(platformId: number, locale: string): PromotionBanner | null | undefined {
|
|
36
|
+
try {
|
|
37
|
+
const raw = localStorage.getItem(`${CACHE_KEY}_${platformId}_${locale}`);
|
|
38
|
+
if (!raw) return undefined;
|
|
39
|
+
const entry: CacheEntry = JSON.parse(raw);
|
|
40
|
+
if (Date.now() - entry.cachedAt > CACHE_TTL_MS) return undefined;
|
|
41
|
+
return entry.banner; // null = cached "no active banner"
|
|
42
|
+
} catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function writeCache(platformId: number, locale: string, banner: PromotionBanner | null) {
|
|
48
|
+
try {
|
|
49
|
+
const entry: CacheEntry = { banner, cachedAt: Date.now() };
|
|
50
|
+
localStorage.setItem(`${CACHE_KEY}_${platformId}_${locale}`, JSON.stringify(entry));
|
|
51
|
+
} catch {
|
|
52
|
+
// localStorage unavailable or full — silently skip
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const usePromotionStore = defineStore("promotion-store", {
|
|
57
|
+
state: () => ({
|
|
58
|
+
banner: null as PromotionBanner | null,
|
|
59
|
+
dismissed: false,
|
|
60
|
+
loaded: false,
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
actions: {
|
|
64
|
+
async fetchBanner() {
|
|
65
|
+
if (this.loaded) return;
|
|
66
|
+
|
|
67
|
+
const runtimeConfig = useRuntimeConfig();
|
|
68
|
+
const networkBaseUrl =
|
|
69
|
+
runtimeConfig.public.mgSharedUi?.networkBaseUrl ||
|
|
70
|
+
import.meta.env.VITE_BASE_URL_NETWORK;
|
|
71
|
+
const platformId = Number(
|
|
72
|
+
runtimeConfig.public.mgSharedUi?.systemId || import.meta.env.VITE_SYSTEM_ID,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (!networkBaseUrl || !platformId) {
|
|
76
|
+
this.loaded = true;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { locale } = useI18n();
|
|
81
|
+
const localeVal = locale.value || "en";
|
|
82
|
+
|
|
83
|
+
// ── Try cache first ────────────────────────────────────────────────
|
|
84
|
+
// Impressions are NOT fired on cache hits — the user already
|
|
85
|
+
// received an impression when the banner was first fetched.
|
|
86
|
+
const cached = readCache(platformId, localeVal);
|
|
87
|
+
if (cached !== undefined) {
|
|
88
|
+
this.banner = cached;
|
|
89
|
+
if (cached) {
|
|
90
|
+
this.dismissed = !!localStorage.getItem(`${DISMISSED_PREFIX}${cached.id}`);
|
|
91
|
+
}
|
|
92
|
+
this.loaded = true;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── Cache miss — fetch from API ────────────────────────────────────
|
|
97
|
+
try {
|
|
98
|
+
const params = new URLSearchParams({ platform_id: String(platformId) });
|
|
99
|
+
params.set("locale", localeVal);
|
|
100
|
+
|
|
101
|
+
const url = `${networkBaseUrl}/promotion-banners/active?${params.toString()}`;
|
|
102
|
+
const data: any = await $fetch(url, { credentials: "include" });
|
|
103
|
+
|
|
104
|
+
const banner: PromotionBanner | null = data?.data ?? null;
|
|
105
|
+
this.banner = banner;
|
|
106
|
+
|
|
107
|
+
if (banner) {
|
|
108
|
+
this.dismissed = !!localStorage.getItem(`${DISMISSED_PREFIX}${banner.id}`);
|
|
109
|
+
|
|
110
|
+
// Fire impression on real fetch only — non-blocking, best-effort
|
|
111
|
+
$fetch(`${networkBaseUrl}/promotion-banners/${banner.id}/impression`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
credentials: "include",
|
|
114
|
+
}).catch(() => {});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
writeCache(platformId, localeVal, banner);
|
|
118
|
+
} catch {
|
|
119
|
+
// Silently fail — promotion banner is non-critical; do not cache on error
|
|
120
|
+
} finally {
|
|
121
|
+
this.loaded = true;
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
async recordClick() {
|
|
126
|
+
if (!this.banner) return;
|
|
127
|
+
|
|
128
|
+
const runtimeConfig = useRuntimeConfig();
|
|
129
|
+
const networkBaseUrl =
|
|
130
|
+
runtimeConfig.public.mgSharedUi?.networkBaseUrl ||
|
|
131
|
+
import.meta.env.VITE_BASE_URL_NETWORK;
|
|
132
|
+
|
|
133
|
+
$fetch(`${networkBaseUrl}/promotion-banners/${this.banner.id}/click`, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
credentials: "include",
|
|
136
|
+
}).catch(() => {});
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
dismiss() {
|
|
140
|
+
if (this.banner) {
|
|
141
|
+
localStorage.setItem(`${DISMISSED_PREFIX}${this.banner.id}`, "1");
|
|
142
|
+
}
|
|
143
|
+
this.dismissed = true;
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
getters: {
|
|
148
|
+
isVisible: (state) => !!state.banner && !state.dismissed,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (import.meta.hot) {
|
|
153
|
+
import.meta.hot.accept(acceptHMRUpdate(usePromotionStore, import.meta.hot));
|
|
154
|
+
}
|
package/types/index.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
export interface MgUser {
|
|
2
|
+
id: number | null;
|
|
3
|
+
uuid: string | null;
|
|
4
|
+
name: string | null;
|
|
5
|
+
nickname: string | null;
|
|
6
|
+
avatar: string | null;
|
|
7
|
+
avatar_url: string | null;
|
|
8
|
+
inviteQrCode: string | null;
|
|
9
|
+
followHash: string | null;
|
|
10
|
+
follow_hash: string | null;
|
|
11
|
+
followers: number | null;
|
|
12
|
+
following: number | null;
|
|
13
|
+
followers_count: number | null;
|
|
14
|
+
following_count: number | null;
|
|
15
|
+
user_is_following: boolean;
|
|
16
|
+
coins: number | null;
|
|
17
|
+
bio: {
|
|
18
|
+
short: string;
|
|
19
|
+
long: string;
|
|
20
|
+
};
|
|
21
|
+
short_bio: string;
|
|
22
|
+
long_bio: string;
|
|
23
|
+
country: MgCountry;
|
|
24
|
+
invite_qr_code: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface MgCountry {
|
|
28
|
+
id: number | null;
|
|
29
|
+
name: string | null;
|
|
30
|
+
localized_name: string | null;
|
|
31
|
+
originalName: string | null;
|
|
32
|
+
language_id: number | null;
|
|
33
|
+
languageId: number | null;
|
|
34
|
+
isocode: string | null;
|
|
35
|
+
code2: string | null;
|
|
36
|
+
code3: string | null;
|
|
37
|
+
flag: string | null;
|
|
38
|
+
flag_url: string | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface MgNotification {
|
|
42
|
+
id: string | null;
|
|
43
|
+
type: string | number;
|
|
44
|
+
object: string | null;
|
|
45
|
+
slug: string | null;
|
|
46
|
+
url: string | null;
|
|
47
|
+
title: string;
|
|
48
|
+
message: string;
|
|
49
|
+
image: string;
|
|
50
|
+
read_at: string | null;
|
|
51
|
+
created_at: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface MgChatMessage {
|
|
55
|
+
id: number;
|
|
56
|
+
chat_id: number;
|
|
57
|
+
user_id: number;
|
|
58
|
+
message: string;
|
|
59
|
+
created_at: string;
|
|
60
|
+
updated_at: string;
|
|
61
|
+
readed_at?: string;
|
|
62
|
+
user_is_author?: boolean;
|
|
63
|
+
user: MgChatUser;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface MgChatUser {
|
|
67
|
+
id: number;
|
|
68
|
+
uuid: string;
|
|
69
|
+
name: string;
|
|
70
|
+
email: string;
|
|
71
|
+
preferred_lang: string;
|
|
72
|
+
url_image: string;
|
|
73
|
+
nickname: string;
|
|
74
|
+
avatar_url: string;
|
|
75
|
+
first_name: string;
|
|
76
|
+
last_name: string;
|
|
77
|
+
full_name: string;
|
|
78
|
+
country: MgCountry;
|
|
79
|
+
user_status?: MgUserStatus[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface MgUserStatus {
|
|
83
|
+
hiddenstatus: boolean;
|
|
84
|
+
online: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface MgChat {
|
|
88
|
+
id: number;
|
|
89
|
+
mg_network_system_id: number;
|
|
90
|
+
chat_type_id: number;
|
|
91
|
+
created_at: string;
|
|
92
|
+
updated_at: string;
|
|
93
|
+
users_count: number;
|
|
94
|
+
chat_messages_count: number;
|
|
95
|
+
unread_messages_count: number;
|
|
96
|
+
chat_messages: MgChatMessage[];
|
|
97
|
+
users: MgChatUser[];
|
|
98
|
+
last_message?: {
|
|
99
|
+
created_at_diff: string;
|
|
100
|
+
user_is_author: boolean;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface MgLanguage {
|
|
105
|
+
name: string;
|
|
106
|
+
name_abrev: string;
|
|
107
|
+
flag_url: string;
|
|
108
|
+
native_name: string;
|
|
109
|
+
localized_name: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface MgSharedUiConfig {
|
|
113
|
+
platform: string;
|
|
114
|
+
systemId: string;
|
|
115
|
+
apiBaseURL: string;
|
|
116
|
+
accountsBaseUrl: string;
|
|
117
|
+
features: {
|
|
118
|
+
chat: boolean;
|
|
119
|
+
notifications: boolean;
|
|
120
|
+
wallet: boolean;
|
|
121
|
+
darkMode: boolean;
|
|
122
|
+
search: boolean;
|
|
123
|
+
statusOnline: boolean;
|
|
124
|
+
};
|
|
125
|
+
languages: string[];
|
|
126
|
+
protectedRoutes: string[];
|
|
127
|
+
chatEndpoints: {
|
|
128
|
+
list: string;
|
|
129
|
+
send: string;
|
|
130
|
+
show: string;
|
|
131
|
+
unread: string;
|
|
132
|
+
delete: string;
|
|
133
|
+
deleteMessage: string;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface NestedObject {
|
|
2
|
+
[key: string]: string | string[];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface SerializeObject {
|
|
6
|
+
[key: string]: string | number | boolean | NestedObject;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function serialize(obj: SerializeObject): string {
|
|
10
|
+
const searchParams = new URLSearchParams();
|
|
11
|
+
for (const key in obj) {
|
|
12
|
+
if (typeof obj[key] === "object" && obj[key] !== null) {
|
|
13
|
+
const nestedObj = obj[key] as NestedObject;
|
|
14
|
+
for (const iKey in nestedObj) {
|
|
15
|
+
const value = nestedObj[iKey];
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
value.forEach((arrValue, index) => {
|
|
18
|
+
if (arrValue !== "") searchParams.append(`filter[${iKey}][${index}]`, arrValue);
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
if (value !== "") searchParams.append(`filter[${iKey}]`, value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} else if (obj[key] !== undefined && obj[key] !== null) {
|
|
25
|
+
searchParams.append(`${key}`, String(obj[key]));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return `?${decodeURIComponent(searchParams.toString())}`;
|
|
29
|
+
}
|