Skip to content

Commit

Permalink
Merge pull request #3527 from ever-co/feat/timesheet-date-handling-op…
Browse files Browse the repository at this point in the history
…timization

[Feat]: Optimize Timesheet Date Handling and Performance
  • Loading branch information
evereq authored Jan 19, 2025
2 parents 342e2b2 + f386e2d commit baa644f
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 19 deletions.
26 changes: 20 additions & 6 deletions apps/web/app/[locale]/timesheet/[memberId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,24 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb
'ListView'
);

const [dateRange, setDateRange] = React.useState<{ from: Date | null; to: Date | null }>({
from: startOfMonth(new Date()),
to: endOfMonth(new Date())
});
/**
* Default date range for the current month
*/
const defaultDateRange = useMemo(() => ({
from: startOfMonth(new Date()),
to: endOfMonth(new Date())
}), []);

const [dateRange, setDateRange] = React.useState<{ from: Date | null; to: Date | null }>(defaultDateRange);

/**
* Memoized date range for timesheet
* Returns default dates if current dates are null
*/
const timesheetDateRange = useMemo(() => ({
startDate: dateRange.from || defaultDateRange.from,
endDate: dateRange.to || defaultDateRange.to
}), [dateRange.from, dateRange.to, defaultDateRange]);

const {
timesheet: filterDataTimesheet,
Expand All @@ -73,8 +87,8 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb
updateTimesheetStatus,
deleteTaskTimesheet
} = useTimesheet({
startDate: dateRange.from!,
endDate: dateRange.to!,
startDate: timesheetDateRange.startDate,
endDate: timesheetDateRange.endDate,
timesheetViewMode: timesheetNavigator,
inputSearch: search
});
Expand Down
70 changes: 57 additions & 13 deletions apps/web/app/hooks/features/useTimesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useAuthenticateUser } from './useAuthenticateUser';
import { useAtom } from 'jotai';
import { timesheetRapportState } from '@/app/stores/time-logs';
import { useQuery } from '../useQuery';
import { useCallback, useEffect, useMemo } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { deleteTaskTimesheetLogsApi, getTaskTimesheetLogsApi, updateStatusTimesheetFromApi, createTimesheetFromApi, updateTimesheetFromAPi } from '@/app/services/client/api/timer/timer-log';
import moment from 'moment';
import { ID, TimesheetLog, TimesheetStatus, UpdateTimesheet } from '@/app/interfaces';
Expand Down Expand Up @@ -178,8 +178,8 @@ const groupByMonth = createGroupingFunction(getMonthKey);
* @prop {boolean} isManage - Whether the user is authorized to manage the timesheet.
*/
export function useTimesheet({
startDate,
endDate,
startDate = moment().startOf('month').toDate(),
endDate = moment().endOf('month').toDate(),
timesheetViewMode,
inputSearch
}: TimesheetParams) {
Expand All @@ -193,18 +193,48 @@ export function useTimesheet({
const { loading: loadingUpdateTimesheet, queryCall: queryUpdateTimesheet } = useQuery(updateTimesheetFromAPi);
const isManage = user && isUserAllowedToAccess(user);

const [createTimesheetResponse, setCreateTimesheetResponse] = useState<any>(null);

/**
* Memoized date range with fallback to defaults
* Ensures all dates are converted to Date objects
*/
const currentDateRange = useMemo(() => {
const defaultStart = moment().startOf('month').toDate();
const defaultEnd = moment().endOf('month').toDate();

return {
startDate: startDate ? moment(startDate).toDate() : defaultStart,
endDate: endDate ? moment(endDate).toDate() : defaultEnd
};
}, [startDate, endDate]);

/**
* Format date to YYYY-MM-DD ensuring valid date input
* @param date - Input date (optional)
* @param defaultDate - Default date if input is undefined
*/
const formatDate = useCallback((date: Date | string | undefined, defaultDate: Date): string => {
try {
return moment(date || defaultDate).format('YYYY-MM-DD');
} catch (error) {
console.warn('Invalid date provided, using default date');
return moment(defaultDate).format('YYYY-MM-DD');
}
}, []);

const getTaskTimesheet = useCallback(
({ startDate, endDate }: TimesheetParams) => {
if (!user) return;

const from = moment(startDate).format('YYYY-MM-DD');
const to = moment(endDate).format('YYYY-MM-DD');
const from = formatDate(startDate, currentDateRange.startDate);
const to = formatDate(endDate, currentDateRange.endDate);
queryTimesheet({
startDate: from,
endDate: to,
organizationId: user.employee?.organizationId,
tenantId: user.tenantId ?? '',
timeZone: user.timeZone?.split('(')[0].trim(),
timeZone: user.timeZone?.split('(')[0].trim() || 'UTC',
employeeIds: isManage
? employee?.map(({ employee: { id } }) => id).filter(Boolean)
: [user.employee.id],
Expand All @@ -217,7 +247,7 @@ export function useTimesheet({
console.error('Error fetching timesheet:', error);
});
},
[user, queryTimesheet, isManage, employee, project, task, statusState, setTimesheet]
[user, formatDate, currentDateRange.startDate, currentDateRange.endDate, queryTimesheet, isManage, employee, project, task, statusState, setTimesheet]
);

const createTimesheet = useCallback(
Expand All @@ -226,10 +256,9 @@ export function useTimesheet({
throw new Error("User not authenticated");
}
try {
const response = queryCreateTimesheet(timesheetParams).then((res) => {
return res.data
});
return response
const response = await queryCreateTimesheet(timesheetParams);
setCreateTimesheetResponse(response.data);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error('Axios Error:', {
Expand Down Expand Up @@ -446,9 +475,24 @@ export function useTimesheet({
};


/**
* Combined effect for fetching timesheet data
* Handles both initial load and updates after timesheet creation
*/
useEffect(() => {
getTaskTimesheet({ startDate, endDate });
}, [getTaskTimesheet, startDate, endDate, timesheetGroupByDays, inputSearch]);
if (createTimesheetResponse) {
getTaskTimesheet(currentDateRange);
setCreateTimesheetResponse(null);
} else {
getTaskTimesheet(currentDateRange);
}
}, [
getTaskTimesheet,
currentDateRange,
createTimesheetResponse,
timesheetGroupByDays,
inputSearch
]);

return {
loadingTimesheet,
Expand Down

0 comments on commit baa644f

Please sign in to comment.