From 129c132f97e31865b03e50655dc6655bc4ba4331 Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Wed, 9 Oct 2024 14:20:07 +0200 Subject: [PATCH] make project and tags in mass updates resettable --- .../TimeEntry/TimeEntryMassUpdateModal.vue | 130 +++++++++++------- resources/js/packages/ui/src/Badge.vue | 2 +- .../TimeTrackerProjectTaskDropdown.vue | 30 +++- 3 files changed, 110 insertions(+), 52 deletions(-) diff --git a/resources/js/Components/Common/TimeEntry/TimeEntryMassUpdateModal.vue b/resources/js/Components/Common/TimeEntry/TimeEntryMassUpdateModal.vue index 9c2ba9e5..d68db42c 100644 --- a/resources/js/Components/Common/TimeEntry/TimeEntryMassUpdateModal.vue +++ b/resources/js/Components/Common/TimeEntry/TimeEntryMassUpdateModal.vue @@ -22,7 +22,7 @@ import { } from '@/packages/api/src'; import { useClientsStore } from '@/utils/useClients'; import { getOrganizationCurrencyString } from '@/utils/money'; -import { Badge } from '@/packages/ui/src'; +import { Badge, Checkbox } from '@/packages/ui/src'; import SelectDropdown from '../../../packages/ui/src/Input/SelectDropdown.vue'; import { getCurrentOrganizationId } from '@/utils/useUser'; import { useNotificationsStore } from '@/utils/notification'; @@ -71,7 +71,7 @@ watch(show, (value) => { const description = ref(''); const taskId = ref(undefined); -const projectId = ref(undefined); +const projectId = ref(null); const billable = ref(undefined); const selectedTags = ref([]); @@ -106,19 +106,28 @@ async function submit() { if (description.value && description.value !== '') { timeEntryUpdatesBody.description = description.value; } - if (projectId.value !== undefined) { - timeEntryUpdatesBody.project_id = projectId.value; + if (projectId.value !== null) { + if (projectId.value === '') { + // "No Project" is selected + timeEntryUpdatesBody.project_id = null; + } else { + timeEntryUpdatesBody.project_id = projectId.value; + } timeEntryUpdatesBody.task_id = null; + if (taskId.value !== undefined) { + timeEntryUpdatesBody.task_id = taskId.value; + } } - if (taskId.value !== undefined) { - timeEntryUpdatesBody.task_id = taskId.value; - } + if (billable.value !== undefined) { timeEntryUpdatesBody.billable = billable.value; } if (selectedTags.value.length > 0) { timeEntryUpdatesBody.tags = selectedTags.value; } + if (removeAllTags.value) { + timeEntryUpdatesBody.tags = []; + } try { await handleApiRequestNotifications( @@ -144,11 +153,12 @@ async function submit() { show.value = false; emit('submit'); description.value = ''; - projectId.value = undefined; + projectId.value = null; taskId.value = undefined; selectedTags.value = []; billable.value = undefined; saving.value = false; + removeAllTags.value = false; } ); } catch (e) { @@ -156,6 +166,12 @@ async function submit() { } } } +const removeAllTags = ref(false); +watch(removeAllTags, () => { + if (removeAllTags.value) { + selectedTags.value = []; + } +}); diff --git a/resources/js/packages/ui/src/Badge.vue b/resources/js/packages/ui/src/Badge.vue index 8a4fa7f4..24674f77 100644 --- a/resources/js/packages/ui/src/Badge.vue +++ b/resources/js/packages/ui/src/Badge.vue @@ -39,7 +39,7 @@ const borderClasses = computed(() => { twMerge( badgeClasses[size], borderClasses, - 'rounded inline-flex items-center font-semibold text-white outline-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80', + 'rounded inline-flex items-center font-semibold text-white disabled:text-text-quaternary outline-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80', props.class ) "> diff --git a/resources/js/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue b/resources/js/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue index 05d648eb..7d857bad 100644 --- a/resources/js/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue +++ b/resources/js/packages/ui/src/TimeTracker/TimeTrackerProjectTaskDropdown.vue @@ -12,7 +12,12 @@ import type { } from '@/packages/api/src'; import ProjectBadge from '@/packages/ui/src/Project/ProjectBadge.vue'; import Badge from '@/packages/ui/src/Badge.vue'; -import { PlusIcon, PlusCircleIcon, MinusIcon } from '@heroicons/vue/16/solid'; +import { + PlusIcon, + PlusCircleIcon, + MinusIcon, + XMarkIcon, +} from '@heroicons/vue/16/solid'; import ProjectCreateModal from '@/packages/ui/src/Project/ProjectCreateModal.vue'; const task = defineModel('task', { @@ -56,10 +61,14 @@ const props = withDefaults( ) => Promise; createClient: (client: CreateClientBody) => Promise; currency: string; + emptyPlaceholder: string; + allowReset: boolean; }>(), { showBadgeBorder: true, size: 'large', + emptyPlaceholder: 'No Project', + allowReset: false, } ); @@ -478,7 +487,13 @@ const currentTask = computed(() => { }); const selectedProjectName = computed(() => { - return currentProject.value?.name || 'No Project'; + if (project.value === null) { + return props.emptyPlaceholder; + } + if (project.value === '') { + return 'No Project'; + } + return currentProject.value?.name; }); const selectedProjectColor = computed(() => { @@ -535,7 +550,7 @@ const showCreateProject = ref(false); :border="showBadgeBorder" tag="button" :name="selectedProjectName" - class="focus:border-border-tertiary w-full focus:outline-0 focus:bg-card-background-separator min-w-0"> + class="focus:border-border-tertiary w-full focus:outline-0 focus:bg-card-background-separator min-w-0 relative">
{{ selectedProjectName }} @@ -549,6 +564,15 @@ const showCreateProject = ref(false); {{ currentTask.name }}
+