Skip to content

Commit 6ba0b19

Browse files
Onatcerkorridor
authored andcommitted
change dashboard ui to use api instead of inertia props
1 parent 01f6f0f commit 6ba0b19

File tree

14 files changed

+905
-440
lines changed

14 files changed

+905
-440
lines changed

app/Http/Controllers/Api/V1/ChartController.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class ChartController extends Controller
1515
{
1616
/**
1717
* @throws AuthorizationException
18+
*
19+
* @operationId weeklyProjectOverview
20+
*
21+
* @response array<int, array{value: int, name: string, color: string}>
1822
*/
1923
public function weeklyProjectOverview(Organization $organization, DashboardService $dashboardService): JsonResponse
2024
{
@@ -28,6 +32,10 @@ public function weeklyProjectOverview(Organization $organization, DashboardServi
2832

2933
/**
3034
* @throws AuthorizationException
35+
*
36+
* @operationId latestTasks
37+
*
38+
* @response array<int, array{task_id: string, name: string, description: string|null, status: bool, time_entry_id: string|null}>
3139
*/
3240
public function latestTasks(Organization $organization, DashboardService $dashboardService): JsonResponse
3341
{
@@ -41,6 +49,10 @@ public function latestTasks(Organization $organization, DashboardService $dashbo
4149

4250
/**
4351
* @throws AuthorizationException
52+
*
53+
* @operationId lastSevenDays
54+
*
55+
* @response array<int, array{ date: string, duration: int, history: array<int> }>
4456
*/
4557
public function lastSevenDays(Organization $organization, DashboardService $dashboardService): JsonResponse
4658
{
@@ -54,6 +66,10 @@ public function lastSevenDays(Organization $organization, DashboardService $dash
5466

5567
/**
5668
* @throws AuthorizationException
69+
*
70+
* @operationId latestTeamActivity
71+
*
72+
* @response array<int, array{member_id: string, name: string, description: string|null, time_entry_id: string, task_id: string|null, status: bool }>
5773
*/
5874
public function latestTeamActivity(Organization $organization, DashboardService $dashboardService, PermissionStore $permissionStore): JsonResponse
5975
{
@@ -66,6 +82,10 @@ public function latestTeamActivity(Organization $organization, DashboardService
6682

6783
/**
6884
* @throws AuthorizationException
85+
*
86+
* @operationId dailyTrackedHours
87+
*
88+
* @response array<int, array{date: string, duration: int}>
6989
*/
7090
public function dailyTrackedHours(Organization $organization, DashboardService $dashboardService): JsonResponse
7191
{
@@ -79,6 +99,10 @@ public function dailyTrackedHours(Organization $organization, DashboardService $
7999

80100
/**
81101
* @throws AuthorizationException
102+
*
103+
* @operationId totalWeeklyTime
104+
*
105+
* @response int
82106
*/
83107
public function totalWeeklyTime(Organization $organization, DashboardService $dashboardService): JsonResponse
84108
{
@@ -92,6 +116,10 @@ public function totalWeeklyTime(Organization $organization, DashboardService $da
92116

93117
/**
94118
* @throws AuthorizationException
119+
*
120+
* @operationId totalWeeklyBillableTime
121+
*
122+
* @response int
95123
*/
96124
public function totalWeeklyBillableTime(Organization $organization, DashboardService $dashboardService): JsonResponse
97125
{
@@ -105,6 +133,10 @@ public function totalWeeklyBillableTime(Organization $organization, DashboardSer
105133

106134
/**
107135
* @throws AuthorizationException
136+
*
137+
* @operationId totalWeeklyBillableAmount
138+
*
139+
* @response array{value: int, currency: string}
108140
*/
109141
public function totalWeeklyBillableAmount(Organization $organization, DashboardService $dashboardService): JsonResponse
110142
{
@@ -123,6 +155,10 @@ public function totalWeeklyBillableAmount(Organization $organization, DashboardS
123155

124156
/**
125157
* @throws AuthorizationException
158+
*
159+
* @operationId weeklyHistory
160+
*
161+
* @response array<int, array{date: string, duration: int}>
126162
*/
127163
public function weeklyHistory(Organization $organization, DashboardService $dashboardService): JsonResponse
128164
{

app/Http/Controllers/Web/DashboardController.php

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,6 @@ public function dashboard(DashboardService $dashboardService, PermissionStore $p
2020
{
2121
$user = $this->user();
2222
$organization = $this->currentOrganization();
23-
$dailyTrackedHours = $dashboardService->getDailyTrackedHours($user, $organization, 60);
24-
$weeklyHistory = $dashboardService->getWeeklyHistory($user, $organization);
25-
$totalWeeklyTime = $dashboardService->totalWeeklyTime($user, $organization);
26-
$totalWeeklyBillableTime = $dashboardService->totalWeeklyBillableTime($user, $organization);
27-
$totalWeeklyBillableAmount = $dashboardService->totalWeeklyBillableAmount($user, $organization);
28-
$weeklyProjectOverview = $dashboardService->weeklyProjectOverview($user, $organization);
29-
$latestTasks = $dashboardService->latestTasks($user, $organization);
30-
$lastSevenDays = $dashboardService->lastSevenDays($user, $organization);
3123

3224
$latestTeamActivity = null;
3325
if ($permissionStore->has($organization, 'time-entries:view:all')) {
@@ -36,16 +28,6 @@ public function dashboard(DashboardService $dashboardService, PermissionStore $p
3628

3729
$showBillableRate = $this->member($organization)->role !== Role::Employee->value || $organization->employees_can_see_billable_rates;
3830

39-
return Inertia::render('Dashboard', [
40-
'weeklyProjectOverview' => $weeklyProjectOverview,
41-
'latestTasks' => $latestTasks,
42-
'lastSevenDays' => $lastSevenDays,
43-
'latestTeamActivity' => $latestTeamActivity,
44-
'dailyTrackedHours' => $dailyTrackedHours,
45-
'totalWeeklyTime' => $totalWeeklyTime,
46-
'totalWeeklyBillableTime' => $totalWeeklyBillableTime,
47-
'totalWeeklyBillableAmount' => $showBillableRate ? $totalWeeklyBillableAmount : null,
48-
'weeklyHistory' => $weeklyHistory,
49-
]);
31+
return Inertia::render('Dashboard');
5032
}
5133
}

e2e/timetracker.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ test('test that starting and updating the time while running works', async ({
136136
await Promise.all([
137137
page.waitForResponse(async (response) => {
138138
return (
139+
response.url().includes('/time-entries') &&
139140
response.status() === 200 &&
140141
(await response.headerValue('Content-Type')) ===
141142
'application/json' &&

e2e/utils/currentTimeEntry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export function newTimeEntryResponse(
1818
) {
1919
return page.waitForResponse(async (response) => {
2020
return (
21+
response.url().includes('/time-entries') &&
2122
response.status() === status &&
2223
(await response.headerValue('Content-Type')) ===
2324
'application/json' &&

resources/js/Components/Dashboard/ActivityGraphCard.vue

Lines changed: 128 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,159 @@
11
<script lang="ts" setup>
2-
import VChart, { THEME_KEY } from 'vue-echarts';
3-
import { provide, ref } from 'vue';
4-
import { use } from 'echarts/core';
5-
import DashboardCard from '@/Components/Dashboard/DashboardCard.vue';
6-
import { BoltIcon } from '@heroicons/vue/20/solid';
7-
import { HeatmapChart } from 'echarts/charts';
2+
import VChart, { THEME_KEY } from "vue-echarts";
3+
import { provide, computed } from "vue";
4+
import { use } from "echarts/core";
5+
import DashboardCard from "@/Components/Dashboard/DashboardCard.vue";
6+
import { BoltIcon } from "@heroicons/vue/20/solid";
7+
import { HeatmapChart } from "echarts/charts";
88
import {
99
CalendarComponent,
1010
TitleComponent,
1111
TooltipComponent,
12-
VisualMapComponent,
13-
} from 'echarts/components';
14-
import { CanvasRenderer } from 'echarts/renderers';
15-
import dayjs from 'dayjs';
12+
VisualMapComponent
13+
} from "echarts/components";
14+
import { CanvasRenderer } from "echarts/renderers";
15+
import dayjs from "dayjs";
1616
import {
1717
firstDayIndex,
1818
formatDate,
1919
formatHumanReadableDuration,
20-
getDayJsInstance,
21-
} from '@/packages/ui/src/utils/time';
22-
import { useCssVar } from '@vueuse/core';
20+
getDayJsInstance
21+
} from "@/packages/ui/src/utils/time";
22+
import { useCssVar } from "@vueuse/core";
23+
import { useQuery } from "@tanstack/vue-query";
24+
import { getCurrentOrganizationId } from "@/utils/useUser";
25+
import { api } from "@/packages/api/src";
26+
import { LoadingSpinner } from "@/packages/ui/src";
27+
28+
// Get the organization ID using the utility function
29+
const organizationId = computed(() => getCurrentOrganizationId());
2330
24-
const props = defineProps<{
25-
dailyHoursTracked: { duration: number; date: string }[];
26-
}>();
31+
32+
const { data: dailyHoursTracked, isLoading } = useQuery({
33+
queryKey: ["dailyTrackedHours", organizationId],
34+
queryFn: () => {
35+
return api.dailyTrackedHours({
36+
params: {
37+
organization: organizationId.value!
38+
}
39+
});
40+
},
41+
enabled: computed(() => !!organizationId.value)
42+
});
2743
2844
use([
2945
TitleComponent,
3046
TooltipComponent,
3147
VisualMapComponent,
3248
CalendarComponent,
3349
HeatmapChart,
34-
CanvasRenderer,
50+
CanvasRenderer
3551
]);
3652
37-
provide(THEME_KEY, 'dark');
53+
provide(THEME_KEY, "dark");
3854
39-
const max = Math.max(
40-
Math.max(...props.dailyHoursTracked.map((el) => el.duration)),
41-
1
55+
const max = computed(() => {
56+
if (!isLoading.value && dailyHoursTracked.value) {
57+
return Math.max(
58+
Math.max(...dailyHoursTracked.value.map((el) => el.duration)),
59+
1
60+
);
61+
} else {
62+
return 1;
63+
}
64+
}
4265
);
4366
44-
const backgroundColor = useCssVar('--color-bg-secondary');
45-
const itemBackgroundColor = useCssVar('--color-bg-tertiary');
46-
const option = ref({
47-
tooltip: {},
48-
visualMap: {
49-
min: 0,
50-
max: max,
51-
type: 'piecewise',
52-
orient: 'horizontal',
53-
left: 'center',
54-
top: 'center',
55-
inRange: {
56-
color: [itemBackgroundColor.value, '#2DBE45'],
57-
},
58-
show: false,
59-
},
60-
calendar: {
61-
top: 40,
62-
bottom: 20,
63-
left: 40,
64-
right: 10,
65-
cellSize: [40, 40],
66-
dayLabel: {
67-
firstDay: firstDayIndex.value,
68-
},
69-
splitLine: {
70-
show: false,
71-
},
72-
range: [
73-
dayjs().format('YYYY-MM-DD'),
74-
getDayJsInstance()()
75-
.subtract(50, 'day')
76-
.startOf('week')
77-
.format('YYYY-MM-DD'),
78-
],
79-
itemStyle: {
80-
color: 'transparent',
81-
borderWidth: 8,
82-
borderColor: backgroundColor.value,
83-
},
84-
yearLabel: { show: false },
85-
},
86-
series: {
87-
type: 'heatmap',
88-
coordinateSystem: 'calendar',
89-
data: props.dailyHoursTracked.map((el) => [el.date, el.duration]),
90-
itemStyle: {
91-
borderRadius: 5,
92-
borderColor: 'rgba(255,255,255,0.05)',
93-
borderWidth: 1,
94-
},
95-
tooltip: {
96-
valueFormatter: (value: number, dataIndex: number) => {
97-
return (
98-
formatDate(props.dailyHoursTracked[dataIndex].date) +
99-
': ' +
100-
formatHumanReadableDuration(value)
101-
);
67+
const backgroundColor = useCssVar("--color-bg-secondary");
68+
const itemBackgroundColor = useCssVar("--color-bg-tertiary");
69+
const option = computed(() => {
70+
return {
71+
tooltip: {},
72+
visualMap: {
73+
min: 0,
74+
max: max.value,
75+
type: "piecewise",
76+
orient: "horizontal",
77+
left: "center",
78+
top: "center",
79+
inRange: {
80+
color: [itemBackgroundColor.value, "#2DBE45"]
81+
},
82+
show: false
10283
},
103-
},
104-
},
105-
backgroundColor: 'transparent',
106-
});
84+
calendar: {
85+
top: 40,
86+
bottom: 20,
87+
left: 40,
88+
right: 10,
89+
cellSize: [40, 40],
90+
dayLabel: {
91+
firstDay: firstDayIndex.value
92+
},
93+
splitLine: {
94+
show: false
95+
},
96+
range: [
97+
dayjs().format("YYYY-MM-DD"),
98+
getDayJsInstance()()
99+
.subtract(50, "day")
100+
.startOf("week")
101+
.format("YYYY-MM-DD")
102+
],
103+
itemStyle: {
104+
color: "transparent",
105+
borderWidth: 8,
106+
borderColor: backgroundColor.value
107+
},
108+
yearLabel: { show: false }
109+
},
110+
series: {
111+
type: "heatmap",
112+
coordinateSystem: "calendar",
113+
data: dailyHoursTracked?.value?.map((el) => [el.date, el.duration]) ?? [],
114+
itemStyle: {
115+
borderRadius: 5,
116+
borderColor: "rgba(255,255,255,0.05)",
117+
borderWidth: 1
118+
},
119+
tooltip: {
120+
valueFormatter: (value: number, dataIndex: number) => {
121+
if(dailyHoursTracked?.value){
122+
return (
123+
formatDate(dailyHoursTracked?.value[dataIndex].date) +
124+
": " +
125+
formatHumanReadableDuration(value)
126+
);
127+
}
128+
else {
129+
return "";
130+
}
131+
132+
}
133+
}
134+
},
135+
backgroundColor: "transparent"
136+
};
137+
});
138+
107139
</script>
108140

109141
<template>
110142
<DashboardCard title="Activity Graph" :icon="BoltIcon">
111143
<div class="px-2">
112-
<v-chart
113-
class="chart"
114-
:autoresize="true"
115-
:option="option"
116-
style="height: 260px; background-color: transparent" />
144+
<div v-if="isLoading" class="flex justify-center items-center h-40">
145+
<LoadingSpinner />
146+
</div>
147+
<div v-else-if="dailyHoursTracked">
148+
<v-chart
149+
class="chart"
150+
:autoresize="true"
151+
:option="option"
152+
style="height: 260px; background-color: transparent" />
153+
</div>
154+
<div v-else class="text-center text-gray-500 py-8">
155+
No activity data available
156+
</div>
117157
</div>
118158
</DashboardCard>
119159
</template>

0 commit comments

Comments
 (0)