| @@ -133,7 +133,10 @@ export const validateTimeLeaveRecord = ( | |||||
| } | } | ||||
| }); | }); | ||||
| return Object.keys(errors).length > 0 ? errors : undefined; | |||||
| const hasErrors = Object.keys(errors).length > 0; | |||||
| const temporarilySaveable = isTemporarilySaveable(records, errors, holidays); | |||||
| return !temporarilySaveable && hasErrors ? errors : undefined; | |||||
| }; | }; | ||||
| export const checkTotalHours = ( | export const checkTotalHours = ( | ||||
| @@ -180,3 +183,35 @@ export const checkTotalHours = ( | |||||
| export const DAILY_NORMAL_MAX_HOURS = 8; | export const DAILY_NORMAL_MAX_HOURS = 8; | ||||
| export const TIMESHEET_DAILY_MAX_HOURS = 20; | export const TIMESHEET_DAILY_MAX_HOURS = 20; | ||||
| export const isTemporarilySaveable = ( | |||||
| records: RecordTimeLeaveInput, | |||||
| errors: { [date: string]: string }, | |||||
| holidays: Set<string>, | |||||
| ): boolean => { | |||||
| const filledDates = Object.keys(records) | |||||
| .reduce<{ date: string; hasFilled: boolean }[]>((acc, date) => { | |||||
| const dayJsObj = dayjs(date); | |||||
| const isHoliday = | |||||
| holidays.has(date) || dayJsObj.day() === 0 || dayJsObj.day() === 6; | |||||
| if (isHoliday) { | |||||
| return acc; | |||||
| } | |||||
| return [...acc, { date, hasFilled: !Boolean(errors[date]) }]; | |||||
| }, []) | |||||
| .sort((a, b) => dayjs(a.date).diff(dayjs(b.date))); | |||||
| const isConsecutivelyFilled = filledDates.every((currentDate, index) => { | |||||
| if (index === 0) { | |||||
| return true; | |||||
| } | |||||
| if (currentDate.hasFilled && !filledDates[index - 1].hasFilled) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| }); | |||||
| return isConsecutivelyFilled; | |||||
| }; | |||||
| @@ -33,6 +33,7 @@ interface Props<EntryComponentProps = object> { | |||||
| >; | >; | ||||
| entryComponentProps: EntryComponentProps; | entryComponentProps: EntryComponentProps; | ||||
| errorComponent?: React.ReactNode; | errorComponent?: React.ReactNode; | ||||
| onSubmit?: () => void; | |||||
| } | } | ||||
| function DateHoursList<EntryTableProps>({ | function DateHoursList<EntryTableProps>({ | ||||
| @@ -43,6 +44,7 @@ function DateHoursList<EntryTableProps>({ | |||||
| entryComponentProps, | entryComponentProps, | ||||
| companyHolidays, | companyHolidays, | ||||
| errorComponent, | errorComponent, | ||||
| onSubmit, | |||||
| }: Props<EntryTableProps>) { | }: Props<EntryTableProps>) { | ||||
| const { | const { | ||||
| t, | t, | ||||
| @@ -240,7 +242,12 @@ function DateHoursList<EntryTableProps>({ | |||||
| {t("Done")} | {t("Done")} | ||||
| </Button> | </Button> | ||||
| ) : ( | ) : ( | ||||
| <Button variant="contained" startIcon={<Check />} type="submit"> | |||||
| <Button | |||||
| variant="contained" | |||||
| startIcon={<Check />} | |||||
| type="submit" | |||||
| onClick={onSubmit} | |||||
| > | |||||
| {t("Save")} | {t("Save")} | ||||
| </Button> | </Button> | ||||
| )} | )} | ||||
| @@ -237,7 +237,14 @@ const TimeLeaveModal: React.FC<Props> = ({ | |||||
| > | > | ||||
| {t("Cancel")} | {t("Cancel")} | ||||
| </Button> | </Button> | ||||
| <Button variant="contained" startIcon={<Check />} type="submit"> | |||||
| <Button | |||||
| variant="contained" | |||||
| startIcon={<Check />} | |||||
| type="submit" | |||||
| onClick={() => { | |||||
| formProps.clearErrors(); | |||||
| }} | |||||
| > | |||||
| {t("Save")} | {t("Save")} | ||||
| </Button> | </Button> | ||||
| </CardActions> | </CardActions> | ||||
| @@ -277,6 +284,9 @@ const TimeLeaveModal: React.FC<Props> = ({ | |||||
| miscTasks, | miscTasks, | ||||
| }} | }} | ||||
| errorComponent={errorComponent} | errorComponent={errorComponent} | ||||
| onSubmit={() => { | |||||
| formProps.clearErrors(); | |||||
| }} | |||||
| /> | /> | ||||
| </Box> | </Box> | ||||
| </FullscreenModal> | </FullscreenModal> | ||||