11<script setup lang="ts">
22import { useQuery } from ' @tanstack/vue-query'
3- import { type Component , computed , nextTick , onMounted , watch , watchEffect } from ' vue'
3+ import { type Component , computed , nextTick , onMounted , ref , watch , watchEffect } from ' vue'
44
55import {
66 TimeEntryGroupedTable ,
77 TimeTrackerControls ,
88 TimeTrackerRunningInDifferentOrganizationOverlay ,
9+ TimeEntryMassActionRow ,
910} from ' @solidtime/ui'
1011import {
1112 emptyTimeEntry ,
@@ -17,6 +18,7 @@ import {
1718 useCurrentTimeEntryUpdateMutation ,
1819 useTimeEntriesUpdateMutation ,
1920 useTimeEntryUpdateMutation ,
21+ useTimeEntriesDeleteMutation ,
2022} from ' ../utils/timeEntries.ts'
2123import { getAllProjects , useProjectCreateMutation } from ' ../utils/projects.ts'
2224import { getAllTasks } from ' ../utils/tasks.ts'
@@ -27,6 +29,7 @@ import type {
2729 Project ,
2830 Tag ,
2931 TimeEntry ,
32+ UpdateMultipleTimeEntriesChangeset ,
3033} from ' @solidtime/api'
3134import { getAllTags , useTagCreateMutation } from ' ../utils/tags.ts'
3235import { LoadingSpinner } from ' @solidtime/ui'
@@ -44,11 +47,15 @@ import { apiClient } from '../utils/api'
4447import { updateTrayState } from ' ../utils/tray'
4548import { getMe } from ' ../utils/me'
4649
47- const { currentOrganizationId } = useMyMemberships ()
48- const currentOrganizationLoaded = computed (() => !! currentOrganizationId )
50+ const { currentOrganizationId, currentMembership } = useMyMemberships ()
51+ const currentOrganizationLoaded = computed (() => !! currentOrganizationId . value )
4952
5053const { liveTimer, startLiveTimer, stopLiveTimer } = useLiveTimer ()
5154
55+ watch (currentOrganizationId , () => {
56+ selectedTimeEntries .value = []
57+ })
58+
5259const { data : timeEntriesResponse } = useQuery ({
5360 queryKey: [' timeEntries' , currentOrganizationId ],
5461 queryFn : () => getAllTimeEntries (currentOrganizationId .value , currentMembershipId .value ),
@@ -61,8 +68,8 @@ const { data: currentTimeEntryResponse, isError: currentTimeEntryResponseIsError
6168 queryFn : () => getCurrentTimeEntry (),
6269})
6370
64- const currentTimeEntry = useStorage (' currentTimeEntry' , { ... emptyTimeEntry })
65- const lastTimeEntry = useStorage (' lastTimeEntry' , { ... emptyTimeEntry })
71+ const currentTimeEntry = useStorage < TimeEntry > (' currentTimeEntry' , { ... emptyTimeEntry })
72+ const lastTimeEntry = useStorage < TimeEntry > (' lastTimeEntry' , { ... emptyTimeEntry })
6673
6774watch (timeEntries , () => {
6875 if (timeEntries .value ?.[0 ]) {
@@ -116,6 +123,7 @@ const tags = computed(() => tagsResponse.value?.data)
116123
117124const currentTimeEntryUpdateMutation = useCurrentTimeEntryUpdateMutation ()
118125const timeEntriesUpdate = useTimeEntriesUpdateMutation ()
126+ const timeEntriesDelete = useTimeEntriesDeleteMutation ()
119127const timeEntryUpdate = useTimeEntryUpdateMutation ()
120128const timeEntryDelete = useTimeEntryDeleteMutation ()
121129const timeEntryCreate = useTimeEntryCreateMutation ()
@@ -264,8 +272,30 @@ watch(meResponse, () => {
264272 }
265273})
266274
275+ const selectedTimeEntries = ref ([] as TimeEntry [])
276+
277+ function deleteSelected() {
278+ timeEntriesDelete .mutate (selectedTimeEntries .value )
279+ selectedTimeEntries .value = []
280+ }
281+
282+ async function clearSelectionAndState() {
283+ selectedTimeEntries .value = []
284+ }
285+
267286// TODO: Fix me
268287const currency = ' EUR'
288+
289+ const canCreateProjects = computed (() => {
290+ if (currentMembership .value ) {
291+ return (
292+ currentMembership .value ?.role === ' admin' ||
293+ currentMembership .value ?.role === ' owner' ||
294+ currentMembership .value ?.role === ' manager'
295+ )
296+ }
297+ return false
298+ })
269299 </script >
270300
271301<template >
@@ -289,6 +319,8 @@ const currency = 'EUR'
289319 v-model:currentTimeEntry =" currentTimeEntry"
290320 v-model:liveTimer =" liveTimer"
291321 :tags
322+ :enableEstimatedTime =" false"
323+ :canCreateProject =" canCreateProjects"
292324 :createProject
293325 :createClient
294326 :tasks
@@ -305,8 +337,33 @@ const currency = 'EUR'
305337 </div >
306338 </div >
307339 <div class =" overflow-y-scroll w-full flex-1" >
340+ <TimeEntryMassActionRow
341+ :selectedTimeEntries
342+ :deleteSelected
343+ :allSelected =" selectedTimeEntries.length === timeEntries.length"
344+ :tasks
345+ :tags
346+ :currency
347+ :enableEstimatedTime =" false"
348+ :canCreateProject =" canCreateProjects"
349+ :projects
350+ :clients
351+ :updateTimeEntries ="
352+ (args: UpdateMultipleTimeEntriesChangeset) =>
353+ timeEntriesUpdate.mutate({
354+ ids: selectedTimeEntries.map((timeEntry) => timeEntry.id),
355+ changes: args,
356+ })
357+ "
358+ :createProject
359+ :createClient
360+ :createTag
361+ @submit =" clearSelectionAndState"
362+ @select-all =" selectedTimeEntries = [...timeEntries]"
363+ @unselect-all =" selectedTimeEntries = []" ></TimeEntryMassActionRow >
308364 <TimeEntryGroupedTable
309365 v-if =" timeEntries && projects && tasks && tags && clients"
366+ v-model:selected =" selectedTimeEntries"
310367 :projects
311368 :tasks
312369 :tags
@@ -324,7 +381,10 @@ const currency = 'EUR'
324381 timeEntriesUpdate.mutate({ ids: ids, changes: changes })
325382 "
326383 :deleteTimeEntries ="
327- (args) => args.forEach((timeEntry) => timeEntryDelete.mutate(timeEntry))
384+ (args: TimeEntry[]) =>
385+ args.forEach((timeEntry: TimeEntry) =>
386+ timeEntryDelete.mutate(timeEntry)
387+ )
328388 "
329389 :createTimeEntry =" createTimeEntry"
330390 :createTag
0 commit comments