2025-08-14 15:10:45 +00:00
|
|
|
import { parse, isValid } from "date-fns";
|
|
|
|
|
import { IRunScriptBatchModalScheduleFormData } from "./RunScriptBatchModal";
|
|
|
|
|
|
|
|
|
|
// TODO: create a validator abstraction for this and the other form validation files
|
|
|
|
|
|
|
|
|
|
export interface IRunScriptBatchModalFormValidation {
|
|
|
|
|
isValid: boolean;
|
|
|
|
|
date?: { isValid: boolean; message?: string };
|
|
|
|
|
time?: { isValid: boolean; message?: string };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type IMessageFunc = (formData: IRunScriptBatchModalScheduleFormData) => string;
|
|
|
|
|
type IValidationMessage = string | IMessageFunc;
|
|
|
|
|
type IFormValidationKey = keyof Omit<
|
|
|
|
|
IRunScriptBatchModalScheduleFormData,
|
|
|
|
|
"isValid"
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
interface IValidation {
|
|
|
|
|
name: string;
|
|
|
|
|
isValid: (
|
|
|
|
|
formData: IRunScriptBatchModalScheduleFormData,
|
|
|
|
|
validations?: IRunScriptBatchModalFormValidation
|
|
|
|
|
) => boolean;
|
|
|
|
|
message?: IValidationMessage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type IFormValidations = Record<
|
|
|
|
|
IFormValidationKey,
|
|
|
|
|
{ validations: IValidation[] }
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
const FORM_VALIDATIONS: IFormValidations = {
|
|
|
|
|
date: {
|
|
|
|
|
validations: [
|
|
|
|
|
{
|
|
|
|
|
name: "required",
|
|
|
|
|
isValid: (formData: IRunScriptBatchModalScheduleFormData) => {
|
|
|
|
|
return formData.date.length > 0;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "validDate",
|
|
|
|
|
isValid: (formData: IRunScriptBatchModalScheduleFormData) => {
|
|
|
|
|
if (!formData.date.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const parsedDate = parse(formData.date, "yyyy-MM-dd", new Date());
|
|
|
|
|
return isValid(parsedDate);
|
|
|
|
|
},
|
|
|
|
|
message: "Date (UTC) must have valid format",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "notInPast",
|
|
|
|
|
isValid: (formData: IRunScriptBatchModalScheduleFormData) => {
|
|
|
|
|
const now = new Date();
|
|
|
|
|
const parsedDate = parse(
|
|
|
|
|
`${formData.date} 23:59:59.999`,
|
|
|
|
|
"yyyy-MM-dd HH:mm:ss.SSS",
|
|
|
|
|
now
|
|
|
|
|
);
|
|
|
|
|
return parsedDate >= now;
|
|
|
|
|
},
|
|
|
|
|
message: `Date (UTC) cannot be in the past`,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
time: {
|
|
|
|
|
validations: [
|
|
|
|
|
{
|
|
|
|
|
name: "required",
|
|
|
|
|
isValid: (formData: IRunScriptBatchModalScheduleFormData) => {
|
|
|
|
|
return formData.time.length > 0;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "validTime",
|
|
|
|
|
isValid: (formData: IRunScriptBatchModalScheduleFormData) => {
|
|
|
|
|
if (!formData.time.match(/^\d{2}:\d{2}$/)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const parsedDate = parse(
|
|
|
|
|
`1982-10-13 ${formData.time}`,
|
|
|
|
|
"yyyy-MM-dd HH:mm",
|
|
|
|
|
new Date()
|
|
|
|
|
);
|
|
|
|
|
return isValid(parsedDate);
|
|
|
|
|
},
|
|
|
|
|
message: "Time (UTC) must have valid format",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "notInPast",
|
|
|
|
|
isValid: (
|
|
|
|
|
formData: IRunScriptBatchModalScheduleFormData,
|
|
|
|
|
validations?: IRunScriptBatchModalFormValidation
|
|
|
|
|
) => {
|
|
|
|
|
if (validations?.date?.isValid === false) {
|
|
|
|
|
return true; // If date is invalid, skip time validation
|
|
|
|
|
}
|
|
|
|
|
const parsedDate = parse(
|
2025-08-25 14:15:12 +00:00
|
|
|
`${formData.date} ${formData.time}:00.000Z`,
|
|
|
|
|
"yyyy-MM-dd HH:mm:ss.SSSX",
|
2025-08-14 15:10:45 +00:00
|
|
|
new Date()
|
|
|
|
|
);
|
|
|
|
|
return parsedDate >= new Date();
|
|
|
|
|
},
|
|
|
|
|
message: `Time (UTC) cannot be in the past`,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getErrorMessage = (
|
|
|
|
|
formData: IRunScriptBatchModalScheduleFormData,
|
|
|
|
|
message?: IValidationMessage
|
|
|
|
|
) => {
|
|
|
|
|
if (message === undefined || typeof message === "string") {
|
|
|
|
|
return message;
|
|
|
|
|
}
|
|
|
|
|
return message(formData);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const validateFormData = (
|
|
|
|
|
formData: IRunScriptBatchModalScheduleFormData,
|
|
|
|
|
runMode: "run_now" | "schedule" = "run_now"
|
|
|
|
|
) => {
|
|
|
|
|
const formValidation: IRunScriptBatchModalFormValidation = {
|
|
|
|
|
isValid: true,
|
|
|
|
|
};
|
|
|
|
|
if (runMode === "run_now") {
|
|
|
|
|
return formValidation; // No validation needed for run now
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Object.keys(FORM_VALIDATIONS).forEach((key) => {
|
|
|
|
|
const objKey = key as keyof typeof FORM_VALIDATIONS;
|
|
|
|
|
const failedValidation = FORM_VALIDATIONS[objKey].validations.find(
|
|
|
|
|
(validation) => !validation.isValid(formData, formValidation)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!failedValidation) {
|
|
|
|
|
formValidation[objKey] = {
|
|
|
|
|
isValid: true,
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
formValidation.isValid = false;
|
|
|
|
|
formValidation[objKey] = {
|
|
|
|
|
isValid: false,
|
|
|
|
|
message: getErrorMessage(formData, failedValidation.message),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return formValidation;
|
|
|
|
|
};
|