Skip to content

Commit db76a11

Browse files
EnsiyehEArnei
andauthored
fix /Scheduling: Multiple event scheduling nitpicks #1077 (#1398)
* fix /Scheduling: Multiple event scheduling nitpicks #1077 * fix the issues * Turn whitespaces into tabs --------- Co-authored-by: Arnei <arnewilken@yahoo.de>
1 parent 8986b74 commit db76a11

4 files changed

Lines changed: 117 additions & 14 deletions

File tree

src/components/events/partials/ModalTabsAndPages/NewSourcePage.tsx

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,60 @@ const Schedule = <T extends {
370370
}) => {
371371
const { t } = useTranslation();
372372
const currentLanguage = getCurrentLanguageInformation();
373+
const getEndDateForSchedulingTime = () => {
374+
const {
375+
scheduleStartDate,
376+
scheduleStartHour,
377+
scheduleStartMinute,
378+
scheduleEndDate,
379+
scheduleEndHour,
380+
scheduleEndMinute,
381+
scheduleDurationHours,
382+
sourceMode,
383+
} = formik.values;
384+
385+
const durationHours = Number(scheduleDurationHours) || 0;
386+
387+
if (durationHours === 0) {
388+
return undefined;
389+
}
390+
391+
const startDateTime = new Date(scheduleStartDate);
392+
startDateTime.setHours(
393+
parseInt(scheduleStartHour, 10),
394+
parseInt(scheduleStartMinute, 10),
395+
0,
396+
0,
397+
);
398+
399+
let endDateTime: Date;
400+
401+
if (sourceMode === "SCHEDULE_MULTIPLE") {
402+
endDateTime = new Date(startDateTime);
403+
endDateTime.setHours(endDateTime.getHours() + durationHours);
404+
} else {
405+
if (!scheduleEndDate) {
406+
return undefined;
407+
}
408+
endDateTime = new Date(scheduleEndDate);
409+
endDateTime.setHours(
410+
parseInt(scheduleEndHour, 10),
411+
parseInt(scheduleEndMinute, 10),
412+
0,
413+
0,
414+
);
415+
}
416+
417+
if (
418+
endDateTime.getDate() !== startDateTime.getDate() ||
419+
endDateTime.getMonth() !== startDateTime.getMonth() ||
420+
endDateTime.getFullYear() !== startDateTime.getFullYear()
421+
) {
422+
return "+1 day";
423+
}
424+
return undefined;
425+
};
426+
373427

374428
const renderInputDeviceOptions = () => {
375429
if (formik.values.location) {
@@ -606,13 +660,7 @@ const Schedule = <T extends {
606660
);
607661
}
608662
}}
609-
date={
610-
formik.values.sourceMode === "SCHEDULE_SINGLE" &&
611-
(new Date(formik.values.scheduleEndDate).getDate() !==
612-
new Date(formik.values.scheduleStartDate).getDate())
613-
? formik.values.scheduleEndDate
614-
: undefined
615-
}
663+
date={getEndDateForSchedulingTime()}
616664
/>
617665

618666
<SchedulingLocation

