@iobroker/adapter-react-v5 6.1.10 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/Components/404.js +13 -13
  2. package/Components/Loader.js +223 -223
  3. package/Components/Loaders/PT.css +108 -108
  4. package/Components/Loaders/PT.js +103 -103
  5. package/Components/Loaders/Vendor.css +13 -13
  6. package/Components/Loaders/Vendor.js +7 -7
  7. package/Components/ObjectBrowser.js +29 -29
  8. package/Components/UploadImage.js +305 -305
  9. package/Components/loader.css +221 -221
  10. package/Components/types.d.ts +82 -82
  11. package/GenericApp.js +49 -49
  12. package/LICENSE +22 -22
  13. package/Prompt.js +7 -7
  14. package/README.md +1004 -1005
  15. package/Theme.js +8 -7
  16. package/assets/devices/Alarm Systems.svg +18 -18
  17. package/assets/devices/Amplifier.svg +21 -21
  18. package/assets/devices/Awnings.svg +4 -4
  19. package/assets/devices/Battery Status.svg +4 -4
  20. package/assets/devices/Ceiling Spotlights.svg +15 -15
  21. package/assets/devices/Chandelier.svg +6 -6
  22. package/assets/devices/Climate.svg +11 -11
  23. package/assets/devices/Coffee Makers.svg +5 -5
  24. package/assets/devices/Cold Water.svg +31 -31
  25. package/assets/devices/Computer.svg +21 -21
  26. package/assets/devices/Consumption.svg +7 -7
  27. package/assets/devices/Curtains.svg +43 -43
  28. package/assets/devices/Dishwashers.svg +11 -11
  29. package/assets/devices/Doors.svg +5 -5
  30. package/assets/devices/Doorstep.svg +35 -35
  31. package/assets/devices/Dryer.svg +13 -13
  32. package/assets/devices/Fan.svg +20 -20
  33. package/assets/devices/Floor Lamps.svg +4 -4
  34. package/assets/devices/Garage Doors.svg +9 -9
  35. package/assets/devices/Gates.svg +32 -32
  36. package/assets/devices/Hairdryer.svg +23 -23
  37. package/assets/devices/Handle.svg +6 -6
  38. package/assets/devices/Hanging Lamps.svg +8 -8
  39. package/assets/devices/Heater.svg +44 -44
  40. package/assets/devices/Hoods.svg +11 -11
  41. package/assets/devices/Hot Water.svg +9 -9
  42. package/assets/devices/Humidity.svg +41 -41
  43. package/assets/devices/Iron.svg +4 -4
  44. package/assets/devices/Irrigation.svg +22 -22
  45. package/assets/devices/Led Strip.svg +30 -30
  46. package/assets/devices/Light.svg +29 -29
  47. package/assets/devices/Lightings.svg +46 -46
  48. package/assets/devices/Lock.svg +19 -19
  49. package/assets/devices/Louvre.svg +6 -6
  50. package/assets/devices/Mowing Machine.svg +8 -8
  51. package/assets/devices/Music.svg +12 -12
  52. package/assets/devices/Outdoor Blinds.svg +6 -6
  53. package/assets/devices/People.svg +19 -19
  54. package/assets/devices/Pool.svg +7 -7
  55. package/assets/devices/Power Consumption.svg +12 -12
  56. package/assets/devices/Printer.svg +9 -9
  57. package/assets/devices/Pump.svg +9 -9
  58. package/assets/devices/Receiver.svg +18 -18
  59. package/assets/devices/Sconces.svg +9 -9
  60. package/assets/devices/Security.svg +34 -34
  61. package/assets/devices/Shading.svg +4 -4
  62. package/assets/devices/Shutters.svg +10 -10
  63. package/assets/devices/SmokeDetector.svg +12 -12
  64. package/assets/devices/Sockets.svg +13 -13
  65. package/assets/devices/Speaker.svg +35 -35
  66. package/assets/devices/Stove.svg +11 -11
  67. package/assets/devices/Table Lamps.svg +11 -11
  68. package/assets/devices/Temperature Sensors.svg +28 -28
  69. package/assets/devices/Tv.svg +7 -7
  70. package/assets/devices/Vacuum Cleaner.svg +15 -15
  71. package/assets/devices/Ventilation.svg +12 -12
  72. package/assets/devices/Washing Machines.svg +15 -15
  73. package/assets/devices/Water Consumption.svg +5 -5
  74. package/assets/devices/Water Heater.svg +8 -8
  75. package/assets/devices/Water.svg +40 -40
  76. package/assets/devices/Weather.svg +28 -28
  77. package/assets/devices/Window.svg +7 -7
  78. package/assets/lamp_ceiling.svg +8 -8
  79. package/assets/lamp_table.svg +7 -7
  80. package/assets/no_icon.svg +9 -9
  81. package/assets/rooms/Anteroom.svg +52 -52
  82. package/assets/rooms/Attic.svg +21 -21
  83. package/assets/rooms/Balcony.svg +12 -12
  84. package/assets/rooms/Barn.svg +5 -5
  85. package/assets/rooms/Basement.svg +4 -4
  86. package/assets/rooms/Bathroom.svg +38 -38
  87. package/assets/rooms/Bedroom.svg +5 -5
  88. package/assets/rooms/Boiler Room.svg +12 -12
  89. package/assets/rooms/Carport.svg +17 -17
  90. package/assets/rooms/Cellar.svg +89 -89
  91. package/assets/rooms/Chamber.svg +9 -9
  92. package/assets/rooms/Corridor.svg +52 -52
  93. package/assets/rooms/Dining Area.svg +37 -37
  94. package/assets/rooms/Dining Room.svg +37 -37
  95. package/assets/rooms/Dining.svg +37 -37
  96. package/assets/rooms/Dressing Room.svg +4 -4
  97. package/assets/rooms/Driveway.svg +14 -14
  98. package/assets/rooms/Entrance.svg +44 -44
  99. package/assets/rooms/Equipment Room.svg +14 -14
  100. package/assets/rooms/Front Yard.svg +64 -64
  101. package/assets/rooms/Gallery.svg +13 -13
  102. package/assets/rooms/Garage.svg +20 -20
  103. package/assets/rooms/Garden.svg +12 -12
  104. package/assets/rooms/Ground Floor.svg +95 -95
  105. package/assets/rooms/Guest Bathroom.svg +32 -32
  106. package/assets/rooms/Guest Room.svg +5 -5
  107. package/assets/rooms/Gym.svg +4 -4
  108. package/assets/rooms/Hall.svg +19 -19
  109. package/assets/rooms/Home Theater.svg +7 -7
  110. package/assets/rooms/Kitchen.svg +17 -17
  111. package/assets/rooms/Laundry Room.svg +11 -11
  112. package/assets/rooms/Living Area.svg +10 -10
  113. package/assets/rooms/Living Room.svg +10 -10
  114. package/assets/rooms/Locker Room.svg +16 -16
  115. package/assets/rooms/Nursery.svg +4 -4
  116. package/assets/rooms/Office.svg +8 -8
  117. package/assets/rooms/Outdoors.svg +7 -7
  118. package/assets/rooms/Playroom.svg +5 -5
  119. package/assets/rooms/Pool.svg +7 -7
  120. package/assets/rooms/Rear Wall.svg +30 -30
  121. package/assets/rooms/Second Floor.svg +95 -95
  122. package/assets/rooms/Shed.svg +16 -16
  123. package/assets/rooms/Sleeping Area.svg +22 -22
  124. package/assets/rooms/Stairway.svg +4 -4
  125. package/assets/rooms/Stairwell.svg +15 -15
  126. package/assets/rooms/Storeroom.svg +4 -4
  127. package/assets/rooms/Summer House.svg +27 -27
  128. package/assets/rooms/Swimming Pool.svg +21 -21
  129. package/assets/rooms/Terrace.svg +6 -6
  130. package/assets/rooms/Toilet.svg +10 -10
  131. package/assets/rooms/Upstairs.svg +5 -5
  132. package/assets/rooms/Wardrobe.svg +60 -60
  133. package/assets/rooms/Washroom.svg +19 -19
  134. package/assets/rooms/Wc.svg +10 -10
  135. package/assets/rooms/Windscreen.svg +60 -60
  136. package/assets/rooms/Workshop.svg +22 -22
  137. package/assets/rooms/Workspace.svg +8 -8
  138. package/craco-module-federation.js +71 -71
  139. package/icons/IconFx.js +1 -1
  140. package/icons/IconLogout.js +1 -1
  141. package/index.css +54 -54
  142. package/modulefederation.admin.config.js +31 -31
  143. package/package.json +4 -4
  144. package/src/AdminConnection.tsx +3 -3
  145. package/src/Components/404.tsx +121 -121
  146. package/src/Components/ColorPicker.tsx +315 -315
  147. package/src/Components/ComplexCron.tsx +507 -507
  148. package/src/Components/CopyToClipboard.tsx +165 -165
  149. package/src/Components/CustomModal.tsx +163 -163
  150. package/src/Components/FileBrowser.tsx +2414 -2414
  151. package/src/Components/FileViewer.tsx +393 -393
  152. package/src/Components/Icon.tsx +210 -210
  153. package/src/Components/IconPicker.tsx +149 -149
  154. package/src/Components/IconSelector.tsx +2202 -2202
  155. package/src/Components/Image.tsx +176 -176
  156. package/src/Components/Loader.tsx +304 -304
  157. package/src/Components/Logo.tsx +166 -166
  158. package/src/Components/MDUtils.tsx +100 -100
  159. package/src/Components/ObjectBrowser.tsx +8032 -8032
  160. package/src/Components/Router.tsx +90 -90
  161. package/src/Components/SaveCloseButtons.tsx +113 -113
  162. package/src/Components/Schedule.tsx +1724 -1724
  163. package/src/Components/SelectWithIcon.tsx +197 -197
  164. package/src/Components/TabContainer.tsx +55 -55
  165. package/src/Components/TabContent.tsx +37 -37
  166. package/src/Components/TabHeader.tsx +19 -19
  167. package/src/Components/TableResize.tsx +259 -259
  168. package/src/Components/TextWithIcon.tsx +148 -148
  169. package/src/Components/ToggleThemeMenu.tsx +34 -34
  170. package/src/Components/TreeTable.tsx +919 -919
  171. package/src/Components/UploadImage.tsx +599 -599
  172. package/src/Components/Utils.tsx +1794 -1794
  173. package/src/Components/loader.css +221 -221
  174. package/src/Components/withWidth.tsx +21 -21
  175. package/src/Connection.tsx +7 -7
  176. package/src/Dialogs/ComplexCron.tsx +129 -129
  177. package/src/Dialogs/Confirm.tsx +162 -162
  178. package/src/Dialogs/Cron.tsx +182 -182
  179. package/src/Dialogs/Error.tsx +72 -72
  180. package/src/Dialogs/Message.tsx +71 -71
  181. package/src/Dialogs/SelectFile.tsx +270 -270
  182. package/src/Dialogs/SelectID.tsx +298 -298
  183. package/src/Dialogs/SimpleCron.tsx +100 -100
  184. package/src/Dialogs/TextInput.tsx +107 -107
  185. package/src/GenericApp.tsx +976 -976
  186. package/src/LegacyConnection.tsx +3589 -3589
  187. package/src/Prompt.tsx +20 -20
  188. package/src/Theme.tsx +479 -479
  189. package/src/icons/IconAdapter.tsx +20 -20
  190. package/src/icons/IconAlias.tsx +20 -20
  191. package/src/icons/IconChannel.tsx +21 -21
  192. package/src/icons/IconClearFilter.tsx +22 -22
  193. package/src/icons/IconClosed.tsx +17 -17
  194. package/src/icons/IconCopy.tsx +16 -16
  195. package/src/icons/IconDevice.tsx +27 -27
  196. package/src/icons/IconDocument.tsx +17 -17
  197. package/src/icons/IconDocumentReadOnly.tsx +18 -18
  198. package/src/icons/IconExpert.tsx +18 -18
  199. package/src/icons/IconFx.tsx +36 -36
  200. package/src/icons/IconInstance.tsx +20 -20
  201. package/src/icons/IconLogout.tsx +30 -30
  202. package/src/icons/IconNoIcon.tsx +19 -19
  203. package/src/icons/IconOpen.tsx +17 -17
  204. package/src/icons/IconProps.tsx +15 -15
  205. package/src/icons/IconState.tsx +17 -17
  206. package/src/index.css +54 -54
  207. package/types.d.ts +134 -134
