@@ -6,12 +6,13 @@ import type {
6
6
UmbDocumentScheduleModalValue ,
7
7
UmbDocumentScheduleSelectionModel ,
8
8
} from './document-schedule-modal.token.js' ;
9
- import { css , customElement , html , repeat , state , when } from '@umbraco-cms/backoffice/external/lit' ;
9
+ import { css , customElement , html , ref , repeat , state , when } from '@umbraco-cms/backoffice/external/lit' ;
10
10
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal' ;
11
11
import { UmbTextStyles } from '@umbraco-cms/backoffice/style' ;
12
12
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils' ;
13
+ import { umbBindToValidation , UmbValidationContext } from '@umbraco-cms/backoffice/validation' ;
13
14
import type { UmbInputDateElement } from '@umbraco-cms/backoffice/components' ;
14
- import type { UUIBooleanInputElement } from '@umbraco-cms/backoffice/external/uui' ;
15
+ import type { UUIBooleanInputElement , UUIButtonState } from '@umbraco-cms/backoffice/external/uui' ;
15
16
16
17
@customElement ( 'umb-document-schedule-modal' )
17
18
export class UmbDocumentScheduleModalElement extends UmbModalBaseElement <
@@ -35,6 +36,11 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
35
36
@state ( )
36
37
_internalValues : Array < UmbDocumentScheduleSelectionModel > = [ ] ;
37
38
39
+ @state ( )
40
+ private _submitButtonState ?: UUIButtonState ;
41
+
42
+ #validation = new UmbValidationContext ( this ) ;
43
+
38
44
#pickableFilter = ( option : UmbDocumentVariantOptionModel ) => {
39
45
if ( isNotPublishedMandatory ( option ) ) {
40
46
return true ;
@@ -91,11 +97,20 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
91
97
this . #selectionManager. setSelection ( selected ) ;
92
98
}
93
99
94
- #submit( ) {
95
- this . value = {
96
- selection : this . _internalValues ,
97
- } ;
98
- this . modalContext ?. submit ( ) ;
100
+ async #submit( ) {
101
+ this . _submitButtonState = 'waiting' ;
102
+ try {
103
+ await this . #validation. validate ( ) ;
104
+ this . _submitButtonState = 'success' ;
105
+ this . value = {
106
+ selection : this . _internalValues ,
107
+ } ;
108
+ this . modalContext ?. submit ( ) ;
109
+ } catch {
110
+ this . _submitButtonState = 'failed' ;
111
+ } finally {
112
+ this . _submitButtonState = undefined ;
113
+ }
99
114
}
100
115
101
116
#close( ) {
@@ -146,6 +161,7 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
146
161
<div slot= "actions" >
147
162
<uui- butto n label= ${ this . localize . term ( 'general_close' ) } @click = ${ this . #close} > </ uui- butto n>
148
163
<uui- butto n
164
+ .state = ${ this . _submitButtonState }
149
165
label= "${ this . localize . term ( 'buttons_schedulePublish' ) } "
150
166
look= "primary"
151
167
color = "positive"
@@ -203,59 +219,115 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
203
219
` ;
204
220
}
205
221
222
+ #attachValidatorsToPublish( element : UmbInputDateElement | null ) {
223
+ if ( ! element ) return ;
224
+
225
+ element . addValidator (
226
+ 'badInput' ,
227
+ ( ) => this . localize . term ( 'speechBubbles_scheduleErrReleaseDate1' ) ,
228
+ ( ) => {
229
+ const value = element . value . toString ( ) ;
230
+ if ( ! value ) return false ;
231
+ const date = new Date ( value ) ;
232
+ return date < new Date ( ) ;
233
+ } ,
234
+ ) ;
235
+ }
236
+
237
+ #attachValidatorsToUnpublish( element : UmbInputDateElement | null , unique : string ) {
238
+ if ( ! element ) return ;
239
+
240
+ element . addValidator (
241
+ 'badInput' ,
242
+ ( ) => this . localize . term ( 'speechBubbles_scheduleErrExpireDate1' ) ,
243
+ ( ) => {
244
+ const value = element . value . toString ( ) ;
245
+ if ( ! value ) return false ;
246
+ const date = new Date ( value ) ;
247
+ return date < new Date ( ) ;
248
+ } ,
249
+ ) ;
250
+
251
+ element . addValidator (
252
+ 'customError' ,
253
+ ( ) => this . localize . term ( 'speechBubbles_scheduleErrExpireDate2' ) ,
254
+ ( ) => {
255
+ const value = element . value . toString ( ) ;
256
+ if ( ! value ) return false ;
257
+
258
+ // Check if the unpublish date is before the publish date
259
+ const variant = this . _internalValues . find ( ( s ) => s . unique === unique ) ;
260
+ if ( ! variant ) return false ;
261
+ const publishTime = variant . schedule ?. publishTime ;
262
+ if ( ! publishTime ) return false ;
263
+
264
+ const date = new Date ( value ) ;
265
+ const publishDate = new Date ( publishTime ) ;
266
+ return date < publishDate ;
267
+ } ,
268
+ ) ;
269
+ }
270
+
206
271
#renderPublishDateInput( option : UmbDocumentVariantOptionModel , fromDate : string | null , toDate : string | null ) {
207
- return html `<div class= "publish-date" >
208
- <uui- for m- layout- item>
209
- <uui- label slot= "label" > <umb- localize key= "content_releaseDate" > Publish at </ umb- localize> </ uui- label>
210
- <div>
211
- <umb- input- date
212
- type= "datetime-local"
213
- .value = ${ this . #formatDate( fromDate ) }
214
- @change = ${ ( e : Event ) => this . #onFromDateChange( e , option . unique ) }
215
- label= ${ this . localize . term ( 'general_publishDate' ) } >
216
- <div slot= "append" >
217
- ${ when (
218
- fromDate ,
219
- ( ) => html `
220
- <uui- butto n
221
- compact
222
- label= ${ this . localize . term ( 'general_clear' ) }
223
- title= ${ this . localize . term ( 'general_clear' ) }
224
- @click = ${ ( ) => this . #removeFromDate( option . unique ) } >
225
- <uui- icon name= "remove" > </ uui- icon>
226
- </ uui- butto n>
227
- ` ,
228
- ) }
229
- </ div>
230
- </ umb- input- date>
231
- </ div>
232
- </ uui- for m- layout- item>
233
- <uui- for m- layout- item>
234
- <uui- label slot= "label" > <umb- localize key= "content_unpublishDate" > Unpublish at </ umb- localize> </ uui- label>
235
- <div>
236
- <umb- input- date
237
- type= "datetime-local"
238
- .value = ${ this . #formatDate( toDate ) }
239
- @change = ${ ( e : Event ) => this . #onToDateChange( e , option . unique ) }
240
- label= ${ this . localize . term ( 'general_publishDate' ) } >
241
- <div slot= "append" >
242
- ${ when (
243
- toDate ,
244
- ( ) => html `
245
- <uui- butto n
246
- compact
247
- label= ${ this . localize . term ( 'general_clear' ) }
248
- title= ${ this . localize . term ( 'general_clear' ) }
249
- @click = ${ ( ) => this . #removeToDate( option . unique ) } >
250
- <uui- icon name= "remove" > </ uui- icon>
251
- </ uui- butto n>
252
- ` ,
253
- ) }
254
- </ div>
255
- </ umb- input- date>
256
- </ div>
257
- </ uui- for m- layout- item>
258
- </ div> ` ;
272
+ return html `
273
+ <div class= "publish-date" >
274
+ <uui- for m- layout- item>
275
+ <uui- label slot= "label" > <umb- localize key= "content_releaseDate" > Publish at </ umb- localize> </ uui- label>
276
+ <div>
277
+ <umb- input- date
278
+ ${ ref ( ( e ) => this . #attachValidatorsToPublish( e as UmbInputDateElement ) ) }
279
+ ${ umbBindToValidation ( this ) }
280
+ type= "datetime-local"
281
+ .value = ${ this . #formatDate( fromDate ) }
282
+ @change = ${ ( e : Event ) => this . #onFromDateChange( e , option . unique ) }
283
+ label= ${ this . localize . term ( 'general_publishDate' ) } >
284
+ <div slot= "append" >
285
+ ${ when (
286
+ fromDate ,
287
+ ( ) => html `
288
+ <uui- butto n
289
+ compact
290
+ label= ${ this . localize . term ( 'general_clear' ) }
291
+ title= ${ this . localize . term ( 'general_clear' ) }
292
+ @click = ${ ( ) => this . #removeFromDate( option . unique ) } >
293
+ <uui- icon name= "remove" > </ uui- icon>
294
+ </ uui- butto n>
295
+ ` ,
296
+ ) }
297
+ </ div>
298
+ </ umb- input- date>
299
+ </ div>
300
+ </ uui- for m- layout- item>
301
+
302
+ <uui- for m- layout- item>
303
+ <uui- label slot= "label" > <umb- localize key= "content_unpublishDate" > Unpublish at </ umb- localize> </ uui- label>
304
+ <div>
305
+ <umb- input- date
306
+ ${ ref ( ( e ) => this . #attachValidatorsToUnpublish( e as UmbInputDateElement , option . unique ) ) }
307
+ ${ umbBindToValidation ( this ) }
308
+ type= "datetime-local"
309
+ .value = ${ this . #formatDate( toDate ) }
310
+ @change = ${ ( e : Event ) => this . #onToDateChange( e , option . unique ) }
311
+ label= ${ this . localize . term ( 'general_publishDate' ) } >
312
+ <div slot= "append" >
313
+ ${ when (
314
+ toDate ,
315
+ ( ) => html `
316
+ <uui- butto n
317
+ compact
318
+ label= ${ this . localize . term ( 'general_clear' ) }
319
+ title= ${ this . localize . term ( 'general_clear' ) }
320
+ @click = ${ ( ) => this . #removeToDate( option . unique ) } >
321
+ <uui- icon name= "remove" > </ uui- icon>
322
+ </ uui- butto n>
323
+ ` ,
324
+ ) }
325
+ </ div>
326
+ </ umb- input- date>
327
+ </ div>
328
+ </ uui- for m- layout- item>
329
+ </ div>
330
+ ` ;
259
331
}
260
332
261
333
#fromDate( unique : string ) : string | null {
@@ -275,6 +347,7 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
275
347
...variant . schedule ,
276
348
publishTime : null ,
277
349
} ;
350
+ this . #validation. validate ( ) ;
278
351
this . requestUpdate ( '_internalValues' ) ;
279
352
}
280
353
@@ -285,6 +358,7 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
285
358
...variant . schedule ,
286
359
unpublishTime : null ,
287
360
} ;
361
+ this . #validation. validate ( ) ;
288
362
this . requestUpdate ( '_internalValues' ) ;
289
363
}
290
364
@@ -325,6 +399,7 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
325
399
...variant . schedule ,
326
400
publishTime : this . #getDateValue( e ) ,
327
401
} ;
402
+ this . #validation. validate ( ) ;
328
403
this . requestUpdate ( '_internalValues' ) ;
329
404
}
330
405
@@ -335,6 +410,7 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
335
410
...variant . schedule ,
336
411
unpublishTime : this . #getDateValue( e ) ,
337
412
} ;
413
+ this . #validation. validate ( ) ;
338
414
this . requestUpdate ( '_internalValues' ) ;
339
415
}
340
416
0 commit comments