UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

1 lines 12.2 kB
{"version":3,"sources":["../../../src/components/Auth/useUrlAuthentication.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { useLocation } from 'react-router-dom';\n\n/**\n * Options interface for the useUrlAuthentication hook\n *\n * @template Tokens - Type for authentication tokens\n * @template Session - Type for session information\n * @template Profile - Type for profile information\n * @template User - Type for user information\n *\n * @interface UseUrlAuthOptions\n * @property {(tokens: Tokens) => void} setTokens - Function to set authentication tokens\n * @property {(session: Session) => void} setSessionInfo - Function to set session information\n * @property {(profile: Profile) => void} [setSelectedProfile] - Optional function to set selected profile\n * @property {(user: User) => void} [setUser] - Optional function to set user data\n * @property {object} api - API instance with get method\n * @property {(endpoint: string, config: unknown) => Promise<unknown>} api.get - API get method\n * @property {string} endpoint - API endpoint to fetch session data\n * @property {(searchParams: URLSearchParams) => object} [extractParams] - Custom parameter extraction function\n * @property {() => void} [clearParamsFromURL] - Function to clear URL parameters after processing\n * @property {number} [maxRetries] - Maximum number of retry attempts (default: 3)\n * @property {number} [retryDelay] - Base delay between retries in milliseconds (default: 1000)\n * @property {(error: unknown) => void} [onError] - Error handler callback\n */\nexport interface UseUrlAuthOptions<\n Tokens = unknown,\n Session = unknown,\n Profile = unknown,\n User = unknown,\n> {\n setTokens: (tokens: Tokens) => void;\n setSessionInfo: (session: Session) => void;\n setSelectedProfile?: (profile: Profile) => void;\n setUser?: (user: User) => void;\n api: { get: (endpoint: string, config: unknown) => Promise<unknown> };\n endpoint: string;\n extractParams?: (searchParams: URLSearchParams) => {\n sessionId: string;\n token: string;\n refreshToken: string;\n };\n clearParamsFromURL?: () => void;\n maxRetries?: number;\n retryDelay?: number;\n onError?: (error: unknown) => void;\n}\n\n/**\n * Helper function to extract authentication parameters from URL\n *\n * @param {object} location - Location object with search property\n * @param {string} location.search - URL search string\n * @param {function} [extractParams] - Custom parameter extraction function\n * @returns {object} Object with sessionId, token, and refreshToken\n *\n * @private\n */\nconst getAuthParams = (\n location: { search: string },\n extractParams?: (searchParams: URLSearchParams) => {\n sessionId: string;\n token: string;\n refreshToken: string;\n }\n) => {\n const searchParams = new URLSearchParams(location.search);\n return extractParams\n ? extractParams(searchParams)\n : {\n sessionId: searchParams.get('sessionId'),\n token: searchParams.get('token'),\n refreshToken: searchParams.get('refreshToken'),\n };\n};\n\n/**\n * Helper function to validate authentication parameters\n *\n * @param {object} authParams - Authentication parameters object\n * @param {string | null} authParams.sessionId - Session ID from URL\n * @param {string | null} authParams.token - Authentication token from URL\n * @param {string | null} authParams.refreshToken - Refresh token from URL\n * @returns {boolean} True if all required parameters are present\n *\n * @private\n */\nconst hasValidAuthParams = (authParams: {\n sessionId: string | null;\n token: string | null;\n refreshToken: string | null;\n}) => {\n return !!(\n authParams?.sessionId &&\n authParams?.token &&\n authParams?.refreshToken\n );\n};\n\n/**\n * Helper function to check if response has valid profile data\n *\n * @param {unknown} data - Response data to validate\n * @returns {data is Record<string, unknown>} Type guard for valid profile data\n *\n * @private\n */\nconst hasValidProfileData = (\n data: unknown\n): data is Record<string, unknown> => {\n return data !== null && typeof data === 'object' && data !== undefined;\n};\n\n/**\n * Helper function to handle profile selection from response data\n *\n * @template Profile - Profile type\n * @param {unknown} responseData - Response data from API\n * @param {(profile: Profile) => void} [setSelectedProfile] - Optional function to set selected profile\n * @returns {void}\n *\n * @private\n */\nconst handleProfileSelection = <Profile>(\n responseData: unknown,\n setSelectedProfile?: (profile: Profile) => void\n) => {\n if (!setSelectedProfile) return;\n if (!hasValidProfileData(responseData)) return;\n\n const profileId = responseData.profileId;\n const isValidProfileId = profileId !== null && profileId !== undefined;\n\n if (isValidProfileId) {\n setSelectedProfile({\n id: profileId,\n } as Profile);\n }\n};\n\n/**\n * Helper function to handle user data extraction from response data\n *\n * @template User - User type\n * @param {unknown} responseData - Response data from API\n * @param {(user: User) => void} [setUser] - Optional function to set user data\n * @returns {void}\n *\n * @private\n */\nconst handleUserData = <User>(\n responseData: unknown,\n setUser?: (user: User) => void\n) => {\n if (!setUser) return;\n if (!hasValidProfileData(responseData)) return;\n\n // Extrair dados do usuário da resposta da API\n const userId = responseData.userId;\n const userName = responseData.userName;\n const userEmail = responseData.userEmail;\n\n if (userId) {\n const userData: Record<string, unknown> = {\n id: userId,\n };\n\n if (userName) {\n userData.name = userName;\n }\n\n if (userEmail) {\n userData.email = userEmail;\n }\n\n // Adicionar outros campos conforme necessário\n setUser(userData as User);\n }\n};\n\n/**\n * Hook for handling URL-based authentication\n * Extracts authentication parameters from URL and processes them\n *\n * @template Tokens - Type for authentication tokens\n * @template Session - Type for session information\n * @template Profile - Type for profile information\n * @template User - Type for user information\n *\n * @param {UseUrlAuthOptions<Tokens, Session, Profile, User>} options - Configuration options\n * @returns {void}\n *\n * @example\n * ```typescript\n * useUrlAuthentication({\n * setTokens: (tokens) => authStore.setTokens(tokens),\n * setSessionInfo: (session) => authStore.setSessionInfo(session),\n * setSelectedProfile: (profile) => authStore.setProfile(profile),\n * setUser: (user) => authStore.setUser(user),\n * api: apiInstance,\n * endpoint: '/auth/session',\n * clearParamsFromURL: () => navigate('/', { replace: true })\n * });\n * ```\n */\nexport function useUrlAuthentication<\n Tokens = unknown,\n Session = unknown,\n Profile = unknown,\n User = unknown,\n>(options: UseUrlAuthOptions<Tokens, Session, Profile, User>) {\n const location = useLocation();\n const processedRef = useRef(false);\n\n useEffect(() => {\n /**\n * Main authentication handler that processes URL parameters\n *\n * @private\n */\n const handleAuthentication = async (): Promise<void> => {\n // Check if we already processed this request\n if (processedRef.current) {\n return;\n }\n\n const authParams = getAuthParams(location, options.extractParams);\n\n // Only proceed if we have all required auth parameters\n if (!hasValidAuthParams(authParams)) {\n return;\n }\n\n // Mark as processed to prevent multiple calls\n processedRef.current = true;\n\n try {\n // Set tokens first\n options.setTokens({\n token: authParams.token,\n refreshToken: authParams.refreshToken,\n } as Tokens);\n\n // Call session-info with proper error handling and retry\n const maxRetries = options.maxRetries || 3;\n const retryDelay = options.retryDelay || 1000;\n let retries = 0;\n let sessionData = null;\n\n while (retries < maxRetries && !sessionData) {\n try {\n const response = (await options.api.get(options.endpoint, {\n headers: {\n Authorization: `Bearer ${authParams.token}`,\n },\n })) as { data: { data: unknown; [key: string]: unknown } };\n\n sessionData = response.data.data;\n break;\n } catch (error) {\n retries++;\n console.warn(\n `Tentativa ${retries}/${maxRetries} falhou para ${options.endpoint}:`,\n error\n );\n\n if (retries < maxRetries) {\n // Wait before retry (exponential backoff)\n await new Promise((resolve) =>\n setTimeout(resolve, retryDelay * retries)\n );\n } else {\n throw error;\n }\n }\n }\n\n // Always call setSessionInfo with the received data (even if null)\n options.setSessionInfo(sessionData as Session);\n handleProfileSelection(sessionData, options.setSelectedProfile);\n handleUserData(sessionData, options.setUser);\n options.clearParamsFromURL?.();\n } catch (error) {\n console.error('Erro ao obter informações da sessão:', error);\n // Reset processed flag on error to allow retry\n processedRef.current = false;\n // Call error handler if provided\n options.onError?.(error);\n }\n };\n\n handleAuthentication();\n }, [\n location.search,\n options.setSessionInfo,\n options.setSelectedProfile,\n options.setUser,\n options.setTokens,\n options.api,\n options.endpoint,\n options.extractParams,\n options.clearParamsFromURL,\n options.maxRetries,\n options.retryDelay,\n options.onError,\n ]);\n}\n"],"mappings":"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","names":[]}