@usssa/component-library 1.0.0-alpha.91 → 1.0.0-alpha.92
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/package.json +1 -1
- package/src/components/core/UMenuSearch.vue +128 -112
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, ref, toRaw, watch } from 'vue'
|
|
3
|
-
import { Notify, SessionStorage } from 'quasar'
|
|
4
3
|
import UAvatar from './UAvatar.vue'
|
|
5
4
|
import UBtnStd from './UBtnStd.vue'
|
|
6
5
|
import UInputTypeaheadAdvanceSearch from './UInputTypeaheadAdvanceSearch.vue'
|
|
7
6
|
import UMenuDropdownAdvancedSearch from './UMenuDropdownAdvancedSearch.vue'
|
|
8
7
|
import UTabBtnStd from './UTabBtnStd.vue'
|
|
9
8
|
import UTooltip from './UTooltip.vue'
|
|
9
|
+
import { useNotify } from '../../composables/useNotify'
|
|
10
10
|
import { parseInitials, categorizeObjects, deepEqual } from '../../utils/data'
|
|
11
11
|
|
|
12
12
|
const props = defineProps({
|
|
@@ -21,11 +21,21 @@ const props = defineProps({
|
|
|
21
21
|
advancedSearchSelectedTab: {
|
|
22
22
|
type: String,
|
|
23
23
|
},
|
|
24
|
+
actionButtonLoading: {
|
|
25
|
+
type: Boolean,
|
|
26
|
+
},
|
|
24
27
|
// Set context for component for special handling
|
|
25
28
|
// context.action (e.g. addContact)
|
|
26
29
|
// context.data (e.g. array of existing contacts)
|
|
27
30
|
context: {
|
|
28
|
-
type:
|
|
31
|
+
type: Array,
|
|
32
|
+
},
|
|
33
|
+
disabledButtonColor: {
|
|
34
|
+
type: String,
|
|
35
|
+
},
|
|
36
|
+
exceedLimitCount: {
|
|
37
|
+
type: Number,
|
|
38
|
+
default: 50,
|
|
29
39
|
},
|
|
30
40
|
fields: {
|
|
31
41
|
type: Array,
|
|
@@ -38,11 +48,6 @@ const props = defineProps({
|
|
|
38
48
|
type: String,
|
|
39
49
|
default: 'fa-kit-duotone fa-filter-search',
|
|
40
50
|
},
|
|
41
|
-
//Number of maximum search result to show
|
|
42
|
-
maxSearchResults: {
|
|
43
|
-
type: Number,
|
|
44
|
-
default: 5,
|
|
45
|
-
},
|
|
46
51
|
menuClass: {
|
|
47
52
|
type: String,
|
|
48
53
|
},
|
|
@@ -52,6 +57,12 @@ const props = defineProps({
|
|
|
52
57
|
options: {
|
|
53
58
|
type: Array,
|
|
54
59
|
},
|
|
60
|
+
recentSearches: {
|
|
61
|
+
type: Array,
|
|
62
|
+
},
|
|
63
|
+
recentSearchesLoading: {
|
|
64
|
+
type: Boolean,
|
|
65
|
+
},
|
|
55
66
|
showCustomMenu: {
|
|
56
67
|
type: Boolean,
|
|
57
68
|
default: false,
|
|
@@ -87,6 +98,9 @@ const props = defineProps({
|
|
|
87
98
|
type: String,
|
|
88
99
|
default: 'Advanced search',
|
|
89
100
|
},
|
|
101
|
+
toolTipDisabledButton: {
|
|
102
|
+
type: String,
|
|
103
|
+
},
|
|
90
104
|
})
|
|
91
105
|
|
|
92
106
|
const emit = defineEmits([
|
|
@@ -98,6 +112,7 @@ const emit = defineEmits([
|
|
|
98
112
|
])
|
|
99
113
|
|
|
100
114
|
const loading = defineModel('loading')
|
|
115
|
+
const { notify } = useNotify()
|
|
101
116
|
|
|
102
117
|
const advancedSearchPendingFilterModel = structuredClone(toRaw(props.model))
|
|
103
118
|
const advancedSearchSelectedTab = ref(props.advancedSearchSelectedTab ?? null)
|
|
@@ -113,11 +128,11 @@ const searchMenuShowing = ref(false)
|
|
|
113
128
|
|
|
114
129
|
const recentSearches = computed({
|
|
115
130
|
get() {
|
|
116
|
-
let arr =
|
|
117
|
-
if (props.context
|
|
131
|
+
let arr = props.recentSearches
|
|
132
|
+
if (props.context) {
|
|
118
133
|
arr = specialContextHandler(arr)
|
|
119
134
|
}
|
|
120
|
-
return arr
|
|
135
|
+
return arr
|
|
121
136
|
},
|
|
122
137
|
set(value) {
|
|
123
138
|
return value
|
|
@@ -173,50 +188,33 @@ const handleTabChange = (val) => {
|
|
|
173
188
|
search()
|
|
174
189
|
}
|
|
175
190
|
|
|
176
|
-
const recentSearchHandler = (item) => {
|
|
177
|
-
let index = recentSearches.value.findIndex((s) => s.id === item.id)
|
|
178
|
-
if (index >= 0) {
|
|
179
|
-
recentSearches.value.splice(index, 1)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (recentSearches.value.length === props.maxSearchResults) {
|
|
183
|
-
recentSearches.value.pop()
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
recentSearches.value.push({
|
|
187
|
-
...item,
|
|
188
|
-
added_to_recent: new Date().valueOf(),
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
recentSearches.value.sort((a, b) => b.added_to_recent - a.added_to_recent)
|
|
192
|
-
|
|
193
|
-
SessionStorage.set('recentSearches', recentSearches.value)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
191
|
const onItemActionClick = (item) => {
|
|
197
|
-
recentSearchHandler(item)
|
|
198
192
|
return emit('onItemActionClick', item, searchMenuRef.value)
|
|
199
193
|
}
|
|
200
194
|
|
|
201
195
|
const specialContextHandler = (results) => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
196
|
+
// Mark result records that are already exits
|
|
197
|
+
results = results.map((result) => {
|
|
198
|
+
const isAlreadyContactSearch = props.context.filter(
|
|
199
|
+
(contact) => contact.id === result.id
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if (isAlreadyContactSearch && isAlreadyContactSearch.length > 0) {
|
|
203
|
+
const tooltip = props.toolTipDisabledButton
|
|
204
|
+
const color = props.disabledButtonColor
|
|
205
|
+
return {
|
|
206
|
+
...result,
|
|
207
|
+
disable: true,
|
|
208
|
+
btnProps: {
|
|
209
|
+
color,
|
|
210
|
+
},
|
|
211
|
+
tooltip,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return result
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
return results
|
|
220
218
|
}
|
|
221
219
|
|
|
222
220
|
const convertDate = (inputDate) => {
|
|
@@ -327,7 +325,7 @@ const search = async () => {
|
|
|
327
325
|
|
|
328
326
|
const res = await props.algoliaIndex.search(props.searchText, configPayload)
|
|
329
327
|
|
|
330
|
-
if (res.hits.length >=
|
|
328
|
+
if (res.hits.length >= props.exceedLimitCount) {
|
|
331
329
|
exceedLimit.value = true
|
|
332
330
|
} else {
|
|
333
331
|
exceedLimit.value = false
|
|
@@ -335,7 +333,7 @@ const search = async () => {
|
|
|
335
333
|
|
|
336
334
|
let results = res.hits
|
|
337
335
|
|
|
338
|
-
if (props.context
|
|
336
|
+
if (props.context) {
|
|
339
337
|
results = specialContextHandler(results)
|
|
340
338
|
}
|
|
341
339
|
|
|
@@ -348,9 +346,10 @@ const search = async () => {
|
|
|
348
346
|
}
|
|
349
347
|
return void 0
|
|
350
348
|
} catch (error) {
|
|
351
|
-
|
|
352
|
-
type: '
|
|
353
|
-
|
|
349
|
+
notify({
|
|
350
|
+
type: 'accent',
|
|
351
|
+
label: 'Search broke',
|
|
352
|
+
position: 'top',
|
|
354
353
|
})
|
|
355
354
|
} finally {
|
|
356
355
|
loading.value = false
|
|
@@ -527,6 +526,7 @@ watch(
|
|
|
527
526
|
:color="item.btnProps?.color ?? 'primary'"
|
|
528
527
|
:disable="item.disable"
|
|
529
528
|
:label="actionButtonLabel"
|
|
529
|
+
:loading="actionButtonLoading"
|
|
530
530
|
outline
|
|
531
531
|
size="sm"
|
|
532
532
|
@click.stop="onItemActionClick(item)"
|
|
@@ -596,56 +596,81 @@ watch(
|
|
|
596
596
|
|
|
597
597
|
<!-- Recently selected list -->
|
|
598
598
|
|
|
599
|
-
<q-list
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
<q-item class="list-item" clickable>
|
|
606
|
-
<q-item-section side>
|
|
607
|
-
<UAvatar
|
|
608
|
-
v-if="
|
|
609
|
-
!item.profilePictureUrl ||
|
|
610
|
-
item.profilePictureUrl?.nullValue === 0
|
|
611
|
-
"
|
|
612
|
-
:aria-label="item.name"
|
|
613
|
-
:name="parseInitials(item.name)"
|
|
614
|
-
size="md"
|
|
615
|
-
/>
|
|
616
|
-
<UAvatar
|
|
617
|
-
v-else
|
|
618
|
-
:aria-label="item.name"
|
|
619
|
-
:image="item.profilePictureUrl"
|
|
620
|
-
:round="true"
|
|
621
|
-
size="md"
|
|
622
|
-
:showIndicator="false"
|
|
623
|
-
/>
|
|
624
|
-
</q-item-section>
|
|
625
|
-
|
|
626
|
-
<q-item-section>
|
|
627
|
-
<q-item-label class="text-caption-md wrapped-text">
|
|
628
|
-
{{ item?.name }}
|
|
629
|
-
</q-item-label>
|
|
630
|
-
<q-item-label
|
|
631
|
-
class="text-body-xs text-neutral-9 label wrapped-text"
|
|
632
|
-
>
|
|
633
|
-
{{ item?.description }}
|
|
634
|
-
</q-item-label>
|
|
635
|
-
</q-item-section>
|
|
599
|
+
<q-list class="search-list q-mt-xs">
|
|
600
|
+
<div
|
|
601
|
+
v-if="showRecentSelected && recentSearchesLoading"
|
|
602
|
+
class="row justify-between items-center"
|
|
603
|
+
>
|
|
604
|
+
<span class="text-overline-xs"> Recently Selected </span>
|
|
636
605
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
606
|
+
<q-spinner
|
|
607
|
+
v-if="recentSearchesLoading"
|
|
608
|
+
color="grey-14"
|
|
609
|
+
size="1rem"
|
|
610
|
+
/>
|
|
611
|
+
</div>
|
|
612
|
+
<div
|
|
613
|
+
v-if="showRecentSelected && recentSearches && recentSearches.length"
|
|
614
|
+
>
|
|
615
|
+
<span class="text-overline-xs"> Recently Selected </span>
|
|
616
|
+
|
|
617
|
+
<template v-for="item in recentSearches" :key="item.id">
|
|
618
|
+
<q-item class="list-item" clickable>
|
|
619
|
+
<q-item-section side>
|
|
620
|
+
<UAvatar
|
|
621
|
+
v-if="
|
|
622
|
+
!item.profilePictureUrl ||
|
|
623
|
+
item.profilePictureUrl?.nullValue === 0
|
|
624
|
+
"
|
|
625
|
+
:aria-label="item.name"
|
|
626
|
+
:name="parseInitials(item.name)"
|
|
627
|
+
size="md"
|
|
628
|
+
/>
|
|
629
|
+
<UAvatar
|
|
630
|
+
v-else
|
|
631
|
+
:aria-label="item.name"
|
|
632
|
+
:image="item.profilePictureUrl"
|
|
633
|
+
:round="true"
|
|
634
|
+
size="md"
|
|
635
|
+
:showIndicator="false"
|
|
636
|
+
/>
|
|
637
|
+
</q-item-section>
|
|
638
|
+
|
|
639
|
+
<q-item-section>
|
|
640
|
+
<q-item-label class="text-caption-md wrapped-text">
|
|
641
|
+
{{ item?.name }}
|
|
642
|
+
</q-item-label>
|
|
643
|
+
<q-item-label
|
|
644
|
+
class="text-body-xs text-neutral-9 label wrapped-text"
|
|
645
|
+
>
|
|
646
|
+
{{ item?.description }}
|
|
647
|
+
</q-item-label>
|
|
648
|
+
</q-item-section>
|
|
649
|
+
|
|
650
|
+
<q-item-section side>
|
|
651
|
+
<UBtnStd
|
|
652
|
+
v-bind="item.btnProps"
|
|
653
|
+
:color="item.btnProps?.color ?? 'primary'"
|
|
654
|
+
:disable="item.disable"
|
|
655
|
+
:label="actionButtonLabel"
|
|
656
|
+
:loading="actionButtonLoading"
|
|
657
|
+
outline
|
|
658
|
+
size="sm"
|
|
659
|
+
@click.stop="onItemActionClick(item)"
|
|
660
|
+
>
|
|
661
|
+
<template v-if="item.tooltip && item.disable" #tooltip>
|
|
662
|
+
<UTooltip
|
|
663
|
+
anchor="top middle"
|
|
664
|
+
:description="item.tooltip"
|
|
665
|
+
:offset="[0, 4]"
|
|
666
|
+
self="bottom middle"
|
|
667
|
+
/>
|
|
668
|
+
</template>
|
|
669
|
+
</UBtnStd>
|
|
670
|
+
</q-item-section>
|
|
671
|
+
</q-item>
|
|
672
|
+
</template>
|
|
673
|
+
</div>
|
|
649
674
|
</q-list>
|
|
650
675
|
</div>
|
|
651
676
|
</q-list>
|
|
@@ -683,14 +708,6 @@ watch(
|
|
|
683
708
|
display: flex
|
|
684
709
|
flex-direction: column
|
|
685
710
|
gap: $xxs
|
|
686
|
-
.searchText-md
|
|
687
|
-
flex: 1
|
|
688
|
-
word-wrap: break-word
|
|
689
|
-
min-width: 18.5rem
|
|
690
|
-
.searchText-sm
|
|
691
|
-
flex: 1
|
|
692
|
-
word-wrap: break-word
|
|
693
|
-
min-width: 16.5rem
|
|
694
711
|
.list-item
|
|
695
712
|
border-radius: $xs
|
|
696
713
|
padding: $xs
|
|
@@ -706,5 +723,4 @@ watch(
|
|
|
706
723
|
white-space: normal
|
|
707
724
|
overflow: hidden
|
|
708
725
|
word-wrap: break-word
|
|
709
|
-
max-width: 18rem
|
|
710
726
|
</style>
|