Skip to content

Commit 900cde6

Browse files
committed
feat: fix repeat end and make saving
1 parent 8be6802 commit 900cde6

3 files changed

Lines changed: 134 additions & 178 deletions

File tree

packages/devextreme/js/__internal/scheduler/appointment_popup/m_form.ts

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { TextEditorButton } from '@js/common';
22
import messageLocalization from '@js/common/core/localization/message';
33
import { DataSource } from '@js/common/data';
4-
import type { dxElementWrapper } from '@js/core/renderer';
54
import $ from '@js/core/renderer';
65
import dateUtils from '@js/core/utils/date';
76
import { extend } from '@js/core/utils/extend';
@@ -18,8 +17,8 @@ import { dateSerialization } from '@ts/core/utils/m_date_serialization';
1817

1918
import timeZoneUtils from '../m_utils_time_zone';
2019
import type { ResourceLoader } from '../utils/loader/resource_loader';
21-
import { RecurrenceRule, RecurrentForm } from './m_recurrent_form';
22-
import { createFormIconTemplate, getStartDateCommonConfig } from './utils';
20+
import { RecurrentForm } from './m_recurrent_form';
21+
import { createFormIconTemplate, getStartDateCommonConfig, RecurrenceRule } from './utils';
2322

2423
const CLASSES = {
2524
form: 'dx-scheduler-form',
@@ -143,6 +142,9 @@ export class AppointmentForm {
143142

144143
set formData(formData: Record<string, any>) {
145144
this.dxForm.option('formData', formData);
145+
146+
const repeatEditorValue = this.dxForm.getEditor(EDITOR_NAMES.repeat)?.option('value');
147+
this._recurrentForm.updateRecurrenceFormValues(repeatEditorValue, this.recurrenceRuleRaw);
146148
}
147149

148150
get startDate(): Date | null {
@@ -707,14 +709,6 @@ export class AppointmentForm {
707709
}
708710

709711
showMainGroup(saveRecurrenceValue = true): void {
710-
/*
711-
if(saveRecurrenceValue) {
712-
const recurrenceValue = this.recurrenceForm.getRecurrenceValue() -> returns string
713-
this.form.updateData('recurrenceExpr', recurrenceValue);
714-
}
715-
*/
716-
717-
// TODO: it better to store these group elements in the class fields
718712
const $formElement = $(this.dxForm.element());
719713
const mainGroup = $formElement.find(`.${CLASSES.mainGroupClass}`);
720714
const recurrenceGroup = $formElement.find(`.${CLASSES.recurrenceGroup}`);
@@ -724,29 +718,23 @@ export class AppointmentForm {
724718

725719
this._popup.updateToolbarForMainGroup();
726720

727-
// this._isRecurrenceFormVisible = false;
728-
729-
// if (!this._recurrentForm) {
730-
// return;
731-
// }
732-
733-
// if (saveChanges && this._recurrentForm.tempRecurrenceRule) {
734-
// const tempRecurrenceString = this._recurrentForm.tempRecurrenceRule.getRecurrenceString();
721+
this._isRecurrenceFormVisible = false;
735722

736-
// this._recurrenceRule = this._recurrentForm.tempRecurrenceRule;
737-
// this._recurrentForm.recurrenceRule = this._recurrenceRule;
723+
if (saveRecurrenceValue) {
724+
const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr;
725+
this.dxForm.updateData(
726+
recurrenceRuleExpr,
727+
this._recurrentForm.recurrenceRule.getRecurrenceString() ?? undefined,
728+
);
738729

739-
// const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr;
740-
// this.dxForm.updateData(recurrenceRuleExpr, tempRecurrenceString ?? undefined);
730+
// const repeatEditor = this.dxForm.getEditor(EDITOR_NAMES.repeat);
741731

742-
// const repeatEditor = this.dxForm.getEditor(EDITOR_NAMES.repeat);
732+
// if (repeatEditor) {
733+
// const { freq } = this._recurrenceRule.getRules();
743734

744-
// if (repeatEditor) {
745-
// const { freq } = this._recurrenceRule.getRules();
746-
747-
// if (freq) {
748-
// const freqValue = freq.toLowerCase();
749-
// repeatEditor.option('value', freqValue);
735+
// if (freq) {
736+
// const freqValue = freq.toLowerCase();
737+
// repeatEditor.option('value', freqValue);
750738

751739
// const buttons = this.getRepeatEditorButtons();
752740
// repeatEditor.option('buttons', buttons);
@@ -757,7 +745,7 @@ export class AppointmentForm {
757745
// }
758746
// } else if (!saveChanges) {
759747
// this._recurrentForm.tempRecurrenceRule = undefined;
760-
// }
748+
}
761749
}
762750

763751
private updateDateEditorsValues(): void {
@@ -784,7 +772,7 @@ export class AppointmentForm {
784772
} else {
785773
const recurrenceRule = new RecurrenceRule(this.recurrenceRuleRaw);
786774
const freq = recurrenceRule.getRule('freq');
787-
const value = freq ? freq.toLowerCase() : repeatNeverValue;
775+
const value = freq ? (freq as string).toLowerCase() : repeatNeverValue;
788776

789777
repeatEditor.option('value', value);
790778
}

packages/devextreme/js/__internal/scheduler/appointment_popup/m_recurrent_form.ts

Lines changed: 30 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import messageLocalization from '@js/common/core/localization/message';
44
import $, { type dxElementWrapper } from '@js/core/renderer';
55
import dateUtils from '@js/core/utils/date';
66
import { extend } from '@js/core/utils/extend';
7-
import { isDefined } from '@js/core/utils/type';
87
import type dxButton from '@js/ui/button';
98
import Button from '@js/ui/button';
109
import type { Properties as DateBoxProperties } from '@js/ui/date_box';
@@ -17,10 +16,7 @@ import { capitalize } from '@ts/core/utils/capitalize';
1716
import { dateSerialization } from '@ts/core/utils/m_date_serialization';
1817

1918
import type Scheduler from '../m_scheduler';
20-
import { getRecurrenceString, parseRecurrenceRule } from '../recurrence/base';
21-
import { daysFromByDayRule } from '../recurrence/days_from_by_day_rule';
22-
import type { Rule } from '../recurrence/types';
23-
import { createFormIconTemplate, getStartDateCommonConfig } from './utils';
19+
import { createFormIconTemplate, getStartDateCommonConfig, RecurrenceRule } from './utils';
2420

2521
const CLASSES = {
2622
groupWithIcon: 'dx-scheduler-form-group-with-icon',
@@ -79,69 +75,6 @@ const weekDays = dateLocalization.getDayNames('abbreviated').map((dayName) => da
7975

8076
const RECURRENCE_GROUP_NAME = 'recurrenceGroup';
8177

82-
export class RecurrenceRule {
83-
private _recurrenceRule: Rule;
84-
85-
constructor(rule: string) {
86-
this._recurrenceRule = parseRecurrenceRule(rule);
87-
}
88-
89-
setRule(field: string, value: any): void {
90-
if (!value || (Array.isArray(value) && !value.length)) {
91-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
92-
delete this._recurrenceRule[field];
93-
return;
94-
}
95-
96-
if (isDefined(field)) {
97-
if (field === 'until') {
98-
delete this._recurrenceRule.count;
99-
}
100-
101-
if (field === 'count') {
102-
delete this._recurrenceRule.until;
103-
}
104-
105-
this._recurrenceRule[field] = value;
106-
}
107-
}
108-
109-
getRepeatEndRule(): string {
110-
const rules = this._recurrenceRule;
111-
112-
if ('count' in rules) {
113-
return 'count';
114-
}
115-
116-
if ('until' in rules) {
117-
return 'until';
118-
}
119-
120-
return 'never';
121-
}
122-
123-
getRecurrenceString(): string | undefined {
124-
return getRecurrenceString(this._recurrenceRule);
125-
}
126-
127-
getRules(): Rule {
128-
return this._recurrenceRule;
129-
}
130-
131-
getRule(field: string): any | undefined {
132-
return this._recurrenceRule[field];
133-
}
134-
135-
getDaysFromByDayRule(): string[] {
136-
return daysFromByDayRule(this._recurrenceRule);
137-
}
138-
}
139-
140-
/*
141-
1. Use RecurrenceRule to store editor's value
142-
2. Use RecurrentForm properties to store editor's value
143-
3. Use formData
144-
*/
14578
export class RecurrentForm {
14679
private readonly scheduler: any;
14780

@@ -196,7 +129,7 @@ export class RecurrentForm {
196129
showSpinButtons: true,
197130
useLargeSpinButtons: false,
198131
onContentReady: (e): void => {
199-
e.component.option('value', this.recurrenceRule.getRule('bymonthday'));
132+
e.component.option('value', parseInt(this.recurrenceRule.getRule('bymonthday')?.toString() ?? '1', 10));
200133
},
201134
onValueChanged: (e): void => {
202135
this.recurrenceRule.setRule('bymonthday', e.value);
@@ -355,7 +288,7 @@ export class RecurrentForm {
355288
showSpinButtons: true,
356289
useLargeSpinButtons: false,
357290
onContentReady: (e): void => {
358-
e.component.option('value', this.recurrenceRule.getRule('interval'));
291+
e.component.option('value', parseInt(this.recurrenceRule.getRule('interval')?.toString() ?? '1', 10));
359292
},
360293
onValueChanged: (e): void => {
361294
this.recurrenceRule.setRule('interval', e.value);
@@ -523,9 +456,8 @@ export class RecurrentForm {
523456
onContentReady: (e): void => {
524457
e.component.option('value', this.recurrenceRule.getRepeatEndRule());
525458
},
526-
onValueChanged: (args): void => {
527-
this.recurrenceRule.setRule('repeatEnd', args.value);
528-
this._updateDisabledRepeatEndEditors();
459+
onValueChanged: (e): void => {
460+
this._repeatEndValueChangedHandler(e.value);
529461
},
530462
} as RadioGroupProperties,
531463
},
@@ -552,19 +484,11 @@ export class RecurrentForm {
552484
firstDayOfWeek: this.scheduler.getFirstDayOfWeek(),
553485
},
554486
onContentReady: (e): void => {
555-
e.component.option('value', this._getUntilValue());
487+
e.component.option('value', this.recurrenceRule.getUntilValue() ?? dateUtils.setToDayEnd(new Date()));
556488
},
557-
onValueChanged: (args): void => {
558-
if (this._tempRecurrenceRule && this._tempRecurrenceRule.getRepeatEndRule() === 'until') {
559-
const dateInTimeZone = this._formatUntilDate(new Date(args.value));
560-
this._tempRecurrenceRule.setRule('until', dateInTimeZone);
561-
}
562-
},
563-
onFocusIn: (): void => {
564-
const currentRepeatEnd = this._tempRecurrenceRule?.getRepeatEndRule();
565-
if (currentRepeatEnd !== 'until') {
566-
this._repeatEndValueChangedHandler({ value: 'until' });
567-
}
489+
onValueChanged: (e): void => {
490+
this.recurrenceRule.setRule('until', e.value);
491+
this.recurrenceRule.setUntilValue(e.value);
568492
},
569493
} as DateBoxProperties,
570494
},
@@ -582,19 +506,12 @@ export class RecurrentForm {
582506
useLargeSpinButtons: false,
583507
disabled: repeatType !== 'count',
584508
onContentReady: (e): void => {
585-
const count = this._recurrenceRule.getRules().count ?? 1;
509+
const count = this.recurrenceRule.getCountValue() ?? 1;
586510
e.component.option('value', count);
587511
},
588-
onValueChanged: (args): void => {
589-
if (this._tempRecurrenceRule && this._tempRecurrenceRule.getRepeatEndRule() === 'count') {
590-
this._tempRecurrenceRule.setRule('count', args.value);
591-
}
592-
},
593-
onFocusIn: (): void => {
594-
const currentRepeatEnd = this._tempRecurrenceRule?.getRepeatEndRule();
595-
if (currentRepeatEnd !== 'count') {
596-
this._repeatEndValueChangedHandler({ value: 'count' });
597-
}
512+
onValueChanged: (e): void => {
513+
this.recurrenceRule.setRule('count', e.value);
514+
this.recurrenceRule.setCountValue(e.value);
598515
},
599516
} as NumberBoxProperties,
600517
},
@@ -609,14 +526,13 @@ export class RecurrentForm {
609526
updateRecurrenceFormValues(repeatEditorValue: string, recurrenceRuleRaw: string | null): void {
610527
this.recurrenceRule = this.createRecurrenceRule(repeatEditorValue, recurrenceRuleRaw);
611528
const rules = this.recurrenceRule.getRules();
612-
const repeatEndValue = this.recurrenceRule.getRepeatEndRule();
613529

614530
this.dxForm.getEditor('recurrenceStartDate')?.option('value', this.startDate);
615531
this.dxForm.getEditor('freq')?.option('value', repeatEditorValue);
616532
this.dxForm.getEditor('interval')?.option('value', rules.interval);
617-
this.dxForm.getEditor('repeatEnd')?.option('value', repeatEndValue);
618-
this.dxForm.getEditor('until')?.option('value', rules.until);
619-
this.dxForm.getEditor('count')?.option('value', rules.count);
533+
this.dxForm.getEditor('repeatEnd')?.option('value', this.recurrenceRule.getRepeatEndRule());
534+
this.dxForm.getEditor('until')?.option('value', this.recurrenceRule.getUntilValue());
535+
this.dxForm.getEditor('count')?.option('value', this.recurrenceRule.getCountValue());
620536

621537
this._updateDisabledRepeatEndEditors();
622538
this.updateRecurrenceRepeatOnVisibility();
@@ -631,15 +547,15 @@ export class RecurrentForm {
631547
const recurrenceFreq = recurrenceRule?.getRules().freq?.toLowerCase();
632548

633549
if (recurrenceFreq !== repeatEditorValue) {
634-
const todayEnd = dateUtils.setToDayEnd(new Date());
550+
// const todayEnd = dateUtils.setToDayEnd(new Date());
635551
const newRecurrenceRule = new RecurrenceRule('');
636552
const defaultByDay = weekDays[this.startDate?.getDay() ?? this.scheduler.getFirstDayOfWeek()];
637553

638554
newRecurrenceRule.setRule('freq', repeatEditorValue);
639555
newRecurrenceRule.setRule('interval', 1);
640-
newRecurrenceRule.setRule('repeatEnd', 'never'); // TODO: change 'never' to constant variable
641-
newRecurrenceRule.setRule('until', todayEnd);
642-
newRecurrenceRule.setRule('count', 1);
556+
// newRecurrenceRule.setRule('repeatEnd', 'never'); // TODO: change 'never' to constant variable
557+
newRecurrenceRule.setUntilValue(dateUtils.setToDayEnd(new Date()));
558+
newRecurrenceRule.setCountValue(1);
643559
newRecurrenceRule.setRule('byday', defaultByDay);
644560
newRecurrenceRule.setRule('bymonth', (this.startDate?.getMonth() ?? 0) + 1);
645561
newRecurrenceRule.setRule('bymonthday', this.startDate?.getDate() ?? 1);
@@ -650,40 +566,22 @@ export class RecurrentForm {
650566
return recurrenceRule;
651567
}
652568

653-
private _getTempUntilValue(): Date {
654-
if (!this._tempRecurrenceRule) {
655-
return this._formatUntilDate(new Date());
656-
}
657-
658-
const untilDate = this._tempRecurrenceRule.getRules().until;
659-
660-
if (!untilDate) {
661-
return this._formatUntilDate(new Date());
662-
}
663-
664-
return new Date(untilDate);
665-
}
666-
667-
private _repeatEndValueChangedHandler(args: any): void {
668-
const { value } = args;
669-
670-
this._updateDisabledRepeatEndEditors();
671-
672-
if (!this._tempRecurrenceRule) {
673-
return;
674-
}
675-
569+
private _repeatEndValueChangedHandler(value: string): void {
676570
if (value === 'until') {
677-
this._tempRecurrenceRule.setRule(value, this._getTempUntilValue());
571+
this.recurrenceRule.setRule('until', this.recurrenceRule.getUntilValue() ?? dateUtils.setToDayEnd(new Date()));
572+
this.recurrenceRule.setUntilValue(this.recurrenceRule.getUntilValue()
573+
?? dateUtils.setToDayEnd(new Date()));
678574
}
679575
if (value === 'count') {
680-
const countEditor = this.dxForm.getEditor('count');
681-
this._tempRecurrenceRule.setRule(value, countEditor?.option('value') || 1);
576+
this.recurrenceRule.setRule('count', this.recurrenceRule.getCountValue() ?? 1);
577+
this.recurrenceRule.setCountValue(this.recurrenceRule.getCountValue() ?? 1);
682578
}
683579
if (value === 'never') {
684-
this._tempRecurrenceRule.setRule('count', '');
685-
this._tempRecurrenceRule.setRule('until', '');
580+
this.recurrenceRule.setRule('count', '');
581+
this.recurrenceRule.setRule('until', '');
686582
}
583+
584+
this._updateDisabledRepeatEndEditors();
687585
}
688586

689587
private _updateDisabledRepeatEndEditors(): void {
@@ -696,20 +594,6 @@ export class RecurrentForm {
696594
countEditor?.option('disabled', repeatEndValue !== 'count');
697595
}
698596

699-
private _formatUntilDate(date: Date): Date {
700-
return dateUtils.setToDayEnd(date);
701-
}
702-
703-
private _getUntilValue(): Date {
704-
const untilDate = this._recurrenceRule.getRules().until;
705-
706-
if (!untilDate) {
707-
return this._formatUntilDate(new Date());
708-
}
709-
710-
return new Date(untilDate);
711-
}
712-
713597
private updateRecurrenceRepeatOnVisibility(): void {
714598
const freq = this.recurrenceRule.getRule('freq');
715599

0 commit comments

Comments
 (0)