Skip to content

Commit

Permalink
feat: Date Filter: Custom date-time range [GAUD-6474] (#4752)
Browse files Browse the repository at this point in the history
  • Loading branch information
margaree authored Jun 24, 2024
1 parent dafb89a commit b745726
Show file tree
Hide file tree
Showing 57 changed files with 345 additions and 27 deletions.
11 changes: 8 additions & 3 deletions components/filter/demo/filter.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
import '../../filter/filter-dimension-set-empty-state.js';
import '../../filter/filter-dimension-set-value.js';
import '../../filter/filter-dimension-set-date-text-value.js';
import '../../filter/filter-dimension-set-date-time-range-value.js';
import './filter-search-demo.js';
import './filter-load-more-demo.js';
</script>
<script>
window.D2L = { LP: { Web: { UI: { Flags: { Flag: () => true } } } } };
</script>
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1.0">
<meta charset="UTF-8">
</head>
Expand Down Expand Up @@ -162,11 +166,12 @@ <h2>Date Filter</h2>
<template>
<d2l-filter id="filter-single">
<d2l-filter-dimension-set key="dates" text="Dates">
<d2l-filter-dimension-set-value key="lastweek" text="Last Week"></d2l-filter-dimension-set-value>
<d2l-filter-dimension-set-date-text-value key="lastHour" range="lastHour" selected></d2l-filter-dimension-set-date-text-value>
<d2l-filter-dimension-set-value key="lastweek" text="Last 7 days"></d2l-filter-dimension-set-value>
<d2l-filter-dimension-set-date-text-value key="lastHour" range="lastHour" ></d2l-filter-dimension-set-date-text-value>
<d2l-filter-dimension-set-date-text-value key="48hours" range="48hours" disabled></d2l-filter-dimension-set-date-text-value>
<d2l-filter-dimension-set-date-text-value key="14days" range="14days"></d2l-filter-dimension-set-date-text-value>
<d2l-filter-dimension-set-date-text-value key="today" range="today"></d2l-filter-dimension-set-date-text-value>
<d2l-filter-dimension-set-date-text-value key="6months" range="6months"></d2l-filter-dimension-set-date-text-value>
<d2l-filter-dimension-set-date-time-range-value key="custom" ></d2l-filter-dimension-set-date-time-range-value>
</d2l-filter-dimension-set>
</d2l-filter>
</template>
Expand Down
134 changes: 134 additions & 0 deletions components/filter/filter-dimension-set-date-time-range-value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import '../inputs/input-date-time-range.js';
import { html, LitElement } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';

/**
* A component to represent a possible custom date range or date-time range value that can be selected for a dimension set (the main filter dimension type).
* The start-value and end-value will be included in the d2l-filter-change event and formatted as an ISO string in UTC time.
* This component does not render anything, but instead gathers data needed for the d2l-filter.
*/
class FilterDimensionSetDateTimeRangeValue extends LocalizeCoreElement(LitElement) {

static get properties() {
return {
/**
* Whether this value in the filter is disabled or not
* @type {boolean}
*/
disabled: { type: Boolean, reflect: true },
/**
* @ignore
*/
endValue: { type: String, attribute: 'end-value' },
/**
* REQUIRED: Unique key to represent this value in the dimension
* @type {string}
*/
key: { type: String },
/**
* Whether this value in the filter is selected or not
* @type {boolean}
*/
selected: { type: Boolean, reflect: true },
/**
* @ignore
*/
startValue: { type: String, attribute: 'start-value' },
/**
* Defaults to "Custom Date Range" (localized). Can be overridden if desired.
* @type {string}
*/
text: { type: String, reflect: true }
};
}

constructor() {
super();
this.disabled = false;
this.selected = false;
this._dispatchFilterChangeEvent = false;
this._enforceSingleSelection = true;
this._filterSetValue = true;
this._minWidth = 375;
this._noSearchSupport = true;

this._handleDateChange = this._handleDateChange.bind(this);
}

firstUpdated(changedProperties) {
super.firstUpdated(changedProperties);

this.text = this.text || this.localize('components.filter-dimension-set-date-time-range-value.text');
}

updated(changedProperties) {
super.updated(changedProperties);

const changes = new Map();
let shouldDispatchChangeEvent = false;
changedProperties.forEach((oldValue, prop) => {
if (oldValue === undefined && (prop === 'selected' || prop === 'disabled')) return;
if (this._dispatchFilterChangeEvent && (prop === 'startValue' || prop === 'endValue')) shouldDispatchChangeEvent = true;

if (prop === 'disabled' || prop === 'selected' || prop === 'startValue' || prop === 'endValue' || prop === 'text') {
changes.set(prop, this[prop]);
}
});
if (changes.size > 0) {
/** @ignore */
this.dispatchEvent(new CustomEvent('d2l-filter-dimension-set-value-data-change', {
detail: { valueKey: this.key, changes: changes, dispatchChangeEvent: shouldDispatchChangeEvent },
bubbles: true,
composed: false
}));
this._dispatchFilterChangeEvent = false;
}
}

getValueDetails() {
return {
disabled: this.disabled,
key: this.key,
selected: this.selected,
text: this.text,
additionalContent: this._getAdditionalContent.bind(this),
getAdditionalEventDetails: this._getAdditionalEventDetails.bind(this),
clearProperties: this._clearProperties.bind(this)
};
}

_clearProperties() {
this.startValue = undefined;
this.endValue = undefined;
}

_getAdditionalContent() {
return html`
<d2l-input-date-time-range
@change="${this._handleDateChange}"
child-labels-hidden
data-dimensionvaluekey="${this.key}"
end-value="${ifDefined(this.endValue)}"
label="Custom Range"
label-hidden
prefer-fixed-positioning
start-value="${ifDefined(this.startValue)}"
></d2l-input-date-time-range>
`;
}

_getAdditionalEventDetails(selected) {
if (!selected) return {};
return { startValue: this.startValue, endValue: this.endValue };
}

async _handleDateChange(e) {
this.startValue = e.target.startValue;
this.endValue = e.target.endValue;

this._dispatchFilterChangeEvent = true;
}
}

customElements.define('d2l-filter-dimension-set-date-time-range-value', FilterDimensionSetDateTimeRangeValue);
9 changes: 8 additions & 1 deletion components/filter/filter-dimension-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class FilterDimensionSet extends LitElement {
* @type {boolean}
*/
loading: { type: Boolean },
/**
* @ignore
*/
minWidth: { type: Number },
/**
* Whether to hide the search input, perform a simple text search, or fire an event on search
* @type {'none'|'automatic'|'manual'}
Expand Down Expand Up @@ -138,14 +142,17 @@ class FilterDimensionSet extends LitElement {
const valueNodes = this._getSlottedNodes();
let noSearchSupport = false;
let enforceSingleSelection = false;
let minWidth = undefined;
const values = valueNodes.map(value => {
if (value._noSearchSupport) noSearchSupport = true;
if (value._enforceSingleSelection) enforceSingleSelection = true;
if (value._minWidth) minWidth = value._minWidth;

return value.getValueDetails();
});
if (noSearchSupport) this.searchType = 'none';
if (enforceSingleSelection) this.selectionSingle = true;
if (minWidth) this.minWidth = minWidth;
return values;
}

Expand Down Expand Up @@ -182,7 +189,7 @@ class FilterDimensionSet extends LitElement {

_handleDimensionSetValueDataChange(e) {
e.stopPropagation();
this._dispatchDataChangeEvent({ dimensionKey: this.key, valueKey: e.detail.valueKey, changes: e.detail.changes });
this._dispatchDataChangeEvent({ dimensionKey: this.key, valueKey: e.detail.valueKey, changes: e.detail.changes, dispatchChangeEvent: e.detail.dispatchChangeEvent });
}

_handleSearchEmptyStateSlotChange(e) {
Expand Down
32 changes: 26 additions & 6 deletions components/filter/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { SubscriberRegistryController } from '../../controllers/subscriber/subsc

const ARROWLEFT_KEY_CODE = 37;
const ESCAPE_KEY_CODE = 27;
const FILTER_CONTENT_CLASS = 'd2l-filter-dropdown-content';
const SET_DIMENSION_ID_PREFIX = 'list-';

/**
Expand Down Expand Up @@ -67,6 +68,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
text: { type: String },
_activeDimensionKey: { type: String, attribute: false },
_dimensions: { type: Array, attribute: false },
_minWidth: { type: Number, attribute: false },
_totalAppliedCount: { type: Number, attribute: false }
};
}
Expand Down Expand Up @@ -144,8 +146,8 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
flex-shrink: 0;
}
d2l-expand-collapse-content[expanded] {
margin-inline-start: -2rem;
padding-block: 0.5rem;
padding-inline: 0.2rem;
}
.d2l-filter-dimension-set-value-text {
Expand Down Expand Up @@ -206,6 +208,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
this.opened = false;
this._changeEventsToDispatch = new Map();
this._dimensions = [];
this._minWidth = 285;
this._openedDimensions = [];
this._totalAppliedCount = 0;

Expand Down Expand Up @@ -244,27 +247,29 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {

const dropdownContent = singleDimension ? html`
<d2l-dropdown-content
class="vdiff-target"
min-width="285"
class="vdiff-target ${FILTER_CONTENT_CLASS}"
min-width="${this._minWidth}"
max-width="420"
mobile-tray="right"
mobile-breakpoint="768"
no-padding-header
no-padding
?opened="${this.opened}"
prefer-fixed-positioning
?trap-focus="${!this._isDimensionEmpty(this._dimensions[0])}">
${header}
${dimensions}
</d2l-dropdown-content>`
: html`
<d2l-dropdown-menu
class="vdiff-target"
min-width="285"
class="vdiff-target ${FILTER_CONTENT_CLASS}"
min-width="${this._minWidth}"
max-width="420"
mobile-tray="right"
mobile-breakpoint="768"
no-padding-header
?opened="${this.opened}"
prefer-fixed-positioning
trap-focus>
${header}
<d2l-menu label="${this.localize('components.filter.filters')}">
Expand All @@ -289,7 +294,8 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
@d2l-dropdown-open="${this._handleDropdownOpen}"
@d2l-dropdown-position="${this._stopPropagation}"
class="vdiff-target"
?disabled="${this.disabled}">
?disabled="${this.disabled}"
prefer-fixed-positioning>
<d2l-button-subtle
class="d2l-dropdown-opener"
description="${description}"
Expand Down Expand Up @@ -496,6 +502,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
`;
}

if (dimension.minWidth) this._minWidth = dimension.minWidth;
if (this._isDimensionEmpty(dimension)) {
const emptyState = dimension.setEmptyState
? this._createEmptyState(dimension.setEmptyState, dimension.key)
Expand Down Expand Up @@ -633,6 +640,12 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
this._activeFiltersSubscribers.updateSubscribers();
}

_dispatchChangeEventValueDataChange(dimension, value, valueKey) {
const details = { valueKey: valueKey, selected: value.selected };
if (value.getAdditionalEventDetails) Object.assign(details, value.getAdditionalEventDetails(value.selected));
this._dispatchChangeEvent(dimension, details);
}

_dispatchDimensionFirstOpenEvent(dimension) {
if (!this._openedDimensions.includes(dimension.key)) {
this.dispatchEvent(new CustomEvent('d2l-filter-dimension-first-open', { bubbles: true, composed: false, detail: { key: dimension.key } }));
Expand Down Expand Up @@ -746,6 +759,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
if (shouldResizeDropdown) {
this._requestDropdownResize();
}
if (e.detail.dispatchChangeEvent) this._dispatchChangeEventValueDataChange(dimension, value, e.detail.valueKey);
}

_handleDimensionHide() {
Expand Down Expand Up @@ -798,12 +812,16 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
}

_handleDropdownClose(e) {
if (!e.target.classList?.contains(FILTER_CONTENT_CLASS)) return;

this.opened = false;
this._activeDimensionKey = null;
this._stopPropagation(e);
}

_handleDropdownOpen(e) {
if (!e.target.classList?.contains(FILTER_CONTENT_CLASS)) return;

this.opened = true;
if (this._dimensions.length === 1) {
const dimension = this._dimensions[0];
Expand Down Expand Up @@ -846,6 +864,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
info.headerText = dimension.headerText;
info.introductoryText = dimension.introductoryText;
info.hasMore = dimension.hasMore;
info.minWidth = dimension.minWidth;
info.searchType = dimension.searchType;
info.searchValue = '';
info.selectedFirst = dimension.selectedFirst;
Expand Down Expand Up @@ -907,6 +926,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
value.selected = false;
this._setDimensionChangeEvent(dimension, { valueKey: value.key, selected: false }, true);
}
if (value.clearProperties) value.clearProperties();
});
break;
}
Expand Down
Loading

0 comments on commit b745726

Please sign in to comment.