|
Lines 922-927
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 922 |
); |
922 |
); |
| 923 |
} |
923 |
} |
| 924 |
|
924 |
|
|
|
925 |
// Create feedback message container below the calendar |
| 926 |
let feedbackDiv = periodPicker.calendarContainer.querySelector( |
| 927 |
".booking-conflict-feedback" |
| 928 |
); |
| 929 |
if (!feedbackDiv) { |
| 930 |
feedbackDiv = document.createElement("div"); |
| 931 |
feedbackDiv.className = |
| 932 |
"booking-conflict-feedback alert d-none"; |
| 933 |
periodPicker.calendarContainer.appendChild(feedbackDiv); |
| 934 |
} |
| 935 |
|
| 925 |
// Add hints for days before the start range and after the end range |
936 |
// Add hints for days before the start range and after the end range |
| 926 |
periodPicker.calendarContainer.addEventListener( |
937 |
periodPicker.calendarContainer.addEventListener( |
| 927 |
"mouseover", |
938 |
"mouseover", |
|
Lines 941-949
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 941 |
const leadStart = startDate |
952 |
const leadStart = startDate |
| 942 |
? startDate.subtract(leadDays, "day") |
953 |
? startDate.subtract(leadDays, "day") |
| 943 |
: hoverDate.subtract(leadDays, "day"); |
954 |
: hoverDate.subtract(leadDays, "day"); |
| 944 |
const leadEnd = startDate ? startDate : hoverDate; |
955 |
const leadEnd = startDate |
| 945 |
const trailStart = hoverDate; |
956 |
? startDate.subtract(1, "day") |
| 946 |
const trailEnd = hoverDate.add(trailDays, "day"); |
957 |
: hoverDate.subtract(1, "day"); |
|
|
958 |
const trailStart = startDate |
| 959 |
? hoverDate.add(1, "day") |
| 960 |
: hoverDate.add(1, "day"); |
| 961 |
const trailEnd = startDate |
| 962 |
? hoverDate.add(trailDays, "day") |
| 963 |
: hoverDate.add(trailDays, "day"); |
| 947 |
|
964 |
|
| 948 |
// BIDIRECTIONAL ENHANCEMENT: Collect closest bookings for visual feedback |
965 |
// BIDIRECTIONAL ENHANCEMENT: Collect closest bookings for visual feedback |
| 949 |
// and check for mathematical conflicts in a single pass |
966 |
// and check for mathematical conflicts in a single pass |
|
Lines 956-961
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 956 |
let leadDisable = false; |
973 |
let leadDisable = false; |
| 957 |
let trailDisable = false; |
974 |
let trailDisable = false; |
| 958 |
|
975 |
|
|
|
976 |
// Track conflict reasons for messaging |
| 977 |
let leadConflictReason = { |
| 978 |
withTrail: false, |
| 979 |
withLead: false, |
| 980 |
withBooking: false, |
| 981 |
}; |
| 982 |
let trailConflictReason = { |
| 983 |
withTrail: false, |
| 984 |
withLead: false, |
| 985 |
withBooking: false, |
| 986 |
}; |
| 987 |
|
| 959 |
bookings.forEach(booking => { |
988 |
bookings.forEach(booking => { |
| 960 |
// Skip if we're editing this booking |
989 |
// Skip if we're editing this booking |
| 961 |
if ( |
990 |
if ( |
|
Lines 1000-1007
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1000 |
"day" |
1029 |
"day" |
| 1001 |
); |
1030 |
); |
| 1002 |
|
1031 |
|
| 1003 |
// Check if new booking's LEAD period overlaps with existing booking's TRAIL period |
1032 |
// Check if new booking's LEAD period overlaps with existing booking |
| 1004 |
if (!periodPicker.selectedDates[0]) { |
1033 |
if (!periodPicker.selectedDates[0]) { |
|
|
1034 |
// Check overlap with existing booking's trail period |
| 1005 |
if ( |
1035 |
if ( |
| 1006 |
leadStart.isSameOrBefore( |
1036 |
leadStart.isSameOrBefore( |
| 1007 |
existingTrailEnd |
1037 |
existingTrailEnd |
|
Lines 1011-1021
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1011 |
) |
1041 |
) |
| 1012 |
) { |
1042 |
) { |
| 1013 |
leadDisable = true; |
1043 |
leadDisable = true; |
|
|
1044 |
leadConflictReason.withTrail = true; |
| 1045 |
} |
| 1046 |
// Check overlap with existing booking's lead period |
| 1047 |
else if ( |
| 1048 |
leadStart.isSameOrBefore( |
| 1049 |
existingLeadEnd |
| 1050 |
) && |
| 1051 |
leadEnd.isSameOrAfter(existingLeadStart) |
| 1052 |
) { |
| 1053 |
leadDisable = true; |
| 1054 |
leadConflictReason.withLead = true; |
| 1055 |
} |
| 1056 |
// Check overlap with existing booking itself |
| 1057 |
else if ( |
| 1058 |
leadStart.isSameOrBefore(bookingEnd) && |
| 1059 |
leadEnd.isSameOrAfter(bookingStart) |
| 1060 |
) { |
| 1061 |
leadDisable = true; |
| 1062 |
leadConflictReason.withBooking = true; |
| 1014 |
} |
1063 |
} |
| 1015 |
} |
1064 |
} |
| 1016 |
|
1065 |
|
| 1017 |
// Check if new booking's TRAIL period overlaps with existing booking's LEAD period |
1066 |
// Check if new booking's TRAIL period overlaps with existing booking |
| 1018 |
if (periodPicker.selectedDates[0]) { |
1067 |
if (periodPicker.selectedDates[0]) { |
|
|
1068 |
// Check overlap with existing booking's lead period |
| 1019 |
if ( |
1069 |
if ( |
| 1020 |
trailStart.isSameOrBefore( |
1070 |
trailStart.isSameOrBefore( |
| 1021 |
existingLeadEnd |
1071 |
existingLeadEnd |
|
Lines 1025-1030
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1025 |
) |
1075 |
) |
| 1026 |
) { |
1076 |
) { |
| 1027 |
trailDisable = true; |
1077 |
trailDisable = true; |
|
|
1078 |
trailConflictReason.withLead = true; |
| 1079 |
} |
| 1080 |
// Check overlap with existing booking's trail period |
| 1081 |
else if ( |
| 1082 |
trailStart.isSameOrBefore( |
| 1083 |
existingTrailEnd |
| 1084 |
) && |
| 1085 |
trailEnd.isSameOrAfter( |
| 1086 |
existingTrailStart |
| 1087 |
) |
| 1088 |
) { |
| 1089 |
trailDisable = true; |
| 1090 |
trailConflictReason.withTrail = true; |
| 1091 |
} |
| 1092 |
// Check overlap with existing booking itself |
| 1093 |
else if ( |
| 1094 |
trailStart.isSameOrBefore(bookingEnd) && |
| 1095 |
trailEnd.isSameOrAfter(bookingStart) |
| 1096 |
) { |
| 1097 |
trailDisable = true; |
| 1098 |
trailConflictReason.withBooking = true; |
| 1028 |
} |
1099 |
} |
| 1029 |
} |
1100 |
} |
| 1030 |
|
1101 |
|
|
Lines 1058-1063
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1058 |
} |
1129 |
} |
| 1059 |
}); |
1130 |
}); |
| 1060 |
|
1131 |
|
|
|
1132 |
// Work through all days in view and add classes appropraitely based on hovered date |
| 1061 |
periodPicker.calendarContainer |
1133 |
periodPicker.calendarContainer |
| 1062 |
.querySelectorAll(".flatpickr-day") |
1134 |
.querySelectorAll(".flatpickr-day") |
| 1063 |
.forEach(function (dayElem) { |
1135 |
.forEach(function (dayElem) { |
|
Lines 1085-1119
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1085 |
"existingBookingTrailEnd" |
1157 |
"existingBookingTrailEnd" |
| 1086 |
); |
1158 |
); |
| 1087 |
|
1159 |
|
| 1088 |
// Apply new booking's lead/trail period classes |
1160 |
// Apply proposed booking's lead/trail period classes |
| 1089 |
dayElem.classList.toggle( |
1161 |
// Only apply lead classes if lead period > 0 |
| 1090 |
"leadRangeStart", |
1162 |
if (leadDays > 0) { |
| 1091 |
elemDate.isSame(leadStart) |
1163 |
dayElem.classList.toggle( |
| 1092 |
); |
1164 |
"leadRangeStart", |
| 1093 |
dayElem.classList.toggle( |
1165 |
elemDate.isSame(leadStart) |
| 1094 |
"leadRange", |
1166 |
); |
| 1095 |
elemDate.isSameOrAfter(leadStart) && |
1167 |
dayElem.classList.toggle( |
| 1096 |
elemDate.isBefore(leadEnd) |
1168 |
"leadRange", |
| 1097 |
); |
1169 |
elemDate.isSameOrAfter(leadStart) && |
| 1098 |
dayElem.classList.toggle( |
1170 |
elemDate.isSameOrBefore(leadEnd) |
| 1099 |
"leadRangeEnd", |
1171 |
); |
| 1100 |
elemDate.isSame(leadEnd) |
1172 |
dayElem.classList.toggle( |
| 1101 |
); |
1173 |
"leadRangeEnd", |
| 1102 |
dayElem.classList.toggle( |
1174 |
elemDate.isSame(leadEnd) |
| 1103 |
"trailRangeStart", |
1175 |
); |
| 1104 |
elemDate.isSame(trailStart) |
1176 |
} |
| 1105 |
); |
|
|
| 1106 |
dayElem.classList.toggle( |
| 1107 |
"trailRange", |
| 1108 |
elemDate.isAfter(trailStart) && |
| 1109 |
elemDate.isSameOrBefore(trailEnd) |
| 1110 |
); |
| 1111 |
dayElem.classList.toggle( |
| 1112 |
"trailRangeEnd", |
| 1113 |
elemDate.isSame(trailEnd) |
| 1114 |
); |
| 1115 |
|
1177 |
|
| 1116 |
// BIDIRECTIONAL: Show closest existing booking's trail period |
1178 |
// Only apply trail classes if trail period > 0 |
|
|
1179 |
if (trailDays > 0) { |
| 1180 |
dayElem.classList.toggle( |
| 1181 |
"trailRangeStart", |
| 1182 |
elemDate.isSame(trailStart) |
| 1183 |
); |
| 1184 |
dayElem.classList.toggle( |
| 1185 |
"trailRange", |
| 1186 |
elemDate.isSameOrAfter( |
| 1187 |
trailStart |
| 1188 |
) && |
| 1189 |
elemDate.isSameOrBefore( |
| 1190 |
trailEnd |
| 1191 |
) |
| 1192 |
); |
| 1193 |
dayElem.classList.toggle( |
| 1194 |
"trailRangeEnd", |
| 1195 |
elemDate.isSame(trailEnd) |
| 1196 |
); |
| 1197 |
} |
| 1198 |
|
| 1199 |
// Show closest preceding existing booking's trail period |
| 1117 |
if (closestBeforeBooking && trailDays > 0) { |
1200 |
if (closestBeforeBooking && trailDays > 0) { |
| 1118 |
const existingTrailStart = |
1201 |
const existingTrailStart = |
| 1119 |
closestBeforeBooking.end.add( |
1202 |
closestBeforeBooking.end.add( |
|
Lines 1159-1165
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1159 |
} |
1242 |
} |
| 1160 |
} |
1243 |
} |
| 1161 |
|
1244 |
|
| 1162 |
// BIDIRECTIONAL: Show closest existing booking's lead period |
1245 |
// Show closest following existing booking's lead period |
| 1163 |
if (closestAfterBooking && leadDays > 0) { |
1246 |
if (closestAfterBooking && leadDays > 0) { |
| 1164 |
const existingLeadStart = |
1247 |
const existingLeadStart = |
| 1165 |
closestAfterBooking.start.subtract( |
1248 |
closestAfterBooking.start.subtract( |
|
Lines 1203-1209
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1203 |
} |
1286 |
} |
| 1204 |
} |
1287 |
} |
| 1205 |
|
1288 |
|
| 1206 |
// Check for conflicts with flatpickr-disabled dates (original behavior) |
1289 |
// Check for conflicts with flatpickr-disabled dates |
| 1207 |
if ( |
1290 |
if ( |
| 1208 |
dayElem.classList.contains( |
1291 |
dayElem.classList.contains( |
| 1209 |
"flatpickr-disabled" |
1292 |
"flatpickr-disabled" |
|
Lines 1212-1223
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1212 |
if ( |
1295 |
if ( |
| 1213 |
!periodPicker.selectedDates[0] && |
1296 |
!periodPicker.selectedDates[0] && |
| 1214 |
elemDate.isSameOrAfter(leadStart) && |
1297 |
elemDate.isSameOrAfter(leadStart) && |
| 1215 |
elemDate.isBefore(leadEnd) |
1298 |
elemDate.isSameOrBefore(leadEnd) |
| 1216 |
) { |
1299 |
) { |
| 1217 |
leadDisable = true; |
1300 |
leadDisable = true; |
| 1218 |
} |
1301 |
} |
| 1219 |
if ( |
1302 |
if ( |
| 1220 |
elemDate.isAfter(trailStart) && |
1303 |
periodPicker.selectedDates[0] && |
|
|
1304 |
elemDate.isSameOrAfter( |
| 1305 |
trailStart |
| 1306 |
) && |
| 1221 |
elemDate.isSameOrBefore(trailEnd) |
1307 |
elemDate.isSameOrBefore(trailEnd) |
| 1222 |
) { |
1308 |
) { |
| 1223 |
// Only consider this a conflict if the disabled date is within the max date range |
1309 |
// Only consider this a conflict if the disabled date is within the max date range |
|
Lines 1238-1244
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1238 |
} |
1324 |
} |
| 1239 |
} |
1325 |
} |
| 1240 |
|
1326 |
|
| 1241 |
// BIDIRECTIONAL: Check for conflicts with existing booking's trail period |
1327 |
// Check for conflicts with existing booking's trail period |
| 1242 |
if ( |
1328 |
if ( |
| 1243 |
!periodPicker.selectedDates[0] && |
1329 |
!periodPicker.selectedDates[0] && |
| 1244 |
dayElem.classList.contains( |
1330 |
dayElem.classList.contains( |
|
Lines 1248-1268
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1248 |
// New booking's lead period overlaps with existing booking's trail |
1334 |
// New booking's lead period overlaps with existing booking's trail |
| 1249 |
if ( |
1335 |
if ( |
| 1250 |
elemDate.isSameOrAfter(leadStart) && |
1336 |
elemDate.isSameOrAfter(leadStart) && |
| 1251 |
elemDate.isBefore(leadEnd) |
1337 |
elemDate.isSameOrBefore(leadEnd) |
| 1252 |
) { |
1338 |
) { |
| 1253 |
leadDisable = true; |
1339 |
leadDisable = true; |
| 1254 |
} |
1340 |
} |
| 1255 |
} |
1341 |
} |
| 1256 |
|
1342 |
|
| 1257 |
// BIDIRECTIONAL: Check for conflicts with existing booking's lead period |
1343 |
// Check for conflicts with existing booking's lead period |
| 1258 |
if ( |
1344 |
if ( |
|
|
1345 |
periodPicker.selectedDates[0] && |
| 1259 |
dayElem.classList.contains( |
1346 |
dayElem.classList.contains( |
| 1260 |
"existingBookingLead" |
1347 |
"existingBookingLead" |
| 1261 |
) |
1348 |
) |
| 1262 |
) { |
1349 |
) { |
| 1263 |
// New booking's trail period overlaps with existing booking's lead |
1350 |
// New booking's trail period overlaps with existing booking's lead |
| 1264 |
if ( |
1351 |
if ( |
| 1265 |
elemDate.isAfter(trailStart) && |
1352 |
elemDate.isSameOrAfter( |
|
|
1353 |
trailStart |
| 1354 |
) && |
| 1266 |
elemDate.isSameOrBefore(trailEnd) |
1355 |
elemDate.isSameOrBefore(trailEnd) |
| 1267 |
) { |
1356 |
) { |
| 1268 |
trailDisable = true; |
1357 |
trailDisable = true; |
|
Lines 1278-1283
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1278 |
); |
1367 |
); |
| 1279 |
}); |
1368 |
}); |
| 1280 |
|
1369 |
|
|
|
1370 |
// Additional check for hovering directly on existing booking's lead/trail periods |
| 1371 |
// If hovering on an existing booking's lead period when selecting start date, block selection |
| 1372 |
if ( |
| 1373 |
!periodPicker.selectedDates[0] && |
| 1374 |
target.classList.contains("existingBookingLead") |
| 1375 |
) { |
| 1376 |
leadDisable = true; |
| 1377 |
} |
| 1378 |
|
| 1379 |
// If hovering on an existing booking's trail period when selecting end date, block selection |
| 1380 |
if ( |
| 1381 |
periodPicker.selectedDates[0] && |
| 1382 |
target.classList.contains( |
| 1383 |
"existingBookingTrail" |
| 1384 |
) |
| 1385 |
) { |
| 1386 |
trailDisable = true; |
| 1387 |
} |
| 1388 |
|
| 1281 |
if (leadDisable) { |
1389 |
if (leadDisable) { |
| 1282 |
target.classList.add("leadDisable"); |
1390 |
target.classList.add("leadDisable"); |
| 1283 |
} |
1391 |
} |
|
Lines 1291-1296
$("#placeBookingModal").on("show.bs.modal", function (e) {
Link Here
|
| 1291 |
true |
1399 |
true |
| 1292 |
); |
1400 |
); |
| 1293 |
} |
1401 |
} |
|
|
1402 |
|
| 1403 |
// Update feedback message |
| 1404 |
const feedbackDiv = |
| 1405 |
periodPicker.calendarContainer.querySelector( |
| 1406 |
".booking-conflict-feedback" |
| 1407 |
); |
| 1408 |
if (feedbackDiv) { |
| 1409 |
let message = ""; |
| 1410 |
let messageType = "info"; // info, warning, error |
| 1411 |
|
| 1412 |
// Determine what the hovered date is (needed for both error and info messages) |
| 1413 |
const today = dayjs().startOf("day"); |
| 1414 |
const isDisabled = |
| 1415 |
target.classList.contains( |
| 1416 |
"flatpickr-disabled" |
| 1417 |
); |
| 1418 |
const isInExistingLead = |
| 1419 |
target.classList.contains( |
| 1420 |
"existingBookingLead" |
| 1421 |
); |
| 1422 |
const isInExistingTrail = |
| 1423 |
target.classList.contains( |
| 1424 |
"existingBookingTrail" |
| 1425 |
); |
| 1426 |
|
| 1427 |
// Generate appropriate feedback messages based on conflicts |
| 1428 |
if (leadDisable || trailDisable) { |
| 1429 |
messageType = "error"; |
| 1430 |
|
| 1431 |
// When selecting START date (no date selected yet) |
| 1432 |
if (!periodPicker.selectedDates[0]) { |
| 1433 |
// Check direct state first (what IS this date?) |
| 1434 |
if (hoverDate.isBefore(today)) { |
| 1435 |
message = __( |
| 1436 |
"Cannot select: date is in the past" |
| 1437 |
); |
| 1438 |
} else if (isDisabled) { |
| 1439 |
message = __( |
| 1440 |
"Cannot select: this date is part of an existing booking" |
| 1441 |
); |
| 1442 |
} else if (isInExistingLead) { |
| 1443 |
message = __( |
| 1444 |
"Cannot select: this date is part of an existing booking's lead period" |
| 1445 |
); |
| 1446 |
} else if (isInExistingTrail) { |
| 1447 |
message = __( |
| 1448 |
"Cannot select: this date is part of an existing booking's trail period" |
| 1449 |
); |
| 1450 |
} |
| 1451 |
// Then check calculated lead period conflicts |
| 1452 |
else if ( |
| 1453 |
leadDays > 0 && |
| 1454 |
leadStart.isSameOrBefore(today) |
| 1455 |
) { |
| 1456 |
message = |
| 1457 |
__("Cannot select") + |
| 1458 |
": " + |
| 1459 |
__( |
| 1460 |
"insufficient lead time (%s days required before start)" |
| 1461 |
).format(leadDays); |
| 1462 |
} else if (leadDays > 0) { |
| 1463 |
// Use mathematical conflict detection (works across month boundaries) |
| 1464 |
if (leadConflictReason.withTrail) { |
| 1465 |
message = |
| 1466 |
__("Cannot select") + |
| 1467 |
": " + |
| 1468 |
__( |
| 1469 |
"lead period (%s days before start) conflicts with an existing booking's trail period" |
| 1470 |
).format(leadDays); |
| 1471 |
} else if ( |
| 1472 |
leadConflictReason.withLead |
| 1473 |
) { |
| 1474 |
message = |
| 1475 |
__("Cannot select") + |
| 1476 |
": " + |
| 1477 |
__( |
| 1478 |
"lead period (%s days before start) conflicts with an existing booking's lead period" |
| 1479 |
).format(leadDays); |
| 1480 |
} else if ( |
| 1481 |
leadConflictReason.withBooking |
| 1482 |
) { |
| 1483 |
message = |
| 1484 |
__("Cannot select") + |
| 1485 |
": " + |
| 1486 |
__( |
| 1487 |
"lead period (%s days before start) conflicts with an existing booking" |
| 1488 |
).format(leadDays); |
| 1489 |
} |
| 1490 |
} else { |
| 1491 |
message = __( |
| 1492 |
"Cannot select: conflicts with an existing booking" |
| 1493 |
); |
| 1494 |
} |
| 1495 |
} |
| 1496 |
// When selecting END date (start date already selected) |
| 1497 |
else if (periodPicker.selectedDates[0]) { |
| 1498 |
// Check direct state first (what IS this date?) |
| 1499 |
if (isDisabled) { |
| 1500 |
message = __( |
| 1501 |
"Cannot select: this date is part of an existing booking" |
| 1502 |
); |
| 1503 |
} else if (isInExistingLead) { |
| 1504 |
message = __( |
| 1505 |
"Cannot select: this date is part of an existing booking's lead period" |
| 1506 |
); |
| 1507 |
} else if (isInExistingTrail) { |
| 1508 |
message = __( |
| 1509 |
"Cannot select: this date is part of an existing booking's trail period" |
| 1510 |
); |
| 1511 |
} |
| 1512 |
// Then check calculated trail period conflicts |
| 1513 |
else if (trailDays > 0) { |
| 1514 |
// Use mathematical conflict detection (works across month boundaries) |
| 1515 |
if (trailConflictReason.withLead) { |
| 1516 |
message = |
| 1517 |
__("Cannot select") + |
| 1518 |
": " + |
| 1519 |
__( |
| 1520 |
"trail period (%s days after return) conflicts with an existing booking's lead period" |
| 1521 |
).format(trailDays); |
| 1522 |
} else if ( |
| 1523 |
trailConflictReason.withTrail |
| 1524 |
) { |
| 1525 |
message = |
| 1526 |
__("Cannot select") + |
| 1527 |
": " + |
| 1528 |
__( |
| 1529 |
"trail period (%s days after return) conflicts with an existing booking's trail period" |
| 1530 |
).format(trailDays); |
| 1531 |
} else if ( |
| 1532 |
trailConflictReason.withBooking |
| 1533 |
) { |
| 1534 |
message = |
| 1535 |
__("Cannot select") + |
| 1536 |
": " + |
| 1537 |
__( |
| 1538 |
"trail period (%s days after return) conflicts with an existing booking" |
| 1539 |
).format(trailDays); |
| 1540 |
} |
| 1541 |
} else { |
| 1542 |
message = __( |
| 1543 |
"Cannot select: conflicts with existing an booking" |
| 1544 |
); |
| 1545 |
} |
| 1546 |
} |
| 1547 |
} else { |
| 1548 |
// Show helpful info messages when no conflicts |
| 1549 |
if (!periodPicker.selectedDates[0]) { |
| 1550 |
// When selecting start date, show both lead and trail info |
| 1551 |
if (leadDays > 0 && trailDays > 0) { |
| 1552 |
message = |
| 1553 |
__("Selecting start date") + |
| 1554 |
". " + |
| 1555 |
__( |
| 1556 |
"Lead period: %s days before start" |
| 1557 |
).format(leadDays) + |
| 1558 |
". " + |
| 1559 |
__( |
| 1560 |
"Trail period: %s days after return" |
| 1561 |
).format(trailDays); |
| 1562 |
} else if (leadDays > 0) { |
| 1563 |
message = |
| 1564 |
__("Selecting start date") + |
| 1565 |
". " + |
| 1566 |
__( |
| 1567 |
"Lead period: %s days before start" |
| 1568 |
).format(leadDays); |
| 1569 |
} else if (trailDays > 0) { |
| 1570 |
message = |
| 1571 |
__("Selecting start date") + |
| 1572 |
". " + |
| 1573 |
__( |
| 1574 |
"Trail period: %s days after return" |
| 1575 |
).format(trailDays); |
| 1576 |
} else { |
| 1577 |
message = __( |
| 1578 |
"Selecting start date" |
| 1579 |
); |
| 1580 |
} |
| 1581 |
messageType = "info"; |
| 1582 |
} else { |
| 1583 |
if (trailDays > 0) { |
| 1584 |
message = |
| 1585 |
__("Selecting end date") + |
| 1586 |
". " + |
| 1587 |
__( |
| 1588 |
"Trail period: %s days after return" |
| 1589 |
).format(trailDays); |
| 1590 |
} else { |
| 1591 |
message = __("Selecting end date"); |
| 1592 |
} |
| 1593 |
messageType = "info"; |
| 1594 |
} |
| 1595 |
|
| 1596 |
// Show additional context if hovering over existing booking periods |
| 1597 |
if (isInExistingLead) { |
| 1598 |
message += |
| 1599 |
" • " + |
| 1600 |
__( |
| 1601 |
"hovering existing booking's lead period" |
| 1602 |
); |
| 1603 |
} else if (isInExistingTrail) { |
| 1604 |
message += |
| 1605 |
" • " + |
| 1606 |
__( |
| 1607 |
"hovering existing booking's trail period" |
| 1608 |
); |
| 1609 |
} |
| 1610 |
} |
| 1611 |
|
| 1612 |
feedbackDiv.textContent = message; |
| 1613 |
feedbackDiv.classList.remove( |
| 1614 |
"alert-danger", |
| 1615 |
"alert-warning", |
| 1616 |
"alert-info" |
| 1617 |
); |
| 1618 |
|
| 1619 |
if (message) { |
| 1620 |
feedbackDiv.classList.remove("d-none"); |
| 1621 |
// Apply appropriate Bootstrap alert class based on message type |
| 1622 |
if (messageType === "error") { |
| 1623 |
feedbackDiv.classList.add( |
| 1624 |
"alert-danger" |
| 1625 |
); |
| 1626 |
} else if (messageType === "warning") { |
| 1627 |
feedbackDiv.classList.add( |
| 1628 |
"alert-warning" |
| 1629 |
); |
| 1630 |
} else { |
| 1631 |
feedbackDiv.classList.add("alert-info"); |
| 1632 |
} |
| 1633 |
} else { |
| 1634 |
feedbackDiv.classList.add("d-none"); |
| 1635 |
} |
| 1636 |
} |
| 1294 |
} |
1637 |
} |
| 1295 |
} |
1638 |
} |
| 1296 |
); |
1639 |
); |
| 1297 |
- |
|
|