@@ -8,8 +8,6 @@ import { | |||||
fetchTeamMemberTimesheets, | fetchTeamMemberTimesheets, | ||||
fetchTimesheets, | fetchTimesheets, | ||||
} from "@/app/api/timesheets"; | } from "@/app/api/timesheets"; | ||||
import { authOptions } from "@/config/authConfig"; | |||||
import { getServerSession } from "next-auth"; | |||||
import { | import { | ||||
fetchAssignedProjects, | fetchAssignedProjects, | ||||
fetchProjectWithTasks, | fetchProjectWithTasks, | ||||
@@ -21,22 +19,18 @@ export const metadata: Metadata = { | |||||
}; | }; | ||||
const Home: React.FC = async () => { | const Home: React.FC = async () => { | ||||
const session = await getServerSession(authOptions); | |||||
// Get name for caching | |||||
const username = session!.user!.name!; | |||||
fetchTimesheets(username); | |||||
fetchAssignedProjects(username); | |||||
fetchLeaves(username); | |||||
fetchTimesheets(); | |||||
fetchAssignedProjects(); | |||||
fetchLeaves(); | |||||
fetchLeaveTypes(); | fetchLeaveTypes(); | ||||
fetchProjectWithTasks(); | fetchProjectWithTasks(); | ||||
fetchHolidays(); | fetchHolidays(); | ||||
fetchTeamMemberTimesheets(username); | |||||
fetchTeamMemberLeaves(username); | |||||
fetchTeamMemberTimesheets(); | |||||
fetchTeamMemberLeaves(); | |||||
return ( | return ( | ||||
<I18nProvider namespaces={["home", "common"]}> | <I18nProvider namespaces={["home", "common"]}> | ||||
<UserWorkspacePage username={username} /> | |||||
<UserWorkspacePage /> | |||||
</I18nProvider> | </I18nProvider> | ||||
); | ); | ||||
}; | }; | ||||
@@ -170,11 +170,11 @@ export const fetchProjectWorkNatures = cache(async () => { | |||||
}); | }); | ||||
}); | }); | ||||
export const fetchAssignedProjects = cache(async (username: string) => { | |||||
export const fetchAssignedProjects = cache(async () => { | |||||
return serverFetchJson<AssignedProject[]>( | return serverFetchJson<AssignedProject[]>( | ||||
`${BASE_API_URL}/projects/assignedProjects`, | `${BASE_API_URL}/projects/assignedProjects`, | ||||
{ | { | ||||
next: { tags: [`assignedProjects__${username}`] }, | |||||
next: { tags: [`assignedProjects`] }, | |||||
}, | }, | ||||
); | ); | ||||
}); | }); | ||||
@@ -31,10 +31,7 @@ export interface RecordLeaveInput { | |||||
[date: string]: LeaveEntry[]; | [date: string]: LeaveEntry[]; | ||||
} | } | ||||
export const saveTimesheet = async ( | |||||
data: RecordTimesheetInput, | |||||
username: string, | |||||
) => { | |||||
export const saveTimesheet = async (data: RecordTimesheetInput) => { | |||||
const savedRecords = await serverFetchJson<RecordTimesheetInput>( | const savedRecords = await serverFetchJson<RecordTimesheetInput>( | ||||
`${BASE_API_URL}/timesheets/save`, | `${BASE_API_URL}/timesheets/save`, | ||||
{ | { | ||||
@@ -44,12 +41,12 @@ export const saveTimesheet = async ( | |||||
}, | }, | ||||
); | ); | ||||
revalidateTag(`timesheets_${username}`); | |||||
revalidateTag(`timesheets`); | |||||
return savedRecords; | return savedRecords; | ||||
}; | }; | ||||
export const saveLeave = async (data: RecordLeaveInput, username: string) => { | |||||
export const saveLeave = async (data: RecordLeaveInput) => { | |||||
const savedRecords = await serverFetchJson<RecordLeaveInput>( | const savedRecords = await serverFetchJson<RecordLeaveInput>( | ||||
`${BASE_API_URL}/timesheets/saveLeave`, | `${BASE_API_URL}/timesheets/saveLeave`, | ||||
{ | { | ||||
@@ -59,7 +56,7 @@ export const saveLeave = async (data: RecordLeaveInput, username: string) => { | |||||
}, | }, | ||||
); | ); | ||||
revalidateTag(`leaves_${username}`); | |||||
revalidateTag(`leaves`); | |||||
return savedRecords; | return savedRecords; | ||||
}; | }; | ||||
@@ -24,17 +24,17 @@ export type TeamLeaves = { | |||||
}; | }; | ||||
}; | }; | ||||
export const fetchTimesheets = cache(async (username: string) => { | |||||
export const fetchTimesheets = cache(async () => { | |||||
return serverFetchJson<RecordTimesheetInput>(`${BASE_API_URL}/timesheets`, { | return serverFetchJson<RecordTimesheetInput>(`${BASE_API_URL}/timesheets`, { | ||||
next: { tags: [`timesheets_${username}`] }, | |||||
next: { tags: [`timesheets`] }, | |||||
}); | }); | ||||
}); | }); | ||||
export const fetchLeaves = cache(async (username: string) => { | |||||
export const fetchLeaves = cache(async () => { | |||||
return serverFetchJson<RecordLeaveInput>( | return serverFetchJson<RecordLeaveInput>( | ||||
`${BASE_API_URL}/timesheets/leaves`, | `${BASE_API_URL}/timesheets/leaves`, | ||||
{ | { | ||||
next: { tags: [`leaves_${username}`] }, | |||||
next: { tags: [`leaves`] }, | |||||
}, | }, | ||||
); | ); | ||||
}); | }); | ||||
@@ -45,17 +45,17 @@ export const fetchLeaveTypes = cache(async () => { | |||||
}); | }); | ||||
}); | }); | ||||
export const fetchTeamMemberTimesheets = cache(async (username: string) => { | |||||
export const fetchTeamMemberTimesheets = cache(async () => { | |||||
return serverFetchJson<TeamTimeSheets>( | return serverFetchJson<TeamTimeSheets>( | ||||
`${BASE_API_URL}/timesheets/teamTimesheets`, | `${BASE_API_URL}/timesheets/teamTimesheets`, | ||||
{ | { | ||||
next: { tags: [`team_timesheets_${username}`] }, | |||||
next: { tags: [`team_timesheets`] }, | |||||
}, | }, | ||||
); | ); | ||||
}); | }); | ||||
export const fetchTeamMemberLeaves = cache(async (username: string) => { | |||||
export const fetchTeamMemberLeaves = cache(async () => { | |||||
return serverFetchJson<TeamLeaves>(`${BASE_API_URL}/timesheets/teamLeaves`, { | return serverFetchJson<TeamLeaves>(`${BASE_API_URL}/timesheets/teamLeaves`, { | ||||
next: { tags: [`team_leaves_${username}`] }, | |||||
next: { tags: [`team_leaves`] }, | |||||
}); | }); | ||||
}); | }); |
@@ -36,7 +36,6 @@ import ErrorAlert from "../ErrorAlert"; | |||||
interface Props { | interface Props { | ||||
isOpen: boolean; | isOpen: boolean; | ||||
onClose: () => void; | onClose: () => void; | ||||
username: string; | |||||
defaultLeaveRecords?: RecordLeaveInput; | defaultLeaveRecords?: RecordLeaveInput; | ||||
leaveTypes: LeaveType[]; | leaveTypes: LeaveType[]; | ||||
timesheetRecords: RecordTimesheetInput; | timesheetRecords: RecordTimesheetInput; | ||||
@@ -56,7 +55,6 @@ const modalSx: SxProps = { | |||||
const LeaveModal: React.FC<Props> = ({ | const LeaveModal: React.FC<Props> = ({ | ||||
isOpen, | isOpen, | ||||
onClose, | onClose, | ||||
username, | |||||
defaultLeaveRecords, | defaultLeaveRecords, | ||||
timesheetRecords, | timesheetRecords, | ||||
leaveTypes, | leaveTypes, | ||||
@@ -97,7 +95,7 @@ const LeaveModal: React.FC<Props> = ({ | |||||
); | ); | ||||
return; | return; | ||||
} | } | ||||
const savedRecords = await saveLeave(data, username); | |||||
const savedRecords = await saveLeave(data); | |||||
const today = dayjs(); | const today = dayjs(); | ||||
const newFormValues = Array(7) | const newFormValues = Array(7) | ||||
@@ -113,7 +111,7 @@ const LeaveModal: React.FC<Props> = ({ | |||||
formProps.reset(newFormValues); | formProps.reset(newFormValues); | ||||
onClose(); | onClose(); | ||||
}, | }, | ||||
[companyHolidays, formProps, onClose, timesheetRecords, username], | |||||
[companyHolidays, formProps, onClose, timesheetRecords], | |||||
); | ); | ||||
const onCancel = useCallback(() => { | const onCancel = useCallback(() => { | ||||
@@ -1,6 +1,9 @@ | |||||
import { LeaveType } from "@/app/api/timesheets"; | import { LeaveType } from "@/app/api/timesheets"; | ||||
import { LeaveEntry } from "@/app/api/timesheets/actions"; | import { LeaveEntry } from "@/app/api/timesheets/actions"; | ||||
import { DAILY_NORMAL_MAX_HOURS } from "@/app/api/timesheets/utils"; | |||||
import { | |||||
DAILY_NORMAL_MAX_HOURS, | |||||
TIMESHEET_DAILY_MAX_HOURS, | |||||
} from "@/app/api/timesheets/utils"; | |||||
import { shortDateFormatter } from "@/app/utils/formatUtil"; | import { shortDateFormatter } from "@/app/utils/formatUtil"; | ||||
import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | ||||
import { Check, Delete } from "@mui/icons-material"; | import { Check, Delete } from "@mui/icons-material"; | ||||
@@ -153,7 +156,10 @@ const LeaveEditModal: React.FC<Props> = ({ | |||||
/> | /> | ||||
{formState.errors.root?.message && ( | {formState.errors.root?.message && ( | ||||
<Typography variant="caption" color="error"> | <Typography variant="caption" color="error"> | ||||
{t(formState.errors.root.message, { DAILY_NORMAL_MAX_HOURS })} | |||||
{t(formState.errors.root.message, { | |||||
DAILY_NORMAL_MAX_HOURS, | |||||
TIMESHEET_DAILY_MAX_HOURS, | |||||
})} | |||||
</Typography> | </Typography> | ||||
)} | )} | ||||
<Box display="flex" justifyContent="flex-end" gap={1}> | <Box display="flex" justifyContent="flex-end" gap={1}> | ||||
@@ -38,7 +38,6 @@ interface Props { | |||||
onClose: () => void; | onClose: () => void; | ||||
allProjects: ProjectWithTasks[]; | allProjects: ProjectWithTasks[]; | ||||
assignedProjects: AssignedProject[]; | assignedProjects: AssignedProject[]; | ||||
username: string; | |||||
defaultTimesheets?: RecordTimesheetInput; | defaultTimesheets?: RecordTimesheetInput; | ||||
leaveRecords: RecordLeaveInput; | leaveRecords: RecordLeaveInput; | ||||
companyHolidays: HolidaysResult[]; | companyHolidays: HolidaysResult[]; | ||||
@@ -60,7 +59,6 @@ const TimesheetModal: React.FC<Props> = ({ | |||||
onClose, | onClose, | ||||
allProjects, | allProjects, | ||||
assignedProjects, | assignedProjects, | ||||
username, | |||||
defaultTimesheets, | defaultTimesheets, | ||||
leaveRecords, | leaveRecords, | ||||
companyHolidays, | companyHolidays, | ||||
@@ -97,7 +95,7 @@ const TimesheetModal: React.FC<Props> = ({ | |||||
); | ); | ||||
return; | return; | ||||
} | } | ||||
const savedRecords = await saveTimesheet(data, username); | |||||
const savedRecords = await saveTimesheet(data); | |||||
const today = dayjs(); | const today = dayjs(); | ||||
const newFormValues = Array(7) | const newFormValues = Array(7) | ||||
@@ -113,7 +111,7 @@ const TimesheetModal: React.FC<Props> = ({ | |||||
formProps.reset(newFormValues); | formProps.reset(newFormValues); | ||||
onClose(); | onClose(); | ||||
}, | }, | ||||
[companyHolidays, formProps, leaveRecords, onClose, username], | |||||
[companyHolidays, formProps, leaveRecords, onClose], | |||||
); | ); | ||||
const onCancel = useCallback(() => { | const onCancel = useCallback(() => { | ||||
@@ -23,7 +23,10 @@ import { TaskGroup } from "@/app/api/tasks"; | |||||
import uniqBy from "lodash/uniqBy"; | import uniqBy from "lodash/uniqBy"; | ||||
import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | import { roundToNearestQuarter } from "@/app/utils/manhourUtils"; | ||||
import { shortDateFormatter } from "@/app/utils/formatUtil"; | import { shortDateFormatter } from "@/app/utils/formatUtil"; | ||||
import { DAILY_NORMAL_MAX_HOURS } from "@/app/api/timesheets/utils"; | |||||
import { | |||||
DAILY_NORMAL_MAX_HOURS, | |||||
TIMESHEET_DAILY_MAX_HOURS, | |||||
} from "@/app/api/timesheets/utils"; | |||||
export interface Props extends Omit<ModalProps, "children"> { | export interface Props extends Omit<ModalProps, "children"> { | ||||
onSave: (timeEntry: TimeEntry, recordDate?: string) => Promise<void>; | onSave: (timeEntry: TimeEntry, recordDate?: string) => Promise<void>; | ||||
@@ -277,7 +280,10 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||||
/> | /> | ||||
{formState.errors.root?.message && ( | {formState.errors.root?.message && ( | ||||
<Typography variant="caption" color="error"> | <Typography variant="caption" color="error"> | ||||
{t(formState.errors.root.message, { DAILY_NORMAL_MAX_HOURS })} | |||||
{t(formState.errors.root.message, { | |||||
DAILY_NORMAL_MAX_HOURS, | |||||
TIMESHEET_DAILY_MAX_HOURS, | |||||
})} | |||||
</Typography> | </Typography> | ||||
)} | )} | ||||
<Box display="flex" justifyContent="flex-end" gap={1}> | <Box display="flex" justifyContent="flex-end" gap={1}> | ||||
@@ -30,7 +30,6 @@ export interface Props { | |||||
leaveTypes: LeaveType[]; | leaveTypes: LeaveType[]; | ||||
allProjects: ProjectWithTasks[]; | allProjects: ProjectWithTasks[]; | ||||
assignedProjects: AssignedProject[]; | assignedProjects: AssignedProject[]; | ||||
username: string; | |||||
defaultLeaveRecords: RecordLeaveInput; | defaultLeaveRecords: RecordLeaveInput; | ||||
defaultTimesheets: RecordTimesheetInput; | defaultTimesheets: RecordTimesheetInput; | ||||
holidays: HolidaysResult[]; | holidays: HolidaysResult[]; | ||||
@@ -48,7 +47,6 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||||
leaveTypes, | leaveTypes, | ||||
allProjects, | allProjects, | ||||
assignedProjects, | assignedProjects, | ||||
username, | |||||
defaultLeaveRecords, | defaultLeaveRecords, | ||||
defaultTimesheets, | defaultTimesheets, | ||||
holidays, | holidays, | ||||
@@ -180,7 +178,6 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||||
onClose={handleCloseTimesheetModal} | onClose={handleCloseTimesheetModal} | ||||
allProjects={allProjects} | allProjects={allProjects} | ||||
assignedProjects={assignedProjects} | assignedProjects={assignedProjects} | ||||
username={username} | |||||
defaultTimesheets={defaultTimesheets} | defaultTimesheets={defaultTimesheets} | ||||
leaveRecords={defaultLeaveRecords} | leaveRecords={defaultLeaveRecords} | ||||
/> | /> | ||||
@@ -191,7 +188,6 @@ const UserWorkspacePage: React.FC<Props> = ({ | |||||
onClose={handleCloseLeaveModal} | onClose={handleCloseLeaveModal} | ||||
defaultLeaveRecords={defaultLeaveRecords} | defaultLeaveRecords={defaultLeaveRecords} | ||||
timesheetRecords={defaultTimesheets} | timesheetRecords={defaultTimesheets} | ||||
username={username} | |||||
/> | /> | ||||
{assignedProjects.length > 0 ? ( | {assignedProjects.length > 0 ? ( | ||||
<AssignedProjects assignedProjects={assignedProjects} /> | <AssignedProjects assignedProjects={assignedProjects} /> | ||||
@@ -12,11 +12,7 @@ import { | |||||
} from "@/app/api/timesheets"; | } from "@/app/api/timesheets"; | ||||
import { fetchHolidays } from "@/app/api/holidays"; | import { fetchHolidays } from "@/app/api/holidays"; | ||||
interface Props { | |||||
username: string; | |||||
} | |||||
const UserWorkspaceWrapper: React.FC<Props> = async ({ username }) => { | |||||
const UserWorkspaceWrapper: React.FC = async () => { | |||||
const [ | const [ | ||||
teamLeaves, | teamLeaves, | ||||
teamTimesheets, | teamTimesheets, | ||||
@@ -27,12 +23,12 @@ const UserWorkspaceWrapper: React.FC<Props> = async ({ username }) => { | |||||
leaveTypes, | leaveTypes, | ||||
holidays, | holidays, | ||||
] = await Promise.all([ | ] = await Promise.all([ | ||||
fetchTeamMemberLeaves(username), | |||||
fetchTeamMemberTimesheets(username), | |||||
fetchAssignedProjects(username), | |||||
fetchTeamMemberLeaves(), | |||||
fetchTeamMemberTimesheets(), | |||||
fetchAssignedProjects(), | |||||
fetchProjectWithTasks(), | fetchProjectWithTasks(), | ||||
fetchTimesheets(username), | |||||
fetchLeaves(username), | |||||
fetchTimesheets(), | |||||
fetchLeaves(), | |||||
fetchLeaveTypes(), | fetchLeaveTypes(), | ||||
fetchHolidays(), | fetchHolidays(), | ||||
]); | ]); | ||||
@@ -43,7 +39,6 @@ const UserWorkspaceWrapper: React.FC<Props> = async ({ username }) => { | |||||
teamTimesheets={teamTimesheets} | teamTimesheets={teamTimesheets} | ||||
allProjects={allProjects} | allProjects={allProjects} | ||||
assignedProjects={assignedProjects} | assignedProjects={assignedProjects} | ||||
username={username} | |||||
defaultTimesheets={timesheets} | defaultTimesheets={timesheets} | ||||
defaultLeaveRecords={leaves} | defaultLeaveRecords={leaves} | ||||
leaveTypes={leaveTypes} | leaveTypes={leaveTypes} | ||||