11<script setup lang="ts">
2- import { computed , nextTick , onMounted , ref , watch } from ' vue' ;
2+ import { computed , onMounted , ref , watch } from ' vue' ;
33import { storeToRefs } from ' pinia' ;
4- import ClientDropdownItem from ' @/packages/ui/src/Client/ClientDropdownItem.vue' ;
54import { useMembersStore } from ' @/utils/useMembers' ;
6- import { UserIcon , XMarkIcon } from ' @heroicons/vue/24/solid' ;
7- import TextInput from ' @/packages/ui/src/Input/TextInput.vue' ;
5+ import { UserIcon , ChevronDownIcon } from ' @heroicons/vue/24/solid' ;
86import { useFocus } from ' @vueuse/core' ;
97import type { ProjectMember } from ' @/packages/api/src' ;
10- import Dropdown from ' @/packages/ui/src/Input/Dropdown.vue' ;
8+ import { Badge , SelectDropdown } from ' @/packages/ui/src' ;
9+ import type { Member } from ' @/packages/api/src' ;
1110
1211const membersStore = useMembersStore ();
1312const { members } = storeToRefs (membersStore );
@@ -31,13 +30,9 @@ const searchInput = ref<HTMLInputElement | null>(null);
3130
3231const searchValue = ref (' ' );
3332
34- function isMemberSelected(id : string ) {
35- return model .value === id ;
36- }
37-
3833useFocus (searchInput , { initialValue: true });
3934
40- const filteredMembers = computed (() => {
35+ const filteredMembers = computed < Member []> (() => {
4136 return members .value .filter ((member ) => {
4237 return (
4338 member .name
@@ -65,141 +60,35 @@ function resetHighlightedItem() {
6560 }
6661}
6762
68- function updateSearchValue(event : Event ) {
69- const newInput = (event .target as HTMLInputElement ).value ;
70- if (newInput === ' ' ) {
71- searchValue .value = ' ' ;
72- const highlightedClientId = highlightedItemId .value ;
73- if (highlightedClientId ) {
74- const highlightedClient = members .value .find (
75- (member ) => member .id === highlightedClientId
76- );
77- if (highlightedClient ) {
78- model .value = highlightedClient .id ;
79- }
80- }
81- } else {
82- searchValue .value = newInput ;
83- }
84- }
85-
86- const emit = defineEmits ([' update:modelValue' , ' changed' ]);
87-
88- function updateMember(newValue : string | null ) {
89- if (newValue ) {
90- model .value = newValue ;
91- nextTick (() => {
92- emit (' changed' );
93- });
94- }
95- }
96-
97- function moveHighlightUp() {
98- if (highlightedItem .value ) {
99- const currentHightlightedIndex = filteredMembers .value .indexOf (
100- highlightedItem .value
101- );
102- if (currentHightlightedIndex === 0 ) {
103- highlightedItemId .value =
104- filteredMembers .value [filteredMembers .value .length - 1 ].id ;
105- } else {
106- highlightedItemId .value =
107- filteredMembers .value [currentHightlightedIndex - 1 ].id ;
108- }
109- }
110- }
111-
112- function moveHighlightDown() {
113- if (highlightedItem .value ) {
114- const currentHightlightedIndex = filteredMembers .value .indexOf (
115- highlightedItem .value
116- );
117- if (currentHightlightedIndex === filteredMembers .value .length - 1 ) {
118- highlightedItemId .value = filteredMembers .value [0 ].id ;
119- } else {
120- highlightedItemId .value =
121- filteredMembers .value [currentHightlightedIndex + 1 ].id ;
122- }
123- }
124- }
125-
12663const highlightedItemId = ref <string | null >(null );
127- const highlightedItem = computed (() => {
128- return members .value .find (
129- (member ) => member .id === highlightedItemId .value
130- );
131- });
13264
13365const currentValue = computed (() => {
13466 if (model .value ) {
13567 return members .value .find ((member ) => member .id === model .value )?.name ;
13668 }
13769 return searchValue .value ;
13870});
139-
140- const hasMemberSelected = computed (() => {
141- return model .value !== ' ' ;
142- });
143-
144- const showMembersDropdown = ref (true );
14571 </script >
14672
14773<template >
148- <Dropdown
149- align =" bottom-start"
150- width =" 300"
151- v-model =" showMembersDropdown"
152- :closeOnContentClick =" true" >
153- <template #trigger >
154- <div class =" flex relative" >
155- <div
156- ref =" reference"
157- class =" absolute h-full items-center px-3 w-full flex justify-between" >
158- <UserIcon class =" relative z-10 w-4 text-muted" ></UserIcon >
159- <button
160- v-if =" hasMemberSelected"
161- @click =" model = ''"
162- class =" focus:text-accent-200 focus:bg-card-background text-muted" >
163- <XMarkIcon class =" relative z-10 w-4" ></XMarkIcon >
164- </button >
74+ <SelectDropdown
75+ v-model =" model"
76+ :items =" filteredMembers"
77+ :get-key-from-item =" (member) => member.id"
78+ :get-name-for-item =" (member) => member.name" >
79+ <template v-slot :trigger >
80+ <Badge
81+ tag =" button"
82+ class =" flex w-full text-base text-left space-x-3 px-3 text-text-secondary font-normal cursor py-1.5" >
83+ <UserIcon class =" relative z-10 w-4 text-muted" ></UserIcon >
84+ <div v-if =" currentValue" class =" flex-1 truncate" >
85+ {{ currentValue }}
16586 </div >
166- <TextInput
167- :value =" currentValue"
168- :disabled =" disabled"
169- @input =" updateSearchValue"
170- data-testid =" member_dropdown_search"
171- @keydown.enter.prevent =" updateMember(highlightedItemId)"
172- @keydown.up.prevent =" moveHighlightUp"
173- class =" relative w-full pl-10"
174- @keydown.down.prevent =" moveHighlightDown"
175- placeholder =" Search for a member..."
176- ref =" searchInput" />
177- </div >
178- </template >
179- <template #content >
180- <div
181- class =" py-2 text-white px-3"
182- v-if =" filteredMembers.length === 0" >
183- All members are already added.
184- </div >
185- <div
186- v-for =" member in filteredMembers"
187- :key =" member.id"
188- role =" option"
189- :value =" member.id"
190- :class =" {
191- 'bg-card-background-active':
192- member.id === highlightedItemId,
193- }"
194- @click =" updateMember(member.id)"
195- data-testid =" client_dropdown_entries"
196- :data-client-id =" member.id" >
197- <ClientDropdownItem
198- :selected =" isMemberSelected(member.id)"
199- :name =" member.name" ></ClientDropdownItem >
200- </div >
87+ <div class =" flex-1" v-else >Select a member...</div >
88+ <ChevronDownIcon class =" w-4 text-muted" ></ChevronDownIcon >
89+ </Badge >
20190 </template >
202- </Dropdown >
91+ </SelectDropdown >
20392</template >
20493
20594<style scoped></style >
0 commit comments