@@ -1,1724 +1,1724 @@
1
- import React, { Component } from 'react';
2
-
3
- import {
4
- Input,
5
- Radio,
6
- FormControlLabel,
7
- FormGroup,
8
- Checkbox,
9
- MenuItem,
10
- Select,
11
- TextField, Box,
12
- } from '@mui/material';
13
-
14
- import I18n from '../i18n';
15
- import { IobTheme } from '../types';
16
- import Utils from './Utils';
17
-
18
- const styles: Record<string, any> = {
19
- hr: {
20
- border: 0,
21
- borderTop: '1px solid gray',
22
- },
23
- scrollWindow: {
24
- width: '100%',
25
- overflow: 'auto',
26
- height: 'calc(100% - 22px)',
27
- },
28
- rowDiv: {
29
- width: '100%',
30
- },
31
- modeDiv: {
32
- width: 200,
33
- display: 'inline-block',
34
- verticalAlign: 'top',
35
- },
36
- settingsDiv: {
37
- display: 'inline-block',
38
- verticalAlign: 'top',
39
- },
40
- inputTime: {
41
- width: 90,
42
- marginTop: 0,
43
- marginLeft: 5,
44
- },
45
- inputDate: {
46
- width: 140,
47
- marginTop: 0,
48
- marginLeft: 5,
49
- },
50
- inputEvery: {
51
- width: 40,
52
- marginLeft: 5,
53
- marginRight: 5,
54
- },
55
- inputRadio: {
56
- padding: '4px 12px',
57
- verticalAlign: 'top',
58
- },
59
- inputGroup: {
60
- maxWidth: 400,
61
- display: 'inline-block',
62
- },
63
- inputGroupElement: {
64
- width: 120,
65
- },
66
- inputDateDay: {
67
- width: 60,
68
- },
69
- inputDateDayCheck: {
70
- padding: 4,
71
- },
72
- inputSmallCheck: {
73
- padding: 0,
74
- },
75
- rowOnce: {
76
-
77
- },
78
- rowDays: (theme: IobTheme) => ({
79
- background: theme.palette.mode !== 'dark' ? '#ddeaff' : '#4b5057',
80
- }),
81
- rowDows: (theme: IobTheme) => ({
82
- background: theme.palette.mode !== 'dark' ? '#DDFFDD' : '#52646c',
83
- }),
84
- rowDates: (theme: IobTheme) => ({
85
- background: theme.palette.mode !== 'dark' ? '#DDDDFF' : '#747a86',
86
- }),
87
- rowWeeks: (theme: IobTheme) => ({
88
- background: theme.palette.mode !== 'dark' ? '#DDDDFF' : '#717680',
89
- }),
90
- rowMonths: (theme: IobTheme) => ({
91
- background: theme.palette.mode !== 'dark' ? '#DDFFFF' : '#1f5557',
92
- }),
93
- rowMonthsDates: (theme: IobTheme) => ({
94
- background: theme.palette.mode !== 'dark' ? '#EEFFFF' : '#3c5737',
95
- maxWidth: 600,
96
- }),
97
- rowYears: (theme: IobTheme) => ({
98
- background: theme.palette.mode !== 'dark' ? '#fbffdd' : '#574b33',
99
- }),
100
- rowDaysDows: (theme: IobTheme) => ({
101
- background: theme.palette.mode !== 'dark' ? '#EEEAFF' : '#573544',
102
- pl: '10px',
103
- pb: '10px',
104
- }),
105
- rowDowsDows: (theme: IobTheme) => ({
106
- background: theme.palette.mode !== 'dark' ? '#EEFFEE' : '#3d4c54',
107
- pl: '10px',
108
- pb: '10px',
109
- }),
110
- };
111
-
112
- const WEEKDAYS = [
113
- 'Sunday',
114
- 'Monday',
115
- 'Tuesday',
116
- 'Wednesday',
117
- 'Thursday',
118
- 'Friday',
119
- 'Saturday',
120
- 'Sunday',
121
- ];
122
- const MONTHS = [
123
- 'January',
124
- 'February',
125
- 'March',
126
- 'April',
127
- 'May',
128
- 'June',
129
- 'July',
130
- 'August',
131
- 'September',
132
- 'October',
133
- 'November',
134
- 'December',
135
- ];
136
- const PERIODS = {
137
- minutes: 'minutes',
138
- hours: 'hours',
139
- };
140
- const ASTRO = [
141
- 'sunrise',
142
- 'sunriseEnd',
143
- 'goldenHourEnd',
144
- 'solarNoon',
145
- 'goldenHour',
146
- 'sunsetStart',
147
- 'sunset',
148
- 'dusk',
149
- 'nauticalDusk',
150
- 'night',
151
- 'nightEnd',
152
- 'nauticalDawn',
153
- 'dawn',
154
- 'nadir',
155
- ];
156
-
157
- function padding(num: number): string {
158
- if (num < 10) {
159
- return `0${num}`;
160
- }
161
- return `${num}`;
162
- }
163
-
164
- interface ScheduleConfig {
165
- time: {
166
- exactTime: boolean;
167
- start: string;
168
- end: string;
169
- mode: string;
170
- interval: number;
171
- };
172
- period: {
173
- once: string;
174
- days: number;
175
- dows: string;
176
- dates: string;
177
- weeks: number;
178
- months: string | number;
179
- years: number;
180
- yearMonth: number;
181
- yearDate: number;
182
- };
183
- valid: {
184
- from: string;
185
- to?: string;
186
- };
187
- }
188
-
189
- // interface TextTimeProps {
190
- // inputRef: React.RefObject<HTMLInputElement>;
191
- // placeholder?: string;
192
- // }
193
-
194
- // function TextTime(props: TextTimeProps) {
195
- // const { inputRef, ...other } = props;
196
- //
197
- // return <MaskedInput
198
- // {...other}
199
- // ref={inputRef}
200
- // mask={[/[0-2]/, /[0-9]/, ':', /[0-5]/, /[0-9]/]}
201
- // placeholderChar={props.placeholder || '00:00'}
202
- // showMask
203
- // />;
204
- // }
205
-
206
- // function TextDate(props: TextTimeProps) {
207
- // const { inputRef, ...other } = props;
208
- //
209
- // return <MaskedInput
210
- // {...other}
211
- // ref={inputRef}
212
- // mask={[/[0-3]/, /[0-9]/, '.', /[0-1]/, /[0-9]/, '.', '2', '0', /[0-9]/, /[0-9]/]}
213
- // placeholderChar={props.placeholder || '01.01.2020'}
214
- // showMask
215
- // />;
216
- // }
217
-
218
- const DEFAULT: ScheduleConfig = {
219
- time: {
220
- exactTime: false,
221
-
222
- start: '00:00',
223
- end: '23:59',
224
-
225
- mode: 'hours',
226
- interval: 1,
227
- },
228
- period: {
229
- once: '',
230
- days: 1,
231
- dows: '',
232
- dates: '',
233
- weeks: 0,
234
- months: '',
235
-
236
- years: 0,
237
- yearMonth: 0,
238
- yearDate: 0,
239
- },
240
- valid: {
241
- from: '',
242
- to: '',
243
- },
244
- };
245
-
246
- function string2USdate(date: string): string {
247
- const parts = date.split('.');
248
- if (parts.length === 3) {
249
- return `${parts[2]}-${parts[1]}-${parts[0]}`;
250
- }
251
- return '';
252
- }
253
-
254
- interface ScheduleProps {
255
- schedule: string | ScheduleConfig;
256
- onChange: (schedule: string, desc?: string) => void;
257
- theme: IobTheme;
258
- }
259
-
260
- interface ScheduleState {
261
- schedule: ScheduleConfig;
262
- desc: string;
263
- }
264
-
265
- class Schedule extends Component<ScheduleProps, ScheduleState> {
266
- private readonly refFrom: React.RefObject<HTMLInputElement>;
267
-
268
- private readonly refTo: React.RefObject<HTMLInputElement>;
269
-
270
- private readonly refOnce: React.RefObject<HTMLInputElement>;
271
-
272
- private timerOnce: ReturnType<typeof setTimeout> | null = null;
273
-
274
- private timerFrom: ReturnType<typeof setTimeout> | null = null;
275
-
276
- private timerTo: ReturnType<typeof setTimeout> | null = null;
277
-
278
- constructor(props: ScheduleProps) {
279
- super(props);
280
- let schedule: ScheduleConfig | undefined;
281
- if (this.props.schedule && typeof this.props.schedule === 'string' && this.props.schedule[0] === '{') {
282
- try {
283
- schedule = JSON.parse(this.props.schedule);
284
- } catch (e) {
285
- // ignore
286
- }
287
- } else if (typeof this.props.schedule === 'object') {
288
- schedule = this.props.schedule;
289
- }
290
-
291
- if ((!schedule || !Object.keys(schedule).length)) {
292
- setTimeout(() => this.onChange(this.state.schedule, true), 200);
293
- schedule = DEFAULT;
294
- }
295
- schedule = { ...DEFAULT, ...schedule };
296
- schedule.valid.from = schedule.valid.from || Schedule.now2string();
297
-
298
- this.refFrom = React.createRef();
299
- this.refTo = React.createRef();
300
- this.refOnce = React.createRef();
301
-
302
- this.state = {
303
- schedule,
304
- desc: Schedule.state2text(schedule),
305
- };
306
-
307
- if (JSON.stringify(schedule) !== this.props.schedule) {
308
- setTimeout(() =>
309
- this.props.onChange && this.props.onChange(JSON.stringify(schedule)), 100);
310
- }
311
- }
312
-
313
- onChange(schedule: ScheduleConfig, force?: boolean) {
314
- const isDiff = JSON.stringify(schedule) !== JSON.stringify(this.state.schedule);
315
- if (force || isDiff) {
316
- isDiff && this.setState({ schedule, desc: Schedule.state2text(schedule) });
317
- const copy = JSON.parse(JSON.stringify(schedule));
318
- if (copy.period.once) {
319
- const once = copy.period.once;
320
- delete copy.period;
321
- copy.period = { once };
322
- delete copy.valid;
323
- } else if (copy.period.days) {
324
- const days = copy.period.days;
325
- const daysOfWeek = copy.period.dows;
326
- delete copy.period;
327
- copy.period = { days };
328
- if (daysOfWeek && daysOfWeek !== '[]') {
329
- copy.period.dows = daysOfWeek;
330
- }
331
- } else if (copy.period.weeks) {
332
- const weeks = copy.period.weeks;
333
- const daysOfWeek = copy.period.dows;
334
- delete copy.period;
335
- copy.period = { weeks };
336
- if (daysOfWeek && daysOfWeek !== '[]') {
337
- copy.period.dows = daysOfWeek;
338
- }
339
- } else if (copy.period.months) {
340
- const months = copy.period.months;
341
- const dates = copy.period.dates;
342
- delete copy.period;
343
- copy.period = { months };
344
- if (dates && dates !== '[]') {
345
- copy.period.dates = dates;
346
- }
347
- } else if (copy.period.years) {
348
- const years = copy.period.years;
349
- const yearMonth = copy.period.yearMonth;
350
- const yearDate = copy.period.yearDate;
351
- delete copy.period;
352
- copy.period = { years, yearDate };
353
- if (yearMonth) {
354
- copy.period.yearMonth = yearMonth;
355
- }
356
- }
357
-
358
- if (copy.time.exactTime) {
359
- delete copy.time.end;
360
- delete copy.time.mode;
361
- delete copy.time.interval;
362
- } else {
363
- delete copy.time.exactTime;
364
- }
365
- if (copy.valid) {
366
- if (!copy.valid.to) {
367
- delete copy.valid.to;
368
- }
369
- if (copy.period.days === 1 || copy.period.weeks === 1 || copy.period.months === 1 || copy.period.years === 1) {
370
- const from = Schedule.string2date(copy.valid.from);
371
- const today = new Date();
372
- today.setHours(0);
373
- today.setMinutes(0);
374
- today.setSeconds(0);
375
- today.setMilliseconds(0);
376
- if (from <= today) {
377
- delete copy.valid.from;
378
- }
379
- }
380
- if (!copy.valid.from && !copy.valid.to) {
381
- delete copy.valid;
382
- }
383
- }
384
-
385
- this.props.onChange && this.props.onChange(JSON.stringify(copy), Schedule.state2text(schedule));
386
- }
387
- }
388
-
389
- static state2text(schedule: string | ScheduleConfig): string {
390
- if (typeof schedule === 'string') {
391
- try {
392
- schedule = JSON.parse(schedule) as ScheduleConfig;
393
- } catch (e) {
394
- return '';
395
- }
396
- }
397
-
398
- const desc = [];
399
- const validFrom = Schedule.string2date(schedule.valid.from);
400
- if (schedule.period.once) {
401
- // once
402
- const once = Schedule.string2date(schedule.period.once);
403
- const now = new Date();
404
- now.setMilliseconds(0);
405
- now.setSeconds(0);
406
- now.setMinutes(0);
407
- now.setHours(0);
408
-
409
- //
410
- if (once < now) {
411
- // will be not executed anymore, because start is in the past
412
- return I18n.t('sch_desc_onceInPast');
413
- }
414
- // only once
415
- desc.push(I18n.t('sch_desc_once_on', schedule.period.once));
416
- } else if (schedule.period.days) {
417
- if (schedule.period.days === 1) {
418
- if (schedule.period.dows) {
419
- const daysOfWeek = JSON.parse(schedule.period.dows);
420
- if (daysOfWeek.length === 2 && daysOfWeek[0] === 0 && daysOfWeek[1] === 6) {
421
- // on weekends
422
- desc.push(I18n.t('sch_desc_onWeekends'));
423
- } else if (daysOfWeek.length === 5 && daysOfWeek[0] === 1 && daysOfWeek[1] === 2 && daysOfWeek[2] === 3 && daysOfWeek[3] === 4 && daysOfWeek[4] === 5) {
424
- // on workdays
425
- desc.push(I18n.t('sch_desc_onWorkdays'));
426
- } else {
427
- const tDows = daysOfWeek.map((day: number) => I18n.t(WEEKDAYS[day]));
428
- if (tDows.length === 1) {
429
- // on Monday
430
- desc.push(I18n.t('sch_desc_onWeekday', tDows[0]));
431
- } else if (tDows.length === 7) {
432
- // on every day
433
- desc.push(I18n.t('sch_desc_everyDay'));
434
- } else {
435
- const last = tDows.pop();
436
- // on Monday and Sunday
437
- desc.push(I18n.t('sch_desc_onWeekdays', tDows.join(', '), last));
438
- }
439
- }
440
- } else {
441
- desc.push(I18n.t('sch_desc_everyDay'));
442
- }
443
- } else {
444
- desc.push(I18n.t('sch_desc_everyNDay', schedule.period.days.toString()));
445
- }
446
- } else if (schedule.period.weeks) {
447
- if (schedule.period.weeks === 1) {
448
- desc.push(I18n.t('sch_desc_everyWeek'));
449
- } else {
450
- desc.push(I18n.t('sch_desc_everyNWeeks', schedule.period.weeks.toString()));
451
- }
452
-
453
- if (schedule.period.dows) {
454
- const daysOfWeek = JSON.parse(schedule.period.dows);
455
- if (daysOfWeek.length === 2 && daysOfWeek[0] === 0 && daysOfWeek[1] === 6) {
456
- // on weekends
457
- desc.push(I18n.t('sch_desc_onWeekends'));
458
- } else if (daysOfWeek.length === 5 && daysOfWeek[0] === 1 && daysOfWeek[1] === 2 && daysOfWeek[2] === 3 && daysOfWeek[3] === 4 && daysOfWeek[4] === 5) {
459
- // on workdays
460
- desc.push(I18n.t('sch_desc_onWorkdays'));
461
- } else {
462
- const tDows = daysOfWeek.map((day: number) => I18n.t(WEEKDAYS[day]));
463
- if (tDows.length === 1) {
464
- // on Monday
465
- desc.push(I18n.t('sch_desc_onWeekday', tDows[0]));
466
- } else if (tDows.length === 7) {
467
- // on every day
468
- desc.push(I18n.t('sch_desc_everyDay'));
469
- } else {
470
- const last = tDows.pop();
471
- // on Monday and Sunday
472
- desc.push(I18n.t('sch_desc_onWeekdays', tDows.join(', '), last));
473
- }
474
- }
475
- } else {
476
- return I18n.t('sch_desc_never');
477
- }
478
- } else if (schedule.period.months) {
479
- if (schedule.period.dates) {
480
- const dates = JSON.parse(schedule.period.dates);
481
- if (dates.length === 1) {
482
- // in 1 of month
483
- desc.push(I18n.t('sch_desc_onDate', dates[0]));
484
- } else if (dates.length === 31) {
485
- desc.push(I18n.t('sch_desc_onEveryDate'));
486
- } else if (!dates.length) {
487
- return I18n.t('sch_desc_never');
488
- } else {
489
- const last = dates.pop();
490
- // in 1 and 4 of month
491
- desc.push(I18n.t('sch_desc_onDates', dates.join(', '), last));
492
- }
493
- } else {
494
- desc.push(I18n.t('sch_desc_onEveryDate'));
495
- }
496
-
497
- if (schedule.period.months === 1) {
498
- desc.push(I18n.t('sch_desc_everyMonth'));
499
- } else if (typeof schedule.period.months === 'number') {
500
- desc.push(I18n.t('sch_desc_everyNMonths', schedule.period.months.toString()));
501
- } else {
502
- const months = JSON.parse(schedule.period.months);
503
- const tMonths = months.map((month: number) => I18n.t(MONTHS[month - 1]));
504
- if (!tMonths.length) {
505
- // in January
506
- return I18n.t('sch_desc_never');
507
- }
508
- if (tMonths.length === 1) {
509
- // in January
510
- desc.push(I18n.t('sch_desc_onMonth', tMonths[0]));
511
- } else if (tMonths.length === 12) {
512
- // every month
513
- desc.push(I18n.t('sch_desc_everyMonth'));
514
- } else {
515
- const last = tMonths.pop();
516
- // in January and May
517
- desc.push(I18n.t('sch_desc_onMonths', tMonths.join(', '), last));
518
- }
519
- }
520
- } else if (schedule.period.years) {
521
- if (schedule.period.years === 1) {
522
- desc.push(I18n.t('sch_desc_everyYear'));
523
- } else {
524
- desc.push(I18n.t('sch_desc_everyNYears', schedule.period.years.toString()));
525
- }
526
- desc.push(I18n.t(
527
- 'sch_desc_onDate',
528
- schedule.period.yearDate.toString(),
529
- schedule.period.yearMonth ? I18n.t(MONTHS[schedule.period.yearMonth - 1]) : I18n.t('sch_desc_everyMonth'),
530
- ));
531
- }
532
-
533
- // time
534
- if (schedule.time.exactTime) {
535
- if (ASTRO.includes(schedule.time.start)) {
536
- // at sunset
537
- desc.push(I18n.t('sch_desc_atTime', I18n.t(`sch_astro_${schedule.time.start}`)));
538
- } else {
539
- // at HH:MM
540
- desc.push(I18n.t('sch_desc_atTime', schedule.time.start));
541
- }
542
- } else {
543
- if (schedule.time.mode === PERIODS.minutes) {
544
- if (schedule.time.interval === 1) {
545
- // every minute
546
- desc.push(I18n.t('sch_desc_everyMinute'));
547
- } else {
548
- // every N minutes
549
- desc.push(I18n.t('sch_desc_everyNMinutes', schedule.time.interval.toString()));
550
- }
551
- } else if (schedule.time.interval === 1) {
552
- // every minute
553
- desc.push(I18n.t('sch_desc_everyHour'));
554
- } else {
555
- // every N minutes
556
- desc.push(I18n.t('sch_desc_everyNHours', schedule.time.interval.toString()));
557
- }
558
-
559
- const start = ASTRO.indexOf(schedule.time.start) !== -1 ? I18n.t(`sch_astro_${schedule.time.start}`) : schedule.time.start;
560
- const end = ASTRO.indexOf(schedule.time.end) !== -1 ? I18n.t(`sch_astro_${schedule.time.end}`) : schedule.time.end;
561
- if (start !== '00:00' || (end !== '24:00' && end !== '23:59')) {
562
- // from HH:mm to HH:mm
563
- desc.push(I18n.t('sch_desc_intervalFromTo', start, end));
564
- }
565
- }
566
-
567
- if (!schedule.period.once) {
568
- // valid
569
- if (validFrom.getTime() > Date.now() && schedule.valid.to) {
570
- // from XXX to XXXX
571
- desc.push(I18n.t('sch_desc_validFromTo', schedule.valid.from, schedule.valid.to));
572
- } else if (validFrom.getTime() > Date.now()) {
573
- // from XXXX
574
- desc.push(I18n.t('sch_desc_validFrom', schedule.valid.from));
575
- } else if (schedule.valid.to) {
576
- // till XXXX
577
- desc.push(I18n.t('sch_desc_validTo', schedule.valid.to));
578
- }
579
- }
580
- return desc.join(' ');
581
- }
582
-
583
- getTimePeriodElements() {
584
- const schedule = this.state.schedule;
585
- let wholeDay = false;
586
- let day = false;
587
- let night = false;
588
- let fromTo = true;
589
- if (schedule.time.start === '00:00' && schedule.time.end === '24:00') {
590
- wholeDay = true;
591
- fromTo = false;
592
- } else if (schedule.time.start === 'sunrise') {
593
- day = true;
594
- fromTo = false;
595
- } else if (schedule.time.start === 'sunset') {
596
- night = true;
597
- fromTo = false;
598
- }
599
-
600
- return <div key="timePeriod" style={styles.rowDiv}>
601
- <div style={styles.modeDiv}>
602
- <FormControlLabel
603
- control={<Radio
604
- style={styles.inputRadio}
605
- checked={!schedule.time.exactTime}
606
- onClick={() => {
607
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
608
- _schedule.time.exactTime = false;
609
- this.onChange(_schedule);
610
- }}
611
- />}
612
- label={I18n.t('sch_intervalTime')}
613
- />
614
- </div>
615
- <div style={styles.settingsDiv}>
616
- <div style={styles.settingsDiv}>
617
- {!schedule.time.exactTime && <div>
618
- <div>
619
- <FormControlLabel
620
- control={<Radio
621
- style={styles.inputRadio}
622
- checked={!!fromTo}
623
- onClick={() => {
624
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
625
- _schedule.time.start = '00:00';
626
- _schedule.time.end = '23:59';
627
- this.onChange(_schedule);
628
- }}
629
- />}
630
- label={!fromTo ? I18n.t('sch_fromTo') : ''}
631
- />
632
- {fromTo && [
633
- <TextField
634
- variant="standard"
635
- style={{ ...styles.inputTime, marginRight: 10 }}
636
- key="exactTimeFrom"
637
- type="time"
638
- value={this.state.schedule.time.start}
639
- // InputProps={{inputComponent: TextTime}}
640
- onChange={e => {
641
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
642
- _schedule.time.start = e.target.value;
643
- this.onChange(_schedule);
644
- }}
645
- InputLabelProps={{ shrink: true }}
646
- label={I18n.t('sch_from')}
647
- margin="normal"
648
- />,
649
- <TextField
650
- variant="standard"
651
- style={styles.inputTime}
652
- key="exactTimeTo"
653
- type="time"
654
- value={this.state.schedule.time.end}
655
- // InputProps={{inputComponent: TextTime}}
656
- onChange={e => {
657
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
658
- _schedule.time.end = e.target.value;
659
- this.onChange(_schedule);
660
- }}
661
- InputLabelProps={{ shrink: true }}
662
- label={I18n.t('sch_to')}
663
- margin="normal"
664
- />,
665
- ]}
666
- </div>
667
- </div>}
668
-
669
- {!schedule.time.exactTime && <div>
670
- <FormControlLabel
671
- control={<Radio
672
- style={styles.inputRadio}
673
- checked={!!wholeDay}
674
- onClick={() => {
675
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
676
- _schedule.time.start = '00:00';
677
- _schedule.time.end = '24:00';
678
- this.onChange(_schedule);
679
- }}
680
- />}
681
- label={I18n.t('sch_wholeDay')}
682
- />
683
- </div>}
684
-
685
- {!schedule.time.exactTime && <div>
686
- <FormControlLabel
687
- control={<Radio
688
- style={styles.inputRadio}
689
- checked={!!day}
690
- onClick={() => {
691
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
692
- _schedule.time.start = 'sunrise';
693
- _schedule.time.end = 'sunset';
694
- this.onChange(_schedule);
695
- }}
696
- />}
697
- label={I18n.t('sch_astroDay')}
698
- />
699
- </div>}
700
-
701
- {!schedule.time.exactTime && <div>
702
- <FormControlLabel
703
- control={<Radio
704
- style={styles.inputRadio}
705
- checked={!!night}
706
- onClick={() => {
707
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
708
- _schedule.time.start = 'sunset';
709
- _schedule.time.end = 'sunrise';
710
- this.onChange(_schedule);
711
- }}
712
- />}
713
- label={I18n.t('sch_astroNight')}
714
- />
715
- </div>}
716
- </div>
717
- {!schedule.time.exactTime && this.getPeriodSettingsMinutes()}
718
- </div>
719
- </div>;
720
- }
721
-
722
- getTimeExactElements() {
723
- const isAstro = ASTRO.includes(this.state.schedule.time.start);
724
-
725
- return <div key="timeExact" style={styles.rowDiv}>
726
- <div style={styles.modeDiv}>
727
- <FormControlLabel
728
- control={<Radio
729
- style={styles.inputRadio}
730
- checked={!!this.state.schedule.time.exactTime}
731
- onClick={() => {
732
- const schedule = JSON.parse(JSON.stringify(this.state.schedule));
733
- schedule.time.exactTime = true;
734
- this.onChange(schedule);
735
- }}
736
- />}
737
- label={I18n.t('sch_exactTime')}
738
- />
739
- </div>
740
- {this.state.schedule.time.exactTime && <Select
741
- variant="standard"
742
- value={isAstro ? this.state.schedule.time.start : '00:00'}
743
- onChange={e => {
744
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
745
- _schedule.time.start = e.target.value;
746
- this.onChange(_schedule);
747
- }}
748
- >
749
- <MenuItem key="specific" value="00:00">{I18n.t('sch_specificTime')}</MenuItem>
750
- {ASTRO.map(event => <MenuItem key={event} value={event}>{I18n.t(`sch_astro_${event}`)}</MenuItem>)}
751
- </Select>}
752
- {this.state.schedule.time.exactTime && !isAstro &&
753
- <div style={styles.settingsDiv}>
754
- <TextField
755
- variant="standard"
756
- style={styles.inputTime}
757
- key="exactTimeValue"
758
- value={this.state.schedule.time.start}
759
- type="time"
760
- // inputComponent={TextTime}
761
- onChange={e => {
762
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
763
- _schedule.time.start = e.target.value;
764
- this.onChange(_schedule);
765
- }}
766
- InputLabelProps={{ shrink: true }}
767
- margin="normal"
768
- />
769
- </div>}
770
- </div>;
771
- }
772
-
773
- static getDivider() {
774
- return <hr style={styles.hr} />;
775
- }
776
-
777
- getPeriodModes() {
778
- const schedule = this.state.schedule;
779
- const isOnce = !schedule.period.dows && !schedule.period.months && !schedule.period.dates && !schedule.period.years && !schedule.period.days && !schedule.period.weeks;
780
- if (isOnce && !schedule.period.once) {
781
- schedule.period.once = Schedule.now2string(true);
782
- }
783
-
784
- return [
785
- // ----- once ---
786
- <div key="once" style={{ ...styles.rowDiv, ...styles.rowOnce }}>
787
- <div style={styles.modeDiv}>
788
- <FormControlLabel
789
- control={<Radio
790
- style={styles.inputRadio}
791
- checked={!!isOnce}
792
- onClick={() => {
793
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
794
- _schedule.period.once = _schedule.period.once || Schedule.now2string(true);
795
- _schedule.period.dows = '';
796
- _schedule.period.months = '';
797
- _schedule.period.dates = '';
798
- _schedule.period.years = 0;
799
- _schedule.period.yearDate = 0;
800
- _schedule.period.yearMonth = 0;
801
- _schedule.period.weeks = 0;
802
- _schedule.period.days = 0;
803
- this.onChange(_schedule);
804
- }}
805
- />}
806
- label={I18n.t('sch_periodOnce')}
807
- />
808
- </div>
809
- {isOnce && <div style={styles.settingsDiv}>
810
- <TextField
811
- variant="standard"
812
- style={styles.inputDate}
813
- type="date"
814
- ref={this.refOnce}
815
- key="exactDateAt"
816
- defaultValue={string2USdate(schedule.period.once)}
817
- // InputProps={{inputComponent: TextTime}}
818
- onChange={e => {
819
- this.timerOnce && clearTimeout(this.timerOnce);
820
- this.timerOnce = null;
821
-
822
- if (this.refOnce.current) {
823
- this.refOnce.current.style.background = '#ff000030';
824
- }
825
- this.timerOnce = setTimeout(value => {
826
- this.timerOnce = null;
827
- if (this.refOnce.current) {
828
- this.refOnce.current.style.background = '';
829
- }
830
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
831
- const date = Schedule.string2date(value);
832
- if (date.toString() !== 'Invalid Date') {
833
- _schedule.period.once = `${padding(date.getDate())}.${padding(date.getMonth() + 1)}.${date.getFullYear()}`;
834
- this.onChange(_schedule);
835
- }
836
- }, 1500, e.target.value);
837
- }}
838
- InputLabelProps={{ shrink: true }}
839
- label={I18n.t('sch_at')}
840
- margin="normal"
841
- />
842
- </div>}
843
- </div>,
844
-
845
- // ----- days ---
846
- <Box component="div" key="days" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowDays)}>
847
- <div style={styles.modeDiv}>
848
- <FormControlLabel
849
- control={<Radio
850
- style={styles.inputRadio}
851
- checked={!!schedule.period.days}
852
- onClick={() => {
853
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
854
- _schedule.period.days = 1;
855
- _schedule.period.dows = '';
856
- _schedule.period.months = '';
857
- _schedule.period.dates = '';
858
- _schedule.period.years = 0;
859
- _schedule.period.yearDate = 0;
860
- _schedule.period.yearMonth = 0;
861
- _schedule.period.weeks = 0;
862
- _schedule.period.once = '';
863
- this.onChange(_schedule);
864
- }}
865
- />}
866
- label={I18n.t('sch_periodDaily')}
867
- />
868
- </div>
869
- <div style={styles.settingsDiv}>
870
- {this.getPeriodSettingsDaily()}
871
- {schedule.period.days ? this.getPeriodSettingsWeekdays() : null}
872
- </div>
873
- </Box>,
874
-
875
- // ----- days of weeks ---
876
- /*
877
- !schedule.period.days && (
878
- <div key="dows" style={styles.rowDiv + ' ' + styles.rowDows}>
879
- <div style={styles.modeDiv}>
880
- <FormControlLabel control={<Radio style={styles.inputRadio} checked={!!schedule.period.dows} onClick={() => {
881
- const schedule = JSON.parse(JSON.stringify(this.state.schedule));
882
- schedule.period.dows = schedule.period.dows ? '' : '[0,1,2,3,4,5,6]';
883
- this.onChange(schedule);
884
- }}/>}
885
- label={I18n.t('sch_periodWeekdays')} />
886
- </div>
887
- <div style={styles.settingsDiv}>
888
- {this.getPeriodSettingsWeekdays()}
889
- </div>
890
- </div>,
891
- */
892
- // ----- weeks ---
893
- <Box component="div" key="weeks" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowDows)}>
894
- <div style={styles.modeDiv}>
895
- <FormControlLabel
896
- control={<Radio
897
- style={styles.inputRadio}
898
- checked={!!schedule.period.weeks}
899
- onClick={() => {
900
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
901
- _schedule.period.weeks = schedule.period.weeks ? 0 : 1;
902
- _schedule.period.dows = schedule.period.dows || '[0]';
903
- _schedule.period.months = '';
904
- _schedule.period.dates = '';
905
- _schedule.period.years = 0;
906
- _schedule.period.yearDate = 0;
907
- _schedule.period.yearMonth = 0;
908
- _schedule.period.days = 0;
909
- _schedule.period.once = '';
910
- this.onChange(_schedule);
911
- }}
912
- />}
913
- label={I18n.t('sch_periodWeekly')}
914
- />
915
- </div>
916
- <Box component="div" style={styles.settingsDiv}>
917
- <div style={styles.settingsDiv}>{this.getPeriodSettingsWeekly()}</div>
918
- <Box component="div" sx={Utils.getStyle(this.props.theme, styles.settingsDiv, styles.rowDowsDows)}>
919
- {this.state.schedule.period.weeks ? this.getPeriodSettingsWeekdays() : null}
920
- </Box>
921
- </Box>
922
- </Box>,
923
-
924
- // ----- months ---
925
- <Box component="div" key="months" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowMonths)}>
926
- <div style={styles.modeDiv}>
927
- <FormControlLabel
928
- control={<Radio
929
- style={styles.inputRadio}
930
- checked={!!schedule.period.months}
931
- onClick={() => {
932
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
933
- _schedule.period.months = 1;
934
- _schedule.period.dows = '';
935
- _schedule.period.dates = '';
936
- _schedule.period.years = 0;
937
- _schedule.period.yearDate = 0;
938
- _schedule.period.yearMonth = 0;
939
- _schedule.period.weeks = 0;
940
- _schedule.period.days = 0;
941
- _schedule.period.once = '';
942
- this.onChange(_schedule);
943
- }}
944
- />}
945
- label={I18n.t('sch_periodMonthly')}
946
- />
947
- </div>
948
- <div style={styles.settingsDiv}>
949
- {this.getPeriodSettingsMonthly()}
950
- {schedule.period.months ? <Box>
951
- <Box component="div" sx={Utils.getStyle(this.props.theme, styles.settingsDiv, styles.rowMonthsDates)}>
952
- <FormControlLabel
953
- control={<Checkbox
954
- style={styles.inputRadio}
955
- checked={!!schedule.period.dates}
956
- onClick={() => {
957
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
958
- _schedule.period.months = _schedule.period.months || 1;
959
- const dates = [];
960
- for (let i = 1; i <= 31; i++) {
961
- dates.push(i);
962
- }
963
- _schedule.period.dates = _schedule.period.dates || JSON.stringify(dates);
964
- _schedule.period.dows = '';
965
- _schedule.period.years = 0;
966
- _schedule.period.yearDate = 0;
967
- _schedule.period.yearMonth = 0;
968
- _schedule.period.weeks = 0;
969
- _schedule.period.days = 0;
970
- _schedule.period.once = '';
971
-
972
- this.onChange(_schedule);
973
- }}
974
- />}
975
- label={I18n.t('sch_periodDates')}
976
- />
977
- </Box>
978
- <Box component="div" sx={Utils.getStyle(this.props.theme, styles.settingsDiv, styles.rowMonthsDates)}>
979
- {this.getPeriodSettingsDates()}
980
- </Box>
981
- </Box> : null}
982
- </div>
983
- </Box>,
984
-
985
- // ----- years ---
986
- <Box component="div" key="years" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowYears)}>
987
- <div style={styles.modeDiv}>
988
- <FormControlLabel
989
- control={<Radio
990
- style={styles.inputRadio}
991
- checked={!!schedule.period.years}
992
- onClick={() => {
993
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
994
- _schedule.period.years = 1;
995
- _schedule.period.yearDate = 1;
996
- _schedule.period.yearMonth = 1;
997
- _schedule.period.dows = '';
998
- _schedule.period.months = 0;
999
- _schedule.period.dates = '';
1000
- _schedule.period.weeks = 0;
1001
- _schedule.period.days = 0;
1002
- _schedule.period.once = '';
1003
- this.onChange(_schedule);
1004
- }}
1005
- />}
1006
- label={I18n.t('sch_periodYearly')}
1007
- />
1008
- </div>
1009
- <div style={styles.settingsDiv}>
1010
- <div style={styles.settingsDiv}>{this.getPeriodSettingsYearly()}</div>
1011
- {!!schedule.period.years && <div style={styles.settingsDiv}>
1012
- <span>{I18n.t('sch_on')}</span>
1013
- <Input
1014
- key="input"
1015
- value={this.state.schedule.period.yearDate}
1016
- style={styles.inputEvery}
1017
- type="number"
1018
- inputProps={{ min: 1, max: 31 }}
1019
- onChange={e => {
1020
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1021
- _schedule.period.yearDate = parseInt(e.target.value, 10);
1022
- if (_schedule.period.yearDate < 1) _schedule.period.yearDate = 31;
1023
- if (_schedule.period.yearDate > 31) _schedule.period.yearDate = 1;
1024
- this.onChange(_schedule);
1025
- }}
1026
- />
1027
- <Select
1028
- variant="standard"
1029
- value={schedule.period.yearMonth}
1030
- onChange={e => {
1031
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1032
- _schedule.period.yearMonth = e.target.value;
1033
- this.onChange(_schedule);
1034
- }}
1035
- >
1036
- <MenuItem key="every" value={0}>{I18n.t('sch_yearEveryMonth')}</MenuItem>
1037
- {MONTHS.map((month, i) => <MenuItem key={month} value={i + 1}>{I18n.t(month)}</MenuItem>)}
1038
- </Select>
1039
- </div>}
1040
- </div>
1041
- </Box>,
1042
- ];
1043
- }
1044
-
1045
- getPeriodSettingsMinutes() {
1046
- return <div style={{ display: 'inline-block' }}>
1047
- <label>{I18n.t('sch_every')}</label>
1048
- <Input
1049
- value={this.state.schedule.time.interval}
1050
- style={{ ...styles.inputEvery, verticalAlign: 'bottom' }}
1051
- type="number"
1052
- inputProps={{ min: 1 }}
1053
- onChange={e => {
1054
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1055
- _schedule.time.interval = parseInt(e.target.value, 10);
1056
- this.onChange(_schedule);
1057
- }}
1058
- />
1059
- <Select
1060
- variant="standard"
1061
- value={this.state.schedule.time.mode}
1062
- onChange={e => {
1063
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1064
- _schedule.time.mode = e.target.value;
1065
- this.onChange(_schedule);
1066
- }}
1067
- >
1068
- <MenuItem value={PERIODS.minutes}>{I18n.t('sch_periodMinutes')}</MenuItem>
1069
- <MenuItem value={PERIODS.hours}>{I18n.t('sch_periodHours')}</MenuItem>
1070
- </Select>
1071
- </div>;
1072
- }
1073
-
1074
- getPeriodSettingsWeekdays() {
1075
- // || this.state.schedule.period.dows === '[1, 2, 3, 4, 5]' || this.state.schedule.period.dows === '[0, 6]'
1076
- const schedule = this.state.schedule;
1077
- const isSpecific = schedule.period.dows && schedule.period.dows !== '[1, 2, 3, 4, 5]' && schedule.period.dows !== '[0, 6]';
1078
- return [
1079
- <div key="workdays">
1080
- <FormControlLabel
1081
- control={<Radio
1082
- style={styles.inputRadio}
1083
- checked={schedule.period.dows === '[1, 2, 3, 4, 5]'}
1084
- onClick={() => {
1085
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1086
- _schedule.period.dows = '[1, 2, 3, 4, 5]';
1087
- if (_schedule.period.days) {
1088
- _schedule.period.days = 1;
1089
- }
1090
- this.onChange(_schedule);
1091
- }}
1092
- />}
1093
- label={I18n.t('sch_periodWorkdays')}
1094
- />
1095
- </div>,
1096
-
1097
- <div key="weekend">
1098
- <FormControlLabel
1099
- control={<Radio
1100
- style={styles.inputRadio}
1101
- checked={schedule.period.dows === '[0, 6]'}
1102
- onClick={() => {
1103
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1104
- _schedule.period.dows = '[0, 6]';
1105
- if (_schedule.period.days) {
1106
- _schedule.period.days = 1;
1107
- }
1108
- this.onChange(_schedule);
1109
- }}
1110
- />}
1111
- label={I18n.t('sch_periodWeekend')}
1112
- />
1113
- </div>,
1114
-
1115
- <div
1116
- key="specific"
1117
- style={{ verticalAlign: 'top' }}
1118
- >
1119
- <FormControlLabel
1120
- style={{ verticalAlign: 'top' }}
1121
- control={<Radio
1122
- style={styles.inputRadio}
1123
- checked={!!isSpecific}
1124
- onClick={() => {
1125
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1126
- _schedule.period.dows = '[0, 1, 2, 3, 4, 5, 6]';
1127
- if (_schedule.period.days) {
1128
- _schedule.period.days = 1;
1129
- }
1130
- this.onChange(_schedule);
1131
- }}
1132
- />}
1133
- label={I18n.t('sch_periodWeekdays')}
1134
- />
1135
- {isSpecific && (schedule.period.days === 1 || schedule.period.weeks) &&
1136
- <FormGroup row style={{ ...styles.inputGroup, width: 150 }}>
1137
- {[1, 2, 3, 4, 5, 6, 0].map(i =>
1138
- <FormControlLabel
1139
- key={`specific_${i}`}
1140
- style={styles.inputGroupElement}
1141
- control={<Checkbox
1142
- style={styles.inputSmallCheck}
1143
- checked={schedule.period.dows.includes(i.toString())}
1144
- onChange={e => {
1145
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1146
- let daysOfWeek: number[];
1147
- try {
1148
- daysOfWeek = JSON.parse(_schedule.period.dows);
1149
- } catch (err) {
1150
- daysOfWeek = [];
1151
- }
1152
- if (e.target.checked && !daysOfWeek.includes(i)) {
1153
- daysOfWeek.push(i);
1154
- } else if (!e.target.checked && daysOfWeek.includes(i)) {
1155
- daysOfWeek.splice(daysOfWeek.indexOf(i), 1);
1156
- }
1157
- daysOfWeek.sort((a: number, b: number) => a - b);
1158
- _schedule.period.dows = JSON.stringify(daysOfWeek);
1159
- if (_schedule.period.days) {
1160
- _schedule.period.days = 1;
1161
- }
1162
- this.onChange(_schedule);
1163
- }}
1164
- />}
1165
- label={I18n.t(WEEKDAYS[i])}
1166
- />)}
1167
- </FormGroup>}
1168
- </div>,
1169
- ];
1170
- }
1171
-
1172
- getPeriodSettingsDaily() {
1173
- if (!this.state.schedule.period.days) {
1174
- return null;
1175
- }
1176
- const schedule = this.state.schedule;
1177
- return [
1178
- <div key="every_day">
1179
- <FormControlLabel
1180
- control={<Radio
1181
- style={styles.inputRadio}
1182
- checked={schedule.period.days === 1 && !schedule.period.dows}
1183
- onClick={() => {
1184
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1185
- _schedule.period.days = 1;
1186
- _schedule.period.dows = '';
1187
- this.onChange(_schedule);
1188
- }}
1189
- />}
1190
- label={I18n.t('sch_periodEveryDay')}
1191
- />
1192
- </div>,
1193
- <div key="everyN_day">
1194
- <FormControlLabel
1195
- control={<Radio
1196
- style={styles.inputRadio}
1197
- checked={schedule.period.days > 1}
1198
- onClick={() => {
1199
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1200
- _schedule.period.days = 2;
1201
- _schedule.period.dows = '';
1202
- this.onChange(_schedule);
1203
- }}
1204
- />}
1205
- label={I18n.t('sch_periodEvery')}
1206
- />
1207
- {schedule.period.days > 1 && [
1208
- <Input
1209
- key="input"
1210
- value={this.state.schedule.period.days}
1211
- style={styles.inputEvery}
1212
- type="number"
1213
- inputProps={{ min: 2 }}
1214
- onChange={e => {
1215
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1216
- _schedule.period.days = parseInt(e.target.value, 10);
1217
- _schedule.period.dows = '';
1218
- this.onChange(_schedule);
1219
- }}
1220
- />,
1221
- <span key="span" style={{ paddingRight: 10 }}>{I18n.t('sch_periodDay')}</span>,
1222
- ]}
1223
- </div>,
1224
- ];
1225
- }
1226
-
1227
- getPeriodSettingsWeekly() {
1228
- if (!this.state.schedule.period.weeks) {
1229
- return null;
1230
- }
1231
- const schedule = this.state.schedule;
1232
- return [
1233
- <div key="radios" style={{ display: 'inline-block', verticalAlign: 'top' }}>
1234
- <div>
1235
- <FormControlLabel
1236
- control={<Radio
1237
- style={styles.inputRadio}
1238
- checked={schedule.period.weeks === 1}
1239
- onClick={() => {
1240
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1241
- _schedule.period.weeks = 1;
1242
- this.onChange(_schedule);
1243
- }}
1244
- />}
1245
- label={I18n.t('sch_periodEveryWeek')}
1246
- />
1247
- </div>
1248
- <div>
1249
- <FormControlLabel
1250
- control={<Radio
1251
- style={styles.inputRadio}
1252
- checked={schedule.period.weeks > 1}
1253
- onClick={() => {
1254
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1255
- _schedule.period.weeks = 2;
1256
- this.onChange(_schedule);
1257
- }}
1258
- />}
1259
- label={I18n.t('sch_periodEvery')}
1260
- />
1261
- {schedule.period.weeks > 1 && [
1262
- <Input
1263
- key="input"
1264
- value={this.state.schedule.period.weeks}
1265
- style={styles.inputEvery}
1266
- type="number"
1267
- inputProps={{ min: 2 }}
1268
- onChange={e => {
1269
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1270
- _schedule.period.weeks = parseInt(e.target.value, 10);
1271
- this.onChange(_schedule);
1272
- }}
1273
- />,
1274
- <span key="text">{I18n.t('sch_periodWeek')}</span>,
1275
- ]}
1276
- </div>
1277
- </div>,
1278
- ];
1279
- }
1280
-
1281
- getPeriodSettingsDates() {
1282
- if (!this.state.schedule.period.dates) {
1283
- return null;
1284
- }
1285
- const schedule = this.state.schedule;
1286
-
1287
- const dates = [];
1288
- for (let i = 1; i <= 31; i++) {
1289
- dates.push(i);
1290
- }
1291
-
1292
- const parsedDates = JSON.parse(schedule.period.dates);
1293
-
1294
- return <FormGroup
1295
- row
1296
- style={{ ...styles.inputGroup, maxWidth: 620 }}
1297
- >
1298
- <FormControlLabel
1299
- style={styles.inputDateDay}
1300
- control={<Checkbox
1301
- style={styles.inputDateDayCheck}
1302
- checked={parsedDates.length === 31}
1303
- onChange={() => {
1304
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1305
- const _dates = [];
1306
- for (let i = 1; i <= 31; i++) {
1307
- _dates.push(i);
1308
- }
1309
- _schedule.period.dates = JSON.stringify(_dates);
1310
- this.onChange(_schedule);
1311
- }}
1312
- />}
1313
- label={I18n.t('sch_all')}
1314
- />
1315
- <FormControlLabel
1316
- style={styles.inputDateDay}
1317
- control={<Checkbox
1318
- style={styles.inputDateDayCheck}
1319
- checked={!parsedDates.length}
1320
- onChange={() => {
1321
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1322
- _schedule.period.dates = '[]';
1323
- this.onChange(_schedule);
1324
- }}
1325
- />}
1326
- label={I18n.t('sch_no_one')}
1327
- />
1328
- {parsedDates.length !== 31 && !!parsedDates.length &&
1329
- <FormControlLabel
1330
- style={styles.inputDateDay}
1331
- control={<Checkbox
1332
- style={styles.inputDateDayCheck}
1333
- checked={false}
1334
- onChange={() => {
1335
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1336
- const result = [];
1337
- const _parsedDates = JSON.parse(_schedule.period.dates);
1338
- for (let i = 1; i <= 31; i++) {
1339
- if (!_parsedDates.includes(i)) {
1340
- result.push(i);
1341
- }
1342
- }
1343
- result.sort((a, b) => a - b);
1344
- _schedule.period.dates = JSON.stringify(result);
1345
- this.onChange(_schedule);
1346
- }}
1347
- />}
1348
- label={I18n.t('sch_invert')}
1349
- />}
1350
- <div />
1351
- {dates.map(i =>
1352
- <FormControlLabel
1353
- key={`date_${i}`}
1354
- style={!i ? {
1355
- ...styles.inputDateDay,
1356
- opacity: 0,
1357
- cursor: 'default',
1358
- userSelect: 'none',
1359
- pointerEvents: 'none',
1360
- } : styles.inputDateDay}
1361
- control={<Checkbox
1362
- style={styles.inputDateDayCheck}
1363
- checked={JSON.parse(schedule.period.dates).includes(i)}
1364
- onChange={e => {
1365
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1366
- let _dates;
1367
- try {
1368
- _dates = JSON.parse(_schedule.period.dates);
1369
- } catch (err) {
1370
- _dates = [];
1371
- }
1372
- if (e.target.checked && !_dates.includes(i)) {
1373
- _dates.push(i);
1374
- } else if (!e.target.checked && _dates.includes(i)) {
1375
- _dates.splice(_dates.indexOf(i), 1);
1376
- }
1377
- _dates.sort((a: number, b: number) => a - b);
1378
- _schedule.period.dates = JSON.stringify(_dates);
1379
- this.onChange(_schedule);
1380
- }}
1381
- />}
1382
- label={i < 10 ? [
1383
- <span key="0" style={{ opacity: 0 }}>0</span>,
1384
- <span key="num">{i}</span>,
1385
- ] : i}
1386
- />)}
1387
- </FormGroup>;
1388
- }
1389
-
1390
- getPeriodSettingsMonthly() {
1391
- if (!this.state.schedule.period.months) {
1392
- return null;
1393
- }
1394
- const schedule = this.state.schedule;
1395
- const parsedMonths = typeof schedule.period.months === 'string' ? JSON.parse(schedule.period.months) : [];
1396
-
1397
- return [
1398
- <div key="every">
1399
- <FormControlLabel
1400
- control={<Radio
1401
- style={styles.inputRadio}
1402
- checked={typeof schedule.period.months === 'number' && schedule.period.months === 1}
1403
- onClick={() => {
1404
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1405
- _schedule.period.months = 1;
1406
- this.onChange(schedule);
1407
- }}
1408
- />}
1409
- label={I18n.t('sch_periodEveryMonth')}
1410
- />
1411
- </div>,
1412
- <div key="everyN">
1413
- <FormControlLabel
1414
- control={<Radio
1415
- style={styles.inputRadio}
1416
- checked={typeof schedule.period.months === 'number' && schedule.period.months > 1}
1417
- onClick={() => {
1418
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1419
- _schedule.period.months = 2;
1420
- this.onChange(_schedule);
1421
- }}
1422
- />}
1423
- label={I18n.t('sch_periodEvery')}
1424
- />
1425
- {typeof schedule.period.months === 'number' && schedule.period.months > 1 && [
1426
- <Input
1427
- key="input"
1428
- value={schedule.period.months}
1429
- style={styles.inputEvery}
1430
- type="number"
1431
- inputProps={{ min: 2 }}
1432
- onChange={e => {
1433
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1434
- _schedule.period.months = parseInt(e.target.value, 10);
1435
- if (_schedule.period.months < 1) _schedule.period.months = 1;
1436
- this.onChange(_schedule);
1437
- }}
1438
- />,
1439
- <span key="text">{I18n.t('sch_periodMonth')}</span>,
1440
- ]}
1441
- </div>,
1442
- <div key="specific" style={{ verticalAlign: 'top' }}>
1443
- <FormControlLabel
1444
- style={{ verticalAlign: 'top' }}
1445
- control={<Radio
1446
- style={styles.inputRadio}
1447
- checked={typeof schedule.period.months === 'string'}
1448
- onClick={() => {
1449
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1450
- _schedule.period.months = '[1,2,3,4,5,6,7,8,9,10,11,12]';
1451
- this.onChange(_schedule);
1452
- }}
1453
- />}
1454
- label={I18n.t('sch_periodSpecificMonths')}
1455
- />
1456
- {typeof schedule.period.months === 'string' &&
1457
- <FormGroup
1458
- row
1459
- style={styles.inputGroup}
1460
- >
1461
- <FormControlLabel
1462
- style={styles.inputDateDay}
1463
- control={<Checkbox
1464
- style={styles.inputDateDayCheck}
1465
- checked={parsedMonths.length === 12}
1466
- onChange={() => {
1467
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1468
- const months = [];
1469
- for (let i = 1; i <= 12; i++) {
1470
- months.push(i);
1471
- }
1472
- _schedule.period.months = JSON.stringify(months);
1473
- this.onChange(_schedule);
1474
- }}
1475
- />}
1476
- label={I18n.t('sch_all')}
1477
- />
1478
- <FormControlLabel
1479
- style={styles.inputDateDay}
1480
- control={<Checkbox
1481
- style={styles.inputDateDayCheck}
1482
- checked={!parsedMonths.length}
1483
- onChange={() => {
1484
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1485
- _schedule.period.months = '[]';
1486
- this.onChange(_schedule);
1487
- }}
1488
- />}
1489
- label={I18n.t('sch_no_one')}
1490
- />
1491
- {parsedMonths.length !== 12 && !!parsedMonths.length &&
1492
- <FormControlLabel
1493
- style={styles.inputDateDay}
1494
- control={<Checkbox
1495
- style={styles.inputDateDayCheck}
1496
- checked={false}
1497
- onChange={() => {
1498
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1499
- const result = [];
1500
- const _parsedMonths = JSON.parse(_schedule.period.months);
1501
- for (let i = 1; i <= 12; i++) {
1502
- if (!_parsedMonths.includes(i)) {
1503
- result.push(i);
1504
- }
1505
- }
1506
- result.sort((a, b) => a - b);
1507
- _schedule.period.months = JSON.stringify(result);
1508
- this.onChange(_schedule);
1509
- }}
1510
- />}
1511
- label={I18n.t('sch_invert')}
1512
- />}
1513
- <div />
1514
- {MONTHS.map((month, i) =>
1515
- <FormControlLabel
1516
- style={styles.inputGroupElement}
1517
- control={<Checkbox
1518
- style={styles.inputSmallCheck}
1519
- checked={typeof schedule.period.months === 'string' ? JSON.parse(schedule.period.months).includes(i + 1) : schedule.period.months === i}
1520
- onChange={e => {
1521
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1522
- let months;
1523
- try {
1524
- months = JSON.parse(_schedule.period.months);
1525
- } catch (err) {
1526
- months = [];
1527
- }
1528
- if (e.target.checked && !months.includes(i + 1)) {
1529
- months.push(i + 1);
1530
- } else if (!e.target.checked && months.includes(i + 1)) {
1531
- months.splice(months.indexOf(i + 1), 1);
1532
- }
1533
- months.sort((a: number, b: number) => a - b);
1534
- _schedule.period.months = JSON.stringify(months);
1535
- this.onChange(_schedule);
1536
- }}
1537
- />}
1538
- label={I18n.t(month)}
1539
- />)}
1540
- </FormGroup>}
1541
- </div>,
1542
- ];
1543
- }
1544
-
1545
- getPeriodSettingsYearly() {
1546
- if (!this.state.schedule.period.years) {
1547
- return null;
1548
- }
1549
- const schedule = this.state.schedule;
1550
- return [
1551
- <div key="year">
1552
- <FormControlLabel
1553
- control={<Radio
1554
- style={styles.inputRadio}
1555
- checked={schedule.period.years === 1}
1556
- onClick={() => {
1557
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1558
- _schedule.period.years = 1;
1559
- this.onChange(_schedule);
1560
- }}
1561
- />}
1562
- label={I18n.t('sch_periodEveryYear')}
1563
- />
1564
- </div>,
1565
- <div key="every">
1566
- <FormControlLabel
1567
- control={<Radio
1568
- style={styles.inputRadio}
1569
- checked={schedule.period.years > 1}
1570
- onClick={() => {
1571
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1572
- _schedule.period.years = 2;
1573
- this.onChange(_schedule);
1574
- }}
1575
- />}
1576
- label={I18n.t('sch_periodEvery')}
1577
- />
1578
- {schedule.period.years > 1 && [
1579
- <Input
1580
- key="input"
1581
- value={this.state.schedule.period.years}
1582
- style={styles.inputEvery}
1583
- type="number"
1584
- inputProps={{ min: 2 }}
1585
- onChange={e => {
1586
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1587
- _schedule.period.years = parseInt(e.target.value, 10);
1588
- if (_schedule.period.years < 1) _schedule.period.years = 1;
1589
- this.onChange(_schedule);
1590
- }}
1591
- />,
1592
- <span key="text">{I18n.t('sch_periodYear')}</span>,
1593
- ]}
1594
- </div>,
1595
- ];
1596
- }
1597
-
1598
- static now2string(isEnd?: boolean): string {
1599
- const d = new Date();
1600
- d.setHours(0);
1601
- d.setMinutes(0);
1602
- d.setSeconds(0);
1603
- d.setMilliseconds(0);
1604
- if (isEnd) {
1605
- d.setDate(d.getDate() + 2);
1606
- d.setMilliseconds(d.getMilliseconds() - 1);
1607
- }
1608
-
1609
- return `${padding(d.getDate())}.${padding(d.getMonth() + 1)}.${padding(d.getFullYear())}`;
1610
- }
1611
-
1612
- static string2date(str: string): Date {
1613
- let parts = str.split('.'); // 31.12.2019
1614
- if (parts.length === 1) {
1615
- parts = str.split('-'); // 2018-12-31
1616
- return new Date(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10));
1617
- }
1618
- return new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0], 10));
1619
- }
1620
-
1621
- getValidSettings() {
1622
- const schedule = this.state.schedule;
1623
- // ----- from ---
1624
- return <div style={styles.rowDiv}>
1625
- <div style={{ ...styles.modeDiv, verticalAlign: 'middle' }}>
1626
- <span style={{ fontWeight: 'bold', paddingRight: 10 }}>{I18n.t('sch_valid')}</span>
1627
- <span>{I18n.t('sch_validFrom')}</span>
1628
- </div>
1629
- <div style={styles.settingsDiv}>
1630
- <TextField
1631
- variant="standard"
1632
- style={{ ...styles.inputDate, marginRight: 10 }}
1633
- key="exactTimeFrom"
1634
- inputRef={this.refFrom}
1635
- defaultValue={string2USdate(schedule.valid.from)}
1636
- type="date"
1637
- // inputComponent={TextDate}
1638
- onChange={e => {
1639
- this.timerFrom && clearTimeout(this.timerFrom);
1640
-
1641
- if (this.refFrom.current) {
1642
- this.refFrom.current.style.background = '#ff000030';
1643
- }
1644
-
1645
- this.timerFrom = setTimeout(value => {
1646
- this.timerFrom = null;
1647
- if (this.refFrom.current) {
1648
- this.refFrom.current.style.background = '';
1649
- }
1650
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1651
- const date = Schedule.string2date(value);
1652
- if (date.toString() !== 'Invalid Date') {
1653
- _schedule.valid.from = `${padding(date.getDate())}.${padding(date.getMonth() + 1)}.${date.getFullYear()}`;
1654
- this.onChange(_schedule);
1655
- }
1656
- }, 1500, e.target.value);
1657
- }}
1658
- InputLabelProps={{ shrink: true }}
1659
- margin="normal"
1660
- />
1661
- <FormControlLabel
1662
- control={<Checkbox
1663
- style={styles.inputRadio}
1664
- checked={!!schedule.valid.to}
1665
- onClick={() => {
1666
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1667
- _schedule.valid.to = _schedule.valid.to ? '' : Schedule.now2string(true);
1668
- this.onChange(_schedule);
1669
- }}
1670
- />}
1671
- label={I18n.t('sch_validTo')}
1672
- />
1673
- {!!schedule.valid.to && <TextField
1674
- variant="standard"
1675
- inputRef={this.refTo}
1676
- style={{ ...styles.inputDate, marginRight: 10 }}
1677
- key="exactTimeFrom"
1678
- type="date"
1679
- defaultValue={string2USdate(schedule.valid.to)}
1680
- // inputComponent={TextDate}
1681
- onChange={e => {
1682
- this.timerTo && clearTimeout(this.timerTo);
1683
-
1684
- if (this.refTo.current) {
1685
- this.refTo.current.style.background = '#ff000030';
1686
- }
1687
- this.timerTo = setTimeout(value => {
1688
- this.timerTo = null;
1689
- if (this.refTo.current) {
1690
- this.refTo.current.style.background = '';
1691
- }
1692
- const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1693
- const date = Schedule.string2date(value);
1694
- if (date.toString() !== 'Invalid Date') {
1695
- _schedule.valid.to = `${padding(date.getDate())}.${padding(date.getMonth() + 1)}.${date.getFullYear()}`;
1696
- this.onChange(_schedule);
1697
- }
1698
- }, 1500, e.target.value);
1699
- }}
1700
- InputLabelProps={{ shrink: true }}
1701
- margin="normal"
1702
- />}
1703
- </div>
1704
- </div>;
1705
- }
1706
-
1707
- render() {
1708
- return <div style={{ height: 'calc(100% - 48px)', width: '100%', overflow: 'hidden' }}>
1709
- <div>{this.state.desc}</div>
1710
- <div style={styles.scrollWindow}>
1711
- <h5>{I18n.t('sch_time')}</h5>
1712
- {this.getTimePeriodElements()}
1713
- {this.getTimeExactElements()}
1714
- {Schedule.getDivider()}
1715
- <h5>{I18n.t('sch_period')}</h5>
1716
- {this.getPeriodModes()}
1717
- {!this.state.schedule.period.once && Schedule.getDivider()}
1718
- {!this.state.schedule.period.once && this.getValidSettings()}
1719
- </div>
1720
- </div>;
1721
- }
1722
- }
1723
-
1724
- export default Schedule;
1
+ import React, { Component } from 'react';
2
+
3
+ import {
4
+ Input,
5
+ Radio,
6
+ FormControlLabel,
7
+ FormGroup,
8
+ Checkbox,
9
+ MenuItem,
10
+ Select,
11
+ TextField, Box,
12
+ } from '@mui/material';
13
+
14
+ import I18n from '../i18n';
15
+ import { IobTheme } from '../types';
16
+ import Utils from './Utils';
17
+
18
+ const styles: Record<string, any> = {
19
+ hr: {
20
+ border: 0,
21
+ borderTop: '1px solid gray',
22
+ },
23
+ scrollWindow: {
24
+ width: '100%',
25
+ overflow: 'auto',
26
+ height: 'calc(100% - 22px)',
27
+ },
28
+ rowDiv: {
29
+ width: '100%',
30
+ },
31
+ modeDiv: {
32
+ width: 200,
33
+ display: 'inline-block',
34
+ verticalAlign: 'top',
35
+ },
36
+ settingsDiv: {
37
+ display: 'inline-block',
38
+ verticalAlign: 'top',
39
+ },
40
+ inputTime: {
41
+ width: 90,
42
+ marginTop: 0,
43
+ marginLeft: 5,
44
+ },
45
+ inputDate: {
46
+ width: 140,
47
+ marginTop: 0,
48
+ marginLeft: 5,
49
+ },
50
+ inputEvery: {
51
+ width: 40,
52
+ marginLeft: 5,
53
+ marginRight: 5,
54
+ },
55
+ inputRadio: {
56
+ padding: '4px 12px',
57
+ verticalAlign: 'top',
58
+ },
59
+ inputGroup: {
60
+ maxWidth: 400,
61
+ display: 'inline-block',
62
+ },
63
+ inputGroupElement: {
64
+ width: 120,
65
+ },
66
+ inputDateDay: {
67
+ width: 60,
68
+ },
69
+ inputDateDayCheck: {
70
+ padding: 4,
71
+ },
72
+ inputSmallCheck: {
73
+ padding: 0,
74
+ },
75
+ rowOnce: {
76
+
77
+ },
78
+ rowDays: (theme: IobTheme) => ({
79
+ background: theme.palette.mode !== 'dark' ? '#ddeaff' : '#4b5057',
80
+ }),
81
+ rowDows: (theme: IobTheme) => ({
82
+ background: theme.palette.mode !== 'dark' ? '#DDFFDD' : '#52646c',
83
+ }),
84
+ rowDates: (theme: IobTheme) => ({
85
+ background: theme.palette.mode !== 'dark' ? '#DDDDFF' : '#747a86',
86
+ }),
87
+ rowWeeks: (theme: IobTheme) => ({
88
+ background: theme.palette.mode !== 'dark' ? '#DDDDFF' : '#717680',
89
+ }),
90
+ rowMonths: (theme: IobTheme) => ({
91
+ background: theme.palette.mode !== 'dark' ? '#DDFFFF' : '#1f5557',
92
+ }),
93
+ rowMonthsDates: (theme: IobTheme) => ({
94
+ background: theme.palette.mode !== 'dark' ? '#EEFFFF' : '#3c5737',
95
+ maxWidth: 600,
96
+ }),
97
+ rowYears: (theme: IobTheme) => ({
98
+ background: theme.palette.mode !== 'dark' ? '#fbffdd' : '#574b33',
99
+ }),
100
+ rowDaysDows: (theme: IobTheme) => ({
101
+ background: theme.palette.mode !== 'dark' ? '#EEEAFF' : '#573544',
102
+ pl: '10px',
103
+ pb: '10px',
104
+ }),
105
+ rowDowsDows: (theme: IobTheme) => ({
106
+ background: theme.palette.mode !== 'dark' ? '#EEFFEE' : '#3d4c54',
107
+ pl: '10px',
108
+ pb: '10px',
109
+ }),
110
+ };
111
+
112
+ const WEEKDAYS = [
113
+ 'Sunday',
114
+ 'Monday',
115
+ 'Tuesday',
116
+ 'Wednesday',
117
+ 'Thursday',
118
+ 'Friday',
119
+ 'Saturday',
120
+ 'Sunday',
121
+ ];
122
+ const MONTHS = [
123
+ 'January',
124
+ 'February',
125
+ 'March',
126
+ 'April',
127
+ 'May',
128
+ 'June',
129
+ 'July',
130
+ 'August',
131
+ 'September',
132
+ 'October',
133
+ 'November',
134
+ 'December',
135
+ ];
136
+ const PERIODS = {
137
+ minutes: 'minutes',
138
+ hours: 'hours',
139
+ };
140
+ const ASTRO = [
141
+ 'sunrise',
142
+ 'sunriseEnd',
143
+ 'goldenHourEnd',
144
+ 'solarNoon',
145
+ 'goldenHour',
146
+ 'sunsetStart',
147
+ 'sunset',
148
+ 'dusk',
149
+ 'nauticalDusk',
150
+ 'night',
151
+ 'nightEnd',
152
+ 'nauticalDawn',
153
+ 'dawn',
154
+ 'nadir',
155
+ ];
156
+
157
+ function padding(num: number): string {
158
+ if (num < 10) {
159
+ return `0${num}`;
160
+ }
161
+ return `${num}`;
162
+ }
163
+
164
+ interface ScheduleConfig {
165
+ time: {
166
+ exactTime: boolean;
167
+ start: string;
168
+ end: string;
169
+ mode: string;
170
+ interval: number;
171
+ };
172
+ period: {
173
+ once: string;
174
+ days: number;
175
+ dows: string;
176
+ dates: string;
177
+ weeks: number;
178
+ months: string | number;
179
+ years: number;
180
+ yearMonth: number;
181
+ yearDate: number;
182
+ };
183
+ valid: {
184
+ from: string;
185
+ to?: string;
186
+ };
187
+ }
188
+
189
+ // interface TextTimeProps {
190
+ // inputRef: React.RefObject<HTMLInputElement>;
191
+ // placeholder?: string;
192
+ // }
193
+
194
+ // function TextTime(props: TextTimeProps) {
195
+ // const { inputRef, ...other } = props;
196
+ //
197
+ // return <MaskedInput
198
+ // {...other}
199
+ // ref={inputRef}
200
+ // mask={[/[0-2]/, /[0-9]/, ':', /[0-5]/, /[0-9]/]}
201
+ // placeholderChar={props.placeholder || '00:00'}
202
+ // showMask
203
+ // />;
204
+ // }
205
+
206
+ // function TextDate(props: TextTimeProps) {
207
+ // const { inputRef, ...other } = props;
208
+ //
209
+ // return <MaskedInput
210
+ // {...other}
211
+ // ref={inputRef}
212
+ // mask={[/[0-3]/, /[0-9]/, '.', /[0-1]/, /[0-9]/, '.', '2', '0', /[0-9]/, /[0-9]/]}
213
+ // placeholderChar={props.placeholder || '01.01.2020'}
214
+ // showMask
215
+ // />;
216
+ // }
217
+
218
+ const DEFAULT: ScheduleConfig = {
219
+ time: {
220
+ exactTime: false,
221
+
222
+ start: '00:00',
223
+ end: '23:59',
224
+
225
+ mode: 'hours',
226
+ interval: 1,
227
+ },
228
+ period: {
229
+ once: '',
230
+ days: 1,
231
+ dows: '',
232
+ dates: '',
233
+ weeks: 0,
234
+ months: '',
235
+
236
+ years: 0,
237
+ yearMonth: 0,
238
+ yearDate: 0,
239
+ },
240
+ valid: {
241
+ from: '',
242
+ to: '',
243
+ },
244
+ };
245
+
246
+ function string2USdate(date: string): string {
247
+ const parts = date.split('.');
248
+ if (parts.length === 3) {
249
+ return `${parts[2]}-${parts[1]}-${parts[0]}`;
250
+ }
251
+ return '';
252
+ }
253
+
254
+ interface ScheduleProps {
255
+ schedule: string | ScheduleConfig;
256
+ onChange: (schedule: string, desc?: string) => void;
257
+ theme: IobTheme;
258
+ }
259
+
260
+ interface ScheduleState {
261
+ schedule: ScheduleConfig;
262
+ desc: string;
263
+ }
264
+
265
+ class Schedule extends Component<ScheduleProps, ScheduleState> {
266
+ private readonly refFrom: React.RefObject<HTMLInputElement>;
267
+
268
+ private readonly refTo: React.RefObject<HTMLInputElement>;
269
+
270
+ private readonly refOnce: React.RefObject<HTMLInputElement>;
271
+
272
+ private timerOnce: ReturnType<typeof setTimeout> | null = null;
273
+
274
+ private timerFrom: ReturnType<typeof setTimeout> | null = null;
275
+
276
+ private timerTo: ReturnType<typeof setTimeout> | null = null;
277
+
278
+ constructor(props: ScheduleProps) {
279
+ super(props);
280
+ let schedule: ScheduleConfig | undefined;
281
+ if (this.props.schedule && typeof this.props.schedule === 'string' && this.props.schedule[0] === '{') {
282
+ try {
283
+ schedule = JSON.parse(this.props.schedule);
284
+ } catch (e) {
285
+ // ignore
286
+ }
287
+ } else if (typeof this.props.schedule === 'object') {
288
+ schedule = this.props.schedule;
289
+ }
290
+
291
+ if ((!schedule || !Object.keys(schedule).length)) {
292
+ setTimeout(() => this.onChange(this.state.schedule, true), 200);
293
+ schedule = DEFAULT;
294
+ }
295
+ schedule = { ...DEFAULT, ...schedule };
296
+ schedule.valid.from = schedule.valid.from || Schedule.now2string();
297
+
298
+ this.refFrom = React.createRef();
299
+ this.refTo = React.createRef();
300
+ this.refOnce = React.createRef();
301
+
302
+ this.state = {
303
+ schedule,
304
+ desc: Schedule.state2text(schedule),
305
+ };
306
+
307
+ if (JSON.stringify(schedule) !== this.props.schedule) {
308
+ setTimeout(() =>
309
+ this.props.onChange && this.props.onChange(JSON.stringify(schedule)), 100);
310
+ }
311
+ }
312
+
313
+ onChange(schedule: ScheduleConfig, force?: boolean) {
314
+ const isDiff = JSON.stringify(schedule) !== JSON.stringify(this.state.schedule);
315
+ if (force || isDiff) {
316
+ isDiff && this.setState({ schedule, desc: Schedule.state2text(schedule) });
317
+ const copy = JSON.parse(JSON.stringify(schedule));
318
+ if (copy.period.once) {
319
+ const once = copy.period.once;
320
+ delete copy.period;
321
+ copy.period = { once };
322
+ delete copy.valid;
323
+ } else if (copy.period.days) {
324
+ const days = copy.period.days;
325
+ const daysOfWeek = copy.period.dows;
326
+ delete copy.period;
327
+ copy.period = { days };
328
+ if (daysOfWeek && daysOfWeek !== '[]') {
329
+ copy.period.dows = daysOfWeek;
330
+ }
331
+ } else if (copy.period.weeks) {
332
+ const weeks = copy.period.weeks;
333
+ const daysOfWeek = copy.period.dows;
334
+ delete copy.period;
335
+ copy.period = { weeks };
336
+ if (daysOfWeek && daysOfWeek !== '[]') {
337
+ copy.period.dows = daysOfWeek;
338
+ }
339
+ } else if (copy.period.months) {
340
+ const months = copy.period.months;
341
+ const dates = copy.period.dates;
342
+ delete copy.period;
343
+ copy.period = { months };
344
+ if (dates && dates !== '[]') {
345
+ copy.period.dates = dates;
346
+ }
347
+ } else if (copy.period.years) {
348
+ const years = copy.period.years;
349
+ const yearMonth = copy.period.yearMonth;
350
+ const yearDate = copy.period.yearDate;
351
+ delete copy.period;
352
+ copy.period = { years, yearDate };
353
+ if (yearMonth) {
354
+ copy.period.yearMonth = yearMonth;
355
+ }
356
+ }
357
+
358
+ if (copy.time.exactTime) {
359
+ delete copy.time.end;
360
+ delete copy.time.mode;
361
+ delete copy.time.interval;
362
+ } else {
363
+ delete copy.time.exactTime;
364
+ }
365
+ if (copy.valid) {
366
+ if (!copy.valid.to) {
367
+ delete copy.valid.to;
368
+ }
369
+ if (copy.period.days === 1 || copy.period.weeks === 1 || copy.period.months === 1 || copy.period.years === 1) {
370
+ const from = Schedule.string2date(copy.valid.from);
371
+ const today = new Date();
372
+ today.setHours(0);
373
+ today.setMinutes(0);
374
+ today.setSeconds(0);
375
+ today.setMilliseconds(0);
376
+ if (from <= today) {
377
+ delete copy.valid.from;
378
+ }
379
+ }
380
+ if (!copy.valid.from && !copy.valid.to) {
381
+ delete copy.valid;
382
+ }
383
+ }
384
+
385
+ this.props.onChange && this.props.onChange(JSON.stringify(copy), Schedule.state2text(schedule));
386
+ }
387
+ }
388
+
389
+ static state2text(schedule: string | ScheduleConfig): string {
390
+ if (typeof schedule === 'string') {
391
+ try {
392
+ schedule = JSON.parse(schedule) as ScheduleConfig;
393
+ } catch (e) {
394
+ return '';
395
+ }
396
+ }
397
+
398
+ const desc = [];
399
+ const validFrom = Schedule.string2date(schedule.valid.from);
400
+ if (schedule.period.once) {
401
+ // once
402
+ const once = Schedule.string2date(schedule.period.once);
403
+ const now = new Date();
404
+ now.setMilliseconds(0);
405
+ now.setSeconds(0);
406
+ now.setMinutes(0);
407
+ now.setHours(0);
408
+
409
+ //
410
+ if (once < now) {
411
+ // will be not executed anymore, because start is in the past
412
+ return I18n.t('sch_desc_onceInPast');
413
+ }
414
+ // only once
415
+ desc.push(I18n.t('sch_desc_once_on', schedule.period.once));
416
+ } else if (schedule.period.days) {
417
+ if (schedule.period.days === 1) {
418
+ if (schedule.period.dows) {
419
+ const daysOfWeek = JSON.parse(schedule.period.dows);
420
+ if (daysOfWeek.length === 2 && daysOfWeek[0] === 0 && daysOfWeek[1] === 6) {
421
+ // on weekends
422
+ desc.push(I18n.t('sch_desc_onWeekends'));
423
+ } else if (daysOfWeek.length === 5 && daysOfWeek[0] === 1 && daysOfWeek[1] === 2 && daysOfWeek[2] === 3 && daysOfWeek[3] === 4 && daysOfWeek[4] === 5) {
424
+ // on workdays
425
+ desc.push(I18n.t('sch_desc_onWorkdays'));
426
+ } else {
427
+ const tDows = daysOfWeek.map((day: number) => I18n.t(WEEKDAYS[day]));
428
+ if (tDows.length === 1) {
429
+ // on Monday
430
+ desc.push(I18n.t('sch_desc_onWeekday', tDows[0]));
431
+ } else if (tDows.length === 7) {
432
+ // on every day
433
+ desc.push(I18n.t('sch_desc_everyDay'));
434
+ } else {
435
+ const last = tDows.pop();
436
+ // on Monday and Sunday
437
+ desc.push(I18n.t('sch_desc_onWeekdays', tDows.join(', '), last));
438
+ }
439
+ }
440
+ } else {
441
+ desc.push(I18n.t('sch_desc_everyDay'));
442
+ }
443
+ } else {
444
+ desc.push(I18n.t('sch_desc_everyNDay', schedule.period.days.toString()));
445
+ }
446
+ } else if (schedule.period.weeks) {
447
+ if (schedule.period.weeks === 1) {
448
+ desc.push(I18n.t('sch_desc_everyWeek'));
449
+ } else {
450
+ desc.push(I18n.t('sch_desc_everyNWeeks', schedule.period.weeks.toString()));
451
+ }
452
+
453
+ if (schedule.period.dows) {
454
+ const daysOfWeek = JSON.parse(schedule.period.dows);
455
+ if (daysOfWeek.length === 2 && daysOfWeek[0] === 0 && daysOfWeek[1] === 6) {
456
+ // on weekends
457
+ desc.push(I18n.t('sch_desc_onWeekends'));
458
+ } else if (daysOfWeek.length === 5 && daysOfWeek[0] === 1 && daysOfWeek[1] === 2 && daysOfWeek[2] === 3 && daysOfWeek[3] === 4 && daysOfWeek[4] === 5) {
459
+ // on workdays
460
+ desc.push(I18n.t('sch_desc_onWorkdays'));
461
+ } else {
462
+ const tDows = daysOfWeek.map((day: number) => I18n.t(WEEKDAYS[day]));
463
+ if (tDows.length === 1) {
464
+ // on Monday
465
+ desc.push(I18n.t('sch_desc_onWeekday', tDows[0]));
466
+ } else if (tDows.length === 7) {
467
+ // on every day
468
+ desc.push(I18n.t('sch_desc_everyDay'));
469
+ } else {
470
+ const last = tDows.pop();
471
+ // on Monday and Sunday
472
+ desc.push(I18n.t('sch_desc_onWeekdays', tDows.join(', '), last));
473
+ }
474
+ }
475
+ } else {
476
+ return I18n.t('sch_desc_never');
477
+ }
478
+ } else if (schedule.period.months) {
479
+ if (schedule.period.dates) {
480
+ const dates = JSON.parse(schedule.period.dates);
481
+ if (dates.length === 1) {
482
+ // in 1 of month
483
+ desc.push(I18n.t('sch_desc_onDate', dates[0]));
484
+ } else if (dates.length === 31) {
485
+ desc.push(I18n.t('sch_desc_onEveryDate'));
486
+ } else if (!dates.length) {
487
+ return I18n.t('sch_desc_never');
488
+ } else {
489
+ const last = dates.pop();
490
+ // in 1 and 4 of month
491
+ desc.push(I18n.t('sch_desc_onDates', dates.join(', '), last));
492
+ }
493
+ } else {
494
+ desc.push(I18n.t('sch_desc_onEveryDate'));
495
+ }
496
+
497
+ if (schedule.period.months === 1) {
498
+ desc.push(I18n.t('sch_desc_everyMonth'));
499
+ } else if (typeof schedule.period.months === 'number') {
500
+ desc.push(I18n.t('sch_desc_everyNMonths', schedule.period.months.toString()));
501
+ } else {
502
+ const months = JSON.parse(schedule.period.months);
503
+ const tMonths = months.map((month: number) => I18n.t(MONTHS[month - 1]));
504
+ if (!tMonths.length) {
505
+ // in January
506
+ return I18n.t('sch_desc_never');
507
+ }
508
+ if (tMonths.length === 1) {
509
+ // in January
510
+ desc.push(I18n.t('sch_desc_onMonth', tMonths[0]));
511
+ } else if (tMonths.length === 12) {
512
+ // every month
513
+ desc.push(I18n.t('sch_desc_everyMonth'));
514
+ } else {
515
+ const last = tMonths.pop();
516
+ // in January and May
517
+ desc.push(I18n.t('sch_desc_onMonths', tMonths.join(', '), last));
518
+ }
519
+ }
520
+ } else if (schedule.period.years) {
521
+ if (schedule.period.years === 1) {
522
+ desc.push(I18n.t('sch_desc_everyYear'));
523
+ } else {
524
+ desc.push(I18n.t('sch_desc_everyNYears', schedule.period.years.toString()));
525
+ }
526
+ desc.push(I18n.t(
527
+ 'sch_desc_onDate',
528
+ schedule.period.yearDate.toString(),
529
+ schedule.period.yearMonth ? I18n.t(MONTHS[schedule.period.yearMonth - 1]) : I18n.t('sch_desc_everyMonth'),
530
+ ));
531
+ }
532
+
533
+ // time
534
+ if (schedule.time.exactTime) {
535
+ if (ASTRO.includes(schedule.time.start)) {
536
+ // at sunset
537
+ desc.push(I18n.t('sch_desc_atTime', I18n.t(`sch_astro_${schedule.time.start}`)));
538
+ } else {
539
+ // at HH:MM
540
+ desc.push(I18n.t('sch_desc_atTime', schedule.time.start));
541
+ }
542
+ } else {
543
+ if (schedule.time.mode === PERIODS.minutes) {
544
+ if (schedule.time.interval === 1) {
545
+ // every minute
546
+ desc.push(I18n.t('sch_desc_everyMinute'));
547
+ } else {
548
+ // every N minutes
549
+ desc.push(I18n.t('sch_desc_everyNMinutes', schedule.time.interval.toString()));
550
+ }
551
+ } else if (schedule.time.interval === 1) {
552
+ // every minute
553
+ desc.push(I18n.t('sch_desc_everyHour'));
554
+ } else {
555
+ // every N minutes
556
+ desc.push(I18n.t('sch_desc_everyNHours', schedule.time.interval.toString()));
557
+ }
558
+
559
+ const start = ASTRO.indexOf(schedule.time.start) !== -1 ? I18n.t(`sch_astro_${schedule.time.start}`) : schedule.time.start;
560
+ const end = ASTRO.indexOf(schedule.time.end) !== -1 ? I18n.t(`sch_astro_${schedule.time.end}`) : schedule.time.end;
561
+ if (start !== '00:00' || (end !== '24:00' && end !== '23:59')) {
562
+ // from HH:mm to HH:mm
563
+ desc.push(I18n.t('sch_desc_intervalFromTo', start, end));
564
+ }
565
+ }
566
+
567
+ if (!schedule.period.once) {
568
+ // valid
569
+ if (validFrom.getTime() > Date.now() && schedule.valid.to) {
570
+ // from XXX to XXXX
571
+ desc.push(I18n.t('sch_desc_validFromTo', schedule.valid.from, schedule.valid.to));
572
+ } else if (validFrom.getTime() > Date.now()) {
573
+ // from XXXX
574
+ desc.push(I18n.t('sch_desc_validFrom', schedule.valid.from));
575
+ } else if (schedule.valid.to) {
576
+ // till XXXX
577
+ desc.push(I18n.t('sch_desc_validTo', schedule.valid.to));
578
+ }
579
+ }
580
+ return desc.join(' ');
581
+ }
582
+
583
+ getTimePeriodElements() {
584
+ const schedule = this.state.schedule;
585
+ let wholeDay = false;
586
+ let day = false;
587
+ let night = false;
588
+ let fromTo = true;
589
+ if (schedule.time.start === '00:00' && schedule.time.end === '24:00') {
590
+ wholeDay = true;
591
+ fromTo = false;
592
+ } else if (schedule.time.start === 'sunrise') {
593
+ day = true;
594
+ fromTo = false;
595
+ } else if (schedule.time.start === 'sunset') {
596
+ night = true;
597
+ fromTo = false;
598
+ }
599
+
600
+ return <div key="timePeriod" style={styles.rowDiv}>
601
+ <div style={styles.modeDiv}>
602
+ <FormControlLabel
603
+ control={<Radio
604
+ style={styles.inputRadio}
605
+ checked={!schedule.time.exactTime}
606
+ onClick={() => {
607
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
608
+ _schedule.time.exactTime = false;
609
+ this.onChange(_schedule);
610
+ }}
611
+ />}
612
+ label={I18n.t('sch_intervalTime')}
613
+ />
614
+ </div>
615
+ <div style={styles.settingsDiv}>
616
+ <div style={styles.settingsDiv}>
617
+ {!schedule.time.exactTime && <div>
618
+ <div>
619
+ <FormControlLabel
620
+ control={<Radio
621
+ style={styles.inputRadio}
622
+ checked={!!fromTo}
623
+ onClick={() => {
624
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
625
+ _schedule.time.start = '00:00';
626
+ _schedule.time.end = '23:59';
627
+ this.onChange(_schedule);
628
+ }}
629
+ />}
630
+ label={!fromTo ? I18n.t('sch_fromTo') : ''}
631
+ />
632
+ {fromTo && [
633
+ <TextField
634
+ variant="standard"
635
+ style={{ ...styles.inputTime, marginRight: 10 }}
636
+ key="exactTimeFrom"
637
+ type="time"
638
+ value={this.state.schedule.time.start}
639
+ // InputProps={{inputComponent: TextTime}}
640
+ onChange={e => {
641
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
642
+ _schedule.time.start = e.target.value;
643
+ this.onChange(_schedule);
644
+ }}
645
+ InputLabelProps={{ shrink: true }}
646
+ label={I18n.t('sch_from')}
647
+ margin="normal"
648
+ />,
649
+ <TextField
650
+ variant="standard"
651
+ style={styles.inputTime}
652
+ key="exactTimeTo"
653
+ type="time"
654
+ value={this.state.schedule.time.end}
655
+ // InputProps={{inputComponent: TextTime}}
656
+ onChange={e => {
657
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
658
+ _schedule.time.end = e.target.value;
659
+ this.onChange(_schedule);
660
+ }}
661
+ InputLabelProps={{ shrink: true }}
662
+ label={I18n.t('sch_to')}
663
+ margin="normal"
664
+ />,
665
+ ]}
666
+ </div>
667
+ </div>}
668
+
669
+ {!schedule.time.exactTime && <div>
670
+ <FormControlLabel
671
+ control={<Radio
672
+ style={styles.inputRadio}
673
+ checked={!!wholeDay}
674
+ onClick={() => {
675
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
676
+ _schedule.time.start = '00:00';
677
+ _schedule.time.end = '24:00';
678
+ this.onChange(_schedule);
679
+ }}
680
+ />}
681
+ label={I18n.t('sch_wholeDay')}
682
+ />
683
+ </div>}
684
+
685
+ {!schedule.time.exactTime && <div>
686
+ <FormControlLabel
687
+ control={<Radio
688
+ style={styles.inputRadio}
689
+ checked={!!day}
690
+ onClick={() => {
691
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
692
+ _schedule.time.start = 'sunrise';
693
+ _schedule.time.end = 'sunset';
694
+ this.onChange(_schedule);
695
+ }}
696
+ />}
697
+ label={I18n.t('sch_astroDay')}
698
+ />
699
+ </div>}
700
+
701
+ {!schedule.time.exactTime && <div>
702
+ <FormControlLabel
703
+ control={<Radio
704
+ style={styles.inputRadio}
705
+ checked={!!night}
706
+ onClick={() => {
707
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
708
+ _schedule.time.start = 'sunset';
709
+ _schedule.time.end = 'sunrise';
710
+ this.onChange(_schedule);
711
+ }}
712
+ />}
713
+ label={I18n.t('sch_astroNight')}
714
+ />
715
+ </div>}
716
+ </div>
717
+ {!schedule.time.exactTime && this.getPeriodSettingsMinutes()}
718
+ </div>
719
+ </div>;
720
+ }
721
+
722
+ getTimeExactElements() {
723
+ const isAstro = ASTRO.includes(this.state.schedule.time.start);
724
+
725
+ return <div key="timeExact" style={styles.rowDiv}>
726
+ <div style={styles.modeDiv}>
727
+ <FormControlLabel
728
+ control={<Radio
729
+ style={styles.inputRadio}
730
+ checked={!!this.state.schedule.time.exactTime}
731
+ onClick={() => {
732
+ const schedule = JSON.parse(JSON.stringify(this.state.schedule));
733
+ schedule.time.exactTime = true;
734
+ this.onChange(schedule);
735
+ }}
736
+ />}
737
+ label={I18n.t('sch_exactTime')}
738
+ />
739
+ </div>
740
+ {this.state.schedule.time.exactTime && <Select
741
+ variant="standard"
742
+ value={isAstro ? this.state.schedule.time.start : '00:00'}
743
+ onChange={e => {
744
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
745
+ _schedule.time.start = e.target.value;
746
+ this.onChange(_schedule);
747
+ }}
748
+ >
749
+ <MenuItem key="specific" value="00:00">{I18n.t('sch_specificTime')}</MenuItem>
750
+ {ASTRO.map(event => <MenuItem key={event} value={event}>{I18n.t(`sch_astro_${event}`)}</MenuItem>)}
751
+ </Select>}
752
+ {this.state.schedule.time.exactTime && !isAstro &&
753
+ <div style={styles.settingsDiv}>
754
+ <TextField
755
+ variant="standard"
756
+ style={styles.inputTime}
757
+ key="exactTimeValue"
758
+ value={this.state.schedule.time.start}
759
+ type="time"
760
+ // inputComponent={TextTime}
761
+ onChange={e => {
762
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
763
+ _schedule.time.start = e.target.value;
764
+ this.onChange(_schedule);
765
+ }}
766
+ InputLabelProps={{ shrink: true }}
767
+ margin="normal"
768
+ />
769
+ </div>}
770
+ </div>;
771
+ }
772
+
773
+ static getDivider() {
774
+ return <hr style={styles.hr} />;
775
+ }
776
+
777
+ getPeriodModes() {
778
+ const schedule = this.state.schedule;
779
+ const isOnce = !schedule.period.dows && !schedule.period.months && !schedule.period.dates && !schedule.period.years && !schedule.period.days && !schedule.period.weeks;
780
+ if (isOnce && !schedule.period.once) {
781
+ schedule.period.once = Schedule.now2string(true);
782
+ }
783
+
784
+ return [
785
+ // ----- once ---
786
+ <div key="once" style={{ ...styles.rowDiv, ...styles.rowOnce }}>
787
+ <div style={styles.modeDiv}>
788
+ <FormControlLabel
789
+ control={<Radio
790
+ style={styles.inputRadio}
791
+ checked={!!isOnce}
792
+ onClick={() => {
793
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
794
+ _schedule.period.once = _schedule.period.once || Schedule.now2string(true);
795
+ _schedule.period.dows = '';
796
+ _schedule.period.months = '';
797
+ _schedule.period.dates = '';
798
+ _schedule.period.years = 0;
799
+ _schedule.period.yearDate = 0;
800
+ _schedule.period.yearMonth = 0;
801
+ _schedule.period.weeks = 0;
802
+ _schedule.period.days = 0;
803
+ this.onChange(_schedule);
804
+ }}
805
+ />}
806
+ label={I18n.t('sch_periodOnce')}
807
+ />
808
+ </div>
809
+ {isOnce && <div style={styles.settingsDiv}>
810
+ <TextField
811
+ variant="standard"
812
+ style={styles.inputDate}
813
+ type="date"
814
+ ref={this.refOnce}
815
+ key="exactDateAt"
816
+ defaultValue={string2USdate(schedule.period.once)}
817
+ // InputProps={{inputComponent: TextTime}}
818
+ onChange={e => {
819
+ this.timerOnce && clearTimeout(this.timerOnce);
820
+ this.timerOnce = null;
821
+
822
+ if (this.refOnce.current) {
823
+ this.refOnce.current.style.background = '#ff000030';
824
+ }
825
+ this.timerOnce = setTimeout(value => {
826
+ this.timerOnce = null;
827
+ if (this.refOnce.current) {
828
+ this.refOnce.current.style.background = '';
829
+ }
830
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
831
+ const date = Schedule.string2date(value);
832
+ if (date.toString() !== 'Invalid Date') {
833
+ _schedule.period.once = `${padding(date.getDate())}.${padding(date.getMonth() + 1)}.${date.getFullYear()}`;
834
+ this.onChange(_schedule);
835
+ }
836
+ }, 1500, e.target.value);
837
+ }}
838
+ InputLabelProps={{ shrink: true }}
839
+ label={I18n.t('sch_at')}
840
+ margin="normal"
841
+ />
842
+ </div>}
843
+ </div>,
844
+
845
+ // ----- days ---
846
+ <Box component="div" key="days" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowDays)}>
847
+ <div style={styles.modeDiv}>
848
+ <FormControlLabel
849
+ control={<Radio
850
+ style={styles.inputRadio}
851
+ checked={!!schedule.period.days}
852
+ onClick={() => {
853
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
854
+ _schedule.period.days = 1;
855
+ _schedule.period.dows = '';
856
+ _schedule.period.months = '';
857
+ _schedule.period.dates = '';
858
+ _schedule.period.years = 0;
859
+ _schedule.period.yearDate = 0;
860
+ _schedule.period.yearMonth = 0;
861
+ _schedule.period.weeks = 0;
862
+ _schedule.period.once = '';
863
+ this.onChange(_schedule);
864
+ }}
865
+ />}
866
+ label={I18n.t('sch_periodDaily')}
867
+ />
868
+ </div>
869
+ <div style={styles.settingsDiv}>
870
+ {this.getPeriodSettingsDaily()}
871
+ {schedule.period.days ? this.getPeriodSettingsWeekdays() : null}
872
+ </div>
873
+ </Box>,
874
+
875
+ // ----- days of weeks ---
876
+ /*
877
+ !schedule.period.days && (
878
+ <div key="dows" style={styles.rowDiv + ' ' + styles.rowDows}>
879
+ <div style={styles.modeDiv}>
880
+ <FormControlLabel control={<Radio style={styles.inputRadio} checked={!!schedule.period.dows} onClick={() => {
881
+ const schedule = JSON.parse(JSON.stringify(this.state.schedule));
882
+ schedule.period.dows = schedule.period.dows ? '' : '[0,1,2,3,4,5,6]';
883
+ this.onChange(schedule);
884
+ }}/>}
885
+ label={I18n.t('sch_periodWeekdays')} />
886
+ </div>
887
+ <div style={styles.settingsDiv}>
888
+ {this.getPeriodSettingsWeekdays()}
889
+ </div>
890
+ </div>,
891
+ */
892
+ // ----- weeks ---
893
+ <Box component="div" key="weeks" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowDows)}>
894
+ <div style={styles.modeDiv}>
895
+ <FormControlLabel
896
+ control={<Radio
897
+ style={styles.inputRadio}
898
+ checked={!!schedule.period.weeks}
899
+ onClick={() => {
900
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
901
+ _schedule.period.weeks = schedule.period.weeks ? 0 : 1;
902
+ _schedule.period.dows = schedule.period.dows || '[0]';
903
+ _schedule.period.months = '';
904
+ _schedule.period.dates = '';
905
+ _schedule.period.years = 0;
906
+ _schedule.period.yearDate = 0;
907
+ _schedule.period.yearMonth = 0;
908
+ _schedule.period.days = 0;
909
+ _schedule.period.once = '';
910
+ this.onChange(_schedule);
911
+ }}
912
+ />}
913
+ label={I18n.t('sch_periodWeekly')}
914
+ />
915
+ </div>
916
+ <Box component="div" style={styles.settingsDiv}>
917
+ <div style={styles.settingsDiv}>{this.getPeriodSettingsWeekly()}</div>
918
+ <Box component="div" sx={Utils.getStyle(this.props.theme, styles.settingsDiv, styles.rowDowsDows)}>
919
+ {this.state.schedule.period.weeks ? this.getPeriodSettingsWeekdays() : null}
920
+ </Box>
921
+ </Box>
922
+ </Box>,
923
+
924
+ // ----- months ---
925
+ <Box component="div" key="months" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowMonths)}>
926
+ <div style={styles.modeDiv}>
927
+ <FormControlLabel
928
+ control={<Radio
929
+ style={styles.inputRadio}
930
+ checked={!!schedule.period.months}
931
+ onClick={() => {
932
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
933
+ _schedule.period.months = 1;
934
+ _schedule.period.dows = '';
935
+ _schedule.period.dates = '';
936
+ _schedule.period.years = 0;
937
+ _schedule.period.yearDate = 0;
938
+ _schedule.period.yearMonth = 0;
939
+ _schedule.period.weeks = 0;
940
+ _schedule.period.days = 0;
941
+ _schedule.period.once = '';
942
+ this.onChange(_schedule);
943
+ }}
944
+ />}
945
+ label={I18n.t('sch_periodMonthly')}
946
+ />
947
+ </div>
948
+ <div style={styles.settingsDiv}>
949
+ {this.getPeriodSettingsMonthly()}
950
+ {schedule.period.months ? <Box>
951
+ <Box component="div" sx={Utils.getStyle(this.props.theme, styles.settingsDiv, styles.rowMonthsDates)}>
952
+ <FormControlLabel
953
+ control={<Checkbox
954
+ style={styles.inputRadio}
955
+ checked={!!schedule.period.dates}
956
+ onClick={() => {
957
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
958
+ _schedule.period.months = _schedule.period.months || 1;
959
+ const dates = [];
960
+ for (let i = 1; i <= 31; i++) {
961
+ dates.push(i);
962
+ }
963
+ _schedule.period.dates = _schedule.period.dates || JSON.stringify(dates);
964
+ _schedule.period.dows = '';
965
+ _schedule.period.years = 0;
966
+ _schedule.period.yearDate = 0;
967
+ _schedule.period.yearMonth = 0;
968
+ _schedule.period.weeks = 0;
969
+ _schedule.period.days = 0;
970
+ _schedule.period.once = '';
971
+
972
+ this.onChange(_schedule);
973
+ }}
974
+ />}
975
+ label={I18n.t('sch_periodDates')}
976
+ />
977
+ </Box>
978
+ <Box component="div" sx={Utils.getStyle(this.props.theme, styles.settingsDiv, styles.rowMonthsDates)}>
979
+ {this.getPeriodSettingsDates()}
980
+ </Box>
981
+ </Box> : null}
982
+ </div>
983
+ </Box>,
984
+
985
+ // ----- years ---
986
+ <Box component="div" key="years" sx={Utils.getStyle(this.props.theme, styles.rowDiv, styles.rowYears)}>
987
+ <div style={styles.modeDiv}>
988
+ <FormControlLabel
989
+ control={<Radio
990
+ style={styles.inputRadio}
991
+ checked={!!schedule.period.years}
992
+ onClick={() => {
993
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
994
+ _schedule.period.years = 1;
995
+ _schedule.period.yearDate = 1;
996
+ _schedule.period.yearMonth = 1;
997
+ _schedule.period.dows = '';
998
+ _schedule.period.months = 0;
999
+ _schedule.period.dates = '';
1000
+ _schedule.period.weeks = 0;
1001
+ _schedule.period.days = 0;
1002
+ _schedule.period.once = '';
1003
+ this.onChange(_schedule);
1004
+ }}
1005
+ />}
1006
+ label={I18n.t('sch_periodYearly')}
1007
+ />
1008
+ </div>
1009
+ <div style={styles.settingsDiv}>
1010
+ <div style={styles.settingsDiv}>{this.getPeriodSettingsYearly()}</div>
1011
+ {!!schedule.period.years && <div style={styles.settingsDiv}>
1012
+ <span>{I18n.t('sch_on')}</span>
1013
+ <Input
1014
+ key="input"
1015
+ value={this.state.schedule.period.yearDate}
1016
+ style={styles.inputEvery}
1017
+ type="number"
1018
+ inputProps={{ min: 1, max: 31 }}
1019
+ onChange={e => {
1020
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1021
+ _schedule.period.yearDate = parseInt(e.target.value, 10);
1022
+ if (_schedule.period.yearDate < 1) _schedule.period.yearDate = 31;
1023
+ if (_schedule.period.yearDate > 31) _schedule.period.yearDate = 1;
1024
+ this.onChange(_schedule);
1025
+ }}
1026
+ />
1027
+ <Select
1028
+ variant="standard"
1029
+ value={schedule.period.yearMonth}
1030
+ onChange={e => {
1031
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1032
+ _schedule.period.yearMonth = e.target.value;
1033
+ this.onChange(_schedule);
1034
+ }}
1035
+ >
1036
+ <MenuItem key="every" value={0}>{I18n.t('sch_yearEveryMonth')}</MenuItem>
1037
+ {MONTHS.map((month, i) => <MenuItem key={month} value={i + 1}>{I18n.t(month)}</MenuItem>)}
1038
+ </Select>
1039
+ </div>}
1040
+ </div>
1041
+ </Box>,
1042
+ ];
1043
+ }
1044
+
1045
+ getPeriodSettingsMinutes() {
1046
+ return <div style={{ display: 'inline-block' }}>
1047
+ <label>{I18n.t('sch_every')}</label>
1048
+ <Input
1049
+ value={this.state.schedule.time.interval}
1050
+ style={{ ...styles.inputEvery, verticalAlign: 'bottom' }}
1051
+ type="number"
1052
+ inputProps={{ min: 1 }}
1053
+ onChange={e => {
1054
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1055
+ _schedule.time.interval = parseInt(e.target.value, 10);
1056
+ this.onChange(_schedule);
1057
+ }}
1058
+ />
1059
+ <Select
1060
+ variant="standard"
1061
+ value={this.state.schedule.time.mode}
1062
+ onChange={e => {
1063
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1064
+ _schedule.time.mode = e.target.value;
1065
+ this.onChange(_schedule);
1066
+ }}
1067
+ >
1068
+ <MenuItem value={PERIODS.minutes}>{I18n.t('sch_periodMinutes')}</MenuItem>
1069
+ <MenuItem value={PERIODS.hours}>{I18n.t('sch_periodHours')}</MenuItem>
1070
+ </Select>
1071
+ </div>;
1072
+ }
1073
+
1074
+ getPeriodSettingsWeekdays() {
1075
+ // || this.state.schedule.period.dows === '[1, 2, 3, 4, 5]' || this.state.schedule.period.dows === '[0, 6]'
1076
+ const schedule = this.state.schedule;
1077
+ const isSpecific = schedule.period.dows && schedule.period.dows !== '[1, 2, 3, 4, 5]' && schedule.period.dows !== '[0, 6]';
1078
+ return [
1079
+ <div key="workdays">
1080
+ <FormControlLabel
1081
+ control={<Radio
1082
+ style={styles.inputRadio}
1083
+ checked={schedule.period.dows === '[1, 2, 3, 4, 5]'}
1084
+ onClick={() => {
1085
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1086
+ _schedule.period.dows = '[1, 2, 3, 4, 5]';
1087
+ if (_schedule.period.days) {
1088
+ _schedule.period.days = 1;
1089
+ }
1090
+ this.onChange(_schedule);
1091
+ }}
1092
+ />}
1093
+ label={I18n.t('sch_periodWorkdays')}
1094
+ />
1095
+ </div>,
1096
+
1097
+ <div key="weekend">
1098
+ <FormControlLabel
1099
+ control={<Radio
1100
+ style={styles.inputRadio}
1101
+ checked={schedule.period.dows === '[0, 6]'}
1102
+ onClick={() => {
1103
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1104
+ _schedule.period.dows = '[0, 6]';
1105
+ if (_schedule.period.days) {
1106
+ _schedule.period.days = 1;
1107
+ }
1108
+ this.onChange(_schedule);
1109
+ }}
1110
+ />}
1111
+ label={I18n.t('sch_periodWeekend')}
1112
+ />
1113
+ </div>,
1114
+
1115
+ <div
1116
+ key="specific"
1117
+ style={{ verticalAlign: 'top' }}
1118
+ >
1119
+ <FormControlLabel
1120
+ style={{ verticalAlign: 'top' }}
1121
+ control={<Radio
1122
+ style={styles.inputRadio}
1123
+ checked={!!isSpecific}
1124
+ onClick={() => {
1125
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1126
+ _schedule.period.dows = '[0, 1, 2, 3, 4, 5, 6]';
1127
+ if (_schedule.period.days) {
1128
+ _schedule.period.days = 1;
1129
+ }
1130
+ this.onChange(_schedule);
1131
+ }}
1132
+ />}
1133
+ label={I18n.t('sch_periodWeekdays')}
1134
+ />
1135
+ {isSpecific && (schedule.period.days === 1 || schedule.period.weeks) &&
1136
+ <FormGroup row style={{ ...styles.inputGroup, width: 150 }}>
1137
+ {[1, 2, 3, 4, 5, 6, 0].map(i =>
1138
+ <FormControlLabel
1139
+ key={`specific_${i}`}
1140
+ style={styles.inputGroupElement}
1141
+ control={<Checkbox
1142
+ style={styles.inputSmallCheck}
1143
+ checked={schedule.period.dows.includes(i.toString())}
1144
+ onChange={e => {
1145
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1146
+ let daysOfWeek: number[];
1147
+ try {
1148
+ daysOfWeek = JSON.parse(_schedule.period.dows);
1149
+ } catch (err) {
1150
+ daysOfWeek = [];
1151
+ }
1152
+ if (e.target.checked && !daysOfWeek.includes(i)) {
1153
+ daysOfWeek.push(i);
1154
+ } else if (!e.target.checked && daysOfWeek.includes(i)) {
1155
+ daysOfWeek.splice(daysOfWeek.indexOf(i), 1);
1156
+ }
1157
+ daysOfWeek.sort((a: number, b: number) => a - b);
1158
+ _schedule.period.dows = JSON.stringify(daysOfWeek);
1159
+ if (_schedule.period.days) {
1160
+ _schedule.period.days = 1;
1161
+ }
1162
+ this.onChange(_schedule);
1163
+ }}
1164
+ />}
1165
+ label={I18n.t(WEEKDAYS[i])}
1166
+ />)}
1167
+ </FormGroup>}
1168
+ </div>,
1169
+ ];
1170
+ }
1171
+
1172
+ getPeriodSettingsDaily() {
1173
+ if (!this.state.schedule.period.days) {
1174
+ return null;
1175
+ }
1176
+ const schedule = this.state.schedule;
1177
+ return [
1178
+ <div key="every_day">
1179
+ <FormControlLabel
1180
+ control={<Radio
1181
+ style={styles.inputRadio}
1182
+ checked={schedule.period.days === 1 && !schedule.period.dows}
1183
+ onClick={() => {
1184
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1185
+ _schedule.period.days = 1;
1186
+ _schedule.period.dows = '';
1187
+ this.onChange(_schedule);
1188
+ }}
1189
+ />}
1190
+ label={I18n.t('sch_periodEveryDay')}
1191
+ />
1192
+ </div>,
1193
+ <div key="everyN_day">
1194
+ <FormControlLabel
1195
+ control={<Radio
1196
+ style={styles.inputRadio}
1197
+ checked={schedule.period.days > 1}
1198
+ onClick={() => {
1199
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1200
+ _schedule.period.days = 2;
1201
+ _schedule.period.dows = '';
1202
+ this.onChange(_schedule);
1203
+ }}
1204
+ />}
1205
+ label={I18n.t('sch_periodEvery')}
1206
+ />
1207
+ {schedule.period.days > 1 && [
1208
+ <Input
1209
+ key="input"
1210
+ value={this.state.schedule.period.days}
1211
+ style={styles.inputEvery}
1212
+ type="number"
1213
+ inputProps={{ min: 2 }}
1214
+ onChange={e => {
1215
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1216
+ _schedule.period.days = parseInt(e.target.value, 10);
1217
+ _schedule.period.dows = '';
1218
+ this.onChange(_schedule);
1219
+ }}
1220
+ />,
1221
+ <span key="span" style={{ paddingRight: 10 }}>{I18n.t('sch_periodDay')}</span>,
1222
+ ]}
1223
+ </div>,
1224
+ ];
1225
+ }
1226
+
1227
+ getPeriodSettingsWeekly() {
1228
+ if (!this.state.schedule.period.weeks) {
1229
+ return null;
1230
+ }
1231
+ const schedule = this.state.schedule;
1232
+ return [
1233
+ <div key="radios" style={{ display: 'inline-block', verticalAlign: 'top' }}>
1234
+ <div>
1235
+ <FormControlLabel
1236
+ control={<Radio
1237
+ style={styles.inputRadio}
1238
+ checked={schedule.period.weeks === 1}
1239
+ onClick={() => {
1240
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1241
+ _schedule.period.weeks = 1;
1242
+ this.onChange(_schedule);
1243
+ }}
1244
+ />}
1245
+ label={I18n.t('sch_periodEveryWeek')}
1246
+ />
1247
+ </div>
1248
+ <div>
1249
+ <FormControlLabel
1250
+ control={<Radio
1251
+ style={styles.inputRadio}
1252
+ checked={schedule.period.weeks > 1}
1253
+ onClick={() => {
1254
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1255
+ _schedule.period.weeks = 2;
1256
+ this.onChange(_schedule);
1257
+ }}
1258
+ />}
1259
+ label={I18n.t('sch_periodEvery')}
1260
+ />
1261
+ {schedule.period.weeks > 1 && [
1262
+ <Input
1263
+ key="input"
1264
+ value={this.state.schedule.period.weeks}
1265
+ style={styles.inputEvery}
1266
+ type="number"
1267
+ inputProps={{ min: 2 }}
1268
+ onChange={e => {
1269
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1270
+ _schedule.period.weeks = parseInt(e.target.value, 10);
1271
+ this.onChange(_schedule);
1272
+ }}
1273
+ />,
1274
+ <span key="text">{I18n.t('sch_periodWeek')}</span>,
1275
+ ]}
1276
+ </div>
1277
+ </div>,
1278
+ ];
1279
+ }
1280
+
1281
+ getPeriodSettingsDates() {
1282
+ if (!this.state.schedule.period.dates) {
1283
+ return null;
1284
+ }
1285
+ const schedule = this.state.schedule;
1286
+
1287
+ const dates = [];
1288
+ for (let i = 1; i <= 31; i++) {
1289
+ dates.push(i);
1290
+ }
1291
+
1292
+ const parsedDates = JSON.parse(schedule.period.dates);
1293
+
1294
+ return <FormGroup
1295
+ row
1296
+ style={{ ...styles.inputGroup, maxWidth: 620 }}
1297
+ >
1298
+ <FormControlLabel
1299
+ style={styles.inputDateDay}
1300
+ control={<Checkbox
1301
+ style={styles.inputDateDayCheck}
1302
+ checked={parsedDates.length === 31}
1303
+ onChange={() => {
1304
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1305
+ const _dates = [];
1306
+ for (let i = 1; i <= 31; i++) {
1307
+ _dates.push(i);
1308
+ }
1309
+ _schedule.period.dates = JSON.stringify(_dates);
1310
+ this.onChange(_schedule);
1311
+ }}
1312
+ />}
1313
+ label={I18n.t('sch_all')}
1314
+ />
1315
+ <FormControlLabel
1316
+ style={styles.inputDateDay}
1317
+ control={<Checkbox
1318
+ style={styles.inputDateDayCheck}
1319
+ checked={!parsedDates.length}
1320
+ onChange={() => {
1321
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1322
+ _schedule.period.dates = '[]';
1323
+ this.onChange(_schedule);
1324
+ }}
1325
+ />}
1326
+ label={I18n.t('sch_no_one')}
1327
+ />
1328
+ {parsedDates.length !== 31 && !!parsedDates.length &&
1329
+ <FormControlLabel
1330
+ style={styles.inputDateDay}
1331
+ control={<Checkbox
1332
+ style={styles.inputDateDayCheck}
1333
+ checked={false}
1334
+ onChange={() => {
1335
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1336
+ const result = [];
1337
+ const _parsedDates = JSON.parse(_schedule.period.dates);
1338
+ for (let i = 1; i <= 31; i++) {
1339
+ if (!_parsedDates.includes(i)) {
1340
+ result.push(i);
1341
+ }
1342
+ }
1343
+ result.sort((a, b) => a - b);
1344
+ _schedule.period.dates = JSON.stringify(result);
1345
+ this.onChange(_schedule);
1346
+ }}
1347
+ />}
1348
+ label={I18n.t('sch_invert')}
1349
+ />}
1350
+ <div />
1351
+ {dates.map(i =>
1352
+ <FormControlLabel
1353
+ key={`date_${i}`}
1354
+ style={!i ? {
1355
+ ...styles.inputDateDay,
1356
+ opacity: 0,
1357
+ cursor: 'default',
1358
+ userSelect: 'none',
1359
+ pointerEvents: 'none',
1360
+ } : styles.inputDateDay}
1361
+ control={<Checkbox
1362
+ style={styles.inputDateDayCheck}
1363
+ checked={JSON.parse(schedule.period.dates).includes(i)}
1364
+ onChange={e => {
1365
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1366
+ let _dates;
1367
+ try {
1368
+ _dates = JSON.parse(_schedule.period.dates);
1369
+ } catch (err) {
1370
+ _dates = [];
1371
+ }
1372
+ if (e.target.checked && !_dates.includes(i)) {
1373
+ _dates.push(i);
1374
+ } else if (!e.target.checked && _dates.includes(i)) {
1375
+ _dates.splice(_dates.indexOf(i), 1);
1376
+ }
1377
+ _dates.sort((a: number, b: number) => a - b);
1378
+ _schedule.period.dates = JSON.stringify(_dates);
1379
+ this.onChange(_schedule);
1380
+ }}
1381
+ />}
1382
+ label={i < 10 ? [
1383
+ <span key="0" style={{ opacity: 0 }}>0</span>,
1384
+ <span key="num">{i}</span>,
1385
+ ] : i}
1386
+ />)}
1387
+ </FormGroup>;
1388
+ }
1389
+
1390
+ getPeriodSettingsMonthly() {
1391
+ if (!this.state.schedule.period.months) {
1392
+ return null;
1393
+ }
1394
+ const schedule = this.state.schedule;
1395
+ const parsedMonths = typeof schedule.period.months === 'string' ? JSON.parse(schedule.period.months) : [];
1396
+
1397
+ return [
1398
+ <div key="every">
1399
+ <FormControlLabel
1400
+ control={<Radio
1401
+ style={styles.inputRadio}
1402
+ checked={typeof schedule.period.months === 'number' && schedule.period.months === 1}
1403
+ onClick={() => {
1404
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1405
+ _schedule.period.months = 1;
1406
+ this.onChange(schedule);
1407
+ }}
1408
+ />}
1409
+ label={I18n.t('sch_periodEveryMonth')}
1410
+ />
1411
+ </div>,
1412
+ <div key="everyN">
1413
+ <FormControlLabel
1414
+ control={<Radio
1415
+ style={styles.inputRadio}
1416
+ checked={typeof schedule.period.months === 'number' && schedule.period.months > 1}
1417
+ onClick={() => {
1418
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1419
+ _schedule.period.months = 2;
1420
+ this.onChange(_schedule);
1421
+ }}
1422
+ />}
1423
+ label={I18n.t('sch_periodEvery')}
1424
+ />
1425
+ {typeof schedule.period.months === 'number' && schedule.period.months > 1 && [
1426
+ <Input
1427
+ key="input"
1428
+ value={schedule.period.months}
1429
+ style={styles.inputEvery}
1430
+ type="number"
1431
+ inputProps={{ min: 2 }}
1432
+ onChange={e => {
1433
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1434
+ _schedule.period.months = parseInt(e.target.value, 10);
1435
+ if (_schedule.period.months < 1) _schedule.period.months = 1;
1436
+ this.onChange(_schedule);
1437
+ }}
1438
+ />,
1439
+ <span key="text">{I18n.t('sch_periodMonth')}</span>,
1440
+ ]}
1441
+ </div>,
1442
+ <div key="specific" style={{ verticalAlign: 'top' }}>
1443
+ <FormControlLabel
1444
+ style={{ verticalAlign: 'top' }}
1445
+ control={<Radio
1446
+ style={styles.inputRadio}
1447
+ checked={typeof schedule.period.months === 'string'}
1448
+ onClick={() => {
1449
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1450
+ _schedule.period.months = '[1,2,3,4,5,6,7,8,9,10,11,12]';
1451
+ this.onChange(_schedule);
1452
+ }}
1453
+ />}
1454
+ label={I18n.t('sch_periodSpecificMonths')}
1455
+ />
1456
+ {typeof schedule.period.months === 'string' &&
1457
+ <FormGroup
1458
+ row
1459
+ style={styles.inputGroup}
1460
+ >
1461
+ <FormControlLabel
1462
+ style={styles.inputDateDay}
1463
+ control={<Checkbox
1464
+ style={styles.inputDateDayCheck}
1465
+ checked={parsedMonths.length === 12}
1466
+ onChange={() => {
1467
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1468
+ const months = [];
1469
+ for (let i = 1; i <= 12; i++) {
1470
+ months.push(i);
1471
+ }
1472
+ _schedule.period.months = JSON.stringify(months);
1473
+ this.onChange(_schedule);
1474
+ }}
1475
+ />}
1476
+ label={I18n.t('sch_all')}
1477
+ />
1478
+ <FormControlLabel
1479
+ style={styles.inputDateDay}
1480
+ control={<Checkbox
1481
+ style={styles.inputDateDayCheck}
1482
+ checked={!parsedMonths.length}
1483
+ onChange={() => {
1484
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1485
+ _schedule.period.months = '[]';
1486
+ this.onChange(_schedule);
1487
+ }}
1488
+ />}
1489
+ label={I18n.t('sch_no_one')}
1490
+ />
1491
+ {parsedMonths.length !== 12 && !!parsedMonths.length &&
1492
+ <FormControlLabel
1493
+ style={styles.inputDateDay}
1494
+ control={<Checkbox
1495
+ style={styles.inputDateDayCheck}
1496
+ checked={false}
1497
+ onChange={() => {
1498
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1499
+ const result = [];
1500
+ const _parsedMonths = JSON.parse(_schedule.period.months);
1501
+ for (let i = 1; i <= 12; i++) {
1502
+ if (!_parsedMonths.includes(i)) {
1503
+ result.push(i);
1504
+ }
1505
+ }
1506
+ result.sort((a, b) => a - b);
1507
+ _schedule.period.months = JSON.stringify(result);
1508
+ this.onChange(_schedule);
1509
+ }}
1510
+ />}
1511
+ label={I18n.t('sch_invert')}
1512
+ />}
1513
+ <div />
1514
+ {MONTHS.map((month, i) =>
1515
+ <FormControlLabel
1516
+ style={styles.inputGroupElement}
1517
+ control={<Checkbox
1518
+ style={styles.inputSmallCheck}
1519
+ checked={typeof schedule.period.months === 'string' ? JSON.parse(schedule.period.months).includes(i + 1) : schedule.period.months === i}
1520
+ onChange={e => {
1521
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1522
+ let months;
1523
+ try {
1524
+ months = JSON.parse(_schedule.period.months);
1525
+ } catch (err) {
1526
+ months = [];
1527
+ }
1528
+ if (e.target.checked && !months.includes(i + 1)) {
1529
+ months.push(i + 1);
1530
+ } else if (!e.target.checked && months.includes(i + 1)) {
1531
+ months.splice(months.indexOf(i + 1), 1);
1532
+ }
1533
+ months.sort((a: number, b: number) => a - b);
1534
+ _schedule.period.months = JSON.stringify(months);
1535
+ this.onChange(_schedule);
1536
+ }}
1537
+ />}
1538
+ label={I18n.t(month)}
1539
+ />)}
1540
+ </FormGroup>}
1541
+ </div>,
1542
+ ];
1543
+ }
1544
+
1545
+ getPeriodSettingsYearly() {
1546
+ if (!this.state.schedule.period.years) {
1547
+ return null;
1548
+ }
1549
+ const schedule = this.state.schedule;
1550
+ return [
1551
+ <div key="year">
1552
+ <FormControlLabel
1553
+ control={<Radio
1554
+ style={styles.inputRadio}
1555
+ checked={schedule.period.years === 1}
1556
+ onClick={() => {
1557
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1558
+ _schedule.period.years = 1;
1559
+ this.onChange(_schedule);
1560
+ }}
1561
+ />}
1562
+ label={I18n.t('sch_periodEveryYear')}
1563
+ />
1564
+ </div>,
1565
+ <div key="every">
1566
+ <FormControlLabel
1567
+ control={<Radio
1568
+ style={styles.inputRadio}
1569
+ checked={schedule.period.years > 1}
1570
+ onClick={() => {
1571
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1572
+ _schedule.period.years = 2;
1573
+ this.onChange(_schedule);
1574
+ }}
1575
+ />}
1576
+ label={I18n.t('sch_periodEvery')}
1577
+ />
1578
+ {schedule.period.years > 1 && [
1579
+ <Input
1580
+ key="input"
1581
+ value={this.state.schedule.period.years}
1582
+ style={styles.inputEvery}
1583
+ type="number"
1584
+ inputProps={{ min: 2 }}
1585
+ onChange={e => {
1586
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1587
+ _schedule.period.years = parseInt(e.target.value, 10);
1588
+ if (_schedule.period.years < 1) _schedule.period.years = 1;
1589
+ this.onChange(_schedule);
1590
+ }}
1591
+ />,
1592
+ <span key="text">{I18n.t('sch_periodYear')}</span>,
1593
+ ]}
1594
+ </div>,
1595
+ ];
1596
+ }
1597
+
1598
+ static now2string(isEnd?: boolean): string {
1599
+ const d = new Date();
1600
+ d.setHours(0);
1601
+ d.setMinutes(0);
1602
+ d.setSeconds(0);
1603
+ d.setMilliseconds(0);
1604
+ if (isEnd) {
1605
+ d.setDate(d.getDate() + 2);
1606
+ d.setMilliseconds(d.getMilliseconds() - 1);
1607
+ }
1608
+
1609
+ return `${padding(d.getDate())}.${padding(d.getMonth() + 1)}.${padding(d.getFullYear())}`;
1610
+ }
1611
+
1612
+ static string2date(str: string): Date {
1613
+ let parts = str.split('.'); // 31.12.2019
1614
+ if (parts.length === 1) {
1615
+ parts = str.split('-'); // 2018-12-31
1616
+ return new Date(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10));
1617
+ }
1618
+ return new Date(parseInt(parts[2], 10), parseInt(parts[1], 10) - 1, parseInt(parts[0], 10));
1619
+ }
1620
+
1621
+ getValidSettings() {
1622
+ const schedule = this.state.schedule;
1623
+ // ----- from ---
1624
+ return <div style={styles.rowDiv}>
1625
+ <div style={{ ...styles.modeDiv, verticalAlign: 'middle' }}>
1626
+ <span style={{ fontWeight: 'bold', paddingRight: 10 }}>{I18n.t('sch_valid')}</span>
1627
+ <span>{I18n.t('sch_validFrom')}</span>
1628
+ </div>
1629
+ <div style={styles.settingsDiv}>
1630
+ <TextField
1631
+ variant="standard"
1632
+ style={{ ...styles.inputDate, marginRight: 10 }}
1633
+ key="exactTimeFrom"
1634
+ inputRef={this.refFrom}
1635
+ defaultValue={string2USdate(schedule.valid.from)}
1636
+ type="date"
1637
+ // inputComponent={TextDate}
1638
+ onChange={e => {
1639
+ this.timerFrom && clearTimeout(this.timerFrom);
1640
+
1641
+ if (this.refFrom.current) {
1642
+ this.refFrom.current.style.background = '#ff000030';
1643
+ }
1644
+
1645
+ this.timerFrom = setTimeout(value => {
1646
+ this.timerFrom = null;
1647
+ if (this.refFrom.current) {
1648
+ this.refFrom.current.style.background = '';
1649
+ }
1650
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1651
+ const date = Schedule.string2date(value);
1652
+ if (date.toString() !== 'Invalid Date') {
1653
+ _schedule.valid.from = `${padding(date.getDate())}.${padding(date.getMonth() + 1)}.${date.getFullYear()}`;
1654
+ this.onChange(_schedule);
1655
+ }
1656
+ }, 1500, e.target.value);
1657
+ }}
1658
+ InputLabelProps={{ shrink: true }}
1659
+ margin="normal"
1660
+ />
1661
+ <FormControlLabel
1662
+ control={<Checkbox
1663
+ style={styles.inputRadio}
1664
+ checked={!!schedule.valid.to}
1665
+ onClick={() => {
1666
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1667
+ _schedule.valid.to = _schedule.valid.to ? '' : Schedule.now2string(true);
1668
+ this.onChange(_schedule);
1669
+ }}
1670
+ />}
1671
+ label={I18n.t('sch_validTo')}
1672
+ />
1673
+ {!!schedule.valid.to && <TextField
1674
+ variant="standard"
1675
+ inputRef={this.refTo}
1676
+ style={{ ...styles.inputDate, marginRight: 10 }}
1677
+ key="exactTimeFrom"
1678
+ type="date"
1679
+ defaultValue={string2USdate(schedule.valid.to)}
1680
+ // inputComponent={TextDate}
1681
+ onChange={e => {
1682
+ this.timerTo && clearTimeout(this.timerTo);
1683
+
1684
+ if (this.refTo.current) {
1685
+ this.refTo.current.style.background = '#ff000030';
1686
+ }
1687
+ this.timerTo = setTimeout(value => {
1688
+ this.timerTo = null;
1689
+ if (this.refTo.current) {
1690
+ this.refTo.current.style.background = '';
1691
+ }
1692
+ const _schedule = JSON.parse(JSON.stringify(this.state.schedule));
1693
+ const date = Schedule.string2date(value);
1694
+ if (date.toString() !== 'Invalid Date') {
1695
+ _schedule.valid.to = `${padding(date.getDate())}.${padding(date.getMonth() + 1)}.${date.getFullYear()}`;
1696
+ this.onChange(_schedule);
1697
+ }
1698
+ }, 1500, e.target.value);
1699
+ }}
1700
+ InputLabelProps={{ shrink: true }}
1701
+ margin="normal"
1702
+ />}
1703
+ </div>
1704
+ </div>;
1705
+ }
1706
+
1707
+ render() {
1708
+ return <div style={{ height: 'calc(100% - 48px)', width: '100%', overflow: 'hidden' }}>
1709
+ <div>{this.state.desc}</div>
1710
+ <div style={styles.scrollWindow}>
1711
+ <h5>{I18n.t('sch_time')}</h5>
1712
+ {this.getTimePeriodElements()}
1713
+ {this.getTimeExactElements()}
1714
+ {Schedule.getDivider()}
1715
+ <h5>{I18n.t('sch_period')}</h5>
1716
+ {this.getPeriodModes()}
1717
+ {!this.state.schedule.period.once && Schedule.getDivider()}
1718
+ {!this.state.schedule.period.once && this.getValidSettings()}
1719
+ </div>
1720
+ </div>;
1721
+ }
1722
+ }
1723
+
1724
+ export default Schedule;