@codecademy/gamut

72.5.172.5.2-alpha.733b32.0
dist/DatePicker/DatePickerInput/utils/validation.js
+dist/DatePicker/DatePickerInput/utils/validation.jsNew file
+106
Index: package/dist/DatePicker/DatePickerInput/utils/validation.js
===================================================================
--- package/dist/DatePicker/DatePickerInput/utils/validation.js
+++ package/dist/DatePicker/DatePickerInput/utils/validation.js
@@ -0,0 +1,106 @@
+import { rangeContainsDisabled } from '../../DatePickerCalendar/utils/dateSelect';
+import { parseSegmentsToDate } from '../Segment/utils';
+const detectValidationIssue = segments => {
+  const {
+    month,
+    day,
+    year
+  } = segments;
+  const monthNumber = parseInt(month, 10);
+  const dayNumber = parseInt(day, 10);
+  const yearNumber = parseInt(year, 10);
+  if (monthNumber < 1 || monthNumber > 12) return 'invalid-month';
+  const parsed = new Date(yearNumber, monthNumber - 1, dayNumber);
+  if (parsed.getFullYear() !== yearNumber || parsed.getMonth() !== monthNumber - 1) {
+    return 'date-rollover';
+  }
+  if (parsed.getDate() !== dayNumber) {
+    return 'invalid-day';
+  }
+  return null;
+};
+export const generateErrorMessage = (reason, segments, translations) => {
+  const {
+    month,
+    day
+  } = segments;
+  const monthNumber = parseInt(month, 10);
+  switch (reason) {
+    case 'incomplete':
+      return translations.invalidDateIncomplete;
+    case 'invalid-month':
+      return translations.invalidDateInvalidMonth;
+    case 'invalid-day':
+    case 'date-rollover':
+      {
+        const monthName = new Date(2024, monthNumber - 1, 1).toLocaleString('en-US', {
+          month: 'long'
+        });
+        const message = reason === 'invalid-day' ? translations.invalidDateInvalidDay : translations.invalidDateRollover;
+        return message.replace('{{month}}', monthName).replace('{{day}}', day);
+      }
+    case 'disabled-date':
+      return translations.invalidDateNotAvailable;
+    case 'range-contains-disabled-date':
+      return translations.invalidDateRangeContainsDisabledDate;
+    case 'invalid-date':
+    default:
+      return translations.invalidDate;
+  }
+};
+export const validateSegments = (segments, translations, disableDate) => {
+  const {
+    month,
+    day,
+    year
+  } = segments;
+  const hasCompleteYear = year.length === 4;
+  const hasMonthAndDay = month.length > 0 && day.length > 0;
+  if (!hasCompleteYear || !hasMonthAndDay) {
+    return {
+      isValid: false,
+      errorMessage: '',
+      reason: 'incomplete'
+    };
+  }
+  const parsed = parseSegmentsToDate(segments);
+  if (parsed) {
+    if (disableDate?.(parsed)) {
+      return {
+        isValid: false,
+        errorMessage: generateErrorMessage('disabled-date', segments, translations),
+        reason: 'disabled-date'
+      };
+    }
+    return {
+      isValid: true,
+      date: parsed
+    };
+  }
+  const reason = detectValidationIssue(segments) ?? 'invalid-date';
+  const errorMessage = generateErrorMessage(reason, segments, translations);
+  return {
+    isValid: false,
+    errorMessage,
+    reason
+  };
+};
+export const validateDateRange = (startDate, endDate, translations, disableDate) => {
+  if (!startDate || !endDate || !disableDate) return null;
+  if (rangeContainsDisabled({
+    startDate,
+    endDate,
+    disableDate
+  })) {
+    return {
+      isValid: false,
+      errorMessage: generateErrorMessage('range-contains-disabled-date', {
+        month: '',
+        day: '',
+        year: ''
+      }, translations),
+      reason: 'range-contains-disabled-date'
+    };
+  }
+  return null;
+};
\ No newline at end of file