diff --git a/src/NeoCron.tsx b/src/NeoCron.tsx index 9579fc7..68ef1e0 100644 --- a/src/NeoCron.tsx +++ b/src/NeoCron.tsx @@ -9,9 +9,10 @@ import { arrayToString, stringToArray } from './lib/part'; import { Schedule, getSchedule } from './lib/schedule'; import { CronState, ValuePayload } from './types'; +const defaultCronString = '* * * * *'; + interface Props { - setCronString?: (val: string) => void; //the cron string itself - defaultValue?: string; //if you want to specify a default cron string to start with + setCronString?: (val: string) => void; //updates the cron string itself disableInput?: boolean; //disable the input and only have drop down selectors disableSelectors?: boolean; //disable the selectors and only have the input disableExplainerText?: boolean; //disables the schedule explainer text @@ -21,12 +22,12 @@ interface Props { export default function NeoCron(props: Props): ReactElement { const { setCronString = () => {}, - defaultValue = '* * * * *', disableInput = false, disableSelectors = false, disableExplainerText = false, selectorText = 'Run every', } = props; + const updateSchedule = (state: CronState): CronState => { const newSchedule = getSchedule(state.array); setSchedule(newSchedule); @@ -37,68 +38,69 @@ export default function NeoCron(props: Props): ReactElement { }; const getInitialState = (): CronState => { - const expression = defaultValue; - const array = stringToArray(expression); return updateSchedule({ - expression, - array, + expression: defaultCronString, + array: stringToArray(defaultCronString), error: '', next: '', }); }; const [schedule, setSchedule] = useState( - new Schedule(stringToArray('* * * * *')) + new Schedule(stringToArray(defaultCronString)) ); - const [state, setState] = useState(getInitialState); + const [cronState, setCronState] = useState(getInitialState); const [resetSelectedValues, setResetSelectedValues] = useState(false); const setExpression = (expression: string) => { - let newState: CronState = { ...state, expression, error: '' }; + let newState: CronState = { ...cronState, expression, error: '' }; try { newState.array = stringToArray(expression); newState = updateSchedule(newState); } catch (e: any) { newState.error = e.message; } - setState(newState); + setCronState(newState); }; - const setValue = (payload: ValuePayload) => { - const newArray = [...state.array]; + const constructCronState = (payload: ValuePayload) => { + const newArray = [...cronState.array]; newArray[payload.index] = payload.values; - - let newState: CronState = { ...state, array: newArray, error: '' }; + let newState: CronState = { ...cronState, array: newArray, error: '' }; try { newState.expression = arrayToString(newState.array); newState = updateSchedule(newState); } catch (e: any) { newState.error = e.message; } - setState(newState); + + if (newState.expression !== cronState.expression) { + setCronState(newState); + } }; useEffect(() => { if (setCronString) { - setCronString(state.expression); + setCronString(cronState.expression); } - }, [state.expression]); + }, [cronState.expression]); const setError = (error: string) => { - setState({ ...state, error: error }); + setCronState({ ...cronState, error: error }); }; const resetSchedule = () => { - schedule.reset; - setState(getInitialState()); + schedule.reset(); + const initSchedule = getInitialState(); + setCronState(initSchedule); setResetSelectedValues(true); }; return (
{!disableInput && ( - + )} {disableInput || (disableSelectors ? null : ( @@ -110,9 +112,9 @@ export default function NeoCron(props: Props): ReactElement { ))} {!disableSelectors && ( )}
diff --git a/src/components/CronExpression.tsx b/src/components/CronExpression.tsx index 8364315..3ce3c65 100644 --- a/src/components/CronExpression.tsx +++ b/src/components/CronExpression.tsx @@ -3,12 +3,12 @@ import { CronState } from '../types'; import { Input } from './ui/input'; interface Props { - state: CronState; + cronState: CronState; setExpression: (val: string) => void; } export default function CronExpression(props: Props): ReactElement { - const { state, setExpression } = props; + const { cronState, setExpression } = props; return (
setExpression(e.target.value)} - value={state.expression} + value={cronState.expression} />
); diff --git a/src/components/MultiSelect.tsx b/src/components/MultiSelect.tsx index 8908f27..25826e9 100644 --- a/src/components/MultiSelect.tsx +++ b/src/components/MultiSelect.tsx @@ -24,9 +24,9 @@ interface Props { options: Unit; resetSelectedValues: boolean; setResetSelectedValues: (val: boolean) => void; - state: CronState; + cronState: CronState; setError: (val: string) => void; - setValue: (val: SetValueObject) => void; + constructCronState: (val: SetValueObject) => void; } export default function MultiSelect(props: Props) { @@ -35,8 +35,8 @@ export default function MultiSelect(props: Props) { options, resetSelectedValues, setResetSelectedValues, - state, - setValue, + cronState, + constructCronState, setError, } = props; const [openCombobox, setOpenCombobox] = useState(false); @@ -53,11 +53,30 @@ export default function MultiSelect(props: Props) { } }, [resetSelectedValues, setResetSelectedValues]); + //this handles converting the cron expression to the selected values if a user types in a string first + //the if(!isFull){...}only updates the values in the UI if the user has changed it otherwise leaves it + //this is to prevent the case where the base cron string is ***** and it selects everything in the drop down + useEffect(() => { + try { + const arr = stringToArray(cronState.expression); //prints the number[][] of all selectors + const allUnits = getUnits(); //get all units so we can find the index of this selectors unit + const index = allUnits.findIndex((unit) => unit.name == options.name); + + if (arr && Array.isArray(arr)) { + if (!isFull(arr[index], options)) { + setSelectedValues(arr[index].map(String)); + } + } + } catch (e: any) { + setError(e.message); + } + }, [cronState, options]); + useEffect(() => { if (selectedValues.length > 0) { - setValue({ index: ind, values: selectedValues.map(Number) }); + constructCronState({ index: ind, values: selectedValues.map(Number) }); } - }, [selectedValues, setValue, ind]); + }, [selectedValues, ind]); const toggleOptions = (option: string) => { setSelectedValues((currentOption) => { @@ -73,35 +92,16 @@ export default function MultiSelect(props: Props) { inputRef?.current?.focus(); }; - //this handles converting the cron expression to the selected values if a user types in a string first - //the if(!isFull){...}only updates the values in the UI if the user has changed it otherwise leaves it - //this is to prevent the case where the base cron string is ***** and it selects everything in the drop down - useEffect(() => { - try { - const arr = stringToArray(state.expression); //prints the number[][] array of all selectors - const allUnits = getUnits(); //get all units so we can find the index of this selectors unit - const index = allUnits.findIndex((unit) => unit.name == options.name); - - if (arr && Array.isArray(arr)) { - if (!isFull(arr[index], options)) { - setSelectedValues(arr[index].map(String)); - } - } - } catch (e: any) { - setError(e.message); - } - }, [state]); - const handleSelectAll = () => { if (!selectAll) { setSelectAll(true); const allOptions = spreadOption(options); setSelectedValues(allOptions); - setValue({ index: ind, values: allOptions.map(Number) }); + constructCronState({ index: ind, values: allOptions.map(Number) }); } else { setSelectAll(false); setSelectedValues([]); - setValue({ index: 0, values: [] }); + constructCronState({ index: 0, values: [] }); } }; @@ -176,10 +176,10 @@ export default function MultiSelect(props: Props) { key={option} value={option} onSelect={() => toggleOptions(option)} - // onSelect={() => setOption(option)} className={cn( 'flex-1', - isActive && 'multiselect-selected-value' + isActive && 'multiselect-selected-value', + !isActive && 'multiselect-unselected-value' )} >
{formatOption(option)}
diff --git a/src/components/ScheduleSelectors.tsx b/src/components/ScheduleSelectors.tsx index 5245401..0670842 100644 --- a/src/components/ScheduleSelectors.tsx +++ b/src/components/ScheduleSelectors.tsx @@ -12,9 +12,9 @@ import { } from './ui/select'; interface Props { - setValue: (val: ValuePayload) => void; + constructCronState: (val: ValuePayload) => void; resetSchedule: () => void; - state: CronState; + cronState: CronState; resetSelectedValues: boolean; setResetSelectedValues: (val: boolean) => void; setError: (val: string) => void; @@ -23,8 +23,8 @@ interface Props { const scheduleSelector: ScheduleSelectorObject[] = [ { name: 'year', prefix: 'on' }, - { name: 'month', prefix: 'on' }, { name: 'weekday', prefix: 'on' }, + { name: 'month', prefix: 'on' }, { name: 'day', prefix: 'and' }, { name: 'hour', prefix: 'at' }, { name: 'minute', prefix: ':' }, @@ -32,9 +32,9 @@ const scheduleSelector: ScheduleSelectorObject[] = [ export default function ScheduleSelectors(props: Props): ReactElement { const { - setValue, + constructCronState, resetSchedule, - state, + cronState, resetSelectedValues, setResetSelectedValues, setError, @@ -58,16 +58,14 @@ export default function ScheduleSelectors(props: Props): ReactElement { return (
{opt.prefix}
-
- -
+
); }); diff --git a/src/lib/units.ts b/src/lib/units.ts index 3b94917..cdd0a9a 100644 --- a/src/lib/units.ts +++ b/src/lib/units.ts @@ -17,12 +17,6 @@ export const units: Unit[] = [ min: 1, max: 31, }, - { - name: 'weekday', - min: 0, - max: 6, - alt: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - }, { name: 'month', min: 1, @@ -42,6 +36,12 @@ export const units: Unit[] = [ 'Dec', ], }, + { + name: 'weekday', + min: 0, + max: 6, + alt: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + }, ]; //turns the min and max in the option into an array with all of the values