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 @@ class ReportController extends Controller
$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/resources/js/Components/Common/Report/ReportCreateModal.vue b/resources/js/Components/Common/Report/ReportCreateModal.vue
index 1d4ecd7b..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',
@@ -109,7 +114,10 @@ async function submit() {
(optional)
-
+
diff --git a/resources/js/Components/Common/Report/ReportEditModal.vue b/resources/js/Components/Common/Report/ReportEditModal.vue
index 3224fd55..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,9 +126,10 @@ async function submit() {
v-if="report.is_public"
class="flex items-center space-x-4">
-
+
diff --git a/resources/js/packages/ui/src/Input/DatePicker.vue b/resources/js/packages/ui/src/Input/DatePicker.vue
index 7259e0e7..1ea265b5 100644
--- a/resources/js/packages/ui/src/Input/DatePicker.vue
+++ b/resources/js/packages/ui/src/Input/DatePicker.vue
@@ -30,7 +30,9 @@ const handleChange = (date: DateValue | undefined) => {
return;
}
- const dayjs = getLocalizedDayJs(model.value);
+ const dayjs = model.value
+ ? getLocalizedDayJs(model.value)
+ : getLocalizedDayJs();
model.value = dayjs
.year(date.year)
.month(date.month - 1) // CalendarDate uses 1-based months
@@ -62,12 +64,15 @@ const organization = inject>('organization');
]"
:tabindex="tabindex">
+ :class="[
+ size === 'xs'
+ ? 'h-3 w-3'
+ : size === 'sm'
+ ? 'h-3 w-3'
+ : size === 'lg'
+ ? 'h-4.5 w-4.5'
+ : 'h-4 w-4',
+ ]" />
{{
model
diff --git a/tests/Unit/Endpoint/Api/V1/ReportEndpointTest.php b/tests/Unit/Endpoint/Api/V1/ReportEndpointTest.php
index 0239e050..8c54c346 100644
--- a/tests/Unit/Endpoint/Api/V1/ReportEndpointTest.php
+++ b/tests/Unit/Endpoint/Api/V1/ReportEndpointTest.php
@@ -340,6 +340,35 @@ class ReportEndpointTest extends ApiEndpointTestAbstract
);
}
+ public function test_update_endpoint_can_update_public_until_without_changing_secret(): void
+ {
+ // Arrange
+ $data = $this->createUserWithPermission([
+ 'reports:update',
+ ]);
+ $report = Report::factory()->public()->forOrganization($data->organization)->create();
+ $secret = $report->share_secret;
+ $newPublicUntil = Carbon::now()->addDays(30)->toIso8601ZuluString();
+ Passport::actingAs($data->user);
+
+ // Act
+ $response = $this->putJson(route('api.v1.reports.update', [$data->organization->getKey(), $report->getKey()]), [
+ 'public_until' => $newPublicUntil,
+ ]);
+
+ // Assert
+ $report->refresh();
+ $this->assertTrue($report->is_public);
+ $this->assertSame($secret, $report->share_secret);
+ $this->assertSame($newPublicUntil, $report->public_until->toIso8601ZuluString());
+ $response->assertStatus(200);
+ $response->assertJson(fn (AssertableJson $json) => $json
+ ->has('data')
+ ->where('data.is_public', true)
+ ->where('data.shareable_link', $report->getShareableLink())
+ );
+ }
+
public function test_update_endpoint_can_update_the_report_all_properties_set(): void
{
// Arrange