1- import React , { useCallback , useRef } from 'react' ;
1+ import React , { useCallback , useMemo , useRef } from 'react' ;
22import Scheduler , {
33 Editing ,
44 Resource ,
55 Form as SchedulerForm ,
66 Item ,
7+ Label ,
78} from 'devextreme-react/scheduler' ;
89import { query } from 'devextreme-react/common/data' ;
910import Appointment from './Appointment.js' ;
@@ -14,35 +15,15 @@ import { data, moviesData, theatreData } from './data.js';
1415const currentDate = new Date ( 2025 , 3 , 27 ) ;
1516const views = [ 'day' , 'week' , 'timelineDay' ] ;
1617const groups = [ 'theatreId' ] ;
17- const getMovieById = ( id ) => query ( moviesData ) . filter ( [ 'id' , id ] ) . toArray ( ) [ 0 ] ;
18+ const getMovieById = ( id ) => ( id ? query ( moviesData ) . filter ( [ 'id' , '=' , id ] ) . toArray ( ) [ 0 ] : null ) ;
1819const getEditorStylingMode = ( ) => {
1920 const isMaterialOrFluent = document . querySelector ( '.dx-theme-fluent, .dx-theme-material' ) ;
2021 return isMaterialOrFluent ? 'filled' : 'outlined' ;
2122} ;
2223const priceDisplayExpr = ( value ) => `$${ value } ` ;
23- const updateEndDate = ( form , movie ) => {
24- const formData = form . option ( 'formData' ) ;
25- const { startDate } = formData ;
26- if ( startDate && movie ?. duration ) {
27- const newEndDate = new Date ( startDate . getTime ( ) + 60 * 1000 * movie . duration ) ;
28- form . updateData ( 'endDate' , newEndDate ) ;
29- }
30- } ;
24+ const colCountByScreen = { xs : 2 } ;
3125const App = ( ) => {
3226 const formInstanceRef = useRef ( null ) ;
33- const onMovieValueChanged = useCallback ( ( e ) => {
34- const movie = getMovieById ( e . value ) ;
35- if ( formInstanceRef . current && movie ) {
36- formInstanceRef . current . updateData ( 'director' , movie . director ) ;
37- updateEndDate ( formInstanceRef . current , movie ) ;
38- }
39- } , [ ] ) ;
40- const onMovieEditorContentReady = useCallback ( ( e ) => {
41- e . component . option ( 'stylingMode' , getEditorStylingMode ( ) ) ;
42- } , [ ] ) ;
43- const onPriceEditorContentReady = useCallback ( ( e ) => {
44- e . component . option ( 'stylingMode' , getEditorStylingMode ( ) ) ;
45- } , [ ] ) ;
4627 const onPopupOptionChanged = useCallback ( ( e ) => {
4728 if ( e . fullName === 'toolbarItems' && e . value ) {
4829 e . value . forEach ( ( item , index ) => {
@@ -52,25 +33,75 @@ const App = () => {
5233 } ) ;
5334 }
5435 } , [ ] ) ;
55- const onFormInitialized = useCallback ( ( e ) => {
56- const form = e . component ;
57- formInstanceRef . current = form ;
58- form . on ( 'fieldDataChanged' , ( fieldEvent ) => {
59- if ( fieldEvent . dataField === 'startDate' ) {
60- const currentFormData = form . option ( 'formData' ) ;
61- if ( currentFormData . movieId ) {
36+ const popupOptions = useMemo (
37+ ( ) => ( {
38+ maxWidth : 440 ,
39+ onOptionChanged : onPopupOptionChanged ,
40+ } ) ,
41+ [ onPopupOptionChanged ] ,
42+ ) ;
43+ const updateEndDate = useCallback ( ( movie ) => {
44+ const form = formInstanceRef . current ;
45+ const formData = form . option ( 'formData' ) ;
46+ const { startDate } = formData ;
47+ if ( startDate ) {
48+ const newEndDate = new Date ( startDate . getTime ( ) + 60 * 1000 * movie . duration ) ;
49+ form . updateData ( 'endDate' , newEndDate ) ;
50+ }
51+ } , [ ] ) ;
52+ const onFormInitialized = useCallback (
53+ ( e ) => {
54+ const form = e . component ;
55+ formInstanceRef . current = form ;
56+ form . on ( 'fieldDataChanged' , ( fieldEvent ) => {
57+ if ( fieldEvent . dataField === 'startDate' ) {
58+ const currentFormData = form . option ( 'formData' ) ;
6259 const movie = getMovieById ( currentFormData . movieId ) ;
6360 if ( movie ) {
64- updateEndDate ( form , movie ) ;
61+ updateEndDate ( movie ) ;
6562 }
6663 }
64+ } ) ;
65+ } ,
66+ [ updateEndDate ] ,
67+ ) ;
68+ const onMovieValueChanged = useCallback (
69+ ( e ) => {
70+ const movie = getMovieById ( e . value ) ;
71+ if ( movie ) {
72+ formInstanceRef . current . updateData ( 'director' , movie . director ) ;
73+ updateEndDate ( movie ) ;
6774 }
68- } ) ;
69- } , [ ] ) ;
75+ } ,
76+ [ updateEndDate ] ,
77+ ) ;
7078 const movieInfoContainerRender = useCallback (
7179 ( ) => < MovieInfoContainer formInstanceRef = { formInstanceRef } /> ,
7280 [ ] ,
7381 ) ;
82+ const onCustomEditorContentReady = useCallback ( ( e ) => {
83+ e . component . option ( 'stylingMode' , getEditorStylingMode ( ) ) ;
84+ } , [ ] ) ;
85+ const movieEditorOptions = useMemo (
86+ ( ) => ( {
87+ items : moviesData ,
88+ displayExpr : 'text' ,
89+ valueExpr : 'id' ,
90+ stylingMode : getEditorStylingMode ( ) ,
91+ onValueChanged : onMovieValueChanged ,
92+ onContentReady : onCustomEditorContentReady ,
93+ } ) ,
94+ [ onMovieValueChanged , onCustomEditorContentReady ] ,
95+ ) ;
96+ const priceEditorOptions = useMemo (
97+ ( ) => ( {
98+ items : [ 5 , 10 , 15 , 20 ] ,
99+ displayExpr : priceDisplayExpr ,
100+ stylingMode : getEditorStylingMode ( ) ,
101+ onContentReady : onCustomEditorContentReady ,
102+ } ) ,
103+ [ onCustomEditorContentReady ] ,
104+ ) ;
74105 return (
75106 < Scheduler
76107 timeZone = "America/Los_Angeles"
@@ -91,46 +122,33 @@ const App = () => {
91122 >
92123 < Editing
93124 allowAdding = { false }
94- popup = { {
95- maxWidth : 440 ,
96- onOptionChanged : onPopupOptionChanged ,
97- } }
125+ popup = { popupOptions }
98126 >
99127 < SchedulerForm onInitialized = { onFormInitialized } >
100128 < Item render = { movieInfoContainerRender } />
101129
102130 < Item
103131 itemType = "group"
104132 colCount = { 2 }
105- colCountByScreen = { { xs : 2 } }
133+ colCountByScreen = { colCountByScreen }
106134 >
107135 < Item
108136 dataField = "movieId"
109137 editorType = "dxSelectBox"
110- label = { { text : 'Movie' } }
111138 colSpan = { 1 }
112- editorOptions = { {
113- items : moviesData ,
114- displayExpr : 'text' ,
115- valueExpr : 'id' ,
116- stylingMode : getEditorStylingMode ( ) ,
117- onValueChanged : onMovieValueChanged ,
118- onContentReady : onMovieEditorContentReady ,
119- } }
120- />
139+ editorOptions = { movieEditorOptions }
140+ >
141+ < Label > Movie</ Label >
142+ </ Item >
121143
122144 < Item
123145 dataField = "price"
124146 editorType = "dxSelectBox"
125- label = { { text : 'Price' } }
126147 colSpan = { 1 }
127- editorOptions = { {
128- items : [ 5 , 10 , 15 , 20 ] ,
129- displayExpr : priceDisplayExpr ,
130- stylingMode : getEditorStylingMode ( ) ,
131- onContentReady : onPriceEditorContentReady ,
132- } }
133- />
148+ editorOptions = { priceEditorOptions }
149+ >
150+ < Label > Price</ Label >
151+ </ Item >
134152 </ Item >
135153
136154 < Item
0 commit comments