@goweekdays/layer-common 0.0.3 → 0.0.6
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/CHANGELOG.md +18 -0
- package/components/Layout/Header.vue +4 -2
- package/components/SwitchOrg.vue +1 -1
- package/composables/usePaymentMethod.ts +11 -2
- package/composables/useSubscription.ts +22 -4
- package/composables/useUtils.ts +34 -0
- package/error.vue +41 -0
- package/layouts/plain.vue +7 -0
- package/middleware/auth.ts +25 -0
- package/middleware/org.ts +16 -0
- package/package.json +3 -2
- package/pages/require-organization-membership.vue +47 -0
- package/pages/unauthorized.vue +29 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @goweekdays/layer-common
|
|
2
2
|
|
|
3
|
+
## 0.0.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 01873f7: Add error page
|
|
8
|
+
|
|
9
|
+
## 0.0.5
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 0a6bba5: Enhance usePaymentMethod
|
|
14
|
+
|
|
15
|
+
## 0.0.4
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- e23db37: Update org landing page link
|
|
20
|
+
|
|
3
21
|
## 0.0.3
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -112,7 +112,9 @@
|
|
|
112
112
|
height="42"
|
|
113
113
|
></v-img>
|
|
114
114
|
|
|
115
|
-
<span v-else class="text-
|
|
115
|
+
<span v-else class="text-subtitle-1">{{
|
|
116
|
+
getNameInitials(name)
|
|
117
|
+
}}</span>
|
|
116
118
|
</v-avatar>
|
|
117
119
|
</v-btn>
|
|
118
120
|
</template>
|
|
@@ -229,7 +231,7 @@ const defaultApps = [
|
|
|
229
231
|
title: "Organization",
|
|
230
232
|
icon: "mdi-domain",
|
|
231
233
|
link: APP_ORG,
|
|
232
|
-
landingPage:
|
|
234
|
+
landingPage: `org/${currentUser.value?.defaultOrg}`,
|
|
233
235
|
},
|
|
234
236
|
{
|
|
235
237
|
title: "Admin",
|
package/components/SwitchOrg.vue
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
>
|
|
13
13
|
<template #activator="{ props }">
|
|
14
14
|
<v-btn variant="text" class="text-none ml-2" v-bind="props">
|
|
15
|
-
<div class="d-block text-truncate" style="
|
|
15
|
+
<div class="d-block text-truncate" style="width: 130px">
|
|
16
16
|
{{ selectedOrg?.text || "Select organization" }}
|
|
17
17
|
</div>
|
|
18
18
|
<v-icon class="ml-1">mdi-menu-down</v-icon>
|
|
@@ -7,7 +7,7 @@ export default function usePaymentMethod() {
|
|
|
7
7
|
success_return_url = "",
|
|
8
8
|
failure_return_url = "",
|
|
9
9
|
cancel_return_url = "",
|
|
10
|
-
|
|
10
|
+
category = "individual",
|
|
11
11
|
} = {}) {
|
|
12
12
|
return useNuxtApp().$api<Record<string, any>>(
|
|
13
13
|
"/api/payment-methods/e-wallet",
|
|
@@ -21,7 +21,7 @@ export default function usePaymentMethod() {
|
|
|
21
21
|
success_return_url,
|
|
22
22
|
failure_return_url,
|
|
23
23
|
cancel_return_url,
|
|
24
|
-
|
|
24
|
+
category,
|
|
25
25
|
},
|
|
26
26
|
}
|
|
27
27
|
);
|
|
@@ -81,6 +81,14 @@ export default function usePaymentMethod() {
|
|
|
81
81
|
const cardholderName = useState("cardholderName", () => "");
|
|
82
82
|
const selectedPaymentMethod = useState("selectedPaymentMethod", () => "");
|
|
83
83
|
|
|
84
|
+
function reset() {
|
|
85
|
+
eWalletNumber.value = "";
|
|
86
|
+
cardNumber.value = "";
|
|
87
|
+
cardExpiration.value = "";
|
|
88
|
+
cardSecurityCode.value = "";
|
|
89
|
+
cardholderName.value = "";
|
|
90
|
+
}
|
|
91
|
+
|
|
84
92
|
return {
|
|
85
93
|
linkEWallet,
|
|
86
94
|
linkCard,
|
|
@@ -92,5 +100,6 @@ export default function usePaymentMethod() {
|
|
|
92
100
|
cardSecurityCode,
|
|
93
101
|
cardholderName,
|
|
94
102
|
selectedPaymentMethod,
|
|
103
|
+
reset,
|
|
95
104
|
};
|
|
96
105
|
}
|
|
@@ -13,6 +13,12 @@ export default function useSubscription() {
|
|
|
13
13
|
return useNuxtApp().$api<TSubscription>(`/api/subscriptions/id/${id}`);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function getByOrgId(id: string) {
|
|
17
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
18
|
+
`/api/subscriptions/org/${id}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
function getSubscriptions() {
|
|
17
23
|
return useNuxtApp().$api("/api/subscriptions");
|
|
18
24
|
}
|
|
@@ -68,21 +74,33 @@ export default function useSubscription() {
|
|
|
68
74
|
customer_id: string;
|
|
69
75
|
amount: number;
|
|
70
76
|
payment_method_id: string;
|
|
77
|
+
payment_method_type: string;
|
|
78
|
+
payment_method_channel: string;
|
|
79
|
+
payment_method_number: string;
|
|
80
|
+
payment_method_expiry_month?: string;
|
|
81
|
+
payment_method_expiry_year?: string;
|
|
82
|
+
payment_method_cvv?: string;
|
|
83
|
+
payment_method_cardholder_name?: string;
|
|
71
84
|
currency?: string;
|
|
85
|
+
seats: number;
|
|
72
86
|
organization: TOrg;
|
|
73
87
|
billingAddress: TAddress;
|
|
74
88
|
};
|
|
75
89
|
|
|
76
90
|
function initOrgSubscription(value: TOrgSubscription) {
|
|
77
|
-
return useNuxtApp().$api
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
92
|
+
"/api/subscriptions/organization",
|
|
93
|
+
{
|
|
94
|
+
method: "POST",
|
|
95
|
+
body: value,
|
|
96
|
+
}
|
|
97
|
+
);
|
|
81
98
|
}
|
|
82
99
|
|
|
83
100
|
return {
|
|
84
101
|
add,
|
|
85
102
|
getById,
|
|
103
|
+
getByOrgId,
|
|
86
104
|
getSubscriptions,
|
|
87
105
|
affiliateSubscription,
|
|
88
106
|
checkSubscription,
|
package/composables/useUtils.ts
CHANGED
|
@@ -131,6 +131,39 @@ export default function useUtils() {
|
|
|
131
131
|
maximumFractionDigits: 2,
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
function formatNumber(
|
|
135
|
+
amount: number,
|
|
136
|
+
options: {
|
|
137
|
+
currency?: string;
|
|
138
|
+
locale?: string;
|
|
139
|
+
useSymbol?: boolean;
|
|
140
|
+
decimalPlaces?: number;
|
|
141
|
+
} = {}
|
|
142
|
+
): string {
|
|
143
|
+
const {
|
|
144
|
+
currency,
|
|
145
|
+
locale = "en-US",
|
|
146
|
+
useSymbol = false,
|
|
147
|
+
decimalPlaces = 2,
|
|
148
|
+
} = options;
|
|
149
|
+
|
|
150
|
+
return new Intl.NumberFormat(locale, {
|
|
151
|
+
style: useSymbol && currency ? "currency" : "decimal",
|
|
152
|
+
currency: currency || "USD", // Default currency (ignored if `useSymbol` is false)
|
|
153
|
+
minimumFractionDigits: decimalPlaces,
|
|
154
|
+
maximumFractionDigits: decimalPlaces,
|
|
155
|
+
}).format(amount);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 🔹 Examples:
|
|
159
|
+
// console.log(formatNumber(1234.56)); // "1,234.56" (comma separator, 2 decimals)
|
|
160
|
+
// console.log(formatNumber(1234.56, { decimalPlaces: 0 })); // "1,234" (no decimals)
|
|
161
|
+
// console.log(formatNumber(1234.56, { useSymbol: true, currency: "USD" })); // "$1,234.56"
|
|
162
|
+
// console.log(formatNumber(1234.56, { useSymbol: true, currency: "PHP", decimalPlaces: 0 })); // "₱1,234"
|
|
163
|
+
// console.log(formatNumber(1234.56, { useSymbol: false, decimalPlaces: 0 })); // "1,234"
|
|
164
|
+
// console.log(formatNumber(1234.56, { useSymbol: true, currency: "EUR", locale: "de-DE" })); // "1.234,56 €"
|
|
165
|
+
// console.log(formatNumber(1234.56, { useSymbol: true, currency: "EUR", locale: "de-DE", decimalPlaces: 0 })); // "1.234 €"
|
|
166
|
+
|
|
134
167
|
return {
|
|
135
168
|
requiredRule,
|
|
136
169
|
emailRule,
|
|
@@ -146,5 +179,6 @@ export default function useUtils() {
|
|
|
146
179
|
validateWord,
|
|
147
180
|
getCountries,
|
|
148
181
|
formatter,
|
|
182
|
+
formatNumber,
|
|
149
183
|
};
|
|
150
184
|
}
|
package/error.vue
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { NuxtError } from "#app";
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
error: Object as () => NuxtError,
|
|
6
|
+
});
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<v-app>
|
|
11
|
+
<v-main>
|
|
12
|
+
<v-row
|
|
13
|
+
class="fill-height"
|
|
14
|
+
no-gutters
|
|
15
|
+
justify="center"
|
|
16
|
+
align-content="center"
|
|
17
|
+
>
|
|
18
|
+
<v-col cols="9">
|
|
19
|
+
<v-row>
|
|
20
|
+
<v-col cols="12" class="text-center text-h2">
|
|
21
|
+
<span class="font-weight-bold">{{ props.error?.message }}</span>
|
|
22
|
+
</v-col>
|
|
23
|
+
<v-col cols="12">
|
|
24
|
+
<v-row no-gutters justify="center">
|
|
25
|
+
<v-btn
|
|
26
|
+
rounded="xl"
|
|
27
|
+
size="large"
|
|
28
|
+
class="text-none"
|
|
29
|
+
variant="tonal"
|
|
30
|
+
:to="{ name: 'index' }"
|
|
31
|
+
>
|
|
32
|
+
Go to home page
|
|
33
|
+
</v-btn>
|
|
34
|
+
</v-row>
|
|
35
|
+
</v-col>
|
|
36
|
+
</v-row>
|
|
37
|
+
</v-col>
|
|
38
|
+
</v-row>
|
|
39
|
+
</v-main>
|
|
40
|
+
</v-app>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export default defineNuxtRouteMiddleware(async () => {
|
|
2
|
+
// Ensure middleware runs only on the client side
|
|
3
|
+
if (import.meta.server) return;
|
|
4
|
+
|
|
5
|
+
const { cookieConfig } = useRuntimeConfig().public;
|
|
6
|
+
|
|
7
|
+
// Get access token from cookies
|
|
8
|
+
const accessToken = useCookie("accessToken", cookieConfig).value;
|
|
9
|
+
|
|
10
|
+
if (!accessToken) {
|
|
11
|
+
// Redirect to login page if no access token
|
|
12
|
+
return navigateTo({ name: "index" });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { getCurrentUser } = useLocalAuth();
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
await getCurrentUser();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.log(error);
|
|
21
|
+
|
|
22
|
+
// Redirect to login page if user authentication fails
|
|
23
|
+
return navigateTo({ name: "index" });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const hexSchema = z
|
|
4
|
+
.string()
|
|
5
|
+
.regex(/^[0-9a-fA-F]{24}$/, "Invalid organization ID");
|
|
6
|
+
|
|
7
|
+
export default defineNuxtRouteMiddleware((to) => {
|
|
8
|
+
const { organization } = to.params;
|
|
9
|
+
|
|
10
|
+
if (organization && !hexSchema.safeParse(organization).success) {
|
|
11
|
+
return navigateTo(
|
|
12
|
+
{ name: "require-organization-membership" },
|
|
13
|
+
{ replace: true }
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
});
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@goweekdays/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.6",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@mdi/font": "^7.4.47",
|
|
31
|
-
"sass": "^1.80.6"
|
|
31
|
+
"sass": "^1.80.6",
|
|
32
|
+
"zod": "^3.24.2"
|
|
32
33
|
}
|
|
33
34
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters class="fill-height" align="center" justify="center">
|
|
3
|
+
<v-col cols="12" lg="6" md="6" sm="6" class="text-center text-subtitle-1">
|
|
4
|
+
You must be a member of an organization to view this page. Please join or
|
|
5
|
+
contact your administrator for access.
|
|
6
|
+
<v-row no-gutters justify="center" align="center" class="mt-2">
|
|
7
|
+
<v-btn
|
|
8
|
+
@click="goToAccount"
|
|
9
|
+
rounded="xl"
|
|
10
|
+
variant="tonal"
|
|
11
|
+
class="text-none text-subtitle-2"
|
|
12
|
+
>
|
|
13
|
+
Go to Account Page
|
|
14
|
+
</v-btn>
|
|
15
|
+
<span class="mx-2">or</span>
|
|
16
|
+
<v-btn
|
|
17
|
+
@click="createOrg"
|
|
18
|
+
rounded="xl"
|
|
19
|
+
variant="tonal"
|
|
20
|
+
class="text-none text-subtitle-2"
|
|
21
|
+
>
|
|
22
|
+
Create an Organization
|
|
23
|
+
</v-btn>
|
|
24
|
+
</v-row>
|
|
25
|
+
</v-col>
|
|
26
|
+
</v-row>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
definePageMeta({
|
|
31
|
+
layout: "plain",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const { APP_ACCOUNT, APP_NAME, APP_ORG } = useRuntimeConfig().public;
|
|
35
|
+
|
|
36
|
+
function goToAccount() {
|
|
37
|
+
window.location.href = `${APP_ACCOUNT}/home`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createOrg() {
|
|
41
|
+
if (APP_NAME.toLowerCase() === "org") {
|
|
42
|
+
navigateTo({ name: "organizations-create" });
|
|
43
|
+
} else {
|
|
44
|
+
window.location.href = `${APP_ORG}/organizations/create`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters class="fill-height" align="center" justify="center">
|
|
3
|
+
<v-col cols="12" lg="6" md="6" sm="6" class="text-center text-subtitle-1">
|
|
4
|
+
You must be a member of an organization to view this page. Please join or
|
|
5
|
+
contact your administrator for access.
|
|
6
|
+
<v-row no-gutters justify="center" class="mt-2">
|
|
7
|
+
<v-btn
|
|
8
|
+
@click="goToAccount"
|
|
9
|
+
rounded="xl"
|
|
10
|
+
variant="tonal"
|
|
11
|
+
class="text-none text-subtitle-2"
|
|
12
|
+
>
|
|
13
|
+
Go to Account Page
|
|
14
|
+
</v-btn>
|
|
15
|
+
</v-row>
|
|
16
|
+
</v-col>
|
|
17
|
+
</v-row>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
definePageMeta({
|
|
22
|
+
layout: "plain",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function goToAccount() {
|
|
26
|
+
const { APP_ACCOUNT } = useRuntimeConfig().public;
|
|
27
|
+
window.location.href = `${APP_ACCOUNT}/home`;
|
|
28
|
+
}
|
|
29
|
+
</script>
|