change project member id from member_id to user_id, fix member combobox

This commit is contained in:
Gregor Vostrak
2024-04-21 01:42:40 +02:00
parent 338e4ec469
commit 0f85c65d5f
3 changed files with 55 additions and 33 deletions

View File

@@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import Dropdown from '@/Components/Dropdown.vue'; import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { type Component, computed, nextTick, onMounted, ref, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import ClientDropdownItem from '@/Components/Common/Client/ClientDropdownItem.vue'; import ClientDropdownItem from '@/Components/Common/Client/ClientDropdownItem.vue';
import { useMembersStore } from '@/utils/useMembers'; import { useMembersStore } from '@/utils/useMembers';
@@ -8,6 +7,7 @@ import { UserIcon, XMarkIcon } from '@heroicons/vue/24/solid';
import TextInput from '@/Components/TextInput.vue'; import TextInput from '@/Components/TextInput.vue';
import { useFocus } from '@vueuse/core'; import { useFocus } from '@vueuse/core';
import type { ProjectMember } from '@/utils/api'; import type { ProjectMember } from '@/utils/api';
import Dropdown from '@/Components/Dropdown.vue';
const membersStore = useMembersStore(); const membersStore = useMembersStore();
const { members } = storeToRefs(membersStore); const { members } = storeToRefs(membersStore);
@@ -21,7 +21,6 @@ const props = defineProps<{
}>(); }>();
const searchInput = ref<HTMLInputElement | null>(null); const searchInput = ref<HTMLInputElement | null>(null);
const dropdownViewport = ref<Component | null>(null);
const searchValue = ref(''); const searchValue = ref('');
@@ -38,7 +37,7 @@ const filteredMembers = computed(() => {
.toLowerCase() .toLowerCase()
.includes(searchValue.value?.toLowerCase()?.trim() || '') && .includes(searchValue.value?.toLowerCase()?.trim() || '') &&
!props.hiddenMembers.some( !props.hiddenMembers.some(
(hiddenMember) => hiddenMember.user_id === member.id (hiddenMember) => hiddenMember.user_id === member.user_id
) && ) &&
member.is_placeholder === false member.is_placeholder === false
); );
@@ -55,7 +54,7 @@ onMounted(() => {
function resetHighlightedItem() { function resetHighlightedItem() {
if (filteredMembers.value.length > 0) { if (filteredMembers.value.length > 0) {
highlightedItemId.value = filteredMembers.value[0].id; highlightedItemId.value = filteredMembers.value[0].user_id;
} }
} }
@@ -66,10 +65,10 @@ function updateSearchValue(event: Event) {
const highlightedClientId = highlightedItemId.value; const highlightedClientId = highlightedItemId.value;
if (highlightedClientId) { if (highlightedClientId) {
const highlightedClient = members.value.find( const highlightedClient = members.value.find(
(member) => member.id === highlightedClientId (member) => member.user_id === highlightedClientId
); );
if (highlightedClient) { if (highlightedClient) {
model.value = highlightedClient.id; model.value = highlightedClient.user_id;
} }
} }
} else { } else {
@@ -80,6 +79,7 @@ function updateSearchValue(event: Event) {
const emit = defineEmits(['update:modelValue', 'changed']); const emit = defineEmits(['update:modelValue', 'changed']);
function updateMember(newValue: string | null) { function updateMember(newValue: string | null) {
console.log(newValue);
if (newValue) { if (newValue) {
model.value = newValue; model.value = newValue;
nextTick(() => { nextTick(() => {
@@ -95,10 +95,10 @@ function moveHighlightUp() {
); );
if (currentHightlightedIndex === 0) { if (currentHightlightedIndex === 0) {
highlightedItemId.value = highlightedItemId.value =
filteredMembers.value[filteredMembers.value.length - 1].id; filteredMembers.value[filteredMembers.value.length - 1].user_id;
} else { } else {
highlightedItemId.value = highlightedItemId.value =
filteredMembers.value[currentHightlightedIndex - 1].id; filteredMembers.value[currentHightlightedIndex - 1].user_id;
} }
} }
} }
@@ -109,10 +109,10 @@ function moveHighlightDown() {
highlightedItem.value highlightedItem.value
); );
if (currentHightlightedIndex === filteredMembers.value.length - 1) { if (currentHightlightedIndex === filteredMembers.value.length - 1) {
highlightedItemId.value = filteredMembers.value[0].id; highlightedItemId.value = filteredMembers.value[0].user_id;
} else { } else {
highlightedItemId.value = highlightedItemId.value =
filteredMembers.value[currentHightlightedIndex + 1].id; filteredMembers.value[currentHightlightedIndex + 1].user_id;
} }
} }
} }
@@ -120,13 +120,14 @@ function moveHighlightDown() {
const highlightedItemId = ref<string | null>(null); const highlightedItemId = ref<string | null>(null);
const highlightedItem = computed(() => { const highlightedItem = computed(() => {
return members.value.find( return members.value.find(
(member) => member.id === highlightedItemId.value (member) => member.user_id === highlightedItemId.value
); );
}); });
const currentValue = computed(() => { const currentValue = computed(() => {
if (model.value) { if (model.value) {
return members.value.find((member) => member.id === model.value)?.name; return members.value.find((member) => member.user_id === model.value)
?.name;
} }
return searchValue.value; return searchValue.value;
}); });
@@ -134,11 +135,23 @@ const currentValue = computed(() => {
const hasMemberSelected = computed(() => { const hasMemberSelected = computed(() => {
return model.value !== ''; return model.value !== '';
}); });
const showMembersDropdown = ref(true);
function onUnfocus() {
// TODO this is a hack to prevent the dropdown from closing when clicking on the dropdown
setTimeout(() => {
if (!focused.value) {
showMembersDropdown.value = false;
}
}, 100);
}
</script> </script>
<template> <template>
<div class="flex relative"> <div class="flex relative">
<div <div
ref="reference"
class="absolute h-full items-center px-3 w-full flex justify-between"> class="absolute h-full items-center px-3 w-full flex justify-between">
<UserIcon class="relative z-10 w-4 text-muted"></UserIcon> <UserIcon class="relative z-10 w-4 text-muted"></UserIcon>
<button <button
@@ -156,32 +169,37 @@ const hasMemberSelected = computed(() => {
@keydown.up.prevent="moveHighlightUp" @keydown.up.prevent="moveHighlightUp"
class="relative w-full pl-10" class="relative w-full pl-10"
@keydown.down.prevent="moveHighlightDown" @keydown.down.prevent="moveHighlightDown"
@focusin="showMembersDropdown = true"
@blur="onUnfocus"
placeholder="Search for a member..." placeholder="Search for a member..."
ref="searchInput" /> ref="searchInput" />
</div> </div>
<Dropdown <Dropdown
align="left" align="bottom-start"
width="300" width="300"
v-model="focused" v-model="showMembersDropdown"
:closeOnContentClick="true"> :closeOnContentClick="true">
<template #content> <template #content>
<div ref="dropdownViewport" class="w-60"> <div
<div class="py-2 text-white px-3"
v-for="member in filteredMembers" v-if="filteredMembers.length === 0">
:key="member.id" All members are already added.
role="option" </div>
:value="member.id" <div
:class="{ v-for="member in filteredMembers"
'bg-card-background-active': :key="member.user_id"
member.id === highlightedItemId, role="option"
}" :value="member.user_id"
@click="updateMember(member.id)" :class="{
data-testid="client_dropdown_entries" 'bg-card-background-active':
:data-client-id="member.id"> member.user_id === highlightedItemId,
<ClientDropdownItem }"
:selected="isMemberSelected(member.id)" @click="updateMember(member.user_id)"
:name="member.name"></ClientDropdownItem> data-testid="client_dropdown_entries"
</div> :data-client-id="member.user_id">
<ClientDropdownItem
:selected="isMemberSelected(member.user_id)"
:name="member.name"></ClientDropdownItem>
</div> </div>
</template> </template>
</Dropdown> </Dropdown>

View File

@@ -25,6 +25,10 @@ const projectMember = ref<CreateProjectMemberBody>({
async function submit() { async function submit() {
await createProjectMember(props.projectId, projectMember.value); await createProjectMember(props.projectId, projectMember.value);
show.value = false; show.value = false;
projectMember.value = {
user_id: '',
billable_rate: null,
};
} }
const projectNameInput = ref<HTMLInputElement | null>(null); const projectNameInput = ref<HTMLInputElement | null>(null);

View File

@@ -22,7 +22,7 @@ function deleteProjectMember() {
const { members } = storeToRefs(useMembersStore()); const { members } = storeToRefs(useMembersStore());
const member = computed(() => { const member = computed(() => {
return members.value.find( return members.value.find(
(member) => member.id === props.projectMember.user_id (member) => member.user_id === props.projectMember.user_id
); );
}); });
</script> </script>