@iservice365/layer-common 0.1.0 → 0.2.1

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.
Files changed (93) hide show
  1. package/.playground/app.vue +7 -2
  2. package/.playground/pages/feedback.vue +30 -0
  3. package/CHANGELOG.md +12 -0
  4. package/components/Chat/Bubbles.vue +53 -0
  5. package/components/Chat/Information.vue +187 -0
  6. package/components/Chat/ListCard.vue +62 -0
  7. package/components/Chat/Message.vue +149 -0
  8. package/components/Chat/Navigation.vue +150 -0
  9. package/components/ConfirmDialog.vue +66 -0
  10. package/components/Container/Standard.vue +33 -0
  11. package/components/Feedback/Form.vue +136 -0
  12. package/components/FeedbackDetail.vue +465 -0
  13. package/components/FeedbackMain.vue +454 -0
  14. package/components/FormDialog.vue +65 -0
  15. package/components/Input/File.vue +203 -0
  16. package/components/Input/ListGroupSelection.vue +96 -0
  17. package/components/Input/NewDate.vue +123 -0
  18. package/components/Input/Number.vue +124 -0
  19. package/components/InvitationMain.vue +284 -0
  20. package/components/Layout/Header.vue +14 -4
  21. package/components/ListView.vue +87 -0
  22. package/components/MemberMain.vue +459 -0
  23. package/components/RolePermissionFormCreate.vue +161 -0
  24. package/components/RolePermissionFormPreviewUpdate.vue +183 -0
  25. package/components/RolePermissionMain.vue +361 -0
  26. package/components/ServiceProviderFormCreate.vue +154 -0
  27. package/components/ServiceProviderMain.vue +195 -0
  28. package/components/SignaturePad.vue +73 -0
  29. package/components/SpecificAttr.vue +53 -0
  30. package/components/SwitchContext.vue +26 -5
  31. package/components/TableList.vue +150 -0
  32. package/components/TableListSecondary.vue +164 -0
  33. package/components/WorkOrder/Create.vue +197 -0
  34. package/components/WorkOrder/ListView.vue +96 -0
  35. package/components/WorkOrder/Main.vue +308 -0
  36. package/components/Workorder.vue +1 -0
  37. package/composables/useAddress.ts +107 -0
  38. package/composables/useCommonPermission.ts +130 -0
  39. package/composables/useCustomer.ts +113 -0
  40. package/composables/useFeedback.ts +117 -0
  41. package/composables/useFile.ts +40 -0
  42. package/composables/useInvoice.ts +18 -0
  43. package/composables/useLocal.ts +24 -4
  44. package/composables/useLocalAuth.ts +62 -20
  45. package/composables/useLocalSetup.ts +13 -0
  46. package/composables/useMember.ts +111 -0
  47. package/composables/useOrg.ts +76 -92
  48. package/composables/usePaymentMethod.ts +101 -0
  49. package/composables/usePrice.ts +15 -0
  50. package/composables/usePromoCode.ts +36 -0
  51. package/composables/useRole.ts +38 -7
  52. package/composables/useServiceProvider.ts +218 -0
  53. package/composables/useSite.ts +108 -0
  54. package/composables/useSubscription.ts +149 -0
  55. package/composables/useUser.ts +38 -14
  56. package/composables/useUtils.ts +218 -6
  57. package/composables/useVerification.ts +33 -0
  58. package/composables/useWorkOrder.ts +68 -0
  59. package/middleware/01.auth.ts +11 -0
  60. package/middleware/02.org.ts +18 -0
  61. package/middleware/03.customer.ts +13 -0
  62. package/middleware/member.ts +4 -0
  63. package/nuxt.config.ts +3 -1
  64. package/package.json +7 -3
  65. package/pages/index.vue +3 -0
  66. package/pages/payment-method-linked.vue +31 -0
  67. package/pages/require-customer.vue +56 -0
  68. package/pages/require-organization-membership.vue +47 -0
  69. package/pages/unauthorized.vue +29 -0
  70. package/plugins/API.ts +2 -25
  71. package/plugins/iconify.client.ts +5 -0
  72. package/plugins/secure-member.client.ts +54 -0
  73. package/plugins/vuetify.ts +2 -0
  74. package/public/bg-camera.jpg +0 -0
  75. package/public/bg-city.jpg +0 -0
  76. package/public/bg-condo.jpg +0 -0
  77. package/public/images/icons/delete-icon.png +0 -0
  78. package/public/sprite.svg +1 -0
  79. package/types/address.d.ts +13 -0
  80. package/types/customer.d.ts +15 -0
  81. package/types/feedback.d.ts +63 -0
  82. package/types/local.d.ts +47 -38
  83. package/types/member.d.ts +21 -0
  84. package/types/org.d.ts +13 -0
  85. package/types/permission.d.ts +1 -0
  86. package/types/price.d.ts +17 -0
  87. package/types/promo-code.d.ts +19 -0
  88. package/types/service-provider.d.ts +15 -0
  89. package/types/site.d.ts +13 -0
  90. package/types/subscription.d.ts +23 -0
  91. package/types/user.d.ts +19 -0
  92. package/types/verification.d.ts +20 -0
  93. package/types/work-order.d.ts +40 -0
