@iobroker/adapter-react-v5 7.0.1 → 7.1.0

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