@iservice365/layer-common 1.4.1 → 1.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1a1f3e0: Virtual patrol initial release
8
+
9
+ ## 1.4.2
10
+
11
+ ### Patch Changes
12
+
13
+ - d71fd3b: Add new services
14
+
3
15
  ## 1.4.1
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <v-row no-gutters>
3
+ <v-col cols="12">
4
+ <v-card
5
+ width="100%"
6
+ variant="outlined"
7
+ border="thin"
8
+ rounded="lg"
9
+ :loading="false"
10
+ >
11
+ <v-toolbar density="compact" color="grey-lighten-4">
12
+ <template #prepend>
13
+ <v-btn fab icon density="comfortable">
14
+ <v-icon>mdi-refresh</v-icon>
15
+ </v-btn>
16
+ </template>
17
+ <template #append>
18
+ <v-row no-gutters justify="end" align="center">
19
+ <span class="mr-2 text-caption text-fontgray">
20
+ {{ pageRange }}
21
+ </span>
22
+ <local-pagination v-model="page" :length="pages" />
23
+ </v-row>
24
+ </template>
25
+ </v-toolbar>
26
+
27
+ <v-data-table
28
+ :headers="headers"
29
+ :items="items"
30
+ item-value="_id"
31
+ items-per-page="20"
32
+ fixed-header
33
+ hide-default-footer
34
+ hide-default-header
35
+ style="max-height: calc(100vh - (180px))"
36
+ >
37
+ <template #item.permissions="{ value }">
38
+ <span class="text-caption font-weight-bold text-capitalize">
39
+ permissions
40
+ </span>
41
+ <v-chip>{{ value.length }}</v-chip>
42
+ </template>
43
+
44
+ <template #item.nature="{ item }">
45
+ <span class="text-capitalize">
46
+ {{ item.nature }}
47
+ </span>
48
+ </template>
49
+ </v-data-table>
50
+ </v-card>
51
+ </v-col>
52
+ </v-row>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ const page = ref(1);
57
+ const pages = ref(0);
58
+ const pageRange = ref("-- - -- of --");
59
+
60
+ const items = ref<Array<Record<string, any>>>([]);
61
+
62
+ const headers = [
63
+ { title: "Name", value: "name" },
64
+ { title: "Nature", value: "nature" },
65
+ ];
66
+ </script>
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <v-card flat border="md black">
3
+ <v-card-text class="d-flex justify-space-between align-center py-0">
4
+ <p>{{ label }}</p>
5
+ <v-switch v-model="toggle" :color="toggleColor" hide-details />
6
+ </v-card-text>
7
+ </v-card>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ defineProps({
12
+ label: {
13
+ type: String,
14
+ default: "Enable"
15
+ },
16
+ toggleColor: {
17
+ type: String,
18
+ default: 'primary'
19
+ }
20
+ })
21
+
22
+ const toggle = defineModel({default: false})
23
+ </script>
24
+
25
+ <style scoped></style>
@@ -13,7 +13,7 @@
13
13
  </template>
14
14
  </v-toolbar>
15
15
 
16
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
16
+ <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0" :class="contentNoPadding ? 'pa-0' : ''">
17
17
  <slot name="content" />
18
18
  </v-card-text>
19
19
 
@@ -90,6 +90,10 @@ const prop = defineProps({
90
90
  type: String,
91
91
  default: "Details",
92
92
  },
93
+ contentNoPadding: {
94
+ type: Boolean,
95
+ default: false,
96
+ },
93
97
  });
94
98
 
95
99
  const emit = defineEmits(["close", "edit", "delete"]);
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <ClientOnly>
3
+ <v-row no-gutters class="ckeditor-container w-100">
4
+ <ckeditor v-model="data" :editor="ClassicEditor" :config="config" />
5
+ </v-row>
6
+ </ClientOnly>
7
+ </template>
8
+
9
+ <script setup>
10
+ import {
11
+ ClassicEditor,
12
+ Essentials,
13
+ Paragraph,
14
+ Bold,
15
+ Italic,
16
+ Heading,
17
+ List,
18
+ Link,
19
+ Alignment,
20
+ Font
21
+ } from 'ckeditor5'
22
+ import { Ckeditor } from '@ckeditor/ckeditor5-vue'
23
+ import 'ckeditor5/ckeditor5.css';
24
+
25
+ import 'ckeditor5/ckeditor5.css'
26
+
27
+ const data = defineModel({ required: true, default: "" })
28
+
29
+ const config = computed(() => ({
30
+ licenseKey: 'GPL',
31
+ plugins: [Essentials, Paragraph, Bold, Italic, Heading, List, Alignment, Font],
32
+ toolbar: [
33
+ 'undo', 'redo',
34
+ '|', 'bold', 'italic',
35
+ '|', 'fontSize', 'fontColor', 'fontBackgroundColor',
36
+ '|', 'bulletedList', 'numberedList',
37
+ '|', 'heading', '|', 'alignment:left', 'alignment:center', 'alignment:right', 'alignment:justify',
38
+ ]
39
+ }))
40
+ </script>
41
+
42
+ <style scoped>
43
+ .ckeditor-container {
44
+ width: 100%;
45
+ max-width: 100% !important;
46
+ overflow: hidden;
47
+ }
48
+
49
+ :deep(.ck.ck-editor) {
50
+ width: 100% !important;
51
+ max-width: 100%;
52
+ box-sizing: border-box;
53
+ }
54
+
55
+ :deep(.ck-editor__editable_inline) {
56
+ min-height: 200px;
57
+ width: 100% !important;
58
+ box-sizing: border-box;
59
+ }
60
+ </style>
61
+
@@ -1,78 +1,73 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
3
  <v-col cols="12" class="mb-2">
