@@ -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> | ||||