diff --git a/app/Http/Controllers/Api/V1/ReportController.php b/app/Http/Controllers/Api/V1/ReportController.php index 46fe7208..5a53fb64 100644 --- a/app/Http/Controllers/Api/V1/ReportController.php +++ b/app/Http/Controllers/Api/V1/ReportController.php @@ -148,6 +148,8 @@ public function update(Organization $organization, Report $report, ReportUpdateR $report->share_secret = null; $report->public_until = null; } + } elseif ($report->is_public && $request->has('public_until')) { + $report->public_until = $request->getPublicUntil(); } $report->save(); diff --git a/e2e/organization.spec.ts b/e2e/organization.spec.ts index ebb4a539..3b1e046e 100644 --- a/e2e/organization.spec.ts +++ b/e2e/organization.spec.ts @@ -230,7 +230,9 @@ test('test that format settings are reflected in the dashboard', async ({ await expect(page.getByText('0.00€')).toBeVisible(); // check that 00:00 is displayed - await expect(page.getByText('0:00', { exact: true }).nth(0)).toBeVisible(); + await expect( + page.getByText('0:00 h', { exact: true }).nth(0) + ).toBeVisible(); // check that 0h 00min is not displayed await expect( page.getByText('0h 00min', { exact: true }).nth(0) diff --git a/e2e/projects.spec.ts b/e2e/projects.spec.ts index 156d66e6..d30ac382 100644 --- a/e2e/projects.spec.ts +++ b/e2e/projects.spec.ts @@ -102,7 +102,7 @@ test('test that updating billable rate works with existing time entries', async await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('menuitem').getByText('Edit').first().click(); - await page.getByText('Non-Billable').click(); + await page.getByText('Non-Billable').click(); await page.getByText('Custom Rate').click(); await page .getByPlaceholder('Billable Rate') @@ -136,6 +136,49 @@ test('test that updating billable rate works with existing time entries', async ).toBeVisible(); }); +test('test that creating and updating project time estimate works', async ({ page }) => { + const newProjectName = 'New Project ' + Math.floor(1 + Math.random() * 10000); + const timeEstimate = '10'; + + await goToProjectsOverview(page); + await page.getByRole('button', { name: 'Create Project' }).click(); + await page.getByLabel('Project Name').fill(newProjectName); + await page.getByLabel('Time Estimated').fill(timeEstimate); + + await Promise.all([ + page.getByRole('button', { name: 'Create Project' }).click(), + page.waitForResponse( + async (response) => + response.url().includes('/projects') && + response.request().method() === 'POST' && + response.status() === 201 && + (await response.json()).data.estimated_time === parseInt(timeEstimate) * 60 * 60 + ), + ]); + + // Check that time estimate is displayed in the projects table + await expect(page.getByTestId('project_table')).toContainText(timeEstimate + 'h'); + + // Edit project to remove time estimate + await page.getByRole('row').first().getByRole('button').click(); + await page.getByRole('menuitem').getByText('Edit').first().click(); + await page.getByLabel('Time Estimated').fill(''); + + await Promise.all([ + page.getByRole('button', { name: 'Update Project' }).click(), + page.waitForResponse( + async (response) => + response.url().includes('/projects') && + response.request().method() === 'PUT' && + response.status() === 200 && + (await response.json()).data.estimated_time === null + ), + ]); + + // Check that time estimate is no longer displayed + await expect(page.getByTestId('project_table')).not.toContainText(timeEstimate + 'h'); +}); + // Create new project with new Client // Create new project with existing Client diff --git a/resources/js/Components/Common/Report/ReportCreateModal.vue b/resources/js/Components/Common/Report/ReportCreateModal.vue index 085b7989..c21f1693 100644 --- a/resources/js/Components/Common/Report/ReportCreateModal.vue +++ b/resources/js/Components/Common/Report/ReportCreateModal.vue @@ -15,6 +15,7 @@ import { api } from '@/packages/api/src'; import { Checkbox } from '@/packages/ui/src'; import DatePicker from '@/packages/ui/src/Input/DatePicker.vue'; import { useNotificationsStore } from '@/utils/notification'; +import { getLocalizedDayJs } from '@/packages/ui/src/utils/time'; const show = defineModel('show', { default: false }); const saving = ref(false); @@ -47,10 +48,14 @@ const report = ref({ const { handleApiRequestNotifications } = useNotificationsStore(); async function submit() { + const { public_until, ...reportProperties } = report.value; await handleApiRequestNotifications( () => createReportMutation.mutateAsync({ - ...report.value, + ...reportProperties, + public_until: public_until + ? getLocalizedDayJs(public_until).utc().format() + : null, properties: { ...props.properties }, }), 'Success', @@ -103,13 +108,16 @@ async function submit() {
-
+
(optional)
- +
diff --git a/resources/js/Components/Common/Report/ReportEditModal.vue b/resources/js/Components/Common/Report/ReportEditModal.vue index 6d9b161d..cbef9692 100644 --- a/resources/js/Components/Common/Report/ReportEditModal.vue +++ b/resources/js/Components/Common/Report/ReportEditModal.vue @@ -13,6 +13,7 @@ import { Checkbox } from '@/packages/ui/src'; import DatePicker from '@/packages/ui/src/Input/DatePicker.vue'; import { useNotificationsStore } from '@/utils/notification'; import type { Report } from '@/packages/api/src'; +import { getLocalizedDayJs } from '@/packages/ui/src/utils/time'; const show = defineModel('show', { default: false }); const saving = ref(false); @@ -64,8 +65,15 @@ watch( const { handleApiRequestNotifications } = useNotificationsStore(); async function submit() { + const { public_until, ...reportProperties } = report.value; await handleApiRequestNotifications( - () => updateReportMutation.mutateAsync(report.value), + () => + updateReportMutation.mutateAsync({ + ...reportProperties, + public_until: public_until + ? getLocalizedDayJs(public_until).utc().format() + : null, + }), 'Success', 'Error', () => { @@ -118,7 +126,10 @@ async function submit() { v-if="report.is_public" class="flex items-center space-x-4"> - + diff --git a/resources/js/Pages/Time.vue b/resources/js/Pages/Time.vue index 1d011e6f..7d02016f 100644 --- a/resources/js/Pages/Time.vue +++ b/resources/js/Pages/Time.vue @@ -119,7 +119,8 @@ function deleteSelected() {