4
- <v-row no-gutters>
4
+ <v-row no-gutters align="center" justify="space-between">
5
5
  <v-btn
6
6
  class="text-none text-capitalize"
7
7
  rounded="pill"
8
8
  variant="tonal"
9
- @click="showCreateDialog = true"
10
9
  size="large"
10
+ @click="showCreateDialog = true"
11
11
  v-if="canCreateFeedback"
12
12
  >
13
13
  Create Feedback
14
14
  </v-btn>
15
+
16
+ <v-text-field
17
+ v-model="searchText"
18
+ placeholder="Search feedback..."
19
+ variant="outlined"
20
+ density="comfortable"
21
+ clearable
22
+ hide-details
23
+ class="ml-2"
24
+ style="max-width: 250px"
25
+ />
15
26
  </v-row>
16
27
  </v-col>
17
28
 
18
29
  <v-col cols="12">
19
- <ListView
20
- :headers="headers"
21
- :items="items"
22
- :pages="pages"
23
- :page-range="pageRange"
24
- :loading="loading || onNextPrevPageLoading"
25
- :height="'calc(100vh - 175px)'"
26
- v-model:page="page"
27
- :selected="selected"
28
- @update:value="getAllReqRefresh"
29
- @update:selected="onSelectedUpdate"
30
- @click:create="showCreateDialog = true"
31
- :viewPage="{ name: 'org-site-feedbacks-id' }"
32
- :clickable-rows="true"
33
- :length="pages"
34
- @update:pagination="updatePage"
30
+ <v-card
31
+ width="100%"
32
+ variant="outlined"
33
+ border="thin"
34
+ rounded="lg"
35
+ :loading="loading"
35
36
  >
36
- <template #title>
37
- <span class="text-h6 font-weight-regular">Feedbacks</span>
38
- </template>
39
-
40
- <template #category="{ item }">
41
- <span class="text-capitalize">{{ item.category }}</span>
42
- </template>
43
-
44
- <template #status="{ item }">
45
- <v-chip
46
- :color="getColorStatus(item.status || 'No Status')"
47
- text-color="white"
48
- variant="flat"
49
- >
50
- {{ item.status || "No Status" }}
51
- </v-chip>
52
- </template>
53
-
54
- <template #action-table="{ item }">
55
- <v-menu
56
- v-model="item.menuOpen"
57
- :close-on-content-click="false"
58
- offset-y
59
- width="150"
60
- >
61
- <template v-slot:activator="{ props }">
62
- <v-icon v-bind="props">mdi-dots-horizontal-circle-outline</v-icon>
63
- </template>
64
- <v-list>
65
- <v-list-item @click="onViewFeedback(item)">View</v-list-item>
66
- <v-list-item @click="editFeedback(item)">Edit</v-list-item>
67
- <v-list-item
68
- @click="confirmDeleteFeedback(item)"
69
- v-if="canDeleteFeedback"
70
- >Delete</v-list-item
71
- >
72
- </v-list>
73
- </v-menu>
74
- </template>
75
- </ListView>
37
+ <v-toolbar density="compact" color="grey-lighten-4">
38
+ <template #prepend>
39
+ <v-btn fab icon density="comfortable" @click="updatePage">
40
+ <v-icon>mdi-refresh</v-icon>
41
+ </v-btn>
42
+ </template>
43
+
44
+ <template #append>
45
+ <v-row no-gutters justify="end" align="center">
46
+ <span class="mr-2 text-caption text-fontgray">
47
+ {{ pageRange }}
48
+ </span>
49
+ <local-pagination
50
+ v-model="page"
51
+ :length="pages"
52
+ @update:value="updatePage"
53
+ />
54
+ </v-row>
55
+ </template>
56
+ </v-toolbar>
57
+
58
+ <v-data-table
59
+ :headers="headers"
60
+ :items="items"
61
+ item-value="_id"
62
+ items-per-page="20"
63
+ fixed-header
64
+ hide-default-footer
65
+ hide-default-header
66
+ @click:row="tableRowClickHandler"
67
+ style="max-height: calc(100vh - (200px))"
68
+ >
69
+ </v-data-table>
70
+ </v-card>
76
71
  </v-col>
