Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow disabling arbitrary dates in vaadin-date-picker via isDateAvailable property #5252

Closed
wants to merge 5 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Jan 6, 2023

Description

This change updates the vaadin-date-picker to allow disabling arbitrary dates via a new isDateAvailable property. This property is a function

Fixes #1820 but see this platform issue for specific discussion: vaadin/platform#2867

This PR only addresses the UX-frontend portion. This PR does not attempt to address the Java API side.

Type of change

  • Bugfix
  • Feature

Checklist

  • I have read the contribution guide: https://vaadin.com/docs/latest/contributing/overview
  • I have added a description following the guideline.
  • The issue is created in the corresponding repository and I have referenced it.
  • I have added tests to ensure my change is effective and works as intended.
  • New and existing tests are passing locally with my change.
  • I have performed self-review and corrected misspellings.

Additional for Feature type of change

  • Enhancement / new feature was discussed in a corresponding GitHub issue and Acceptance Criteria were created.

@ghost
Copy link
Author

ghost commented Jan 6, 2023

I went ahead and pushed up a draft of my changes even though I haven't added the tests yet. I wanted a starting point to discuss issue #1820, specifically the comments in the related platform issue where the discussion includes whether we change the Java API.

Our team doesn't use the Java/hilla code at all, but we understand the general use case for validators that are hosted on the API side. However, for this specific use-case, we all questioned why anyone would really want a server-side isDateAvailable function because it is going to get hit hundreds of times in rapid succession as it pre-renders months worth of month data in preparation for scrolling. Is is really realistic to expect we want the performance hit of Java-side logic for this specific case?

@sonarcloud
Copy link

sonarcloud bot commented Jan 17, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@ghost ghost marked this pull request as ready for review January 17, 2023 22:12
Copy link
Contributor

@sissbruecker sissbruecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review.

The overall approach of introducing a customizable function makes sense to me, and should be a sufficient basis for introducing the same feature in the Flow API. Some API could be improved, and there are some missing tests.

@@ -235,6 +235,11 @@ export declare class DatePickerMixinClass {
*/
max: string | undefined;

/**
* Function to override the default function for determining if a date is available.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the same description as in the JSDoc here.

Comment on lines +287 to +312
/**
* A function that is used to determine if a date should be disabled.
*
* @type {function(Date): boolean | undefined}
*/
isDateAvailable: {
type: Function,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Since the main purpose of the new feature is to disable specific dates, I think it would make more sense to name this to isDateDisabled.

  2. While passing a date instance is reasonable, I think for consistency we should align this with other functions that can be configured currently: formatDate and parseDate via the i18n property. Those take and return an object of the form: { year: number, month: number, day: number }.

  3. The param should also be documented in some detail in the JSDoc.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commenting here even though I'm moving to a new PR. Are you sure we should make the object sent to the isDateDisabled function the DatePickerDate interface? The reason I ask is the main place this gets called is in vaadin-date-picker-helper in the dateAllowed function. That function receives a Javascript Date rather than a vaadin DatePickerDate shape.

export function dateAllowed(date, min, max) {
return (!min || date >= min) && (!max || date <= max);
export function dateAllowed(date, min, max, isDateAvailable) {
const dateIsAvailable = isDateAvailable && typeof isDateAvailable === 'function' ? isDateAvailable(date) : true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const dateIsAvailable = isDateAvailable && typeof isDateAvailable === 'function' ? isDateAvailable(date) : true;
const dateIsAvailable = typeof isDateAvailable === 'function' ? isDateAvailable(date) : true;

The typeof check should be enough.

@@ -61,8 +61,9 @@ export function dateEquals(date1, date2) {
* @param {Date} max Range end
* @return {boolean} True if the date is in the range
*/
export function dateAllowed(date, min, max) {
return (!min || date >= min) && (!max || date <= max);
export function dateAllowed(date, min, max, isDateAvailable) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add the new parameter to the JSDoc.

Comment on lines 543 to +603
const minMaxValid = !this._selectedDate || dateAllowed(this._selectedDate, this._minDate, this._maxDate);
const isDateAvailableValid = this.isDateAvailable ? this.isDateAvailable(this._selectedDate) : true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since dateAllowed is capable of checking for whether the date should be disabled, it seems unnecessary to call isDateAvailable separately. Instead, I would suggest to pass the function into dateAllowed, and generalize the constant name from minMaxValid to something more general like isDateValid.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much cleaner.

_dateAllowed(date, min = this.minDate, max = this.maxDate) {
return (!min || date >= min) && (!max || date <= max);
_dateAllowed(date, min = this.minDate, max = this.maxDate, isDateAvailable = this.isDateAvailable) {
return (!min || date >= min) && (!max || date <= max) && (!isDateAvailable || isDateAvailable(date))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to reuse the typeof check here, as it's more precise than checking for a falsy value.

}

__getDayAriaDisabled(date, min, max) {
__getDayAriaDisabled(date, min, max, isDateAvailable) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like the new function is properly passed to this method.

Also indicates a missing test, it looks like month calendar attributes like part and aria-disabled are currently covered by snapshot tests, so a new snapshot test should be added there.

@@ -214,6 +214,24 @@ describe('validation', () => {
datePicker._overlayContent._selectDate(new Date('2017-01-01')); // Invalid
});

it('should reflect correct invalid value on value-changed eventListener when using isDateAvailable', (done) => {
Copy link
Contributor

@sissbruecker sissbruecker May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some additional tests for the max attribute, respective tests for the new function should be added:

  • it('should validate when the field has max', async () => {
    datePicker.max = '2020-01-01';
    document.body.appendChild(datePicker);
    await nextRender();
    expect(validateSpy.calledOnce).to.be.true;
    });
  • it('should not validate on max change when no value is provided', () => {
    datePicker.max = '2020-01-01';
    expect(validateSpy.called).to.be.false;
    });
    it('should validate on max change when a value is provided', () => {
    datePicker.value = '2020-01-01';
    validateSpy.resetHistory();
    datePicker.max = '2020-01-01';
    expect(validateSpy.calledOnce).to.be.true;
    });

@ghost
Copy link
Author

ghost commented May 19, 2023

The company I work for has pivoted away from using the vaadin-date-picker so we don't have cycles to put to this PR. I'm closing it and if anyone wants to pick up the work they are free to take the work done here and update it per the review comments.

@ghost ghost closed this May 19, 2023
@ghost ghost reopened this Sep 11, 2023
@ghost
Copy link
Author

ghost commented Sep 11, 2023

Re-opening. We have pivoted back to this web component so we'll polish up the PR and get the remaining tests working so we can have this functionality working.

@sonarcloud
Copy link

sonarcloud bot commented Sep 20, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@ghost ghost closed this Sep 20, 2023
@ghost ghost deleted the master branch September 20, 2023 16:51
@ghost
Copy link
Author

ghost commented Sep 21, 2023

I'll create a new PR. Needed to rebase and the renaming of master to main in vaadin meant I needed to follow suit in my PR to get the tests to run correctly.

@ghost ghost mentioned this pull request Oct 5, 2023
10 tasks
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[date-picker] Add support for disabled dates
2 participants