diff --git a/app/Http/Requests/AnswerFormRequest.php b/app/Http/Requests/AnswerFormRequest.php index 7cd1f3b..999586f 100644 --- a/app/Http/Requests/AnswerFormRequest.php +++ b/app/Http/Requests/AnswerFormRequest.php @@ -152,15 +152,25 @@ class AnswerFormRequest extends FormRequest return ['email:filter']; case 'date': if (isset($property['date_range']) && $property['date_range']) { - $this->requestRules[$property['id'].'.*'] = ['date']; - return ['array']; + $this->requestRules[$property['id'].'.*'] = $this->getRulesForDate($property); + return ['array', 'min:2']; } - return ['date']; + return $this->getRulesForDate($property); default: return []; } } + private function getRulesForDate($property) + { + if (isset($property['disable_past_dates']) && $property['disable_past_dates']) { + return ['date', 'after_or_equal:today']; + }else if (isset($property['disable_future_dates']) && $property['disable_future_dates']) { + return ['date', 'before_or_equal:today']; + } + return ['date']; + } + private function getSelectPropertyOptions($property): array { $type = $property['type']; diff --git a/app/Http/Requests/UserFormRequest.php b/app/Http/Requests/UserFormRequest.php index e5fd267..ea9a0df 100644 --- a/app/Http/Requests/UserFormRequest.php +++ b/app/Http/Requests/UserFormRequest.php @@ -102,6 +102,8 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest 'properties.*.use_am_pm' => 'boolean|nullable', 'properties.*.date_range' => 'boolean|nullable', 'properties.*.prefill_today' => 'boolean|nullable', + 'properties.*.disable_past_dates' => 'boolean|nullable', + 'properties.*.disable_future_dates' => 'boolean|nullable', // Select / Multi Select field 'properties.*.allow_creation' => 'boolean|nullable', diff --git a/resources/js/components/forms/DateInput.vue b/resources/js/components/forms/DateInput.vue index abddb1c..15e0ac7 100644 --- a/resources/js/components/forms/DateInput.vue +++ b/resources/js/components/forms/DateInput.vue @@ -13,6 +13,7 @@ :date-format="useTime?'Z':'Y-m-d'" :user-format="useTime ? amPm ? 'F j, Y - G:i K' : 'F j, Y - H:i' : 'F j, Y'" :amPm="amPm" + :disabled-dates="disabledDates" /> {{ help }} @@ -32,7 +33,9 @@ export default { props: { withTime: { type: Boolean, default: false }, dateRange: { type: Boolean, default: false }, - amPm: { type: Boolean, default: false } + amPm: { type: Boolean, default: false }, + disablePastDates: { type: Boolean, default: false }, + disableFutureDates: { type: Boolean, default: false } }, data: () => ({ @@ -74,6 +77,15 @@ export default { const dateInput = this.$refs.datepicker.$el.getElementsByTagName('input')[0] dateInput.style.setProperty('--tw-ring-color', this.color) } + }, + disabledDates (date) { + const today = new Date() + if(this.disablePastDates){ + return new Date(date.getFullYear(), date.getMonth(), date.getDate()) < new Date(today.getFullYear(), today.getMonth(), today.getDate()) + } else if(this.disableFutureDates){ + return new Date(date.getFullYear(), date.getMonth(), date.getDate()) > new Date(today.getFullYear(), today.getMonth(), today.getDate()) + } + return false; } } } diff --git a/resources/js/components/open/forms/OpenForm.vue b/resources/js/components/open/forms/OpenForm.vue index 16bf259..9481e92 100644 --- a/resources/js/components/open/forms/OpenForm.vue +++ b/resources/js/components/open/forms/OpenForm.vue @@ -378,6 +378,11 @@ export default { if (field.use_am_pm) { inputProperties.amPm = true } + if (field.disable_past_dates) { + inputProperties.disablePastDates = true + }else if (field.disable_future_dates) { + inputProperties.disableFutureDates = true + } } else if (field.type === 'files' || (field.type === 'url' && field.file_upload)) { inputProperties.multiple = (field.multiple !== undefined && field.multiple) inputProperties.mbLimit = 5 diff --git a/resources/js/components/open/forms/fields/FormFieldOptionsModal.vue b/resources/js/components/open/forms/fields/FormFieldOptionsModal.vue index fba165a..b37cbb5 100644 --- a/resources/js/components/open/forms/fields/FormFieldOptionsModal.vue +++ b/resources/js/components/open/forms/fields/FormFieldOptionsModal.vue @@ -167,6 +167,20 @@

if enabled we will pre-fill this field with the current date

+ + + Disable past dates + + + + Disable future dates + @@ -484,6 +498,8 @@ export default { if (this.field.prefill_today) { this.$set(this.field, 'prefill', 'Pre-filled with current date') this.$set(this.field, 'date_range', false) + this.$set(this.field, 'disable_future_dates', false) + this.$set(this.field, 'disable_past_dates', false) } else { this.$set(this.field, 'prefill', null) } @@ -500,6 +516,20 @@ export default { this.$set(this.field, 'allow_creation', false) } }, + onFieldDisablePastDatesChange (val) { + this.$set(this.field, 'disable_past_dates', val) + if (this.field.disable_past_dates) { + this.$set(this.field, 'disable_future_dates', false) + this.$set(this.field, 'prefill_today', false) + } + }, + onFieldDisableFutureDatesChange (val) { + this.$set(this.field, 'disable_future_dates', val) + if (this.field.disable_future_dates) { + this.$set(this.field, 'disable_past_dates', false) + this.$set(this.field, 'prefill_today', false) + } + } } } diff --git a/tests/Feature/Forms/AnswerFormTest.php b/tests/Feature/Forms/AnswerFormTest.php index b89c820..8d6d98b 100644 --- a/tests/Feature/Forms/AnswerFormTest.php +++ b/tests/Feature/Forms/AnswerFormTest.php @@ -83,4 +83,52 @@ it('can not submit draft form', function () { $this->postJson(route('forms.answer', $form->slug), $formData) ->assertStatus(403); +}); + +it('can not submit form with past dates', function () { + $user = $this->actingAsUser(); + $workspace = $this->createUserWorkspace($user); + $form = $this->createForm($user, $workspace); + + $submissionData = []; + $form->properties = collect($form->properties)->map(function ($property) use (&$submissionData) { + if(in_array($property['type'], ['date'])){ + $property["disable_past_dates"] = true; + $submissionData[$property['id']] = now()->subDays(4)->format('Y-m-d'); + } + return $property; + })->toArray(); + $form->update(); + + $formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData); + + $this->postJson(route('forms.answer', $form->slug), $formData) + ->assertStatus(422) + ->assertJson([ + 'message' => 'The Date must be a date after or equal to today.' + ]); +}); + +it('can not submit form with future dates', function () { + $user = $this->actingAsUser(); + $workspace = $this->createUserWorkspace($user); + $form = $this->createForm($user, $workspace); + + $submissionData = []; + $form->properties = collect($form->properties)->map(function ($property) use (&$submissionData) { + if(in_array($property['type'], ['date'])){ + $property["disable_future_dates"] = true; + $submissionData[$property['id']] = now()->addDays(4)->format('Y-m-d'); + } + return $property; + })->toArray(); + $form->update(); + + $formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData); + + $this->postJson(route('forms.answer', $form->slug), $formData) + ->assertStatus(422) + ->assertJson([ + 'message' => 'The Date must be a date before or equal to today.' + ]); }); \ No newline at end of file