diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index 5e1860dbd..3df5aebe6 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -41,21 +41,33 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId const setActivityTypeFilter = useSetRecoilState(activityTypeState); const hook = useTaskFilter(profile); - const isManagerConnectedUser = activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id); - const canSeeActivity = profile.userProfile?.id === user?.id || isManagerConnectedUser != -1; + const isManagerConnectedUser = useMemo( + () => activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id), + [activeTeamManagers, user?.id] + ); + const canSeeActivity = useMemo( + () => profile.userProfile?.id === user?.id || isManagerConnectedUser != -1, + [isManagerConnectedUser, profile.userProfile?.id, user?.id] + ); const t = useTranslations(); - const breadcrumb = [ - { title: activeTeam?.name || '', href: '/' }, - { title: JSON.parse(t('pages.profile.BREADCRUMB')) || '', href: `/profile/${params.memberId}` } - ]; - - const activityScreens = { - Tasks: , - Screenshots: , - Apps: , - 'Visited Sites': - }; + const breadcrumb = useMemo( + () => [ + { title: activeTeam?.name || '', href: '/' }, + { title: JSON.parse(t('pages.profile.BREADCRUMB')) || '', href: `/profile/${params.memberId}` } + ], + [activeTeam?.name, params.memberId, t] + ); + + const activityScreens = useMemo( + () => ({ + Tasks: , + Screenshots: , + Apps: , + 'Visited Sites': + }), + [hook, profile] + ); const profileIsAuthUser = useMemo(() => profile.isAuthUser, [profile.isAuthUser]); const hookFilterType = useMemo(() => hook.filterType, [hook.filterType]); diff --git a/apps/web/lib/features/task/task-card.tsx b/apps/web/lib/features/task/task-card.tsx index 152ba751d..937afae9e 100644 --- a/apps/web/lib/features/task/task-card.tsx +++ b/apps/web/lib/features/task/task-card.tsx @@ -101,51 +101,64 @@ export function TaskCard(props: Props) { const seconds = useRecoilValue(timerSecondsState); const { activeTaskDailyStat, activeTaskTotalStat, addSeconds } = useTaskStatistics(seconds); const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); - const members = activeTeam?.members || []; - const currentMember = members.find((m) => { - return m.employee.user?.id === profile?.userProfile?.id; - }); + const members = useMemo(() => activeTeam?.members || [], [activeTeam?.members]); + const currentMember = useMemo( + () => + members.find((m) => { + return m.employee.user?.id === profile?.userProfile?.id; + }), + [members, profile?.userProfile?.id] + ); const { h, m } = secondsToTime((activeTaskTotalStat?.duration || 0) + addSeconds); - const totalWork = - isAuthUser && activeAuthTask ? ( -
- {t('pages.taskDetails.TOTAL_TIME')}: - - {h}h : {m}m - -
- ) : ( - <> - ); - + const totalWork = useMemo( + () => + isAuthUser && activeAuthTask ? ( +
+ {t('pages.taskDetails.TOTAL_TIME')}: + + {h}h : {m}m + +
+ ) : ( + <> + ), + [activeAuthTask, h, isAuthUser, m, t] + ); // Daily work - const { h: dh, m: dm } = secondsToTime((activeTaskDailyStat?.duration || 0) + addSeconds); - const todayWork = - isAuthUser && activeAuthTask ? ( -
- {t('common.TOTAL_WORK')} - - {dh}h : {dm}m - -
- ) : ( - <> - ); - + const { h: dh, m: dm } = useMemo( + () => secondsToTime((activeTaskDailyStat?.duration || 0) + addSeconds), + [activeTaskDailyStat?.duration, addSeconds] + ); + const todayWork = useMemo( + () => + isAuthUser && activeAuthTask ? ( +
+ {t('common.TOTAL_WORK')} + + {dh}h : {dm}m + +
+ ) : ( + <> + ), + [activeAuthTask, dh, dm, isAuthUser, t] + ); const memberInfo = useTeamMemberCard(currentMember || undefined); const taskEdition = useTMCardTaskEdit(task); - const activeMembers = task != null && task?.members?.length > 0; - const hasMembers = task?.members && task?.members?.length > 0; - const taskAssignee: ImageOverlapperProps[] = - task?.members?.map((member: any) => { - return { - id: member.user?.id, - url: member.user?.imageUrl, - alt: member.user?.firstName - }; - }) || []; - + const activeMembers = useMemo(() => task != null && task?.members?.length > 0, [task]); + const hasMembers = useMemo(() => task?.members && task?.members?.length > 0, [task?.members]); + const taskAssignee: ImageOverlapperProps[] = useMemo( + () => + task?.members?.map((member: any) => { + return { + id: member.user?.id, + url: member.user?.imageUrl, + alt: member.user?.firstName + }; + }) || [], + [task?.members] + ); return ( <> } & IClassName) { const t = useTranslations(); - const members = task?.members || []; + const members = useMemo(() => task?.members || [], [task?.members]); return (
diff --git a/apps/web/lib/features/task/task-filters.tsx b/apps/web/lib/features/task/task-filters.tsx index ff6c8f95d..9932545f3 100644 --- a/apps/web/lib/features/task/task-filters.tsx +++ b/apps/web/lib/features/task/task-filters.tsx @@ -48,15 +48,22 @@ type StatusFilter = { [x in IStatusType]: string[] }; */ export function useTaskFilter(profile: I_UserProfilePage) { const t = useTranslations(); - const defaultValue = - typeof window !== 'undefined' ? (window.localStorage.getItem('task-tab') as ITab) || null : 'worked'; - + const defaultValue = useMemo( + () => (typeof window !== 'undefined' ? (window.localStorage.getItem('task-tab') as ITab) || null : 'worked'), + [] + ); const { activeTeamManagers, activeTeam } = useOrganizationTeams(); const { user } = useAuthenticateUser(); const { profileDailyPlans } = useDailyPlan(); - const isManagerConnectedUser = activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id); - const canSeeActivity = profile.userProfile?.id === user?.id || isManagerConnectedUser != -1; + const isManagerConnectedUser = useMemo( + () => activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id), + [activeTeamManagers, user?.id] + ); + const canSeeActivity = useMemo( + () => profile.userProfile?.id === user?.id || isManagerConnectedUser != -1, + [isManagerConnectedUser, profile.userProfile?.id, user?.id] + ); const [tab, setTab] = useState(defaultValue || 'worked'); const [filterType, setFilterType] = useState(undefined); @@ -67,14 +74,17 @@ export function useTaskFilter(profile: I_UserProfilePage) { const [taskName, setTaskName] = useState(''); - const tasksFiltered: { [x in ITab]: ITeamTask[] } = { - unassigned: profile.tasksGrouped.unassignedTasks, - assigned: profile.tasksGrouped.assignedTasks, - worked: profile.tasksGrouped.workedTasks, - dailyplan: [] // Change this soon - }; + const tasksFiltered: { [x in ITab]: ITeamTask[] } = useMemo( + () => ({ + unassigned: profile.tasksGrouped.unassignedTasks, + assigned: profile.tasksGrouped.assignedTasks, + worked: profile.tasksGrouped.workedTasks, + dailyplan: [] // Change this soon + }), + [profile.tasksGrouped.assignedTasks, profile.tasksGrouped.unassignedTasks, profile.tasksGrouped.workedTasks] + ); - const tasks = tasksFiltered[tab]; + const tasks = useMemo(() => tasksFiltered[tab], [tab, tasksFiltered]); const outclickFilterCard = useOutsideClick(() => { if (filterType === 'search' && taskName.trim().length === 0) { diff --git a/apps/web/lib/features/task/task-status.tsx b/apps/web/lib/features/task/task-status.tsx index 72d78f1f1..df23da5ab 100644 --- a/apps/web/lib/features/task/task-status.tsx +++ b/apps/web/lib/features/task/task-status.tsx @@ -775,18 +775,18 @@ export function TaskStatus({ isEpic }: PropsWithChildren< TStatusItem & - IClassName & { - active?: boolean; - issueType?: 'status' | 'issue'; - showIssueLabels?: boolean; - forDetails?: boolean; - titleClassName?: string; - cheched?: boolean; - sidebarUI?: boolean; - value?: string; - isVersion?: boolean; - isEpic?: boolean; - } + IClassName & { + active?: boolean; + issueType?: 'status' | 'issue'; + showIssueLabels?: boolean; + forDetails?: boolean; + titleClassName?: string; + cheched?: boolean; + sidebarUI?: boolean; + value?: string; + isVersion?: boolean; + isEpic?: boolean; + } >) { const { theme } = useTheme(); const readableColorHex = readableColor(backgroundColor || (theme === 'light' ? '#FFF' : '#000')); @@ -839,8 +839,8 @@ export function TaskStatus({ style={ isVersion || isEpic ? { - color: theme === 'light' ? '#000' : '#FFF' - } + color: theme === 'light' ? '#000' : '#FFF' + } : {} } > @@ -996,7 +996,7 @@ export function StatusDropdown({ sidebarUI && ['text-xs'], 'text-dark dark:text-white bg-[#F2F2F2] dark:bg-dark--theme-light', forDetails && - 'bg-transparent border dark:border-[#FFFFFF33] dark:bg-[#1B1D22]', + 'bg-transparent border dark:border-[#FFFFFF33] dark:bg-[#1B1D22]', taskStatusClassName )} name={ diff --git a/apps/web/lib/features/task/task-times.tsx b/apps/web/lib/features/task/task-times.tsx index 79fd6b9f3..92d3ea545 100644 --- a/apps/web/lib/features/task/task-times.tsx +++ b/apps/web/lib/features/task/task-times.tsx @@ -4,6 +4,7 @@ import { IClassName, ITeamTask, Nullable, OT_Member } from '@app/interfaces'; import { clsxm } from '@app/utils'; import { Text, Tooltip } from 'lib/components'; import { useTranslations } from 'next-intl'; +import { useMemo } from 'react'; type Props = { task: Nullable; @@ -18,23 +19,35 @@ type Props = { export function TaskTimes({ className, task, memberInfo, showDaily = true, showTotal = true, isBlock = false }: Props) { // For public page const { activeTeam } = useOrganizationTeams(); - const currentMember = activeTeam?.members.find((member) => member.id === memberInfo?.member?.id || memberInfo?.id); + const currentMember = useMemo( + () => activeTeam?.members.find((member) => member.id === memberInfo?.member?.id || memberInfo?.id), + [activeTeam?.members, memberInfo?.id, memberInfo?.member?.id] + ); - const { h, m } = secondsToTime( - (currentMember?.totalWorkedTasks && - currentMember?.totalWorkedTasks?.length && - currentMember?.totalWorkedTasks - .filter((t) => t.id === task?.id) - .reduce((previousValue, currentValue) => previousValue + currentValue.duration, 0)) || - 0 + const { h, m } = useMemo( + () => + secondsToTime( + (currentMember?.totalWorkedTasks && + currentMember?.totalWorkedTasks?.length && + currentMember?.totalWorkedTasks + .filter((t) => t.id === task?.id) + .reduce((previousValue, currentValue) => previousValue + currentValue.duration, 0)) || + 0 + ), + [currentMember?.totalWorkedTasks, task?.id] ); - const { h: dh, m: dm } = secondsToTime( - (currentMember?.totalTodayTasks && - currentMember?.totalTodayTasks.length && - currentMember?.totalTodayTasks - .filter((t) => t.id === task?.id) - .reduce((previousValue, currentValue) => previousValue + currentValue.duration, 0)) || - 0 + + const { h: dh, m: dm } = useMemo( + () => + secondsToTime( + (currentMember?.totalTodayTasks && + currentMember?.totalTodayTasks.length && + currentMember?.totalTodayTasks + .filter((t) => t.id === task?.id) + .reduce((previousValue, currentValue) => previousValue + currentValue.duration, 0)) || + 0 + ), + [currentMember?.totalTodayTasks, task?.id] ); return ( diff --git a/apps/web/lib/features/user-profile-tasks.tsx b/apps/web/lib/features/user-profile-tasks.tsx index 027b545fa..f7857f225 100644 --- a/apps/web/lib/features/user-profile-tasks.tsx +++ b/apps/web/lib/features/user-profile-tasks.tsx @@ -4,6 +4,7 @@ import { UserProfilePlans } from 'lib/features'; import { TaskCard } from './task/task-card'; import { I_TaskFilter } from './task/task-filters'; import { useTranslations } from 'next-intl'; +import { useMemo } from 'react'; type Props = { tabFiltered: I_TaskFilter; profile: I_UserProfilePage; @@ -23,10 +24,11 @@ export function UserProfileTask({ profile, tabFiltered }: Props) { /** * When tab is worked, then filter exclude the active task */ - const tasks = tabFiltered.tasksFiltered; + const tasks = useMemo(() => tabFiltered.tasksFiltered, [tabFiltered.tasksFiltered]); - const otherTasks = tasks.filter((t) => - profile.member?.running == true ? t.id !== profile.activeUserTeamTask?.id : t + const otherTasks = useMemo( + () => tasks.filter((t) => (profile.member?.running == true ? t.id !== profile.activeUserTeamTask?.id : t)), + [profile.activeUserTeamTask?.id, profile.member?.running, tasks] ); // const data = otherTasks.length < 10 ? otherTasks : data;