@usssa/component-library 1.0.0-alpha.91 → 1.0.0-alpha.93

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usssa/component-library",
3
- "version": "1.0.0-alpha.91",
3
+ "version": "1.0.0-alpha.93",
4
4
  "description": "A Quasar component library project",
5
5
  "productName": "Quasar component library App",
6
6
  "author": "Troy Moreland <troy.moreland@usssa.com>",
@@ -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: Object,
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 = SessionStorage.getItem('recentSearches') ?? []
117
- if (props.context && props.context.action) {
131
+ let arr = props.recentSearches
132
+ if (props.context) {
118
133
  arr = specialContextHandler(arr)
119
134
  }
120
- return arr.sort((a, b) => b.added_to_recent - a.added_to_recent)
135
+ return arr
121
136
  },
122
137
  set(value) {
123
138
  return value
@@ -173,50 +188,38 @@ 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
- }
191
+ const onItemActionClick = (item, isRecentSearchAction) => {
192
+ return emit(
193
+ 'onItemActionClick',
194
+ item,
195
+ isRecentSearchAction,
196
+ searchMenuRef.value
197
+ )
198
+ }
181
199
 
182
- if (recentSearches.value.length === props.maxSearchResults) {
183
- recentSearches.value.pop()
184
- }
200
+ const specialContextHandler = (results) => {
201
+ // Mark result records that are already exits
202
+ results = results.map((result) => {
203
+ const isAlreadyContactSearch = props.context.filter(
204
+ (contact) => contact.id === result.id
205
+ )
185
206
 
186
- recentSearches.value.push({
187
- ...item,
188
- added_to_recent: new Date().valueOf(),
207
+ if (isAlreadyContactSearch && isAlreadyContactSearch.length > 0) {
208
+ const tooltip = props.toolTipDisabledButton
209
+ const color = props.disabledButtonColor
210
+ return {
211
+ ...result,
212
+ disable: true,
213
+ btnProps: {
214
+ color,
215
+ },
216
+ tooltip,
217
+ }
218
+ }
219
+ return result
189
220
  })
190
221
 
191
- recentSearches.value.sort((a, b) => b.added_to_recent - a.added_to_recent)
192
-
193
- SessionStorage.set('recentSearches', recentSearches.value)
194
- }
195
-
196
- const onItemActionClick = (item) => {
197
- recentSearchHandler(item)
198
- return emit('onItemActionClick', item, searchMenuRef.value)
199
- }
200
-
201
- const specialContextHandler = (results) => {
202
- switch (props.context.action) {
203
- case 'addContact':
204
- // Mark result records that are already contacts
205
- results = results.map((result) => {
206
- const isAlreadyContactSearch = props.context.data.filter(
207
- (contact) => contact.userId === result.id
208
- )
209
- if (isAlreadyContactSearch && isAlreadyContactSearch.length > 0) {
210
- return {
211
- ...result,
212
- disable: true,
213
- tooltip: 'Person is already a contact',
214
- }
215
- }
216
- return result
217
- })
218
- return results
219
- }
222
+ return results
220
223
  }
221
224
 
222
225
  const convertDate = (inputDate) => {
@@ -327,7 +330,7 @@ const search = async () => {
327
330
 
328
331
  const res = await props.algoliaIndex.search(props.searchText, configPayload)
329
332
 
330
- if (res.hits.length >= 50) {
333
+ if (res.hits.length >= props.exceedLimitCount) {
331
334
  exceedLimit.value = true
332
335
  } else {
333
336
  exceedLimit.value = false
@@ -335,7 +338,7 @@ const search = async () => {
335
338
 
336
339
  let results = res.hits
337
340
 
338
- if (props.context && data.context.action) {
341
+ if (props.context) {
339
342
  results = specialContextHandler(results)
340
343
  }
341
344
 
@@ -348,9 +351,10 @@ const search = async () => {
348
351
  }
349
352
  return void 0
350
353
  } catch (error) {
351
- Notify.create({
352
- type: 'error',
353
- message: 'Search broke',
354
+ notify({
355
+ type: 'accent',
356
+ label: 'Search broke',
357
+ position: 'top',
354
358
  })
355
359
  } finally {
356
360
  loading.value = false
@@ -527,6 +531,7 @@ watch(
527
531
  :color="item.btnProps?.color ?? 'primary'"
528
532
  :disable="item.disable"
529
533
  :label="actionButtonLabel"
534
+ :loading="actionButtonLoading"
530
535
  outline
531
536
  size="sm"
532
537
  @click.stop="onItemActionClick(item)"
@@ -572,7 +577,7 @@ watch(
572
577
  label="Invite"
573
578
  outline
574
579
  size="sm"
575
- @click.stop="onInvitePerson(item)"
580
+ @click.stop="onInvitePerson(item, false)"
576
581
  />
577
582
  </div>
578
583
  </div>
@@ -596,56 +601,81 @@ watch(
596
601
 
597
602
  <!-- Recently selected list -->
598
603
 
599
- <q-list
600
- v-if="showRecentSelected && recentSearches.length"
601
- class="search-list q-mt-xs"
602
- >
603
- <span class="text-overline-xs">Recently Selected</span>
604
- <template v-for="item in recentSearches" :key="item.id">
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>
604
+ <q-list class="search-list q-mt-xs">
605
+ <div
606
+ v-if="showRecentSelected && recentSearchesLoading"
607
+ class="row justify-between items-center"
608
+ >
609
+ <span class="text-overline-xs"> Recently Selected </span>
636
610
 
637
- <q-item-section side>
638
- <UBtnStd
639
- v-bind="item.btnProps"
640
- :color="item.btnProps?.color ?? 'primary'"
641
- :label="actionButtonLabel"
642
- outline
643
- size="sm"
644
- @click.stop="onItemActionClick(item)"
645
- />
646
- </q-item-section>
647
- </q-item>
648
- </template>
611
+ <q-spinner
612
+ v-if="recentSearchesLoading"
613
+ color="grey-14"
614
+ size="1rem"
615
+ />
616
+ </div>
617
+ <div
618
+ v-if="showRecentSelected && recentSearches && recentSearches.length"
619
+ >
620
+ <span class="text-overline-xs"> Recently Selected </span>
621
+
622
+ <template v-for="item in recentSearches" :key="item.id">
623
+ <q-item class="list-item" clickable>
624
+ <q-item-section side>
625
+ <UAvatar
626
+ v-if="
627
+ !item.profilePictureUrl ||
628
+ item.profilePictureUrl?.nullValue === 0
629
+ "
630
+ :aria-label="item.name"
631
+ :name="parseInitials(item.name)"
632
+ size="md"
633
+ />
634
+ <UAvatar
635
+ v-else
636
+ :aria-label="item.name"
637
+ :image="item.profilePictureUrl"
638
+ :round="true"
639
+ size="md"
640
+ :showIndicator="false"
641
+ />
642
+ </q-item-section>
643
+
644
+ <q-item-section>
645
+ <q-item-label class="text-caption-md wrapped-text">
646
+ {{ item?.name }}
647
+ </q-item-label>
648
+ <q-item-label
649
+ class="text-body-xs text-neutral-9 label wrapped-text"
650
+ >
651
+ {{ item?.description }}
652
+ </q-item-label>
653
+ </q-item-section>
654
+
655
+ <q-item-section side>
656
+ <UBtnStd
657
+ v-bind="item.btnProps"
658
+ :color="item.btnProps?.color ?? 'primary'"
659
+ :disable="item.disable"
660
+ :label="actionButtonLabel"
661
+ :loading="actionButtonLoading"
662
+ outline
663
+ size="sm"
664
+ @click.stop="onItemActionClick(item, true)"
665
+ >
666
+ <template v-if="item.tooltip && item.disable" #tooltip>
667
+ <UTooltip
668
+ anchor="top middle"
669
+ :description="item.tooltip"
670
+ :offset="[0, 4]"
671
+ self="bottom middle"
672
+ />
673
+ </template>
674
+ </UBtnStd>
675
+ </q-item-section>
676
+ </q-item>
677
+ </template>
678
+ </div>
649
679
  </q-list>
650
680
  </div>
651
681
  </q-list>
@@ -683,14 +713,6 @@ watch(
683
713
  display: flex
684
714
  flex-direction: column
685
715
  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
716
  .list-item
695
717
  border-radius: $xs
696
718
  padding: $xs
@@ -706,5 +728,4 @@ watch(
706
728
  white-space: normal
707
729
  overflow: hidden
708
730
  word-wrap: break-word
709
- max-width: 18rem
710
731
  </style>