@goweekdays/layer-common 1.3.5 → 1.4.2

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @goweekdays/layer-common
2
2
 
3
+ ## 1.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 273fab2: Enhance member fetching and UI improvements
8
+
9
+ ## 1.4.1
10
+
11
+ ### Patch Changes
12
+
13
+ - b7afd94: Improve organization requirement page UX and messaging
14
+
15
+ ## 1.4.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 6a01b5d: Add plan management and refactor subscription logic
20
+
3
21
  ## 1.3.5
4
22
 
5
23
  ### Patch Changes
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <span class="text-subtitle-2 font-weight-bold">
3
- {{ title }} <span v-if="props.required" class="text-error">*</span>
3
+ <span :class="props.class">
4
+ {{ title }}
5
+ </span>
6
+ <span v-if="props.required" class="text-error">*</span>
4
7
  </span>
5
8
  </template>
6
9
 
@@ -14,5 +17,9 @@ const props = defineProps({
14
17
  type: Boolean,
15
18
  default: false,
16
19
  },
20
+ class: {
21
+ type: String,
22
+ default: "",
23
+ },
17
24
  });
18
25
  </script>
@@ -26,6 +26,9 @@
26
26
  <template #append>
27
27
  <slot name="append"></slot>
28
28
  </template>
29
+ <template #prepend>
30
+ <slot name="prepend"></slot>
31
+ </template>
29
32
  </v-navigation-drawer>
30
33
  </template>
31
34
 
@@ -25,7 +25,7 @@
25
25
 
26
26
  <v-card width="300px" rounded="lg" class="pa-4">
27
27
  <span class="text-subtitle-2 font-weight-bold">
28
- Switch {{ prop.title }} context
28
+ {{ prop.title }}
29
29
  </span>
30
30
  <v-text-field
31
31
  v-model="search"
