export const SCHEDULE_MODES = {
|
DAILY: 'DAILY',
|
WEEKLY: 'WEEKLY',
|
MONTHLY: 'MONTHLY',
|
};
|
|
export const WEEK_DAYS = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'];
|
export const MONTH_DAY_OPTIONS = Array.from({ length: 31 }, (_, idx) => idx + 1);
|
|
const DEFAULT_TIME = '10:00';
|
const pad = (value) => value.toString().padStart(2, '0');
|
|
const sanitizeWeekDays = (days) => {
|
if (!Array.isArray(days) || days.length === 0) {
|
return ['MON'];
|
}
|
const unique = [...new Set(days.filter((day) => WEEK_DAYS.includes(day)))];
|
return unique.length ? unique : ['MON'];
|
};
|
|
const sanitizeMonthDays = (days) => {
|
if (!Array.isArray(days) || days.length === 0) {
|
return [1];
|
}
|
const unique = [...new Set(days.map((day) => Number(day)).filter((day) => day >= 1 && day <= 31))];
|
return unique.length ? unique : [1];
|
};
|
|
const sanitizeTime = (time = DEFAULT_TIME) => {
|
if (typeof time !== 'string') {
|
return DEFAULT_TIME;
|
}
|
const [hour = '10', minute = '00'] = time.split(':');
|
const parsedHour = Math.min(23, Math.max(0, parseInt(hour, 10) || 0));
|
const parsedMinute = Math.min(59, Math.max(0, parseInt(minute, 10) || 0));
|
return `${pad(parsedHour)}:${pad(parsedMinute)}`;
|
};
|
|
export const DEFAULT_SCHEDULE_STATE = {
|
mode: SCHEDULE_MODES.DAILY,
|
time: DEFAULT_TIME,
|
weekDays: ['MON'],
|
monthDays: [1],
|
};
|
|
export const buildCronExpression = (state = DEFAULT_SCHEDULE_STATE) => {
|
const mode = state?.mode || SCHEDULE_MODES.DAILY;
|
const time = sanitizeTime(state?.time);
|
const [hour, minute] = time.split(':');
|
|
if (mode === SCHEDULE_MODES.WEEKLY) {
|
const days = sanitizeWeekDays(state?.weekDays).join(',');
|
return `0 ${minute} ${hour} ? * ${days}`;
|
}
|
|
if (mode === SCHEDULE_MODES.MONTHLY) {
|
const days = sanitizeMonthDays(state?.monthDays).sort((a, b) => a - b).join(',');
|
return `0 ${minute} ${hour} ${days} * ?`;
|
}
|
|
return `0 ${minute} ${hour} * * ?`;
|
};
|
|
export const DEFAULT_CRON_EXPRESSION = buildCronExpression(DEFAULT_SCHEDULE_STATE);
|
|
const createParsedState = () => ({
|
...DEFAULT_SCHEDULE_STATE,
|
valid: false,
|
});
|
|
export const parseCronExpression = (expr) => {
|
const state = createParsedState();
|
if (!expr || typeof expr !== 'string') {
|
return state;
|
}
|
const tokens = expr.trim().split(/\s+/);
|
if (tokens.length < 6) {
|
return state;
|
}
|
const [, minute, hour, dayOfMonth, , dayOfWeek] = tokens;
|
const time = sanitizeTime(`${hour}:${minute}`);
|
|
if (dayOfMonth === '*' && dayOfWeek === '?') {
|
return {
|
...state,
|
valid: true,
|
mode: SCHEDULE_MODES.DAILY,
|
time,
|
};
|
}
|
|
if (dayOfMonth === '?' && dayOfWeek && dayOfWeek !== '?') {
|
const weekDays = dayOfWeek.split(',').filter((day) => WEEK_DAYS.includes(day));
|
return {
|
...state,
|
valid: true,
|
mode: SCHEDULE_MODES.WEEKLY,
|
time,
|
weekDays: sanitizeWeekDays(weekDays),
|
};
|
}
|
|
if (dayOfMonth && dayOfMonth !== '*' && dayOfWeek === '?') {
|
const monthDays = dayOfMonth
|
.split(',')
|
.map((day) => parseInt(day, 10))
|
.filter((day) => !Number.isNaN(day));
|
return {
|
...state,
|
valid: true,
|
mode: SCHEDULE_MODES.MONTHLY,
|
time,
|
monthDays: sanitizeMonthDays(monthDays),
|
};
|
}
|
|
return state;
|
};
|
|
export const getWeekdayLabel = (day, translate) => {
|
const key = `page.guarantee.week.${day?.toLowerCase?.()}`;
|
return translate ? translate(key) : day;
|
};
|
|
const formatWeekdays = (days, translate) => {
|
const normalized = sanitizeWeekDays(days);
|
return normalized.map((day) => getWeekdayLabel(day, translate)).join(' / ');
|
};
|
|
const formatMonthDays = (days, translate) => {
|
const normalized = sanitizeMonthDays(days).sort((a, b) => a - b);
|
return normalized
|
.map((day) => (translate ? translate('page.guarantee.schedule.monthDay', { day }) : `${day}`))
|
.join(' / ');
|
};
|
|
export const describeCronExpression = (expr, translate) => {
|
if (!expr) {
|
return '';
|
}
|
const parsed = parseCronExpression(expr);
|
const time = parsed.time || DEFAULT_TIME;
|
|
if (!parsed.valid) {
|
return expr;
|
}
|
|
switch (parsed.mode) {
|
case SCHEDULE_MODES.WEEKLY:
|
return translate
|
? translate('page.guarantee.schedule.description.weekly', {
|
days: formatWeekdays(parsed.weekDays, translate),
|
time,
|
})
|
: `Weekly ${formatWeekdays(parsed.weekDays)} ${time}`;
|
case SCHEDULE_MODES.MONTHLY:
|
return translate
|
? translate('page.guarantee.schedule.description.monthly', {
|
days: formatMonthDays(parsed.monthDays, translate),
|
time,
|
})
|
: `Monthly ${formatMonthDays(parsed.monthDays)} ${time}`;
|
default:
|
return translate
|
? translate('page.guarantee.schedule.description.daily', { time })
|
: `Daily ${time}`;
|
}
|
};
|