UNPKG

react-js-cron-mantine

Version:

Fork of [react-js-cron](https://github.com/xrutayisire/react-js-cron), made to work with [mantine](https://mantine.dev)

278 lines (271 loc) 10.7 kB
import React, { useState, useCallback, useEffect, useRef, useMemo } from 'react'; import Period from './fields/Period'; import MonthDays from './fields/MonthDays'; import Months from './fields/Months'; import Hours from './fields/Hours'; import Minutes from './fields/Minutes'; import WeekDays from './fields/WeekDays'; import { classNames, usePrevious } from './utils'; import { DEFAULT_LOCALE_EN } from './locale'; import { setValuesFromCronString, getCronStringFromValues } from './converter'; import { SimpleGrid } from '@mantine/core'; import { Button } from '@mantine/core'; import dayjs from 'dayjs'; import RelativeTime from 'dayjs/plugin/relativeTime'; import tz from 'dayjs/plugin/timezone'; import utc from 'dayjs/plugin/utc'; export default function Cron(props) { const { timezone_value = 'UTC', clearButton = true, convertToTimezone = false, clearButtonAction = 'fill-with-every', locale = DEFAULT_LOCALE_EN, value = '', setValue, setValueObj, displayError = true, onError, className, defaultPeriod = 'day', allowEmpty = 'for-default-value', humanizeLabels = true, humanizeValue = false, disabled = false, readOnly = false, leadingZero = false, shortcuts = ['@yearly', '@annually', '@monthly', '@weekly', '@daily', '@midnight', '@hourly'], clockFormat, periodicityOnDoubleClick = true, mode = 'multiple', allowedDropdowns = ['period', 'months', 'month-days', 'week-days', 'hours', 'minutes', 'switch'], allowedPeriods = ['year', 'month', 'week', 'day', 'hour', 'minute', 'reboot'] } = props; const internalValueRef = useRef(value); const defaultPeriodRef = useRef(defaultPeriod); const [period, setPeriod] = useState(); const [monthDays, setMonthDays] = useState(); const [months, setMonths] = useState(); const [weekDays, setWeekDays] = useState(); const [hours, setHours] = useState(); const [minutes, setMinutes] = useState(); const [tzhours, setTzHours] = useState(); const [tzminutes, setTzMinutes] = useState(); const [utchours, utcsetHours] = useState(); const [utcminutes, utcsetMinutes] = useState(); const [error, setInternalError] = useState(false); const [tzerror, setTzError] = useState(''); const [valueCleared, setValueCleared] = useState(false); const previousValueCleared = usePrevious(valueCleared); const localeJSON = JSON.stringify(locale); const [checked, setChecked] = useState(false); useEffect(() => { setValuesFromCronString(value, setInternalError, onError, allowEmpty, internalValueRef, true, locale, shortcuts, setMinutes, setHours, setMonthDays, setMonths, setWeekDays, setPeriod); }, []); useEffect(() => { if (value !== internalValueRef.current) { setValuesFromCronString(value, setInternalError, onError, allowEmpty, internalValueRef, false, locale, shortcuts, setMinutes, setHours, setMonthDays, setMonths, setWeekDays, setPeriod); } }, [value, internalValueRef, localeJSON, allowEmpty, shortcuts]); useEffect(() => { if ((period || minutes || months || monthDays || weekDays || hours) && !valueCleared && !previousValueCleared) { const selectedPeriod = period || defaultPeriodRef.current; const cron = getCronStringFromValues(selectedPeriod, months, monthDays, weekDays, convertToTimezone ? tzhours : hours, convertToTimezone ? tzminutes : minutes, setValueObj, humanizeValue); setValue(cron, { selectedPeriod }); internalValueRef.current = cron; setInternalError(false); } else if (valueCleared) { setValueCleared(false); } }, [period, monthDays, months, weekDays, tzhours, tzminutes, minutes, hours, humanizeValue, timezone_value, valueCleared]); const handleClear = useCallback(() => { setMonthDays([]); setMonths([]); setWeekDays([]); setHours([]); setMinutes([]); let newValue = ''; const newPeriod = period !== 'reboot' && period ? period : defaultPeriodRef.current; if (newPeriod !== period) { setPeriod(newPeriod); } if (clearButtonAction === 'fill-with-every') { const cron = getCronStringFromValues(newPeriod, undefined, undefined, undefined, undefined, undefined, setValueObj); newValue = cron; } setValue(newValue, { selectedPeriod: newPeriod }); internalValueRef.current = newValue; setValueCleared(true); if (allowEmpty === 'never' && clearButtonAction === 'empty') { setInternalError(true); } else { setInternalError(false); } }, [period, setValue, onError, clearButtonAction]); const internalClassName = useMemo(() => classNames({ 'react-js-cron': true, 'react-js-cron-error': error && displayError, 'react-js-cron-disabled': disabled, 'react-js-cron-read-only': readOnly, [`${className}`]: !!className, [`${className}-error`]: error && displayError && !!className, [`${className}-disabled`]: disabled && !!className, [`${className}-read-only`]: readOnly && !!className }), [className, error, displayError, disabled, readOnly]); const clearButtonClassName = useMemo(() => classNames({ 'react-js-cron-clear-button': true, [`${className}-clear-button`]: !!className }), [className]); const clearButtonNode = useMemo(() => { if (clearButton && !readOnly) { return React.createElement(Button, { disabled: disabled, ml: 5, onClick: handleClear, color: "red", size: "xs" }, "Clear"); } return null; }, [clearButton, readOnly, localeJSON, clearButtonClassName, disabled, handleClear]); const periodForRender = period || defaultPeriodRef.current; dayjs.extend(RelativeTime); dayjs.extend(utc); dayjs.extend(tz); useEffect(() => { const hourarr = []; const minutearr = []; if (convertToTimezone == true) { try { if (hours && hours.length > 0) { const newh = hours?.map(h => { if (minutes && minutes.length > 0) { minutes?.map(m => { hourarr.includes(Number(dayjs().hour(h).minute(m).tz(timezone_value).format('HH'))) ? null : hourarr.push(Number(dayjs().hour(h).minute(m).tz(timezone_value).format('HH'))); minutearr.includes(Number(dayjs().hour(h).minute(m).tz(timezone_value).format('mm'))) ? null : minutearr.push(Number(dayjs().hour(h).minute(m).tz(timezone_value).format('mm'))); }); } else { if (Number(dayjs().hour(h).minute(0).tz(timezone_value).format('mm')) !== 0) { hourarr.includes(Number(dayjs().hour(h).minute(0).tz(timezone_value).format('HH'))) ? null : hourarr.push(Number(dayjs().hour(h).minute(0).tz(timezone_value).format('HH'))); minutearr.includes(Number(dayjs().hour(h).minute(0).tz(timezone_value).format('mm'))) ? null : minutearr.push(Number(dayjs().hour(h).minute(0).tz(timezone_value).format('mm'))); } else { hourarr.includes(Number(dayjs().hour(h).minute(0).tz(timezone_value).format('HH'))) ? null : hourarr.push(Number(dayjs().hour(h).minute(0).tz(timezone_value).format('HH'))); } } }); } setTzHours(hourarr); setTzMinutes(minutearr); setInternalError(false); onError && onError(undefined); setTzError(''); } catch (err) { setTzError(err.message); onError && onError({ type: 'invalid_cron', description: err.message }); setInternalError(true); } } else { setTzError(''); setInternalError(false); onError && onError(undefined); setTzHours([]); setTzMinutes([]); } }, [hours, minutes, timezone_value, convertToTimezone]); return React.createElement(React.Fragment, null, React.createElement(SimpleGrid, { breakpoints: [{ maxWidth: 980, cols: 2, spacing: 'md' }, { maxWidth: 755, cols: 2, spacing: 'sm' }, { maxWidth: 600, cols: 1, spacing: 'sm' }], mb: 10, cols: 2 }, ' ', allowedDropdowns.includes('period') && React.createElement(Period, { value: periodForRender, setValue: setPeriod, locale: locale, className: className, disabled: disabled, readOnly: readOnly, shortcuts: shortcuts, allowedPeriods: allowedPeriods }), periodForRender === 'reboot' ? clearButtonNode : React.createElement(React.Fragment, null, periodForRender === 'year' && allowedDropdowns.includes('months') && React.createElement(Months, { value: months, setValue: setMonths, locale: locale, className: className, humanizeLabels: humanizeLabels, disabled: disabled, readOnly: readOnly, period: periodForRender, periodicityOnDoubleClick: periodicityOnDoubleClick, mode: mode }), (periodForRender === 'year' || periodForRender === 'month') && allowedDropdowns.includes('month-days') && React.createElement(MonthDays, { value: monthDays, setValue: setMonthDays, locale: locale, className: className, weekDays: weekDays, disabled: disabled, readOnly: readOnly, leadingZero: leadingZero, period: periodForRender, periodicityOnDoubleClick: periodicityOnDoubleClick, mode: mode }), (periodForRender === 'year' || periodForRender === 'month' || periodForRender === 'week') && allowedDropdowns.includes('week-days') && React.createElement(WeekDays, { value: weekDays, setValue: setWeekDays, locale: locale, className: className, humanizeLabels: humanizeLabels, monthDays: monthDays, disabled: disabled, readOnly: readOnly, period: periodForRender, periodicityOnDoubleClick: periodicityOnDoubleClick, mode: mode }), periodForRender !== 'minute' && periodForRender !== 'hour' && allowedDropdowns.includes('hours') && React.createElement(Hours, { value: hours, setValue: setHours, locale: locale, className: className, disabled: disabled, readOnly: readOnly, leadingZero: leadingZero, clockFormat: clockFormat, period: periodForRender, periodicityOnDoubleClick: periodicityOnDoubleClick, mode: mode }), periodForRender !== 'minute' && allowedDropdowns.includes('minutes') && React.createElement(Minutes, { value: minutes, setValue: setMinutes, locale: locale, period: periodForRender, className: className, disabled: disabled, readOnly: readOnly, leadingZero: leadingZero, clockFormat: clockFormat, periodicityOnDoubleClick: periodicityOnDoubleClick, mode: mode }))), React.createElement("div", { style: { float: 'right' } }, clearButtonNode)); }