mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-15 11:42:15 +01:00
refactor tag components and tagCreate events, change global week_start and timezone settings, fix pie charts
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user