Skip to content

Commit 5aff64a

Browse files
sjburTucchhaa
andauthored
Scheduler: update react storybook for legacy popup layout (#31911)
Co-authored-by: Eldar Iusupzhanov <[email protected]>
1 parent b224101 commit 5aff64a

File tree

5 files changed

+271
-72
lines changed

5 files changed

+271
-72
lines changed

apps/react-storybook/stories/scheduler/SchedulerFormCustomization.stories.tsx

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Meta, StoryObj } from "@storybook/react";
2-
import React from "react";
2+
import React, { useRef } from "react";
33
import dxScheduler from "devextreme/ui/scheduler";
44
import type { Properties } from "devextreme/ui/scheduler";
55
import { wrapDxWithReact } from "../utils";
@@ -8,6 +8,9 @@ import "./form-customization.css";
88

99
const Scheduler = wrapDxWithReact<Properties>(dxScheduler);
1010

11+
import ReactScheduler from 'devextreme-react/scheduler';
12+
import dxForm from "devextreme/ui/form";
13+
1114
const iconsShowModeArgType = {
1215
"editing.form.iconsShowMode": {
1316
control: "radio",
@@ -332,21 +335,117 @@ export const RTL: Story = {
332335
export const LegacyPopup: Story = {
333336
args: {
334337
...baseConfig,
335-
"editing.form.iconsShowMode": "none",
338+
"editing.form.iconsShowMode": "both",
336339
} as Properties,
337340
argTypes: iconsShowModeArgType,
338341
render: (args) => {
342+
let form: InstanceType<typeof dxForm> | null = null;
343+
344+
const schedulerRef = useRef(null);
345+
339346
return (
340-
<Scheduler
347+
// @ts-ignore
348+
<ReactScheduler
349+
ref={schedulerRef}
341350
{...baseConfig}
351+
onAppointmentUpdating={(e) => {
352+
delete e.newData.repeat;
353+
}}
354+
onAppointmentAdding={(e) => {
355+
delete e.appointmentData.repeat;
356+
}}
342357
editing={{
358+
popup: {
359+
maxWidth: 800,
360+
toolbarItems: [
361+
{
362+
toolbar: 'top',
363+
location: 'before',
364+
text: "Edit Appointment",
365+
cssClass: 'dx-toolbar-label',
366+
},
367+
{
368+
toolbar: 'top',
369+
location: 'after',
370+
options: {
371+
stylingMode: 'contained',
372+
type: 'default',
373+
onClick: () => {
374+
// @ts-ignore
375+
schedulerRef.current?.instance()?.hideAppointmentPopup(true);
376+
},
377+
text: 'Save',
378+
},
379+
shortcut: 'done',
380+
},
381+
{
382+
toolbar: 'top',
383+
location: 'after',
384+
shortcut: 'cancel',
385+
},
386+
],
387+
},
343388
form: {
389+
onInitialized: function (e) {
390+
e.component?.on('fieldDataChanged', (e) => {
391+
if (e.dataField === 'recurrenceRule') {
392+
form?.option('formData.repeat', !!e.value)
393+
}
394+
});
395+
},
396+
onContentReady: function (e) {
397+
form = e.component;
398+
},
399+
iconsShowMode: args["editing.form.iconsShowMode"],
344400
items: [
345-
"mainGroup",
346-
{name: 'recurenceGroup', visible: true}
401+
{
402+
name: "mainGroup",
403+
cssClass: "",
404+
items: [
405+
"subjectGroup",
406+
"dateGroup",
407+
{
408+
name: "repeatGroup",
409+
items: [
410+
"repeatIcon",
411+
{
412+
name: "customRepeatEditor",
413+
editorType: "dxSwitch",
414+
dataField: "repeat",
415+
editorOptions: {
416+
onValueChanged: (e) => {
417+
if (e.value) {
418+
const recurrenceRule = form?.option('formData')?.recurrenceRule;
419+
420+
form?.option("colCount", 2);
421+
form?.option('formData.recurrenceRule', recurrenceRule || "FREQ=DAILY");
422+
form?.itemOption("recurrenceGroup", "visible", true);
423+
} else {
424+
form?.option("colCount", 1);
425+
form?.option('formData.recurrenceRule', "");
426+
form?.itemOption("recurrenceGroup", "visible", false);
427+
}
428+
},
429+
},
430+
},
431+
],
432+
},
433+
"resourcesGroup",
434+
"descriptionGroup",
435+
],
436+
},
437+
{
438+
name: "recurrenceGroup",
439+
itemType: "group",
440+
cssClass: "",
441+
visible: false,
442+
items: [
443+
"recurrenceRuleGroup",
444+
"recurrenceEndGroup",
445+
],
446+
},
347447
],
348-
iconsShowMode: args["editing.form.iconsShowMode"]
349-
}
448+
},
350449
} as Properties['editing']}
351450
/>
352451
);

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

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,30 @@ describe('Appointment Form', () => {
13071307
expect(POM.popup.isRecurrenceGroupVisible()).toBe(true);
13081308
});
13091309

1310+
it('should have disabled week day buttons when allowUpdating is false', async () => {
1311+
const { POM, scheduler } = await createScheduler({
1312+
...getDefaultConfig(),
1313+
dataSource: [{ ...recurringAppointment, recurrenceRule: 'FREQ=WEEKLY;BYDAY=WE,TU,TH,FR,SA' }],
1314+
editing: { allowUpdating: false },
1315+
});
1316+
1317+
const dataSource = (scheduler as any).getDataSource();
1318+
const appointment = dataSource.items()[0];
1319+
1320+
scheduler.showAppointmentPopup(appointment);
1321+
POM.popup.openRecurrenceSettings();
1322+
1323+
const weekDayButtons = POM.popup.recurrenceWeekDayButtons;
1324+
expect(weekDayButtons).toBeTruthy();
1325+
1326+
const firstButton = weekDayButtons?.querySelector('.dx-button');
1327+
expect(firstButton).toBeTruthy();
1328+
1329+
// @ts-expect-error
1330+
const buttonInstance = $(firstButton).dxButton('instance');
1331+
expect(buttonInstance?.option('disabled')).toBe(true);
1332+
});
1333+
13101334
it('should be visible after changing repeat editor\'s value', async () => {
13111335
const { scheduler, POM } = await createScheduler(getDefaultConfig());
13121336

@@ -1563,6 +1587,95 @@ describe('Appointment Form', () => {
15631587
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('5 occurrence(s)');
15641588
});
15651589
});
1590+
1591+
describe('Repeat End Values Preservation', () => {
1592+
it('should preserve count value when switching between recurrence types', async () => {
1593+
const { scheduler, POM } = await createScheduler(getDefaultConfig());
1594+
const testCount = 15;
1595+
1596+
scheduler.showAppointmentPopup({
1597+
text: 'Meeting',
1598+
startDate: new Date(2017, 4, 1, 10, 30),
1599+
endDate: new Date(2017, 4, 1, 11),
1600+
});
1601+
1602+
POM.popup.selectRepeatValue('daily');
1603+
1604+
POM.popup.setInputValue('recurrenceRepeatEndEditor', 'count');
1605+
POM.popup.setInputValue('recurrenceEndCountEditor', testCount);
1606+
1607+
POM.popup.getBackButton().click();
1608+
1609+
POM.popup.selectRepeatValue('weekly');
1610+
1611+
POM.popup.openRecurrenceSettings();
1612+
1613+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe(`${testCount} occurrence(s)`);
1614+
1615+
scheduler.hideAppointmentPopup();
1616+
});
1617+
1618+
it('should preserve until value when switching between recurrence types', async () => {
1619+
const { scheduler, POM } = await createScheduler(getDefaultConfig());
1620+
const testUntilDate = new Date(2017, 5, 16);
1621+
1622+
scheduler.showAppointmentPopup({
1623+
text: 'Meeting',
1624+
startDate: new Date(2017, 4, 1, 10, 30),
1625+
endDate: new Date(2017, 4, 1, 11),
1626+
});
1627+
1628+
POM.popup.selectRepeatValue('daily');
1629+
1630+
POM.popup.setInputValue('recurrenceRepeatEndEditor', 'until');
1631+
POM.popup.setInputValue('recurrenceEndUntilEditor', testUntilDate);
1632+
1633+
POM.popup.getBackButton().click();
1634+
1635+
POM.popup.selectRepeatValue('weekly');
1636+
1637+
POM.popup.openRecurrenceSettings();
1638+
1639+
expect(POM.popup.getInputValue('recurrenceEndUntilEditor')).toBe('6/16/2017');
1640+
1641+
scheduler.hideAppointmentPopup();
1642+
});
1643+
});
1644+
1645+
describe('Repeat End Editors Disabled State', () => {
1646+
['never', 'until', 'count'].forEach((repeatEndValue) => {
1647+
it(`should set correct disabled state when repeatEnd is ${repeatEndValue}`, async () => {
1648+
const { scheduler, POM } = await createScheduler(getDefaultConfig());
1649+
let recurrenceRule = '';
1650+
switch (repeatEndValue) {
1651+
case 'count':
1652+
recurrenceRule = 'FREQ=DAILY;COUNT=10';
1653+
break;
1654+
case 'until':
1655+
recurrenceRule = 'FREQ=DAILY;UNTIL=20170615T000000Z';
1656+
break;
1657+
default:
1658+
recurrenceRule = 'FREQ=DAILY';
1659+
}
1660+
1661+
scheduler.showAppointmentPopup({
1662+
text: 'Meeting',
1663+
startDate: new Date(2017, 4, 1, 10, 30),
1664+
endDate: new Date(2017, 4, 1, 11),
1665+
recurrenceRule,
1666+
});
1667+
1668+
POM.popup.getEditSeriesButton().click();
1669+
POM.popup.openRecurrenceSettings();
1670+
1671+
const untilEditor = POM.popup.form.getEditor('recurrenceEndUntilEditor');
1672+
const countEditor = POM.popup.form.getEditor('recurrenceEndCountEditor');
1673+
1674+
expect(untilEditor?.option('disabled')).toBe(repeatEndValue !== 'until');
1675+
expect(countEditor?.option('disabled')).toBe(repeatEndValue !== 'count');
1676+
});
1677+
});
1678+
});
15661679
});
15671680

15681681
describe('firstDayOfWeek', () => {

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

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ export class AppointmentForm {
280280
this.updateDateEditorsValues();
281281
}
282282

283+
if (isRecurrenceRuleChanged || startDateExpr === dataField) {
284+
this._recurrenceForm.updateRecurrenceFormValues(
285+
this.recurrenceRuleRaw,
286+
this.startDate,
287+
);
288+
}
289+
283290
if (isRecurrenceRuleChanged) {
284291
this.updateRepeatEditorValue();
285292
}
@@ -663,7 +670,14 @@ export class AppointmentForm {
663670
onValueChanged: (e): void => {
664671
if (e.value === repeatNeverValue) {
665672
this.dxForm.updateData(recurrenceRuleExpr, '');
666-
} else if (e.event) {
673+
} else {
674+
const currentRecurrenceRule = this._recurrenceForm.recurrenceRule.toString() ?? '';
675+
const recurrenceRule = new RecurrenceRule(currentRecurrenceRule, this.startDate);
676+
recurrenceRule.frequency = e.value;
677+
this.dxForm.updateData(recurrenceRuleExpr, recurrenceRule.toString());
678+
}
679+
680+
if (e.value !== repeatNeverValue && e.event) {
667681
this.showRecurrenceGroup();
668682
}
669683

@@ -833,30 +847,6 @@ export class AppointmentForm {
833847
}
834848
}
835849

836-
showRecurrenceGroup(): void {
837-
const currentHeight = this.dxPopup.option('height') as string | number | undefined;
838-
839-
if (currentHeight === 'auto' || currentHeight === undefined) {
840-
const overlayHeight = this.dxPopup.$overlayContent().get(0).clientHeight;
841-
this.dxPopup.option('height', overlayHeight);
842-
}
843-
844-
this._$mainGroup?.addClass(CLASSES.mainHidden);
845-
this._$mainGroup?.attr('tabindex', '-1');
846-
this._$recurrenceGroup?.removeClass(CLASSES.recurrenceHidden);
847-
this._$recurrenceGroup?.removeAttr('tabindex');
848-
849-
const repeatEditorValue = this.dxForm.getEditor(REPEAT_EDITOR_NAME)?.option('value');
850-
851-
this._recurrenceForm.updateRecurrenceFormValues(
852-
repeatEditorValue,
853-
this.recurrenceRuleRaw,
854-
this.startDate,
855-
);
856-
857-
this._popup.updateToolbarForRecurrenceGroup();
858-
}
859-
860850
showMainGroup(): void {
861851
const currentHeight = this.dxPopup.option('height') as string | number | undefined;
862852
const editingConfig = this.scheduler.getEditingConfig();
@@ -874,13 +864,23 @@ export class AppointmentForm {
874864
this._popup.updateToolbarForMainGroup();
875865
}
876866

877-
saveRecurrenceValue(): void {
878-
const isRecurrenceFormOpened = !this._$recurrenceGroup?.hasClass(CLASSES.recurrenceHidden);
867+
showRecurrenceGroup(): void {
868+
const currentHeight = this.dxPopup.option('height') as string | number | undefined;
879869

880-
if (!isRecurrenceFormOpened) {
881-
return;
870+
if (currentHeight === 'auto' || currentHeight === undefined) {
871+
const overlayHeight = this.dxPopup.$overlayContent().get(0).clientHeight;
872+
this.dxPopup.option('height', overlayHeight);
882873
}
883874

875+
this._$mainGroup?.addClass(CLASSES.mainHidden);
876+
this._$mainGroup?.attr('tabindex', '-1');
877+
this._$recurrenceGroup?.removeClass(CLASSES.recurrenceHidden);
878+
this._$recurrenceGroup?.removeAttr('tabindex');
879+
880+
this._popup.updateToolbarForRecurrenceGroup();
881+
}
882+
883+
saveRecurrenceValue(): void {
884884
const { recurrenceRule } = this._recurrenceForm;
885885
const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr;
886886

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ export class AppointmentPopup {
192192

193193
const formData = this._createFormData(appointmentAdapter);
194194

195-
this.form.formData = formData;
196195
this.form.readOnly = this._isReadOnly(appointmentAdapter);
196+
this.form.formData = formData;
197197

198198
this.form.showMainGroup();
199199
}

0 commit comments

Comments
 (0)