refactor tag components and tagCreate events, change global week_start and timezone settings, fix pie charts

This commit is contained in:
Gregor Vostrak
2024-07-15 17:20:07 +02:00
parent 10d8540e6c
commit 655723db49
25 changed files with 255 additions and 133 deletions

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"></script>
<template>
<div class="px-3 sm:px-6 lg:px-8 3xl:px-12 mx-auto">
<div class="px-3 sm:px-4 lg:px-8 3xl:px-12 mx-auto">
<slot></slot>
</div>
</template>

View File

@@ -21,7 +21,7 @@ import {
import { type GroupingOption, useReportingStore } from '@/utils/useReporting';
import { storeToRefs } from 'pinia';
import TagDropdown from '@/Components/Common/Tag/TagDropdown.vue';
import type { AggregatedTimeEntriesQueryParams } from '@/utils/api';
import type { AggregatedTimeEntriesQueryParams, Tag } from '@/utils/api';
import ReportingFilterBadge from '@/Components/Common/Reporting/ReportingFilterBadge.vue';
import ProjectMultiselectDropdown from '@/Components/Common/Project/ProjectMultiselectDropdown.vue';
import MemberMultiselectDropdown from '@/Components/Common/Member/MemberMultiselectDropdown.vue';
@@ -33,6 +33,7 @@ import { formatCents } from '@/utils/money';
import ReportingPieChart from '@/Components/Common/Reporting/ReportingPieChart.vue';
import { getCurrentMembershipId, getCurrentRole } from '@/utils/useUser';
import ClientMultiselectDropdown from '@/Components/Common/Client/ClientMultiselectDropdown.vue';
import { useTagsStore } from '@/utils/useTags';
const startDate = ref<string | null>(
getLocalizedDayJs(getDayJsInstance()().format()).subtract(14, 'd').format()
@@ -136,6 +137,14 @@ onMounted(() => {
updateGraphReporting();
updateTableReporting();
});
const { tags } = storeToRefs(useTagsStore());
async function createTag(tag: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(tag);
if (newTag !== undefined) {
callback(newTag);
}
}
</script>
<template>
@@ -196,7 +205,9 @@ onMounted(() => {
</ClientMultiselectDropdown>
<TagDropdown
@submit="updateReporting"
v-model="selectedTags">
@createTag="createTag"
v-model="selectedTags"
:tags="tags">
<template v-slot:trigger>
<ReportingFilterBadge
:count="selectedTags.length"

View File

@@ -8,7 +8,15 @@ import TagTable from '@/Components/Common/Tag/TagTable.vue';
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import PageTitle from '@/Components/Common/PageTitle.vue';
import { canCreateTags } from '@/utils/permissions';
const createTag = ref(false);
import { useTagsStore } from '@/utils/useTags';
import type { Tag } from '@/utils/api';
const showCreateTagModal = ref(false);
async function createTag(tag: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(tag);
if (newTag !== undefined) {
callback(newTag);
}
}
</script>
<template>
@@ -21,10 +29,12 @@ const createTag = ref(false);
<SecondaryButton
v-if="canCreateTags()"
:icon="PlusIcon"
@click="createTag = true"
@click="showCreateTagModal = true"
>Create Tag</SecondaryButton
>
<TagCreateModal v-model:show="createTag"></TagCreateModal>
<TagCreateModal
@createTag="createTag"
v-model:show="showCreateTagModal"></TagCreateModal>
</MainContainer>
<TagTable></TagTable>
</AppLayout>

View File

@@ -5,18 +5,18 @@ import { onMounted, ref, watch } from 'vue';
import MainContainer from '@/Pages/MainContainer.vue';
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
import { storeToRefs } from 'pinia';
import type { TimeEntry } from '@/utils/api';
import type { CreateTimeEntryBody, Tag, TimeEntry } from '@/utils/api';
import { useElementVisibility } from '@vueuse/core';
import { ClockIcon } from '@heroicons/vue/20/solid';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import { PlusIcon } from '@heroicons/vue/16/solid';
import TimeEntryCreateModal from '@/Components/Common/TimeEntry/TimeEntryCreateModal.vue';
import LoadingSpinner from '@/Components/LoadingSpinner.vue';
import dayjs from 'dayjs';
import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
import { useTasksStore } from '@/utils/useTasks';
import { useProjectsStore } from '@/utils/useProjects';
import TimeEntryGroupedTable from '@/Components/Common/TimeEntry/TimeEntryGroupedTable.vue';
import { useTagsStore } from '@/utils/useTags';
const timeEntriesStore = useTimeEntriesStore();
const { timeEntries, allTimeEntriesLoaded } = storeToRefs(timeEntriesStore);
@@ -33,20 +33,18 @@ function updateTimeEntries(timeEntries: TimeEntry[]) {
const loading = ref(false);
const loadMoreContainer = ref<HTMLDivElement | null>(null);
const isLoadMoreVisible = useElementVisibility(loadMoreContainer);
const currentTimeEntryStore = useCurrentTimeEntryStore();
const { currentTimeEntry } = storeToRefs(currentTimeEntryStore);
const { stopTimer } = currentTimeEntryStore;
const { tags } = storeToRefs(useTagsStore());
async function onStartStopClick(timeEntry: TimeEntry) {
if (timeEntry.start && !timeEntry.end) {
await updateTimeEntry({
...timeEntry,
end: dayjs().utc().format(),
});
} else {
await createTimeEntry({
...timeEntry,
start: dayjs().utc().format(),
end: null,
});
async function startTimeEntry(
timeEntry: Omit<CreateTimeEntryBody, 'member_id'>
) {
if (currentTimeEntry.value.id) {
await stopTimer();
}
await createTimeEntry(timeEntry);
fetchTimeEntries();
useCurrentTimeEntryStore().fetchCurrentTimeEntry();
}
@@ -78,6 +76,13 @@ const projectStore = useProjectsStore();
const { projects } = storeToRefs(projectStore);
const taskStore = useTasksStore();
const { tasks } = storeToRefs(taskStore);
async function createTag(name: string, callback: (tag: Tag) => void) {
const newTag = await useTagsStore().createTag(name);
if (newTag !== undefined) {
callback(newTag);
}
}
</script>
<template>
@@ -105,10 +110,12 @@ const { tasks } = storeToRefs(taskStore);
@updateTimeEntry="updateTimeEntry"
@updateTimeEntries="updateTimeEntries"
@deleteTimeEntries="deleteTimeEntries"
@onStartStopClick="onStartStopClick"
@createTimeEntry="startTimeEntry"
@createTag="createTag"
:projects="projects"
:tasks="tasks"
:timeEntries="timeEntries"></TimeEntryGroupedTable>
:timeEntries="timeEntries"
:tags="tags"></TimeEntryGroupedTable>
<div v-if="timeEntries.length === 0" class="text-center pt-12">
<ClockIcon class="w-8 text-icon-default inline pb-2"></ClockIcon>
<h3 class="text-white font-semibold">No time entries found</h3>