@goweekdays/layer-common 0.0.12 → 0.1.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.
@@ -10,7 +10,7 @@ const inputRef = ref<HTMLInputElement | null>(null);
10
10
  const attrs = useAttrs();
11
11
 
12
12
  let cursorPosition = 0;
13
- let forceCursorToEnd = false;
13
+ let forceCursorToEnd = true;
14
14
 
15
15
  // Computed property to format value with commas or infinity sign
16
16
  const formattedValue = computed({
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <v-app-bar scroll-behavior="elevate" scroll-threshold="200">
3
- <div style="width: 264px" class="ml-4">
3
+ <v-app-bar-nav-icon @click="drawer = !drawer" />
4
+ <div style="width: 206px" class="ml-4">
4
5
  <nuxt-link
5
6
  class="text-h6 font-weight-medium text-decoration-none APP_NAME"
6
7
  :to="{ name: APP_NAME_ROUTE }"
@@ -172,7 +173,7 @@ import { useTheme } from "vuetify";
172
173
 
173
174
  const search = defineModel("search", { type: String });
174
175
 
175
- const { redirect, apps } = useLocal();
176
+ const { redirect, apps, drawer } = useLocal();
176
177
 
177
178
  const {
178
179
  APP_MAIN,
@@ -220,7 +221,7 @@ const name = computed(() => {
220
221
 
221
222
  const { getNameInitials } = useUtils();
222
223
 
223
- const defaultApps = [
224
+ const defaultApps = computed(() => [
224
225
  {
225
226
  title: "Account",
226
227
  icon: "mdi-account",
@@ -231,7 +232,9 @@ const defaultApps = [
231
232
  title: "Organization",
232
233
  icon: "mdi-domain",
233
234
  link: APP_ORG,
234
- landingPage: `org/${currentUser.value?.defaultOrg}`,
235
+ landingPage: currentUser.value?.defaultOrg
236
+ ? `org/${currentUser.value?.defaultOrg}`
237
+ : "index",
235
238
  },
236
239
  {
237
240
  title: "Admin",
@@ -245,7 +248,7 @@ const defaultApps = [
245
248
  link: APP_AFFILIATE,
246
249
  landingPage: "home",
247
250
  },
248
- ];
251
+ ]);
249
252
  </script>
250
253
 
251
254
  <style scoped>
@@ -1,16 +1,17 @@
1
1
  <template>
2
- <v-navigation-drawer permanent floating class="pr-2">
3
- <v-list>
2
+ <v-navigation-drawer v-model="drawer" permanent floating class="pr-2">
3
+ <v-list class="py-1">
4
4
  <slot name="action"></slot>
5
5
  <template
6
6
  v-for="(navigationItem, navigationIndex) in props.navigationItems"
7
- :key="`${navigationItem.route.name}-${navigationIndex}`"
7
+ :key="`${navigationItem.title}-${navigationIndex}`"
8
8
  >
9
9
  <NavigationItem
10
10
  :title="navigationItem.title"
11
11
  :icon="navigationItem.icon"
12
12
  :route="navigationItem.route"
13
13
  :children="navigationItem.children"
14
+ :disabled="navigationItem.disabled"
14
15
  />
15
16
  </template>
16
17
  </v-list>
@@ -21,4 +22,6 @@
21
22
  const props = defineProps({
22
23
  navigationItems: { type: Array<TNavigationItem>, required: true },
23
24
  });
25
+
26
+ const { drawer } = useLocal();
24
27
  </script>
@@ -1,31 +1,41 @@
1
1
  <template>
2
- <div class="arrow-navigation">
3
- <v-btn icon="mdi-chevron-left" variant="text" density="comfortable" :disabled="page <= 1" @click="decrement" />
4
- <v-btn
5
- icon="mdi-chevron-right" variant="text" density="comfortable" :disabled="page >= props.length"
6
- @click="increment" />
7
- </div>
2
+ <div class="arrow-navigation">
3
+ <v-btn
4
+ icon="mdi-chevron-left"
5
+ variant="text"
6
+ density="comfortable"
7
+ :disabled="page <= 1"
8
+ @click="decrement"
9
+ />
10
+ <v-btn
11
+ icon="mdi-chevron-right"
12
+ variant="text"
13
+ density="comfortable"
14
+ :disabled="page >= props.length"
15
+ @click="increment"
16
+ />
17
+ </div>
8
18
  </template>
9
19
 
10
20
  <script setup lang="ts">
11
21
  const page = defineModel({ type: Number, default: 0 });
12
22
  function increment() {
13
- page.value++;
23
+ page.value++;
14
24
  }
15
25
 
16
26
  function decrement() {
17
- page.value--;
27
+ page.value--;
18
28
  }
19
- const emit = defineEmits(['update:value']);
29
+ const emit = defineEmits(["update:value"]);
20
30
  watch(page, () => {
21
- emit('update:value', page.value);
31
+ emit("update:value", page.value);
22
32
  });
23
33
 
24
34
  const props = defineProps({
25
- length: {
26
- type: Number,
27
- required: true,
28
- default: 0
29
- }
35
+ length: {
36
+ type: Number,
37
+ required: true,
38
+ default: 0,
39
+ },
30
40
  });
31
- </script>
41
+ </script>
@@ -18,6 +18,7 @@
18
18
  :icon="child.icon"
19
19
  :route="child.route"
20
20
  :children="child.children"
21
+ :disabled="child.disabled"
21
22
  />
22
23
  </v-list-group>
23
24
 
@@ -27,6 +28,7 @@
27
28
  :to="props.route"
28
29
  rounded="e-pill"
29
30
  class="text-subtitle-2"
31
+ :disabled="props.disabled"
30
32
  >
31
33
  {{ title }}
32
34
  </v-list-item>
@@ -55,5 +57,10 @@ const props = defineProps({
55
57
  required: false,
56
58
  default: () => [],
57
59
  },
60
+ disabled: {
61
+ type: Boolean,
62
+ required: false,
63
+ default: false,
64
+ },
58
65
  });
59
66
  </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <v-row no-gutters justify="end" align="center">
3
+ <span class="mr-2 text-caption text-fontgray">
4
+ {{ props.pageRange }}
5
+ </span>
6
+ <div class="arrow-navigation">
7
+ <v-btn
8
+ icon="mdi-chevron-left"
9
+ variant="text"
10
+ density="comfortable"
11
+ :disabled="page <= 1"
12
+ @click="decrement"
13
+ />
14
+ <v-btn
15
+ icon="mdi-chevron-right"
16
+ variant="text"
17
+ density="comfortable"
18
+ :disabled="page >= props.pages"
19
+ @click="increment"
20
+ />
21
+ </div>
22
+ </v-row>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ const page = defineModel({ type: Number, default: 0 });
27
+
28
+ const props = defineProps({
29
+ pages: {
30
+ type: Number,
31
+ required: true,
32
+ default: 0,
33
+ },
34
+ pageRange: {
35
+ type: String,
36
+ required: true,
37
+ default: "-- - -- of --",
38
+ },
39
+ });
40
+
41
+ const emit = defineEmits(["refresh", "update:pagination"]);
42
+
43
+ function increment() {
44
+ page.value++;
45
+ emit("update:pagination", page.value);
46
+ }
47
+
48
+ function decrement() {
49
+ page.value--;
50
+ emit("update:pagination", page.value);
51
+ }
52
+ </script>
@@ -19,8 +19,13 @@
19
19
  :close-on-content-click="false"
20
20
  >
21
21
  <template #activator="{ props }">
22
- <v-btn variant="text" class="text-none ml-2" v-bind="props">
23
- <div class="d-block text-truncate" style="width: 130px">
22
+ <v-btn
23
+ variant="text"
24
+ class="text-none ml-2"
25
+ size="large"
26
+ v-bind="props"
27
+ >
28
+ <div class="d-block text-truncate text-start" style="width: 130px">
24
29
  {{ selectedOrg?.text || "Select organization" }}
25
30
  </div>
26
31
  <v-icon class="ml-1">mdi-menu-down</v-icon>
@@ -42,7 +47,6 @@
42
47
  density="compact"
43
48
  class="text-caption font-weight-bold"
44
49
  v-for="item in orgs"
45
- :key="item.value"
46
50
  @click="switchOrg(item.value)"
47
51
  >
48
52
  <v-icon size="16" class="mr-2">
@@ -54,18 +58,20 @@
54
58
  </v-list>
55
59
 
56
60
  <v-btn
61
+ v-if="isOrg"
57
62
  block
58
63
  class="text-none mb-1"
59
64
  variant="tonal"
60
- :to="{ name: 'organizations' }"
65
+ @click="navigateToOrgs"
61
66
  >
62
67
  Manage Organizations
63
68
  </v-btn>
64
69
  <v-btn
70
+ v-if="isOrg"
65
71
  block
66
72
  class="text-none mt-1"
67
73
  variant="tonal"
68
- :to="{ name: 'organizations-create' }"
74
+ @click="createOrg"
69
75
  >
70
76
  Create Organization
71
77
  </v-btn>
@@ -119,4 +125,36 @@ function switchOrg(org: string) {
119
125
  params: { organization: org },
120
126
  });
121
127
  }
128
+
129
+ const APP_NAME = useRuntimeConfig().public.APP_NAME;
130
+ const APP_ORG = useRuntimeConfig().public.APP_ORG;
131
+
132
+ const { redirect } = useLocal();
133
+
134
+ function createOrg() {
135
+ if (APP_NAME.toLowerCase() === "organization") {
136
+ navigateTo({
137
+ name: "organizations-create",
138
+ });
139
+ return;
140
+ }
141
+
142
+ redirect(APP_ORG, "organizations/create");
143
+ }
144
+
145
+ function navigateToOrgs() {
146
+ if (APP_NAME.toLowerCase() === "organization") {
147
+ navigateTo({
148
+ name: "organizations",
149
+ params: { status: "active" },
150
+ });
151
+ return;
152
+ }
153
+
154
+ redirect(APP_ORG, "organizations");
155
+ }
156
+
157
+ const isOrg = computed(() => {
158
+ return APP_NAME.toLowerCase() === "organization";
159
+ });
122
160
  </script>
@@ -43,10 +43,11 @@
43
43
  <slot name="extension"></slot>
44
44
  </template>
45
45
  </v-toolbar>
46
+ <v-divider></v-divider>
46
47
 
47
48
  <v-data-table
48
49
  v-model="selected"
49
- v-bind="$attrs"
50
+ v-bind="attrs"
50
51
  :headers="props.headers"
51
52
  :items="props.items"
52
53
  item-value="_id"
@@ -66,6 +67,7 @@
66
67
  </template>
67
68
 
68
69
  <script setup lang="ts">
70
+ const attrs = useAttrs();
69
71
  const selected = defineModel({
70
72
  type: Array as PropType<Array<string>>,
71
73
  default: () => [],
@@ -32,10 +32,45 @@ export default function useAddress() {
32
32
  });
33
33
  }
34
34
 
35
+ function updateById({
36
+ id = "",
37
+ country = "",
38
+ address = "",
39
+ continuedAddress = "",
40
+ city = "",
41
+ province = "",
42
+ postalCode = "",
43
+ taxId = "",
44
+ orgId = "",
45
+ } = {}) {
46
+ const payload: Record<string, any> = {
47
+ country,
48
+ address,
49
+ continuedAddress,
50
+ city,
51
+ province,
52
+ postalCode,
53
+ taxId,
54
+ };
55
+
56
+ if (orgId) {
57
+ payload.org = orgId;
58
+ }
59
+
60
+ return useNuxtApp().$api(`/api/addresses/details/${id}`, {
61
+ method: "PUT",
62
+ body: payload,
63
+ });
64
+ }
65
+
35
66
  function getByUserId(user = "") {
36
67
  return useNuxtApp().$api<TAddress>(`/api/addresses/user/${user}`);
37
68
  }
38
69
 
70
+ function getByOrgId(id = "") {
71
+ return useNuxtApp().$api<TAddress>(`/api/addresses/org/${id}`);
72
+ }
73
+
39
74
  const _address = useState("address", (): TAddress => {
40
75
  return {
41
76
  type: "",
@@ -103,5 +138,7 @@ export default function useAddress() {
103
138
  getByUserId,
104
139
  address: _address,
105
140
  completeAddress,
141
+ getByOrgId,
142
+ updateById,
106
143
  };
107
144
  }
@@ -0,0 +1,62 @@
1
+ export default function useChartOfAccount() {
2
+ function getAll(
3
+ { page = 1, status = "active", orgId = "", children = null } = {} as {
4
+ page?: number;
5
+ status?: string;
6
+ orgId?: string;
7
+ children?: number;
8
+ }
9
+ ) {
10
+ return useNuxtApp().$api<Record<string, any>>("/api/chart-of-accounts", {
11
+ method: "GET",
12
+ query: { page, status, orgId, children },
13
+ });
14
+ }
15
+
16
+ type TAddPayload = {
17
+ orgId: string;
18
+ code: string;
19
+ name: string;
20
+ normalBalance: string;
21
+ parent?: string;
22
+ description?: string;
23
+ };
24
+
25
+ function add(value: TAddPayload) {
26
+ return useNuxtApp().$api<TAddPayload>("/api/chart-of-accounts", {
27
+ method: "POST",
28
+ body: value,
29
+ });
30
+ }
31
+
32
+ function getById(id: string) {
33
+ return useNuxtApp().$api<Record<string, any>>(
34
+ `/api/chart-of-accounts/id/${id}`
35
+ );
36
+ }
37
+
38
+ function updateById(
39
+ id: string,
40
+ value: Pick<TAddPayload, "name" | "code" | "normalBalance" | "parent">
41
+ ) {
42
+ return useNuxtApp().$api<TAddPayload>(`/api/chart-of-accounts/id/${id}`, {
43
+ method: "PUT",
44
+ body: value,
45
+ });
46
+ }
47
+
48
+ function deleteById(id: string) {
49
+ return useNuxtApp().$api<Record<string, any>>(
50
+ `/api/chart-of-accounts/id/${id}`,
51
+ { method: "DELETE" }
52
+ );
53
+ }
54
+
55
+ return {
56
+ getAll,
57
+ add,
58
+ getById,
59
+ updateById,
60
+ deleteById,
61
+ };
62
+ }
@@ -1,5 +1,9 @@
1
1
  export default function useInvoice() {
2
2
  function getBySubscriptionId({ search = "", id = "", page = 1 } = {}) {
3
+ if (!id) {
4
+ throw new Error("Subscription ID is required");
5
+ }
6
+
3
7
  return useNuxtApp().$api<Record<string, any>>(
4
8
  `/api/invoices/subscription/${id}`,
5
9
  {
@@ -9,27 +9,35 @@ export default function useLocal() {
9
9
 
10
10
  const drawer = useState("drawer", () => true);
11
11
 
12
- const { APP_INVENTORY, APP_ASSET, APP_BOOK_KEEPING } = appConfig;
12
+ const { APP_INVENTORY, APP_ASSET, APP_BOOK_KEEPING, APP_ACCOUNTING } =
13
+ appConfig;
14
+ const { currentOrg } = useOrg();
13
15
 
14
16
  const apps = computed(() => {
15
17
  return [
16
18
  {
17
- title: "Inventory Management",
19
+ title: "Accounting",
20
+ icon: "mdi-file-document-multiple",
21
+ link: APP_ACCOUNTING as string,
22
+ landingPage: `org/${currentOrg.value ?? ""}`,
23
+ },
24
+ {
25
+ title: "Bookkeeping",
26
+ icon: "mdi-file-document-edit-outline",
27
+ link: APP_BOOK_KEEPING as string,
28
+ landingPage: `org/${currentOrg.value ?? ""}`,
29
+ },
30
+ {
31
+ title: "Inventory",
18
32
  icon: "mdi-warehouse",
19
33
  link: APP_INVENTORY as string,
20
- landingPage: "home",
34
+ landingPage: `org/${currentOrg.value ?? ""}`,
21
35
  },
22
36
  {
23
- title: "Asset Management",
37
+ title: "Asset",
24
38
  icon: "mdi-package-variant-closed",
25
39
  link: APP_ASSET as string,
26
- landingPage: "home",
27
- },
28
- {
29
- title: "Bookkeeping Management",
30
- icon: "mdi-file-document-multiple",
31
- link: APP_BOOK_KEEPING as string,
32
- landingPage: "home",
40
+ landingPage: `org/${currentOrg.value ?? ""}`,
33
41
  },
34
42
  ];
35
43
  });
@@ -1,6 +1,38 @@
1
1
  export default function useLocalAuth() {
2
2
  const { cookieConfig } = useRuntimeConfig().public;
3
3
 
4
+ const currentUser = useState<TUser | null>("currentUser", () => null);
5
+
6
+ function authenticate() {
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
+ navigateTo({ name: "index" });
13
+ }
14
+
15
+ const user = useCookie("user", cookieConfig).value;
16
+
17
+ const { data: getCurrentUserReq, error: getCurrentUserErr } =
18
+ useLazyAsyncData("get-current-user", () =>
19
+ useNuxtApp().$api<TUser>(`/api/users/id/${user}`)
20
+ );
21
+
22
+ watchEffect(() => {
23
+ if (getCurrentUserReq.value) {
24
+ currentUser.value = getCurrentUserReq.value;
25
+ }
26
+ });
27
+
28
+ watchEffect(() => {
29
+ if (getCurrentUserErr.value) {
30
+ // Redirect to login page if user authentication fails
31
+ navigateTo({ name: "index" });
32
+ }
33
+ });
34
+ }
35
+
4
36
  async function login({ email = "", password = "", role = "" }) {
5
37
  return useNuxtApp().$api<TKeyValuePair>("/api/auth/login", {
6
38
  method: "POST",
@@ -42,16 +74,39 @@ export default function useLocalAuth() {
42
74
  }
43
75
  }
44
76
 
45
- const currentUser = useState((): TUser | null => null);
77
+ function getById(id: string) {
78
+ return useNuxtApp().$api<TUser>(`/api/users/id/${id}`);
79
+ }
80
+
81
+ const user = useCookie("user", cookieConfig).value ?? "";
82
+
83
+ if (currentUser.value === null) {
84
+ const { data: userData } = useLazyAsyncData("getCurrentUser", async () =>
85
+ useNuxtApp().$api<TUser>(`/api/users/id/${user}`, {
86
+ method: "GET",
87
+ })
88
+ );
89
+
90
+ watchEffect(() => {
91
+ if (userData.value) {
92
+ currentUser.value = userData.value;
93
+ }
94
+ });
95
+ }
46
96
 
47
97
  async function getCurrentUser() {
48
98
  const user = useCookie("user", cookieConfig).value;
49
99
  if (!user) return null;
50
- const _user = await useNuxtApp().$api<TUser>(`/api/users/id/${user}`, {
51
- method: "GET",
52
- });
53
- currentUser.value = _user;
54
- return _user;
100
+ try {
101
+ const _user = await useNuxtApp().$api<TUser>(`/api/users/id/${user}`, {
102
+ method: "GET",
103
+ });
104
+
105
+ currentUser.value = _user;
106
+ return _user;
107
+ } catch (error) {
108
+ console.log("Error fetching current user:", error);
109
+ }
55
110
  }
56
111
 
57
112
  async function forgotPassword(email: string) {
@@ -105,6 +160,7 @@ export default function useLocalAuth() {
105
160
  const permissions = useState("permissions", (): Array<string> => []);
106
161
 
107
162
  return {
163
+ authenticate,
108
164
  login,
109
165
  logout,
110
166
  clearCookies,
@@ -52,7 +52,7 @@ export default function useOrg() {
52
52
  }
53
53
 
54
54
  const perSeatPrice = 300;
55
- const seats = useState("seats", () => 0);
55
+ const seats = useState("seats", () => 1);
56
56
  const total = computed(() => seats.value * perSeatPrice);
57
57
 
58
58
  function getByName(name = "") {