77
72
  </v-row>
78
73
 
@@ -123,6 +118,82 @@
123
118
  </ConfirmDialog>
124
119
 
125
120
  <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
121
+
122
+ <!-- Preview Dialog -->
123
+ <v-dialog v-model="dialogPreview" width="450" persistent>
124
+ <v-card width="100%">
125
+ <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
126
+ <v-row no-gutters v-if="selectedFeedback" class="mb-4">
127
+ <v-col cols="12">
128
+ <strong>Subject:</strong> {{ selectedFeedback.subject }}
129
+ </v-col>
130
+ <v-col cols="12">
131
+ <strong>Category:</strong>
132
+ {{ selectedFeedback.category }}
133
+ </v-col>
134
+ <v-col cols="12">
135
+ <strong>Status:</strong>
136
+ {{ selectedFeedback.status }}
137
+ </v-col>
138
+ </v-row>
139
+ </v-card-text>
140
+ <v-toolbar class="pa-0" density="compact">
141
+ <v-row no-gutters>
142
+ <v-col cols="6" class="pa-0">
143
+ <v-btn
144
+ block
145
+ variant="text"
146
+ class="text-none"
147
+ size="large"
148
+ @click="dialogPreview = false"
149
+ height="48"
150
+ >
151
+ Close
152
+ </v-btn>
153
+ </v-col>
154
+ <v-col cols="6" class="pa-0">
155
+ <v-menu>
156
+ <template #activator="{ props }">
157
+ <v-btn
158
+ block
159
+ variant="flat"
160
+ color="black"
161
+ class="text-none"
162
+ height="48"
163
+ v-bind="props"
164
+ tile
165
+ >
166
+ More actions
167
+ </v-btn>
168
+ </template>
169
+
170
+ <v-list class="pa-0">
171
+ <v-list-item @click="onViewFeedback(selectedFeedback)">
172
+ <v-list-item-title class="text-subtitle-2">
173
+ View
174
+ </v-list-item-title>
175
+ </v-list-item>
176
+ <v-list-item @click="editFeedback(selectedFeedback)">
177
+ <v-list-item-title class="text-subtitle-2">
178
+ Edit
179
+ </v-list-item-title>
180
+ </v-list-item>
181
+
182
+ <v-list-item
183
+ @click="confirmDeleteFeedback(selectedFeedback)"
184
+ class="text-red"
185
+ >
186
+ <v-list-item-title class="text-subtitle-2">
187
+ Delete
188
+ </v-list-item-title>
189
+ </v-list-item>
190
+ </v-list>
191
+ </v-menu>
192
+ </v-col>
193
+ </v-row>
194
+ </v-toolbar>
195
+ </v-card></v-dialog
196
+ >
126
197
  </template>
127
198
 
128
199
  <script setup lang="ts">
@@ -225,7 +296,7 @@ const selected = ref<string[]>([]);
225
296
 
226
297
  const { getColorStatus } = useUtils();
227
298
 
228
- const headers = [
299
+ const headers: Array<Record<string, any>> = [
229
300
  { title: "Name", value: "createdByName", align: "start" },
230
301
  { title: "Subject", value: "subject", align: "start" },
231
302
  { title: "Category", value: "category", align: "start" },
@@ -311,6 +382,7 @@ async function editFeedback(item: any) {
311
382
  _feedbackId.value = item._id;
312
383
  isEditMode.value = true;
313
384
  showCreateDialog.value = true;
385
+ dialogPreview.value = false;
314
386
  } catch (error) {
315
387
  showMessage("Failed to load full feedback", "error");
316
388
  }
@@ -326,6 +398,7 @@ function onViewFeedback(item: any) {
326
398
  name: props.detailRoute,
327
399
  params: { org, site, id },
328
400
  });
401
+ dialogPreview.value = false;
329
402
  }
330
403
 
331
404
  function confirmDeleteFeedback(item: any) {
@@ -349,6 +422,7 @@ async function submitDelete() {
349
422
  submitting.value = false;
350
423
  showDeleteDialog.value = false;
351
424
  feedbackToDelete.value = null;
425
+ dialogPreview.value = false;
352
426
  }
353
427
  }
