@mundogamernetwork/shared-ui 1.17.0 → 1.17.4
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, watch, onMounted } from "vue";
|
|
2
|
+
import { computed, ref, watch, onMounted } from "vue";
|
|
3
3
|
import type { AxiosInstance } from "axios";
|
|
4
4
|
import { useMgBillingProfile } from "../../composables/useMgBillingProfile";
|
|
5
5
|
|
|
@@ -15,11 +15,14 @@ const props = defineProps<{
|
|
|
15
15
|
httpService: AxiosInstance;
|
|
16
16
|
/** Start expanded regardless of whether a profile already exists. */
|
|
17
17
|
defaultOpen?: boolean;
|
|
18
|
+
/** Override the endpoint when the instance's baseURL is an unusual shape. */
|
|
19
|
+
path?: string;
|
|
18
20
|
}>();
|
|
19
21
|
|
|
20
22
|
const emit = defineEmits<{ (e: "change", wanted: boolean): void }>();
|
|
21
23
|
|
|
22
|
-
const
|
|
24
|
+
const nuxtApp = typeof useNuxtApp === "function" ? useNuxtApp() : null;
|
|
25
|
+
const billing = useMgBillingProfile(props.httpService, { path: props.path });
|
|
23
26
|
const wanted = ref(props.defaultOpen ?? false);
|
|
24
27
|
|
|
25
28
|
// A customer who already gave us their details should see them, ticked — not
|
|
@@ -47,6 +50,16 @@ async function save(): Promise<boolean> {
|
|
|
47
50
|
return billing.save();
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
const saveFailed = computed(() => billing.error.value !== null);
|
|
54
|
+
|
|
55
|
+
const saveErrorMessage = computed(() => {
|
|
56
|
+
if (billing.error.value) return billing.error.value;
|
|
57
|
+
const translated = (nuxtApp?.$i18n as any)?.t?.("billing_profile.save_error");
|
|
58
|
+
return translated && translated !== "billing_profile.save_error"
|
|
59
|
+
? translated
|
|
60
|
+
: "Could not save your billing details. Please try again.";
|
|
61
|
+
});
|
|
62
|
+
|
|
50
63
|
defineExpose({ save, wanted, profile: billing.profile, hasData: billing.hasData });
|
|
51
64
|
</script>
|
|
52
65
|
|
|
@@ -103,18 +116,28 @@ defineExpose({ save, wanted, profile: billing.profile, hasData: billing.hasData
|
|
|
103
116
|
</label>
|
|
104
117
|
</div>
|
|
105
118
|
|
|
106
|
-
<p v-if="
|
|
107
|
-
{{
|
|
119
|
+
<p v-if="saveFailed" class="mg-billing-profile__error">
|
|
120
|
+
{{ saveErrorMessage }}
|
|
108
121
|
</p>
|
|
109
122
|
</div>
|
|
110
123
|
</div>
|
|
111
124
|
</template>
|
|
112
125
|
|
|
113
126
|
<style lang="scss" scoped>
|
|
127
|
+
/*
|
|
128
|
+
* Theme-agnostic on purpose. This block renders inside eight different
|
|
129
|
+
* checkouts, and they are not all light: agency's is near-black, and hardcoded
|
|
130
|
+
* light fallbacks turned the labels dark-on-dark and the inputs into glaring
|
|
131
|
+
* white boxes. Everything here inherits the host's own text colour and derives
|
|
132
|
+
* its lines from it, so the block reads correctly on any background without
|
|
133
|
+
* each app having to restyle it.
|
|
134
|
+
*/
|
|
114
135
|
.mg-billing-profile {
|
|
115
136
|
margin-top: 16px;
|
|
116
|
-
border-top: 1px solid
|
|
137
|
+
border-top: 1px solid currentColor;
|
|
138
|
+
border-top-color: color-mix(in srgb, currentColor 18%, transparent);
|
|
117
139
|
padding-top: 16px;
|
|
140
|
+
color: inherit;
|
|
118
141
|
}
|
|
119
142
|
|
|
120
143
|
.mg-billing-profile__toggle {
|
|
@@ -123,6 +146,7 @@ defineExpose({ save, wanted, profile: billing.profile, hasData: billing.hasData
|
|
|
123
146
|
gap: 8px;
|
|
124
147
|
font-size: 14px;
|
|
125
148
|
cursor: pointer;
|
|
149
|
+
color: inherit;
|
|
126
150
|
}
|
|
127
151
|
|
|
128
152
|
.mg-billing-profile__body {
|
|
@@ -131,8 +155,8 @@ defineExpose({ save, wanted, profile: billing.profile, hasData: billing.hasData
|
|
|
131
155
|
|
|
132
156
|
.mg-billing-profile__hint {
|
|
133
157
|
font-size: 13px;
|
|
134
|
-
color: var(--inactive-text, #666);
|
|
135
158
|
margin: 0 0 12px;
|
|
159
|
+
opacity: 0.7;
|
|
136
160
|
}
|
|
137
161
|
|
|
138
162
|
.mg-billing-profile__grid {
|
|
@@ -148,16 +172,28 @@ defineExpose({ save, wanted, profile: billing.profile, hasData: billing.hasData
|
|
|
148
172
|
font-size: 12px;
|
|
149
173
|
}
|
|
150
174
|
|
|
175
|
+
.mg-billing-profile__field > span {
|
|
176
|
+
opacity: 0.7;
|
|
177
|
+
}
|
|
178
|
+
|
|
151
179
|
.mg-billing-profile__field--wide {
|
|
152
180
|
grid-column: 1 / -1;
|
|
153
181
|
}
|
|
154
182
|
|
|
155
183
|
.mg-billing-profile__field input {
|
|
156
|
-
border: 1px solid
|
|
184
|
+
border: 1px solid currentColor;
|
|
185
|
+
border-color: color-mix(in srgb, currentColor 30%, transparent);
|
|
157
186
|
padding: 8px 10px;
|
|
158
187
|
font-size: 14px;
|
|
159
|
-
|
|
160
|
-
|
|
188
|
+
/* Transparent, not white: the host's own background shows through, so the
|
|
189
|
+
field belongs to the surrounding form instead of punching a hole in it. */
|
|
190
|
+
background: transparent;
|
|
191
|
+
color: inherit;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.mg-billing-profile__field input:focus {
|
|
195
|
+
outline: none;
|
|
196
|
+
border-color: color-mix(in srgb, currentColor 60%, transparent);
|
|
161
197
|
}
|
|
162
198
|
|
|
163
199
|
.mg-billing-profile__error {
|
|
@@ -12,7 +12,25 @@ import type { AxiosInstance } from "axios";
|
|
|
12
12
|
* the payment record is created on the way back from the gateway, so anything
|
|
13
13
|
* asked for afterwards misses at least the first document.
|
|
14
14
|
*/
|
|
15
|
-
const
|
|
15
|
+
const BILLING_PROFILE_PATH = "public/user/billing-profile";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the endpoint for whichever axios instance the app hands us.
|
|
19
|
+
*
|
|
20
|
+
* Instances across the platform disagree about their baseURL: useMgCheckout's
|
|
21
|
+
* is origin-only (so it writes "api/v1/shopping-cart"), while most apps'
|
|
22
|
+
* api-main instance already ends in "/api/v1". Hardcoding either shape would
|
|
23
|
+
* force a wrapper service in every app that happens to use the other one.
|
|
24
|
+
*/
|
|
25
|
+
function resolveBillingProfileUrl(httpService: AxiosInstance, override?: string): string {
|
|
26
|
+
if (override) return override;
|
|
27
|
+
|
|
28
|
+
const baseUrl = String(httpService?.defaults?.baseURL ?? "");
|
|
29
|
+
|
|
30
|
+
return /\/api\/v1\/?$/.test(baseUrl)
|
|
31
|
+
? BILLING_PROFILE_PATH
|
|
32
|
+
: `api/v1/${BILLING_PROFILE_PATH}`;
|
|
33
|
+
}
|
|
16
34
|
|
|
17
35
|
export interface MgBillingProfile {
|
|
18
36
|
name: string;
|
|
@@ -48,7 +66,9 @@ export function emptyMgBillingProfile(): MgBillingProfile {
|
|
|
48
66
|
};
|
|
49
67
|
}
|
|
50
68
|
|
|
51
|
-
export function useMgBillingProfile(httpService: AxiosInstance) {
|
|
69
|
+
export function useMgBillingProfile(httpService: AxiosInstance, options?: { path?: string }) {
|
|
70
|
+
const url = resolveBillingProfileUrl(httpService, options?.path);
|
|
71
|
+
|
|
52
72
|
const profile = ref<MgBillingProfile>(emptyMgBillingProfile());
|
|
53
73
|
const loading = ref(false);
|
|
54
74
|
const saving = ref(false);
|
|
@@ -62,7 +82,7 @@ export function useMgBillingProfile(httpService: AxiosInstance) {
|
|
|
62
82
|
async function load() {
|
|
63
83
|
loading.value = true;
|
|
64
84
|
try {
|
|
65
|
-
const res = await httpService.get(
|
|
85
|
+
const res = await httpService.get(url);
|
|
66
86
|
const data = res?.data?.data ?? {};
|
|
67
87
|
(Object.keys(profile.value) as Array<keyof MgBillingProfile>).forEach((key) => {
|
|
68
88
|
profile.value[key] = data[key] ?? "";
|
|
@@ -85,7 +105,7 @@ export function useMgBillingProfile(httpService: AxiosInstance) {
|
|
|
85
105
|
saving.value = true;
|
|
86
106
|
error.value = null;
|
|
87
107
|
try {
|
|
88
|
-
await httpService.put(
|
|
108
|
+
await httpService.put(url, profile.value);
|
|
89
109
|
return true;
|
|
90
110
|
} catch (err: any) {
|
|
91
111
|
error.value = err?.response?.data?.message ?? null;
|
package/package.json
CHANGED
|
@@ -473,7 +473,7 @@ export const fetchCampaignTypes = (params: Record<string, any> = {}) => {
|
|
|
473
473
|
* Fetch active platforms (for the platform filter select).
|
|
474
474
|
*/
|
|
475
475
|
export const fetchCampaignPlatforms = () => {
|
|
476
|
-
return authClient.get("/
|
|
476
|
+
return authClient.get("/platforms/currently")
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
/**
|