@@ -0,0 +1,197 @@
1
+ <template>
2
+ <FormDialog v-model="dialog" @close="closeDialog">
3
+ <template #title>
4
+ <span class="text-h6 font-weight-medium pt-1 text-capitalize">
5
+ {{ isEditMode ? "Edit Work Order" : "Create Work Order" }}
6
+ </span>
7
+ </template>
8
+
9
+ <InputFile
10
+ :attachments="displayedAttachments"
11
+ :errored-images="localErroredImages"
12
+ :max-files="maxFiles"
13
+ @add="handleFileAdded"
14
+ @delete="deleteFile"
15
+ @errored="onImageError"
16
+ />
17
+
18
+ <v-text-field
19
+ label="Subject"
20
+ variant="outlined"
21
+ density="compact"
22
+ v-model="localWorkOrder.subject"
23
+ class="mb-1"
24
+ dense
25
+ />
26
+
27
+ <v-autocomplete
28
+ v-model="localWorkOrder.category"
29
+ :items="categories"
30
+ item-title="title"
31
+ item-value="value"
32
+ item-props
33
+ label="Category"
34
+ variant="outlined"
35
+ density="compact"
36
+ class="mb-2"
37
+ clearable
38
+ />
39
+
40
+ <v-checkbox
41
+ v-model="localWorkOrder.highPriority"
42
+ density="compact"
43
+ class="ma-0"
44
+ >
45
+ <template #label>
46
+ <span class="text-caption">
47
+ Set work order as High Priority (Optional)
48
+ </span>
49
+ </template>
50
+ </v-checkbox>
51
+
52
+ <v-autocomplete
53
+ label="Block"
54
+ variant="outlined"
55
+ density="compact"
56
+ v-model="localWorkOrder.block"
57
+ :items="blocks"
58
+ class="mt-1"
59
+ clearable
60
+ />
61
+
62
+ <v-autocomplete
63
+ label="Level"
64
+ variant="outlined"
65
+ density="compact"
66
+ v-model="localWorkOrder.level"
67
+ :items="levels"
68
+ class="mt-1"
69
+ clearable
70
+ />
71
+
72
+ <v-autocomplete
73
+ label="Unit"
74
+ variant="outlined"
75
+ density="compact"
76
+ v-model="localWorkOrder.unit"
77
+ :items="units"
78
+ class="mt-1"
79
+ clearable
80
+ />
81
+
82
+ <v-text-field
83
+ label="Specific Location"
84
+ variant="outlined"
85
+ density="compact"
86
+ v-model="localWorkOrder.location"
87
+ class="mt-1"
88
+ dense
89
+ />
90
+
91
+ <v-textarea
92
+ label="Work Order Description"
93
+ variant="outlined"
94
+ density="compact"
95
+ v-model="localWorkOrder.description"
96
+ class="mt-1"
97
+ rows="4"
98
+ clearable
99
+ auto-grow
100
+ />
101
+
102
+ <template #footer>
103
+ <v-btn
104
+ color="primary-button"
105
+ class="text-capitalize mb-4"
106
+ block
107
+ height="40"
108
+ :loading="loading"
109
+ @click="submitWorkOrder"
110
+ >
111
+ Submit
112
+ </v-btn>
113
+ </template>
114
+ </FormDialog>
115
+ </template>
116
+
117
+ <script setup lang="ts">
118
+ const props = defineProps<{
119
+ modelValue: boolean;
120
+ workOrder: TWorkOrderCreate & { specificLocation?: string };
121
+ isEditMode: boolean;
122
+ loading: boolean;
123
+ categories: { title: string; value: string }[];
124
+ erroredImages?: string[];
125
+ maxFiles?: number;
126
+ blocks?: string[];
127
+ levels?: string[];
128
+ units?: string[];
129
+ specificLocations?: string[];
130
+ }>();
131
+
132
+ const emit = defineEmits<{
133
+ (e: "update:modelValue", value: boolean): void;
134
+ (e: "update:workOrder", value: TWorkOrderCreate): void;
135
+ (e: "close"): void;
136
+ (e: "submit", payload: TWorkOrderCreate): void;
137
+ (e: "fileAdded", file: File): void;
138
+ (e: "fileDeleted", url: string): void;
139
+ }>();
140
+
141
+ const dialog = computed({
142
+ get: () => props.modelValue,
143
+ set: (val) => emit("update:modelValue", val),
144
+ });
145
+
146
+ const localWorkOrder = computed({
147
+ get: () => props.workOrder,
148
+ set: (val) => emit("update:workOrder", val),
149
+ });
150
+
151
+ const localErroredImages = ref<string[]>(props.erroredImages || []);
152
+
153
+ watch(
154
+ () => props.erroredImages,
155
+ (val) => {
156
+ if (val) localErroredImages.value = val;
157
+ }
158
+ );
159
+
160
+ const displayedAttachments = computed(() => {
161
+ return localWorkOrder.value.attachments || [];
162
+ });
163
+
164
+ function handleFileAdded(file: File) {
165
+ emit("fileAdded", file);
166
+ }
167
+
168
+ function deleteFile(url: string) {
169
+ emit("fileDeleted", url);
170
+ }
171
+
172
+ function onImageError(file: string) {
173
+ if (!localErroredImages.value.includes(file)) {
174
+ localErroredImages.value.push(file);
175
+ }
176
+ }
177
+
178
+ function closeDialog() {
179
+ dialog.value = false;
180
+ emit("close");
181
+ }
182
+
183
+ function submitWorkOrder() {
184
+ emit("submit", { ...localWorkOrder.value });
185
+ }
186
+
187
+ // expose location fields as fallback empty arrays if not passed
188
+ // const blocks = computed(() => props.blocks || []);
189
+ // const levels = computed(() => props.levels || []);
190
+ // const units = computed(() => props.units || []);
191
+
192
+ const blocks = computed(() => ["Block A", "Block B", ...(props.blocks || [])]);
193
+ const levels = computed(() => ["Level 1", "Level 2", ...(props.levels || [])]);
194
+ const units = computed(() => ["Unit 101", "Unit 102", ...(props.units || [])]);
195
+
196
+ const specificLocations = computed(() => props.specificLocations || []);
197
+ </script>
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <TableListSecondary
3
+ :headers="headers"
4
+ :items="workOrders"
5
+ :pages="pages"
6
+ :page-range="pageRange"
7
+ :loading="loading"
8
+ :height="'calc(100vh - 177px)'"
9
+ v-model:page="page"
10
+ v-model="selected"
11
+ @update:pagination="_getWorkOrders"
12
+ @row-click="handleRowClick"
13
+ @click:create="emit('click:create')"
14
+ :length="pages"
15
+ >
16
+ <template #title>
17
+ <span class="text-h6 font-weight-regular">Work Order</span>
18
+ </template>
19
+ <template #action-button>
20
+ <v-btn
21
+ color="primary-button"
22
+ variant="flat"
23
+ class="ml-4 text-capitalize"
24
+ @click="emit('click:create')"
25
+ >
26
+ Work Order
27
+ </v-btn>
28
+ </template>
29
+
30
+ <template #createdAt="{ item }">
31
+ {{
32
+ new Date(item.createdAt).toLocaleString("en-GB", {
33
+ day: "2-digit",
34
+ month: "2-digit",
35
+ year: "numeric",
36
+ hour: "2-digit",
37
+ minute: "2-digit",
38
+ hour12: false,
39
+ })
40
+ }}
41
+ </template>
42
+
43
+ <template #status="{ item }">
44
+ <v-chip
45
+ :color="getColorStatus(item.status || 'No Status')"
46
+ text-color="white"
47
+ variant="flat"
48
+ >
49
+ {{ item.status || "No Status" }}
50
+ </v-chip>
51
+ </template>
52
+ </TableListSecondary>
53
+ </template>
54
+
55
+ <script lang="ts" setup>
56
+ const emit = defineEmits(["click:create", "update:pagination"]);
57
+
58
+ const { page, pages, pageRange, workOrders, getWorkOrders } = useWorkOrder();
59
+ const { getColorStatus } = useUtils();
60
+
61
+ const message = ref("");
62
+ const messageColor = ref("");
63
+ const messageSnackbar = ref(false);
64
+ const loading = ref(false);
65
+ const height = ref("500px");
66
+ const selected = ref<string[]>([]);
67
+
68
+ const headers = ref([
69
+ { title: "Created By", value: "createdByName" },
70
+ { title: "Subject", value: "subject" },
71
+ { title: "Category", value: "application" },
72
+ { title: "Status", value: "status" },
73
+ { title: "Date", value: "createdAt" },
74
+ ]);
75
+
76
+ async function _getWorkOrders() {
77
+ loading.value = true;
78
+
79
+ try {
80
+ await getWorkOrders({
81
+ page: page.value,
82
+ });
83
+
84
+ emit("update:pagination", {
85
+ page: page.value,
86
+ pages: pages.value,
87
+ });
88
+ } catch (error) {
89
+ console.error("Error fetching feedbacks:", error);
90
+ } finally {
91
+ loading.value = false;
92
+ }
93
+ }
94
+
95
+ _getWorkOrders();
96
+ </script>
@@ -0,0 +1,308 @@
1
+ <template>
2
+ <v-row align="start" justify="center" class="fill-height">
3
+ <v-col cols="12" lg="11" md="10">
4
+ <ListView
5
+ :headers="headers"
6
+ :items="items"
7
+ :pages="pages"
8
+ :page-range="pageRange"
9
+ :loading="loading"
10
+ :height="'calc(100vh - 175px)'"
11
+ v-model:page="page"
12
+ :selected="selected"
13
+ @update:value="getAllReqRefresh"
14
+ @update:selected="onSelectedUpdate"
15
+ @click:create="showCreateDialog = true"
16
+ :length="pages"
17
+ >
18
+ <template #title>
19
+ <span class="text-h6 font-weight-regular">Work Orders</span>
20
+ </template>
21
+
22
+ <template #action-button>
23
+ <v-btn
24
+ color="primary-button"
25
+ variant="flat"
26
+ @click="showCreateDialog = true"
27
+ class="text-capitalize"
28
+ >
29
+ Work Order
30
+ </v-btn>
31
+ </template>
32
+
33
+ <template #category="{ item }">
34
+ <span class="text-capitalize">{{ item.category }}</span>
35
+ </template>
36
+
37
+ <template #createdAt="{ item }">
38
+ {{ formatDate(item.createdAt) }}
39
+ </template>
40
+
41
+ <template #status="{ item }">
42
+ <v-chip
43
+ :color="getColorStatus(item.status || 'No Status')"
44
+ text-color="white"
45
+ variant="flat"
46
+ >
47
+ {{ item.status || "No Status" }}
48
+ </v-chip>
49
+ </template>
50
+ </ListView>
51
+ </v-col>
52
+ </v-row>
53
+
54
+ <WorkOrderCreate
55
+ v-model="showCreateDialog"
56
+ :work-order="_workOrder"
57
+ @update:work-order="(val: TWorkOrderCreate) => (_workOrder = val)"
58
+ :is-edit-mode="isEditMode"
59
+ :loading="isSubmitting"
60
+ :categories="serviceProviders"
61
+ :theme="theme"
62
+ :errored-images="erroredImages"
63
+ :max-files="5"
64
+ :message-fn="showMessage"
65
+ @close="handleCloseDialog"
66
+ @file-added="handleFileAdded"
67
+ @file-deleted="deleteFile"
68
+ @submit="submitWorkOrder"
69
+ />
70
+
71
+ <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
72
+ </template>
73
+
74
+ <script setup lang="ts">
75
+ import { useTheme } from "vuetify";
76
+ const emit = defineEmits(["click:create", "update:pagination"]);
77
+
78
+ defineProps({
79
+ detailRoute: {
80
+ type: String,
81
+ default: "index",
82
+ },
83
+ orgId: {
84
+ type: String,
85
+ default: "",
86
+ },
87
+ customerId: {
88
+ type: String,
89
+ default: "",
90
+ },
91
+ siteId: {
92
+ type: String,
93
+ default: "",
94
+ },
95
+ canCreateWorkOrder: {
96
+ type: Boolean,
97
+ default: false,
98
+ },
99
+ canViewWorkOrders: {
100
+ type: Boolean,
101
+ default: false,
102
+ },
103
+ canViewWorkOrderDetails: {
104
+ type: Boolean,
105
+ default: false,
106
+ },
107
+ canDeleteWorkOrder: {
108
+ type: Boolean,
109
+ default: false,
110
+ },
111
+ });
112
+
113
+ const theme = useTheme().name;
114
+ const showCreateDialog = ref(false);
115
+ const isEditMode = ref(false);
116
+ const erroredImages = ref<string[]>([]);
117
+
118
+ const message = ref("");
119
+ const messageColor = ref("");
120
+ const messageSnackbar = ref(false);
121
+
122
+ const { getColorStatus, formatDate } = useUtils();
123
+
124
+ const _workOrder = ref<TWorkOrderCreate>({
125
+ attachments: [],
126
+ category: "",
127
+ subject: "",
128
+ location: "",
129
+ description: "",
130
+ highPriority: false,
131
+ block: "",
132
+ level: "",
133
+ unit: "",
134
+ serviceProvider: "",
135
+ assignee: "",
136
+ organization: "",
137
+ site: "",
138
+ });
139
+
140
+ function showMessage(msg: string, color: string) {
141
+ message.value = msg;
142
+ messageColor.value = color;
143
+ messageSnackbar.value = true;
144
+ }
145
+
146
+ const headers = [
147
+ { title: "Created By", value: "createdByName", align: "start" },
148
+ { title: "Subject", value: "subject", align: "start" },
149
+ { title: "Category", value: "category", align: "start" },
150
+ { title: "Date", value: "createdAt", align: "start" },
151
+ { title: "Status", value: "status", align: "start" },
152
+ ];
153
+
154
+ const submitting = ref(false);
155
+ const selected = ref<string[]>([]);
156
+ const route = useRoute();
157
+ const { customers } = useCustomer();
158
+
159
+ const { getWorkOrders: _getWorkOrders, createWorkOrder } = useWorkOrder();
160
+
161
+ const page = ref(1);
162
+ const pages = ref(0);
163
+ const pageRange = ref("-- - -- of --");
164
+ const items = ref<Array<Record<string, any>>>([]);
165
+
166
+ const {
167
+ data: getAllWorkOrderReq,
168
+ refresh: getAllReqRefresh,
169
+ status: getAllReqStatus,
170
+ } = useLazyAsyncData("get-all-work-orders", () =>
171
+ _getWorkOrders({
172
+ page: page.value,
173
+ organization: route.params.org as string,
174
+ site: route.params.site as string,
175
+ })
176
+ );
177
+
178
+ const loading = computed(() => getAllReqStatus.value === "pending");
179
+
180
+ watchEffect(() => {
181
+ if (getAllWorkOrderReq.value) {
182
+ items.value = getAllWorkOrderReq.value.items;
183
+ pages.value = getAllWorkOrderReq.value.pages;
184
+ pageRange.value = getAllWorkOrderReq.value.pageRange;
185
+ }
186
+ });
187
+ function onSelectedUpdate(newSelected: string[]) {
188
+ selected.value = newSelected;
189
+ }
190
+
191
+ function handleRowClick(row: any) {
192
+ const org = useRoute().params.org || "defaultOrg";
193
+ const site = useRoute().params.site || "defaultSite";
194
+ const id = row._id;
195
+ useRouter().push({
196
+ name: "work-order-details",
197
+ params: {
198
+ org,
199
+ site,
200
+ id,
201
+ },
202
+ });
203
+ }
204
+
205
+ function resetWorkOrderForm() {
206
+ _workOrder.value = {
207
+ attachments: [],
208
+ category: "",
209
+ subject: "",
210
+ location: "",
211
+ description: "",
212
+ highPriority: false,
213
+ block: "",
214
+ level: "",
215
+ unit: "",
216
+ serviceProvider: "",
217
+ assignee: "",
218
+ organization: "",
219
+ site: "",
220
+ };
221
+ }
222
+
223
+ function handleCloseDialog() {
224
+ resetWorkOrderForm();
225
+ isEditMode.value = false;
226
+ showCreateDialog.value = false;
227
+ }
228
+
229
+ const serviceProviders = ref<
230
+ Array<{ title: string; value: string; subtitle: string }>
231
+ >([]);
232
+ const { getAll: getAllServiceProvider } = useServiceProvider();
233
+
234
+ const { data: getAllReq } = useLazyAsyncData("get-all-service-providers", () =>
235
+ getAllServiceProvider({
236
+ siteId: useRoute().params.site as string,
237
+ })
238
+ );
239
+
240
+ watchEffect(() => {
241
+ if (getAllReq.value) {
242
+ serviceProviders.value = getAllReq.value.items.map((i: any) => ({
243
+ title: i.nature.replace(/_/g, " "),
244
+ value: i.serviceProviderOrgId,
245
+ subtitle: i.name,
246
+ }));
247
+ }
248
+ });
249
+
250
+ const { addFile, deleteFile: _deleteFile } = useFile();
251
+
252
+ const API_DO_STORAGE_ENDPOINT =
253
+ useRuntimeConfig().public.API_DO_STORAGE_ENDPOINT;
254
+
255
+ async function handleFileAdded(file: File) {
256
+ try {
257
+ const res = await addFile(file);
258
+ const uploadedId = res?.id;
259
+ if (uploadedId) {
260
+ const url = `${API_DO_STORAGE_ENDPOINT}/${uploadedId}`;
261
+ _workOrder.value.attachments = _workOrder.value.attachments ?? [];
262
+ _workOrder.value.attachments.push(url);
263
+ }
264
+ } catch (error) {
265
+ console.error("Error uploading file:", error);
266
+ showMessage("Failed to upload file", "error");
267
+ }
268
+ }
269
+
270
+ async function deleteFile(value: string) {
271
+ try {
272
+ await _deleteFile(value);
273
+ _workOrder.value.attachments = (_workOrder.value.attachments ?? []).filter(
274
+ (file) => file !== value
275
+ );
276
+ } catch (error) {
277
+ console.log(error);
278
+ showMessage("Failed to delete file", "error");
279
+ }
280
+ }
281
+
282
+ const _workOrderId = ref<string | null>(null);
283
+
284
+ const isSubmitting = ref(false);
285
+
286
+ async function submitWorkOrder() {
287
+ try {
288
+ isSubmitting.value = true;
289
+
290
+ const payload = {
291
+ ..._workOrder.value,
292
+ organization: route.params.org as string,
293
+ site: route.params.site as string,
294
+ };
295
+
296
+ const res = await createWorkOrder(payload);
297
+
298
+ showMessage(res.message, "success");
299
+ showCreateDialog.value = false;
300
+ resetWorkOrderForm();
301
+ getAllReqRefresh();
302
+ } catch (err) {
303
+ showMessage((err as Error).message, "error");
304
+ } finally {
305
+ isSubmitting.value = false;
306
+ }
307
+ }
308
+ </script>
@@ -0,0 +1 @@
1
+ <template><PlaceholderComponent /></template>
@@ -0,0 +1,107 @@
1
+ export default function useAddress() {
2
+ function add({
3
+ type = "",
4
+ user = "",
5
+ org = "",
6
+ country = "",
7
+ countryCode = "",
8
+ phoneNumber = "",
9
+ address = "",
10
+ continuedAddress = "",
11
+ city = "",
12
+ province = "",
13
+ postalCode = "",
14
+ taxId = "",
15
+ } = {}) {
16
+ return useNuxtApp().$api("/api/addresses", {
17
+ method: "POST",
18
+ body: {
19
+ type,
20
+ user,
21
+ org,
22
+ country,
23
+ countryCode,
24
+ phoneNumber,
25
+ address,
26
+ continuedAddress,
27
+ city,
28
+ province,
29
+ postalCode,
30
+ taxId,
31
+ },
32
+ });
33
+ }
34
+
35
+ function getByUserId(user = "") {
36
+ return useNuxtApp().$api<TAddress>(`/api/addresses/user/${user}`);
37
+ }
38
+
39
+ const _address = useState("address", (): TAddress => {
40
+ return {
41
+ type: "",
42
+ user: "",
43
+ org: "",
44
+ country: "",
45
+ address: "",
46
+ continuedAddress: "",
47
+ city: "",
48
+ province: "",
49
+ postalCode: "",
50
+ taxId: "",
51
+ };
52
+ });
53
+
54
+ function reset() {
55
+ _address.value.type = "";
56
+ _address.value.user = "";
57
+ _address.value.org = "";
58
+ _address.value.country = "";
59
+ _address.value.address = "";
60
+ _address.value.continuedAddress = "";
61
+ _address.value.city = "";
62
+ _address.value.province = "";
63
+ _address.value.postalCode = "";
64
+ _address.value.taxId = "";
65
+ }
66
+
67
+ function set({
68
+ type = "",
69
+ user = "",
70
+ org = "",
71
+ country = "",
72
+ address = "",
73
+ continuedAddress = "",
74
+ city = "",
75
+ province = "",
76
+ postalCode = "",
77
+ taxId = "",
78
+ } = {}) {
79
+ _address.value.type = type;
80
+ _address.value.user = user;
81
+ _address.value.org = org;
82
+ _address.value.country = country;
83
+ _address.value.address = address;
84
+ _address.value.continuedAddress = continuedAddress;
85
+ _address.value.city = city;
86
+ _address.value.province = province;
87
+ _address.value.postalCode = postalCode;
88
+ _address.value.taxId = taxId;
89
+ }
90
+
91
+ const { address, city, province, postalCode, country } = _address.value;
92
+
93
+ const completeAddress = computed(() => {
94
+ return `${address ? `${address}, ` : ""}${
95
+ city ? `${city}, ` : ""
96
+ } ${province} ${postalCode ? `${postalCode}, ` : ""} ${country}`;
97
+ });
98
+
99
+ return {
100
+ add,
101
+ reset,
102
+ set,
103
+ getByUserId,
104
+ address: _address,
105
+ completeAddress,
106
+ };
107
+ }