src/components/events/partials/wizards/scheduling/SchedulingTime.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,20 @@ const SchedulingTime = ({
6969
disabled={disabled}
7070
customCSS={{ width: 70 }}
7171
/>
72-
7372
{/* Displays given date. Can be used to signify which date the
7473
scheduling time belong to*/}
75-
{date &&
74+
{date && (
7675
<span style={{ marginLeft: "10px" }}>
77-
{new Date(date).toLocaleDateString(
78-
currentLanguage ? currentLanguage.dateLocale.code : undefined,
79-
)}
76+
{typeof date === "string"
77+
? date // show the string as it is
78+
: date instanceof Date && !isNaN(date.getDate())
79+
? new Date(date).toLocaleDateString(
80+
currentLanguage ? currentLanguage.dateLocale.code : undefined,
81+
)
82+
: null
83+
}
8084
</span>
81-
}
85+
)}
8286
</td>
8387
</tr>
8488
);

src/i18n/org/opencastproject/adminui/languages/lang-en_US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@
211211
"CONFLICT_ALREADY_ENDED": "Scheduling error: The event has already ended.",
212212
"CONFLICT_END_BEFORE_START": "Scheduling error: Schedule end has to be later than the start.",
213213
"CONFLICT_IN_THE_PAST": "The schedule could not be updated: You cannot schedule an event to be in the past.",
214+
"CONFLICT_RANGE_DAYS":"At least one repeat day must be within the scheduled date range.",
214215
"INVALID_ACL_RULES": "Rules have to contain a valid role and read or/and write right(s).",
215216
"MISSING_ACL_RULES": "At least one role with Read and Write permissions is required!",
216217
"SAVED_ACL_RULES": "The access rules have been saved.",

src/slices/eventSlice.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,20 @@ export const checkConflicts = (values: {
910910
values.sourceMode === "SCHEDULE_SINGLE" ||
911911
values.sourceMode === "SCHEDULE_MULTIPLE"
912912
) {
913+
if (values.sourceMode === "SCHEDULE_MULTIPLE") {
914+
const isRepeatOnValid = validateRepeatOnInRange(values);
915+
if (!isRepeatOnValid) {
916+
dispatch(
917+
addNotification({
918+
type: "error",
919+
key: "CONFLICT_RANGE_DAYS",
920+
duration: -1,
921+
context: NOTIFICATION_CONTEXT,
922+
}),
923+
);
924+
return false; // Exit early if repeatOn is invalid
925+
}
926+
}
913927
// Get timezone offset; Checks should be performed on UTC times
914928
// let offset = getTimezoneOffset();
915929

@@ -924,7 +938,7 @@ export const checkConflicts = (values: {
924938
);
925939

926940
// If start date of event is smaller than today --> Event is in past
927-
if (values.sourceMode === "SCHEDULE_SINGLE" && startDate < new Date()) {
941+
if ((values.sourceMode === "SCHEDULE_SINGLE" && startDate < new Date()) || (values.sourceMode === "SCHEDULE_MULTIPLE" && startDate < new Date())) {
928942
dispatch(
929943
addNotification({
930944
type: "error",
@@ -1107,6 +1121,42 @@ export const checkForSchedulingConflicts = (events: EditedEvents[]) => (dispatch
11071121
return data;
11081122
};
11091123

1124+
export const validateRepeatOnInRange = (values: {
1125+
repeatOn: string[], // e.g. ["MO", "TU"]
1126+
scheduleStartDate: string, // e.g. "2025-08-11"
1127+
scheduleEndDate: string // e.g. "2025-08-13"
1128+
}) => {
1129+
if (!values.repeatOn || values.repeatOn.length === 0) {
1130+
return true;
1131+
}
1132+
1133+
const start = new Date(values.scheduleStartDate);
1134+
const end = new Date(values.scheduleEndDate);
1135+
1136+
// Map day codes to numbers: Sunday=0, Monday=1, ..., Saturday=6
1137+
const dayMap: Record<string, number> = {
1138+
SU: 0,
1139+
MO: 1,
1140+
TU: 2,
1141+
WE: 3,
1142+
TH: 4,
1143+
FR: 5,
1144+
SA: 6,
1145+
};
1146+
const repeatDays = values.repeatOn.map(day => dayMap[day]);
1147+
// Check if **at least one** date in the [start..end] range matches repeatOn days
1148+
const current = new Date(start);
1149+
while (current <= end) {
1150+
if (repeatDays.includes(current.getDay())) {
1151+
return true; // Valid because this repeat day is in range
1152+
}
1153+
current.setDate(current.getDate() + 1); // next day
1154+
}
1155+
1156+
// If no repeat days fall within the range, return false
1157+
return false;
1158+
};
1159+
11101160
const eventSlice = createSlice({
11111161
name: "events",
11121162
initialState,

0 commit comments

Comments
 (0)