32
32
:name =" props.name"
33
33
:label =" t('issue.issue')"
34
34
:description =" t('publication.assignToIssue.issueDescription')"
35
- :is-required =" isRequired "
35
+ :is-required =" isIssueSelectionRequired "
36
36
:value =" selectedIssueId"
37
37
:options =" availableIssues"
38
38
:all-errors =" {}"
@@ -88,7 +88,7 @@ const props = defineProps({
88
88
},
89
89
isRequired: {
90
90
type: Boolean ,
91
- default: false ,
91
+ default: true ,
92
92
},
93
93
isPhpForm: {
94
94
type: Boolean ,
@@ -149,7 +149,7 @@ const fetchAssignmentOptions = async () => {
149
149
};
150
150
151
151
const fetchAssignmentType = async () => {
152
- // we will not fetch if the assignment type is give for the publication
152
+ // will not fetch if the assignment type is give for the publication
153
153
// for example, it's can be given from the PHP form
154
154
if (props .assignmentType !== null ) {
155
155
return ;
@@ -184,18 +184,45 @@ const showIssueDropdown = computed(() => {
184
184
return option? .isPublished !== null ;
185
185
});
186
186
187
+ // TODO : need it ?
188
+ // dynamic isRequired based on selection and props.isRequired
189
+ const isIssueSelectionRequired = computed (() => {
190
+ // Only require issue selection if:
191
+ // 1. The field is marked as required (from PHP or JS)
192
+ // 2. AND the selected assignment type actually requires an issue (isPublished !== null)
193
+ const selectedOption = assignmentOptions .value .find (
194
+ (opt ) => opt .value === selectedAssignmentType .value ,
195
+ );
196
+
197
+ return props .isRequired && selectedOption? .isPublished !== null ;
198
+ });
199
+
187
200
const shouldFetchPublishedIssues = computed (() => {
188
201
const option = assignmentOptions .value .find (
189
202
(opt ) => opt .value === selectedAssignmentType .value ,
190
203
);
191
204
return option? .isPublished ;
192
205
});
193
206
207
+ // TODO : need this ?
208
+ // better validation logic
194
209
const isValid = computed (() => {
210
+ // If no assignment type selected, not valid
211
+ if (! selectedAssignmentType .value ) {
212
+ return false ;
213
+ }
214
+
195
215
const option = assignmentOptions .value .find (
196
216
(opt ) => opt .value === selectedAssignmentType .value ,
197
217
);
198
- return option? .isPublished === null || selectedIssueId .value ;
218
+
219
+ // If assignment type doesn't require issue selection, always valid
220
+ if (option? .isPublished === null ) {
221
+ return true ;
222
+ }
223
+
224
+ // If assignment type requires issue selection, check if issue is selected
225
+ return selectedIssueId .value !== null ;
199
226
});
200
227
201
228
const publicationStatus = computed (() => {
@@ -205,23 +232,38 @@ const publicationStatus = computed(() => {
205
232
return option? .status || null ;
206
233
});
207
234
235
+ // TODO : need this ?
236
+ // validation error messages
208
237
const validationErrors = computed (() => {
209
238
if (! isValid .value ) {
210
- return [t (' publication.assignToIssue.validation.issueRequired' )];
239
+ // If assignment type requires issue but none selected
240
+ if (isIssueSelectionRequired .value && ! selectedIssueId .value ) {
241
+ return [t (' publication.assignToIssue.validation.issueRequired' )];
242
+ }
243
+ // If no assignment type selected
244
+ if (! selectedAssignmentType .value ) {
245
+ return [t (' publication.assignToIssue.validation.assignmentRequired' )];
246
+ }
211
247
}
212
248
return [];
213
249
});
214
250
215
- // Emit validation errors to the form system
216
- // FIXME : NOT propagating to top level from component
217
251
watch (
218
252
validationErrors,
219
253
(errors ) => {
220
- if (errors .length > 0 ) {
221
- emit (' set-errors' , props .name , errors);
222
- } else {
223
- emit (' set-errors' , props .name , []);
224
- }
254
+ errors .length > 0
255
+ ? emit (' set-errors' , props .name , errors) // emit errors
256
+ : emit (' set-errors' , props .name , []); // clear errors
257
+ },
258
+ {immediate: true },
259
+ );
260
+
261
+ // Watch for assignment type changes to update validation
262
+ watch (
263
+ selectedAssignmentType,
264
+ () => {
265
+ // Trigger validation update when assignment type changes
266
+ // This ensures validationErrors computed property updates
225
267
},
226
268
{immediate: true },
227
269
);
@@ -262,9 +304,10 @@ const emitValue = () => {
262
304
}
263
305
} else {
264
306
const value = {
265
- assignmentType: selectedAssignmentType .value , // User's assignment type selection
266
- issueId: selectedIssueId .value , // User's issue selection
267
- publicationStatus: publicationStatus .value , // Calculated status from user's selection
307
+ assignmentType: selectedAssignmentType .value ,
308
+ issueId: selectedIssueId .value ,
309
+ publicationStatus: publicationStatus .value ,
310
+ isValid: isValid .value ,
268
311
};
269
312
270
313
// TODO: Remove this after testing
@@ -339,6 +382,52 @@ watch(selectedIssueId, () => {
339
382
emitValue ();
340
383
});
341
384
385
+ // Watch for changes and emit required state
386
+ watch (
387
+ [selectedAssignmentType, selectedIssueId],
388
+ () => {
389
+ // Determine if field is currently required
390
+ let isCurrentlyRequired = true ; // Default to required
391
+
392
+ if (selectedAssignmentType .value ) {
393
+ const selectedOption = assignmentOptions .value .find (
394
+ (opt ) => opt .value === selectedAssignmentType .value ,
395
+ );
396
+
397
+ // If assignment type doesn't require issue selection, not required
398
+ if (selectedOption? .isPublished === null ) {
399
+ isCurrentlyRequired = false ;
400
+ }
401
+ }
402
+
403
+ // Emit the current required state
404
+ emit (' set-field-required' , props .name , isCurrentlyRequired);
405
+
406
+ emitValue (); // emit the value change
407
+ },
408
+ {immediate: false }, // not run immediately since we handle it in onMounted
409
+ );
410
+
411
+ // ✅ NEW: Function to emit initial required state
412
+ const emitInitialRequiredState = () => {
413
+ // Determine if field is currently required based on initial values
414
+ let isCurrentlyRequired = true ; // Default to required
415
+
416
+ if (selectedAssignmentType .value ) {
417
+ const selectedOption = assignmentOptions .value .find (
418
+ (opt ) => opt .value === selectedAssignmentType .value ,
419
+ );
420
+
421
+ // If assignment type doesn't require issue selection, not required
422
+ if (selectedOption? .isPublished === null ) {
423
+ isCurrentlyRequired = false ;
424
+ }
425
+ }
426
+
427
+ // Emit the initial required state
428
+ emit (' set-field-required' , props .name , isCurrentlyRequired);
429
+ };
430
+
342
431
onMounted (async () => {
343
432
selectedAssignmentType .value = props .assignmentType || null ;
344
433
@@ -354,12 +443,9 @@ onMounted(async () => {
354
443
await fetchIssues ();
355
444
}
356
445
357
- // FIXME : remove this once the emit issue for hidden field is fixed
358
- if (props .isPhpForm ) {
359
- $ (' input[name="prePublishStatus"]' ).hide ();
360
- }
361
-
362
446
emitValue ();
447
+
448
+ emitInitialRequiredState ();
363
449
});
364
450
< / script>
365
451
0 commit comments