2 Commits

4 gewijzigde bestanden met toevoegingen van 57 en 5 verwijderingen
  1. +37
    -2
      src/app/api/timesheets/utils.ts
  2. +8
    -1
      src/components/DateHoursTable/DateHoursList.tsx
  3. +11
    -1
      src/components/TimeLeaveModal/TimeLeaveModal.tsx
  4. +1
    -1
      src/components/TimesheetTable/TimesheetEditModal.tsx

+ 37
- 2
src/app/api/timesheets/utils.ts Bestand weergeven

@@ -47,7 +47,7 @@ export const validateTimeEntry = (
} else { } else {
if (entry.taskGroupId && !entry.taskId) { if (entry.taskGroupId && !entry.taskId) {
error.taskId = "Required"; error.taskId = "Required";
} else if (!entry.remark) {
} else if (!entry.taskGroupId && !entry.remark) {
error.remark = "Required for non-billable tasks"; error.remark = "Required for non-billable tasks";
} }
} }
@@ -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;
};

+ 8
- 1
src/components/DateHoursTable/DateHoursList.tsx Bestand weergeven

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


+ 11
- 1
src/components/TimeLeaveModal/TimeLeaveModal.tsx Bestand weergeven

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


+ 1
- 1
src/components/TimesheetTable/TimesheetEditModal.tsx Bestand weergeven

@@ -304,7 +304,7 @@ const TimesheetEditModal: React.FC<Props> = ({
error={Boolean(formState.errors.remark)} error={Boolean(formState.errors.remark)}
{...register("remark", { {...register("remark", {
validate: (value) => validate: (value) =>
Boolean(projectId || value) ||
Boolean(projectId || taskGroupId || value) ||
t("Required for non-billable tasks"), t("Required for non-billable tasks"),
})} })}
helperText={formState.errors.remark?.message} helperText={formState.errors.remark?.message}


Laden…
Annuleren
Opslaan