From c39434c7d5574a242e0e09c0dddedebee53c3d60 Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Wed, 17 Jan 2024 14:02:07 +0200 Subject: [PATCH 01/15] fix: Apps & Screenshots Page --- .../app/[locale]/profile/[memberId]/page.tsx | 41 ++++++++++-------- apps/web/app/[locale]/task/[id]/page.tsx | 2 +- .../hooks/features/useOrganizationTeams.ts | 8 ++-- .../hooks/features/useTimeDailyActivity.ts | 42 +++++++------------ apps/web/app/hooks/features/useTimeSlot.ts | 6 +-- .../app/hooks/features/useUserProfilePage.ts | 3 +- apps/web/lib/features/activity/apps.tsx | 13 +++--- .../lib/features/activity/task-activity.tsx | 5 +++ .../lib/features/activity/visited-sites.tsx | 14 +++++-- .../user-team-card-activity.tsx | 42 +++++++++---------- 10 files changed, 90 insertions(+), 86 deletions(-) create mode 100644 apps/web/lib/features/activity/task-activity.tsx diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index 11928f482..a617bafd2 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -12,23 +12,24 @@ import { ArrowLeft } from 'lib/components/svgs'; import { TaskFilter, Timer, TimerStatus, UserProfileTask, getTimerStatusValue, useTaskFilter } from 'lib/features'; import { MainHeader, MainLayout } from 'lib/layout'; import Link from 'next/link'; -import { useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { useTranslations } from 'next-intl'; import stc from 'string-to-color'; import { useRecoilValue } from 'recoil'; import { fullWidthState } from '@app/stores/fullWidth'; -import { ActivityFilters } from '@app/constants'; import { ScreenshootTab } from 'lib/features/activity/screenshoots'; import { AppsTab } from 'lib/features/activity/apps'; import { VisitedSitesTab } from 'lib/features/activity/visited-sites'; -const Profile = ({ params }: { params: { memberId: string } }) => { +type FilterTab = 'Tasks' | 'Screenshots' | 'Apps' | 'Visited Sites'; + +const Profile = React.memo(function ProfilePage({ params }: { params: { memberId: string } }) { const profile = useUserProfilePage(); const { user } = useAuthenticateUser(); const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); const fullWidth = useRecoilValue(fullWidthState); - const [activityFilter, setActivityFilter] = useState(ActivityFilters.TASKS); + const [activityFilter, setActivityFilter] = useState('Tasks'); const hook = useTaskFilter(profile); const canSeeActivity = profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER'; @@ -41,9 +42,23 @@ const Profile = ({ params }: { params: { memberId: string } }) => { console.log({ activityFilter }); + const activityScreens = { + Tasks: , + Screenshots: , + Apps: , + 'Visited Sites': + }; + const profileIsAuthUser = useMemo(() => profile.isAuthUser, [profile.isAuthUser]); const hookFilterType = useMemo(() => hook.filterType, [hook.filterType]); + const changeActivityFilter = useCallback( + (filter: FilterTab) => { + setActivityFilter(filter); + }, + [setActivityFilter] + ); + return ( <> @@ -80,7 +95,7 @@ const Profile = ({ params }: { params: { memberId: string } }) => { {hook.tab == 'worked' && canSeeActivity && (
- {Object.values(ActivityFilters).map((filter: ActivityFilters, i) => ( + {Object.keys(activityScreens).map((filter, i) => (
{i !== 0 && }
{ 'text-gray-500', activityFilter == filter && 'text-black dark:text-white' )} - onClick={() => setActivityFilter(filter)} + onClick={() => changeActivityFilter(filter as FilterTab)} > {filter}
@@ -99,22 +114,12 @@ const Profile = ({ params }: { params: { memberId: string } }) => { )} - {hook.tab == 'worked' && activityFilter == ActivityFilters.TASKS ? ( - - ) : hook.tab == 'worked' && canSeeActivity && activityFilter == ActivityFilters.SCREENSHOOTS ? ( - - ) : hook.tab == 'worked' && canSeeActivity && activityFilter == ActivityFilters.APPS ? ( - - ) : hook.tab == 'worked' && canSeeActivity && activityFilter == ActivityFilters.VISITED_SITES ? ( - - ) : ( - - )} + {activityScreens[activityFilter] ?? null} ); -}; +}); function UserProfileDetail({ member }: { member?: OT_Member }) { const user = useMemo(() => member?.employee.user, [member?.employee.user]); diff --git a/apps/web/app/[locale]/task/[id]/page.tsx b/apps/web/app/[locale]/task/[id]/page.tsx index b285b4610..7541a3788 100644 --- a/apps/web/app/[locale]/task/[id]/page.tsx +++ b/apps/web/app/[locale]/task/[id]/page.tsx @@ -84,7 +84,7 @@ const TaskDetails = () => { {/* */} {/* */} - {/* */} + {/* */}
diff --git a/apps/web/app/hooks/features/useOrganizationTeams.ts b/apps/web/app/hooks/features/useOrganizationTeams.ts index 79d11a0da..cab8fa04a 100644 --- a/apps/web/app/hooks/features/useOrganizationTeams.ts +++ b/apps/web/app/hooks/features/useOrganizationTeams.ts @@ -213,14 +213,14 @@ export function useOrganizationTeams() { const setActiveTeam = useCallback( (team: (typeof teams)[0]) => { - setActiveTeamIdCookie(team.id); - setOrganizationIdCookie(team.organizationId); + setActiveTeamIdCookie(team?.id); + setOrganizationIdCookie(team?.organizationId); // This must be called at the end (Update store) - setActiveTeamId(team.id); + setActiveTeamId(team?.id); // Set Project Id to cookie // TODO: Make it dynamic when we add Dropdown in Navbar - if (team && team.projects && team.projects.length) { + if (team && team?.projects && team.projects.length) { setActiveProjectIdCookie(team.projects[0].id); } }, diff --git a/apps/web/app/hooks/features/useTimeDailyActivity.ts b/apps/web/app/hooks/features/useTimeDailyActivity.ts index dff66b892..4accbb60c 100644 --- a/apps/web/app/hooks/features/useTimeDailyActivity.ts +++ b/apps/web/app/hooks/features/useTimeDailyActivity.ts @@ -3,31 +3,30 @@ import { useCallback, useEffect } from 'react'; import { useQuery } from '../useQuery'; import { useRecoilState } from 'recoil'; -import { timeAppVisitedDetail, timeAppsState, timeVisitedSitesState } from '@app/stores/time-slot'; +import { timeAppsState, timeVisitedSitesState } from '@app/stores/time-slot'; import moment from 'moment'; import { useAuthenticateUser } from './useAuthenticateUser'; import { getTimerDailyRequestAPI } from '@app/services/client/api'; -import { useUserProfilePage } from './useUserProfilePage'; +import { IUser } from '@app/interfaces'; -export function useTimeDailyActivity(type: string, id?: string) { - const profile = useUserProfilePage(); +export function useTimeDailyActivity(type: string, userProfile: IUser | undefined, id?: string) { const { user } = useAuthenticateUser(); const [visitedApps, setVisitedApps] = useRecoilState(timeAppsState); - const [visitedAppDetail, setVisitedAppDetail] = useRecoilState(timeAppVisitedDetail); + // const [visitedAppDetail, setVisitedAppDetail] = useRecoilState(timeAppVisitedDetail); const [visitedSites, setVisitedSites] = useRecoilState(timeVisitedSitesState); const { loading, queryCall } = useQuery(getTimerDailyRequestAPI); const getVisitedApps = useCallback( - ({ title }: { title?: string }) => { + (title?: string) => { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); - const employeeId = id ?? profile.member?.employeeId ?? ''; - if (profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + const employeeId = id ? id : userProfile?.employee?.id; + if (userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { queryCall({ tenantId: user?.tenantId ?? '', organizationId: user?.employee.organizationId ?? '', - employeeId: employeeId, + employeeId: employeeId ?? '', todayEnd, type, todayStart, @@ -36,37 +35,26 @@ export function useTimeDailyActivity(type: string, id?: string) { .then((response) => { if (response.data) { // @ts-ignore - if (title) setVisitedAppDetail(response.data[0]); - else if (type == 'APP') setVisitedApps(response.data); + // if (title) setVisitedAppDetail(response.data[0]); + if (type == 'APP') setVisitedApps(response.data); else setVisitedSites(response.data); } }) .catch((err) => console.log(err)); } }, - [ - profile.member?.employeeId, - profile.userProfile?.id, - user?.id, - user?.role?.name, - user?.tenantId, - user?.employee.organizationId, - queryCall, - type, - setVisitedAppDetail, - setVisitedApps, - setVisitedSites - ] + // eslint-disable-next-line react-hooks/exhaustive-deps + [id, userProfile, queryCall, type] ); useEffect(() => { - getVisitedApps({}); - }, [user, getVisitedApps]); + getVisitedApps(); + }, [getVisitedApps]); return { visitedApps, visitedSites, - visitedAppDetail, + // visitedAppDetail, getVisitedApps, loading }; diff --git a/apps/web/app/hooks/features/useTimeSlot.ts b/apps/web/app/hooks/features/useTimeSlot.ts index 949c95aed..83b0b54f7 100644 --- a/apps/web/app/hooks/features/useTimeSlot.ts +++ b/apps/web/app/hooks/features/useTimeSlot.ts @@ -20,8 +20,8 @@ export function useTimeSlots(id?: string) { const getTimeSlots = useCallback(() => { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); - const employeeId = id ? id : profile.member?.employeeId ; - if ( profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + const employeeId = id ? id : profile.member?.employeeId; + if (profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { queryCall({ tenantId: user?.tenantId ?? '', organizationId: user?.employee.organizationId ?? '', @@ -63,7 +63,7 @@ export function useTimeSlots(id?: string) { useEffect(() => { getTimeSlots(); - }, [user, getTimeSlots]); + }, [getTimeSlots]); return { timeSlots, diff --git a/apps/web/app/hooks/features/useUserProfilePage.ts b/apps/web/app/hooks/features/useUserProfilePage.ts index 790a739b0..4a03c87b5 100644 --- a/apps/web/app/hooks/features/useUserProfilePage.ts +++ b/apps/web/app/hooks/features/useUserProfilePage.ts @@ -42,7 +42,8 @@ export function useUserProfilePage() { if (employeeId) { getTasksStatsData(employeeId); } - }, [getTasksStatsData, employeeId]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [employeeId]); const assignTask = useCallback( (task: ITeamTask) => { diff --git a/apps/web/lib/features/activity/apps.tsx b/apps/web/lib/features/activity/apps.tsx index c83eca996..68c002ea8 100644 --- a/apps/web/lib/features/activity/apps.tsx +++ b/apps/web/lib/features/activity/apps.tsx @@ -3,13 +3,14 @@ import { AppVisitedSkeleton } from './components/app-visited-skeleton'; import { groupAppsByHour } from '@app/helpers/array-data'; import { useTranslations } from 'next-intl'; import AppVisitedItem from './components/app-visited-Item'; +import { IUser } from '@app/interfaces'; // import { AppVisitedModal } from './components/app-visited-details'; -export function AppsTab({ id}: {id?: string}) { - const { visitedApps, loading } = useTimeDailyActivity('APP', id); +export function AppsTab({ id, userProfile }: { id?: string; userProfile?: IUser }) { + const { visitedApps, loading } = useTimeDailyActivity('URL', userProfile, id); const t = useTranslations(); const apps = groupAppsByHour(visitedApps); - console.log("INTO APP TAB"); + console.log('INTO APP TAB'); return (
{/* TODO: Filters components */}
@@ -30,11 +31,7 @@ export function AppsTab({ id}: {id?: string}) { {app.apps?.map((item, i) => (
{/* */} - + {/* */}
))} diff --git a/apps/web/lib/features/activity/task-activity.tsx b/apps/web/lib/features/activity/task-activity.tsx new file mode 100644 index 000000000..32efad3c9 --- /dev/null +++ b/apps/web/lib/features/activity/task-activity.tsx @@ -0,0 +1,5 @@ +export function TaskActivity(){ + return ( +
+ ) +} \ No newline at end of file diff --git a/apps/web/lib/features/activity/visited-sites.tsx b/apps/web/lib/features/activity/visited-sites.tsx index b38a32506..14b6e595f 100644 --- a/apps/web/lib/features/activity/visited-sites.tsx +++ b/apps/web/lib/features/activity/visited-sites.tsx @@ -3,9 +3,17 @@ import { AppVisitedSkeleton } from './components/app-visited-skeleton'; import { groupAppsByHour } from '@app/helpers/array-data'; import { useTranslations } from 'next-intl'; import AppVisitedItem from './components/app-visited-Item'; +import React from 'react'; +import { IUser } from '@app/interfaces'; -export function VisitedSitesTab({ id }: { id?: string}) { - const { visitedSites, loading } = useTimeDailyActivity('URL', id); +export const VisitedSitesTab = React.memo(function VisitedSitesT({ + id, + userProfile +}: { + id?: string; + userProfile?: IUser; +}) { + const { visitedSites, loading } = useTimeDailyActivity('URL', userProfile, id); const t = useTranslations(); const sites = groupAppsByHour(visitedSites); return ( @@ -47,4 +55,4 @@ export function VisitedSitesTab({ id }: { id?: string}) { )}
); -} +}); diff --git a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx index 7dca90bdb..4763ef257 100644 --- a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx +++ b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx @@ -34,34 +34,34 @@ const UserTeamActivity = ({ member, showActivity }: { member: OT_Member | undefi
{t('timer.TIME_ACTIVITY')} -

{activityPercent ? activityPercent.toFixed(2): "00"} %

+

+ {activityPercent ? activityPercent.toFixed(2) : '00'} % +

-
- {Object.values(ActivityFilters) - .filter((el) => el !== 'Tasks') - .map((filter: string) => ( - - clsxm( - 'w-full rounded-lg py-2.5 text-sm font-medium leading-5', - ' focus:outline-none focus:ring-2', - selected - ? 'bg-white dark:bg-dark text-blue-700 shadow' - : ' hover:bg-white/[0.50]' - ) - } - > - {filter} - - ))} + {Object.values(ActivityFilters).map((filter: string) => ( + + clsxm( + 'w-full rounded-lg py-2.5 text-sm font-medium leading-5', + ' focus:outline-none focus:ring-2', + selected + ? 'bg-white dark:bg-dark text-blue-700 shadow' + : ' hover:bg-white/[0.50]' + ) + } + > + {filter} + + ))} + Tasks @@ -69,7 +69,7 @@ const UserTeamActivity = ({ member, showActivity }: { member: OT_Member | undefi - + From c2122d75b0d6a53a0cf439e2aa9f965535507725 Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Wed, 17 Jan 2024 15:47:11 +0200 Subject: [PATCH 02/15] feat: add icon to expand Card --- apps/web/components/ui/svgs/expand.tsx | 29 ++++++++++++ .../features/team/user-team-card/index.tsx | 45 +++++++++++++------ .../user-team-card-activity.tsx | 16 ++++--- 3 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 apps/web/components/ui/svgs/expand.tsx diff --git a/apps/web/components/ui/svgs/expand.tsx b/apps/web/components/ui/svgs/expand.tsx new file mode 100644 index 000000000..98819f67a --- /dev/null +++ b/apps/web/components/ui/svgs/expand.tsx @@ -0,0 +1,29 @@ +export function ExpandIcon({ width, height, fill = '#8C7AE4' }: { width: number; height: number; fill?: string }) { + return ( + + + + ); +} + +export function CollapseUpIcon({ width, height, fill = '#8C7AE4' }: { width: number; height: number; fill?: string }) { + return ( + + + + + + + + + + + + + ); +} diff --git a/apps/web/lib/features/team/user-team-card/index.tsx b/apps/web/lib/features/team/user-team-card/index.tsx index dc1f88829..49a01388c 100644 --- a/apps/web/lib/features/team/user-team-card/index.tsx +++ b/apps/web/lib/features/team/user-team-card/index.tsx @@ -16,6 +16,7 @@ import { UserInfo } from './user-info'; import { UserTeamCardMenu } from './user-team-card-menu'; import React from 'react'; import UserTeamActivity from './user-team-card-activity'; +import { CollapseUpIcon, ExpandIcon } from '@components/ui/svgs/expand'; type IUserTeamCard = { active?: boolean; @@ -120,12 +121,24 @@ export function UserTeamCard({ {/* Task information */} - +
+ +

setShowActivity((prev) => !prev)} + > + {!showActivity ? ( + + ) : ( + + )} +

+
{/* TaskTimes */} @@ -148,17 +161,23 @@ export function UserTeamCard({ {/* TodayWorkedTime */} -
setShowActivity((prev) => !prev)}> - +
+ +

setShowActivity((prev) => !prev)} + className="flex items-center w-8 h-8 border dark:border-gray-800 rounded justify-center cursor-pointer text-center" + > + {!showActivity ? ( + + ) : ( + + )} +

{/* Card menu */}
{menu}
- + { - const id = member?.employeeId ?? ''; +const UserTeamActivity = ({ member, showActivity }: { member: IUser | undefined; showActivity: boolean }) => { + const id = member?.employee?.id ?? ''; const { timeSlots } = useTimeSlots(id); const t = useTranslations(); const activityPercent = timeSlots.reduce((acc, el) => acc + el.percentage, 0) / timeSlots.length; + console.log('ACTIVITY TEAM M.'); return ( - Tasks + + {/* */} + - + - + From 402bbed028aba1474b41064030b56cbb018088e9 Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Wed, 17 Jan 2024 16:08:26 +0200 Subject: [PATCH 03/15] feat: add global state for activity filter type --- apps/web/app/stores/activity-type.ts | 6 ++++++ .../lib/features/team/user-team-card/index.tsx | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 apps/web/app/stores/activity-type.ts diff --git a/apps/web/app/stores/activity-type.ts b/apps/web/app/stores/activity-type.ts new file mode 100644 index 000000000..68b022ef0 --- /dev/null +++ b/apps/web/app/stores/activity-type.ts @@ -0,0 +1,6 @@ +import { atom } from 'recoil'; + +export const activityTypeState = atom<'DATE' | 'TICKET'>({ + key: 'activityTypeState', + default: 'DATE' +}); diff --git a/apps/web/lib/features/team/user-team-card/index.tsx b/apps/web/lib/features/team/user-team-card/index.tsx index 49a01388c..9d728e8fb 100644 --- a/apps/web/lib/features/team/user-team-card/index.tsx +++ b/apps/web/lib/features/team/user-team-card/index.tsx @@ -9,7 +9,7 @@ import { Card, HorizontalSeparator, InputField, Text, VerticalSeparator } from ' import { DraggerIcon } from 'lib/components/svgs'; import { TaskTimes, TodayWorkedTime } from 'lib/features'; import { useTranslations } from 'next-intl'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import { TaskEstimateInfo } from './task-estimate'; import { TaskInfo } from './task-info'; import { UserInfo } from './user-info'; @@ -17,6 +17,7 @@ import { UserTeamCardMenu } from './user-team-card-menu'; import React from 'react'; import UserTeamActivity from './user-team-card-activity'; import { CollapseUpIcon, ExpandIcon } from '@components/ui/svgs/expand'; +import { activityTypeState } from '@app/stores/activity-type'; type IUserTeamCard = { active?: boolean; @@ -50,9 +51,15 @@ export function UserTeamCard({ const { collaborativeSelect, user_selected, onUserSelect } = useCollaborative(memberInfo.memberUser); const seconds = useRecoilValue(timerSecondsState); + const setActivityFilter = useSetRecoilState(activityTypeState); const { activeTaskTotalStat, addSeconds } = useTaskStatistics(seconds); const [showActivity, setShowActivity] = React.useState(false); + const showActivityFilter = (type: 'DATE' | 'TICKET') => { + setShowActivity((prev) => !prev); + setActivityFilter(type); + }; + let totalWork = <>; if (memberInfo.isAuthUser) { const { h, m } = secondsToTime( @@ -112,8 +119,8 @@ export function UserTeamCard({ )} >
-
- +
+
{/* Show user name, email and image */} @@ -130,7 +137,7 @@ export function UserTeamCard({ />

setShowActivity((prev) => !prev)} + onClick={() => showActivityFilter('TICKET')} > {!showActivity ? ( @@ -164,7 +171,7 @@ export function UserTeamCard({

setShowActivity((prev) => !prev)} + onClick={() => showActivityFilter('DATE')} className="flex items-center w-8 h-8 border dark:border-gray-800 rounded justify-center cursor-pointer text-center" > {!showActivity ? ( From 774fd9ba9517de4c27da04c91849228066fb0f38 Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Wed, 17 Jan 2024 19:53:57 +0200 Subject: [PATCH 04/15] feat: add hook to fetch Worked Task for Member --- apps/web/app/hooks/features/useUserDetails.ts | 66 +++++++++++++++++++ .../user-team-card-activity.tsx | 2 + .../team/user-team-card/user-worked-task.tsx | 10 +++ 3 files changed, 78 insertions(+) create mode 100644 apps/web/app/hooks/features/useUserDetails.ts create mode 100644 apps/web/lib/features/team/user-team-card/user-worked-task.tsx diff --git a/apps/web/app/hooks/features/useUserDetails.ts b/apps/web/app/hooks/features/useUserDetails.ts new file mode 100644 index 000000000..e624a71da --- /dev/null +++ b/apps/web/app/hooks/features/useUserDetails.ts @@ -0,0 +1,66 @@ +'use client'; + +import { ITeamTask } from '@app/interfaces'; +import { useCallback, useEffect } from 'react'; +import { useAuthenticateUser } from './useAuthenticateUser'; +import { useAuthTeamTasks } from './useAuthTeamTasks'; +import { useOrganizationTeams } from './useOrganizationTeams'; +import { useTaskStatistics } from './useTaskStatistics'; +import { useTeamTasks } from './useTeamTasks'; + +export function useUserDetails(memberId: string) { + const { activeTeam } = useOrganizationTeams(); + const { activeTeamTask, updateTask } = useTeamTasks(); + + const { user: auth } = useAuthenticateUser(); + const { getTasksStatsData } = useTaskStatistics(); + + const members = activeTeam?.members || []; + + const matchUser = members.find((m) => { + return m.employee.userId === memberId; + }); + + const isAuthUser = auth?.employee?.userId === memberId; + + const activeUserTeamTask = isAuthUser ? activeTeamTask : matchUser?.lastWorkedTask; + + const userProfile = isAuthUser ? auth : matchUser?.employee.user; + + const employeeId = isAuthUser ? auth?.employee?.id : matchUser?.employeeId; + + /* Filtering the tasks */ + const tasksGrouped = useAuthTeamTasks(userProfile); + + useEffect(() => { + if (employeeId) { + getTasksStatsData(employeeId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [employeeId]); + + const assignTask = useCallback( + (task: ITeamTask) => { + if (!matchUser?.employeeId) { + return Promise.resolve(); + } + + return updateTask({ + ...task, + members: [...task.members, (matchUser?.employeeId ? { id: matchUser?.employeeId } : {}) as any] + }); + }, + [updateTask, matchUser] + ); + + return { + isAuthUser, + activeUserTeamTask, + userProfile, + tasksGrouped, + member: matchUser, + assignTask + }; +} + +export type I_UserProfilePage = ReturnType; diff --git a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx index d8636686c..36d641b4d 100644 --- a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx +++ b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx @@ -10,6 +10,7 @@ import { clsxm } from '@app/utils'; import { ScreenshootTeamTab } from 'lib/features/activity/screenshoots'; import { AppsTab } from 'lib/features/activity/apps'; import { VisitedSitesTab } from 'lib/features/activity/visited-sites'; +import { UserWokedTaskTab } from './user-worked-task'; // import { UserProfileTask } from 'lib/features/user-profile-tasks'; const UserTeamActivity = ({ member, showActivity }: { member: IUser | undefined; showActivity: boolean }) => { @@ -65,6 +66,7 @@ const UserTeamActivity = ({ member, showActivity }: { member: IUser | undefined; {/* */} + diff --git a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx new file mode 100644 index 000000000..2b6f7eda2 --- /dev/null +++ b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx @@ -0,0 +1,10 @@ +import { useUserDetails } from '@app/hooks/features/useUserDetails'; +import { useTaskFilter } from 'lib/features/task/task-filters'; +import { UserProfileTask } from 'lib/features/user-profile-tasks'; + +export function UserWokedTaskTab({ id }: { id: string }) { + const profile = useUserDetails(id); + const hook = useTaskFilter(profile); + + return ; +} From d25254a0237c47bc27b562df1673041e231ad352 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 07:22:23 +0000 Subject: [PATCH 05/15] implement PUT organization-projects/setting/:id api on frontend --- .../setting/[id]/route.ts | 20 +++++++++---------- .../client/api/organization-projects.ts | 8 +++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/apps/web/app/api/organization-projects/setting/[id]/route.ts b/apps/web/app/api/organization-projects/setting/[id]/route.ts index 93c6816d2..830715142 100644 --- a/apps/web/app/api/organization-projects/setting/[id]/route.ts +++ b/apps/web/app/api/organization-projects/setting/[id]/route.ts @@ -10,15 +10,13 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) const { id } = params; const body = await req.json(); - switch (req.method) { - case 'PUT': - return $res( - await editOrganizationProjectsSettingsRequest({ - bearer_token: access_token, - id, - datas: body, - tenantId - }) - ); - } + + const response = await editOrganizationProjectsSettingsRequest({ + bearer_token: access_token, + id, + datas: body, + tenantId + }); + + $res(response.data); } diff --git a/apps/web/app/services/client/api/organization-projects.ts b/apps/web/app/services/client/api/organization-projects.ts index 84f4c5d64..7239c4081 100644 --- a/apps/web/app/services/client/api/organization-projects.ts +++ b/apps/web/app/services/client/api/organization-projects.ts @@ -1,11 +1,9 @@ import { IProject } from '@app/interfaces'; -import api from '../axios'; +import api, { put } from '../axios'; export function editOrganizationProjectSettingAPI(id: string, data: any, tenantId?: string) { - return api.put(`/organization-projects/setting/${id}`, data, { - headers: { - 'Tenant-Id': tenantId - } + return put(`/organization-projects/setting/${id}`, data, { + tenantId }); } From 7552607f91c08503b88a94f1907108ff38118de5 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 11:01:05 +0000 Subject: [PATCH 06/15] implement PUT organization-projects/:id api on frontend --- .../app/api/organization-projects/[id]/route.ts | 17 +++++++++-------- .../client/api/organization-projects.ts | 8 +++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/web/app/api/organization-projects/[id]/route.ts b/apps/web/app/api/organization-projects/[id]/route.ts index 88a982d9c..0b2242eb3 100644 --- a/apps/web/app/api/organization-projects/[id]/route.ts +++ b/apps/web/app/api/organization-projects/[id]/route.ts @@ -9,14 +9,15 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const { id } = params; + const body = await req.json(); - return $res( - await editOrganizationProjectsRequest({ - bearer_token: access_token, - id, - datas: body, - tenantId - }) - ); + const response = await editOrganizationProjectsRequest({ + bearer_token: access_token, + id, + datas: body, + tenantId + }); + + return $res(response.data); } diff --git a/apps/web/app/services/client/api/organization-projects.ts b/apps/web/app/services/client/api/organization-projects.ts index 7239c4081..1f2d7243f 100644 --- a/apps/web/app/services/client/api/organization-projects.ts +++ b/apps/web/app/services/client/api/organization-projects.ts @@ -1,5 +1,5 @@ import { IProject } from '@app/interfaces'; -import api, { put } from '../axios'; +import { put } from '../axios'; export function editOrganizationProjectSettingAPI(id: string, data: any, tenantId?: string) { return put(`/organization-projects/setting/${id}`, data, { @@ -8,9 +8,7 @@ export function editOrganizationProjectSettingAPI(id: string, data: any, tenantI } export function editOrganizationProjectAPI(id: string, data: any, tenantId?: string) { - return api.put(`/organization-projects/${id}`, data, { - headers: { - 'Tenant-Id': tenantId - } + return put(`/organization-projects/${id}`, data, { + tenantId }); } From 4e1c84377f7244a66001e1516c9b59e0a4f71b6d Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 11:58:09 +0000 Subject: [PATCH 07/15] implement organization-team-employee/:id on frontend --- .../api/organization-team-employee/[id]/route.ts | 16 ++++++++-------- .../client/api/organization-team-employee.ts | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/web/app/api/organization-team-employee/[id]/route.ts b/apps/web/app/api/organization-team-employee/[id]/route.ts index 654aebb94..e2c1246b6 100644 --- a/apps/web/app/api/organization-team-employee/[id]/route.ts +++ b/apps/web/app/api/organization-team-employee/[id]/route.ts @@ -15,15 +15,15 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) const { id } = params; + const response = await updateOrganizationTeamEmployeeRequest({ + id: id as string, + bearer_token: access_token, + tenantId, + body: body + }); + if (id) { - return $res( - await updateOrganizationTeamEmployeeRequest({ - id: id as string, - bearer_token: access_token, - tenantId, - body: body - }) - ); + return $res(response.data); } } diff --git a/apps/web/app/services/client/api/organization-team-employee.ts b/apps/web/app/services/client/api/organization-team-employee.ts index e14328d1a..7f081e50a 100644 --- a/apps/web/app/services/client/api/organization-team-employee.ts +++ b/apps/web/app/services/client/api/organization-team-employee.ts @@ -1,7 +1,7 @@ import { IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; import { CreateResponse } from '@app/interfaces/IDataResponse'; import { IOrganizationTeam } from '@app/interfaces/IOrganizationTeam'; -import api from '../axios'; +import api, { put } from '../axios'; export function deleteOrganizationEmployeeTeamAPI({ id, @@ -20,7 +20,7 @@ export function deleteOrganizationEmployeeTeamAPI({ } export function updateOrganizationEmployeeTeamAPI(id: string, data: Partial) { - return api.put>(`/organization-team-employee/${id}`, data); + return put(`/organization-team-employee/${id}`, data); } export function updateOrganizationTeamEmployeeActiveTaskAPI( From cb652a1da310a1318e703d018c46b3e06670d4cd Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 12:06:48 +0000 Subject: [PATCH 08/15] implement organization-team-employee/:id api on frontend --- .../organization-team-employee/[id]/route.ts | 20 +++++++++---------- .../client/api/organization-team-employee.ts | 9 ++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/web/app/api/organization-team-employee/[id]/route.ts b/apps/web/app/api/organization-team-employee/[id]/route.ts index e2c1246b6..1d5b2e580 100644 --- a/apps/web/app/api/organization-team-employee/[id]/route.ts +++ b/apps/web/app/api/organization-team-employee/[id]/route.ts @@ -37,16 +37,16 @@ export async function DELETE(req: Request, { params }: { params: { id: string } const { employeeId } = searchParams as unknown as { employeeId: string }; const { id } = params; + const response = await deleteOrganizationTeamEmployeeRequest({ + id: id as string, + bearer_token: access_token, + tenantId, + organizationId, + employeeId: employeeId as string, + organizationTeamId: teamId + }); + if (id) { - return $res( - await deleteOrganizationTeamEmployeeRequest({ - id: id as string, - bearer_token: access_token, - tenantId, - organizationId, - employeeId: employeeId as string, - organizationTeamId: teamId - }) - ); + return $res(response.data); } } diff --git a/apps/web/app/services/client/api/organization-team-employee.ts b/apps/web/app/services/client/api/organization-team-employee.ts index 7f081e50a..cace5d820 100644 --- a/apps/web/app/services/client/api/organization-team-employee.ts +++ b/apps/web/app/services/client/api/organization-team-employee.ts @@ -1,7 +1,8 @@ import { IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; import { CreateResponse } from '@app/interfaces/IDataResponse'; import { IOrganizationTeam } from '@app/interfaces/IOrganizationTeam'; -import api, { put } from '../axios'; +import api, { deleteApi, put } from '../axios'; +import { getActiveTeamIdCookie } from '@app/helpers'; export function deleteOrganizationEmployeeTeamAPI({ id, @@ -14,8 +15,10 @@ export function deleteOrganizationEmployeeTeamAPI({ organizationId: string; tenantId: string; }) { - return api.delete>( - `/organization-team-employee/${id}?tenantId=${tenantId}&employeeId=${employeeId}&organizationId=${organizationId}` + const teamId = getActiveTeamIdCookie(); + + return deleteApi( + `/organization-team-employee/${id}?tenantId=${tenantId}&employeeId=${employeeId}&organizationId=${organizationId}&organizationTeamId=${teamId}` ); } From c9fe7071ae949eaea7ecccbb12ef0e0bac016521 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 12:14:49 +0000 Subject: [PATCH 09/15] implement organization-team-employee/:id/active-task api frontend --- .../[id]/active-task/route.ts | 16 ++++++++-------- .../client/api/organization-team-employee.ts | 8 ++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts b/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts index fddf8fbd6..5857a8804 100644 --- a/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts +++ b/apps/web/app/api/organization-team-employee/[id]/active-task/route.ts @@ -12,13 +12,13 @@ export async function PUT(req: Request, { params }: { params: { id: string } }) const body = (await req.json()) as IOrganizationTeamEmployeeUpdate; if (id) { - return $res( - await updateOrganizationTeamEmployeeActiveTaskRequest({ - id: id as string, - bearer_token: access_token, - tenantId, - body - }) - ); + const response = await updateOrganizationTeamEmployeeActiveTaskRequest({ + id: id as string, + bearer_token: access_token, + tenantId, + body + }); + + return $res(response.data); } } diff --git a/apps/web/app/services/client/api/organization-team-employee.ts b/apps/web/app/services/client/api/organization-team-employee.ts index cace5d820..e4210ae25 100644 --- a/apps/web/app/services/client/api/organization-team-employee.ts +++ b/apps/web/app/services/client/api/organization-team-employee.ts @@ -1,7 +1,6 @@ import { IOrganizationTeamEmployeeUpdate } from '@app/interfaces'; -import { CreateResponse } from '@app/interfaces/IDataResponse'; import { IOrganizationTeam } from '@app/interfaces/IOrganizationTeam'; -import api, { deleteApi, put } from '../axios'; +import { deleteApi, put } from '../axios'; import { getActiveTeamIdCookie } from '@app/helpers'; export function deleteOrganizationEmployeeTeamAPI({ @@ -30,8 +29,5 @@ export function updateOrganizationTeamEmployeeActiveTaskAPI( id: string, data: Partial ) { - return api.put>( - `/organization-team-employee/${id}/active-task`, - data - ); + return put(`/organization-team-employee/${id}/active-task`, data); } From 59273b301350d3d257d957c48341c1988f2b787d Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 12:33:04 +0000 Subject: [PATCH 10/15] implement GET /role-permissions/:id api on frontend --- .../web/app/api/role-permissions/[id]/route.ts | 18 ++++++++---------- .../services/client/api/role-permissions.ts | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/web/app/api/role-permissions/[id]/route.ts b/apps/web/app/api/role-permissions/[id]/route.ts index 4dea0195c..e21421189 100644 --- a/apps/web/app/api/role-permissions/[id]/route.ts +++ b/apps/web/app/api/role-permissions/[id]/route.ts @@ -2,7 +2,7 @@ import { authenticatedGuard } from '@app/services/server/guards/authenticated-gu import { getRolePermissionsRequest, updateRolePermissionRequest } from '@app/services/server/requests'; import { NextResponse } from 'next/server'; -export async function GET(req: Request, { params }: { params: { id: string } }) { +export async function GET(req: Request, { params }: { params: { id: string } }) { const res = new NextResponse(); const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); @@ -10,15 +10,13 @@ export async function GET(req: Request, { params }: { params: { id: string } }) const { id } = params; - return $res( - ( - await getRolePermissionsRequest({ - bearer_token: access_token, - tenantId, - roleId: id as string - }) - ).data - ); + const response = await getRolePermissionsRequest({ + bearer_token: access_token, + tenantId, + roleId: id as string + }); + + return $res(response.data); } export async function PUT(req: Request) { diff --git a/apps/web/app/services/client/api/role-permissions.ts b/apps/web/app/services/client/api/role-permissions.ts index c55ee84be..74e6e6783 100644 --- a/apps/web/app/services/client/api/role-permissions.ts +++ b/apps/web/app/services/client/api/role-permissions.ts @@ -1,8 +1,21 @@ import { IRolePermissions, PaginationResponse } from '@app/interfaces/'; -import api from '../axios'; +import api, { get } from '../axios'; +import { getTenantIdCookie } from '@app/helpers'; export function getRolePermissionAPI(id: string) { - return api.get>(`/role-permissions/${id}`); + const tenantId = getTenantIdCookie(); + + const params = { + data: JSON.stringify({ + findInput: { + roleId: id, + tenantId + } + }) + }; + const query = new URLSearchParams(params); + + return get>(`/role-permissions/${id}?${query.toString()}`); } export function updateRolePermissionAPI(data: IRolePermissions) { From b805b319644a28994fa7d47a7ad0ef639780f956 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 12:41:07 +0000 Subject: [PATCH 11/15] implement PUT role-permissions/:id api on frontend --- apps/web/app/api/role-permissions/[id]/route.ts | 16 +++++++--------- .../app/services/client/api/role-permissions.ts | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/apps/web/app/api/role-permissions/[id]/route.ts b/apps/web/app/api/role-permissions/[id]/route.ts index e21421189..6ceb4941c 100644 --- a/apps/web/app/api/role-permissions/[id]/route.ts +++ b/apps/web/app/api/role-permissions/[id]/route.ts @@ -27,13 +27,11 @@ export async function PUT(req: Request) { const body = await req.json(); - return $res( - ( - await updateRolePermissionRequest({ - bearer_token: access_token, - tenantId, - data: body - }) - ).data - ); + const response = await updateRolePermissionRequest({ + bearer_token: access_token, + tenantId, + data: body + }); + + return $res(response.data); } diff --git a/apps/web/app/services/client/api/role-permissions.ts b/apps/web/app/services/client/api/role-permissions.ts index 74e6e6783..127d8f0ad 100644 --- a/apps/web/app/services/client/api/role-permissions.ts +++ b/apps/web/app/services/client/api/role-permissions.ts @@ -1,5 +1,5 @@ import { IRolePermissions, PaginationResponse } from '@app/interfaces/'; -import api, { get } from '../axios'; +import { get, put } from '../axios'; import { getTenantIdCookie } from '@app/helpers'; export function getRolePermissionAPI(id: string) { @@ -19,5 +19,5 @@ export function getRolePermissionAPI(id: string) { } export function updateRolePermissionAPI(data: IRolePermissions) { - return api.put(`/role-permissions/${data.id}`, data); + return put(`/role-permissions/${data.id}`, data); } From 9642cc1c779b5b6f4407afdc06570b37bde26116 Mon Sep 17 00:00:00 2001 From: Paradoxe Ngwasi Date: Thu, 18 Jan 2024 13:20:39 +0000 Subject: [PATCH 12/15] implement POST /roles api on frontend --- apps/web/app/api/roles/route.ts | 38 +++++++++++------------ apps/web/app/services/client/api/roles.ts | 6 ++-- apps/web/app/services/client/axios.ts | 4 +-- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/apps/web/app/api/roles/route.ts b/apps/web/app/api/roles/route.ts index cc4a1fe87..39d7a8761 100644 --- a/apps/web/app/api/roles/route.ts +++ b/apps/web/app/api/roles/route.ts @@ -9,32 +9,30 @@ export async function GET(req: Request) { const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('unauthorized'); - return $res( - ( - await getRolesRequest({ - bearer_token: access_token, - tenantId - }) - ).data - ); + const response = await getRolesRequest({ + bearer_token: access_token, + tenantId + }); + + return $res(response.data); } export async function POST(req: Request) { const res = new NextResponse(); const { $res, user, access_token, tenantId } = await authenticatedGuard(req, res); + const body = (await req.json()) as IRole; + if (!user) return $res('unauthorized'); - return $res( - ( - await createRoleRequest({ - bearer_token: access_token, - tenantId, - data: { - ...body, - tenantId - } - }) - ).data - ); + const response = await createRoleRequest({ + bearer_token: access_token, + tenantId, + data: { + ...body, + tenantId + } + }); + + return $res(response.data); } diff --git a/apps/web/app/services/client/api/roles.ts b/apps/web/app/services/client/api/roles.ts index 5e3999383..c1e88d5ab 100644 --- a/apps/web/app/services/client/api/roles.ts +++ b/apps/web/app/services/client/api/roles.ts @@ -1,12 +1,12 @@ import { IRole, PaginationResponse } from '@app/interfaces'; -import api from '../axios'; +import api, { get, post } from '../axios'; export function getRolesAPI() { - return api.get>('/roles'); + return get>('/roles'); } export function createRoleAPI(data: IRole) { - return api.post('/roles', data); + return post('/roles', data); } export function deleteRoleAPI(id: string) { diff --git a/apps/web/app/services/client/axios.ts b/apps/web/app/services/client/axios.ts index f355fc9a8..a940e724f 100644 --- a/apps/web/app/services/client/axios.ts +++ b/apps/web/app/services/client/axios.ts @@ -120,11 +120,11 @@ function post(url: string, data?: Record | FormData, config?: AP const { directAPI = true } = config || {}; if (baseURL && directAPI && data && !(data instanceof FormData)) { - if (!data.tenantId) { + if (!data.tenantId && data.tenantId !== null) { data.tenantId = tenantId; } - if (!data.organizationId) { + if (!data.organizationId && data.organizationId !== null) { data.organizationId = organizationId; } } From 2365cb2088a823432f5b04faffaf57d9e0db65f7 Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Thu, 18 Jan 2024 17:18:12 +0200 Subject: [PATCH 13/15] refact: get activity by employee Id --- .../web/app/[locale]/profile/[memberId]/page.tsx | 4 ++-- .../app/hooks/features/useTimeDailyActivity.ts | 14 +++++++------- apps/web/app/hooks/features/useTimeSlot.ts | 11 +++++++---- apps/web/app/interfaces/IActivityFilter.ts | 8 ++++++++ apps/web/app/stores/activity-type.ts | 8 ++++++-- apps/web/lib/features/activity/apps.tsx | 5 ++--- apps/web/lib/features/activity/screenshoots.tsx | 6 ++---- apps/web/lib/features/activity/visited-sites.tsx | 11 ++--------- .../lib/features/team/user-team-card/index.tsx | 16 ++++++++++------ .../user-team-card/user-team-card-activity.tsx | 15 ++++++--------- .../team/user-team-card/user-worked-task.tsx | 7 +++++-- 11 files changed, 57 insertions(+), 48 deletions(-) create mode 100644 apps/web/app/interfaces/IActivityFilter.ts diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index a617bafd2..57d3d2c74 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -45,8 +45,8 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId const activityScreens = { Tasks: , Screenshots: , - Apps: , - 'Visited Sites': + Apps: , + 'Visited Sites': }; const profileIsAuthUser = useMemo(() => profile.isAuthUser, [profile.isAuthUser]); diff --git a/apps/web/app/hooks/features/useTimeDailyActivity.ts b/apps/web/app/hooks/features/useTimeDailyActivity.ts index 4accbb60c..05fb4c129 100644 --- a/apps/web/app/hooks/features/useTimeDailyActivity.ts +++ b/apps/web/app/hooks/features/useTimeDailyActivity.ts @@ -2,17 +2,17 @@ import { useCallback, useEffect } from 'react'; import { useQuery } from '../useQuery'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { timeAppsState, timeVisitedSitesState } from '@app/stores/time-slot'; import moment from 'moment'; import { useAuthenticateUser } from './useAuthenticateUser'; import { getTimerDailyRequestAPI } from '@app/services/client/api'; -import { IUser } from '@app/interfaces'; +import { activityTypeState } from '@app/stores/activity-type'; -export function useTimeDailyActivity(type: string, userProfile: IUser | undefined, id?: string) { +export function useTimeDailyActivity(type: string) { const { user } = useAuthenticateUser(); const [visitedApps, setVisitedApps] = useRecoilState(timeAppsState); - // const [visitedAppDetail, setVisitedAppDetail] = useRecoilState(timeAppVisitedDetail); + const activityFilter = useRecoilValue(activityTypeState); const [visitedSites, setVisitedSites] = useRecoilState(timeVisitedSitesState); const { loading, queryCall } = useQuery(getTimerDailyRequestAPI); @@ -21,8 +21,8 @@ export function useTimeDailyActivity(type: string, userProfile: IUser | undefine (title?: string) => { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); - const employeeId = id ? id : userProfile?.employee?.id; - if (userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + const employeeId = activityFilter.member ? activityFilter.member?.employeeId : user?.employee?.id; + if (activityFilter.member?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { queryCall({ tenantId: user?.tenantId ?? '', organizationId: user?.employee.organizationId ?? '', @@ -44,7 +44,7 @@ export function useTimeDailyActivity(type: string, userProfile: IUser | undefine } }, // eslint-disable-next-line react-hooks/exhaustive-deps - [id, userProfile, queryCall, type] + [queryCall, type] ); useEffect(() => { diff --git a/apps/web/app/hooks/features/useTimeSlot.ts b/apps/web/app/hooks/features/useTimeSlot.ts index 83b0b54f7..9da075c82 100644 --- a/apps/web/app/hooks/features/useTimeSlot.ts +++ b/apps/web/app/hooks/features/useTimeSlot.ts @@ -2,16 +2,18 @@ import { useCallback, useEffect } from 'react'; import { useQuery } from '../useQuery'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { timeSlotsState } from '@app/stores/time-slot'; import moment from 'moment'; import { useAuthenticateUser } from './useAuthenticateUser'; import { deleteTimerLogsRequestAPI, getTimerLogsRequestAPI } from '@app/services/client/api'; import { useUserProfilePage } from './useUserProfilePage'; +import { activityTypeState } from '@app/stores/activity-type'; -export function useTimeSlots(id?: string) { +export function useTimeSlots(hasFilter?: boolean) { const { user } = useAuthenticateUser(); const [timeSlots, setTimeSlots] = useRecoilState(timeSlotsState); + const activityFilter = useRecoilValue(activityTypeState); const profile = useUserProfilePage(); const { loading, queryCall } = useQuery(getTimerLogsRequestAPI); @@ -20,7 +22,7 @@ export function useTimeSlots(id?: string) { const getTimeSlots = useCallback(() => { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); - const employeeId = id ? id : profile.member?.employeeId; + const employeeId = hasFilter ? activityFilter.member?.employeeId : profile.member?.employeeId; if (profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { queryCall({ tenantId: user?.tenantId ?? '', @@ -36,7 +38,8 @@ export function useTimeSlots(id?: string) { }); } }, [ - id, + hasFilter, + activityFilter.member?.employeeId, profile.member?.employeeId, profile.userProfile?.id, user?.id, diff --git a/apps/web/app/interfaces/IActivityFilter.ts b/apps/web/app/interfaces/IActivityFilter.ts new file mode 100644 index 000000000..6acba9970 --- /dev/null +++ b/apps/web/app/interfaces/IActivityFilter.ts @@ -0,0 +1,8 @@ +import { OT_Member } from './IOrganizationTeam'; + +export interface IActivityFilter { + type: 'DATE' | 'TICKET'; + member: OT_Member | null; + dateStart?: Date; + dateStop?: Date; +} diff --git a/apps/web/app/stores/activity-type.ts b/apps/web/app/stores/activity-type.ts index 68b022ef0..2f7d01ea5 100644 --- a/apps/web/app/stores/activity-type.ts +++ b/apps/web/app/stores/activity-type.ts @@ -1,6 +1,10 @@ +import { IActivityFilter } from '@app/interfaces/IActivityFilter'; import { atom } from 'recoil'; -export const activityTypeState = atom<'DATE' | 'TICKET'>({ +export const activityTypeState = atom({ key: 'activityTypeState', - default: 'DATE' + default: { + type: 'DATE', + member: null + } }); diff --git a/apps/web/lib/features/activity/apps.tsx b/apps/web/lib/features/activity/apps.tsx index 68c002ea8..5bdcdb820 100644 --- a/apps/web/lib/features/activity/apps.tsx +++ b/apps/web/lib/features/activity/apps.tsx @@ -3,11 +3,10 @@ import { AppVisitedSkeleton } from './components/app-visited-skeleton'; import { groupAppsByHour } from '@app/helpers/array-data'; import { useTranslations } from 'next-intl'; import AppVisitedItem from './components/app-visited-Item'; -import { IUser } from '@app/interfaces'; // import { AppVisitedModal } from './components/app-visited-details'; -export function AppsTab({ id, userProfile }: { id?: string; userProfile?: IUser }) { - const { visitedApps, loading } = useTimeDailyActivity('URL', userProfile, id); +export function AppsTab() { + const { visitedApps, loading } = useTimeDailyActivity('APPS'); const t = useTranslations(); const apps = groupAppsByHour(visitedApps); console.log('INTO APP TAB'); diff --git a/apps/web/lib/features/activity/screenshoots.tsx b/apps/web/lib/features/activity/screenshoots.tsx index 0c45e14b2..6a1984030 100644 --- a/apps/web/lib/features/activity/screenshoots.tsx +++ b/apps/web/lib/features/activity/screenshoots.tsx @@ -48,9 +48,8 @@ export function ScreenshootTab() { ); } - -export function ScreenshootTeamTab({ id}: {id:string}) { - const { timeSlots, loading } = useTimeSlots(id); +export function ScreenshootTeamTab() { + const { timeSlots, loading } = useTimeSlots(true); const t = useTranslations(); return ( @@ -61,7 +60,6 @@ export function ScreenshootTeamTab({ id}: {id:string}) { timeSlots={hourData.items} startedAt={hourData.startedAt} stoppedAt={hourData.stoppedAt} - /> ))} {timeSlots.length < 1 && !loading && ( diff --git a/apps/web/lib/features/activity/visited-sites.tsx b/apps/web/lib/features/activity/visited-sites.tsx index 14b6e595f..c2e960ec1 100644 --- a/apps/web/lib/features/activity/visited-sites.tsx +++ b/apps/web/lib/features/activity/visited-sites.tsx @@ -4,16 +4,9 @@ import { groupAppsByHour } from '@app/helpers/array-data'; import { useTranslations } from 'next-intl'; import AppVisitedItem from './components/app-visited-Item'; import React from 'react'; -import { IUser } from '@app/interfaces'; -export const VisitedSitesTab = React.memo(function VisitedSitesT({ - id, - userProfile -}: { - id?: string; - userProfile?: IUser; -}) { - const { visitedSites, loading } = useTimeDailyActivity('URL', userProfile, id); +export const VisitedSitesTab = React.memo(function VisitedSitesT() { + const { visitedSites, loading } = useTimeDailyActivity('URL'); const t = useTranslations(); const sites = groupAppsByHour(visitedSites); return ( diff --git a/apps/web/lib/features/team/user-team-card/index.tsx b/apps/web/lib/features/team/user-team-card/index.tsx index 9d728e8fb..c4ed39c43 100644 --- a/apps/web/lib/features/team/user-team-card/index.tsx +++ b/apps/web/lib/features/team/user-team-card/index.tsx @@ -2,7 +2,7 @@ import { secondsToTime } from '@app/helpers'; import { useCollaborative, useTMCardTaskEdit, useTaskStatistics, useTeamMemberCard } from '@app/hooks'; -import { IClassName, IOrganizationTeamList } from '@app/interfaces'; +import { IClassName, IOrganizationTeamList, OT_Member } from '@app/interfaces'; import { timerSecondsState } from '@app/stores'; import { clsxm } from '@app/utils'; import { Card, HorizontalSeparator, InputField, Text, VerticalSeparator } from 'lib/components'; @@ -55,9 +55,13 @@ export function UserTeamCard({ const { activeTaskTotalStat, addSeconds } = useTaskStatistics(seconds); const [showActivity, setShowActivity] = React.useState(false); - const showActivityFilter = (type: 'DATE' | 'TICKET') => { + const showActivityFilter = (type: 'DATE' | 'TICKET', member: OT_Member | null) => { setShowActivity((prev) => !prev); - setActivityFilter(type); + setActivityFilter((prev) => ({ + ...prev, + type, + member + })); }; let totalWork = <>; @@ -137,7 +141,7 @@ export function UserTeamCard({ />

showActivityFilter('TICKET')} + onClick={() => showActivityFilter('TICKET', memberInfo.member ?? null)} > {!showActivity ? ( @@ -171,7 +175,7 @@ export function UserTeamCard({

showActivityFilter('DATE')} + onClick={() => showActivityFilter('DATE', memberInfo.member ?? null)} className="flex items-center w-8 h-8 border dark:border-gray-800 rounded justify-center cursor-pointer text-center" > {!showActivity ? ( @@ -184,7 +188,7 @@ export function UserTeamCard({ {/* Card menu */}

{menu}
- + { - const id = member?.employee?.id ?? ''; - const { timeSlots } = useTimeSlots(id); +const UserTeamActivity = ({ showActivity }: { showActivity: boolean }) => { + const { timeSlots } = useTimeSlots(true); const t = useTranslations(); const activityPercent = timeSlots.reduce((acc, el) => acc + el.percentage, 0) / timeSlots.length; - console.log('ACTIVITY TEAM M.'); return ( {/* */} - + - + - + - + diff --git a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx index 2b6f7eda2..64091fd03 100644 --- a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx +++ b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx @@ -1,9 +1,12 @@ import { useUserDetails } from '@app/hooks/features/useUserDetails'; +import { activityTypeState } from '@app/stores/activity-type'; import { useTaskFilter } from 'lib/features/task/task-filters'; import { UserProfileTask } from 'lib/features/user-profile-tasks'; +import { useRecoilValue } from 'recoil'; -export function UserWokedTaskTab({ id }: { id: string }) { - const profile = useUserDetails(id); +export function UserWokedTaskTab() { + const activityFilter = useRecoilValue(activityTypeState); + const profile = useUserDetails(activityFilter.member?.employeeId ?? ''); const hook = useTaskFilter(profile); return ; From 87a6e4ae543165fc842ac8baff291cba582baaaa Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Thu, 18 Jan 2024 17:35:53 +0200 Subject: [PATCH 14/15] fix: deploy error --- apps/web/app/[locale]/profile/[memberId]/page.tsx | 6 ++---- apps/web/app/interfaces/IActivityFilter.ts | 1 + .../team/user-team-card/user-team-card-activity.tsx | 4 ++-- .../lib/features/team/user-team-card/user-worked-task.tsx | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index 57d3d2c74..a0e99201b 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -40,13 +40,11 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId { title: JSON.parse(t('pages.profile.BREADCRUMB')) || '', href: `/profile/${params.memberId}` } ]; - console.log({ activityFilter }); - const activityScreens = { Tasks: , Screenshots: , - Apps: , - 'Visited Sites': + Apps: , + 'Visited Sites': }; const profileIsAuthUser = useMemo(() => profile.isAuthUser, [profile.isAuthUser]); diff --git a/apps/web/app/interfaces/IActivityFilter.ts b/apps/web/app/interfaces/IActivityFilter.ts index 6acba9970..df7d343b9 100644 --- a/apps/web/app/interfaces/IActivityFilter.ts +++ b/apps/web/app/interfaces/IActivityFilter.ts @@ -3,6 +3,7 @@ import { OT_Member } from './IOrganizationTeam'; export interface IActivityFilter { type: 'DATE' | 'TICKET'; member: OT_Member | null; + taskId?: string; dateStart?: Date; dateStop?: Date; } diff --git a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx index a6dacc72d..cb14d8b49 100644 --- a/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx +++ b/apps/web/lib/features/team/user-team-card/user-team-card-activity.tsx @@ -9,7 +9,7 @@ import { clsxm } from '@app/utils'; import { ScreenshootTeamTab } from 'lib/features/activity/screenshoots'; import { AppsTab } from 'lib/features/activity/apps'; import { VisitedSitesTab } from 'lib/features/activity/visited-sites'; -import { UserWokedTaskTab } from './user-worked-task'; +import { UserWorkedTaskTab } from './user-worked-task'; // import { UserProfileTask } from 'lib/features/user-profile-tasks'; const UserTeamActivity = ({ showActivity }: { showActivity: boolean }) => { @@ -63,7 +63,7 @@ const UserTeamActivity = ({ showActivity }: { showActivity: boolean }) => { {/* */} - + diff --git a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx index 64091fd03..d277b31ec 100644 --- a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx +++ b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx @@ -4,7 +4,7 @@ import { useTaskFilter } from 'lib/features/task/task-filters'; import { UserProfileTask } from 'lib/features/user-profile-tasks'; import { useRecoilValue } from 'recoil'; -export function UserWokedTaskTab() { +export function UserWorkedTaskTab() { const activityFilter = useRecoilValue(activityTypeState); const profile = useUserDetails(activityFilter.member?.employeeId ?? ''); const hook = useTaskFilter(profile); From 323dc5ab3949f62bc730e661aa44668d2776f49f Mon Sep 17 00:00:00 2001 From: cedric karungu Date: Thu, 18 Jan 2024 20:36:50 +0200 Subject: [PATCH 15/15] fix: useAcitivityData for each user --- .../app/hooks/features/useTimeDailyActivity.ts | 7 +++++-- apps/web/app/hooks/features/useTimeSlot.ts | 18 ++++-------------- .../services/client/api/activity/activity.ts | 9 +++++---- apps/web/lib/features/activity/apps.tsx | 3 +-- .../team/user-team-card/user-worked-task.tsx | 2 ++ 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/apps/web/app/hooks/features/useTimeDailyActivity.ts b/apps/web/app/hooks/features/useTimeDailyActivity.ts index 05fb4c129..ee2509123 100644 --- a/apps/web/app/hooks/features/useTimeDailyActivity.ts +++ b/apps/web/app/hooks/features/useTimeDailyActivity.ts @@ -9,7 +9,7 @@ import { useAuthenticateUser } from './useAuthenticateUser'; import { getTimerDailyRequestAPI } from '@app/services/client/api'; import { activityTypeState } from '@app/stores/activity-type'; -export function useTimeDailyActivity(type: string) { +export function useTimeDailyActivity(type?: string) { const { user } = useAuthenticateUser(); const [visitedApps, setVisitedApps] = useRecoilState(timeAppsState); const activityFilter = useRecoilValue(activityTypeState); @@ -22,7 +22,10 @@ export function useTimeDailyActivity(type: string) { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); const employeeId = activityFilter.member ? activityFilter.member?.employeeId : user?.employee?.id; - if (activityFilter.member?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + if ( + activityFilter.member?.employeeId === user?.employee.id || + user?.role?.name?.toUpperCase() == 'MANAGER' + ) { queryCall({ tenantId: user?.tenantId ?? '', organizationId: user?.employee.organizationId ?? '', diff --git a/apps/web/app/hooks/features/useTimeSlot.ts b/apps/web/app/hooks/features/useTimeSlot.ts index 9da075c82..54deda3f3 100644 --- a/apps/web/app/hooks/features/useTimeSlot.ts +++ b/apps/web/app/hooks/features/useTimeSlot.ts @@ -22,8 +22,8 @@ export function useTimeSlots(hasFilter?: boolean) { const getTimeSlots = useCallback(() => { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); - const employeeId = hasFilter ? activityFilter.member?.employeeId : profile.member?.employeeId; - if (profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + const employeeId = activityFilter.member ? activityFilter.member?.employeeId : user?.employee?.id; + if (activityFilter.member?.employeeId === user?.employee.id || user?.role?.name?.toUpperCase() == 'MANAGER') { queryCall({ tenantId: user?.tenantId ?? '', organizationId: user?.employee.organizationId ?? '', @@ -37,18 +37,8 @@ export function useTimeSlots(hasFilter?: boolean) { } }); } - }, [ - hasFilter, - activityFilter.member?.employeeId, - profile.member?.employeeId, - profile.userProfile?.id, - user?.id, - user?.role?.name, - user?.tenantId, - user?.employee.organizationId, - queryCall, - setTimeSlots - ]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [hasFilter, activityFilter.member?.employeeId, profile.member?.employeeId, user?.id, queryCall, setTimeSlots]); const deleteTimeSlots = useCallback( (ids: string[]) => { diff --git a/apps/web/app/services/client/api/activity/activity.ts b/apps/web/app/services/client/api/activity/activity.ts index f64309313..755b37019 100644 --- a/apps/web/app/services/client/api/activity/activity.ts +++ b/apps/web/app/services/client/api/activity/activity.ts @@ -16,7 +16,7 @@ export async function getTimerDailyRequestAPI({ employeeId: string; todayEnd: Date; todayStart: Date; - type: string; + type?: string | undefined; title?: string; }) { const params: { @@ -25,18 +25,19 @@ export async function getTimerDailyRequestAPI({ 'employeeIds[0]': string; startDate: string; endDate: string; - 'types[0]': string; + 'types[0]'?: string; 'title[0]'?: string; } = { tenantId: tenantId, organizationId: organizationId, 'employeeIds[0]': employeeId, startDate: todayStart.toISOString(), - endDate: todayEnd.toISOString(), - 'types[0]': type + endDate: todayEnd.toISOString() }; + if (type) params['types[0]'] = type; if (title) params['title[0]'] = title; const query = new URLSearchParams(params); + console.log('QUERY', query); const endpoint = GAUZY_API_BASE_SERVER_URL.value ? `/timesheet/activity/daily?${query.toString()}` : `/timer/daily?${query.toString()}`; diff --git a/apps/web/lib/features/activity/apps.tsx b/apps/web/lib/features/activity/apps.tsx index 5bdcdb820..f274d5126 100644 --- a/apps/web/lib/features/activity/apps.tsx +++ b/apps/web/lib/features/activity/apps.tsx @@ -6,10 +6,9 @@ import AppVisitedItem from './components/app-visited-Item'; // import { AppVisitedModal } from './components/app-visited-details'; export function AppsTab() { - const { visitedApps, loading } = useTimeDailyActivity('APPS'); + const { visitedApps, loading } = useTimeDailyActivity(); const t = useTranslations(); const apps = groupAppsByHour(visitedApps); - console.log('INTO APP TAB'); return (
{/* TODO: Filters components */}
diff --git a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx index d277b31ec..9f46000b4 100644 --- a/apps/web/lib/features/team/user-team-card/user-worked-task.tsx +++ b/apps/web/lib/features/team/user-team-card/user-worked-task.tsx @@ -9,5 +9,7 @@ export function UserWorkedTaskTab() { const profile = useUserDetails(activityFilter.member?.employeeId ?? ''); const hook = useTaskFilter(profile); + console.log({ hook, profile }); + return ; }