@@ -66,7 +66,7 @@ const prop = defineProps({
66
66
  title: {
67
67
  type: String,
68
68
  required: true,
69
- default: "app",
69
+ default: "Switch Context",
70
70
  },
71
71
  items: {
72
72
  type: Array as PropType<Array<Record<string, any>>>,
@@ -10,7 +10,6 @@ export default function useLocal() {
10
10
  const drawer = useState("drawer", () => true);
11
11
 
12
12
  const { APP_INVENTORY, APP_ASSET, APP_FINANCE } = appConfig;
13
- const { currentOrg } = useOrg();
14
13
 
15
14
  const apps = computed(() => {
16
15
  return [
@@ -18,19 +17,19 @@ export default function useLocal() {
18
17
  title: "Finance",
19
18
  icon: "mdi-file-document-multiple",
20
19
  link: APP_FINANCE as string,
21
- landingPage: `org/${currentOrg.value ?? ""}`,
20
+ landingPage: "",
22
21
  },
23
22
  {
24
23
  title: "Inventory",
25
24
  icon: "mdi-warehouse",
26
25
  link: APP_INVENTORY as string,
27
- landingPage: `org/${currentOrg.value ?? ""}`,
26
+ landingPage: "",
28
27
  },
29
28
  {
30
29
  title: "Asset",
31
30
  icon: "mdi-package-variant-closed",
32
31
  link: APP_ASSET as string,
33
- landingPage: `org/${currentOrg.value ?? ""}`,
32
+ landingPage: "",
34
33
  },
35
34
  ];
36
35
  });
@@ -48,7 +48,7 @@ export default function useLocalAuth() {
48
48
  }
49
49
 
50
50
  function verify(id: string) {
51
- return $fetch<TKeyValuePair>(`/api/auth/verify/${id}`, {
51
+ return $fetch<Record<string, any>>(`/api/auth/verify/${id}`, {
52
52
  method: "GET",
53
53
  });
54
54
  }
@@ -33,6 +33,22 @@ export default function useMember() {
33
33
  });
34
34
  }
35
35
 
36
+ function getAllByAppUser({
37
+ app = "",
38
+ user = "",
39
+ limit = 10,
40
+ page = 1,
41
+ search = "",
42
+ } = {}) {
43
+ return $fetch<Record<string, any>>(
44
+ `/api/members/orgs/app/${app}/user/${user}`,
45
+ {
46
+ method: "GET",
47
+ query: { page, limit, search },
48
+ }
49
+ );
50
+ }
51
+
36
52
  async function getAll({
37
53
  page = 1,
38
54
  search = "",
@@ -104,5 +120,6 @@ export default function useMember() {
104
120
  updateRoleById,
105
121
  updateStatusById,
106
122
  deleteById,
123
+ getAllByAppUser,
107
124
  };
108
125
  }
@@ -1,5 +1,9 @@
1
1
  export default function useOrg() {
2
- function add(value: Pick<TOrg, "name" | "email" | "contact" | "createdBy">) {
2
+ function add(
3
+ value: Pick<TOrg, "name" | "email" | "contact" | "createdBy"> & {
4
+ seats: number;
5
+ }
6
+ ) {
3
7
  return $fetch<Record<string, any>>("/api/organizations", {
4
8
  method: "POST",
5
9
  body: value,
@@ -35,6 +39,16 @@ export default function useOrg() {
35
39
  });
36
40
  }
37
41
 
42
+ function updateById(
43
+ id: string,
44
+ options: Pick<TOrg, "name" | "description" | "email" | "contact">
45
+ ) {
46
+ return $fetch(`/api/organizations/id/${id}`, {
47
+ method: "PATCH",
48
+ body: options,
49
+ });
50
+ }
51
+
38
52
  const org = ref<TOrg>({
39
53
  name: "",
40
54
  contact: "",
@@ -48,5 +62,6 @@ export default function useOrg() {
48
62
  getAll,
49
63
  getByUserId,
50
64
  getById,
65
+ updateById,
51
66
  };
52
67
  }
@@ -0,0 +1,19 @@
1
+ export function usePlan() {
2
+ const plan = ref<TPlan>({
3
+ name: "",
4
+ price: 0,
5
+ currency: "",
6
+ billingCycle: "monthly",
7
+ });
8
+
9
+ function getDefaultPlan() {
10
+ return $fetch<Record<string, any>>(`/api/plans/default`, {
11
+ method: "GET",
12
+ });
13
+ }
14
+
15
+ return {
16
+ plan,
17
+ getDefaultPlan,
18
+ };
19
+ }
@@ -1,252 +1,51 @@
1
1
  export default function useSubscription() {
2
- function createSubscriptionPlan(
3
- seats: number,
4
- trialDays: number,
5
- productId: string
6
- ) {
7
- return $fetch("/api/subscriptions/plan", {
8
- method: "POST",
9
- body: {
10
- seats,
11
- trialDays,
12
- productId,
13
- },
14
- });
15
- }
2
+ const subscription = ref<TSubscription>({
3
+ org: "",
4
+ seats: 0,
5
+ paidSeats: 0,
6
+ amount: 0,
7
+ currency: "",
8
+ billingCycle: "monthly",
9
+ nextBillingDate: "",
10
+ });
16
11
 
17
- function add(subscriptionId: string, user: string) {
18
- return $fetch("/api/subscriptions", {
19
- method: "POST",
20
- body: {
21
- subscriptionId,
22
- user,
23
- },
12
+ function getByOrg(org = "") {
13
+ return $fetch<Record<string, any>>(`/api/subscriptions/org/${org}`, {
14
+ method: "GET",
24
15
  });
25
16
  }
26
17
 
27
- function addBillingContactById(id: string, email: string) {
28
- return $fetch(`/api/subscriptions/billing-contact/${id}`, {
29
- method: "PUT",
30
- body: {
31
- email,
32
- },
33
- });
34
- }
35
-
36
- function updateBillingContactByAddedAt(
37
- id: string,
38
- addedAt: string,
39
- email: string
18
+ function getTransactionsById(
19
+ id = "",
20
+ options: { page?: number; limit?: number } = {}
40
21
  ) {
41
- return $fetch(
42
- `/api/subscriptions/billing-contact/${id}/added-at/${addedAt}`,
43
- {
44
- method: "PUT",
45
- body: {
46
- email,
47
- },
48
- }
49
- );
50
- }
51
-
52
- function deleteBillingContactByAddedAt(id: string, addedAt: string) {
53
- return $fetch(
54
- `/api/subscriptions/billing-contact/${id}/added-at/${addedAt}`,
55
- {
56
- method: "DELETE",
57
- }
58
- );
59
- }
60
-
61
- function getById(id: string) {
62
- return $fetch<TSubscription>(`/api/subscriptions/id/${id}`);
63
- }
64
-
65
- function getByAffiliateId(id: string) {
66
- return $fetch<TSubscription>(`/api/subscriptions/affiliate/${id}`);
67
- }
68
-
69
- function getByOrgId(id: string) {
70
- return $fetch<Record<string, any>>(`/api/subscriptions/org/${id}`);
71
- }
72
-
73
- function getSubscriptions() {
74
- return $fetch("/api/subscriptions");
75
- }
76
-
77
- function getSubscriptionStatusById(id: string) {
78
- return $fetch<Record<string, string>>(`/api/subscriptions/status/${id}`);
79
- }
80
-
81
- function cancelSubscription(id: string) {
82
- return $fetch(`/api/subscriptions/cancel/${id}`, {
83
- method: "DELETE",
84
- });
85
- }
86
-
87
- const affiliateSubscription = useState(
88
- "affiliateSubscription",
89
- () => "inactive"
90
- );
91
-
92
- function updatePromoCodeById(id: string, promoCode: string) {
93
- return $fetch(`/api/subscriptions/promo-code/${id}`, {
94
- method: "PUT",
95
- body: {
96
- promoCode,
97
- },
98
- });
99
- }
100
-
101
- function updateStatusById(id: string, status: string) {
102
- return $fetch(`/api/subscriptions/status/${id}`, {
103
- method: "PUT",
104
- body: {
105
- status,
106
- },
107
- });
108
- }
109
-
110
- function updatePaymentMethodById(id: string, paymentMethodId: string) {
111
- return $fetch(`/api/subscriptions/payment-method/${id}`, {
112
- method: "PUT",
113
- body: {
114
- paymentMethodId,
115
- },
116
- });
117
- }
118
-
119
- async function affSubscriptionStatus() {
120
- const { currentUser } = useLocalAuth();
121
-
122
- if (currentUser.value && currentUser.value._id) {
123
- try {
124
- const result = await getByAffiliateId(currentUser.value._id);
125
- affiliateSubscription.value = result.status as string;
126
- } catch (error) {
127
- console.error("failed to get the subscription", error);
128
- }
129
- }
130
- }
131
-
132
- const orgSubscription = useState("orgSubscription", () => "inactive");
133
-
134
- async function orgSubscriptionStatus() {
135
- const { currentOrg } = useOrg();
136
-
137
- if (currentOrg.value) {
138
- try {
139
- const data = await getByOrgId(currentOrg.value);
140
- orgSubscription.value = data?.status as string;
141
- } catch (error) {
142
- console.error("failed to get the subscription", error);
143
- }
144
- }
145
- }
146
-
147
- type TSub = {
148
- customer_id: string;
149
- amount: number;
150
- payment_method_id: string;
151
- payment_method_type: string;
152
- payment_method_channel: string;
153
- payment_method_expiry_month?: string;
154
- payment_method_expiry_year?: string;
155
- payment_method_cvv?: string;
156
- payment_method_cardholder_name?: string;
157
- currency?: string;
158
- seats?: number;
159
- organization?: TOrg;
160
- billingAddress: TAddress;
161
- promoCode?: string;
162
- };
163
-
164
- function initOrgSubscription(value: TSub) {
165
- return $fetch<Record<string, any>>("/api/subscriptions/organization", {
166
- method: "POST",
167
- body: value,
168
- });
169
- }
170
-
171
- function initAffiliateSubscription(value: TSub) {
172
- return $fetch<Record<string, any>>("/api/subscriptions/affiliate", {
173
- method: "POST",
174
- body: value,
175
- });
176
- }
177
-
178
- function updateSeatsById({
179
- transactionId = "",
180
- subscriptionId = "",
181
- seats = 0,
182
- amount = 0,
183
- } = {}) {
184
22
  return $fetch<Record<string, any>>(
185
- `/api/subscriptions/seats/${subscriptionId}`,
23
+ `/api/subscriptions/id/${id}/transactions`,
186
24
  {
187
- method: "PUT",
188
- body: {
189
- seats,
190
- amount,
191
- transactionId,
25
+ method: "GET",
26
+ query: {
27
+ page: options.page ?? 1,
28
+ limit: options.limit ?? 20,
192
29
  },
193
30
  }
194
31
  );
195
32
  }
196
33
 
197
- function processSubscriptionPayment(id: string, invoice: string) {
198
- return $fetch(`/api/subscriptions/payment/id/${id}`, {
199
- method: "PUT",
34
+ function updateSeatById({ id = "", seats = 0, amount = 0, user = "" } = {}) {
35
+ return $fetch<Record<string, any>>(`/api/subscriptions/id/${id}/seats`, {
36
+ method: "PATCH",
200
37
  body: {
201
- invoice,
38
+ seats,
39
+ amount,
40
+ user,
202
41
  },
203
42
  });
204
43
  }
205
44
 
206
- function addOrgSubscription(value: {
207
- user: string;
208
- transactionId?: string;
209
- promoCode?: string;
210
- seats: number;
211
- perSeatPrice: number;
212
- currency: string;
213
- org: {
214
- name: string;
215
- email: string;
216
- contact: string;
217
- busInst: string;
218
- type: string;
219
- };
220
- }) {
221
- return $fetch("/api/subscriptions/subscribe", {
222
- method: "POST",
223
- body: value,
224
- });
225
- }
226
-
227
45
  return {
228
- add,
229
- getById,
230
- getByOrgId,
231
- getSubscriptions,
232
- affSubscriptionStatus,
233
- affiliateSubscription,
234
- orgSubscriptionStatus,
235
- orgSubscription,
236
- getSubscriptionStatusById,
237
- cancelSubscription,
238
- initAffiliateSubscription,
239
- initOrgSubscription,
240
- getByAffiliateId,
241
- updateSeatsById,
242
- updatePromoCodeById,
243
- updateStatusById,
244
- updatePaymentMethodById,
245
- addBillingContactById,
246
- updateBillingContactByAddedAt,
247
- deleteBillingContactByAddedAt,
248
- processSubscriptionPayment,
249
- createSubscriptionPlan,
250
- addOrgSubscription,
46
+ subscription,
47
+ getByOrg,
48
+ getTransactionsById,
49
+ updateSeatById,
251
50
  };
252
51
  }
package/middleware/org.ts CHANGED
@@ -8,6 +8,6 @@ export default defineNuxtRouteMiddleware((to) => {
8
8
  const org = (to.params.org as string) ?? "";
9
9
 
10
10
  if (org && !hexSchema.safeParse(org).success) {
11
- return navigateTo({ name: "require-organization" }, { replace: true });
11
+ return navigateTo({ name: "require-organization" });
12
12
  }
13
13
  });
package/nuxt.config.ts CHANGED
@@ -55,6 +55,12 @@ export default defineNuxtConfig({
55
55
  "/api/organizations/**": {
56
56
  proxy: `${process.env.API_CORE}/api/organizations/**`,
57
57
  },
58
+ "/api/subscriptions/**": {
59
+ proxy: `${process.env.API_CORE}/api/subscriptions/**`,
60
+ },
61
+ "/api/plans/**": {
62
+ proxy: `${process.env.API_CORE}/api/plans/**`,
63
+ },
58
64
  "/api/members/**": { proxy: `${process.env.API_CORE}/api/members/**` },
59
65
  "/api/teams/**": { proxy: `${process.env.API_CORE}/api/teams/**` },
60
66
  "/api/entities/**": { proxy: `${process.env.API_CORE}/api/entities/**` },
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@goweekdays/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "1.3.5",
5
+ "version": "1.4.2",
6
6
  "main": "./nuxt.config.ts",
7
7
  "publishConfig": {
8
8
  "access": "public"
package/pages/login.vue CHANGED
@@ -157,7 +157,13 @@ async function submit({ email = "", password = "" } = {}) {
157
157
  } else {
158
158
  message.value = "An unexpected error occurred. Please try again.";
159
159
  }
160
- console.log(error);
160
+
161
+ if (
162
+ error.response.status === 404 &&
163
+ error.response.url.includes("/api/members/app")
164
+ ) {
165
+ navigateTo({ name: "index" });
166
+ }
161
167
  } finally {
162
168
  loading.value = false;
163
169
  }
@@ -7,21 +7,45 @@
7
7
  </v-col>
8
8
 
9
9
  <span class="text-subtitle-2">
10
- You must have an organization to access this page.
10
+ You must be part of an organization to access this app. Please contact
11
+ your organization administrator or create a new organization.
11
12
  </span>
12
13
 
13
14
  <v-col cols="12" class="mt-6">
14
15
  <v-row no-gutters justify="center">
15
- <v-btn
16
- size="large"
17
- class="text-none"
18
- variant="flat"
19
- color="black"
20
- rounded
21
- @click="createOrg()"
22
- >
23
- Create Organization
24
- </v-btn>
16
+ <v-col cols="2">
17
+ <v-btn
18
+ block
19
+ size="large"
20
+ class="text-none"
21
+ variant="flat"
22
+ color="black"
23
+ rounded
24
+ @click="createOrg()"
25
+ >
26
+ Create Organization
27
+ </v-btn>
28
+ </v-col>
29
+ </v-row>
30
+ </v-col>
31
+
32
+ <v-col cols="12" class="text-center font-weight-bold my-2"> or </v-col>
33
+
34
+ <v-col cols="12">
35
+ <v-row no-gutters justify="center">
36
+ <v-col cols="2">
37
+ <v-btn
38
+ block
39
+ size="large"
40
+ class="text-none"
41
+ variant="flat"
42
+ color="black"
43
+ rounded
44
+ :to="{ name: 'index' }"
45
+ >
46
+ Return to landing page
47
+ </v-btn>
48
+ </v-col>
25
49
  </v-row>
26
50
  </v-col>
27
51
  </v-row>
@@ -34,7 +58,7 @@ definePageMeta({
34
58
 
35
59
  function createOrg() {
36
60
  const { APP, APP_ORG } = useRuntimeConfig().public;
37
- if (APP === "organization") {
61
+ if (APP === "org") {
38
62
  navigateTo({ name: "organizations-create" });
39
63
  } else {
40
64
  navigateTo(`${APP_ORG}/organizations/create`, { external: true });
@@ -139,7 +139,9 @@ const loading = ref(false);
139
139
 
140
140
  async function validate() {
141
141
  try {
142
- await verify(id);
142
+ const result = await verify(id);
143
+
144
+ type.value = result.type;
143
145
 
144
146
  validInvitation.value = true;
145
147
  message.value = "";
@@ -0,0 +1,13 @@
1
+ declare type TPlan = {
2
+ _id?: string;
3
+ name: string;
4
+ description?: string;
5
+ features?: string[];
6
+ price: number;
7
+ currency: string;
8
+ billingCycle: "monthly" | "yearly";
9
+ default?: boolean;
10
+ status?: "active" | "inactive";
11
+ createdAt?: string;
12
+ updatedAt?: string;
13
+ };
@@ -1,29 +1,27 @@
1
- declare type TBillingRecipient = {
2
- addedAt?: string;
3
- email: string;
4
- };
5
-
6
1
  declare type TSubscription = {
7
2
  _id?: string;
8
- user?: string;
9
- org?: string;
10
- customerId: string;
11
- paymentMethodId: string;
3
+ org: string;
4
+ seats: number;
5
+ paidSeats: number;
12
6
  amount: number;
13
- description?: string;
14
7
  currency: string;
8
+ billingCycle: "monthly" | "yearly"; // e.g., 'monthly', 'yearly'
15
9
  promoCode?: string;
16
- type: string;
17
- paidSeats?: number;
18
- currentSeats?: number;
19
- maxSeats?: number;
20
10
  status?: string;
21
- billingCycle: "monthly" | "yearly";
22
- billingContacts?: TBillingRecipient[];
23
- nextBillingDate?: string;
24
- lastPaymentStatus?: string;
25
- failedAttempts?: number;
11
+ nextBillingDate: string;
12
+ createdAt?: string;
13
+ updatedAt?: string;
14
+ };
15
+
16
+ declare type TSubscriptionTransaction = {
17
+ _id?: string;
18
+ subscription: string;
19
+ amount: number;
20
+ currency: string;
21
+ type: "initiate" | "add-seat" | "remove-seat" | "renewal";
22
+ description?: string;
23
+ createdBy: string;
24
+ createdByName?: string;
26
25
  createdAt?: string;
27
26
  updatedAt?: string;
28
- deletedAt?: string;
29
27
  };