diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index bfb9ab0b3..11928f482 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -2,7 +2,7 @@ /* eslint-disable no-mixed-spaces-and-tabs */ import { imgTitle } from '@app/helpers'; -import { useOrganizationTeams, useTimer, useUserProfilePage } from '@app/hooks'; +import { useAuthenticateUser, useOrganizationTeams, useTimer, useUserProfilePage } from '@app/hooks'; import { ITimerStatusEnum, OT_Member } from '@app/interfaces'; import { clsxm, isValidUrl } from '@app/utils'; import clsx from 'clsx'; @@ -25,11 +25,13 @@ import { VisitedSitesTab } from 'lib/features/activity/visited-sites'; const Profile = ({ 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 hook = useTaskFilter(profile); + const canSeeActivity = profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER'; const t = useTranslations(); const breadcrumb = [ @@ -37,6 +39,8 @@ const Profile = ({ params }: { params: { memberId: string } }) => { { title: JSON.parse(t('pages.profile.BREADCRUMB')) || '', href: `/profile/${params.memberId}` } ]; + console.log({ activityFilter }); + const profileIsAuthUser = useMemo(() => profile.isAuthUser, [profile.isAuthUser]); const hookFilterType = useMemo(() => hook.filterType, [hook.filterType]); @@ -73,7 +77,7 @@ const Profile = ({ params }: { params: { memberId: string } }) => { {/* Divider */}
- {hook.tab == 'worked' && ( + {hook.tab == 'worked' && canSeeActivity && (
{Object.values(ActivityFilters).map((filter: ActivityFilters, i) => ( @@ -97,11 +101,11 @@ const Profile = ({ params }: { params: { memberId: string } }) => { {hook.tab == 'worked' && activityFilter == ActivityFilters.TASKS ? ( - ) : hook.tab == 'worked' && activityFilter == ActivityFilters.SCREENSHOOTS ? ( + ) : hook.tab == 'worked' && canSeeActivity && activityFilter == ActivityFilters.SCREENSHOOTS ? ( - ) : hook.tab == 'worked' && activityFilter == ActivityFilters.APPS ? ( + ) : hook.tab == 'worked' && canSeeActivity && activityFilter == ActivityFilters.APPS ? ( - ) : hook.tab == 'worked' && activityFilter == ActivityFilters.VISITED_SITES ? ( + ) : hook.tab == 'worked' && canSeeActivity && activityFilter == ActivityFilters.VISITED_SITES ? ( ) : ( diff --git a/apps/web/app/hooks/features/useTimeDailyActivity.ts b/apps/web/app/hooks/features/useTimeDailyActivity.ts index deccaae2d..7b2fa9251 100644 --- a/apps/web/app/hooks/features/useTimeDailyActivity.ts +++ b/apps/web/app/hooks/features/useTimeDailyActivity.ts @@ -3,46 +3,70 @@ import { useCallback, useEffect } from 'react'; import { useQuery } from '../useQuery'; import { useRecoilState } from 'recoil'; -import { timeAppsState, timeVisitedSitesState } from '@app/stores/time-slot'; +import { timeAppVisitedDetail, 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'; export function useTimeDailyActivity(type: string) { + const profile = useUserProfilePage(); const { user } = useAuthenticateUser(); const [visitedApps, setVisitedApps] = useRecoilState(timeAppsState); + const [visitedAppDetail, setVisitedAppDetail] = useRecoilState(timeAppVisitedDetail); const [visitedSites, setVisitedSites] = useRecoilState(timeVisitedSitesState); const { loading, queryCall } = useQuery(getTimerDailyRequestAPI); - const getVisitedApps = useCallback(() => { - const todayStart = moment().startOf('day').toDate(); - const todayEnd = moment().endOf('day').toDate(); - - queryCall({ - tenantId: user?.tenantId ?? '', - organizationId: user?.employee.organizationId ?? '', - employeeId: user?.employee.id ?? '', - todayEnd, + const getVisitedApps = useCallback( + ({ title }: { title?: string }) => { + const todayStart = moment().startOf('day').toDate(); + const todayEnd = moment().endOf('day').toDate(); + const employeeId = profile.member?.employeeId ?? ''; + if (profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + queryCall({ + tenantId: user?.tenantId ?? '', + organizationId: user?.employee.organizationId ?? '', + employeeId: employeeId, + todayEnd, + type, + todayStart, + title + }) + .then((response) => { + if (response.data) { + // @ts-ignore + if (title) setVisitedAppDetail(response.data[0]); + else 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, - todayStart - }) - .then((response) => { - if (response.data) { - if (type == 'APP') setVisitedApps(response.data); - else setVisitedSites(response.data); - } - }) - .catch((err) => console.log(err)); - }, [queryCall, setVisitedApps, setVisitedSites, user, type]); + setVisitedAppDetail, + setVisitedApps, + setVisitedSites + ] + ); useEffect(() => { - getVisitedApps(); + getVisitedApps({}); }, [user, getVisitedApps]); return { visitedApps, visitedSites, + visitedAppDetail, getVisitedApps, loading }; diff --git a/apps/web/app/hooks/features/useTimeSlot.ts b/apps/web/app/hooks/features/useTimeSlot.ts index 48091e459..cb919849a 100644 --- a/apps/web/app/hooks/features/useTimeSlot.ts +++ b/apps/web/app/hooks/features/useTimeSlot.ts @@ -7,10 +7,12 @@ 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'; export function useTimeSlots() { const { user } = useAuthenticateUser(); const [timeSlots, setTimeSlots] = useRecoilState(timeSlotsState); + const profile = useUserProfilePage(); const { loading, queryCall } = useQuery(getTimerLogsRequestAPI); const { loading: loadingDelete, queryCall: queryDeleteCall } = useQuery(deleteTimerLogsRequestAPI); @@ -18,19 +20,31 @@ export function useTimeSlots() { const getTimeSlots = useCallback(() => { const todayStart = moment().startOf('day').toDate(); const todayEnd = moment().endOf('day').toDate(); - queryCall({ - tenantId: user?.tenantId ?? '', - organizationId: user?.employee.organizationId ?? '', - employeeId: user?.employee.id ?? '', - todayEnd, - todayStart - }).then((response) => { - if (response.data) { - // @ts-expect-error - setTimeSlots(response.data[0].timeSlots); - } - }); - }, [queryCall, setTimeSlots, user]); + const employeeId = profile.member?.employeeId ?? ''; + if (profile.userProfile?.id === user?.id || user?.role?.name?.toUpperCase() == 'MANAGER') { + queryCall({ + tenantId: user?.tenantId ?? '', + organizationId: user?.employee.organizationId ?? '', + employeeId: employeeId, + todayEnd, + todayStart + }).then((response) => { + if (response.data) { + // @ts-expect-error + setTimeSlots(response.data[0].timeSlots); + } + }); + } + }, [ + profile.member?.employeeId, + profile.userProfile?.id, + user?.id, + user?.role?.name, + user?.tenantId, + user?.employee.organizationId, + 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 38663667c..f64309313 100644 --- a/apps/web/app/services/client/api/activity/activity.ts +++ b/apps/web/app/services/client/api/activity/activity.ts @@ -8,7 +8,8 @@ export async function getTimerDailyRequestAPI({ employeeId, todayEnd, todayStart, - type + type, + title }: { tenantId: string; organizationId: string; @@ -16,8 +17,17 @@ export async function getTimerDailyRequestAPI({ todayEnd: Date; todayStart: Date; type: string; + title?: string; }) { - const params = { + const params: { + tenantId: string; + organizationId: string; + 'employeeIds[0]': string; + startDate: string; + endDate: string; + 'types[0]': string; + 'title[0]'?: string; + } = { tenantId: tenantId, organizationId: organizationId, 'employeeIds[0]': employeeId, @@ -25,6 +35,7 @@ export async function getTimerDailyRequestAPI({ endDate: todayEnd.toISOString(), 'types[0]': type }; + if (title) params['title[0]'] = title; const query = new URLSearchParams(params); const endpoint = GAUZY_API_BASE_SERVER_URL.value ? `/timesheet/activity/daily?${query.toString()}` diff --git a/apps/web/app/services/client/api/timer/timer-status.ts b/apps/web/app/services/client/api/timer/timer-status.ts index 5f5630c29..63ab1693a 100644 --- a/apps/web/app/services/client/api/timer/timer-status.ts +++ b/apps/web/app/services/client/api/timer/timer-status.ts @@ -1,5 +1,6 @@ import { ITimerStatus } from '@app/interfaces'; import { get } from '../../axios'; +import { GAUZY_API_BASE_SERVER_URL } from '@app/constants'; export async function getTaskStatusList( tenantId: string, @@ -7,7 +8,22 @@ export async function getTaskStatusList( employeeId: string, organizationTeamId: string | null ) { - const endpoint = `/timer/status?tenantId=${tenantId}&organizationId=${organizationId}&organizationTeamId=${organizationTeamId}&employeeId=${employeeId}`; + const params: { + tenantId: string; + organizationId: string; + employeeId: string; + organizationTeamId?: string; + } = { + tenantId: tenantId, + organizationId: organizationId, + employeeId: employeeId + }; + if (organizationTeamId) params.organizationTeamId = organizationTeamId; + const query = new URLSearchParams(params); + + const endpoint = GAUZY_API_BASE_SERVER_URL.value + ? `/timesheet/timer/status?${query.toString()}` + : `/timer/status?tenantId=${tenantId}&organizationId=${organizationId}&organizationTeamId=${organizationTeamId}&employeeId=${employeeId}`; return get(endpoint, { tenantId }); } diff --git a/apps/web/app/services/server/requests/timer/status.ts b/apps/web/app/services/server/requests/timer/status.ts new file mode 100644 index 000000000..ec83813a0 --- /dev/null +++ b/apps/web/app/services/server/requests/timer/status.ts @@ -0,0 +1,34 @@ +import { ITimerSlotDataRequest } from '@app/interfaces/timer/ITimerSlot'; +import { serverFetch } from '../../fetch'; + +export function getTimerStatusRequest({ + bearer_token, + tenantId, + organizationId, + todayEnd, + todayStart, + employeeId +}: { + bearer_token: string; + tenantId: string; + organizationId: string; + todayEnd: Date; + todayStart: Date; + employeeId: string; +}) { + const params = { + tenantId: tenantId, + organizationId: organizationId, + employeeId, + todayStart: todayStart.toISOString(), + todayEnd: todayEnd.toISOString(), + 'relations[0]': 'employee' + }; + const query = new URLSearchParams(params); + return serverFetch({ + path: `/timesheet/timer/status?${query.toString()}`, + method: 'GET', + bearer_token, + tenantId + }); +} diff --git a/apps/web/app/stores/time-slot.ts b/apps/web/app/stores/time-slot.ts index 3318cf1b9..f343921f0 100644 --- a/apps/web/app/stores/time-slot.ts +++ b/apps/web/app/stores/time-slot.ts @@ -1,4 +1,4 @@ -import { ITimerApps } from '@app/interfaces/timer/ITimerApp'; +import { IDetailTimerSite, ITimerApps } from '@app/interfaces/timer/ITimerApp'; import { ITimerSlot } from '@app/interfaces/timer/ITimerSlot'; import { atom } from 'recoil'; @@ -16,3 +16,7 @@ export const timeVisitedSitesState = atom({ key: 'timeVisitedSiteState', default: [] }); + +export const timeAppVisitedDetail = atom({ + key: 'timeAppVisitedDetail' +}); diff --git a/apps/web/lib/features/activity/apps.tsx b/apps/web/lib/features/activity/apps.tsx index cbf7b3582..8bbb5845f 100644 --- a/apps/web/lib/features/activity/apps.tsx +++ b/apps/web/lib/features/activity/apps.tsx @@ -3,6 +3,7 @@ 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 { AppVisitedModal } from './components/app-visited-details'; export function AppsTab() { const { visitedApps, loading } = useTimeDailyActivity('APP'); @@ -27,7 +28,13 @@ export function AppsTab() {
{app.apps?.map((item, i) => (
- + + +
))}
diff --git a/apps/web/lib/features/activity/components/app-visited-details.tsx b/apps/web/lib/features/activity/components/app-visited-details.tsx new file mode 100644 index 000000000..f358d04a6 --- /dev/null +++ b/apps/web/lib/features/activity/components/app-visited-details.tsx @@ -0,0 +1,32 @@ +import { useModal } from '@app/hooks'; +// import { useTimeDailyActivity } from '@app/hooks/features/useTimeDailyActivity'; +import { Modal } from 'lib/components'; +import React, { PropsWithChildren } from 'react'; + +export function AppVisitedModal({ children }: PropsWithChildren) { + const { closeModal, isOpen, openModal } = useModal(); + // const { visitedAppDetail, loading } = useTimeDailyActivity('APP'); + return ( +
+
{children}
+ + {/* {loading ? ( +
Loading ...
+ ) : ( +
+

{visitedAppDetail.title}

+

{visitedAppDetail.description}

+
+ {visitedAppDetail.isActive && 'Active'} +
+
+ )} */} +
+
+ ); +} diff --git a/apps/web/lib/features/activity/screenshoots.tsx b/apps/web/lib/features/activity/screenshoots.tsx index bc2ff1a2c..4c9db24c4 100644 --- a/apps/web/lib/features/activity/screenshoots.tsx +++ b/apps/web/lib/features/activity/screenshoots.tsx @@ -4,13 +4,17 @@ import { useTimeSlots } from '@app/hooks/features/useTimeSlot'; import { groupDataByHour } from '@app/helpers/array-data'; import { useTranslations } from 'next-intl'; import { ScreenshootSkeleton } from './components/screenshoots-per-hour-skeleton'; +import { useLiveTimerStatus } from '@app/hooks'; export function ScreenshootTab() { const { timeSlots, loading } = useTimeSlots(); const t = useTranslations(); const activityPercent = timeSlots.reduce((acc, el) => acc + el.percentage, 0) / timeSlots.length; - const totaHours = '1:20:34'; + // const workedSeconds = timeSlots.reduce((acc, el) => acc + el.duration, 0); + const { + time: { h, m } + } = useLiveTimerStatus(); return (
@@ -22,7 +26,7 @@ export function ScreenshootTab() {
{t('timer.TOTAL_HOURS')} -

{totaHours}

+

{`${h}:${m}:00`}

diff --git a/apps/web/lib/settings/JitsuRoot.tsx b/apps/web/lib/settings/JitsuRoot.tsx index f6ed3e9ac..de7f8e5c5 100644 --- a/apps/web/lib/settings/JitsuRoot.tsx +++ b/apps/web/lib/settings/JitsuRoot.tsx @@ -17,8 +17,14 @@ type MyAppProps = { export function JitsuRoot({ pageProps, children }: MyAppProps) { pageProps?.envs && setNextPublicEnv(pageProps?.envs); - const jitsuConf = pageProps?.jitsuConf; - const isJitsuEnvs: boolean = jitsuConf?.host !== '' && jitsuConf?.writeKey !== ''; + const jitsuConf = pageProps?.jitsuConf || { + host: process.env.NEXT_PUBLIC_JITSU_BROWSER_URL, + writeKey: process.env.NEXT_PUBLIC_JITSU_BROWSER_WRITE_KEY, + debug: false, + cookieDomain: process.env.NEXT_PUBLIC_JITSU_COOKIE_DOMAIN, + echoEvents: false + }; + const isJitsuEnvs: boolean = jitsuConf.host !== '' && jitsuConf.writeKey !== ''; console.log(`Jitsu Enabled: ${isJitsuEnvs}`); console.log(`Jitsu Configuration: ${JSON.stringify(jitsuConf)}`); console.log(`Jitsu: ${pageProps}`); @@ -28,11 +34,11 @@ export function JitsuRoot({ pageProps, children }: MyAppProps) { options={ isJitsuEnvs ? { - host: jitsuConf?.host ?? '', - writeKey: jitsuConf?.writeKey ?? undefined, - debug: jitsuConf?.debug, - cookieDomain: jitsuConf?.cookieDomain ?? undefined, - echoEvents: jitsuConf?.echoEvents + host: jitsuConf.host ?? '', + writeKey: jitsuConf.writeKey ?? undefined, + debug: jitsuConf.debug, + cookieDomain: jitsuConf.cookieDomain ?? undefined, + echoEvents: jitsuConf.echoEvents } : { disabled: true