change dashboard ui to use api instead of inertia props

This commit is contained in:
Gregor Vostrak
2025-03-18 12:39:58 +01:00
committed by Constantin Graf
parent 01f6f0f5ea
commit 6ba0b19d40
14 changed files with 915 additions and 450 deletions

View File

@@ -1,32 +1,83 @@
<script setup lang="ts">
import RecentlyTrackedTasksCardEntry from '@/Components/Dashboard/RecentlyTrackedTasksCardEntry.vue';
import DashboardCard from '@/Components/Dashboard/DashboardCard.vue';
import { CheckCircleIcon } from '@heroicons/vue/20/solid';
import SecondaryButton from '@/packages/ui/src/Buttons/SecondaryButton.vue';
import { PlusCircleIcon } from '@heroicons/vue/24/solid';
import { router } from '@inertiajs/vue3';
import { useQuery } from "@tanstack/vue-query";
import { computed } from "vue";
import RecentlyTrackedTasksCardEntry from "@/Components/Dashboard/RecentlyTrackedTasksCardEntry.vue";
import DashboardCard from "@/Components/Dashboard/DashboardCard.vue";
import { CheckCircleIcon } from "@heroicons/vue/20/solid";
import SecondaryButton from "@/packages/ui/src/Buttons/SecondaryButton.vue";
import { PlusCircleIcon } from "@heroicons/vue/24/solid";
import { router } from "@inertiajs/vue3";
import { getCurrentMembershipId, getCurrentOrganizationId } from "@/utils/useUser";
import { api } from "@/packages/api/src";
import { LoadingSpinner } from "@/packages/ui/src";
const props = defineProps<{
latestTasks: {
id: string;
name: string;
project_name: string;
project_id: string;
}[];
}>();
// Get the organization ID using the utility function
const organizationId = computed(() => getCurrentOrganizationId());
// Function to fetch latest tasks using the API client
// Set up the query
const { data: timeEntriesResponse, isLoading, refetch } = useQuery({
queryKey: ["timeEntries", organizationId],
queryFn: () => {
return api.getTimeEntries({
params: {
organization: organizationId.value!
},
queries: {
member_id: getCurrentMembershipId()
}
});
},
enabled: computed(() => !!organizationId.value)
});
const latestTasks = computed(() => {
if (!timeEntriesResponse.value) {
return [];
}
return timeEntriesResponse.value.data;
});
const filteredLatestTasks = computed(() => {
// do not include running time entries
const finishedTimeEntries = latestTasks.value.filter((item) => item.end !== null);
// filter out duplicates based on description, task, project, tags and billable
return finishedTimeEntries.filter((item, index, self) => {
return index === self.findIndex((t) => (
t.description === item.description &&
t.task_id === item.task_id &&
t.project_id === item.project_id &&
t.tags.length === item.tags.length &&
t.tags.every((tag) => item.tags.includes(tag)) &&
t.billable === item.billable
));
}).slice(0, 4);
});
// Listen for dashboard refresh events
window.addEventListener("dashboard:refresh", () => {
refetch();
});
</script>
<template>
<DashboardCard title="Recently Tracked Tasks" :icon="CheckCircleIcon">
<RecentlyTrackedTasksCardEntry
v-for="lastTask in props.latestTasks"
:key="lastTask.id"
:class="props.latestTasks.length === 4 ? 'last:border-0' : ''"
:project_id="lastTask.project_id"
:task_id="lastTask.id"
:title="lastTask.name"></RecentlyTrackedTasksCardEntry>
<DashboardCard title="Recent Time Entries" :icon="CheckCircleIcon">
<div v-if="isLoading" class="flex justify-center items-center h-40">
<LoadingSpinner />
</div>
<div v-else-if="filteredLatestTasks && filteredLatestTasks.length > 0">
<RecentlyTrackedTasksCardEntry
v-for="lastTask in filteredLatestTasks"
:key="lastTask.id"
:time-entry="lastTask"
:class="filteredLatestTasks.length === 4 ? 'last:border-0' : ''"></RecentlyTrackedTasksCardEntry>
</div>
<div
v-if="props.latestTasks.length === 0"
v-else
class="text-center flex flex-1 justify-center items-center">
<div>
<PlusCircleIcon
@@ -36,12 +87,12 @@ const props = defineProps<{
</h3>
<p class="pb-5 text-sm">Create tasks inside of a project!</p>
<SecondaryButton @click="router.visit(route('projects'))"
>Go to Projects
>Go to Projects
</SecondaryButton>
</div>
</div>
<div
v-if="props.latestTasks.length === 1"
v-if="latestTasks && latestTasks.length === 1"
class="text-center flex flex-1 justify-center items-center text-sm">
<div>
<PlusCircleIcon
@@ -49,7 +100,7 @@ const props = defineProps<{
<h3 class="text-white font-semibold">Add more tasks</h3>
<p class="pb-5">Create tasks inside of a project!</p>
<SecondaryButton @click="router.visit(route('projects'))"
>Go to Projects
>Go to Projects
</SecondaryButton>
</div>
</div>