mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-16 12:12:15 +01:00
add break time entries and simplified time tracker ui
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useBreaksEnabled } from '@/packages/ui/src/utils/useBreaksEnabled';
|
||||
import { CheckCircleIcon, TagIcon, UserGroupIcon } from '@heroicons/vue/20/solid';
|
||||
import { FolderIcon } from '@heroicons/vue/16/solid';
|
||||
import { Check } from '@lucide/vue';
|
||||
import { Check, Coffee } from '@lucide/vue';
|
||||
import { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot, type AcceptableValue } from 'reka-ui';
|
||||
import BillableIcon from '@/packages/ui/src/Icons/BillableIcon.vue';
|
||||
import ReportingRoundingControls from '@/Components/Common/Reporting/ReportingRoundingControls.vue';
|
||||
@@ -27,6 +28,7 @@ const selectedClients = defineModel<string[]>('selectedClients', { required: tru
|
||||
const selectedTags = defineModel<string[]>('selectedTags', { required: true });
|
||||
const tagMatchType = defineModel<TagMatchType>('tagMatchType', { required: true });
|
||||
const billable = defineModel<'true' | 'false' | null>('billable', { required: true });
|
||||
const entryType = defineModel<'work' | 'break' | null>('entryType', { required: true });
|
||||
const roundingEnabled = defineModel<boolean>('roundingEnabled', { required: true });
|
||||
const roundingType = defineModel<TimeEntryRoundingType>('roundingType', { required: true });
|
||||
const roundingMinutes = defineModel<number>('roundingMinutes', { required: true });
|
||||
@@ -37,6 +39,8 @@ const emit = defineEmits<{
|
||||
submit: [];
|
||||
}>();
|
||||
|
||||
const breaksEnabled = useBreaksEnabled();
|
||||
|
||||
const { tags } = useTagsQuery();
|
||||
|
||||
const tagMatchOptions: { value: TagMatchType; label: string }[] = [
|
||||
@@ -162,6 +166,38 @@ async function createTag(name: string) {
|
||||
<SelectItem value="false">Non Billable</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select
|
||||
v-if="breaksEnabled"
|
||||
v-model="entryType"
|
||||
@update:model-value="emit('submit')">
|
||||
<SelectTrigger
|
||||
size="sm"
|
||||
variant="outline"
|
||||
:active="entryType !== null"
|
||||
:show-chevron="false">
|
||||
<SelectValue class="flex items-center gap-2">
|
||||
<Coffee
|
||||
class="h-4 w-4"
|
||||
:class="
|
||||
entryType !== null
|
||||
? 'dark:text-accent-300/80 text-accent-400/80'
|
||||
: 'text-text-quaternary'
|
||||
" />
|
||||
<span class="text-text-secondary">{{
|
||||
entryType === null
|
||||
? 'Type'
|
||||
: entryType === 'break'
|
||||
? 'Breaks'
|
||||
: 'Work time'
|
||||
}}</span>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">Both</SelectItem>
|
||||
<SelectItem value="work">Work time</SelectItem>
|
||||
<SelectItem value="break">Breaks</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<ReportingRoundingControls
|
||||
v-model:enabled="roundingEnabled"
|
||||
v-model:type="roundingType"
|
||||
|
||||
@@ -71,6 +71,7 @@ const selectedClients = ref<string[]>([]);
|
||||
const tagMatchType = ref<TagMatchType>('contains');
|
||||
|
||||
const billable = ref<'true' | 'false' | null>(null);
|
||||
const entryType = ref<'work' | 'break' | null>('work');
|
||||
const roundingEnabled = ref<boolean>(false);
|
||||
const roundingType = ref<TimeEntryRoundingType>('nearest');
|
||||
const roundingMinutes = ref<number>(15);
|
||||
@@ -126,6 +127,7 @@ const filterParams = computed<AggregatedTimeEntriesQueryParams>(() => {
|
||||
tag_ids: selectedTags.value.length > 0 ? selectedTags.value : undefined,
|
||||
tag_match_type: selectedTags.value.length > 0 ? tagMatchType.value : undefined,
|
||||
billable: billable.value !== null ? billable.value : undefined,
|
||||
type: entryType.value !== null ? entryType.value : undefined,
|
||||
member_id: getCurrentRole() === 'employee' ? getCurrentMembershipId() : undefined,
|
||||
rounding_type: roundingEnabled.value ? roundingType.value : undefined,
|
||||
rounding_minutes: roundingEnabled.value ? roundingMinutes.value : undefined,
|
||||
@@ -160,7 +162,7 @@ const aggregatedTableTimeEntries = computed<AggregatedTimeEntries | undefined>((
|
||||
});
|
||||
|
||||
const reportProperties = computed(() => {
|
||||
const { billable: billableFilter, ...rest } = filterParams.value;
|
||||
const { billable: billableFilter, type: typeFilter, ...rest } = filterParams.value;
|
||||
|
||||
let billableValue: boolean | null = null;
|
||||
if (billableFilter === 'true') {
|
||||
@@ -172,6 +174,7 @@ const reportProperties = computed(() => {
|
||||
return {
|
||||
...rest,
|
||||
billable: billableValue,
|
||||
time_entry_type: typeFilter ?? null,
|
||||
group: group.value,
|
||||
sub_group: subGroup.value,
|
||||
history_group: getOptimalGroupingOption(startDate.value, endDate.value),
|
||||
@@ -371,6 +374,7 @@ const tableData = computed(() => {
|
||||
v-model:selected-tags="selectedTags"
|
||||
v-model:tag-match-type="tagMatchType"
|
||||
v-model:billable="billable"
|
||||
v-model:entry-type="entryType"
|
||||
v-model:rounding-enabled="roundingEnabled"
|
||||
v-model:rounding-type="roundingType"
|
||||
v-model:rounding-minutes="roundingMinutes"
|
||||
|
||||
Reference in New Issue
Block a user