Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion assets/core/ts/components/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export function calendar({ options, hidePopover }: { options: Options; hidePopov
cleanupCalendarRootListeners: null as (() => void) | null,
calendarClearHandler: null as (() => void) | null,
popStateHandler: null as (() => void) | null,
dateFilterChangedHandler: null as ((e: Event) => void) | null,

parseInputValue(inputValue: string): { selectedDates: string[]; selectedTime: string } {
const normalizedValue = inputValue.trim();
Expand Down Expand Up @@ -382,8 +383,22 @@ export function calendar({ options, hidePopover }: { options: Options; hidePopov

this.popStateHandler = () => this.updateActivePreset();
this.calendarClearHandler = () => this.clear();
this.dateFilterChangedHandler = (e: Event) => {
const detail = (e as CustomEvent)?.detail;
if (!detail) return;

const startDate = detail.startDate || '';
const endDate = detail.endDate || '';
const date = detail.date || '';

const selectedDates = startDate && endDate ? [startDate, endDate] : date ? [date] : [];
this.calendar?.set({ selectedDates });
this.updateActivePreset();
};

window.addEventListener(TUTOR_CALENDAR_EVENTS.popstate, this.popStateHandler);
window.addEventListener(TUTOR_CALENDAR_EVENTS.calendarClear, this.calendarClearHandler);
window.addEventListener(TUTOR_CUSTOM_EVENTS.DATE_FILTER_CHANGED, this.dateFilterChangedHandler);
});
},

Expand All @@ -403,6 +418,11 @@ export function calendar({ options, hidePopover }: { options: Options; hidePopov
window.removeEventListener(TUTOR_CALENDAR_EVENTS.calendarClear, this.calendarClearHandler);
this.calendarClearHandler = null;
}

if (this.dateFilterChangedHandler) {
window.removeEventListener(TUTOR_CUSTOM_EVENTS.DATE_FILTER_CHANGED, this.dateFilterChangedHandler);
this.dateFilterChangedHandler = null;
}
},

handleActionClick(e: Event) {
Expand Down Expand Up @@ -525,12 +545,15 @@ export function calendar({ options, hidePopover }: { options: Options; hidePopov
presetTitle ||
(startDate && endDate ? (startDate === endDate ? startDate : `${startDate} - ${endDate}`) : date || '');

const period = params.period ?? url.searchParams.get('period') ?? '';

window.dispatchEvent(
new CustomEvent(TUTOR_CUSTOM_EVENTS.DATE_FILTER_CHANGED, {
detail: {
startDate,
endDate,
date,
period,
label: formattedLabel,
preset: presetKey || '',
presetTitle: presetTitle || '',
Expand Down Expand Up @@ -611,6 +634,7 @@ export function calendar({ options, hidePopover }: { options: Options; hidePopov
{
[TUTOR_CALENDAR_QUERY_PARAMS.startDate]: null,
[TUTOR_CALENDAR_QUERY_PARAMS.endDate]: null,
...(preset === PRESETS.ALL_TIME ? { period: PRESETS.ALL_TIME } : {}),
},
preset,
presetTitle,
Expand All @@ -628,7 +652,13 @@ export function calendar({ options, hidePopover }: { options: Options; hidePopov
let activePreset: Preset | '' = '';

if (!startDate && !endDate) {
activePreset = PRESETS.ALL_TIME;
const urlPeriod = url.searchParams.get('period');
const defaultPreset = (options as Record<string, unknown>)?.defaultPreset as Preset | undefined;
if (urlPeriod === PRESETS.ALL_TIME) {
activePreset = PRESETS.ALL_TIME;
} else if (defaultPreset && (Object.values(PRESETS) as string[]).includes(defaultPreset)) {
activePreset = defaultPreset;
}
} else if (startDate && endDate) {
const presets = (Object.values(PRESETS) as Preset[]).filter((key) => key !== PRESETS.ALL_TIME);

Expand Down
18 changes: 13 additions & 5 deletions assets/src/js/frontend/dashboard/lazy-section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface LazySectionState {
section: string;
dateDependent: boolean;
sortDependent: boolean;
period: string;
startDate: string;
endDate: string;
sortType: string;
Expand Down Expand Up @@ -87,6 +88,7 @@ export const lazySection = ({
section,
dateDependent,
sortDependent,
period: 'today',
startDate: '',
endDate: '',
sortType: type,
Expand Down Expand Up @@ -141,7 +143,7 @@ export const lazySection = ({
return;
}

const currentKey = `${this.startDate}_${this.endDate}_${this.sortType}`;
const currentKey = `${this.period}_${this.startDate}_${this.endDate}_${this.sortType}`;
if (this.lastFetchedKey !== currentKey || !this.query?.data) {
this.lastFetchedKey = currentKey;
this.fetchSection();
Expand All @@ -152,6 +154,7 @@ export const lazySection = ({
const params = new URLSearchParams(window.location.search);
this.startDate = params.get('start_date') || '';
this.endDate = params.get('end_date') || '';
this.period = this.startDate && this.endDate ? '' : params.get('period') || 'today';
this.sortType = params.get('top_performing_course') || params.get('type') || type;

// Watch for content updates from QueryService and re-initialize Alpine child tree
Expand Down Expand Up @@ -187,15 +190,19 @@ export const lazySection = ({
if (this.dateDependent) {
this.dateChangeHandler = (e: Event) => {
const detail =
e instanceof CustomEvent ? (e.detail as { startDate?: string; endDate?: string } | undefined) : undefined;
e instanceof CustomEvent
? (e.detail as { period?: string; startDate?: string; endDate?: string } | undefined)
: undefined;
const newStart = detail?.startDate || '';
const newEnd = detail?.endDate || '';
const newPeriod = detail?.period || (newStart && newEnd ? '' : 'today');

// Guard: Avoid refetch if the filter dates have not changed
if (this.startDate === newStart && this.endDate === newEnd) {
// Guard: Avoid refetch if neither the period nor the date range has changed
if (this.period === newPeriod && this.startDate === newStart && this.endDate === newEnd) {
return;
}

this.period = newPeriod;
this.startDate = newStart;
this.endDate = newEnd;

Expand Down Expand Up @@ -238,7 +245,7 @@ export const lazySection = ({
},

fetchSection(this: LazySectionContext) {
const queryKey = ['dashboard-section', this.section, this.startDate, this.endDate, this.sortType];
const queryKey = ['dashboard-section', this.section, this.period, this.startDate, this.endDate, this.sortType];
const queryService = window.TutorCore.query;

if (queryService) {
Expand All @@ -247,6 +254,7 @@ export const lazySection = ({
() =>
wpPost<AjaxResponse<SectionResponseData>>('tutor_get_dashboard_section', {
section: this.section,
period: this.period,
start_date: this.startDate,
end_date: this.endDate,
top_performing_course: this.sortType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
@include tutor-transition(background-color);
width: 100%;
padding: $tutor-spacing-4 $tutor-spacing-5;
min-height: 58px;

&:hover {
background-color: $tutor-surface-base;
Expand Down Expand Up @@ -291,6 +292,7 @@

[data-section-id='top_performing_courses'] {
view-transition-name: top-performing-courses;
min-height: 346px;
}

[data-section-id='upcoming_tasks_and_activity'] {
Expand Down
2 changes: 2 additions & 0 deletions classes/DashboardSectionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ public function ajax_get_dashboard_section() {
$user_id = get_current_user_id();
$start_date = Input::post( 'start_date', '', Input::TYPE_STRING );
$end_date = Input::post( 'end_date', '', Input::TYPE_STRING );
$period = Input::post( 'period', '', Input::TYPE_STRING );
$type = Input::post( 'top_performing_course', Input::post( 'type', 'revenue', Input::TYPE_STRING ), Input::TYPE_STRING );
$type = in_array( $type, array( 'revenue', 'student' ), true ) ? $type : 'revenue';

Expand All @@ -233,6 +234,7 @@ public function ajax_get_dashboard_section() {

$params = array(
'user_id' => $user_id,
'period' => $period,
'start_date' => $start_date,
'end_date' => $end_date,
'top_performing_course' => $type,
Expand Down
44 changes: 38 additions & 6 deletions components/DateFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ class DateFilter extends BaseComponent {
*/
protected $clear_params = array();

/**
* Default preset to activate when no date range is selected.
*
* @since 4.2.1
*
* @var string|null
*/
protected $default_preset = null;

/**
* Whether to operate in AJAX mode (dispatch event instead of full page reload).
*
Expand Down Expand Up @@ -296,6 +305,20 @@ public function clear_params( array $params ): self {
return $this;
}

/**
* Set default preset when no date range is selected.
*
* @since 4.2.1
*
* @param string|null $preset Preset key (e.g. 'all-time').
*
* @return self
*/
public function default_preset( ?string $preset = 'all-time' ): self {
$this->default_preset = $preset;
return $this;
}

/**
* Render the component.
*
Expand All @@ -308,11 +331,14 @@ public function get(): string {
$this->label = $this->calculate_label();
}

$default_preset = $this->default_preset ?? ( $this->hide_initial_label ? null : 'all-time' );

// Default settings based on type.
$calendar_options = array(
'type' => 'default',
'clearParams' => $this->clear_params,
'ajaxMode' => $this->ajax_mode,
'type' => 'default',
'clearParams' => $this->clear_params,
'ajaxMode' => $this->ajax_mode,
'defaultPreset' => $default_preset,
);

$button_classes = 'tutor-btn tutor-btn-outline';
Expand All @@ -330,6 +356,7 @@ public function get(): string {
'selectionDatesMode' => 'multiple-ranged',
'clearParams' => $this->clear_params,
'ajaxMode' => $this->ajax_mode,
'defaultPreset' => $default_preset,
);
$popover_classes .= ' tutor-range-calendar-popover';
}
Expand Down Expand Up @@ -357,8 +384,8 @@ public function get(): string {
}"
<?php if ( $this->ajax_mode ) : ?>
@tutor:date-filter-changed.window="
hasSelection = Boolean( $event.detail.startDate || $event.detail.endDate || $event.detail.date );
label = $event.detail.label || <?php echo esc_attr( wp_json_encode( $this->hide_initial_label ? '' : __( 'All Time', 'tutor' ) ) ); ?>;
hasSelection = Boolean( $event.detail.startDate || $event.detail.endDate || $event.detail.date || $event.detail.period === 'all-time' );
label = hasSelection ? ( $event.detail.label || '' ) : <?php echo esc_attr( wp_json_encode( $this->hide_initial_label ? '' : __( 'All Time', 'tutor' ) ) ); ?>;
"
<?php endif; ?>
<?php echo $this->get_attributes_string(); //phpcs:ignore -- Sanitization is performed inside get_attributes_string. ?>
Expand Down Expand Up @@ -406,7 +433,7 @@ protected function has_selection(): bool {
if ( self::TYPE_SINGLE === $this->type ) {
return ! empty( Input::get( 'date' ) );
}
return ! empty( Input::get( 'start_date' ) ) && ! empty( Input::get( 'end_date' ) );
return ( ! empty( Input::get( 'start_date' ) ) && ! empty( Input::get( 'end_date' ) ) ) || 'all-time' === Input::get( 'period' );
}

/**
Expand All @@ -425,6 +452,11 @@ protected function calculate_label(): string {

$start_date = Input::get( 'start_date' );
$end_date = Input::get( 'end_date' );
$period = Input::get( 'period' );

if ( 'all-time' === $period ) {
return __( 'All Time', 'tutor' );
}

if ( ! $start_date || ! $end_date ) {
return $this->hide_initial_label ? '' : __( 'All Time', 'tutor' );
Expand Down
2 changes: 1 addition & 1 deletion components/Skeleton.php
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ protected function render_top_courses(): void {
<div class="tutor-small">
<span class="tutor-skeleton" style="width: 170px; height: 18px; display: inline-block;"></span>
</div>
<span class="tutor-skeleton tutor-rounded-md" style="width: 95px; height: 28px; display: inline-block;"></span>
<span class="tutor-skeleton tutor-rounded-md" style="width: 95px; height: 32px; display: inline-block;"></span>
</div>
<div class="tutor-dashboard-home-card-body tutor-gap-4">
<?php for ( $i = 0; $i < $this->count; $i++ ) : ?>
Expand Down
Loading