diff --git a/src/abstract/lib/getProgressId.ts b/src/abstract/lib/getProgressId.ts index 4aa85495a..3f97067a5 100644 --- a/src/abstract/lib/getProgressId.ts +++ b/src/abstract/lib/getProgressId.ts @@ -1,3 +1,9 @@ export const getProgressId = (entityId: string, eventId: string): string => { return `${entityId}/${eventId}` } + +export const getDataFromProgressId = (progressId: string): { entityId: string; eventId: string } => { + const [entityId, eventId] = progressId.split("/") + + return { entityId, eventId } +} diff --git a/src/entities/event/api/index.ts b/src/entities/event/api/index.ts index 347cf2b5a..d266e622e 100644 --- a/src/entities/event/api/index.ts +++ b/src/entities/event/api/index.ts @@ -1 +1,2 @@ export * from "./useEventsByAppletIdQuery" +export * from "./useUserEventsMutation" diff --git a/src/entities/event/api/useUserEventsMutation.ts b/src/entities/event/api/useUserEventsMutation.ts new file mode 100644 index 000000000..94fdd9591 --- /dev/null +++ b/src/entities/event/api/useUserEventsMutation.ts @@ -0,0 +1,7 @@ +import { MutationOptions, eventsService, useBaseMutation } from "~/shared/api" + +type Options = MutationOptions + +export const useUserEventsMutation = (options?: Options) => { + return useBaseMutation(["getUserEvents"], eventsService.getUserEvents, { ...options }) +} diff --git a/src/shared/api/services/events.service.ts b/src/shared/api/services/events.service.ts index b0ff788df..891f1f256 100644 --- a/src/shared/api/services/events.service.ts +++ b/src/shared/api/services/events.service.ts @@ -1,5 +1,10 @@ import axiosService from "./axios" -import { GetEventsByAppletIdPayload, GetEventsByPublicAppletKey, SuccessEventsByAppletIdResponse } from "../types" +import { + GetEventsByAppletIdPayload, + GetEventsByPublicAppletKey, + SuccessAllUserEventsResponse, + SuccessEventsByAppletIdResponse, +} from "../types" function eventService() { return { @@ -7,7 +12,7 @@ function eventService() { return axiosService.get(`/users/me/events/${payload.appletId}`) }, getUserEvents() { - return axiosService.get("/users/me/events") + return axiosService.get("/users/me/events") }, getEventsByPublicAppletKey(payload: GetEventsByPublicAppletKey) { return axiosService.get(`/public/applets/${payload.publicAppletKey}/events`) diff --git a/src/shared/api/types/applet.ts b/src/shared/api/types/applet.ts index 1f500078c..46b91aab4 100644 --- a/src/shared/api/types/applet.ts +++ b/src/shared/api/types/applet.ts @@ -125,6 +125,11 @@ export type AppletEventsResponse = { events: ScheduleEventDto[] } +export type AllUserEventsDTO = { + appletId: string + events: ScheduleEventDto[] +} + export type AppletEncryptionDTO = { accountId: string base: string // Contains number[] diff --git a/src/shared/api/types/events.ts b/src/shared/api/types/events.ts index a473bb5af..f69f788b8 100644 --- a/src/shared/api/types/events.ts +++ b/src/shared/api/types/events.ts @@ -1,4 +1,4 @@ -import { AppletEventsResponse } from "./applet" +import { AllUserEventsDTO, AppletEventsResponse } from "./applet" import { BaseSuccessResponse } from "./base" import { HourMinute } from "../../utils" @@ -14,6 +14,7 @@ export type GetEventsByPublicAppletKey = { } export type SuccessEventsByAppletIdResponse = BaseSuccessResponse +export type SuccessAllUserEventsResponse = BaseSuccessResponse export type EventsByAppletIdResponseDTO = { appletId: string diff --git a/src/shared/utils/index.ts b/src/shared/utils/index.ts index 15f5f6968..82d738379 100644 --- a/src/shared/utils/index.ts +++ b/src/shared/utils/index.ts @@ -13,3 +13,5 @@ export * from "./helpers" export * from "./eventEmitter" export * from "./dictionary.map" export * from "./mixpanel" +export * from "./useTimer" +export * from "./matchPaths" diff --git a/src/shared/utils/matchPaths.ts b/src/shared/utils/matchPaths.ts new file mode 100644 index 000000000..ebbede444 --- /dev/null +++ b/src/shared/utils/matchPaths.ts @@ -0,0 +1,22 @@ +import { matchPath } from "react-router-dom" + +type Params = { + end?: boolean + caseSensitive?: boolean +} + +export const matchPaths = ( + patterns: string[], + pathname: string, + params: Params = { end: false, caseSensitive: false }, +) => { + return patterns.map(path => + matchPath( + { + path, + ...params, + }, + pathname, + ), + ) +} diff --git a/src/shared/utils/useTimer.ts b/src/shared/utils/useTimer.ts new file mode 100644 index 000000000..d5a8f9fc8 --- /dev/null +++ b/src/shared/utils/useTimer.ts @@ -0,0 +1,29 @@ +import { useCallback, useRef } from "react" + +type SetTimerProps = { + callback: () => void + delay: number +} + +export const useTimer = () => { + const timerRef = useRef(undefined) + + // this resets the timer if it exists. + const resetTimer = useCallback(() => { + if (timerRef) window.clearTimeout(timerRef.current) + }, [timerRef]) + + const setTimer = useCallback( + (props: SetTimerProps) => { + timerRef.current = window.setTimeout(() => { + // clears any pending timer. + resetTimer() + + props.callback() + }, props.delay) + }, + [resetTimer], + ) + + return { setTimer, resetTimer } +} diff --git a/src/widgets/ProtectedRoute/InactivityTracker.tsx b/src/widgets/ProtectedRoute/InactivityTracker.tsx index d55aa9fe9..1494249c2 100644 --- a/src/widgets/ProtectedRoute/InactivityTracker.tsx +++ b/src/widgets/ProtectedRoute/InactivityTracker.tsx @@ -1,43 +1,34 @@ -import { PropsWithChildren, useCallback, useEffect, useRef } from "react" +import { PropsWithChildren, useCallback, useEffect } from "react" import { useLogout } from "~/features/Logout" +import { useTimer } from "~/shared/utils" export type InactivityTrackerProps = PropsWithChildren -const events = ["load", "click", "scroll", "keypress"] +const events = ["load", "click", "scroll", "keypress", "mousemove"] const ONE_SEC = 1000 const ONE_MIN = 60 * ONE_SEC const LOGOUT_TIME_LIMIT = 15 * ONE_MIN // 15 min export const InactivityTracker = ({ children }: InactivityTrackerProps) => { - const timerRef = useRef(undefined) const { logout } = useLogout() + const { resetTimer, setTimer } = useTimer() - // this resets the timer if it exists. - const resetTimer = useCallback(() => { - if (timerRef) window.clearTimeout(timerRef.current) - }, [timerRef]) - - const logoutTimer = useCallback(() => { - timerRef.current = window.setTimeout(() => { - // clears any pending timer. - resetTimer() - - // Listener clean up. Removes the existing event listener from the window - Object.values(events).forEach(item => { - window.removeEventListener(item, resetTimer) - }) + const onLogoutTimerExpire = useCallback(() => { + // Listener clean up. Removes the existing event listener from the window + Object.values(events).forEach(item => { + window.removeEventListener(item, resetTimer) + }) - // logs out user - logout() - }, LOGOUT_TIME_LIMIT) - }, [resetTimer, logout]) + // logs out user + logout() + }, [logout, resetTimer]) const onActivityEventHandler = useCallback(() => { resetTimer() - logoutTimer() - }, [resetTimer, logoutTimer]) + setTimer({ delay: LOGOUT_TIME_LIMIT, callback: onLogoutTimerExpire }) + }, [resetTimer, setTimer, onLogoutTimerExpire]) useEffect(() => { Object.values(events).forEach(item => {