354
428
 
@@ -483,5 +557,15 @@ const categories = computed(() =>
483
557
  }))
484
558
  );
485
559
 
560
+ function tableRowClickHandler(_: any, data: any) {
561
+ console.log(data.item);
562
+ selectedFeedback.value = data.item;
563
+ dialogPreview.value = true;
564
+ }
565
+
566
+ const dialogPreview = ref(false);
567
+ const selectedFeedback = ref<TFeedback | null>(null);
568
+ const searchText = ref("")
569
+
486
570
  getServiceProviderCategories();
487
571
  </script>
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <v-dialog v-model="overlay" v-if="overlay" width="100%" height="100%" opacity="50">
3
+ <v-row align="center" justify="center" class="fill-height" style="position: relative;">
4
+ <v-carousel hide-delimiters width="100%" height="100%" :show-arrows="images.length > 1 ? 'hover' : false"
5
+ v-model="activeIndex">
6
+ <template v-for="x, index in images" :key="x._id">
7
+ <v-carousel-item height="100%" width="100%" rounded="lg">
8
+ <v-row no-gutters class="w-100 h-100" align="center">
9
+ <v-img :lazy-src="getFileUrl(x)" :src="getFileUrl(x)" width="70%" height="70%" :alt="'Image Viewer Card -' + index"></v-img>
10
+ </v-row>
11
+ <template v-slot:placeholder>
12
+ <div class="d-flex align-center justify-center fill-height">
13
+ <v-progress-circular color="grey-lighten-4" indeterminate></v-progress-circular>
14
+ </div>
15
+ </template>
16
+ </v-carousel-item>
17
+ </template>
18
+
19
+ <template v-slot:prev="{ props }">
20
+ <v-btn color="white" variant="outlined" class="text-white" icon="mdi-chevron-left"
21
+ @click="props.onClick"></v-btn>
22
+ </template>
23
+ <template v-slot:next="{ props }">
24
+ <v-btn color="white" class="text-white" variant="outlined" icon="mdi-chevron-right"
25
+ @click="props.onClick"></v-btn>
26
+ </template>
27
+ </v-carousel>
28
+ <div style="position: absolute; top: 2%; left: 0%; right: 0%; z-index: 2"
29
+ class="cursor-pointer text-white text-h6 custom-shadow d-flex justify-space-between" @click="overlay = false">
30
+ <v-row no-gutters style="position: relative">
31
+ <v-col cols="8" xs="6" sm="2" md="2" lg="2">
32
+ <v-btn prepend-icon="mdi-close" text="Close" rounded="lg" color="secondary" class="ml-2"
33
+ style="position: absolute;"></v-btn>
34
+ </v-col>
35
+
36
+ </v-row>
37
+
38
+ </div>
39
+ <span class="text-white text-16px d-flex w-100 mt-2 justify-center" style="position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);">{{ `${activeIndex + 1}/${images.length}`
40
+ }}</span>
41
+
42
+ </v-row>
43
+ </v-dialog>
44
+ </template>
45
+
46
+ <script setup lang="ts">
47
+ const props = defineProps({
48
+ activeImageId: {
49
+ type: String,
50
+ required: false,
51
+ },
52
+ isFavorite: {
53
+ type: Boolean,
54
+ default: false,
55
+ required: false
56
+ },
57
+ images: {
58
+ type: Array as PropType<string[]>,
59
+ default: []
60
+ }
61
+ });
62
+
63
+
64
+ const { getFileUrl } = useFile()
65
+ const overlay = defineModel({ required: true, default: false });
66
+ const activeIndex = ref(0);
67
+ const { currentUser} = useLocalAuth();
68
+
69
+ const emit = defineEmits(['share', 'like'])
70
+
71
+ watchEffect(() => {
72
+ if (props.activeImageId && props.images.length > 0) {
73
+ const index =
74
+ props.images?.findIndex((x) => x == props.activeImageId) || 0;
75
+ if (index !== -1) {
76
+ activeIndex.value = index;
77
+ } else activeIndex.value = 0;
78
+ } else {
79
+ return (activeIndex.value = 0);
80
+ }
81
+ });
82
+
83
+
84
+ const handleShare = () => {
85
+ overlay.value = false;
86
+ emit('share')
87
+ }
88
+
89
+ const handleLike = () => {
90
+ emit('like')
91
+ }
92
+ </script>
93
+
94
+ <style scoped>
95
+ .custom-shadow {
96
+ text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.8);
97
+ }
98
+ </style>