@skylabs-digital/react-identity-access 1.6.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/LoginForm.d.ts.map +1 -1
- package/dist/components/MagicLinkForm.d.ts.map +1 -1
- package/dist/components/MagicLinkVerify.d.ts +2 -2
- package/dist/components/MagicLinkVerify.d.ts.map +1 -1
- package/dist/components/SignupForm.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +1206 -1003
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/providers/AppProvider.d.ts +5 -0
- package/dist/providers/AppProvider.d.ts.map +1 -1
- package/dist/providers/AuthProvider.d.ts +15 -9
- package/dist/providers/AuthProvider.d.ts.map +1 -1
- package/dist/providers/TenantProvider.d.ts +6 -0
- package/dist/providers/TenantProvider.d.ts.map +1 -1
- package/dist/services/SessionManager.d.ts +22 -0
- package/dist/services/SessionManager.d.ts.map +1 -1
- package/dist/types/api.d.ts +4 -2
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/authParams.d.ts +49 -0
- package/dist/types/authParams.d.ts.map +1 -0
- package/package.json +4 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/services/HttpService.ts","../src/services/AppApiService.ts","../src/providers/AppProvider.tsx","../src/services/SessionManager.ts","../src/services/AuthApiService.ts","../src/services/RoleApiService.ts","../src/services/UserApiService.ts","../src/services/TenantApiService.ts","../src/providers/TenantProvider.tsx","../src/providers/AuthProvider.tsx","../src/services/FeatureFlagApiService.ts","../src/providers/FeatureFlagProvider.tsx","../src/services/SubscriptionApiService.ts","../src/providers/SubscriptionProvider.tsx","../src/types/api.ts","../src/components/Protected.tsx","../src/components/ProtectedRoute.tsx","../src/components/TenantRoute.tsx","../src/components/LandingRoute.tsx","../src/components/SubscriptionGuard.tsx","../src/components/FeatureFlag.tsx","../src/components/LoginForm.tsx","../src/components/SignupForm.tsx","../src/components/MagicLinkForm.tsx","../src/components/MagicLinkVerify.tsx","../src/components/PasswordRecoveryForm.tsx","../src/services/PermissionApiService.ts","../src/services/SubscriptionPlanApiService.ts","../src/services/HealthApiService.ts","../src/utils/mappers.ts"],"sourcesContent":["export interface RequestOptions {\n headers?: Record<string, string>;\n timeout?: number;\n skipAuth?: boolean; // Skip automatic auth header injection\n skipRetry?: boolean; // Skip automatic retry on 401\n}\n\nexport class HttpService {\n private baseUrl: string;\n private timeout: number;\n private sessionManager?: any; // SessionManager instance\n\n constructor(baseUrl: string, timeout = 10000) {\n this.baseUrl = baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n this.timeout = timeout;\n }\n\n setSessionManager(sessionManager: any): void {\n this.sessionManager = sessionManager;\n }\n\n getBaseUrl(): string {\n return this.baseUrl;\n }\n\n private async request<T>(\n method: string,\n endpoint: string,\n data?: any,\n options?: RequestOptions\n ): Promise<T> {\n return this.executeRequest<T>(method, endpoint, data, options, false);\n }\n\n private async executeRequest<T>(\n method: string,\n endpoint: string,\n data?: any,\n options?: RequestOptions,\n isRetry = false\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\n const requestTimeout = options?.timeout || this.timeout;\n\n // Inject auth headers automatically unless skipAuth is true\n let requestHeaders = {\n 'Content-Type': 'application/json',\n ...options?.headers,\n };\n\n if (!options?.skipAuth && this.sessionManager) {\n try {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n requestHeaders = { ...requestHeaders, ...authHeaders };\n } catch (error) {\n // If auth header injection fails, continue without auth\n console.warn('Failed to inject auth headers:', error);\n }\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: requestHeaders,\n body: data ? JSON.stringify(data) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle 401 Unauthorized with automatic retry\n if (response.status === 401 && !options?.skipRetry && !isRetry && this.sessionManager) {\n try {\n // Force token refresh by clearing current tokens and getting new auth headers\n const tokens = this.sessionManager.getTokens();\n if (tokens?.refreshToken) {\n // Trigger refresh through getAuthHeaders with expired token\n await this.sessionManager.getAuthHeaders();\n\n // Retry the original request\n return this.executeRequest<T>(method, endpoint, data, options, true);\n }\n } catch {\n // If refresh fails, throw the original 401 error\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n // Handle empty responses\n const contentType = response.headers.get('content-type');\n if (!contentType || !contentType.includes('application/json')) {\n return {} as T;\n }\n\n return await response.json();\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timeout after ${requestTimeout}ms`);\n }\n\n throw error;\n }\n }\n\n async get<T>(endpoint: string, options?: RequestOptions): Promise<T> {\n return this.request<T>('GET', endpoint, undefined, options);\n }\n\n async post<T>(endpoint: string, data: any, options?: RequestOptions): Promise<T> {\n return this.request<T>('POST', endpoint, data, options);\n }\n\n async put<T>(endpoint: string, data: any, options?: RequestOptions): Promise<T> {\n return this.request<T>('PUT', endpoint, data, options);\n }\n\n async delete<T>(endpoint: string, options?: RequestOptions): Promise<T> {\n return this.request<T>('DELETE', endpoint, undefined, options);\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n ApiResponse,\n App,\n CreateAppRequest,\n PublicAppInfo,\n PaginationParams,\n} from '../types/api';\n\nexport class AppApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager: SessionManager\n ) {}\n\n async createApp(request: CreateAppRequest): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<App>>('/apps/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getApps(params?: PaginationParams): Promise<{ apps: App[]; meta: any }> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/apps/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<App[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n apps: response.data,\n meta: response.meta,\n };\n }\n\n async getAppById(id: string): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<App>>(`/apps/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateApp(id: string, request: Partial<CreateAppRequest>): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<App>>(`/apps/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getPublicAppInfo(id: string): Promise<PublicAppInfo> {\n const response = await this.httpService.get<ApiResponse<PublicAppInfo>>(`/apps/${id}/public`);\n return response.data;\n }\n\n async setDefaultSubscriptionPlan(appId: string, planId: string): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<App>>(\n `/apps/${appId}/default-subscription-plan`,\n { planId },\n { headers: authHeaders }\n );\n return response.data;\n }\n\n async updateSettingsSchema(appId: string, schema: any, defaultSettings: any): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<App>>(\n `/apps/${appId}/settings-schema`,\n { schema, defaultSettings },\n { headers: authHeaders }\n );\n return response.data;\n }\n\n async exportConfig(appId: string): Promise<any> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<any>>(`/apps/${appId}/export-config`, {\n headers: authHeaders,\n });\n return response.data;\n }\n}\n","import {\n createContext,\n useContext,\n useMemo,\n ReactNode,\n useState,\n useEffect,\n useCallback,\n} from 'react';\nimport { HttpService } from '../services/HttpService';\nimport { AppApiService } from '../services/AppApiService';\nimport type { PublicAppInfo } from '../types/api';\n\nexport interface AppConfig {\n baseUrl: string;\n appId: string;\n // Fallbacks\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode | ((error: Error, retry: () => void) => ReactNode);\n}\n\ninterface AppContextValue {\n appId: string;\n baseUrl: string;\n // App info with settings schema\n appInfo: PublicAppInfo | null;\n isAppLoading: boolean;\n appError: Error | null;\n retryApp: () => void;\n}\n\nconst AppContext = createContext<AppContextValue | null>(null);\n\ninterface AppProviderProps {\n config: AppConfig;\n children: ReactNode;\n}\n\n// Default loading component\nconst DefaultLoadingFallback = () => (\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div>Loading application...</div>\n </div>\n);\n\n// Default error component\nconst DefaultErrorFallback = ({ error, retry }: { error: Error; retry: () => void }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n textAlign: 'center',\n padding: '20px',\n }}\n >\n <h2 style={{ color: '#dc3545', marginBottom: '16px' }}>Application Error</h2>\n <p style={{ color: '#6c757d', marginBottom: '24px' }}>\n {error.message || 'Unable to load application'}\n </p>\n <button\n onClick={retry}\n style={{\n padding: '8px 16px',\n backgroundColor: '#007bff',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n </div>\n);\n\nexport function AppProvider({ config, children }: AppProviderProps) {\n // App info state\n const [appInfo, setAppInfo] = useState<PublicAppInfo | null>(null);\n const [isAppLoading, setIsAppLoading] = useState(true);\n const [appError, setAppError] = useState<Error | null>(null);\n\n const contextValue = useMemo(() => {\n // Retry function for app loading\n const retryApp = () => {\n loadApp();\n };\n\n return {\n appId: config.appId,\n baseUrl: config.baseUrl,\n // App info\n appInfo,\n isAppLoading,\n appError,\n retryApp,\n };\n }, [config, appInfo, isAppLoading, appError]);\n\n // Load app info\n const loadApp = useCallback(async () => {\n try {\n setIsAppLoading(true);\n setAppError(null);\n\n const httpService = new HttpService(config.baseUrl);\n const appApi = new AppApiService(httpService, {} as any); // SessionManager not needed for public endpoint\n const appData = await appApi.getPublicAppInfo(config.appId);\n setAppInfo(appData);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load app information');\n setAppError(error);\n setAppInfo(null);\n } finally {\n setIsAppLoading(false);\n }\n }, [config.baseUrl, config.appId]);\n\n // Load app info on mount\n useEffect(() => {\n loadApp();\n }, [loadApp]);\n\n // Show loading fallback for app info\n if (isAppLoading) {\n return <>{config.loadingFallback || <DefaultLoadingFallback />}</>;\n }\n\n // Show error fallback for app info\n if (appError) {\n const ErrorComponent =\n typeof config.errorFallback === 'function'\n ? config.errorFallback(appError, () => loadApp())\n : config.errorFallback || <DefaultErrorFallback error={appError} retry={() => loadApp()} />;\n\n return <>{ErrorComponent}</>;\n }\n\n return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>;\n}\n\nexport function useApp(): AppContextValue {\n const context = useContext(AppContext);\n if (!context) {\n throw new Error('useApp must be used within an AppProvider');\n }\n return context;\n}\n\n// Backward compatibility\nexport const useApi = useApp;\n","export interface TokenData {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n expiresIn?: number;\n tokenType?: string;\n}\n\nexport interface TokenStorage {\n get(): any;\n set(data: any): void;\n clear(): void;\n}\n\nexport interface SessionConfig {\n storageKey?: string;\n autoRefresh?: boolean;\n refreshThreshold?: number;\n onRefreshFailed?: () => void;\n tokenStorage?: TokenStorage;\n baseUrl?: string; // Base URL for API calls\n}\n\nexport class SessionManager {\n private storageKey: string;\n private autoRefresh: boolean;\n private refreshThreshold: number;\n private baseUrl: string;\n private onRefreshFailed?: () => void;\n private tokenStorage: TokenStorage;\n\n // Refresh queue management\n private refreshPromise: Promise<void> | null = null;\n private refreshQueue: Array<{\n resolve: (headers: Record<string, string>) => void;\n reject: (error: Error) => void;\n }> = [];\n\n constructor(config: SessionConfig = {}) {\n this.storageKey = config.storageKey || 'auth_tokens';\n this.autoRefresh = config.autoRefresh ?? true;\n this.refreshThreshold = config.refreshThreshold || 300000; // 5 minutes\n this.onRefreshFailed = config.onRefreshFailed;\n this.baseUrl = config.baseUrl || '';\n\n // Use provided tokenStorage or create default localStorage implementation\n this.tokenStorage = config.tokenStorage || {\n get: () => {\n try {\n const stored = localStorage.getItem(this.storageKey);\n return stored ? JSON.parse(stored) : null;\n } catch {\n return null;\n }\n },\n set: (data: any) => {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(data));\n } catch {\n // Handle storage errors silently\n }\n },\n clear: () => {\n try {\n localStorage.removeItem(this.storageKey);\n } catch {\n // Handle storage errors silently\n }\n },\n };\n }\n\n setTokens(tokens: TokenData): void {\n // Convert expiresIn to expiresAt if needed\n const tokenData: TokenData = {\n ...tokens,\n expiresAt:\n tokens.expiresAt || (tokens.expiresIn ? Date.now() + tokens.expiresIn * 1000 : undefined),\n };\n\n this.tokenStorage.set(tokenData);\n }\n\n getTokens(): TokenData | null {\n return this.tokenStorage.get();\n }\n\n clearTokens(): void {\n this.tokenStorage.clear();\n }\n\n isTokenExpired(token?: TokenData): boolean {\n const tokens = token || this.getTokens();\n if (!tokens?.expiresAt) return false;\n\n return Date.now() >= tokens.expiresAt;\n }\n\n shouldRefreshToken(token?: TokenData): boolean {\n const tokens = token || this.getTokens();\n if (!tokens?.expiresAt || !this.autoRefresh) return false;\n\n return Date.now() >= tokens.expiresAt - this.refreshThreshold;\n }\n\n getAccessToken(): string | null {\n const tokens = this.getTokens();\n return tokens?.accessToken || null;\n }\n\n async getAuthHeaders(): Promise<Record<string, string>> {\n const tokens = this.getTokens();\n\n // No tokens available\n if (!tokens?.accessToken) {\n return {};\n }\n\n // Token is valid and doesn't need refresh yet, return headers immediately\n if (!this.shouldRefreshToken(tokens)) {\n return {\n Authorization: `Bearer ${tokens.accessToken}`,\n };\n }\n\n // Token needs refresh\n if (!tokens.refreshToken) {\n // No refresh token available, clear session and return empty headers\n this.clearSession();\n if (this.onRefreshFailed) {\n this.onRefreshFailed();\n }\n return {};\n }\n\n // If refresh is already in progress, queue this request\n if (this.refreshPromise) {\n return new Promise((resolve, reject) => {\n this.refreshQueue.push({ resolve, reject });\n });\n }\n\n // Start refresh process\n this.refreshPromise = this.performTokenRefresh(tokens.refreshToken);\n\n try {\n await this.refreshPromise;\n\n // Refresh successful, process queue\n const newTokens = this.getTokens();\n const headers: Record<string, string> = newTokens?.accessToken\n ? { Authorization: `Bearer ${newTokens.accessToken}` }\n : {};\n\n // Resolve all queued requests\n this.refreshQueue.forEach(({ resolve }) => resolve(headers));\n this.refreshQueue = [];\n\n return headers;\n } catch (error) {\n // Refresh failed, reject all queued requests\n const refreshError = error instanceof Error ? error : new Error('Token refresh failed');\n\n this.refreshQueue.forEach(({ reject }) => reject(refreshError));\n this.refreshQueue = [];\n\n // Clear session and notify\n this.clearSession();\n if (this.onRefreshFailed) {\n this.onRefreshFailed();\n }\n\n return {};\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async performTokenRefresh(refreshToken: string): Promise<void> {\n if (!this.baseUrl) {\n throw new Error('Base URL not configured for token refresh');\n }\n\n const url = `${this.baseUrl}/auth/refresh`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n refreshToken,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);\n }\n\n const refreshResponse = await response.json();\n\n this.setTokens({\n accessToken: refreshResponse.accessToken,\n refreshToken: refreshResponse.refreshToken || refreshToken,\n expiresIn: refreshResponse.expiresIn,\n });\n }\n\n setUser(user: any): void {\n // Store user data alongside tokens\n const currentData = this.tokenStorage.get() || {};\n this.tokenStorage.set({ ...currentData, user });\n }\n\n getUser(): any | null {\n const data = this.tokenStorage.get();\n return data?.user || null;\n }\n\n clearUser(): void {\n const currentData = this.tokenStorage.get() || {};\n delete currentData.user;\n this.tokenStorage.set(currentData);\n }\n\n clearSession(): void {\n this.clearTokens();\n this.clearUser();\n }\n\n hasValidSession(): boolean {\n const tokens = this.getTokens();\n return tokens !== null && !this.isTokenExpired(tokens);\n }\n}\n","import { HttpService } from './HttpService';\nimport type {\n LoginRequest,\n LoginResponse,\n SignupRequest,\n ChangePasswordRequest,\n RefreshTokenRequest,\n RefreshTokenResponse,\n MagicLinkRequest,\n MagicLinkResponse,\n VerifyMagicLinkRequest,\n VerifyMagicLinkResponse,\n ApiResponse,\n User,\n} from '../types/api';\n\nexport class AuthApiService {\n constructor(private httpService: HttpService) {}\n\n // Public endpoints - no auth required\n async login(request: LoginRequest): Promise<LoginResponse> {\n const response = await this.httpService.post<LoginResponse>('/auth/login', request);\n console.log(response);\n return response;\n }\n\n async signup(request: SignupRequest): Promise<User> {\n const response = await this.httpService.post<User>('/auth/signup', request);\n return response;\n }\n\n async signupTenantAdmin(request: {\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n password: string;\n tenantName: string;\n appId?: string;\n }): Promise<{ user: User; tenant: any }> {\n const response = await this.httpService.post<{ user: User; tenant: any }>(\n '/auth/signup/tenant-admin',\n request\n );\n return response;\n }\n\n async refreshToken(request: RefreshTokenRequest): Promise<RefreshTokenResponse> {\n const response = await this.httpService.post<RefreshTokenResponse>('/auth/refresh', request);\n return response;\n }\n\n async requestPasswordReset(request: { email: string; tenantId: string }): Promise<void> {\n await this.httpService.post<void>('/auth/password-reset/request', request);\n }\n\n async sendMagicLink(request: MagicLinkRequest): Promise<MagicLinkResponse> {\n const response = await this.httpService.post<MagicLinkResponse>(\n '/auth/magic-link/send',\n request\n );\n return response;\n }\n\n async verifyMagicLink(request: VerifyMagicLinkRequest): Promise<VerifyMagicLinkResponse> {\n const response = await this.httpService.post<VerifyMagicLinkResponse>(\n '/auth/magic-link/verify',\n request\n );\n return response;\n }\n\n async confirmPasswordReset(request: { token: string; newPassword: string }): Promise<void> {\n await this.httpService.post<void>('/auth/password-reset/confirm', request);\n }\n\n // Protected endpoints - auth required\n async changePassword(\n request: ChangePasswordRequest,\n authHeaders: Record<string, string>\n ): Promise<void> {\n await this.httpService.post<ApiResponse<null>>('/auth/change-password', request, {\n headers: authHeaders,\n });\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Role,\n CreateRoleRequest,\n AssignRoleRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class RoleApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createRole(request: CreateRoleRequest): Promise<Role> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Role>>('/roles/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getRoleById(id: string): Promise<Role> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Role>>(`/roles/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateRole(id: string, request: Partial<CreateRoleRequest>): Promise<Role> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Role>>(`/roles/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async deleteRole(id: string): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/roles/${id}`, {\n headers: authHeaders,\n });\n }\n\n // Public endpoint - no auth required\n async getRolesByApp(\n appId: string,\n params?: PaginationParams\n ): Promise<{ roles: Role[]; meta: any }> {\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/roles/app/${appId}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Role[]>>(url);\n\n return {\n roles: response.data,\n meta: response.meta,\n };\n }\n\n async assignRole(roleId: string, request: AssignRoleRequest): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.post<ApiResponse<null>>(`/roles/${roleId}/assign`, request, {\n headers: authHeaders,\n });\n }\n\n async revokeRole(roleId: string, request: AssignRoleRequest): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.post<ApiResponse<null>>(`/roles/${roleId}/revoke`, request, {\n headers: authHeaders,\n });\n }\n\n async getUserRoles(\n userId: string,\n params?: PaginationParams\n ): Promise<{ roles: Role[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/roles/user/${userId}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Role[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n roles: response.data,\n meta: response.meta,\n };\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type { User, CreateUserRequest, ApiResponse, PaginationParams } from '../types/api';\n\nexport class UserApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager: SessionManager\n ) {}\n\n async createUser(request: CreateUserRequest): Promise<User> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<User>>('/users/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getUsers(params?: PaginationParams): Promise<{ users: User[]; meta: any }> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/users/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<User[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n users: response.data,\n meta: response.meta,\n };\n }\n\n async getUserById(id: string): Promise<User> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<User>>(`/users/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateUser(id: string, request: Partial<CreateUserRequest>): Promise<User> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<User>>(`/users/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async deleteUser(id: string): Promise<void> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/users/${id}`, {\n headers: authHeaders,\n });\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Tenant,\n CreateTenantRequest,\n PublicTenantInfo,\n TenantSettings,\n UpdateTenantSettingsRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class TenantApiService {\n constructor(\n private httpService: HttpService,\n private appId: string,\n private sessionManager?: SessionManager\n ) {}\n\n async createTenant(request: CreateTenantRequest): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Tenant>>('/tenants/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getTenants(params?: PaginationParams): Promise<{ tenants: Tenant[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/tenants/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Tenant[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n tenants: response.data,\n meta: response.meta,\n };\n }\n\n async getTenantById(id: string): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Tenant>>(`/tenants/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateTenant(id: string, request: Partial<CreateTenantRequest>): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Tenant>>(`/tenants/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async adminUpdateTenant(id: string, request: Partial<CreateTenantRequest>): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Tenant>>(\n `/tenants/${id}/admin-update`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n // Public endpoint - no auth required\n async getPublicTenantInfo(slug: string): Promise<PublicTenantInfo> {\n const response = await this.httpService.get<ApiResponse<PublicTenantInfo>>(\n `/tenants/${this.appId}/${slug}/public`\n );\n return response.data;\n }\n\n // Settings endpoints\n async getTenantSettings(id: string): Promise<TenantSettings> {\n const response = await this.httpService.get<ApiResponse<TenantSettings>>(\n `/tenants/${id}/settings`\n );\n return response.data;\n }\n\n async updateTenantSettings(\n id: string,\n request: UpdateTenantSettingsRequest\n ): Promise<TenantSettings> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<TenantSettings>>(\n `/tenants/${id}/settings`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n}\n","import {\n createContext,\n useContext,\n useMemo,\n ReactNode,\n useState,\n useEffect,\n useCallback,\n} from 'react';\nimport { useApp } from './AppProvider';\nimport { HttpService } from '../services/HttpService';\nimport { TenantApiService } from '../services/TenantApiService';\nimport type { TenantSettings, JSONSchema, PublicTenantInfo } from '../types/api';\n\nexport interface TenantConfig {\n // Tenant configuration\n tenantMode?: 'subdomain' | 'selector';\n selectorParam?: string; // Default: 'tenant', used when tenantMode is 'selector'\n // SSR support\n initialTenant?: PublicTenantInfo;\n // Fallbacks\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode | ((error: Error, retry: () => void) => ReactNode);\n}\n\ninterface TenantContextValue {\n // Tenant info\n tenant: PublicTenantInfo | null;\n tenantSlug: string | null;\n isTenantLoading: boolean;\n tenantError: Error | null;\n retryTenant: () => void;\n // Settings\n settings: TenantSettings | null;\n settingsSchema: JSONSchema | null;\n isSettingsLoading: boolean;\n settingsError: Error | null;\n // Actions\n refreshSettings: () => void;\n // Validation\n validateSettings: (settings: TenantSettings) => { isValid: boolean; errors: string[] };\n}\n\nconst TenantContext = createContext<TenantContextValue | null>(null);\n\ninterface TenantProviderProps {\n config: TenantConfig;\n children: ReactNode;\n}\n\n// Default loading component\nconst DefaultLoadingFallback = () => (\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div>Loading tenant...</div>\n </div>\n);\n\n// Default error component\nconst DefaultErrorFallback = ({ error, retry }: { error: Error; retry: () => void }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n textAlign: 'center',\n padding: '20px',\n }}\n >\n <h2 style={{ color: '#dc3545', marginBottom: '16px' }}>Tenant Error</h2>\n <p style={{ color: '#6c757d', marginBottom: '24px' }}>\n {error.message || 'Unable to load tenant'}\n </p>\n <button\n onClick={retry}\n style={{\n padding: '8px 16px',\n backgroundColor: '#007bff',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n </div>\n);\n\nexport function TenantProvider({ config, children }: TenantProviderProps) {\n const { baseUrl, appInfo, appId } = useApp();\n\n // Tenant state\n const [tenant, setTenant] = useState<PublicTenantInfo | null>(config.initialTenant || null);\n const [isTenantLoading, setIsTenantLoading] = useState(!config.initialTenant);\n const [tenantError, setTenantError] = useState<Error | null>(null);\n\n // Settings state\n const [settings, setSettings] = useState<TenantSettings | null>(null);\n const [isSettingsLoading, setIsSettingsLoading] = useState(false);\n const [settingsError, setSettingsError] = useState<Error | null>(null);\n\n // Detect tenant slug from URL or config with localStorage fallback\n const detectTenantSlug = useCallback((): string | null => {\n const tenantMode = config.tenantMode || 'selector';\n const storageKey = `tenant`;\n\n if (typeof window === 'undefined') return null;\n\n if (tenantMode === 'subdomain') {\n const hostname = window.location.hostname;\n const parts = hostname.split('.');\n\n // Extract subdomain (assuming format: subdomain.domain.com)\n if (parts.length >= 3) {\n const subdomain = parts[0];\n // Save to localStorage for persistence\n localStorage.setItem(storageKey, subdomain);\n return subdomain;\n }\n\n // Fallback to localStorage if no subdomain found\n return localStorage.getItem(storageKey);\n } else if (tenantMode === 'selector') {\n // tenantMode === 'selector'\n const urlParams = new URLSearchParams(window.location.search);\n const urlTenant = urlParams.get(config.selectorParam || 'tenant');\n\n if (urlTenant) {\n // Save to localStorage when found in URL\n localStorage.setItem(storageKey, urlTenant);\n return urlTenant;\n }\n\n // Fallback to localStorage if not in URL\n return localStorage.getItem(storageKey);\n }\n\n // No tenant mode specified, return null\n return null;\n }, [config.tenantMode, config.selectorParam]);\n\n const tenantSlug = useMemo(() => detectTenantSlug(), [detectTenantSlug]);\n\n // Get settings schema from app info\n const settingsSchema = appInfo?.settingsSchema || null;\n\n // Load tenant info\n const loadTenant = useCallback(\n async (slug: string) => {\n try {\n setIsTenantLoading(true);\n setTenantError(null);\n\n const httpService = new HttpService(baseUrl);\n const tenantApi = new TenantApiService(httpService, appId);\n const tenantInfo = await tenantApi.getPublicTenantInfo(slug);\n setTenant(tenantInfo);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load tenant information');\n setTenantError(error);\n setTenant(null);\n } finally {\n setIsTenantLoading(false);\n }\n },\n [baseUrl, appId]\n );\n\n // Load tenant settings\n const loadSettings = useCallback(async () => {\n if (!tenant?.id) return;\n\n try {\n setIsSettingsLoading(true);\n setSettingsError(null);\n\n const httpService = new HttpService(baseUrl);\n const tenantApi = new TenantApiService(httpService, tenant.appId);\n const tenantSettings = await tenantApi.getTenantSettings(tenant.id);\n setSettings(tenantSettings);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load tenant settings');\n setSettingsError(error);\n setSettings(null);\n } finally {\n setIsSettingsLoading(false);\n }\n }, [baseUrl, tenant]);\n\n // Refresh settings\n const refreshSettings = useCallback(() => {\n loadSettings();\n }, [loadSettings]);\n\n // Validate settings against schema\n const validateSettings = useCallback(\n (settingsToValidate: TenantSettings) => {\n if (!settingsSchema) {\n return { isValid: true, errors: [] };\n }\n\n const errors: string[] = [];\n\n try {\n // If settingsSchema has properties, validate against them\n if (settingsSchema.properties) {\n Object.entries(settingsSchema.properties).forEach(([key, fieldSchema]) => {\n const value = settingsToValidate[key];\n\n // Check required fields\n if (settingsSchema.required?.includes(key) && (value === undefined || value === null)) {\n errors.push(`Field '${key}' is required`);\n return;\n }\n\n // Skip validation if value is not provided and not required\n if (value === undefined || value === null) return;\n\n // Type validation using JSONSchema\n if (fieldSchema.type) {\n const expectedType = fieldSchema.type;\n const actualType = typeof value;\n\n if (expectedType === 'string' && actualType !== 'string') {\n errors.push(`Field '${key}' must be a string`);\n } else if (\n (expectedType === 'number' || expectedType === 'integer') &&\n actualType !== 'number'\n ) {\n errors.push(`Field '${key}' must be a number`);\n } else if (expectedType === 'boolean' && actualType !== 'boolean') {\n errors.push(`Field '${key}' must be a boolean`);\n } else if (expectedType === 'array' && !Array.isArray(value)) {\n errors.push(`Field '${key}' must be an array`);\n }\n }\n\n // String length validation\n if (\n fieldSchema.minLength !== undefined &&\n typeof value === 'string' &&\n value.length < fieldSchema.minLength\n ) {\n errors.push(\n `Field '${key}' must be at least ${fieldSchema.minLength} characters long`\n );\n }\n if (\n fieldSchema.maxLength !== undefined &&\n typeof value === 'string' &&\n value.length > fieldSchema.maxLength\n ) {\n errors.push(\n `Field '${key}' must be no more than ${fieldSchema.maxLength} characters long`\n );\n }\n\n // Number range validation\n if (\n fieldSchema.minimum !== undefined &&\n typeof value === 'number' &&\n value < fieldSchema.minimum\n ) {\n errors.push(`Field '${key}' must be at least ${fieldSchema.minimum}`);\n }\n if (\n fieldSchema.maximum !== undefined &&\n typeof value === 'number' &&\n value > fieldSchema.maximum\n ) {\n errors.push(`Field '${key}' must be no more than ${fieldSchema.maximum}`);\n }\n\n // Pattern validation for strings\n if (fieldSchema.pattern && typeof value === 'string') {\n const regex = new RegExp(fieldSchema.pattern);\n if (!regex.test(value)) {\n errors.push(`Field '${key}' does not match the required pattern`);\n }\n }\n\n // Enum validation\n if (fieldSchema.enum && !fieldSchema.enum.includes(value)) {\n errors.push(`Field '${key}' must be one of: ${fieldSchema.enum.join(', ')}`);\n }\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n } catch {\n return {\n isValid: false,\n errors: ['Invalid settings schema or validation error'],\n };\n }\n },\n [settingsSchema]\n );\n\n // Load tenant on mount (if not SSR)\n useEffect(() => {\n if (!config.initialTenant && tenantSlug) {\n // Tenant slug found, try to load it from server\n loadTenant(tenantSlug);\n } else if (!config.initialTenant && !tenantSlug) {\n // No tenant slug found - continue without tenant\n setTenant(null);\n setTenantError(null);\n setIsTenantLoading(false);\n }\n }, [config.initialTenant, tenantSlug, loadTenant]);\n\n // Load settings when tenant changes\n useEffect(() => {\n if (tenant?.id) {\n loadSettings();\n } else {\n setSettings(null);\n setSettingsError(null);\n setIsSettingsLoading(false);\n }\n }, [tenant?.id, loadSettings]);\n\n const contextValue = useMemo(() => {\n // Retry function for tenant loading\n const retryTenant = () => {\n if (tenantSlug) {\n loadTenant(tenantSlug);\n }\n };\n\n return {\n // Tenant info\n tenant,\n tenantSlug,\n isTenantLoading,\n tenantError,\n retryTenant,\n // Settings\n settings,\n settingsSchema,\n isSettingsLoading,\n settingsError,\n // Actions\n refreshSettings,\n // Validation\n validateSettings,\n };\n }, [\n tenant,\n tenantSlug,\n isTenantLoading,\n tenantError,\n settings,\n settingsSchema,\n isSettingsLoading,\n settingsError,\n refreshSettings,\n validateSettings,\n ]);\n\n // Show loading fallback\n if (isTenantLoading) {\n return <>{config.loadingFallback || <DefaultLoadingFallback />}</>;\n }\n\n // Show error fallback\n if (tenantError) {\n const ErrorComponent =\n typeof config.errorFallback === 'function'\n ? config.errorFallback(tenantError, () => loadTenant(tenantSlug || ''))\n : config.errorFallback || (\n <DefaultErrorFallback error={tenantError} retry={() => loadTenant(tenantSlug || '')} />\n );\n\n return <>{ErrorComponent}</>;\n }\n\n return <TenantContext.Provider value={contextValue}>{children}</TenantContext.Provider>;\n}\n\nexport function useTenant(): TenantContextValue {\n const context = useContext(TenantContext);\n if (!context) {\n throw new Error('useTenant must be used within a TenantProvider');\n }\n return context;\n}\n\n// Backward compatibility\nexport const useTenantSettings = useTenant;\n\n// Convenience hook for just the settings\nexport function useSettings() {\n const { settings, settingsSchema, isSettingsLoading, settingsError, validateSettings } =\n useTenant();\n return {\n settings,\n settingsSchema,\n isLoading: isSettingsLoading,\n error: settingsError,\n validateSettings,\n };\n}\n\n// Convenience hook for just tenant info\nexport function useTenantInfo() {\n const { tenant, tenantSlug, isTenantLoading, tenantError, retryTenant } = useTenant();\n return {\n tenant,\n tenantSlug,\n isLoading: isTenantLoading,\n error: tenantError,\n retry: retryTenant,\n };\n}\n","import { createContext, useContext, ReactNode, useMemo, useState, useEffect } from 'react';\nimport { SessionManager } from '../services/SessionManager';\nimport { AuthApiService } from '../services/AuthApiService';\nimport { RoleApiService } from '../services/RoleApiService';\nimport { UserApiService } from '../services/UserApiService';\nimport { HttpService } from '../services/HttpService';\nimport { useApp } from './AppProvider';\nimport { useTenantInfo } from './TenantProvider';\nimport type { Role, Permission, User } from '../types/api';\n\nexport interface AuthConfig {\n onRefreshFailed?: () => void;\n initialRoles?: Role[]; // For SSR injection\n}\n\nexport interface AuthContextValue {\n sessionManager: SessionManager;\n authenticatedHttpService: HttpService; // Authenticated HttpService for protected endpoints\n // Auth methods\n login: (username: string, password: string, appId?: string, tenantId?: string) => Promise<any>;\n signup: (\n email?: string,\n phoneNumber?: string,\n name?: string,\n password?: string,\n tenantId?: string,\n lastName?: string,\n appId?: string\n ) => Promise<any>;\n signupTenantAdmin: (\n email?: string,\n phoneNumber?: string,\n name?: string,\n password?: string,\n tenantName?: string,\n lastName?: string,\n appId?: string\n ) => Promise<any>;\n // Magic Link methods\n sendMagicLink: (\n email: string,\n tenantId: string,\n frontendUrl: string,\n name?: string,\n lastName?: string,\n appId?: string\n ) => Promise<any>;\n verifyMagicLink: (token: string, email: string, appId: string, tenantId?: string) => Promise<any>;\n changePassword: (currentPassword: string, newPassword: string) => Promise<void>;\n requestPasswordReset: (email: string, tenantId: string) => Promise<void>;\n confirmPasswordReset: (token: string, newPassword: string) => Promise<void>;\n refreshToken: () => Promise<void>;\n logout: () => void;\n // Session methods\n setTokens: (tokens: { accessToken: string; refreshToken: string; expiresIn: number }) => void;\n hasValidSession: () => boolean;\n clearSession: () => void;\n // User data\n currentUser: User | null;\n isUserLoading: boolean;\n userError: Error | null;\n refreshUser: () => Promise<void>;\n // Role and Permission methods\n userRole: Role | null;\n userPermissions: string[];\n availableRoles: Role[];\n rolesLoading: boolean;\n hasPermission: (permission: string | Permission) => boolean;\n hasAnyPermission: (permissions: (string | Permission)[]) => boolean;\n hasAllPermissions: (permissions: (string | Permission)[]) => boolean;\n getUserPermissionStrings: () => string[];\n refreshRoles: () => Promise<void>;\n}\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\ninterface AuthProviderProps {\n config?: AuthConfig;\n children: ReactNode;\n}\n\nexport function AuthProvider({ config = {}, children }: AuthProviderProps) {\n const { appId, baseUrl } = useApp();\n const tenantInfo = useTenantInfo();\n const tenantSlug = tenantInfo?.tenantSlug || null;\n const [availableRoles, setAvailableRoles] = useState<Role[]>(config.initialRoles || []);\n const [rolesLoading, setRolesLoading] = useState(!config.initialRoles);\n const [currentUser, setCurrentUser] = useState<User | null>(null);\n const [isUserLoading, setIsUserLoading] = useState(false);\n const [userError, setUserError] = useState<Error | null>(null);\n\n // Create services with stable references\n const sessionManager = useMemo(() => {\n const storageKey = tenantSlug ? `auth_tokens_${tenantSlug}` : 'auth_tokens';\n const tokenStorage = {\n get: () => {\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : null;\n } catch {\n return null;\n }\n },\n set: (tokens: any) => {\n try {\n localStorage.setItem(storageKey, JSON.stringify(tokens));\n } catch {\n // Handle storage errors silently\n }\n },\n clear: () => {\n try {\n localStorage.removeItem(storageKey);\n } catch {\n // Handle storage errors silently\n }\n },\n };\n\n return new SessionManager({\n onRefreshFailed: config.onRefreshFailed,\n tokenStorage,\n baseUrl: baseUrl,\n });\n }, [tenantSlug, baseUrl, config.onRefreshFailed]);\n\n const authenticatedHttpService = useMemo(() => {\n const service = new HttpService(baseUrl);\n service.setSessionManager(sessionManager);\n return service;\n }, [baseUrl, sessionManager]);\n\n const authApiService = useMemo(() => {\n return new AuthApiService(new HttpService(baseUrl));\n }, [baseUrl]);\n\n const userApiService = useMemo(() => {\n return new UserApiService(authenticatedHttpService, sessionManager);\n }, [authenticatedHttpService, sessionManager]);\n\n const roleApiService = useMemo(() => {\n return new RoleApiService(new HttpService(baseUrl));\n }, [baseUrl]);\n\n // Calculate derived values with useMemo to prevent recalculation\n const user = useMemo(() => {\n return currentUser || sessionManager.getUser();\n }, [currentUser, sessionManager]);\n\n const userRole = useMemo(() => {\n return user?.roleId ? availableRoles.find(role => role.id === user.roleId) || null : null;\n }, [user, availableRoles]);\n\n const userPermissions = useMemo(() => {\n const permissions = userRole?.permissions || [];\n // Permissions from API are already strings in 'resource.action' format\n return permissions;\n }, [userRole]);\n\n // Debug log only when userPermissions actually changes\n useEffect(() => {\n console.log('AuthProvider - userPermissions changed:', userPermissions);\n }, [userPermissions]);\n\n const contextValue = useMemo(() => {\n // Load user data from API\n const loadUserData = async () => {\n try {\n setIsUserLoading(true);\n setUserError(null);\n\n const user = sessionManager.getUser();\n if (!user?.id) {\n throw new Error('No user ID available in session');\n }\n\n const userData = await userApiService.getUserById(user.id);\n setCurrentUser(userData);\n sessionManager.setUser(userData); // Update session with fresh data\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load user data');\n setUserError(error);\n console.error('Failed to load user data:', error);\n } finally {\n setIsUserLoading(false);\n }\n };\n\n const refreshUser = async () => {\n await loadUserData();\n };\n\n // Auth methods\n const login = async (username: string, password: string, appId?: string, tenantId?: string) => {\n const loginResponse = await authApiService.login({\n username,\n password,\n appId,\n tenantId,\n });\n\n sessionManager.setTokens({\n accessToken: loginResponse.accessToken,\n refreshToken: loginResponse.refreshToken,\n expiresIn: loginResponse.expiresIn,\n });\n\n // Store user data if available in the response\n if (loginResponse.user) {\n sessionManager.setUser(loginResponse.user);\n setCurrentUser(loginResponse.user);\n\n // Load complete user data from API after login\n try {\n await loadUserData();\n } catch (error) {\n console.warn('Failed to load complete user data after login:', error);\n }\n }\n\n return loginResponse;\n };\n\n const signup = async (\n email?: string,\n phoneNumber?: string,\n name?: string,\n password?: string,\n tenantId?: string,\n lastName?: string,\n appId?: string\n ) => {\n if (!email && !phoneNumber) {\n throw new Error('Either email or phoneNumber is required');\n }\n if (!name || !password) {\n throw new Error('Name and password are required');\n }\n\n const signupResponse = await authApiService.signup({\n email,\n phoneNumber,\n name,\n password,\n tenantId,\n lastName,\n appId,\n });\n return signupResponse;\n };\n\n const signupTenantAdmin = async (\n email?: string,\n phoneNumber?: string,\n name?: string,\n password?: string,\n tenantName?: string,\n lastName?: string,\n appId?: string\n ) => {\n if (!email && !phoneNumber) {\n throw new Error('Either email or phoneNumber is required');\n }\n if (!name || !password || !tenantName) {\n throw new Error('Name, password, and tenantName are required');\n }\n\n const signupResponse = await authApiService.signupTenantAdmin({\n email,\n phoneNumber,\n name,\n password,\n tenantName,\n appId,\n lastName,\n });\n return signupResponse;\n };\n\n const changePassword = async (currentPassword: string, newPassword: string) => {\n const authHeaders = await sessionManager.getAuthHeaders();\n await authApiService.changePassword({ currentPassword, newPassword }, authHeaders);\n };\n\n const requestPasswordReset = async (email: string, tenantId: string) => {\n await authApiService.requestPasswordReset({ email, tenantId });\n };\n\n const confirmPasswordReset = async (token: string, newPassword: string) => {\n await authApiService.confirmPasswordReset({ token, newPassword });\n };\n\n // Magic Link methods\n const sendMagicLink = async (\n email: string,\n tenantId: string,\n frontendUrl: string,\n name?: string,\n lastName?: string,\n appId?: string\n ) => {\n const response = await authApiService.sendMagicLink({\n email,\n tenantId,\n frontendUrl,\n name,\n lastName,\n appId,\n });\n return response;\n };\n\n const verifyMagicLink = async (\n token: string,\n email: string,\n appId: string,\n tenantId?: string\n ) => {\n const verifyResponse = await authApiService.verifyMagicLink({\n token,\n email,\n appId,\n tenantId,\n });\n\n // Set tokens from magic link verification\n sessionManager.setTokens({\n accessToken: verifyResponse.accessToken,\n refreshToken: verifyResponse.refreshToken,\n expiresIn: verifyResponse.expiresIn,\n });\n\n // Store user data\n if (verifyResponse.user) {\n sessionManager.setUser(verifyResponse.user);\n setCurrentUser(verifyResponse.user);\n\n // Load complete user data from API after magic link login\n try {\n await loadUserData();\n } catch (error) {\n console.warn('Failed to load complete user data after magic link login:', error);\n }\n }\n\n return verifyResponse;\n };\n\n const refreshToken = async () => {\n const tokens = sessionManager.getTokens();\n if (!tokens?.refreshToken) {\n throw new Error('No refresh token available');\n }\n\n const refreshResponse = await authApiService.refreshToken({\n refreshToken: tokens.refreshToken,\n });\n\n sessionManager.setTokens({\n accessToken: refreshResponse.accessToken,\n refreshToken: refreshResponse.refreshToken || tokens.refreshToken,\n expiresIn: refreshResponse.expiresIn,\n });\n };\n\n const logout = () => {\n sessionManager.clearSession();\n setCurrentUser(null);\n setUserError(null);\n };\n\n const setTokens = (tokens: {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n }) => {\n sessionManager.setTokens(tokens);\n };\n\n const hasValidSession = () => {\n return sessionManager.hasValidSession();\n };\n\n const clearSession = () => {\n sessionManager.clearSession();\n setCurrentUser(null);\n setUserError(null);\n };\n\n // Role and Permission methods\n const fetchRoles = async () => {\n if (!appId) return;\n\n try {\n setRolesLoading(true);\n const { roles } = await roleApiService.getRolesByApp(appId);\n setAvailableRoles(roles);\n } catch (error) {\n console.error('Failed to fetch roles:', error);\n } finally {\n setRolesLoading(false);\n }\n };\n\n const refreshRoles = async () => {\n await fetchRoles();\n };\n\n // Helper functions for permission checks\n const hasPermission = (permission: string | Permission): boolean => {\n if (!userPermissions || userPermissions.length === 0) {\n return false;\n }\n\n if (typeof permission === 'string') {\n // userPermissions is now an array of strings in 'resource.action' format\n return userPermissions.includes(permission);\n }\n\n // For Permission objects, convert to string and check\n const permissionString = `${permission.resource}.${permission.action}`;\n return userPermissions.includes(permissionString);\n };\n\n const hasAnyPermission = (permissions: (string | Permission)[]): boolean => {\n return permissions.some(permission => hasPermission(permission));\n };\n\n const hasAllPermissions = (permissions: (string | Permission)[]): boolean => {\n return permissions.every(permission => hasPermission(permission));\n };\n\n // Utility function to get all user permissions in resource.action format\n const getUserPermissionStrings = (): string[] => {\n if (!userPermissions) return [];\n // userPermissions is already an array of strings\n return userPermissions;\n };\n\n return {\n sessionManager,\n authenticatedHttpService,\n login,\n signup,\n signupTenantAdmin,\n sendMagicLink,\n verifyMagicLink,\n changePassword,\n requestPasswordReset,\n confirmPasswordReset,\n refreshToken,\n logout,\n setTokens,\n hasValidSession,\n clearSession,\n currentUser,\n isUserLoading,\n userError,\n refreshUser,\n userRole,\n userPermissions,\n availableRoles,\n rolesLoading,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n getUserPermissionStrings,\n refreshRoles,\n };\n }, [\n sessionManager,\n authenticatedHttpService,\n authApiService,\n userApiService,\n roleApiService,\n appId,\n availableRoles,\n currentUser,\n isUserLoading,\n userError,\n userRole,\n userPermissions,\n ]);\n\n // Fetch roles on mount if not provided via SSR\n useEffect(() => {\n if (!config.initialRoles && appId) {\n const fetchRoles = async () => {\n try {\n setRolesLoading(true);\n const internalHttpService = new HttpService(baseUrl);\n const roleApiService = new RoleApiService(internalHttpService);\n const { roles } = await roleApiService.getRolesByApp(appId);\n setAvailableRoles(roles);\n } catch (error) {\n console.error('Failed to fetch roles:', error);\n } finally {\n setRolesLoading(false);\n }\n };\n\n fetchRoles();\n }\n }, [appId, baseUrl, config.initialRoles]);\n\n // Initialize user data from session on mount\n useEffect(() => {\n const user = sessionManager.getUser();\n if (user && sessionManager.hasValidSession()) {\n setCurrentUser(user);\n }\n }, [sessionManager]);\n\n return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n return context;\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n ApiResponse,\n FeatureFlagItem,\n FeatureFlagValueResponse,\n FeatureFlag,\n CreateFeatureFlagRequest,\n PaginationParams,\n} from '../types/api';\n\nexport class FeatureFlagApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createFeatureFlag(request: CreateFeatureFlagRequest): Promise<FeatureFlag> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<FeatureFlag>>(\n '/feature-flags/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getFeatureFlags(\n params?: PaginationParams\n ): Promise<{ featureFlags: FeatureFlag[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/feature-flags/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<FeatureFlag[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n featureFlags: response.data,\n meta: response.meta,\n };\n }\n\n async getFeatureFlagById(id: string): Promise<FeatureFlag> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<FeatureFlag>>(`/feature-flags/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateFeatureFlag(\n id: string,\n request: Partial<CreateFeatureFlagRequest>\n ): Promise<FeatureFlag> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<FeatureFlag>>(\n `/feature-flags/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async deleteFeatureFlag(id: string): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/feature-flags/${id}`, {\n headers: authHeaders,\n });\n }\n\n // Public endpoint - no auth required\n async getTenantFeatureFlags(tenantId: string, appId: string): Promise<FeatureFlagItem[]> {\n if (!tenantId || !appId) {\n throw new Error('Tenant ID and App ID are required');\n }\n\n const queryParams = new URLSearchParams();\n queryParams.append('tenantId', tenantId);\n queryParams.append('appId', appId);\n\n const url = `/tenant-feature-flags${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<FeatureFlagItem[]>>(url, {\n headers: { 'X-Tenant-ID': tenantId },\n });\n\n return response.data;\n }\n\n // Public endpoint - no auth required\n async getTenantFeatureFlag(\n flagKey: string,\n tenantId: string,\n appId: string\n ): Promise<FeatureFlagValueResponse> {\n if (!flagKey || !tenantId || !appId) {\n throw new Error('Flag Key, Tenant ID and App ID are required');\n }\n\n const queryParams = new URLSearchParams();\n queryParams.append('tenantId', tenantId);\n queryParams.append('appId', appId);\n\n const url = `/tenant-feature-flags/${flagKey}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<FeatureFlagValueResponse>>(url, {\n headers: { 'X-Tenant-ID': tenantId },\n });\n\n return response.data;\n }\n}\n","import { createContext, useContext, ReactNode, useMemo, useState, useEffect } from 'react';\nimport { FeatureFlagApiService } from '../services/FeatureFlagApiService';\nimport { HttpService } from '../services/HttpService';\nimport { useApp } from './AppProvider';\nimport { useTenantInfo } from './TenantProvider';\nimport type { FeatureFlagItem } from '../types/api';\n\nexport interface FeatureFlagConfig {\n refreshInterval?: number; // in milliseconds, default 5 minutes\n onError?: (error: Error) => void;\n}\n\nexport interface FeatureFlagContextValue {\n featureFlags: FeatureFlagItem[];\n loading: boolean;\n error: string | null;\n isEnabled: (flagName: string) => boolean;\n getFlag: (flagName: string) => FeatureFlagItem | undefined;\n refresh: () => Promise<void>;\n}\n\nconst FeatureFlagContext = createContext<FeatureFlagContextValue | null>(null);\n\ninterface FeatureFlagProviderProps {\n config?: FeatureFlagConfig;\n children: ReactNode;\n}\n\nexport function FeatureFlagProvider({ config = {}, children }: FeatureFlagProviderProps) {\n const { baseUrl, appId } = useApp();\n const { tenant } = useTenantInfo();\n const [featureFlags, setFeatureFlags] = useState<FeatureFlagItem[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const featureFlagService = useMemo(() => {\n const httpService = new HttpService(baseUrl);\n return new FeatureFlagApiService(httpService);\n }, [baseUrl]);\n\n const fetchFeatureFlags = async () => {\n if (!tenant?.id) {\n setFeatureFlags([]);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await featureFlagService.getTenantFeatureFlags(tenant.id, appId);\n setFeatureFlags(response);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch feature flags';\n setError(errorMessage);\n if (config.onError) {\n config.onError(err instanceof Error ? err : new Error(errorMessage));\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Initial fetch and setup refresh interval\n useEffect(() => {\n fetchFeatureFlags();\n\n const refreshInterval = config.refreshInterval || 5 * 60 * 1000; // 5 minutes default\n const interval = setInterval(fetchFeatureFlags, refreshInterval);\n\n return () => clearInterval(interval);\n }, [tenant?.id, config.refreshInterval]);\n\n const contextValue = useMemo(() => {\n const isEnabled = (flagKey: string): boolean => {\n const flag = featureFlags.find(f => f.key === flagKey);\n return flag?.value === true;\n };\n\n const getFlag = (flagKey: string): FeatureFlagItem | undefined => {\n return featureFlags.find(f => f.key === flagKey);\n };\n\n const getFlagState = (flagKey: string): 'enabled' | 'disabled' | 'not_found' => {\n const flag = featureFlags.find(f => f.key === flagKey);\n if (!flag) return 'not_found';\n return flag.value ? 'enabled' : 'disabled';\n };\n\n const refresh = async () => {\n await fetchFeatureFlags();\n };\n\n return {\n featureFlags,\n loading,\n error,\n isEnabled,\n getFlag,\n getFlagState,\n refresh,\n };\n }, [featureFlags, loading, error]);\n\n return <FeatureFlagContext.Provider value={contextValue}>{children}</FeatureFlagContext.Provider>;\n}\n\nexport function useFeatureFlags(): FeatureFlagContextValue {\n const context = useContext(FeatureFlagContext);\n if (!context) {\n throw new Error('useFeatureFlags must be used within a FeatureFlagProvider');\n }\n return context;\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Subscription,\n CreateSubscriptionRequest,\n ApiResponse,\n TenantSubscriptionFeatures,\n} from '../types/api';\n\nexport class SubscriptionApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createSubscription(request: CreateSubscriptionRequest): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Subscription>>(\n '/subscriptions/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getSubscriptionById(id: string): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Subscription>>(\n `/subscriptions/subscriptions/${id}`,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async updateSubscription(\n id: string,\n request: Partial<CreateSubscriptionRequest>\n ): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Subscription>>(\n `/subscriptions/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async changeSubscriptionPlan(subscriptionId: string, planId: string): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Subscription>>(\n `/subscriptions/${subscriptionId}/plan`,\n { planId },\n { headers: authHeaders }\n );\n return response.data;\n }\n\n // Public endpoint - no auth required\n async getTenantSubscriptionFeatures(tenantId: string): Promise<TenantSubscriptionFeatures> {\n const response = await this.httpService.get<ApiResponse<TenantSubscriptionFeatures>>(\n `/subscriptions/tenants/${tenantId}/subscription-features`\n );\n return response.data;\n }\n\n async processPayment(subscriptionId: string, paymentData: any): Promise<any> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<any>>(\n `/subscriptions/${subscriptionId}/process-payment`,\n paymentData,\n { headers: authHeaders }\n );\n return response.data;\n }\n}\n","import { createContext, useContext, ReactNode, useMemo, useState, useEffect } from 'react';\nimport { SubscriptionApiService } from '../services/SubscriptionApiService';\nimport { HttpService } from '../services/HttpService';\nimport { useApp } from './AppProvider';\nimport { useTenantInfo } from './TenantProvider';\nimport type { TenantSubscriptionFeatures, PlanFeature } from '../types/api';\n\nexport interface SubscriptionConfig {\n refreshInterval?: number; // in milliseconds, default 10 minutes\n onError?: (error: Error) => void;\n}\n\nexport interface SubscriptionContextValue {\n subscription: TenantSubscriptionFeatures | null;\n features: PlanFeature[];\n loading: boolean;\n error: string | null;\n isFeatureEnabled: (featureKey: string) => boolean;\n getFeature: (featureKey: string) => PlanFeature | undefined;\n getFeatureValue: <T = any>(featureKey: string, defaultValue?: T) => T;\n hasAllowedPlan: (allowedPlans: string[]) => boolean;\n refresh: () => Promise<void>;\n}\n\nexport interface SubscriptionProviderProps {\n config?: SubscriptionConfig;\n children: ReactNode;\n}\n\nconst SubscriptionContext = createContext<SubscriptionContextValue | undefined>(undefined);\n\nexport function SubscriptionProvider({ config = {}, children }: SubscriptionProviderProps) {\n const { baseUrl } = useApp();\n const { tenant } = useTenantInfo();\n const [subscription, setSubscription] = useState<TenantSubscriptionFeatures | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Create subscription service\n const subscriptionService = useMemo(() => {\n const httpService = new HttpService(baseUrl);\n return new SubscriptionApiService(httpService);\n }, [baseUrl]);\n\n const fetchSubscription = async () => {\n if (!tenant?.id) {\n setSubscription(null);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await subscriptionService.getTenantSubscriptionFeatures(tenant.id);\n setSubscription(response);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch subscription';\n setError(errorMessage);\n if (config.onError) {\n config.onError(err instanceof Error ? err : new Error(errorMessage));\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Fetch subscription on mount and when tenant changes\n useEffect(() => {\n fetchSubscription();\n\n // Set up refresh interval if configured\n if (!config.refreshInterval) return;\n\n const refreshInterval = config.refreshInterval || 10 * 60 * 1000; // 10 minutes default\n const interval = setInterval(fetchSubscription, refreshInterval);\n\n return () => clearInterval(interval);\n }, [tenant?.id, config.refreshInterval]);\n\n const contextValue = useMemo(() => {\n const features = subscription?.features || [];\n\n const isFeatureEnabled = (featureKey: string): boolean => {\n const feature = features.find(f => f.key === featureKey);\n if (!feature) return false;\n\n // Handle different feature types\n if (feature.type === 'BOOLEAN' || feature.type === 'boolean') {\n return feature.value === true;\n }\n\n // For non-boolean features, consider them enabled if they have a truthy value\n return Boolean(feature.value);\n };\n\n const getFeature = (featureKey: string): PlanFeature | undefined => {\n return features.find(f => f.key === featureKey);\n };\n\n const getFeatureValue = <T = any,>(featureKey: string, defaultValue?: T): T => {\n const feature = features.find(f => f.key === featureKey);\n return feature ? feature.value : (defaultValue as T);\n };\n\n const hasAllowedPlan = (allowedPlans: string[]): boolean => {\n if (!subscription || !subscription.isActive) return false;\n\n // Check if current plan is in the allowed plans array\n return allowedPlans.includes(subscription.planId);\n };\n\n const refresh = async () => {\n await fetchSubscription();\n };\n\n return {\n subscription,\n features,\n loading,\n error,\n isFeatureEnabled,\n getFeature,\n getFeatureValue,\n hasAllowedPlan,\n refresh,\n };\n }, [subscription, loading, error]);\n\n return (\n <SubscriptionContext.Provider value={contextValue}>{children}</SubscriptionContext.Provider>\n );\n}\n\nexport function useSubscription(): SubscriptionContextValue {\n const context = useContext(SubscriptionContext);\n if (context === undefined) {\n throw new Error('useSubscription must be used within a SubscriptionProvider');\n }\n return context;\n}\n","// Common API Response Types\nexport interface ApiResponse<T> {\n success: boolean;\n message?: string;\n data: T;\n meta?: PaginationMeta;\n}\n\nexport interface ApiError {\n success: false;\n error: {\n code: string;\n };\n message: string;\n type?: 'AUTH' | 'VALIDATION' | 'BUSINESS' | 'SYSTEM';\n}\n\nexport interface PaginationMeta {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n hasNext: boolean;\n hasPrev: boolean;\n}\n\n// User Types\nexport enum UserType {\n SUPERUSER = 'SUPERUSER',\n TENANT_ADMIN = 'TENANT_ADMIN',\n USER = 'USER',\n}\n\nexport interface User {\n id: string;\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n isActive: boolean;\n userType: UserType;\n tenantId: string;\n roleId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateUserRequest {\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n password: string;\n tenantId: string;\n userType?: string;\n roleId?: string;\n}\n\n// Auth Types\nexport interface LoginRequest {\n username: string; // Can be email or phoneNumber\n password: string;\n appId?: string;\n tenantId?: string;\n}\n\nexport interface LoginResponse {\n user: User;\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\nexport interface SignupRequest {\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n password: string;\n tenantId?: string;\n appId?: string;\n}\n\nexport interface ChangePasswordRequest {\n currentPassword: string;\n newPassword: string;\n}\n\nexport interface RefreshTokenRequest {\n refreshToken: string;\n}\n\nexport interface RefreshTokenResponse {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\n// Magic Link Types\nexport interface MagicLinkRequest {\n email: string;\n tenantId: string;\n frontendUrl: string;\n name?: string; // Required for signup, optional for login\n lastName?: string;\n appId?: string;\n}\n\nexport interface MagicLinkResponse {\n message: string;\n emailSent: boolean;\n}\n\nexport interface VerifyMagicLinkRequest {\n token: string;\n email: string;\n appId: string;\n tenantId?: string;\n}\n\nexport interface VerifyMagicLinkResponse {\n user: User;\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n isNewUser: boolean; // Indicates if user was created during this process\n}\n\n// Role Types\nexport interface Role {\n id: string;\n name: string;\n description: string | null;\n appId: string;\n permissions: string[]; // API returns permissions as strings in 'resource.action' format\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateRoleRequest {\n name: string;\n description?: string;\n appId: string;\n permissionIds: string[];\n}\n\nexport interface AssignRoleRequest {\n userId: string;\n}\n\n// Permission Types\nexport interface Permission {\n id: string;\n name: string;\n description: string | null;\n resource: string;\n action: string;\n appId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreatePermissionRequest {\n name: string;\n description?: string;\n resource: string;\n action: string;\n appId?: string;\n}\n\n// App Types\nexport interface App {\n id: string;\n name: string;\n description: string | null;\n securityLevel: 'ADMIN' | 'USER';\n isActive: boolean;\n autoApproveTenants: boolean;\n defaultSubscriptionPlanId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface JSONSchema {\n $schema?: string;\n $id?: string;\n title?: string;\n description?: string;\n type?: 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';\n properties?: { [key: string]: JSONSchema };\n items?: JSONSchema;\n required?: string[];\n enum?: unknown[];\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n format?: string;\n default?: unknown;\n placeholder?: string;\n additionalProperties?: boolean | JSONSchema;\n}\n\nexport interface PublicAppInfo {\n id: string;\n name: string;\n description: string | null;\n settingsSchema: JSONSchema | null;\n}\n\nexport interface CreateAppRequest {\n name: string;\n description?: string;\n securityLevel?: 'ADMIN' | 'USER';\n}\n\n// Tenant Types\nexport interface Tenant {\n id: string;\n name: string;\n domain: string | null;\n isActive: boolean;\n appId: string;\n settings: Record<string, any>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateTenantRequest {\n name: string;\n domain?: string;\n appId: string;\n settings?: Record<string, any>;\n}\n\nexport interface PublicTenantInfo {\n id: string;\n name: string;\n domain: string | null;\n appId: string;\n}\n\nexport interface TenantSettings {\n [key: string]: any;\n}\n\nexport interface UpdateTenantSettingsRequest {\n settings: TenantSettings;\n}\n\n// Subscription Types\nexport interface Subscription {\n id: string;\n tenantId: string;\n planId: string;\n status: 'ACTIVE' | 'INACTIVE' | 'PENDING' | 'CANCELLED';\n startDate: string;\n endDate: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateSubscriptionRequest {\n tenantId: string;\n planId: string;\n startDate?: string;\n endDate?: string;\n}\n\n// Subscription Plan Types\nexport interface SubscriptionPlan {\n id: string;\n name: string;\n description: string | null;\n price: number;\n currency: string;\n billingCycle: 'MONTHLY' | 'YEARLY';\n appId: string;\n features: SubscriptionFeature[];\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SubscriptionFeature {\n id: string;\n name: string;\n description: string | null;\n featureType: 'BOOLEAN' | 'NUMERIC' | 'TEXT';\n value: any;\n planId: string;\n}\n\nexport interface CreateSubscriptionPlanRequest {\n name: string;\n description?: string;\n price: number;\n currency: string;\n billingCycle: 'MONTHLY' | 'YEARLY';\n appId: string;\n features: CreateSubscriptionFeatureRequest[];\n}\n\nexport interface CreateSubscriptionFeatureRequest {\n name: string;\n description?: string;\n featureType: 'BOOLEAN' | 'NUMERIC' | 'TEXT';\n value: any;\n}\n\n// Feature Flag Types\nexport interface FeatureFlag {\n id: string;\n name: string;\n description: string | null;\n isActive: boolean;\n appId: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateFeatureFlagRequest {\n name: string;\n description?: string;\n appId: string;\n}\n\n// Feature Flag API Response Types\nexport interface FeatureFlagItem {\n featureFlagId: string;\n key: string;\n name: string;\n value: boolean;\n isOverridden: boolean;\n}\n\nexport interface FeatureFlagValueResponse {\n key: string;\n value: boolean;\n}\n\n// Subscription Feature Types\nexport interface PlanFeature {\n key: string;\n name: string;\n type: 'BOOLEAN' | 'NUMBER' | 'STRING' | 'boolean' | 'number' | 'string';\n value: any;\n description?: string;\n}\n\nexport interface TenantSubscriptionFeatures {\n tenantId: string;\n planId: string;\n planName: string;\n subscriptionStatus: string;\n features: PlanFeature[];\n isActive: boolean;\n}\n\n// Common Query Parameters\nexport interface PaginationParams {\n page?: number;\n limit?: number;\n sortBy?: string;\n sortOrder?: 'ASC' | 'DESC';\n}\n","import { ReactNode } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { UserType, Permission } from '../types/api';\n\nexport interface ProtectedProps {\n children: ReactNode;\n fallback?: ReactNode;\n minUserType?: UserType;\n requiredPermissions?: (string | Permission)[];\n requireAllPermissions?: boolean; // If true, user must have ALL permissions. If false, user needs ANY permission\n}\n\nconst DefaultFallback = () => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '20px',\n backgroundColor: '#f8f9fa',\n border: '1px solid #dee2e6',\n borderRadius: '6px',\n textAlign: 'center',\n margin: '20px 0',\n }}\n >\n <div style={{ fontSize: '2rem', marginBottom: '10px' }}>🔒</div>\n <h3 style={{ color: '#495057', marginBottom: '10px' }}>Access Required</h3>\n <p style={{ color: '#6c757d', fontSize: '14px', marginBottom: '15px' }}>\n You need to be signed in to view this content.\n </p>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#007bff',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '14px',\n }}\n onClick={() => (window.location.href = '/login')}\n >\n Sign In\n </button>\n </div>\n);\n\nconst InsufficientPermissionsFallback = ({\n userType,\n minUserType,\n missingPermissions,\n}: {\n userType?: UserType;\n minUserType?: UserType;\n missingPermissions?: string[];\n}) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '20px',\n backgroundColor: '#fff3cd',\n border: '1px solid #ffeaa7',\n borderRadius: '6px',\n textAlign: 'center',\n margin: '20px 0',\n }}\n >\n <div style={{ fontSize: '2rem', marginBottom: '10px' }}>⚠️</div>\n <h3 style={{ color: '#856404', marginBottom: '10px' }}>Insufficient Permissions</h3>\n {minUserType && userType ? (\n <>\n <p style={{ color: '#856404', fontSize: '14px', marginBottom: '10px' }}>\n This content requires <strong>{minUserType}</strong> access level or higher.\n </p>\n <p style={{ color: '#6c757d', fontSize: '12px' }}>\n Your current access level: <strong>{userType}</strong>\n </p>\n </>\n ) : (\n <>\n <p style={{ color: '#856404', fontSize: '14px', marginBottom: '10px' }}>\n You don't have the required permissions to view this content.\n </p>\n {missingPermissions && missingPermissions.length > 0 && (\n <p style={{ color: '#6c757d', fontSize: '12px' }}>\n Required permissions: <strong>{missingPermissions.join(', ')}</strong>\n </p>\n )}\n </>\n )}\n </div>\n);\n\n// Helper function to check if user type meets minimum requirement\nconst hasMinimumUserType = (userType: UserType, minUserType: UserType): boolean => {\n const hierarchy = {\n [UserType.USER]: 1,\n [UserType.TENANT_ADMIN]: 2,\n [UserType.SUPERUSER]: 3,\n };\n\n return hierarchy[userType] >= hierarchy[minUserType];\n};\n\nexport function Protected({\n children,\n fallback,\n minUserType,\n requiredPermissions,\n requireAllPermissions = false,\n}: ProtectedProps) {\n const { hasValidSession, sessionManager, hasPermission, hasAnyPermission, hasAllPermissions } =\n useAuth();\n\n // Check if user has a valid session\n if (!hasValidSession()) {\n return <>{fallback || <DefaultFallback />}</>;\n }\n\n const user = sessionManager.getUser();\n\n if (!user) {\n // User session exists but no user data - show fallback\n return <>{fallback || <DefaultFallback />}</>;\n }\n\n // Check user type permissions if specified\n if (minUserType && !hasMinimumUserType(user.userType, minUserType)) {\n return <InsufficientPermissionsFallback userType={user.userType} minUserType={minUserType} />;\n }\n\n // Check specific permissions if specified\n if (requiredPermissions && requiredPermissions.length > 0) {\n const hasRequiredPermissions = requireAllPermissions\n ? hasAllPermissions(requiredPermissions)\n : hasAnyPermission(requiredPermissions);\n\n if (!hasRequiredPermissions) {\n // Get missing permissions for better error message\n const missingPermissions = requiredPermissions\n .filter(permission => !hasPermission(permission))\n .map(permission => (typeof permission === 'string' ? permission : permission.name));\n\n return <InsufficientPermissionsFallback missingPermissions={missingPermissions} />;\n }\n }\n\n // User is authenticated and has sufficient permissions\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\nimport { useAuth } from '../providers/AuthProvider';\nimport { UserType, Permission } from '../types/api';\n\nexport interface ProtectedRouteProps {\n children: ReactNode;\n redirectTo?: string;\n minUserType?: UserType;\n requiredPermissions?: (string | Permission)[];\n requireAllPermissions?: boolean; // If true, user must have ALL permissions. If false, user needs ANY permission\n fallback?: ReactNode;\n}\n\nconst DefaultFallback = ({ redirectPath }: { redirectPath: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>🔒</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Access Required</h2>\n <p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>\n You need to be signed in to access this page.\n </p>\n <p style={{ fontSize: '0.875rem', color: '#9ca3af' }}>Redirecting to {redirectPath}...</p>\n </div>\n </div>\n);\n\nconst InsufficientPermissionsFallback = ({\n userType,\n minUserType,\n missingPermissions,\n}: {\n userType?: UserType;\n minUserType?: UserType;\n missingPermissions?: string[];\n}) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>⚠️</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Insufficient Permissions</h2>\n {minUserType && userType ? (\n <>\n <p style={{ color: '#6b7280', marginBottom: '1rem' }}>\n This page requires <strong>{minUserType}</strong> access level or higher.\n </p>\n <p style={{ color: '#9ca3af', fontSize: '0.875rem' }}>\n Your current access level: <strong>{userType}</strong>\n </p>\n </>\n ) : (\n <>\n <p style={{ color: '#6b7280', marginBottom: '1rem' }}>\n You don't have the required permissions to access this page.\n </p>\n {missingPermissions && missingPermissions.length > 0 && (\n <p style={{ color: '#9ca3af', fontSize: '0.875rem' }}>\n Required permissions: <strong>{missingPermissions.join(', ')}</strong>\n </p>\n )}\n </>\n )}\n </div>\n </div>\n);\n\n// Helper function to check if user type meets minimum requirement\nconst hasMinimumUserType = (userType: UserType, minUserType: UserType): boolean => {\n const hierarchy = {\n [UserType.USER]: 1,\n [UserType.TENANT_ADMIN]: 2,\n [UserType.SUPERUSER]: 3,\n };\n\n return hierarchy[userType] >= hierarchy[minUserType];\n};\n\nexport function ProtectedRoute({\n children,\n redirectTo = '/login',\n minUserType,\n requiredPermissions,\n requireAllPermissions = false,\n fallback,\n}: ProtectedRouteProps) {\n const { hasValidSession, sessionManager, hasPermission, hasAnyPermission, hasAllPermissions } =\n useAuth();\n const location = useLocation();\n\n // Check if user has a valid session\n if (!hasValidSession()) {\n if (fallback) {\n return <>{fallback}</>;\n }\n\n return (\n <>\n <DefaultFallback redirectPath={redirectTo} />\n <Navigate to={redirectTo} state={{ from: location.pathname }} replace />\n </>\n );\n }\n\n const user = sessionManager.getUser();\n\n if (!user) {\n // User session exists but no user data - redirect to login\n return <Navigate to={redirectTo} state={{ from: location.pathname }} replace />;\n }\n\n // Check user type permissions if specified\n if (minUserType && !hasMinimumUserType(user.userType, minUserType)) {\n return <InsufficientPermissionsFallback userType={user.userType} minUserType={minUserType} />;\n }\n\n // Check specific permissions if specified\n if (requiredPermissions && requiredPermissions.length > 0) {\n const hasRequiredPermissions = requireAllPermissions\n ? hasAllPermissions(requiredPermissions)\n : hasAnyPermission(requiredPermissions);\n\n if (!hasRequiredPermissions) {\n // Get missing permissions for better error message\n const missingPermissions = requiredPermissions\n .filter(permission => !hasPermission(permission))\n .map(permission => (typeof permission === 'string' ? permission : permission.name));\n\n return <InsufficientPermissionsFallback missingPermissions={missingPermissions} />;\n }\n }\n\n // User is authenticated and has sufficient permissions\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface TenantRouteProps {\n children: ReactNode;\n redirectTo?: string;\n fallback?: ReactNode;\n}\n\nconst DefaultTenantRequiredFallback = ({ redirectPath }: { redirectPath: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>🏢</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Tenant Required</h2>\n <p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>\n This page requires a tenant context to access.\n </p>\n <p style={{ fontSize: '0.875rem', color: '#9ca3af' }}>Redirecting to {redirectPath}...</p>\n </div>\n </div>\n);\n\nexport function TenantRoute({ children, redirectTo = '/', fallback }: TenantRouteProps) {\n const { tenant, isLoading, error } = useTenantInfo();\n const location = useLocation();\n\n // Show loading state while tenant is being detected/loaded\n if (isLoading) {\n return null; // Let TenantProvider handle loading fallback\n }\n\n // If there's an error loading tenant, let TenantProvider handle it\n if (error) {\n return null; // Let TenantProvider handle error fallback\n }\n\n // Check if tenant is required but not present\n if (!tenant) {\n if (fallback) {\n return <>{fallback}</>;\n }\n\n return (\n <>\n <DefaultTenantRequiredFallback redirectPath={redirectTo} />\n <Navigate to={redirectTo} state={{ from: location.pathname }} replace />\n </>\n );\n }\n\n // Tenant is present, render children\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface LandingRouteProps {\n children: ReactNode;\n redirectTo?: string;\n fallback?: ReactNode;\n}\n\nconst DefaultTenantDetectedFallback = ({ redirectPath }: { redirectPath: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>🚀</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Tenant Detected</h2>\n <p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>\n You are accessing a tenant-specific context. Redirecting to the appropriate page.\n </p>\n <p style={{ fontSize: '0.875rem', color: '#9ca3af' }}>Redirecting to {redirectPath}...</p>\n </div>\n </div>\n);\n\nexport function LandingRoute({ children, redirectTo = '/dashboard', fallback }: LandingRouteProps) {\n const { tenant, isLoading, error } = useTenantInfo();\n const location = useLocation();\n\n // Show loading state while tenant is being detected/loaded\n if (isLoading) {\n return null; // Let TenantProvider handle loading fallback\n }\n\n // If there's an error loading tenant, let TenantProvider handle it\n if (error) {\n return null; // Let TenantProvider handle error fallback\n }\n\n // Check if tenant is present (should redirect to tenant-specific route)\n if (tenant) {\n if (fallback) {\n return <>{fallback}</>;\n }\n\n return (\n <>\n <DefaultTenantDetectedFallback redirectPath={redirectTo} />\n <Navigate to={redirectTo} state={{ from: location.pathname }} replace />\n </>\n );\n }\n\n // No tenant present, render public landing page\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { useSubscription } from '../providers/SubscriptionProvider';\n\nexport interface SubscriptionGuardProps {\n children: ReactNode;\n fallback?: ReactNode;\n allowedPlans?: string[];\n requiredFeature?: string;\n}\n\nconst DefaultFallback = () => (\n <div\n style={{\n padding: '2rem',\n textAlign: 'center',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '8px',\n color: '#dc2626',\n }}\n >\n <h3 style={{ margin: '0 0 1rem 0' }}>🔒 Subscription Required</h3>\n <p style={{ margin: 0 }}>\n This feature requires a higher subscription plan. Please upgrade your plan to access this\n content.\n </p>\n </div>\n);\n\nexport function SubscriptionGuard({\n children,\n fallback = <DefaultFallback />,\n allowedPlans,\n requiredFeature,\n}: SubscriptionGuardProps) {\n const { subscription, hasAllowedPlan, isFeatureEnabled, loading } = useSubscription();\n\n // Show loading state\n if (loading) {\n return (\n <div\n style={{\n padding: '2rem',\n textAlign: 'center',\n color: '#6b7280',\n }}\n >\n Loading subscription...\n </div>\n );\n }\n\n // No subscription data available\n if (!subscription) {\n return <>{fallback}</>;\n }\n\n // Check if subscription is active\n if (!subscription.isActive) {\n return <>{fallback}</>;\n }\n\n // Check allowed plans requirement\n if (allowedPlans && allowedPlans.length > 0 && !hasAllowedPlan(allowedPlans)) {\n return <>{fallback}</>;\n }\n\n // Check required feature\n if (requiredFeature && !isFeatureEnabled(requiredFeature)) {\n return <>{fallback}</>;\n }\n\n // All checks passed, render children\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { useFeatureFlags } from '../providers/FeatureFlagProvider';\n\ninterface FeatureFlagProps {\n name: string;\n children: ReactNode;\n fallback?: ReactNode;\n}\n\nconst DefaultFallback = ({ flagName }: { flagName: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '15px',\n backgroundColor: '#f8f9fa',\n border: '1px solid #dee2e6',\n borderRadius: '6px',\n textAlign: 'center',\n fontFamily: 'system-ui, sans-serif',\n color: '#6c757d',\n }}\n >\n <div style={{ fontSize: '24px', marginBottom: '8px' }}>🚧</div>\n <div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '4px' }}>\n Feature Not Available\n </div>\n <div style={{ fontSize: '12px', opacity: 0.7 }}>Feature flag \"{flagName}\" is disabled</div>\n </div>\n);\n\nexport function FeatureFlag({ name, children, fallback }: FeatureFlagProps) {\n const { isEnabled, loading } = useFeatureFlags();\n\n // Show loading state while fetching feature flags\n if (loading) {\n return (\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '10px',\n color: '#6c757d',\n fontSize: '14px',\n }}\n >\n Loading feature flags...\n </div>\n );\n }\n\n console.log(name, isEnabled(name));\n // Show children if feature flag is enabled\n if (isEnabled(name)) {\n return <>{children}</>;\n }\n\n // Show fallback if provided, otherwise show default fallback\n return <>{fallback || <DefaultFallback flagName={name} />}</>;\n}\n","import React, { useState } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\nimport { useApp } from '../providers/AppProvider';\n\nexport interface LoginFormCopy {\n title?: string;\n usernameLabel?: string;\n usernamePlaceholder?: string;\n passwordLabel?: string;\n passwordPlaceholder?: string;\n submitButton?: string;\n forgotPasswordLink?: string;\n signupLink?: string;\n signupText?: string;\n magicLinkText?: string;\n magicLinkLink?: string;\n errorMessage?: string;\n loadingText?: string;\n}\n\nexport interface LoginFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n inputContainer?: React.CSSProperties;\n passwordToggle?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n divider?: React.CSSProperties;\n}\n\nexport interface LoginFormIcons {\n showPassword?: React.ReactNode;\n hidePassword?: React.ReactNode;\n}\n\nexport interface LoginFormProps {\n copy?: LoginFormCopy;\n styles?: LoginFormStyles;\n icons?: LoginFormIcons;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onForgotPassword?: () => void;\n onSignupClick?: () => void;\n onMagicLinkClick?: () => void;\n showForgotPassword?: boolean;\n showSignupLink?: boolean;\n showMagicLinkOption?: boolean;\n className?: string;\n}\n\n// Default SVG icons for password toggle\nconst EyeIcon = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ flexShrink: 0 }}\n >\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n);\n\nconst EyeOffIcon = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ flexShrink: 0 }}\n >\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\" />\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n </svg>\n);\n\nconst defaultIcons: Required<LoginFormIcons> = {\n showPassword: <EyeIcon />,\n hidePassword: <EyeOffIcon />,\n};\n\nconst defaultCopy: Required<LoginFormCopy> = {\n title: 'Sign In',\n usernameLabel: 'Email or Phone',\n usernamePlaceholder: 'Enter your email or phone number',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Enter your password',\n submitButton: 'Sign In',\n forgotPasswordLink: 'Forgot your password?',\n signupLink: 'Sign up here',\n signupText: \"Don't have an account?\",\n magicLinkText: 'Prefer passwordless?',\n magicLinkLink: 'Use Magic Link',\n errorMessage: 'Invalid credentials',\n loadingText: 'Signing in...',\n};\n\nconst defaultStyles: Required<LoginFormStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#333333',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n width: '100%',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n inputContainer: {\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n },\n passwordToggle: {\n position: 'absolute',\n right: '0.75rem',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '0.25rem',\n color: '#6b7280',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '24px',\n height: '24px',\n borderRadius: '4px',\n transition: 'background-color 0.15s ease-in-out',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n divider: {\n margin: '0.5rem 0',\n color: '#6b7280',\n fontSize: '0.875rem',\n },\n};\n\nexport function LoginForm({\n copy = {},\n styles = {},\n icons = {},\n onSuccess,\n onError,\n onForgotPassword,\n onSignupClick,\n onMagicLinkClick,\n showForgotPassword = true,\n showSignupLink = true,\n showMagicLinkOption = true,\n className,\n}: LoginFormProps) {\n const [username, setUsername] = useState('');\n const [password, setPassword] = useState('');\n const [showPassword, setShowPassword] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{ username?: boolean; password?: boolean }>({});\n\n const { login } = useAuth();\n const { tenant } = useTenantInfo();\n const { appId } = useApp();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n const mergedIcons = { ...defaultIcons, ...icons };\n\n const validateForm = () => {\n const errors: { username?: boolean; password?: boolean } = {};\n\n if (!username.trim()) errors.username = true;\n if (!password.trim()) errors.password = true;\n\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) return;\n if (!tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n\n try {\n const result = await login(username, password, appId, tenant.id);\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: 'username' | 'password') => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading ? mergedStyles.buttonLoading : {}),\n ...(!username || !password || loading ? mergedStyles.buttonDisabled : {}),\n });\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n\n <form onSubmit={handleSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.usernameLabel}</label>\n <input\n id=\"username\"\n name=\"username\"\n type=\"text\"\n value={username}\n onChange={e => {\n setUsername(e.target.value);\n if (fieldErrors.username) {\n setFieldErrors(prev => ({ ...prev, username: false }));\n }\n }}\n placeholder={mergedCopy.usernamePlaceholder}\n style={getInputStyle('username')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.passwordLabel}</label>\n <div style={mergedStyles.inputContainer}>\n <input\n id=\"password\"\n name=\"password\"\n type={showPassword ? 'text' : 'password'}\n value={password}\n onChange={e => {\n setPassword(e.target.value);\n if (fieldErrors.password) {\n setFieldErrors(prev => ({ ...prev, password: false }));\n }\n }}\n placeholder={mergedCopy.passwordPlaceholder}\n style={{\n ...getInputStyle('password'),\n paddingRight: '2.5rem', // Make room for the icon\n }}\n disabled={loading}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n style={mergedStyles.passwordToggle}\n disabled={loading}\n aria-label={showPassword ? 'Hide password' : 'Show password'}\n >\n {showPassword ? mergedIcons.hidePassword : mergedIcons.showPassword}\n </button>\n </div>\n </div>\n\n <button type=\"submit\" disabled={!username || !password || loading} style={getButtonStyle()}>\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n </form>\n\n {(showForgotPassword || showSignupLink || showMagicLinkOption) && (\n <div style={mergedStyles.linkContainer}>\n {showMagicLinkOption && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.magicLinkText} </span>\n <a onClick={onMagicLinkClick} style={mergedStyles.link}>\n {mergedCopy.magicLinkLink}\n </a>\n </div>\n )}\n\n {showMagicLinkOption && (showForgotPassword || showSignupLink) && (\n <div style={mergedStyles.divider}>•</div>\n )}\n\n {showForgotPassword && (\n <a onClick={onForgotPassword} style={mergedStyles.link}>\n {mergedCopy.forgotPasswordLink}\n </a>\n )}\n\n {showForgotPassword && showSignupLink && <div style={mergedStyles.divider}>•</div>}\n\n {showSignupLink && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.signupText} </span>\n <a onClick={onSignupClick} style={mergedStyles.link}>\n {mergedCopy.signupLink}\n </a>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\nimport { useApp } from '../providers/AppProvider';\n\nexport interface SignupFormCopy {\n title?: string;\n nameLabel?: string;\n namePlaceholder?: string;\n lastNameLabel?: string;\n lastNamePlaceholder?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n phoneNumberLabel?: string;\n phoneNumberPlaceholder?: string;\n passwordLabel?: string;\n passwordPlaceholder?: string;\n confirmPasswordLabel?: string;\n confirmPasswordPlaceholder?: string;\n tenantNameLabel?: string;\n tenantNamePlaceholder?: string;\n submitButton?: string;\n loginLink?: string;\n loginText?: string;\n magicLinkText?: string;\n magicLinkLink?: string;\n errorMessage?: string;\n loadingText?: string;\n passwordMismatchError?: string;\n isAdminLabel?: string;\n isAdminDescription?: string;\n}\n\nexport interface SignupFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n checkbox?: React.CSSProperties;\n checkboxContainer?: React.CSSProperties;\n checkboxLabel?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n divider?: React.CSSProperties;\n}\n\nexport type SignupType = 'user' | 'tenant';\n\nexport interface SignupFormProps {\n copy?: SignupFormCopy;\n styles?: SignupFormStyles;\n signupType?: SignupType;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onLoginClick?: () => void;\n onMagicLinkClick?: () => void;\n showLoginLink?: boolean;\n showMagicLinkOption?: boolean;\n className?: string;\n}\n\nconst defaultCopy: Required<SignupFormCopy> = {\n title: 'Create Account',\n nameLabel: 'First Name',\n namePlaceholder: 'Enter your first name',\n lastNameLabel: 'Last Name',\n lastNamePlaceholder: 'Enter your last name',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n phoneNumberLabel: 'Phone Number',\n phoneNumberPlaceholder: 'Enter your phone number',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Enter your password',\n confirmPasswordLabel: 'Confirm Password',\n confirmPasswordPlaceholder: 'Confirm your password',\n tenantNameLabel: 'Organization Name',\n tenantNamePlaceholder: 'Enter your organization name',\n submitButton: 'Create Account',\n loginLink: 'Sign in here',\n loginText: 'Already have an account?',\n magicLinkText: 'Prefer passwordless?',\n magicLinkLink: 'Use Magic Link',\n errorMessage: 'Failed to create account',\n loadingText: 'Creating account...',\n passwordMismatchError: 'Passwords do not match',\n isAdminLabel: 'Create new organization',\n isAdminDescription: 'Check this if you want to create a new organization',\n};\n\nconst defaultStyles: Required<SignupFormStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#333333',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n checkbox: {\n marginRight: '0.5rem',\n },\n checkboxContainer: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: '0.5rem',\n padding: '0.5rem 0',\n },\n checkboxLabel: {\n fontSize: '0.875rem',\n color: '#374151',\n lineHeight: '1.4',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#10b981',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n divider: {\n margin: '0.5rem 0',\n color: '#6b7280',\n fontSize: '0.875rem',\n },\n};\n\nexport function SignupForm({\n copy = {},\n styles = {},\n signupType = 'user',\n onSuccess,\n onError,\n onLoginClick,\n onMagicLinkClick,\n showLoginLink = true,\n showMagicLinkOption = true,\n className,\n}: SignupFormProps) {\n const [name, setName] = useState('');\n const [lastName, setLastName] = useState('');\n const [email, setEmail] = useState('');\n const [phoneNumber, setPhoneNumber] = useState('');\n const [password, setPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [tenantName, setTenantName] = useState('');\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{\n name?: boolean;\n email?: boolean;\n phoneNumber?: boolean;\n password?: boolean;\n confirmPassword?: boolean;\n tenantName?: boolean;\n }>({});\n\n const { signup, signupTenantAdmin } = useAuth();\n const { tenant } = useTenantInfo();\n const { appId } = useApp();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n\n const validateForm = () => {\n const errors: {\n name?: boolean;\n email?: boolean;\n phoneNumber?: boolean;\n password?: boolean;\n confirmPassword?: boolean;\n tenantName?: boolean;\n } = {};\n\n if (!name.trim()) errors.name = true;\n if (!email.trim() && !phoneNumber.trim()) {\n errors.email = true;\n errors.phoneNumber = true;\n }\n if (!password.trim()) errors.password = true;\n if (!confirmPassword.trim()) errors.confirmPassword = true;\n if (signupType === 'tenant' && !tenantName.trim()) errors.tenantName = true;\n\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) return;\n\n if (password !== confirmPassword) {\n setError(mergedCopy.passwordMismatchError);\n setFieldErrors({ confirmPassword: true });\n return;\n }\n\n if (signupType === 'user' && !tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n\n try {\n let result;\n if (signupType === 'tenant') {\n result = await signupTenantAdmin(\n email || undefined,\n phoneNumber || undefined,\n name,\n password,\n tenantName,\n lastName || undefined,\n appId\n );\n } else {\n result = await signup(\n email || undefined,\n phoneNumber || undefined,\n name,\n password,\n tenant!.id,\n lastName || undefined,\n appId\n );\n }\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: keyof typeof fieldErrors) => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading ? mergedStyles.buttonLoading : {}),\n ...(!name ||\n (!email && !phoneNumber) ||\n !password ||\n !confirmPassword ||\n loading ||\n (signupType === 'tenant' && !tenantName)\n ? mergedStyles.buttonDisabled\n : {}),\n });\n\n const isFormValid =\n name &&\n (email || phoneNumber) &&\n password &&\n confirmPassword &&\n (signupType === 'user' || tenantName);\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n\n <form onSubmit={handleSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.nameLabel}</label>\n <input\n id=\"name\"\n name=\"name\"\n type=\"text\"\n value={name}\n onChange={e => {\n setName(e.target.value);\n if (fieldErrors.name) {\n setFieldErrors(prev => ({ ...prev, name: false }));\n }\n }}\n placeholder={mergedCopy.namePlaceholder}\n style={getInputStyle('name')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.lastNameLabel}</label>\n <input\n id=\"lastName\"\n name=\"lastName\"\n type=\"text\"\n value={lastName}\n onChange={e => setLastName(e.target.value)}\n placeholder={mergedCopy.lastNamePlaceholder}\n style={mergedStyles.input}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.emailLabel}</label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={e => {\n setEmail(e.target.value);\n if (fieldErrors.email) {\n setFieldErrors(prev => ({ ...prev, email: false, phoneNumber: false }));\n }\n }}\n placeholder={mergedCopy.emailPlaceholder}\n style={getInputStyle('email')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.phoneNumberLabel}</label>\n <input\n id=\"phoneNumber\"\n name=\"phoneNumber\"\n type=\"tel\"\n value={phoneNumber}\n onChange={e => {\n setPhoneNumber(e.target.value);\n if (fieldErrors.phoneNumber) {\n setFieldErrors(prev => ({ ...prev, email: false, phoneNumber: false }));\n }\n }}\n placeholder={mergedCopy.phoneNumberPlaceholder}\n style={getInputStyle('phoneNumber')}\n disabled={loading}\n />\n </div>\n\n <div\n style={{\n fontSize: '0.875rem',\n color: '#6b7280',\n textAlign: 'center',\n margin: '0.5rem 0',\n }}\n >\n At least one contact method (email or phone) is required\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.passwordLabel}</label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n value={password}\n onChange={e => {\n setPassword(e.target.value);\n if (fieldErrors.password) {\n setFieldErrors(prev => ({ ...prev, password: false }));\n }\n }}\n placeholder={mergedCopy.passwordPlaceholder}\n style={getInputStyle('password')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.confirmPasswordLabel}</label>\n <input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n value={confirmPassword}\n onChange={e => {\n setConfirmPassword(e.target.value);\n if (fieldErrors.confirmPassword) {\n setFieldErrors(prev => ({ ...prev, confirmPassword: false }));\n }\n if (error === mergedCopy.passwordMismatchError) {\n setError('');\n }\n }}\n placeholder={mergedCopy.confirmPasswordPlaceholder}\n style={getInputStyle('confirmPassword')}\n disabled={loading}\n />\n </div>\n\n {signupType === 'tenant' && (\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.tenantNameLabel}</label>\n <input\n id=\"tenantName\"\n name=\"tenantName\"\n type=\"text\"\n value={tenantName}\n onChange={e => {\n setTenantName(e.target.value);\n if (fieldErrors.tenantName) {\n setFieldErrors(prev => ({ ...prev, tenantName: false }));\n }\n }}\n placeholder={mergedCopy.tenantNamePlaceholder}\n style={getInputStyle('tenantName')}\n disabled={loading}\n />\n </div>\n )}\n\n <button type=\"submit\" disabled={!isFormValid || loading} style={getButtonStyle()}>\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n </form>\n\n {(showLoginLink || showMagicLinkOption) && (\n <div style={mergedStyles.linkContainer}>\n {showMagicLinkOption && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.magicLinkText} </span>\n <a onClick={onMagicLinkClick} style={mergedStyles.link}>\n {mergedCopy.magicLinkLink}\n </a>\n </div>\n )}\n\n {showMagicLinkOption && showLoginLink && <div style={mergedStyles.divider}>•</div>}\n\n {showLoginLink && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.loginText} </span>\n <a onClick={onLoginClick} style={mergedStyles.link}>\n {mergedCopy.loginLink}\n </a>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\nimport { useApp } from '../providers/AppProvider';\n\nexport interface MagicLinkFormCopy {\n title?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n nameLabel?: string;\n namePlaceholder?: string;\n lastNameLabel?: string;\n lastNamePlaceholder?: string;\n submitButton?: string;\n loginLink?: string;\n signupLink?: string;\n loginText?: string;\n signupText?: string;\n successMessage?: string;\n errorMessage?: string;\n loadingText?: string;\n verifyingText?: string;\n description?: string;\n}\n\nexport interface MagicLinkFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n description?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n successText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n divider?: React.CSSProperties;\n}\n\nexport interface MagicLinkFormProps {\n copy?: MagicLinkFormCopy;\n styles?: MagicLinkFormStyles;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onLoginClick?: () => void;\n onSignupClick?: () => void;\n showTraditionalLinks?: boolean;\n className?: string;\n // Auto-verify magic link if token is provided (e.g., from URL params)\n verifyToken?: string;\n // Frontend URL for magic link callback (if not provided, will use window.location.origin)\n frontendUrl?: string;\n}\n\nconst defaultCopy: Required<MagicLinkFormCopy> = {\n title: 'Sign In with Magic Link',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n nameLabel: 'Name',\n namePlaceholder: 'Enter your name',\n lastNameLabel: 'Last Name',\n lastNamePlaceholder: 'Enter your last name',\n submitButton: 'Send Magic Link',\n loginLink: 'Sign in with password',\n signupLink: 'Sign up with password',\n loginText: 'Already have an account?',\n signupText: 'Prefer traditional signup?',\n successMessage: 'Magic link sent! Check your email and click the link to sign in.',\n errorMessage: 'Failed to send magic link. Please try again.',\n loadingText: 'Sending magic link...',\n verifyingText: 'Verifying magic link...',\n description:\n \"Enter your email to receive a magic link. If you don't have an account, we'll create one for you.\",\n};\n\nconst defaultStyles: Required<MagicLinkFormStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1rem',\n color: '#333333',\n },\n description: {\n fontSize: '0.875rem',\n color: '#6b7280',\n textAlign: 'center',\n marginBottom: '1.5rem',\n lineHeight: '1.5',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n width: '100%',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n successText: {\n color: '#10b981',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n padding: '0.75rem',\n backgroundColor: '#f0fdf4',\n borderRadius: '6px',\n border: '1px solid #bbf7d0',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n divider: {\n margin: '0.5rem 0',\n color: '#6b7280',\n fontSize: '0.875rem',\n },\n};\n\nexport function MagicLinkForm({\n copy = {},\n styles = {},\n onSuccess,\n onError,\n onLoginClick,\n onSignupClick,\n showTraditionalLinks = true,\n className,\n verifyToken,\n frontendUrl,\n}: MagicLinkFormProps) {\n const [email, setEmail] = useState('');\n const [name, setName] = useState('');\n const [lastName, setLastName] = useState('');\n const [loading, setLoading] = useState(false);\n const [verifying, setVerifying] = useState(false);\n const [error, setError] = useState('');\n const [success, setSuccess] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{ email?: boolean; name?: boolean }>({});\n const [showNameFields, setShowNameFields] = useState(false);\n\n const { sendMagicLink, verifyMagicLink } = useAuth();\n const { tenant } = useTenantInfo();\n const { appId } = useApp();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n\n // Auto-verify magic link if token is provided\n useEffect(() => {\n if (verifyToken) {\n handleVerifyMagicLink(verifyToken);\n }\n }, [verifyToken]);\n\n const handleVerifyMagicLink = async (token: string) => {\n setVerifying(true);\n setError('');\n\n try {\n // For verification, we need email and appId - these should be provided via props or URL params\n // For now, we'll require them to be passed somehow. This is a limitation that needs to be addressed.\n if (!email || !appId) {\n throw new Error('Email and App ID are required for magic link verification');\n }\n const result = await verifyMagicLink(token, email, appId, tenant?.id);\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || 'Failed to verify magic link';\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setVerifying(false);\n }\n };\n\n const validateForm = () => {\n const errors: { email?: boolean; name?: boolean } = {};\n\n if (!email.trim()) errors.email = true;\n if (showNameFields && !name.trim()) errors.name = true;\n\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) return;\n if (!tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n setSuccess('');\n\n try {\n const finalFrontendUrl =\n frontendUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n const result = await sendMagicLink(\n email,\n tenant.id,\n finalFrontendUrl,\n showNameFields ? name : undefined,\n showNameFields ? lastName : undefined,\n appId\n );\n setSuccess(mergedCopy.successMessage);\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: 'email' | 'name') => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading || verifying ? mergedStyles.buttonLoading : {}),\n ...(!email || loading || verifying ? mergedStyles.buttonDisabled : {}),\n });\n\n if (verifying) {\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.verifyingText}</h2>\n <div style={{ textAlign: 'center', padding: '2rem' }}>\n <div style={{ fontSize: '1rem', color: '#6b7280' }}>\n Please wait while we verify your magic link...\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n <p style={mergedStyles.description}>{mergedCopy.description}</p>\n\n <form onSubmit={handleSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.emailLabel}</label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={e => {\n setEmail(e.target.value);\n if (fieldErrors.email) {\n setFieldErrors(prev => ({ ...prev, email: false }));\n }\n }}\n placeholder={mergedCopy.emailPlaceholder}\n style={getInputStyle('email')}\n disabled={loading || verifying}\n />\n </div>\n\n {/* Toggle to show name fields for new users */}\n {!showNameFields && (\n <div style={{ textAlign: 'center', marginTop: '0.5rem' }}>\n <button\n type=\"button\"\n onClick={() => setShowNameFields(true)}\n style={{\n background: 'none',\n border: 'none',\n color: '#3b82f6',\n fontSize: '0.875rem',\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n New user? Add your name\n </button>\n </div>\n )}\n\n {showNameFields && (\n <>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.nameLabel}</label>\n <input\n id=\"name\"\n name=\"name\"\n type=\"text\"\n value={name}\n onChange={e => {\n setName(e.target.value);\n if (fieldErrors.name) {\n setFieldErrors(prev => ({ ...prev, name: false }));\n }\n }}\n placeholder={mergedCopy.namePlaceholder}\n style={getInputStyle('name')}\n disabled={loading || verifying}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.lastNameLabel}</label>\n <input\n id=\"lastName\"\n name=\"lastName\"\n type=\"text\"\n value={lastName}\n onChange={e => setLastName(e.target.value)}\n placeholder={mergedCopy.lastNamePlaceholder}\n style={mergedStyles.input}\n disabled={loading || verifying}\n />\n </div>\n\n <div style={{ textAlign: 'center', marginTop: '0.5rem' }}>\n <button\n type=\"button\"\n onClick={() => {\n setShowNameFields(false);\n setName('');\n setLastName('');\n }}\n style={{\n background: 'none',\n border: 'none',\n color: '#6b7280',\n fontSize: '0.875rem',\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n Existing user? Hide name fields\n </button>\n </div>\n </>\n )}\n\n <button type=\"submit\" disabled={!email || loading || verifying} style={getButtonStyle()}>\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n {success && <div style={mergedStyles.successText}>{success}</div>}\n </form>\n\n {showTraditionalLinks && (\n <div style={mergedStyles.linkContainer}>\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.loginText} </span>\n <a onClick={onLoginClick} style={mergedStyles.link}>\n {mergedCopy.loginLink}\n </a>\n </div>\n\n <div style={mergedStyles.divider}>•</div>\n\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.signupText} </span>\n <a onClick={onSignupClick} style={mergedStyles.link}>\n {mergedCopy.signupLink}\n </a>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\n\nexport interface MagicLinkVerifyCopy {\n title?: string;\n verifyingMessage?: string;\n successMessage?: string;\n errorMessage?: string;\n redirectingMessage?: string;\n retryButton?: string;\n backToLoginButton?: string;\n}\n\nexport interface MagicLinkVerifyStyles {\n container?: React.CSSProperties;\n card?: React.CSSProperties;\n title?: React.CSSProperties;\n message?: React.CSSProperties;\n successMessage?: React.CSSProperties;\n errorMessage?: React.CSSProperties;\n spinner?: React.CSSProperties;\n buttonContainer?: React.CSSProperties;\n retryButton?: React.CSSProperties;\n backButton?: React.CSSProperties;\n}\n\nexport interface MagicLinkVerifyIcons {\n loading?: React.ReactNode;\n success?: React.ReactNode;\n error?: React.ReactNode;\n}\n\nexport interface MagicLinkVerifyProps {\n copy?: MagicLinkVerifyCopy;\n styles?: MagicLinkVerifyStyles;\n icons?: MagicLinkVerifyIcons;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onRetry?: () => void;\n onBackToLogin?: () => void;\n className?: string;\n // Auto-extract from URL params if not provided\n token?: string;\n email?: string;\n appId?: string;\n tenantId?: string;\n // Auto-redirect after success (in milliseconds)\n autoRedirectDelay?: number;\n}\n\nconst defaultCopy: Required<MagicLinkVerifyCopy> = {\n title: 'Verifying Magic Link',\n verifyingMessage: 'Please wait while we verify your magic link...',\n successMessage: 'Magic link verified successfully! You are now logged in.',\n errorMessage: 'Failed to verify magic link. The link may be expired or invalid.',\n redirectingMessage: 'Redirecting you to the dashboard...',\n retryButton: 'Try Again',\n backToLoginButton: 'Back to Login',\n};\n\nconst defaultStyles: Required<MagicLinkVerifyStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n card: {\n // Not used in new design, keeping for compatibility\n backgroundColor: 'transparent',\n padding: '0',\n borderRadius: '0',\n boxShadow: 'none',\n maxWidth: '100%',\n width: '100%',\n textAlign: 'center',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#333333',\n },\n message: {\n fontSize: '1rem',\n color: '#6b7280',\n marginBottom: '1.5rem',\n lineHeight: '1.5',\n textAlign: 'center',\n },\n successMessage: {\n fontSize: '1rem',\n color: '#059669',\n marginBottom: '1.5rem',\n lineHeight: '1.5',\n textAlign: 'center',\n },\n errorMessage: {\n fontSize: '0.875rem',\n color: '#ef4444',\n textAlign: 'center',\n marginBottom: '1rem',\n lineHeight: '1.5',\n },\n spinner: {\n display: 'inline-block',\n width: '20px',\n height: '20px',\n border: '2px solid #e5e7eb',\n borderTop: '2px solid #3b82f6',\n borderRadius: '50%',\n animation: 'spin 1s linear infinite',\n marginRight: '0.5rem',\n },\n buttonContainer: {\n display: 'flex',\n gap: '0.75rem',\n justifyContent: 'center',\n flexWrap: 'wrap',\n marginTop: '1rem',\n },\n retryButton: {\n padding: '0.75rem 1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n },\n backButton: {\n padding: '0.75rem 1rem',\n backgroundColor: '#f3f4f6',\n color: '#374151',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'all 0.15s ease-in-out',\n },\n};\n\n// Loading spinner icon\nconst LoadingIcon = () => <div style={defaultStyles.spinner} />;\n\n// Success icon\nconst SuccessIcon = () => (\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"#059669\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ margin: '0 auto 1rem auto', display: 'block' }}\n >\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\" />\n <polyline points=\"22,4 12,14.01 9,11.01\" />\n </svg>\n);\n\n// Error icon\nconst ErrorIcon = () => (\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"#ef4444\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ margin: '0 auto 1rem auto', display: 'block' }}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n);\n\nconst defaultIcons: Required<MagicLinkVerifyIcons> = {\n loading: <LoadingIcon />,\n success: <SuccessIcon />,\n error: <ErrorIcon />,\n};\n\ntype VerificationState = 'verifying' | 'success' | 'error' | 'redirecting';\n\nexport function MagicLinkVerify({\n copy = {},\n styles = {},\n icons = {},\n onSuccess,\n onError,\n onRetry,\n onBackToLogin,\n className,\n token: propToken,\n email: propEmail,\n appId: propAppId,\n tenantId: propTenantId,\n autoRedirectDelay = 3000,\n}: MagicLinkVerifyProps) {\n const [state, setState] = useState<VerificationState>('verifying');\n const [error, setError] = useState('');\n\n const { verifyMagicLink } = useAuth();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n const mergedIcons = { ...defaultIcons, ...icons };\n\n // Extract parameters from URL or use props\n const getUrlParams = () => {\n if (typeof window === 'undefined') return {};\n\n const urlParams = new URLSearchParams(window.location.search);\n return {\n token: propToken || urlParams.get('token') || '',\n email: propEmail || urlParams.get('email') || '',\n appId: propAppId || urlParams.get('appId') || '',\n tenantId: propTenantId || urlParams.get('tenantId') || undefined,\n };\n };\n\n const handleVerification = async () => {\n setState('verifying');\n setError('');\n\n try {\n const params = getUrlParams();\n\n if (!params.token || !params.email || !params.appId) {\n throw new Error('Missing required parameters: token, email, or appId');\n }\n\n const result = await verifyMagicLink(\n params.token,\n params.email,\n params.appId,\n params.tenantId\n );\n\n setState('success');\n onSuccess?.(result);\n\n // Auto-redirect after success\n if (autoRedirectDelay > 0) {\n setTimeout(() => {\n setState('redirecting');\n }, autoRedirectDelay);\n }\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n setState('error');\n onError?.(errorMessage);\n }\n };\n\n const handleRetry = () => {\n onRetry?.();\n handleVerification();\n };\n\n const handleBackToLogin = () => {\n onBackToLogin?.();\n };\n\n // Auto-verify on mount\n useEffect(() => {\n handleVerification();\n }, []);\n\n const renderContent = () => {\n switch (state) {\n case 'verifying':\n return (\n <div style={mergedStyles.message}>\n {mergedIcons.loading}\n {mergedCopy.verifyingMessage}\n </div>\n );\n\n case 'success':\n return (\n <>\n {mergedIcons.success}\n <div style={mergedStyles.successMessage}>{mergedCopy.successMessage}</div>\n </>\n );\n\n case 'redirecting':\n return (\n <>\n {mergedIcons.loading}\n <div style={mergedStyles.message}>{mergedCopy.redirectingMessage}</div>\n </>\n );\n\n case 'error':\n return (\n <>\n {mergedIcons.error}\n <div style={mergedStyles.errorMessage}>{error || mergedCopy.errorMessage}</div>\n <div style={mergedStyles.buttonContainer}>\n <button\n onClick={handleRetry}\n style={mergedStyles.retryButton}\n onMouseOver={e => {\n e.currentTarget.style.backgroundColor = '#2563eb';\n }}\n onMouseOut={e => {\n e.currentTarget.style.backgroundColor = '#3b82f6';\n }}\n >\n {mergedCopy.retryButton}\n </button>\n <button\n onClick={handleBackToLogin}\n style={mergedStyles.backButton}\n onMouseOver={e => {\n e.currentTarget.style.backgroundColor = '#e5e7eb';\n }}\n onMouseOut={e => {\n e.currentTarget.style.backgroundColor = '#f3f4f6';\n }}\n >\n {mergedCopy.backToLoginButton}\n </button>\n </div>\n </>\n );\n\n default:\n return null;\n }\n };\n\n return (\n <div style={mergedStyles.container} className={className}>\n <style>\n {`\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `}\n </style>\n <h1 style={mergedStyles.title}>{mergedCopy.title}</h1>\n {renderContent()}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface PasswordRecoveryFormCopy {\n title?: string;\n subtitle?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n submitButton?: string;\n backToLoginLink?: string;\n successMessage?: string;\n errorMessage?: string;\n loadingText?: string;\n // Reset form copy\n resetTitle?: string;\n resetSubtitle?: string;\n tokenLabel?: string;\n tokenPlaceholder?: string;\n newPasswordLabel?: string;\n newPasswordPlaceholder?: string;\n confirmPasswordLabel?: string;\n confirmPasswordPlaceholder?: string;\n resetSubmitButton?: string;\n resetLoadingText?: string;\n resetSuccessMessage?: string;\n passwordMismatchError?: string;\n}\n\nexport interface PasswordRecoveryFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n subtitle?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n successText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n}\n\nexport interface PasswordRecoveryFormProps {\n copy?: PasswordRecoveryFormCopy;\n styles?: PasswordRecoveryFormStyles;\n mode?: 'request' | 'reset';\n token?: string;\n onSuccess?: (data?: any) => void;\n onError?: (error: string) => void;\n onBackToLogin?: () => void;\n onModeChange?: (mode: 'request' | 'reset') => void;\n className?: string;\n}\n\nconst defaultCopy: Required<PasswordRecoveryFormCopy> = {\n title: 'Reset Password',\n subtitle: \"Enter your email address and we'll send you a link to reset your password.\",\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n submitButton: 'Send Reset Link',\n backToLoginLink: 'Back to Sign In',\n successMessage: 'Password reset link sent! Check your email.',\n errorMessage: 'Failed to send reset link',\n loadingText: 'Sending...',\n resetTitle: 'Set New Password',\n resetSubtitle: 'Enter your reset token and new password.',\n tokenLabel: 'Reset Token',\n tokenPlaceholder: 'Enter reset token from email',\n newPasswordLabel: 'New Password',\n newPasswordPlaceholder: 'Enter new password',\n confirmPasswordLabel: 'Confirm Password',\n confirmPasswordPlaceholder: 'Confirm new password',\n resetSubmitButton: 'Reset Password',\n resetLoadingText: 'Resetting...',\n resetSuccessMessage: 'Password reset successfully!',\n passwordMismatchError: 'Passwords do not match',\n};\n\nconst defaultStyles: Required<PasswordRecoveryFormStyles> = {\n container: {\n maxWidth: '400px',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '0.5rem',\n color: '#333333',\n },\n subtitle: {\n fontSize: '0.875rem',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#6b7280',\n lineHeight: '1.4',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#f59e0b',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n successText: {\n color: '#10b981',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n};\n\nexport function PasswordRecoveryForm({\n copy = {},\n styles = {},\n mode = 'request',\n token: initialToken = '',\n onSuccess,\n onError,\n onBackToLogin,\n onModeChange,\n className,\n}: PasswordRecoveryFormProps) {\n const [email, setEmail] = useState('');\n const [token, setToken] = useState(initialToken);\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [success, setSuccess] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{\n email?: boolean;\n token?: boolean;\n newPassword?: boolean;\n confirmPassword?: boolean;\n }>({});\n\n const { requestPasswordReset, confirmPasswordReset } = useAuth();\n const { tenant } = useTenantInfo();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n\n const validateRequestForm = () => {\n const errors: { email?: boolean } = {};\n if (!email.trim()) errors.email = true;\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const validateResetForm = () => {\n const errors: { token?: boolean; newPassword?: boolean; confirmPassword?: boolean } = {};\n if (!token.trim()) errors.token = true;\n if (!newPassword.trim()) errors.newPassword = true;\n if (!confirmPassword.trim()) errors.confirmPassword = true;\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleRequestSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateRequestForm()) return;\n if (!tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n setSuccess('');\n\n try {\n await requestPasswordReset(email, tenant.id);\n setSuccess(mergedCopy.successMessage);\n onSuccess?.();\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const handleResetSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateResetForm()) return;\n\n if (newPassword !== confirmPassword) {\n setError(mergedCopy.passwordMismatchError);\n setFieldErrors({ confirmPassword: true });\n return;\n }\n\n setLoading(true);\n setError('');\n setSuccess('');\n\n try {\n await confirmPasswordReset(token, newPassword);\n setSuccess(mergedCopy.resetSuccessMessage);\n onSuccess?.();\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: keyof typeof fieldErrors) => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading ? mergedStyles.buttonLoading : {}),\n });\n\n if (mode === 'reset') {\n const isFormValid = token && newPassword && confirmPassword;\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.resetTitle}</h2>\n <p style={mergedStyles.subtitle}>{mergedCopy.resetSubtitle}</p>\n\n <form onSubmit={handleResetSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.tokenLabel}</label>\n <input\n type=\"text\"\n value={token}\n onChange={e => {\n setToken(e.target.value);\n if (fieldErrors.token) {\n setFieldErrors(prev => ({ ...prev, token: false }));\n }\n }}\n placeholder={mergedCopy.tokenPlaceholder}\n style={getInputStyle('token')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.newPasswordLabel}</label>\n <input\n type=\"password\"\n value={newPassword}\n onChange={e => {\n setNewPassword(e.target.value);\n if (fieldErrors.newPassword) {\n setFieldErrors(prev => ({ ...prev, newPassword: false }));\n }\n }}\n placeholder={mergedCopy.newPasswordPlaceholder}\n style={getInputStyle('newPassword')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.confirmPasswordLabel}</label>\n <input\n type=\"password\"\n value={confirmPassword}\n onChange={e => {\n setConfirmPassword(e.target.value);\n if (fieldErrors.confirmPassword) {\n setFieldErrors(prev => ({ ...prev, confirmPassword: false }));\n }\n if (error === mergedCopy.passwordMismatchError) {\n setError('');\n }\n }}\n placeholder={mergedCopy.confirmPasswordPlaceholder}\n style={getInputStyle('confirmPassword')}\n disabled={loading}\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={!isFormValid || loading}\n style={{\n ...getButtonStyle(),\n ...(!isFormValid || loading ? mergedStyles.buttonDisabled : {}),\n }}\n >\n {loading ? mergedCopy.resetLoadingText : mergedCopy.resetSubmitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n {success && <div style={mergedStyles.successText}>{success}</div>}\n </form>\n\n <div style={mergedStyles.linkContainer}>\n <a onClick={onBackToLogin} style={mergedStyles.link}>\n {mergedCopy.backToLoginLink}\n </a>\n {onModeChange && (\n <>\n <span style={{ margin: '0 0.5rem', color: '#6b7280' }}>•</span>\n <a onClick={() => onModeChange('request')} style={mergedStyles.link}>\n Request New Link\n </a>\n </>\n )}\n </div>\n </div>\n );\n }\n\n // Request mode\n const isFormValid = email;\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n <p style={mergedStyles.subtitle}>{mergedCopy.subtitle}</p>\n\n <form onSubmit={handleRequestSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.emailLabel}</label>\n <input\n type=\"email\"\n value={email}\n onChange={e => {\n setEmail(e.target.value);\n if (fieldErrors.email) {\n setFieldErrors(prev => ({ ...prev, email: false }));\n }\n }}\n placeholder={mergedCopy.emailPlaceholder}\n style={getInputStyle('email')}\n disabled={loading}\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={!isFormValid || loading}\n style={{\n ...getButtonStyle(),\n ...(!isFormValid || loading ? mergedStyles.buttonDisabled : {}),\n }}\n >\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n {success && <div style={mergedStyles.successText}>{success}</div>}\n </form>\n\n <div style={mergedStyles.linkContainer}>\n <a onClick={onBackToLogin} style={mergedStyles.link}>\n {mergedCopy.backToLoginLink}\n </a>\n {onModeChange && (\n <>\n <span style={{ margin: '0 0.5rem', color: '#6b7280' }}>•</span>\n <a onClick={() => onModeChange('reset')} style={mergedStyles.link}>\n I have a token\n </a>\n </>\n )}\n </div>\n </div>\n );\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Permission,\n CreatePermissionRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class PermissionApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createPermission(request: CreatePermissionRequest): Promise<Permission> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Permission>>(\n '/permissions/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getPermissions(\n params?: PaginationParams\n ): Promise<{ permissions: Permission[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/permissions/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Permission[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n permissions: response.data,\n meta: response.meta,\n };\n }\n\n async getPermissionById(id: string): Promise<Permission> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Permission>>(`/permissions/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updatePermission(\n id: string,\n request: Partial<CreatePermissionRequest>\n ): Promise<Permission> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Permission>>(\n `/permissions/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async deletePermission(id: string): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/permissions/${id}`, {\n headers: authHeaders,\n });\n }\n\n // Public endpoint - no auth required\n async getAppPermissions(\n appId: string,\n params?: PaginationParams\n ): Promise<{ permissions: Permission[]; meta: any }> {\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/permissions/apps/${appId}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Permission[]>>(url);\n\n return {\n permissions: response.data,\n meta: response.meta,\n };\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n SubscriptionPlan,\n CreateSubscriptionPlanRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class SubscriptionPlanApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager: SessionManager\n ) {}\n\n async createSubscriptionPlan(request: CreateSubscriptionPlanRequest): Promise<SubscriptionPlan> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<SubscriptionPlan>>(\n '/subscription-plans/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getSubscriptionPlans(\n params?: PaginationParams & { appId?: string }\n ): Promise<{ plans: SubscriptionPlan[]; meta: any }> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n if (params?.appId) queryParams.append('appId', params.appId);\n\n const url = `/subscription-plans/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<SubscriptionPlan[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n plans: response.data,\n meta: response.meta,\n };\n }\n\n async getSubscriptionPlanById(id: string): Promise<SubscriptionPlan> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<SubscriptionPlan>>(\n `/subscription-plans/${id}`,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async updateSubscriptionPlan(\n id: string,\n request: Partial<CreateSubscriptionPlanRequest>\n ): Promise<SubscriptionPlan> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<SubscriptionPlan>>(\n `/subscription-plans/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async deleteSubscriptionPlan(id: string): Promise<void> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/subscription-plans/${id}`, {\n headers: authHeaders,\n });\n }\n}\n","import { HttpService } from './HttpService';\n\nexport class HealthApiService {\n constructor(private httpService: HttpService) {}\n\n // Public endpoint - no auth required\n async checkHealth(): Promise<{ status: string }> {\n return await this.httpService.get<{ status: string }>('/health');\n }\n}\n","// Data transformation utilities for API responses\n\nexport class ApiMappers {\n // Date string to Date object\n static toDate(dateString: string): Date {\n return new Date(dateString);\n }\n\n // Date object to ISO string\n static toISOString(date: Date): string {\n return date.toISOString();\n }\n\n // Transform API response pagination meta\n static transformPaginationMeta(meta: any) {\n return {\n total: meta.total || 0,\n page: meta.page || 1,\n limit: meta.limit || 100,\n totalPages: meta.totalPages || 1,\n hasNext: meta.hasNext || false,\n hasPrev: meta.hasPrev || false,\n };\n }\n\n // Transform user data for display\n static transformUser(user: any) {\n return {\n ...user,\n createdAt: this.toDate(user.createdAt),\n updatedAt: this.toDate(user.updatedAt),\n displayName: user.lastName ? `${user.name} ${user.lastName}` : user.name,\n isActiveUser: user.isActive,\n };\n }\n\n // Transform role data for display\n static transformRole(role: any) {\n return {\n ...role,\n createdAt: this.toDate(role.createdAt),\n updatedAt: this.toDate(role.updatedAt),\n permissionCount: role.permissions?.length || 0,\n };\n }\n\n // Transform tenant data for display\n static transformTenant(tenant: any) {\n return {\n ...tenant,\n createdAt: this.toDate(tenant.createdAt),\n updatedAt: this.toDate(tenant.updatedAt),\n displayName: tenant.name,\n hasCustomDomain: !!tenant.domain,\n };\n }\n\n // Transform subscription data for display\n static transformSubscription(subscription: any) {\n return {\n ...subscription,\n createdAt: this.toDate(subscription.createdAt),\n updatedAt: this.toDate(subscription.updatedAt),\n startDate: this.toDate(subscription.startDate),\n endDate: subscription.endDate ? this.toDate(subscription.endDate) : null,\n isActive: subscription.status === 'ACTIVE',\n isExpired: subscription.endDate ? new Date(subscription.endDate) < new Date() : false,\n };\n }\n\n // Transform app data for display\n static transformApp(app: any) {\n return {\n ...app,\n createdAt: this.toDate(app.createdAt),\n updatedAt: this.toDate(app.updatedAt),\n isAdminLevel: app.securityLevel === 'ADMIN',\n hasDefaultPlan: !!app.defaultSubscriptionPlanId,\n };\n }\n\n // Transform feature flag data for display\n static transformFeatureFlag(featureFlag: any) {\n return {\n ...featureFlag,\n createdAt: this.toDate(featureFlag.createdAt),\n updatedAt: this.toDate(featureFlag.updatedAt),\n isEnabled: featureFlag.isActive,\n };\n }\n\n // Transform permission data for display\n static transformPermission(permission: any) {\n return {\n ...permission,\n createdAt: this.toDate(permission.createdAt),\n updatedAt: this.toDate(permission.updatedAt),\n fullName: `${permission.resource}:${permission.action}`,\n isSystemLevel: !permission.appId,\n };\n }\n\n // Transform subscription plan data for display\n static transformSubscriptionPlan(plan: any) {\n return {\n ...plan,\n createdAt: this.toDate(plan.createdAt),\n updatedAt: this.toDate(plan.updatedAt),\n displayPrice: `${plan.currency} ${plan.price}`,\n isMonthly: plan.billingCycle === 'MONTHLY',\n featureCount: plan.features?.length || 0,\n };\n }\n\n // Transform error response\n static transformError(error: any) {\n return {\n code: error.error?.code || 'UNKNOWN_ERROR',\n message: error.message || 'An unexpected error occurred',\n type: error.type || 'SYSTEM',\n isAuthError: error.type === 'AUTH',\n isValidationError: error.type === 'VALIDATION',\n };\n }\n\n // Transform query parameters for API calls\n static transformQueryParams(params: any): URLSearchParams {\n const searchParams = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n searchParams.append(key, String(value));\n }\n });\n\n return searchParams;\n }\n}\n"],"names":["HttpService","baseUrl","timeout","sessionManager","method","endpoint","data","options","isRetry","url","requestTimeout","requestHeaders","authHeaders","error","controller","timeoutId","response","tokens","contentType","AppApiService","httpService","request","params","queryParams","id","appId","planId","schema","defaultSettings","AppContext","createContext","DefaultLoadingFallback","jsx","DefaultErrorFallback","retry","jsxs","AppProvider","config","children","appInfo","setAppInfo","useState","isAppLoading","setIsAppLoading","appError","setAppError","contextValue","useMemo","retryApp","loadApp","useCallback","appData","err","useEffect","Fragment","ErrorComponent","useApp","context","useContext","useApi","SessionManager","stored","tokenData","token","resolve","reject","newTokens","headers","refreshError","refreshToken","refreshResponse","user","currentData","AuthApiService","RoleApiService","roleId","userId","UserApiService","TenantApiService","slug","TenantContext","TenantProvider","tenant","setTenant","isTenantLoading","setIsTenantLoading","tenantError","setTenantError","settings","setSettings","isSettingsLoading","setIsSettingsLoading","settingsError","setSettingsError","detectTenantSlug","tenantMode","storageKey","parts","subdomain","urlTenant","tenantSlug","settingsSchema","loadTenant","tenantInfo","loadSettings","tenantSettings","refreshSettings","validateSettings","settingsToValidate","errors","key","fieldSchema","value","_a","expectedType","actualType","useTenant","useTenantSettings","useSettings","useTenantInfo","retryTenant","AuthContext","AuthProvider","availableRoles","setAvailableRoles","rolesLoading","setRolesLoading","currentUser","setCurrentUser","isUserLoading","setIsUserLoading","userError","setUserError","tokenStorage","authenticatedHttpService","service","authApiService","userApiService","roleApiService","userRole","role","userPermissions","loadUserData","userData","refreshUser","login","username","password","tenantId","loginResponse","signup","email","phoneNumber","name","lastName","signupTenantAdmin","tenantName","changePassword","currentPassword","newPassword","requestPasswordReset","confirmPasswordReset","sendMagicLink","frontendUrl","verifyMagicLink","verifyResponse","logout","setTokens","hasValidSession","clearSession","fetchRoles","roles","refreshRoles","hasPermission","permission","permissionString","permissions","internalHttpService","useAuth","FeatureFlagApiService","flagKey","FeatureFlagContext","FeatureFlagProvider","featureFlags","setFeatureFlags","loading","setLoading","setError","featureFlagService","fetchFeatureFlags","errorMessage","refreshInterval","interval","flag","f","useFeatureFlags","SubscriptionApiService","subscriptionId","paymentData","SubscriptionContext","SubscriptionProvider","subscription","setSubscription","subscriptionService","fetchSubscription","features","featureKey","feature","defaultValue","allowedPlans","useSubscription","UserType","DefaultFallback","InsufficientPermissionsFallback","userType","minUserType","missingPermissions","hasMinimumUserType","hierarchy","Protected","fallback","requiredPermissions","requireAllPermissions","hasAnyPermission","hasAllPermissions","redirectPath","ProtectedRoute","redirectTo","location","useLocation","Navigate","DefaultTenantRequiredFallback","TenantRoute","isLoading","DefaultTenantDetectedFallback","LandingRoute","SubscriptionGuard","requiredFeature","hasAllowedPlan","isFeatureEnabled","flagName","FeatureFlag","isEnabled","EyeIcon","EyeOffIcon","defaultIcons","defaultCopy","defaultStyles","LoginForm","copy","styles","icons","onSuccess","onError","onForgotPassword","onSignupClick","onMagicLinkClick","showForgotPassword","showSignupLink","showMagicLinkOption","className","setUsername","setPassword","showPassword","setShowPassword","fieldErrors","setFieldErrors","mergedCopy","mergedStyles","mergedIcons","validateForm","handleSubmit","e","result","getInputStyle","field","getButtonStyle","prev","SignupForm","signupType","onLoginClick","showLoginLink","setName","setLastName","setEmail","setPhoneNumber","confirmPassword","setConfirmPassword","setTenantName","isFormValid","MagicLinkForm","showTraditionalLinks","verifyToken","verifying","setVerifying","success","setSuccess","showNameFields","setShowNameFields","handleVerifyMagicLink","finalFrontendUrl","LoadingIcon","SuccessIcon","ErrorIcon","MagicLinkVerify","onRetry","onBackToLogin","propToken","propEmail","propAppId","propTenantId","autoRedirectDelay","state","setState","getUrlParams","urlParams","handleVerification","handleRetry","handleBackToLogin","renderContent","PasswordRecoveryForm","mode","initialToken","onModeChange","setToken","setNewPassword","validateRequestForm","validateResetForm","handleRequestSubmit","handleResetSubmit","PermissionApiService","SubscriptionPlanApiService","HealthApiService","ApiMappers","dateString","date","meta","app","featureFlag","plan","searchParams"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/services/HttpService.ts","../src/services/AppApiService.ts","../src/providers/AppProvider.tsx","../src/services/SessionManager.ts","../src/services/AuthApiService.ts","../src/services/RoleApiService.ts","../src/services/UserApiService.ts","../src/services/TenantApiService.ts","../src/providers/TenantProvider.tsx","../src/providers/AuthProvider.tsx","../src/services/FeatureFlagApiService.ts","../src/providers/FeatureFlagProvider.tsx","../src/services/SubscriptionApiService.ts","../src/providers/SubscriptionProvider.tsx","../src/types/api.ts","../src/components/Protected.tsx","../src/components/ProtectedRoute.tsx","../src/components/TenantRoute.tsx","../src/components/LandingRoute.tsx","../src/components/SubscriptionGuard.tsx","../src/components/FeatureFlag.tsx","../src/components/LoginForm.tsx","../src/components/SignupForm.tsx","../src/components/MagicLinkForm.tsx","../src/components/MagicLinkVerify.tsx","../src/components/PasswordRecoveryForm.tsx","../src/services/PermissionApiService.ts","../src/services/SubscriptionPlanApiService.ts","../src/services/HealthApiService.ts","../src/utils/mappers.ts"],"sourcesContent":["export interface RequestOptions {\n headers?: Record<string, string>;\n timeout?: number;\n skipAuth?: boolean; // Skip automatic auth header injection\n skipRetry?: boolean; // Skip automatic retry on 401\n}\n\nexport class HttpService {\n private baseUrl: string;\n private timeout: number;\n private sessionManager?: any; // SessionManager instance\n\n constructor(baseUrl: string, timeout = 10000) {\n this.baseUrl = baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n this.timeout = timeout;\n }\n\n setSessionManager(sessionManager: any): void {\n this.sessionManager = sessionManager;\n }\n\n getBaseUrl(): string {\n return this.baseUrl;\n }\n\n private async request<T>(\n method: string,\n endpoint: string,\n data?: any,\n options?: RequestOptions\n ): Promise<T> {\n return this.executeRequest<T>(method, endpoint, data, options, false);\n }\n\n private async executeRequest<T>(\n method: string,\n endpoint: string,\n data?: any,\n options?: RequestOptions,\n isRetry = false\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\n const requestTimeout = options?.timeout || this.timeout;\n\n // Inject auth headers automatically unless skipAuth is true\n let requestHeaders = {\n 'Content-Type': 'application/json',\n ...options?.headers,\n };\n\n if (!options?.skipAuth && this.sessionManager) {\n try {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n requestHeaders = { ...requestHeaders, ...authHeaders };\n } catch (error) {\n // If auth header injection fails, continue without auth\n console.warn('Failed to inject auth headers:', error);\n }\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: requestHeaders,\n body: data ? JSON.stringify(data) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle 401 Unauthorized with automatic retry\n if (response.status === 401 && !options?.skipRetry && !isRetry && this.sessionManager) {\n try {\n // Force token refresh by clearing current tokens and getting new auth headers\n const tokens = this.sessionManager.getTokens();\n if (tokens?.refreshToken) {\n // Trigger refresh through getAuthHeaders with expired token\n await this.sessionManager.getAuthHeaders();\n\n // Retry the original request\n return this.executeRequest<T>(method, endpoint, data, options, true);\n }\n } catch {\n // If refresh fails, throw the original 401 error\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n // Handle empty responses\n const contentType = response.headers.get('content-type');\n if (!contentType || !contentType.includes('application/json')) {\n return {} as T;\n }\n\n return await response.json();\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timeout after ${requestTimeout}ms`);\n }\n\n throw error;\n }\n }\n\n async get<T>(endpoint: string, options?: RequestOptions): Promise<T> {\n return this.request<T>('GET', endpoint, undefined, options);\n }\n\n async post<T>(endpoint: string, data: any, options?: RequestOptions): Promise<T> {\n return this.request<T>('POST', endpoint, data, options);\n }\n\n async put<T>(endpoint: string, data: any, options?: RequestOptions): Promise<T> {\n return this.request<T>('PUT', endpoint, data, options);\n }\n\n async delete<T>(endpoint: string, options?: RequestOptions): Promise<T> {\n return this.request<T>('DELETE', endpoint, undefined, options);\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n ApiResponse,\n App,\n CreateAppRequest,\n PublicAppInfo,\n PaginationParams,\n} from '../types/api';\n\nexport class AppApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager: SessionManager\n ) {}\n\n async createApp(request: CreateAppRequest): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<App>>('/apps/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getApps(params?: PaginationParams): Promise<{ apps: App[]; meta: any }> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/apps/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<App[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n apps: response.data,\n meta: response.meta,\n };\n }\n\n async getAppById(id: string): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<App>>(`/apps/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateApp(id: string, request: Partial<CreateAppRequest>): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<App>>(`/apps/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getPublicAppInfo(id: string): Promise<PublicAppInfo> {\n const response = await this.httpService.get<ApiResponse<PublicAppInfo>>(`/apps/${id}/public`);\n return response.data;\n }\n\n async setDefaultSubscriptionPlan(appId: string, planId: string): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<App>>(\n `/apps/${appId}/default-subscription-plan`,\n { planId },\n { headers: authHeaders }\n );\n return response.data;\n }\n\n async updateSettingsSchema(appId: string, schema: any, defaultSettings: any): Promise<App> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<App>>(\n `/apps/${appId}/settings-schema`,\n { schema, defaultSettings },\n { headers: authHeaders }\n );\n return response.data;\n }\n\n async exportConfig(appId: string): Promise<any> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<any>>(`/apps/${appId}/export-config`, {\n headers: authHeaders,\n });\n return response.data;\n }\n}\n","import {\n createContext,\n useContext,\n useMemo,\n ReactNode,\n useState,\n useEffect,\n useCallback,\n} from 'react';\nimport { HttpService } from '../services/HttpService';\nimport { AppApiService } from '../services/AppApiService';\nimport type { PublicAppInfo } from '../types/api';\n\n// RFC-003: Cache interface for app info\ninterface CachedAppInfo {\n data: PublicAppInfo;\n timestamp: number;\n appId: string;\n}\n\nexport interface AppConfig {\n baseUrl: string;\n appId: string;\n // RFC-003: Cache configuration\n cache?: {\n enabled?: boolean; // Default: true\n ttl?: number; // Time to live in milliseconds, default: 5 minutes\n storageKey?: string; // Default: 'app_cache_{appId}'\n };\n // Fallbacks\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode | ((error: Error, retry: () => void) => ReactNode);\n}\n\ninterface AppContextValue {\n appId: string;\n baseUrl: string;\n // App info with settings schema\n appInfo: PublicAppInfo | null;\n isAppLoading: boolean;\n appError: Error | null;\n retryApp: () => void;\n}\n\nconst AppContext = createContext<AppContextValue | null>(null);\n\ninterface AppProviderProps {\n config: AppConfig;\n children: ReactNode;\n}\n\n// Default loading component\nconst DefaultLoadingFallback = () => (\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div>Loading application...</div>\n </div>\n);\n\n// Default error component\nconst DefaultErrorFallback = ({ error, retry }: { error: Error; retry: () => void }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n textAlign: 'center',\n padding: '20px',\n }}\n >\n <h2 style={{ color: '#dc3545', marginBottom: '16px' }}>Application Error</h2>\n <p style={{ color: '#6c757d', marginBottom: '24px' }}>\n {error.message || 'Unable to load application'}\n </p>\n <button\n onClick={retry}\n style={{\n padding: '8px 16px',\n backgroundColor: '#007bff',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n </div>\n);\n\nexport function AppProvider({ config, children }: AppProviderProps) {\n // RFC-003: Cache configuration with defaults\n const cacheConfig = useMemo(\n () => ({\n enabled: config.cache?.enabled ?? true,\n ttl: config.cache?.ttl ?? 5 * 60 * 1000, // 5 minutes default\n storageKey: config.cache?.storageKey ?? `app_cache_${config.appId}`,\n }),\n [config.cache, config.appId]\n );\n\n // RFC-003: Try to load from cache on initialization\n const [appInfo, setAppInfo] = useState<PublicAppInfo | null>(() => {\n if (!cacheConfig.enabled) return null;\n\n try {\n const cached = localStorage.getItem(cacheConfig.storageKey);\n if (!cached) return null;\n\n const parsed: CachedAppInfo = JSON.parse(cached);\n const now = Date.now();\n const age = now - parsed.timestamp;\n\n // Check if cache is still valid\n if (age < cacheConfig.ttl && parsed.appId === config.appId) {\n return parsed.data;\n }\n\n // Cache expired\n localStorage.removeItem(cacheConfig.storageKey);\n return null;\n } catch {\n return null;\n }\n });\n\n const [isAppLoading, setIsAppLoading] = useState(!appInfo); // Don't load if we have cache\n const [appError, setAppError] = useState<Error | null>(null);\n\n const contextValue = useMemo(() => {\n // Retry function for app loading\n const retryApp = () => {\n loadApp();\n };\n\n return {\n appId: config.appId,\n baseUrl: config.baseUrl,\n // App info\n appInfo,\n isAppLoading,\n appError,\n retryApp,\n };\n }, [config, appInfo, isAppLoading, appError]);\n\n // RFC-003: Load app info with caching\n const loadApp = useCallback(\n async (bypassCache = false) => {\n // Check cache first (unless bypassing)\n if (!bypassCache && cacheConfig.enabled && appInfo) {\n return; // Already have valid cached data\n }\n\n try {\n setIsAppLoading(true);\n setAppError(null);\n\n const httpService = new HttpService(config.baseUrl);\n const appApi = new AppApiService(httpService, {} as any); // SessionManager not needed for public endpoint\n const appData = await appApi.getPublicAppInfo(config.appId);\n setAppInfo(appData);\n\n // RFC-003: Save to cache\n if (cacheConfig.enabled) {\n try {\n const cacheData: CachedAppInfo = {\n data: appData,\n timestamp: Date.now(),\n appId: config.appId,\n };\n localStorage.setItem(cacheConfig.storageKey, JSON.stringify(cacheData));\n } catch (error) {\n console.warn('Failed to cache app info:', error);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load app information');\n setAppError(error);\n setAppInfo(null);\n } finally {\n setIsAppLoading(false);\n }\n },\n [config.baseUrl, config.appId, cacheConfig, appInfo]\n );\n\n // RFC-003: Background refresh for stale-while-revalidate\n const backgroundRefresh = useCallback(async () => {\n if (!cacheConfig.enabled || !appInfo) return;\n\n try {\n const cached = localStorage.getItem(cacheConfig.storageKey);\n if (!cached) return;\n\n const parsed: CachedAppInfo = JSON.parse(cached);\n const age = Date.now() - parsed.timestamp;\n\n // If cache is more than 50% expired, refresh in background\n if (age > cacheConfig.ttl * 0.5) {\n const httpService = new HttpService(config.baseUrl);\n const appApi = new AppApiService(httpService, {} as any);\n const appData = await appApi.getPublicAppInfo(config.appId);\n\n setAppInfo(appData);\n\n const cacheData: CachedAppInfo = {\n data: appData,\n timestamp: Date.now(),\n appId: config.appId,\n };\n localStorage.setItem(cacheConfig.storageKey, JSON.stringify(cacheData));\n }\n } catch (error) {\n console.warn('Background app refresh failed:', error);\n // Don't update error state - keep showing cached data\n }\n }, [config, cacheConfig, appInfo]);\n\n // RFC-003: Load app info on mount or do background refresh\n useEffect(() => {\n if (!appInfo) {\n loadApp();\n } else {\n // We have cached data, do background refresh\n backgroundRefresh();\n }\n }, []); // Only run on mount\n\n // Show loading fallback for app info\n if (isAppLoading) {\n return <>{config.loadingFallback || <DefaultLoadingFallback />}</>;\n }\n\n // Show error fallback for app info\n if (appError) {\n const ErrorComponent =\n typeof config.errorFallback === 'function'\n ? config.errorFallback(appError, () => loadApp())\n : config.errorFallback || <DefaultErrorFallback error={appError} retry={() => loadApp()} />;\n\n return <>{ErrorComponent}</>;\n }\n\n return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>;\n}\n\nexport function useApp(): AppContextValue {\n const context = useContext(AppContext);\n if (!context) {\n throw new Error('useApp must be used within an AppProvider');\n }\n return context;\n}\n\n// Backward compatibility\nexport const useApi = useApp;\n","export interface TokenData {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n expiresIn?: number;\n tokenType?: string;\n}\n\nexport interface JwtPayload {\n userId: string;\n email: string | null;\n phoneNumber: string | null;\n userType: string;\n role: string | null;\n tenantId: string | null;\n appId: string | null;\n iat?: number;\n exp?: number;\n}\n\nexport interface TokenStorage {\n get(): any;\n set(data: any): void;\n clear(): void;\n}\n\nexport interface SessionConfig {\n storageKey?: string;\n tenantSlug?: string | null; // Tenant slug to generate storage key automatically\n autoRefresh?: boolean;\n refreshThreshold?: number;\n onRefreshFailed?: () => void;\n tokenStorage?: TokenStorage;\n baseUrl?: string; // Base URL for API calls\n}\n\nexport class SessionManager {\n private storageKey: string;\n private autoRefresh: boolean;\n private refreshThreshold: number;\n private baseUrl: string;\n private onRefreshFailed?: () => void;\n private tokenStorage: TokenStorage;\n\n // Refresh queue management\n private refreshPromise: Promise<void> | null = null;\n private refreshQueue: Array<{\n resolve: (headers: Record<string, string>) => void;\n reject: (error: Error) => void;\n }> = [];\n\n constructor(config: SessionConfig = {}) {\n // Generate storageKey based on tenantSlug if provided, otherwise use custom key or default\n if (config.tenantSlug !== undefined) {\n this.storageKey = config.tenantSlug ? `auth_tokens_${config.tenantSlug}` : 'auth_tokens';\n } else {\n this.storageKey = config.storageKey || 'auth_tokens';\n }\n\n this.autoRefresh = config.autoRefresh ?? true;\n this.refreshThreshold = config.refreshThreshold || 300000; // 5 minutes\n this.onRefreshFailed = config.onRefreshFailed;\n this.baseUrl = config.baseUrl || '';\n\n // Use provided tokenStorage or create default localStorage implementation\n this.tokenStorage = config.tokenStorage || this.createTokenStorage(this.storageKey);\n }\n\n // Helper to create a TokenStorage for a specific key\n private createTokenStorage(storageKey: string): TokenStorage {\n return {\n get: () => {\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : null;\n } catch {\n return null;\n }\n },\n set: (data: any) => {\n try {\n localStorage.setItem(storageKey, JSON.stringify(data));\n } catch {\n // Handle storage errors silently\n }\n },\n clear: () => {\n try {\n localStorage.removeItem(storageKey);\n } catch {\n // Handle storage errors silently\n }\n },\n };\n }\n\n setTokens(tokens: TokenData): void {\n // Convert expiresIn to expiresAt if needed\n const tokenData: TokenData = {\n ...tokens,\n expiresAt:\n tokens.expiresAt || (tokens.expiresIn ? Date.now() + tokens.expiresIn * 1000 : undefined),\n };\n\n // Always use this instance's tokenStorage (defined in constructor)\n this.tokenStorage.set(tokenData);\n }\n\n getTokens(): TokenData | null {\n return this.tokenStorage.get();\n }\n\n clearTokens(): void {\n this.tokenStorage.clear();\n }\n\n isTokenExpired(token?: TokenData): boolean {\n const tokens = token || this.getTokens();\n if (!tokens?.expiresAt) return false;\n\n return Date.now() >= tokens.expiresAt;\n }\n\n shouldRefreshToken(token?: TokenData): boolean {\n const tokens = token || this.getTokens();\n if (!tokens?.expiresAt || !this.autoRefresh) return false;\n\n return Date.now() >= tokens.expiresAt - this.refreshThreshold;\n }\n\n getAccessToken(): string | null {\n const tokens = this.getTokens();\n return tokens?.accessToken || null;\n }\n\n async getAuthHeaders(): Promise<Record<string, string>> {\n const tokens = this.getTokens();\n\n // No tokens available\n if (!tokens?.accessToken) {\n return {};\n }\n\n // Token is valid and doesn't need refresh yet, return headers immediately\n if (!this.shouldRefreshToken(tokens)) {\n return {\n Authorization: `Bearer ${tokens.accessToken}`,\n };\n }\n\n // Token needs refresh\n if (!tokens.refreshToken) {\n // No refresh token available, clear session and return empty headers\n this.clearSession();\n if (this.onRefreshFailed) {\n this.onRefreshFailed();\n }\n return {};\n }\n\n // If refresh is already in progress, queue this request\n if (this.refreshPromise) {\n return new Promise((resolve, reject) => {\n this.refreshQueue.push({ resolve, reject });\n });\n }\n\n // Start refresh process\n this.refreshPromise = this.performTokenRefresh(tokens.refreshToken);\n\n try {\n await this.refreshPromise;\n\n // Refresh successful, process queue\n const newTokens = this.getTokens();\n const headers: Record<string, string> = newTokens?.accessToken\n ? { Authorization: `Bearer ${newTokens.accessToken}` }\n : {};\n\n // Resolve all queued requests\n this.refreshQueue.forEach(({ resolve }) => resolve(headers));\n this.refreshQueue = [];\n\n return headers;\n } catch (error) {\n // Refresh failed, reject all queued requests\n const refreshError = error instanceof Error ? error : new Error('Token refresh failed');\n\n this.refreshQueue.forEach(({ reject }) => reject(refreshError));\n this.refreshQueue = [];\n\n // Clear session and notify\n this.clearSession();\n if (this.onRefreshFailed) {\n this.onRefreshFailed();\n }\n\n return {};\n } finally {\n this.refreshPromise = null;\n }\n }\n\n private async performTokenRefresh(refreshToken: string): Promise<void> {\n if (!this.baseUrl) {\n throw new Error('Base URL not configured for token refresh');\n }\n\n const url = `${this.baseUrl}/auth/refresh`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n refreshToken,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);\n }\n\n const refreshResponse = await response.json();\n\n this.setTokens({\n accessToken: refreshResponse.accessToken,\n refreshToken: refreshResponse.refreshToken || refreshToken,\n expiresIn: refreshResponse.expiresIn,\n });\n }\n\n setUser(user: any): void {\n // Store user data alongside tokens\n const currentData = this.tokenStorage.get() || {};\n this.tokenStorage.set({ ...currentData, user });\n }\n\n getUser(): any | null {\n const data = this.tokenStorage.get();\n return data?.user || null;\n }\n\n clearUser(): void {\n const currentData = this.tokenStorage.get() || {};\n delete currentData.user;\n this.tokenStorage.set(currentData);\n }\n\n clearSession(): void {\n this.clearTokens();\n this.clearUser();\n }\n\n /**\n * Decode JWT token and extract payload\n * Returns null if token is invalid or cannot be decoded\n */\n getTokenPayload(): JwtPayload | null {\n try {\n const tokens = this.getTokens();\n if (!tokens?.accessToken) return null;\n\n // JWT structure: header.payload.signature\n const parts = tokens.accessToken.split('.');\n if (parts.length !== 3) return null;\n\n // Decode base64 payload (second part)\n const payload = parts[1];\n const decodedPayload = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decodedPayload) as JwtPayload;\n } catch {\n // Silent fail - invalid token format\n return null;\n }\n }\n\n /**\n * Get userId from token (source of truth) or fallback to stored user\n */\n getUserId(): string | null {\n // Priority 1: Get from JWT token (source of truth)\n const payload = this.getTokenPayload();\n if (payload?.userId) return payload.userId;\n\n // Priority 2: Fallback to stored user data\n const user = this.getUser();\n return user?.id || null;\n }\n\n hasValidSession(): boolean {\n const tokens = this.getTokens();\n return tokens !== null && !this.isTokenExpired(tokens);\n }\n}\n","import { HttpService } from './HttpService';\nimport type {\n LoginRequest,\n LoginResponse,\n SignupRequest,\n ChangePasswordRequest,\n RefreshTokenRequest,\n RefreshTokenResponse,\n MagicLinkRequest,\n MagicLinkResponse,\n VerifyMagicLinkRequest,\n VerifyMagicLinkResponse,\n ApiResponse,\n User,\n} from '../types/api';\n\nexport class AuthApiService {\n constructor(private httpService: HttpService) {}\n\n // Public endpoints - no auth required\n async login(request: LoginRequest): Promise<LoginResponse> {\n const response = await this.httpService.post<LoginResponse>('/auth/login', request);\n console.log(response);\n return response;\n }\n\n async signup(request: SignupRequest): Promise<User> {\n const response = await this.httpService.post<User>('/auth/signup', request);\n return response;\n }\n\n async signupTenantAdmin(request: {\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n password: string;\n tenantName: string;\n appId?: string;\n }): Promise<{ user: User; tenant: any }> {\n const response = await this.httpService.post<{ user: User; tenant: any }>(\n '/auth/signup/tenant-admin',\n request\n );\n return response;\n }\n\n async refreshToken(request: RefreshTokenRequest): Promise<RefreshTokenResponse> {\n const response = await this.httpService.post<RefreshTokenResponse>('/auth/refresh', request);\n return response;\n }\n\n async requestPasswordReset(request: { email: string; tenantId: string }): Promise<void> {\n await this.httpService.post<void>('/auth/password-reset/request', request);\n }\n\n async sendMagicLink(request: MagicLinkRequest): Promise<MagicLinkResponse> {\n const response = await this.httpService.post<MagicLinkResponse>(\n '/auth/magic-link/send',\n request\n );\n return response;\n }\n\n async verifyMagicLink(request: VerifyMagicLinkRequest): Promise<VerifyMagicLinkResponse> {\n const response = await this.httpService.post<VerifyMagicLinkResponse>(\n '/auth/magic-link/verify',\n request\n );\n return response;\n }\n\n async confirmPasswordReset(request: { token: string; newPassword: string }): Promise<void> {\n await this.httpService.post<void>('/auth/password-reset/confirm', request);\n }\n\n // Protected endpoints - auth required\n async changePassword(\n request: ChangePasswordRequest,\n authHeaders: Record<string, string>\n ): Promise<void> {\n await this.httpService.post<ApiResponse<null>>('/auth/change-password', request, {\n headers: authHeaders,\n });\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Role,\n CreateRoleRequest,\n AssignRoleRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class RoleApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createRole(request: CreateRoleRequest): Promise<Role> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Role>>('/roles/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getRoleById(id: string): Promise<Role> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Role>>(`/roles/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateRole(id: string, request: Partial<CreateRoleRequest>): Promise<Role> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Role>>(`/roles/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async deleteRole(id: string): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/roles/${id}`, {\n headers: authHeaders,\n });\n }\n\n // Public endpoint - no auth required\n async getRolesByApp(\n appId: string,\n params?: PaginationParams\n ): Promise<{ roles: Role[]; meta: any }> {\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/roles/app/${appId}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Role[]>>(url);\n\n return {\n roles: response.data,\n meta: response.meta,\n };\n }\n\n async assignRole(roleId: string, request: AssignRoleRequest): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.post<ApiResponse<null>>(`/roles/${roleId}/assign`, request, {\n headers: authHeaders,\n });\n }\n\n async revokeRole(roleId: string, request: AssignRoleRequest): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.post<ApiResponse<null>>(`/roles/${roleId}/revoke`, request, {\n headers: authHeaders,\n });\n }\n\n async getUserRoles(\n userId: string,\n params?: PaginationParams\n ): Promise<{ roles: Role[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/roles/user/${userId}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Role[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n roles: response.data,\n meta: response.meta,\n };\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type { User, CreateUserRequest, ApiResponse, PaginationParams } from '../types/api';\n\nexport class UserApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager: SessionManager\n ) {}\n\n async createUser(request: CreateUserRequest): Promise<User> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<User>>('/users/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getUsers(params?: PaginationParams): Promise<{ users: User[]; meta: any }> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/users/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<User[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n users: response.data,\n meta: response.meta,\n };\n }\n\n async getUserById(id: string): Promise<User> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<User>>(`/users/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateUser(id: string, request: Partial<CreateUserRequest>): Promise<User> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<User>>(`/users/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async deleteUser(id: string): Promise<void> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/users/${id}`, {\n headers: authHeaders,\n });\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Tenant,\n CreateTenantRequest,\n PublicTenantInfo,\n TenantSettings,\n UpdateTenantSettingsRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class TenantApiService {\n constructor(\n private httpService: HttpService,\n private appId: string,\n private sessionManager?: SessionManager\n ) {}\n\n async createTenant(request: CreateTenantRequest): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Tenant>>('/tenants/', request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async getTenants(params?: PaginationParams): Promise<{ tenants: Tenant[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/tenants/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Tenant[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n tenants: response.data,\n meta: response.meta,\n };\n }\n\n async getTenantById(id: string): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Tenant>>(`/tenants/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateTenant(id: string, request: Partial<CreateTenantRequest>): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Tenant>>(`/tenants/${id}`, request, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async adminUpdateTenant(id: string, request: Partial<CreateTenantRequest>): Promise<Tenant> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Tenant>>(\n `/tenants/${id}/admin-update`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n // Public endpoint - no auth required\n async getPublicTenantInfo(slug: string): Promise<PublicTenantInfo> {\n const response = await this.httpService.get<ApiResponse<PublicTenantInfo>>(\n `/tenants/${this.appId}/${slug}/public`\n );\n return response.data;\n }\n\n // Settings endpoints\n async getTenantSettings(id: string): Promise<TenantSettings> {\n const response = await this.httpService.get<ApiResponse<TenantSettings>>(\n `/tenants/${id}/settings`\n );\n return response.data;\n }\n\n async updateTenantSettings(\n id: string,\n request: UpdateTenantSettingsRequest\n ): Promise<TenantSettings> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<TenantSettings>>(\n `/tenants/${id}/settings`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n}\n","import {\n createContext,\n useContext,\n useMemo,\n ReactNode,\n useState,\n useEffect,\n useCallback,\n} from 'react';\nimport { useApp } from './AppProvider';\nimport { HttpService } from '../services/HttpService';\nimport { TenantApiService } from '../services/TenantApiService';\nimport type { TenantSettings, JSONSchema, PublicTenantInfo } from '../types/api';\n\n// RFC-003: Cache interface for tenant info\ninterface CachedTenantInfo {\n data: PublicTenantInfo;\n timestamp: number;\n tenantSlug: string;\n}\n\nexport interface TenantConfig {\n // Tenant configuration\n tenantMode?: 'subdomain' | 'selector';\n selectorParam?: string; // Default: 'tenant', used when tenantMode is 'selector'\n // RFC-003: Cache configuration\n cache?: {\n enabled?: boolean; // Default: true\n ttl?: number; // Time to live in milliseconds, default: 5 minutes\n storageKey?: string; // Default: 'tenant_cache_{tenantSlug}'\n };\n // SSR support\n initialTenant?: PublicTenantInfo;\n // Fallbacks\n loadingFallback?: ReactNode;\n errorFallback?: ReactNode | ((error: Error, retry: () => void) => ReactNode);\n}\n\ninterface TenantContextValue {\n // Tenant info\n tenant: PublicTenantInfo | null;\n tenantSlug: string | null;\n isTenantLoading: boolean;\n tenantError: Error | null;\n retryTenant: () => void;\n // Settings\n settings: TenantSettings | null;\n settingsSchema: JSONSchema | null;\n isSettingsLoading: boolean;\n settingsError: Error | null;\n // Actions\n refreshSettings: () => void;\n switchTenant: (tenantSlug: string, mode?: 'navigate' | 'reload') => void;\n // Validation\n validateSettings: (settings: TenantSettings) => { isValid: boolean; errors: string[] };\n}\n\nconst TenantContext = createContext<TenantContextValue | null>(null);\n\ninterface TenantProviderProps {\n config: TenantConfig;\n children: ReactNode;\n}\n\n// Default loading component\nconst DefaultLoadingFallback = () => (\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div>Loading tenant...</div>\n </div>\n);\n\n// Default error component\nconst DefaultErrorFallback = ({ error, retry }: { error: Error; retry: () => void }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100vh',\n fontFamily: 'system-ui, sans-serif',\n textAlign: 'center',\n padding: '20px',\n }}\n >\n <h2 style={{ color: '#dc3545', marginBottom: '16px' }}>Tenant Error</h2>\n <p style={{ color: '#6c757d', marginBottom: '24px' }}>\n {error.message || 'Unable to load tenant'}\n </p>\n <button\n onClick={retry}\n style={{\n padding: '8px 16px',\n backgroundColor: '#007bff',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n </div>\n);\n\nexport function TenantProvider({ config, children }: TenantProviderProps) {\n const { baseUrl, appInfo, appId } = useApp();\n\n // Detect tenant slug from URL or config with localStorage fallback\n const detectTenantSlug = useCallback((): string | null => {\n const tenantMode = config.tenantMode || 'selector';\n const storageKey = `tenant`;\n\n if (typeof window === 'undefined') return null;\n\n if (tenantMode === 'subdomain') {\n const hostname = window.location.hostname;\n const parts = hostname.split('.');\n\n // Extract subdomain (assuming format: subdomain.domain.com)\n if (parts.length >= 3) {\n const subdomain = parts[0];\n // Save to localStorage for persistence\n localStorage.setItem(storageKey, subdomain);\n return subdomain;\n }\n\n // Fallback to localStorage if no subdomain found\n return localStorage.getItem(storageKey);\n } else if (tenantMode === 'selector') {\n // tenantMode === 'selector'\n const urlParams = new URLSearchParams(window.location.search);\n const urlTenant = urlParams.get(config.selectorParam || 'tenant');\n\n if (urlTenant) {\n // Save to localStorage when found in URL\n localStorage.setItem(storageKey, urlTenant);\n return urlTenant;\n }\n\n // Fallback to localStorage if not in URL\n return localStorage.getItem(storageKey);\n }\n\n // No tenant mode specified, return null\n return null;\n }, [config.tenantMode, config.selectorParam]);\n\n // Detect tenant slug on mount and on URL changes\n const [tenantSlug, setTenantSlug] = useState<string | null>(() => detectTenantSlug());\n\n // RFC-003: Cache configuration with defaults\n const cacheConfig = useMemo(\n () => ({\n enabled: config.cache?.enabled ?? true,\n ttl: config.cache?.ttl ?? 5 * 60 * 1000, // 5 minutes default\n storageKey: config.cache?.storageKey ?? `tenant_cache_${tenantSlug || 'default'}`,\n }),\n [config.cache, tenantSlug]\n );\n\n // RFC-003: Try to load from cache on initialization\n const [tenant, setTenant] = useState<PublicTenantInfo | null>(() => {\n if (config.initialTenant) return config.initialTenant;\n if (!cacheConfig.enabled || !tenantSlug) return null;\n\n try {\n const cached = localStorage.getItem(cacheConfig.storageKey);\n if (!cached) return null;\n\n const parsed: CachedTenantInfo = JSON.parse(cached);\n const now = Date.now();\n const age = now - parsed.timestamp;\n\n // Check if cache is still valid\n if (age < cacheConfig.ttl && parsed.tenantSlug === tenantSlug) {\n return parsed.data;\n }\n\n // Cache expired\n localStorage.removeItem(cacheConfig.storageKey);\n return null;\n } catch {\n return null;\n }\n });\n\n const [isTenantLoading, setIsTenantLoading] = useState(!tenant && !config.initialTenant);\n const [tenantError, setTenantError] = useState<Error | null>(null);\n\n // Settings state\n const [settings, setSettings] = useState<TenantSettings | null>(null);\n const [isSettingsLoading, setIsSettingsLoading] = useState(false);\n const [settingsError, setSettingsError] = useState<Error | null>(null);\n\n // Re-detect tenant slug when URL changes\n useEffect(() => {\n const detected = detectTenantSlug();\n setTenantSlug(detected);\n }, [detectTenantSlug]);\n\n // Get settings schema from app info\n const settingsSchema = appInfo?.settingsSchema || null;\n\n // RFC-003: Load tenant info with caching\n const loadTenant = useCallback(\n async (slug: string, bypassCache = false) => {\n // Check cache first (unless bypassing)\n if (!bypassCache && cacheConfig.enabled && tenant && tenant.domain === slug) {\n return; // Already have valid cached data\n }\n\n try {\n setIsTenantLoading(true);\n setTenantError(null);\n\n const httpService = new HttpService(baseUrl);\n const tenantApi = new TenantApiService(httpService, appId);\n const tenantInfo = await tenantApi.getPublicTenantInfo(slug);\n setTenant(tenantInfo);\n\n // RFC-003: Save to cache\n if (cacheConfig.enabled) {\n try {\n const cacheData: CachedTenantInfo = {\n data: tenantInfo,\n timestamp: Date.now(),\n tenantSlug: slug,\n };\n localStorage.setItem(cacheConfig.storageKey, JSON.stringify(cacheData));\n } catch (error) {\n console.warn('Failed to cache tenant info:', error);\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load tenant information');\n setTenantError(error);\n setTenant(null);\n } finally {\n setIsTenantLoading(false);\n }\n },\n [baseUrl, appId, cacheConfig, tenant]\n );\n\n // RFC-003: Background refresh for stale-while-revalidate\n const backgroundRefresh = useCallback(async () => {\n if (!cacheConfig.enabled || !tenant || !tenantSlug) return;\n\n try {\n const cached = localStorage.getItem(cacheConfig.storageKey);\n if (!cached) return;\n\n const parsed: CachedTenantInfo = JSON.parse(cached);\n const age = Date.now() - parsed.timestamp;\n\n // If cache is more than 50% expired, refresh in background\n if (age > cacheConfig.ttl * 0.5) {\n const httpService = new HttpService(baseUrl);\n const tenantApi = new TenantApiService(httpService, appId);\n const tenantInfo = await tenantApi.getPublicTenantInfo(tenantSlug);\n\n setTenant(tenantInfo);\n\n const cacheData: CachedTenantInfo = {\n data: tenantInfo,\n timestamp: Date.now(),\n tenantSlug,\n };\n localStorage.setItem(cacheConfig.storageKey, JSON.stringify(cacheData));\n }\n } catch (error) {\n console.warn('Background tenant refresh failed:', error);\n // Don't update error state - keep showing cached data\n }\n }, [baseUrl, appId, cacheConfig, tenant, tenantSlug]);\n\n // Load tenant settings\n const loadSettings = useCallback(async () => {\n if (!tenant?.id) return;\n\n try {\n setIsSettingsLoading(true);\n setSettingsError(null);\n\n const httpService = new HttpService(baseUrl);\n const tenantApi = new TenantApiService(httpService, tenant.appId);\n const tenantSettings = await tenantApi.getTenantSettings(tenant.id);\n setSettings(tenantSettings);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load tenant settings');\n setSettingsError(error);\n setSettings(null);\n } finally {\n setIsSettingsLoading(false);\n }\n }, [baseUrl, tenant]);\n\n // Refresh settings\n const refreshSettings = useCallback(() => {\n loadSettings();\n }, [loadSettings]);\n\n // Validate settings against schema\n const validateSettings = useCallback(\n (settingsToValidate: TenantSettings) => {\n if (!settingsSchema) {\n return { isValid: true, errors: [] };\n }\n\n const errors: string[] = [];\n\n try {\n // If settingsSchema has properties, validate against them\n if (settingsSchema.properties) {\n Object.entries(settingsSchema.properties).forEach(([key, fieldSchema]) => {\n const value = settingsToValidate[key];\n\n // Check required fields\n if (settingsSchema.required?.includes(key) && (value === undefined || value === null)) {\n errors.push(`Field '${key}' is required`);\n return;\n }\n\n // Skip validation if value is not provided and not required\n if (value === undefined || value === null) return;\n\n // Type validation using JSONSchema\n if (fieldSchema.type) {\n const expectedType = fieldSchema.type;\n const actualType = typeof value;\n\n if (expectedType === 'string' && actualType !== 'string') {\n errors.push(`Field '${key}' must be a string`);\n } else if (\n (expectedType === 'number' || expectedType === 'integer') &&\n actualType !== 'number'\n ) {\n errors.push(`Field '${key}' must be a number`);\n } else if (expectedType === 'boolean' && actualType !== 'boolean') {\n errors.push(`Field '${key}' must be a boolean`);\n } else if (expectedType === 'array' && !Array.isArray(value)) {\n errors.push(`Field '${key}' must be an array`);\n }\n }\n\n // String length validation\n if (\n fieldSchema.minLength !== undefined &&\n typeof value === 'string' &&\n value.length < fieldSchema.minLength\n ) {\n errors.push(\n `Field '${key}' must be at least ${fieldSchema.minLength} characters long`\n );\n }\n if (\n fieldSchema.maxLength !== undefined &&\n typeof value === 'string' &&\n value.length > fieldSchema.maxLength\n ) {\n errors.push(\n `Field '${key}' must be no more than ${fieldSchema.maxLength} characters long`\n );\n }\n\n // Number range validation\n if (\n fieldSchema.minimum !== undefined &&\n typeof value === 'number' &&\n value < fieldSchema.minimum\n ) {\n errors.push(`Field '${key}' must be at least ${fieldSchema.minimum}`);\n }\n if (\n fieldSchema.maximum !== undefined &&\n typeof value === 'number' &&\n value > fieldSchema.maximum\n ) {\n errors.push(`Field '${key}' must be no more than ${fieldSchema.maximum}`);\n }\n\n // Pattern validation for strings\n if (fieldSchema.pattern && typeof value === 'string') {\n const regex = new RegExp(fieldSchema.pattern);\n if (!regex.test(value)) {\n errors.push(`Field '${key}' does not match the required pattern`);\n }\n }\n\n // Enum validation\n if (fieldSchema.enum && !fieldSchema.enum.includes(value)) {\n errors.push(`Field '${key}' must be one of: ${fieldSchema.enum.join(', ')}`);\n }\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n } catch {\n return {\n isValid: false,\n errors: ['Invalid settings schema or validation error'],\n };\n }\n },\n [settingsSchema]\n );\n\n // RFC-003: Load tenant on mount or do background refresh\n useEffect(() => {\n if (!config.initialTenant && tenantSlug) {\n if (!tenant) {\n // No cached data, fetch from server\n loadTenant(tenantSlug);\n } else {\n // We have cached data, do background refresh\n backgroundRefresh();\n }\n } else if (!config.initialTenant && !tenantSlug) {\n // No tenant slug found - continue without tenant\n setTenant(null);\n setTenantError(null);\n setIsTenantLoading(false);\n }\n }, [config.initialTenant, tenantSlug, tenant, loadTenant, backgroundRefresh]);\n\n // Load settings when tenant changes\n useEffect(() => {\n if (tenant?.id) {\n loadSettings();\n } else {\n setSettings(null);\n setSettingsError(null);\n setIsSettingsLoading(false);\n }\n }, [tenant?.id, loadSettings]);\n\n // Switch tenant by updating URL and reloading page\n const switchTenant = useCallback(\n (targetTenantSlug: string, mode: 'navigate' | 'reload' = 'reload') => {\n const tenantMode = config.tenantMode || 'selector';\n\n console.log('[TenantProvider] Switching tenant:', {\n targetTenantSlug,\n currentTenantSlug: tenantSlug,\n tenantMode,\n mode,\n });\n\n // Update localStorage first\n localStorage.setItem('tenant', targetTenantSlug);\n\n if (tenantMode === 'subdomain') {\n // Subdomain mode: redirect to new subdomain\n const currentHostname = window.location.hostname;\n const parts = currentHostname.split('.');\n\n if (parts.length >= 2) {\n // Replace subdomain\n parts[0] = targetTenantSlug;\n const newHostname = parts.join('.');\n const newUrl = `${window.location.protocol}//${newHostname}${window.location.pathname}${window.location.search}`;\n console.log('[TenantProvider] Redirecting to:', newUrl);\n window.location.href = newUrl;\n } else {\n console.warn(\n '[TenantProvider] Cannot switch subdomain, invalid hostname:',\n currentHostname\n );\n }\n } else if (tenantMode === 'selector') {\n // Selector mode: update URL parameter\n const urlParams = new URLSearchParams(window.location.search);\n urlParams.set(config.selectorParam || 'tenant', targetTenantSlug);\n\n if (mode === 'reload') {\n // Full page reload with new tenant\n const newUrl = `${window.location.pathname}?${urlParams.toString()}${window.location.hash}`;\n console.log('[TenantProvider] Reloading with new tenant:', newUrl);\n window.location.href = newUrl;\n } else {\n // Navigate without reload (requires router integration)\n const newUrl = `${window.location.pathname}?${urlParams.toString()}${window.location.hash}`;\n console.log('[TenantProvider] Navigating without reload:', newUrl);\n window.history.pushState({}, '', newUrl);\n // Update state to trigger re-render\n setTenantSlug(targetTenantSlug);\n // Trigger tenant reload\n loadTenant(targetTenantSlug);\n }\n }\n },\n [config.tenantMode, config.selectorParam, loadTenant, tenantSlug]\n );\n\n const contextValue = useMemo(() => {\n // Retry function for tenant loading\n const retryTenant = () => {\n if (tenantSlug) {\n loadTenant(tenantSlug);\n }\n };\n\n return {\n // Tenant info\n tenant,\n tenantSlug,\n isTenantLoading,\n tenantError,\n retryTenant,\n // Settings\n settings,\n settingsSchema,\n isSettingsLoading,\n settingsError,\n // Actions\n refreshSettings,\n switchTenant,\n // Validation\n validateSettings,\n };\n }, [\n tenant,\n tenantSlug,\n isTenantLoading,\n tenantError,\n settings,\n settingsSchema,\n isSettingsLoading,\n settingsError,\n refreshSettings,\n switchTenant,\n validateSettings,\n ]);\n\n // Show loading fallback\n if (isTenantLoading) {\n return <>{config.loadingFallback || <DefaultLoadingFallback />}</>;\n }\n\n // Show error fallback\n if (tenantError) {\n const ErrorComponent =\n typeof config.errorFallback === 'function'\n ? config.errorFallback(tenantError, () => loadTenant(tenantSlug || ''))\n : config.errorFallback || (\n <DefaultErrorFallback error={tenantError} retry={() => loadTenant(tenantSlug || '')} />\n );\n\n return <>{ErrorComponent}</>;\n }\n\n return <TenantContext.Provider value={contextValue}>{children}</TenantContext.Provider>;\n}\n\nexport function useTenant(): TenantContextValue {\n const context = useContext(TenantContext);\n if (!context) {\n throw new Error('useTenant must be used within a TenantProvider');\n }\n return context;\n}\n\n// Backward compatibility\nexport const useTenantSettings = useTenant;\n\n// Convenience hook for just the settings\nexport function useSettings() {\n const { settings, settingsSchema, isSettingsLoading, settingsError, validateSettings } =\n useTenant();\n return {\n settings,\n settingsSchema,\n isLoading: isSettingsLoading,\n error: settingsError,\n validateSettings,\n };\n}\n\n// Convenience hook for just tenant info\nexport function useTenantInfo() {\n const { tenant, tenantSlug, isTenantLoading, tenantError, retryTenant } = useTenant();\n return {\n tenant,\n tenantSlug,\n isLoading: isTenantLoading,\n error: tenantError,\n retry: retryTenant,\n };\n}\n","import { createContext, useContext, ReactNode, useMemo, useState, useEffect } from 'react';\nimport { SessionManager } from '../services/SessionManager';\nimport { AuthApiService } from '../services/AuthApiService';\nimport { RoleApiService } from '../services/RoleApiService';\nimport { UserApiService } from '../services/UserApiService';\nimport { TenantApiService } from '../services/TenantApiService';\nimport { HttpService } from '../services/HttpService';\nimport { useApp } from './AppProvider';\nimport { useTenant } from './TenantProvider';\nimport type {\n Role,\n Permission,\n User,\n LoginResponse,\n VerifyMagicLinkResponse,\n MagicLinkResponse,\n} from '../types/api';\nimport type {\n LoginParams,\n SignupParams,\n SignupTenantAdminParams,\n SendMagicLinkParams,\n VerifyMagicLinkParams,\n RequestPasswordResetParams,\n ConfirmPasswordResetParams,\n ChangePasswordParams,\n} from '../types/authParams';\n\nexport interface AuthConfig {\n onRefreshFailed?: () => void;\n initialRoles?: Role[]; // For SSR injection\n}\n\nexport interface AuthContextValue {\n // RFC-003: Authentication state\n isAuthenticated: boolean;\n sessionManager: SessionManager;\n authenticatedHttpService: HttpService; // Authenticated HttpService for protected endpoints\n // Auth methods (RFC-002: Object parameters)\n login: (params: LoginParams) => Promise<LoginResponse>;\n signup: (params: SignupParams) => Promise<User>;\n signupTenantAdmin: (params: SignupTenantAdminParams) => Promise<{ user: User; tenant: any }>;\n // Magic Link methods\n sendMagicLink: (params: SendMagicLinkParams) => Promise<MagicLinkResponse>;\n verifyMagicLink: (params: VerifyMagicLinkParams) => Promise<VerifyMagicLinkResponse>;\n changePassword: (params: ChangePasswordParams) => Promise<void>;\n requestPasswordReset: (params: RequestPasswordResetParams) => Promise<void>;\n confirmPasswordReset: (params: ConfirmPasswordResetParams) => Promise<void>;\n refreshToken: () => Promise<void>;\n logout: () => void;\n // Session methods\n setTokens: (tokens: { accessToken: string; refreshToken: string; expiresIn: number }) => void;\n hasValidSession: () => boolean;\n clearSession: () => void;\n // User data\n currentUser: User | null;\n isUserLoading: boolean;\n userError: Error | null;\n loadUserData: (forceRefresh?: boolean) => Promise<void>;\n refreshUser: () => Promise<void>;\n // Role and Permission methods\n userRole: Role | null;\n userPermissions: string[];\n availableRoles: Role[];\n rolesLoading: boolean;\n hasPermission: (permission: string | Permission) => boolean;\n hasAnyPermission: (permissions: (string | Permission)[]) => boolean;\n hasAllPermissions: (permissions: (string | Permission)[]) => boolean;\n getUserPermissionStrings: () => string[];\n refreshRoles: () => Promise<void>;\n}\n\nconst AuthContext = createContext<AuthContextValue | null>(null);\n\ninterface AuthProviderProps {\n config?: AuthConfig;\n children: ReactNode;\n}\n\nexport function AuthProvider({ config = {}, children }: AuthProviderProps) {\n const { appId, baseUrl } = useApp();\n const { tenant, tenantSlug, switchTenant } = useTenant();\n const [availableRoles, setAvailableRoles] = useState<Role[]>(config.initialRoles || []);\n const [rolesLoading, setRolesLoading] = useState(!config.initialRoles);\n const [currentUser, setCurrentUser] = useState<User | null>(null);\n const [isUserLoading, setIsUserLoading] = useState(false);\n const [userError, setUserError] = useState<Error | null>(null);\n const [lastUserFetch, setLastUserFetch] = useState<number>(0);\n\n // Create services with stable references\n const sessionManager = useMemo(() => {\n return new SessionManager({\n tenantSlug: tenantSlug, // SessionManager will generate storageKey internally\n onRefreshFailed: config.onRefreshFailed,\n baseUrl: baseUrl,\n });\n }, [tenantSlug, baseUrl, config.onRefreshFailed]);\n\n const authenticatedHttpService = useMemo(() => {\n const service = new HttpService(baseUrl);\n service.setSessionManager(sessionManager);\n return service;\n }, [baseUrl, sessionManager]);\n\n const authApiService = useMemo(() => {\n return new AuthApiService(new HttpService(baseUrl));\n }, [baseUrl]);\n\n const userApiService = useMemo(() => {\n return new UserApiService(authenticatedHttpService, sessionManager);\n }, [authenticatedHttpService, sessionManager]);\n\n const roleApiService = useMemo(() => {\n return new RoleApiService(new HttpService(baseUrl));\n }, [baseUrl]);\n\n // Calculate derived values with useMemo to prevent recalculation\n const user = useMemo(() => {\n return currentUser || sessionManager.getUser();\n }, [currentUser, sessionManager]);\n\n const userRole = useMemo(() => {\n return user?.roleId ? availableRoles.find(role => role.id === user.roleId) || null : null;\n }, [user, availableRoles]);\n\n const userPermissions = useMemo(() => {\n const permissions = userRole?.permissions || [];\n // Permissions from API are already strings in 'resource.action' format\n return permissions;\n }, [userRole]);\n\n // RFC-003: Compute isAuthenticated from session state\n const isAuthenticated = useMemo(() => {\n return sessionManager.hasValidSession() && currentUser !== null;\n }, [sessionManager, currentUser]);\n\n // Cache configuration: refetch user data every 5 minutes\n const USER_DATA_CACHE_TTL = 5 * 60 * 1000; // 5 minutes in milliseconds\n\n const contextValue = useMemo(() => {\n // Load user data from API with cache control\n const loadUserData = async (forceRefresh = false) => {\n try {\n // 1. Check if we have a valid session\n if (!sessionManager.hasValidSession()) {\n return;\n }\n\n // 2. Check if we should use cached data\n const now = Date.now();\n const cacheValid = !forceRefresh && now - lastUserFetch < USER_DATA_CACHE_TTL;\n\n if (cacheValid && currentUser) {\n return;\n }\n\n // 3. Get userId from token (source of truth) or fallback to stored user\n const userId = sessionManager.getUserId();\n if (!userId) {\n console.warn('[AuthProvider] No userId available in token or storage');\n return;\n }\n\n setIsUserLoading(true);\n setUserError(null);\n\n const userData = await userApiService.getUserById(userId);\n setCurrentUser(userData);\n sessionManager.setUser(userData); // Update session with fresh data\n setLastUserFetch(Date.now()); // Update cache timestamp\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load user data');\n setUserError(error);\n console.error('[AuthProvider] Failed to load user data:', error);\n } finally {\n setIsUserLoading(false);\n }\n };\n\n const refreshUser = async () => {\n await loadUserData();\n };\n\n // Auth methods (RFC-002: Object parameters + RFC-001: Auto-switch)\n const login = async (params: LoginParams): Promise<LoginResponse> => {\n const { username, password, tenantSlug: targetSlug } = params;\n\n // RFC-001: Get tenantId from slug if provided, otherwise use current context\n let resolvedTenantId = tenant?.id;\n let targetTenantSlug = tenantSlug;\n let targetSessionManager = sessionManager;\n\n if (targetSlug) {\n // Get tenant ID from public endpoint using slug\n const tenantApi = new TenantApiService(authenticatedHttpService, appId);\n const tenantInfo = await tenantApi.getPublicTenantInfo(targetSlug);\n resolvedTenantId = tenantInfo.id;\n targetTenantSlug = targetSlug;\n }\n\n const loginResponse = await authApiService.login({\n username,\n password,\n appId,\n tenantId: resolvedTenantId,\n });\n\n // Check if we need to switch\n const shouldSwitch = targetSlug && targetSlug !== tenantSlug;\n\n // Save tokens to the correct tenant\n\n if (shouldSwitch) {\n // If switching, create a new SessionManager for the target tenant\n targetSessionManager = new SessionManager({\n tenantSlug: targetTenantSlug,\n baseUrl: baseUrl,\n });\n }\n\n targetSessionManager.setTokens({\n accessToken: loginResponse.accessToken,\n refreshToken: loginResponse.refreshToken,\n expiresIn: loginResponse.expiresIn,\n });\n\n // Store user data if available in the response\n if (loginResponse.user) {\n targetSessionManager.setUser(loginResponse.user);\n setCurrentUser(loginResponse.user);\n\n // Load complete user data from API after login\n try {\n await loadUserData();\n } catch (error) {\n console.warn('Failed to load complete user data after login:', error);\n }\n }\n\n // Now perform the switch if needed\n if (shouldSwitch && targetTenantSlug && targetTenantSlug !== tenantSlug) {\n switchTenant(targetTenantSlug);\n // Code after this won't execute due to page reload\n }\n\n return loginResponse;\n };\n\n const signup = async (params: SignupParams): Promise<User> => {\n const { email, phoneNumber, name, password, lastName, tenantId } = params;\n\n if (!email && !phoneNumber) {\n throw new Error('Either email or phoneNumber is required');\n }\n if (!name || !password) {\n throw new Error('Name and password are required');\n }\n\n const resolvedTenantId = tenantId ?? tenant?.id;\n\n const signupResponse = await authApiService.signup({\n email,\n phoneNumber,\n name,\n password,\n tenantId: resolvedTenantId,\n lastName,\n appId,\n });\n return signupResponse;\n };\n\n const signupTenantAdmin = async (\n params: SignupTenantAdminParams\n ): Promise<{ user: User; tenant: any }> => {\n const { email, phoneNumber, name, password, tenantName, lastName } = params;\n\n if (!email && !phoneNumber) {\n throw new Error('Either email or phoneNumber is required');\n }\n if (!name || !password || !tenantName) {\n throw new Error('Name, password, and tenantName are required');\n }\n\n const signupResponse = await authApiService.signupTenantAdmin({\n email,\n phoneNumber,\n name,\n password,\n tenantName,\n appId,\n lastName,\n });\n return signupResponse;\n };\n\n const changePassword = async (params: ChangePasswordParams): Promise<void> => {\n const { currentPassword, newPassword } = params;\n const authHeaders = await sessionManager.getAuthHeaders();\n await authApiService.changePassword({ currentPassword, newPassword }, authHeaders);\n };\n\n const requestPasswordReset = async (params: RequestPasswordResetParams): Promise<void> => {\n const { email, tenantId } = params;\n const resolvedTenantId = tenantId ?? tenant?.id;\n\n if (!resolvedTenantId) {\n throw new Error('tenantId is required for password reset');\n }\n\n await authApiService.requestPasswordReset({ email, tenantId: resolvedTenantId });\n };\n\n const confirmPasswordReset = async (params: ConfirmPasswordResetParams): Promise<void> => {\n const { token, newPassword } = params;\n await authApiService.confirmPasswordReset({ token, newPassword });\n };\n\n // Magic Link methods\n const sendMagicLink = async (params: SendMagicLinkParams): Promise<MagicLinkResponse> => {\n const { email, frontendUrl, name, lastName, tenantId } = params;\n const resolvedTenantId = tenantId ?? tenant?.id;\n\n if (!resolvedTenantId) {\n throw new Error('tenantId is required for magic link authentication');\n }\n\n const response = await authApiService.sendMagicLink({\n email,\n tenantId: resolvedTenantId,\n frontendUrl,\n name,\n lastName,\n appId,\n });\n return response;\n };\n\n const verifyMagicLink = async (\n params: VerifyMagicLinkParams\n ): Promise<VerifyMagicLinkResponse> => {\n const { token, email, tenantSlug: targetSlug } = params;\n\n // RFC-001: Get tenantId from slug if provided, otherwise use current context\n let resolvedTenantId = tenant?.id;\n let targetTenantSlug = tenantSlug;\n let targetSessionManager = sessionManager;\n\n if (targetSlug) {\n // Get tenant ID from public endpoint using slug\n const tenantApi = new TenantApiService(authenticatedHttpService, appId);\n const tenantInfo = await tenantApi.getPublicTenantInfo(targetSlug);\n resolvedTenantId = tenantInfo.id;\n targetTenantSlug = targetSlug;\n }\n\n const verifyResponse = await authApiService.verifyMagicLink({\n token,\n email,\n appId,\n tenantId: resolvedTenantId,\n });\n\n // Check if we need to switch\n const shouldSwitch = targetSlug && targetSlug !== tenantSlug;\n\n // Save tokens to the correct tenant\n\n if (shouldSwitch) {\n // If switching, create a new SessionManager for the target tenant\n targetSessionManager = new SessionManager({\n tenantSlug: targetTenantSlug,\n baseUrl: baseUrl,\n });\n }\n targetSessionManager.setTokens({\n accessToken: verifyResponse.accessToken,\n refreshToken: verifyResponse.refreshToken,\n expiresIn: verifyResponse.expiresIn,\n });\n\n // Store user data\n if (verifyResponse.user) {\n targetSessionManager.setUser(verifyResponse.user);\n setCurrentUser(verifyResponse.user);\n\n // Load complete user data from API after magic link login\n try {\n await loadUserData();\n } catch (error) {\n console.warn('Failed to load complete user data after magic link login:', error);\n }\n }\n\n // Now perform the switch if needed\n if (shouldSwitch && targetTenantSlug && targetTenantSlug !== tenantSlug) {\n switchTenant(targetTenantSlug);\n // Code after this won't execute due to page reload\n }\n\n return verifyResponse;\n };\n\n const refreshToken = async () => {\n const tokens = sessionManager.getTokens();\n if (!tokens?.refreshToken) {\n throw new Error('No refresh token available');\n }\n\n const refreshResponse = await authApiService.refreshToken({\n refreshToken: tokens.refreshToken,\n });\n\n sessionManager.setTokens({\n accessToken: refreshResponse.accessToken,\n refreshToken: refreshResponse.refreshToken || tokens.refreshToken,\n expiresIn: refreshResponse.expiresIn,\n });\n };\n\n const logout = () => {\n sessionManager.clearSession();\n setCurrentUser(null);\n setUserError(null);\n };\n\n const setTokens = (tokens: {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n }) => {\n sessionManager.setTokens(tokens);\n };\n\n const hasValidSession = () => {\n return sessionManager.hasValidSession();\n };\n\n const clearSession = () => {\n sessionManager.clearSession();\n setCurrentUser(null);\n setUserError(null);\n };\n\n // Role and Permission methods\n const fetchRoles = async () => {\n if (!appId) return;\n\n try {\n setRolesLoading(true);\n const { roles } = await roleApiService.getRolesByApp(appId);\n setAvailableRoles(roles);\n } catch (error) {\n console.error('Failed to fetch roles:', error);\n } finally {\n setRolesLoading(false);\n }\n };\n\n const refreshRoles = async () => {\n await fetchRoles();\n };\n\n // Helper functions for permission checks\n const hasPermission = (permission: string | Permission): boolean => {\n if (!userPermissions || userPermissions.length === 0) {\n return false;\n }\n\n if (typeof permission === 'string') {\n // userPermissions is now an array of strings in 'resource.action' format\n return userPermissions.includes(permission);\n }\n\n // For Permission objects, convert to string and check\n const permissionString = `${permission.resource}.${permission.action}`;\n return userPermissions.includes(permissionString);\n };\n\n const hasAnyPermission = (permissions: (string | Permission)[]): boolean => {\n return permissions.some(permission => hasPermission(permission));\n };\n\n const hasAllPermissions = (permissions: (string | Permission)[]): boolean => {\n return permissions.every(permission => hasPermission(permission));\n };\n\n // Utility function to get all user permissions in resource.action format\n const getUserPermissionStrings = (): string[] => {\n if (!userPermissions) return [];\n // userPermissions is already an array of strings\n return userPermissions;\n };\n\n return {\n // RFC-003: Authentication state\n isAuthenticated,\n sessionManager,\n authenticatedHttpService,\n login,\n signup,\n signupTenantAdmin,\n sendMagicLink,\n verifyMagicLink,\n changePassword,\n requestPasswordReset,\n confirmPasswordReset,\n refreshToken,\n logout,\n setTokens,\n hasValidSession,\n clearSession,\n currentUser,\n isUserLoading,\n userError,\n loadUserData,\n refreshUser,\n userRole,\n userPermissions,\n availableRoles,\n rolesLoading,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n getUserPermissionStrings,\n refreshRoles,\n };\n }, [\n isAuthenticated,\n sessionManager,\n authenticatedHttpService,\n authApiService,\n userApiService,\n roleApiService,\n appId,\n tenant,\n tenantSlug,\n switchTenant,\n availableRoles,\n currentUser,\n isUserLoading,\n userError,\n userRole,\n userPermissions,\n lastUserFetch,\n USER_DATA_CACHE_TTL,\n ]);\n\n // Fetch roles on mount if not provided via SSR\n useEffect(() => {\n if (!config.initialRoles && appId) {\n const fetchRoles = async () => {\n try {\n setRolesLoading(true);\n const internalHttpService = new HttpService(baseUrl);\n const roleApiService = new RoleApiService(internalHttpService);\n const { roles } = await roleApiService.getRolesByApp(appId);\n setAvailableRoles(roles);\n } catch (error) {\n console.error('Failed to fetch roles:', error);\n } finally {\n setRolesLoading(false);\n }\n };\n\n fetchRoles();\n }\n }, [appId, baseUrl, config.initialRoles]);\n\n // Initialize user data from session on mount\n useEffect(() => {\n const user = sessionManager.getUser();\n if (user && sessionManager.hasValidSession()) {\n setCurrentUser(user);\n }\n }, [sessionManager]);\n\n // Auto-load user data if we have tokens but no currentUser\n useEffect(() => {\n // Only trigger auto-load if we don't have currentUser and not already loading\n if (!currentUser && !isUserLoading) {\n contextValue.loadUserData().catch(() => {\n // Silent fail - error already logged in loadUserData\n });\n }\n }, [currentUser, isUserLoading, contextValue]);\n\n // Periodic refresh of user data (every 5 minutes)\n useEffect(() => {\n if (!sessionManager.hasValidSession() || !currentUser) {\n return; // Only refresh if authenticated\n }\n\n const refreshInterval = setInterval(() => {\n contextValue.loadUserData().catch(() => {\n // Silent fail - error already logged in loadUserData\n });\n }, USER_DATA_CACHE_TTL);\n\n return () => clearInterval(refreshInterval);\n }, [sessionManager, currentUser, contextValue, USER_DATA_CACHE_TTL]);\n\n return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextValue {\n const context = useContext(AuthContext);\n if (!context) {\n throw new Error('useAuth must be used within an AuthProvider');\n }\n return context;\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n ApiResponse,\n FeatureFlagItem,\n FeatureFlagValueResponse,\n FeatureFlag,\n CreateFeatureFlagRequest,\n PaginationParams,\n} from '../types/api';\n\nexport class FeatureFlagApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createFeatureFlag(request: CreateFeatureFlagRequest): Promise<FeatureFlag> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<FeatureFlag>>(\n '/feature-flags/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getFeatureFlags(\n params?: PaginationParams\n ): Promise<{ featureFlags: FeatureFlag[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/feature-flags/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<FeatureFlag[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n featureFlags: response.data,\n meta: response.meta,\n };\n }\n\n async getFeatureFlagById(id: string): Promise<FeatureFlag> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<FeatureFlag>>(`/feature-flags/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updateFeatureFlag(\n id: string,\n request: Partial<CreateFeatureFlagRequest>\n ): Promise<FeatureFlag> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<FeatureFlag>>(\n `/feature-flags/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async deleteFeatureFlag(id: string): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/feature-flags/${id}`, {\n headers: authHeaders,\n });\n }\n\n // Public endpoint - no auth required\n async getTenantFeatureFlags(tenantId: string, appId: string): Promise<FeatureFlagItem[]> {\n if (!tenantId || !appId) {\n throw new Error('Tenant ID and App ID are required');\n }\n\n const queryParams = new URLSearchParams();\n queryParams.append('tenantId', tenantId);\n queryParams.append('appId', appId);\n\n const url = `/tenant-feature-flags${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<FeatureFlagItem[]>>(url, {\n headers: { 'X-Tenant-ID': tenantId },\n });\n\n return response.data;\n }\n\n // Public endpoint - no auth required\n async getTenantFeatureFlag(\n flagKey: string,\n tenantId: string,\n appId: string\n ): Promise<FeatureFlagValueResponse> {\n if (!flagKey || !tenantId || !appId) {\n throw new Error('Flag Key, Tenant ID and App ID are required');\n }\n\n const queryParams = new URLSearchParams();\n queryParams.append('tenantId', tenantId);\n queryParams.append('appId', appId);\n\n const url = `/tenant-feature-flags/${flagKey}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<FeatureFlagValueResponse>>(url, {\n headers: { 'X-Tenant-ID': tenantId },\n });\n\n return response.data;\n }\n}\n","import { createContext, useContext, ReactNode, useMemo, useState, useEffect } from 'react';\nimport { FeatureFlagApiService } from '../services/FeatureFlagApiService';\nimport { HttpService } from '../services/HttpService';\nimport { useApp } from './AppProvider';\nimport { useTenantInfo } from './TenantProvider';\nimport type { FeatureFlagItem } from '../types/api';\n\nexport interface FeatureFlagConfig {\n refreshInterval?: number; // in milliseconds, default 5 minutes\n onError?: (error: Error) => void;\n}\n\nexport interface FeatureFlagContextValue {\n featureFlags: FeatureFlagItem[];\n loading: boolean;\n error: string | null;\n isEnabled: (flagName: string) => boolean;\n getFlag: (flagName: string) => FeatureFlagItem | undefined;\n refresh: () => Promise<void>;\n}\n\nconst FeatureFlagContext = createContext<FeatureFlagContextValue | null>(null);\n\ninterface FeatureFlagProviderProps {\n config?: FeatureFlagConfig;\n children: ReactNode;\n}\n\nexport function FeatureFlagProvider({ config = {}, children }: FeatureFlagProviderProps) {\n const { baseUrl, appId } = useApp();\n const { tenant } = useTenantInfo();\n const [featureFlags, setFeatureFlags] = useState<FeatureFlagItem[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const featureFlagService = useMemo(() => {\n const httpService = new HttpService(baseUrl);\n return new FeatureFlagApiService(httpService);\n }, [baseUrl]);\n\n const fetchFeatureFlags = async () => {\n if (!tenant?.id) {\n setFeatureFlags([]);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await featureFlagService.getTenantFeatureFlags(tenant.id, appId);\n setFeatureFlags(response);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch feature flags';\n setError(errorMessage);\n if (config.onError) {\n config.onError(err instanceof Error ? err : new Error(errorMessage));\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Initial fetch and setup refresh interval\n useEffect(() => {\n fetchFeatureFlags();\n\n const refreshInterval = config.refreshInterval || 5 * 60 * 1000; // 5 minutes default\n const interval = setInterval(fetchFeatureFlags, refreshInterval);\n\n return () => clearInterval(interval);\n }, [tenant?.id, config.refreshInterval]);\n\n const contextValue = useMemo(() => {\n const isEnabled = (flagKey: string): boolean => {\n const flag = featureFlags.find(f => f.key === flagKey);\n return flag?.value === true;\n };\n\n const getFlag = (flagKey: string): FeatureFlagItem | undefined => {\n return featureFlags.find(f => f.key === flagKey);\n };\n\n const getFlagState = (flagKey: string): 'enabled' | 'disabled' | 'not_found' => {\n const flag = featureFlags.find(f => f.key === flagKey);\n if (!flag) return 'not_found';\n return flag.value ? 'enabled' : 'disabled';\n };\n\n const refresh = async () => {\n await fetchFeatureFlags();\n };\n\n return {\n featureFlags,\n loading,\n error,\n isEnabled,\n getFlag,\n getFlagState,\n refresh,\n };\n }, [featureFlags, loading, error]);\n\n return <FeatureFlagContext.Provider value={contextValue}>{children}</FeatureFlagContext.Provider>;\n}\n\nexport function useFeatureFlags(): FeatureFlagContextValue {\n const context = useContext(FeatureFlagContext);\n if (!context) {\n throw new Error('useFeatureFlags must be used within a FeatureFlagProvider');\n }\n return context;\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Subscription,\n CreateSubscriptionRequest,\n ApiResponse,\n TenantSubscriptionFeatures,\n} from '../types/api';\n\nexport class SubscriptionApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createSubscription(request: CreateSubscriptionRequest): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Subscription>>(\n '/subscriptions/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getSubscriptionById(id: string): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Subscription>>(\n `/subscriptions/subscriptions/${id}`,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async updateSubscription(\n id: string,\n request: Partial<CreateSubscriptionRequest>\n ): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Subscription>>(\n `/subscriptions/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async changeSubscriptionPlan(subscriptionId: string, planId: string): Promise<Subscription> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Subscription>>(\n `/subscriptions/${subscriptionId}/plan`,\n { planId },\n { headers: authHeaders }\n );\n return response.data;\n }\n\n // Public endpoint - no auth required\n async getTenantSubscriptionFeatures(tenantId: string): Promise<TenantSubscriptionFeatures> {\n const response = await this.httpService.get<ApiResponse<TenantSubscriptionFeatures>>(\n `/subscriptions/tenants/${tenantId}/subscription-features`\n );\n return response.data;\n }\n\n async processPayment(subscriptionId: string, paymentData: any): Promise<any> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<any>>(\n `/subscriptions/${subscriptionId}/process-payment`,\n paymentData,\n { headers: authHeaders }\n );\n return response.data;\n }\n}\n","import { createContext, useContext, ReactNode, useMemo, useState, useEffect } from 'react';\nimport { SubscriptionApiService } from '../services/SubscriptionApiService';\nimport { HttpService } from '../services/HttpService';\nimport { useApp } from './AppProvider';\nimport { useTenantInfo } from './TenantProvider';\nimport type { TenantSubscriptionFeatures, PlanFeature } from '../types/api';\n\nexport interface SubscriptionConfig {\n refreshInterval?: number; // in milliseconds, default 10 minutes\n onError?: (error: Error) => void;\n}\n\nexport interface SubscriptionContextValue {\n subscription: TenantSubscriptionFeatures | null;\n features: PlanFeature[];\n loading: boolean;\n error: string | null;\n isFeatureEnabled: (featureKey: string) => boolean;\n getFeature: (featureKey: string) => PlanFeature | undefined;\n getFeatureValue: <T = any>(featureKey: string, defaultValue?: T) => T;\n hasAllowedPlan: (allowedPlans: string[]) => boolean;\n refresh: () => Promise<void>;\n}\n\nexport interface SubscriptionProviderProps {\n config?: SubscriptionConfig;\n children: ReactNode;\n}\n\nconst SubscriptionContext = createContext<SubscriptionContextValue | undefined>(undefined);\n\nexport function SubscriptionProvider({ config = {}, children }: SubscriptionProviderProps) {\n const { baseUrl } = useApp();\n const { tenant } = useTenantInfo();\n const [subscription, setSubscription] = useState<TenantSubscriptionFeatures | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Create subscription service\n const subscriptionService = useMemo(() => {\n const httpService = new HttpService(baseUrl);\n return new SubscriptionApiService(httpService);\n }, [baseUrl]);\n\n const fetchSubscription = async () => {\n if (!tenant?.id) {\n setSubscription(null);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await subscriptionService.getTenantSubscriptionFeatures(tenant.id);\n setSubscription(response);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch subscription';\n setError(errorMessage);\n if (config.onError) {\n config.onError(err instanceof Error ? err : new Error(errorMessage));\n }\n } finally {\n setLoading(false);\n }\n };\n\n // Fetch subscription on mount and when tenant changes\n useEffect(() => {\n fetchSubscription();\n\n // Set up refresh interval if configured\n if (!config.refreshInterval) return;\n\n const refreshInterval = config.refreshInterval || 10 * 60 * 1000; // 10 minutes default\n const interval = setInterval(fetchSubscription, refreshInterval);\n\n return () => clearInterval(interval);\n }, [tenant?.id, config.refreshInterval]);\n\n const contextValue = useMemo(() => {\n const features = subscription?.features || [];\n\n const isFeatureEnabled = (featureKey: string): boolean => {\n const feature = features.find(f => f.key === featureKey);\n if (!feature) return false;\n\n // Handle different feature types\n if (feature.type === 'BOOLEAN' || feature.type === 'boolean') {\n return feature.value === true;\n }\n\n // For non-boolean features, consider them enabled if they have a truthy value\n return Boolean(feature.value);\n };\n\n const getFeature = (featureKey: string): PlanFeature | undefined => {\n return features.find(f => f.key === featureKey);\n };\n\n const getFeatureValue = <T = any,>(featureKey: string, defaultValue?: T): T => {\n const feature = features.find(f => f.key === featureKey);\n return feature ? feature.value : (defaultValue as T);\n };\n\n const hasAllowedPlan = (allowedPlans: string[]): boolean => {\n if (!subscription || !subscription.isActive) return false;\n\n // Check if current plan is in the allowed plans array\n return allowedPlans.includes(subscription.planId);\n };\n\n const refresh = async () => {\n await fetchSubscription();\n };\n\n return {\n subscription,\n features,\n loading,\n error,\n isFeatureEnabled,\n getFeature,\n getFeatureValue,\n hasAllowedPlan,\n refresh,\n };\n }, [subscription, loading, error]);\n\n return (\n <SubscriptionContext.Provider value={contextValue}>{children}</SubscriptionContext.Provider>\n );\n}\n\nexport function useSubscription(): SubscriptionContextValue {\n const context = useContext(SubscriptionContext);\n if (context === undefined) {\n throw new Error('useSubscription must be used within a SubscriptionProvider');\n }\n return context;\n}\n","// Common API Response Types\nexport interface ApiResponse<T> {\n success: boolean;\n message?: string;\n data: T;\n meta?: PaginationMeta;\n}\n\nexport interface ApiError {\n success: false;\n error: {\n code: string;\n };\n message: string;\n type?: 'AUTH' | 'VALIDATION' | 'BUSINESS' | 'SYSTEM';\n}\n\nexport interface PaginationMeta {\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n hasNext: boolean;\n hasPrev: boolean;\n}\n\n// User Types\nexport enum UserType {\n SUPERUSER = 'SUPERUSER',\n TENANT_ADMIN = 'TENANT_ADMIN',\n USER = 'USER',\n}\n\nexport interface User {\n id: string;\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n isActive: boolean;\n userType: UserType;\n tenantId: string;\n roleId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateUserRequest {\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n password: string;\n tenantId: string;\n userType?: string;\n roleId?: string;\n}\n\n// Auth Types\nexport interface LoginRequest {\n username: string; // Can be email or phoneNumber\n password: string;\n appId?: string;\n tenantId?: string;\n}\n\nexport interface LoginResponse {\n user: User;\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\nexport interface SignupRequest {\n email?: string;\n phoneNumber?: string;\n name: string;\n lastName?: string;\n password: string;\n tenantId?: string;\n appId?: string;\n}\n\nexport interface ChangePasswordRequest {\n currentPassword: string;\n newPassword: string;\n}\n\nexport interface RefreshTokenRequest {\n refreshToken: string;\n}\n\nexport interface RefreshTokenResponse {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\n// Magic Link Types\nexport interface MagicLinkRequest {\n email: string;\n tenantId: string;\n frontendUrl: string;\n name?: string; // Required for signup, optional for login\n lastName?: string;\n appId?: string;\n}\n\nexport interface MagicLinkResponse {\n message: string;\n emailSent: boolean;\n}\n\nexport interface VerifyMagicLinkRequest {\n token: string;\n email: string;\n appId: string;\n tenantId?: string;\n}\n\nexport interface VerifyMagicLinkResponse {\n user: User;\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n isNewUser: boolean; // Indicates if user was created during this process\n}\n\n// Role Types\nexport interface Role {\n id: string;\n name: string;\n description: string | null;\n appId: string;\n permissions: string[]; // API returns permissions as strings in 'resource.action' format\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateRoleRequest {\n name: string;\n description?: string;\n appId: string;\n permissionIds: string[];\n}\n\nexport interface AssignRoleRequest {\n userId: string;\n}\n\n// Permission Types\nexport interface Permission {\n id: string;\n name: string;\n description: string | null;\n resource: string;\n action: string;\n appId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreatePermissionRequest {\n name: string;\n description?: string;\n resource: string;\n action: string;\n appId?: string;\n}\n\n// App Types\nexport interface App {\n id: string;\n name: string;\n description: string | null;\n securityLevel: 'ADMIN' | 'USER';\n isActive: boolean;\n autoApproveTenants: boolean;\n defaultSubscriptionPlanId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface JSONSchema {\n $schema?: string;\n $id?: string;\n title?: string;\n description?: string;\n type?: 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';\n properties?: { [key: string]: JSONSchema };\n items?: JSONSchema;\n required?: string[];\n enum?: unknown[];\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n format?: string;\n default?: unknown;\n placeholder?: string;\n additionalProperties?: boolean | JSONSchema;\n}\n\nexport interface PublicAppInfo {\n id: string;\n name: string;\n description: string | null;\n settingsSchema: JSONSchema | null;\n}\n\nexport interface CreateAppRequest {\n name: string;\n description?: string;\n securityLevel?: 'ADMIN' | 'USER';\n}\n\n// Tenant Types\nexport interface Tenant {\n id: string;\n name: string;\n subdomain: string;\n isActive: boolean;\n appId: string;\n settings: Record<string, any>;\n createdAt: string;\n updatedAt: string;\n isPending?: boolean;\n}\n\nexport interface CreateTenantRequest {\n name: string;\n domain?: string;\n appId: string;\n settings?: Record<string, any>;\n}\n\nexport interface PublicTenantInfo {\n id: string;\n name: string;\n subdomain: string;\n domain?: string | null; // Legacy field\n appId: string;\n}\n\nexport interface TenantSettings {\n [key: string]: any;\n}\n\nexport interface UpdateTenantSettingsRequest {\n settings: TenantSettings;\n}\n\n// Subscription Types\nexport interface Subscription {\n id: string;\n tenantId: string;\n planId: string;\n status: 'ACTIVE' | 'INACTIVE' | 'PENDING' | 'CANCELLED';\n startDate: string;\n endDate: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateSubscriptionRequest {\n tenantId: string;\n planId: string;\n startDate?: string;\n endDate?: string;\n}\n\n// Subscription Plan Types\nexport interface SubscriptionPlan {\n id: string;\n name: string;\n description: string | null;\n price: number;\n currency: string;\n billingCycle: 'MONTHLY' | 'YEARLY';\n appId: string;\n features: SubscriptionFeature[];\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SubscriptionFeature {\n id: string;\n name: string;\n description: string | null;\n featureType: 'BOOLEAN' | 'NUMERIC' | 'TEXT';\n value: any;\n planId: string;\n}\n\nexport interface CreateSubscriptionPlanRequest {\n name: string;\n description?: string;\n price: number;\n currency: string;\n billingCycle: 'MONTHLY' | 'YEARLY';\n appId: string;\n features: CreateSubscriptionFeatureRequest[];\n}\n\nexport interface CreateSubscriptionFeatureRequest {\n name: string;\n description?: string;\n featureType: 'BOOLEAN' | 'NUMERIC' | 'TEXT';\n value: any;\n}\n\n// Feature Flag Types\nexport interface FeatureFlag {\n id: string;\n name: string;\n description: string | null;\n isActive: boolean;\n appId: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateFeatureFlagRequest {\n name: string;\n description?: string;\n appId: string;\n}\n\n// Feature Flag API Response Types\nexport interface FeatureFlagItem {\n featureFlagId: string;\n key: string;\n name: string;\n value: boolean;\n isOverridden: boolean;\n}\n\nexport interface FeatureFlagValueResponse {\n key: string;\n value: boolean;\n}\n\n// Subscription Feature Types\nexport interface PlanFeature {\n key: string;\n name: string;\n type: 'BOOLEAN' | 'NUMBER' | 'STRING' | 'boolean' | 'number' | 'string';\n value: any;\n description?: string;\n}\n\nexport interface TenantSubscriptionFeatures {\n tenantId: string;\n planId: string;\n planName: string;\n subscriptionStatus: string;\n features: PlanFeature[];\n isActive: boolean;\n}\n\n// Common Query Parameters\nexport interface PaginationParams {\n page?: number;\n limit?: number;\n sortBy?: string;\n sortOrder?: 'ASC' | 'DESC';\n}\n","import { ReactNode } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { UserType, Permission } from '../types/api';\n\nexport interface ProtectedProps {\n children: ReactNode;\n fallback?: ReactNode;\n minUserType?: UserType;\n requiredPermissions?: (string | Permission)[];\n requireAllPermissions?: boolean; // If true, user must have ALL permissions. If false, user needs ANY permission\n}\n\nconst DefaultFallback = () => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '20px',\n backgroundColor: '#f8f9fa',\n border: '1px solid #dee2e6',\n borderRadius: '6px',\n textAlign: 'center',\n margin: '20px 0',\n }}\n >\n <div style={{ fontSize: '2rem', marginBottom: '10px' }}>🔒</div>\n <h3 style={{ color: '#495057', marginBottom: '10px' }}>Access Required</h3>\n <p style={{ color: '#6c757d', fontSize: '14px', marginBottom: '15px' }}>\n You need to be signed in to view this content.\n </p>\n <button\n style={{\n padding: '8px 16px',\n backgroundColor: '#007bff',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n fontSize: '14px',\n }}\n onClick={() => (window.location.href = '/login')}\n >\n Sign In\n </button>\n </div>\n);\n\nconst InsufficientPermissionsFallback = ({\n userType,\n minUserType,\n missingPermissions,\n}: {\n userType?: UserType;\n minUserType?: UserType;\n missingPermissions?: string[];\n}) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '20px',\n backgroundColor: '#fff3cd',\n border: '1px solid #ffeaa7',\n borderRadius: '6px',\n textAlign: 'center',\n margin: '20px 0',\n }}\n >\n <div style={{ fontSize: '2rem', marginBottom: '10px' }}>⚠️</div>\n <h3 style={{ color: '#856404', marginBottom: '10px' }}>Insufficient Permissions</h3>\n {minUserType && userType ? (\n <>\n <p style={{ color: '#856404', fontSize: '14px', marginBottom: '10px' }}>\n This content requires <strong>{minUserType}</strong> access level or higher.\n </p>\n <p style={{ color: '#6c757d', fontSize: '12px' }}>\n Your current access level: <strong>{userType}</strong>\n </p>\n </>\n ) : (\n <>\n <p style={{ color: '#856404', fontSize: '14px', marginBottom: '10px' }}>\n You don't have the required permissions to view this content.\n </p>\n {missingPermissions && missingPermissions.length > 0 && (\n <p style={{ color: '#6c757d', fontSize: '12px' }}>\n Required permissions: <strong>{missingPermissions.join(', ')}</strong>\n </p>\n )}\n </>\n )}\n </div>\n);\n\n// Helper function to check if user type meets minimum requirement\nconst hasMinimumUserType = (userType: UserType, minUserType: UserType): boolean => {\n const hierarchy = {\n [UserType.USER]: 1,\n [UserType.TENANT_ADMIN]: 2,\n [UserType.SUPERUSER]: 3,\n };\n\n return hierarchy[userType] >= hierarchy[minUserType];\n};\n\nexport function Protected({\n children,\n fallback,\n minUserType,\n requiredPermissions,\n requireAllPermissions = false,\n}: ProtectedProps) {\n const { hasValidSession, sessionManager, hasPermission, hasAnyPermission, hasAllPermissions } =\n useAuth();\n\n // Check if user has a valid session\n if (!hasValidSession()) {\n return <>{fallback || <DefaultFallback />}</>;\n }\n\n const user = sessionManager.getUser();\n\n if (!user) {\n // User session exists but no user data - show fallback\n return <>{fallback || <DefaultFallback />}</>;\n }\n\n // Check user type permissions if specified\n if (minUserType && !hasMinimumUserType(user.userType, minUserType)) {\n return <InsufficientPermissionsFallback userType={user.userType} minUserType={minUserType} />;\n }\n\n // Check specific permissions if specified\n if (requiredPermissions && requiredPermissions.length > 0) {\n const hasRequiredPermissions = requireAllPermissions\n ? hasAllPermissions(requiredPermissions)\n : hasAnyPermission(requiredPermissions);\n\n if (!hasRequiredPermissions) {\n // Get missing permissions for better error message\n const missingPermissions = requiredPermissions\n .filter(permission => !hasPermission(permission))\n .map(permission => (typeof permission === 'string' ? permission : permission.name));\n\n return <InsufficientPermissionsFallback missingPermissions={missingPermissions} />;\n }\n }\n\n // User is authenticated and has sufficient permissions\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\nimport { useAuth } from '../providers/AuthProvider';\nimport { UserType, Permission } from '../types/api';\n\nexport interface ProtectedRouteProps {\n children: ReactNode;\n redirectTo?: string;\n minUserType?: UserType;\n requiredPermissions?: (string | Permission)[];\n requireAllPermissions?: boolean; // If true, user must have ALL permissions. If false, user needs ANY permission\n fallback?: ReactNode;\n}\n\nconst DefaultFallback = ({ redirectPath }: { redirectPath: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>🔒</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Access Required</h2>\n <p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>\n You need to be signed in to access this page.\n </p>\n <p style={{ fontSize: '0.875rem', color: '#9ca3af' }}>Redirecting to {redirectPath}...</p>\n </div>\n </div>\n);\n\nconst InsufficientPermissionsFallback = ({\n userType,\n minUserType,\n missingPermissions,\n}: {\n userType?: UserType;\n minUserType?: UserType;\n missingPermissions?: string[];\n}) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>⚠️</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Insufficient Permissions</h2>\n {minUserType && userType ? (\n <>\n <p style={{ color: '#6b7280', marginBottom: '1rem' }}>\n This page requires <strong>{minUserType}</strong> access level or higher.\n </p>\n <p style={{ color: '#9ca3af', fontSize: '0.875rem' }}>\n Your current access level: <strong>{userType}</strong>\n </p>\n </>\n ) : (\n <>\n <p style={{ color: '#6b7280', marginBottom: '1rem' }}>\n You don't have the required permissions to access this page.\n </p>\n {missingPermissions && missingPermissions.length > 0 && (\n <p style={{ color: '#9ca3af', fontSize: '0.875rem' }}>\n Required permissions: <strong>{missingPermissions.join(', ')}</strong>\n </p>\n )}\n </>\n )}\n </div>\n </div>\n);\n\n// Helper function to check if user type meets minimum requirement\nconst hasMinimumUserType = (userType: UserType, minUserType: UserType): boolean => {\n const hierarchy = {\n [UserType.USER]: 1,\n [UserType.TENANT_ADMIN]: 2,\n [UserType.SUPERUSER]: 3,\n };\n\n return hierarchy[userType] >= hierarchy[minUserType];\n};\n\nexport function ProtectedRoute({\n children,\n redirectTo = '/login',\n minUserType,\n requiredPermissions,\n requireAllPermissions = false,\n fallback,\n}: ProtectedRouteProps) {\n const { hasValidSession, sessionManager, hasPermission, hasAnyPermission, hasAllPermissions } =\n useAuth();\n const location = useLocation();\n\n // Check if user has a valid session\n if (!hasValidSession()) {\n if (fallback) {\n return <>{fallback}</>;\n }\n\n return (\n <>\n <DefaultFallback redirectPath={redirectTo} />\n <Navigate to={redirectTo} state={{ from: location.pathname }} replace />\n </>\n );\n }\n\n const user = sessionManager.getUser();\n\n if (!user) {\n // User session exists but no user data - redirect to login\n return <Navigate to={redirectTo} state={{ from: location.pathname }} replace />;\n }\n\n // Check user type permissions if specified\n if (minUserType && !hasMinimumUserType(user.userType, minUserType)) {\n return <InsufficientPermissionsFallback userType={user.userType} minUserType={minUserType} />;\n }\n\n // Check specific permissions if specified\n if (requiredPermissions && requiredPermissions.length > 0) {\n const hasRequiredPermissions = requireAllPermissions\n ? hasAllPermissions(requiredPermissions)\n : hasAnyPermission(requiredPermissions);\n\n if (!hasRequiredPermissions) {\n // Get missing permissions for better error message\n const missingPermissions = requiredPermissions\n .filter(permission => !hasPermission(permission))\n .map(permission => (typeof permission === 'string' ? permission : permission.name));\n\n return <InsufficientPermissionsFallback missingPermissions={missingPermissions} />;\n }\n }\n\n // User is authenticated and has sufficient permissions\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface TenantRouteProps {\n children: ReactNode;\n redirectTo?: string;\n fallback?: ReactNode;\n}\n\nconst DefaultTenantRequiredFallback = ({ redirectPath }: { redirectPath: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>🏢</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Tenant Required</h2>\n <p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>\n This page requires a tenant context to access.\n </p>\n <p style={{ fontSize: '0.875rem', color: '#9ca3af' }}>Redirecting to {redirectPath}...</p>\n </div>\n </div>\n);\n\nexport function TenantRoute({ children, redirectTo = '/', fallback }: TenantRouteProps) {\n const { tenant, isLoading, error } = useTenantInfo();\n const location = useLocation();\n\n // Show loading state while tenant is being detected/loaded\n if (isLoading) {\n return null; // Let TenantProvider handle loading fallback\n }\n\n // If there's an error loading tenant, let TenantProvider handle it\n if (error) {\n return null; // Let TenantProvider handle error fallback\n }\n\n // Check if tenant is required but not present\n if (!tenant) {\n if (fallback) {\n return <>{fallback}</>;\n }\n\n return (\n <>\n <DefaultTenantRequiredFallback redirectPath={redirectTo} />\n <Navigate to={redirectTo} state={{ from: location.pathname }} replace />\n </>\n );\n }\n\n // Tenant is present, render children\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { Navigate, useLocation } from 'react-router-dom';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface LandingRouteProps {\n children: ReactNode;\n redirectTo?: string;\n fallback?: ReactNode;\n}\n\nconst DefaultTenantDetectedFallback = ({ redirectPath }: { redirectPath: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100vh',\n padding: '2rem',\n backgroundColor: '#f9fafb',\n textAlign: 'center',\n }}\n >\n <div\n style={{\n backgroundColor: '#ffffff',\n padding: '2rem',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n maxWidth: '400px',\n }}\n >\n <div style={{ fontSize: '3rem', marginBottom: '1rem' }}>🚀</div>\n <h2 style={{ color: '#374151', marginBottom: '1rem' }}>Tenant Detected</h2>\n <p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>\n You are accessing a tenant-specific context. Redirecting to the appropriate page.\n </p>\n <p style={{ fontSize: '0.875rem', color: '#9ca3af' }}>Redirecting to {redirectPath}...</p>\n </div>\n </div>\n);\n\nexport function LandingRoute({ children, redirectTo = '/dashboard', fallback }: LandingRouteProps) {\n const { tenant, isLoading, error } = useTenantInfo();\n const location = useLocation();\n\n // Show loading state while tenant is being detected/loaded\n if (isLoading) {\n return null; // Let TenantProvider handle loading fallback\n }\n\n // If there's an error loading tenant, let TenantProvider handle it\n if (error) {\n return null; // Let TenantProvider handle error fallback\n }\n\n // Check if tenant is present (should redirect to tenant-specific route)\n if (tenant) {\n if (fallback) {\n return <>{fallback}</>;\n }\n\n return (\n <>\n <DefaultTenantDetectedFallback redirectPath={redirectTo} />\n <Navigate to={redirectTo} state={{ from: location.pathname }} replace />\n </>\n );\n }\n\n // No tenant present, render public landing page\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { useSubscription } from '../providers/SubscriptionProvider';\n\nexport interface SubscriptionGuardProps {\n children: ReactNode;\n fallback?: ReactNode;\n allowedPlans?: string[];\n requiredFeature?: string;\n}\n\nconst DefaultFallback = () => (\n <div\n style={{\n padding: '2rem',\n textAlign: 'center',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: '8px',\n color: '#dc2626',\n }}\n >\n <h3 style={{ margin: '0 0 1rem 0' }}>🔒 Subscription Required</h3>\n <p style={{ margin: 0 }}>\n This feature requires a higher subscription plan. Please upgrade your plan to access this\n content.\n </p>\n </div>\n);\n\nexport function SubscriptionGuard({\n children,\n fallback = <DefaultFallback />,\n allowedPlans,\n requiredFeature,\n}: SubscriptionGuardProps) {\n const { subscription, hasAllowedPlan, isFeatureEnabled, loading } = useSubscription();\n\n // Show loading state\n if (loading) {\n return (\n <div\n style={{\n padding: '2rem',\n textAlign: 'center',\n color: '#6b7280',\n }}\n >\n Loading subscription...\n </div>\n );\n }\n\n // No subscription data available\n if (!subscription) {\n return <>{fallback}</>;\n }\n\n // Check if subscription is active\n if (!subscription.isActive) {\n return <>{fallback}</>;\n }\n\n // Check allowed plans requirement\n if (allowedPlans && allowedPlans.length > 0 && !hasAllowedPlan(allowedPlans)) {\n return <>{fallback}</>;\n }\n\n // Check required feature\n if (requiredFeature && !isFeatureEnabled(requiredFeature)) {\n return <>{fallback}</>;\n }\n\n // All checks passed, render children\n return <>{children}</>;\n}\n","import { ReactNode } from 'react';\nimport { useFeatureFlags } from '../providers/FeatureFlagProvider';\n\ninterface FeatureFlagProps {\n name: string;\n children: ReactNode;\n fallback?: ReactNode;\n}\n\nconst DefaultFallback = ({ flagName }: { flagName: string }) => (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '15px',\n backgroundColor: '#f8f9fa',\n border: '1px solid #dee2e6',\n borderRadius: '6px',\n textAlign: 'center',\n fontFamily: 'system-ui, sans-serif',\n color: '#6c757d',\n }}\n >\n <div style={{ fontSize: '24px', marginBottom: '8px' }}>🚧</div>\n <div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '4px' }}>\n Feature Not Available\n </div>\n <div style={{ fontSize: '12px', opacity: 0.7 }}>Feature flag \"{flagName}\" is disabled</div>\n </div>\n);\n\nexport function FeatureFlag({ name, children, fallback }: FeatureFlagProps) {\n const { isEnabled, loading } = useFeatureFlags();\n\n // Show loading state while fetching feature flags\n if (loading) {\n return (\n <div\n style={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n padding: '10px',\n color: '#6c757d',\n fontSize: '14px',\n }}\n >\n Loading feature flags...\n </div>\n );\n }\n\n console.log(name, isEnabled(name));\n // Show children if feature flag is enabled\n if (isEnabled(name)) {\n return <>{children}</>;\n }\n\n // Show fallback if provided, otherwise show default fallback\n return <>{fallback || <DefaultFallback flagName={name} />}</>;\n}\n","import React, { useState } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface LoginFormCopy {\n title?: string;\n usernameLabel?: string;\n usernamePlaceholder?: string;\n passwordLabel?: string;\n passwordPlaceholder?: string;\n submitButton?: string;\n forgotPasswordLink?: string;\n signupLink?: string;\n signupText?: string;\n magicLinkText?: string;\n magicLinkLink?: string;\n errorMessage?: string;\n loadingText?: string;\n}\n\nexport interface LoginFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n inputContainer?: React.CSSProperties;\n passwordToggle?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n divider?: React.CSSProperties;\n}\n\nexport interface LoginFormIcons {\n showPassword?: React.ReactNode;\n hidePassword?: React.ReactNode;\n}\n\nexport interface LoginFormProps {\n copy?: LoginFormCopy;\n styles?: LoginFormStyles;\n icons?: LoginFormIcons;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onForgotPassword?: () => void;\n onSignupClick?: () => void;\n onMagicLinkClick?: () => void;\n showForgotPassword?: boolean;\n showSignupLink?: boolean;\n showMagicLinkOption?: boolean;\n className?: string;\n}\n\n// Default SVG icons for password toggle\nconst EyeIcon = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ flexShrink: 0 }}\n >\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n);\n\nconst EyeOffIcon = () => (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ flexShrink: 0 }}\n >\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\" />\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n </svg>\n);\n\nconst defaultIcons: Required<LoginFormIcons> = {\n showPassword: <EyeIcon />,\n hidePassword: <EyeOffIcon />,\n};\n\nconst defaultCopy: Required<LoginFormCopy> = {\n title: 'Sign In',\n usernameLabel: 'Email or Phone',\n usernamePlaceholder: 'Enter your email or phone number',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Enter your password',\n submitButton: 'Sign In',\n forgotPasswordLink: 'Forgot your password?',\n signupLink: 'Sign up here',\n signupText: \"Don't have an account?\",\n magicLinkText: 'Prefer passwordless?',\n magicLinkLink: 'Use Magic Link',\n errorMessage: 'Invalid credentials',\n loadingText: 'Signing in...',\n};\n\nconst defaultStyles: Required<LoginFormStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#333333',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n width: '100%',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n inputContainer: {\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n },\n passwordToggle: {\n position: 'absolute',\n right: '0.75rem',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: '0.25rem',\n color: '#6b7280',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '24px',\n height: '24px',\n borderRadius: '4px',\n transition: 'background-color 0.15s ease-in-out',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n divider: {\n margin: '0.5rem 0',\n color: '#6b7280',\n fontSize: '0.875rem',\n },\n};\n\nexport function LoginForm({\n copy = {},\n styles = {},\n icons = {},\n onSuccess,\n onError,\n onForgotPassword,\n onSignupClick,\n onMagicLinkClick,\n showForgotPassword = true,\n showSignupLink = true,\n showMagicLinkOption = true,\n className,\n}: LoginFormProps) {\n const [username, setUsername] = useState('');\n const [password, setPassword] = useState('');\n const [showPassword, setShowPassword] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{ username?: boolean; password?: boolean }>({});\n\n const { login } = useAuth();\n const { tenant } = useTenantInfo();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n const mergedIcons = { ...defaultIcons, ...icons };\n\n const validateForm = () => {\n const errors: { username?: boolean; password?: boolean } = {};\n\n if (!username.trim()) errors.username = true;\n if (!password.trim()) errors.password = true;\n\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) return;\n if (!tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n\n try {\n const result = await login({\n username,\n password,\n // tenantId inferred from context automatically\n });\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: 'username' | 'password') => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading ? mergedStyles.buttonLoading : {}),\n ...(!username || !password || loading ? mergedStyles.buttonDisabled : {}),\n });\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n\n <form onSubmit={handleSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.usernameLabel}</label>\n <input\n id=\"username\"\n name=\"username\"\n type=\"text\"\n value={username}\n onChange={e => {\n setUsername(e.target.value);\n if (fieldErrors.username) {\n setFieldErrors(prev => ({ ...prev, username: false }));\n }\n }}\n placeholder={mergedCopy.usernamePlaceholder}\n style={getInputStyle('username')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.passwordLabel}</label>\n <div style={mergedStyles.inputContainer}>\n <input\n id=\"password\"\n name=\"password\"\n type={showPassword ? 'text' : 'password'}\n value={password}\n onChange={e => {\n setPassword(e.target.value);\n if (fieldErrors.password) {\n setFieldErrors(prev => ({ ...prev, password: false }));\n }\n }}\n placeholder={mergedCopy.passwordPlaceholder}\n style={{\n ...getInputStyle('password'),\n paddingRight: '2.5rem', // Make room for the icon\n }}\n disabled={loading}\n />\n <button\n type=\"button\"\n onClick={() => setShowPassword(!showPassword)}\n style={mergedStyles.passwordToggle}\n disabled={loading}\n aria-label={showPassword ? 'Hide password' : 'Show password'}\n >\n {showPassword ? mergedIcons.hidePassword : mergedIcons.showPassword}\n </button>\n </div>\n </div>\n\n <button type=\"submit\" disabled={!username || !password || loading} style={getButtonStyle()}>\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n </form>\n\n {(showForgotPassword || showSignupLink || showMagicLinkOption) && (\n <div style={mergedStyles.linkContainer}>\n {showMagicLinkOption && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.magicLinkText} </span>\n <a onClick={onMagicLinkClick} style={mergedStyles.link}>\n {mergedCopy.magicLinkLink}\n </a>\n </div>\n )}\n\n {showMagicLinkOption && (showForgotPassword || showSignupLink) && (\n <div style={mergedStyles.divider}>•</div>\n )}\n\n {showForgotPassword && (\n <a onClick={onForgotPassword} style={mergedStyles.link}>\n {mergedCopy.forgotPasswordLink}\n </a>\n )}\n\n {showForgotPassword && showSignupLink && <div style={mergedStyles.divider}>•</div>}\n\n {showSignupLink && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.signupText} </span>\n <a onClick={onSignupClick} style={mergedStyles.link}>\n {mergedCopy.signupLink}\n </a>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface SignupFormCopy {\n title?: string;\n nameLabel?: string;\n namePlaceholder?: string;\n lastNameLabel?: string;\n lastNamePlaceholder?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n phoneNumberLabel?: string;\n phoneNumberPlaceholder?: string;\n passwordLabel?: string;\n passwordPlaceholder?: string;\n confirmPasswordLabel?: string;\n confirmPasswordPlaceholder?: string;\n tenantNameLabel?: string;\n tenantNamePlaceholder?: string;\n submitButton?: string;\n loginLink?: string;\n loginText?: string;\n magicLinkText?: string;\n magicLinkLink?: string;\n errorMessage?: string;\n loadingText?: string;\n passwordMismatchError?: string;\n isAdminLabel?: string;\n isAdminDescription?: string;\n}\n\nexport interface SignupFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n checkbox?: React.CSSProperties;\n checkboxContainer?: React.CSSProperties;\n checkboxLabel?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n divider?: React.CSSProperties;\n}\n\nexport type SignupType = 'user' | 'tenant';\n\nexport interface SignupFormProps {\n copy?: SignupFormCopy;\n styles?: SignupFormStyles;\n signupType?: SignupType;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onLoginClick?: () => void;\n onMagicLinkClick?: () => void;\n showLoginLink?: boolean;\n showMagicLinkOption?: boolean;\n className?: string;\n}\n\nconst defaultCopy: Required<SignupFormCopy> = {\n title: 'Create Account',\n nameLabel: 'First Name',\n namePlaceholder: 'Enter your first name',\n lastNameLabel: 'Last Name',\n lastNamePlaceholder: 'Enter your last name',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n phoneNumberLabel: 'Phone Number',\n phoneNumberPlaceholder: 'Enter your phone number',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Enter your password',\n confirmPasswordLabel: 'Confirm Password',\n confirmPasswordPlaceholder: 'Confirm your password',\n tenantNameLabel: 'Organization Name',\n tenantNamePlaceholder: 'Enter your organization name',\n submitButton: 'Create Account',\n loginLink: 'Sign in here',\n loginText: 'Already have an account?',\n magicLinkText: 'Prefer passwordless?',\n magicLinkLink: 'Use Magic Link',\n errorMessage: 'Failed to create account',\n loadingText: 'Creating account...',\n passwordMismatchError: 'Passwords do not match',\n isAdminLabel: 'Create new organization',\n isAdminDescription: 'Check this if you want to create a new organization',\n};\n\nconst defaultStyles: Required<SignupFormStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#333333',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n checkbox: {\n marginRight: '0.5rem',\n },\n checkboxContainer: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: '0.5rem',\n padding: '0.5rem 0',\n },\n checkboxLabel: {\n fontSize: '0.875rem',\n color: '#374151',\n lineHeight: '1.4',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#10b981',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n divider: {\n margin: '0.5rem 0',\n color: '#6b7280',\n fontSize: '0.875rem',\n },\n};\n\nexport function SignupForm({\n copy = {},\n styles = {},\n signupType = 'user',\n onSuccess,\n onError,\n onLoginClick,\n onMagicLinkClick,\n showLoginLink = true,\n showMagicLinkOption = true,\n className,\n}: SignupFormProps) {\n const [name, setName] = useState('');\n const [lastName, setLastName] = useState('');\n const [email, setEmail] = useState('');\n const [phoneNumber, setPhoneNumber] = useState('');\n const [password, setPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [tenantName, setTenantName] = useState('');\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{\n name?: boolean;\n email?: boolean;\n phoneNumber?: boolean;\n password?: boolean;\n confirmPassword?: boolean;\n tenantName?: boolean;\n }>({});\n\n const { signup, signupTenantAdmin } = useAuth();\n const { tenant } = useTenantInfo();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n\n const validateForm = () => {\n const errors: {\n name?: boolean;\n email?: boolean;\n phoneNumber?: boolean;\n password?: boolean;\n confirmPassword?: boolean;\n tenantName?: boolean;\n } = {};\n\n if (!name.trim()) errors.name = true;\n if (!email.trim() && !phoneNumber.trim()) {\n errors.email = true;\n errors.phoneNumber = true;\n }\n if (!password.trim()) errors.password = true;\n if (!confirmPassword.trim()) errors.confirmPassword = true;\n if (signupType === 'tenant' && !tenantName.trim()) errors.tenantName = true;\n\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) return;\n\n if (password !== confirmPassword) {\n setError(mergedCopy.passwordMismatchError);\n setFieldErrors({ confirmPassword: true });\n return;\n }\n\n if (signupType === 'user' && !tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n\n try {\n let result;\n if (signupType === 'tenant') {\n result = await signupTenantAdmin({\n email: email || undefined,\n phoneNumber: phoneNumber || undefined,\n name,\n password,\n tenantName,\n lastName: lastName || undefined,\n });\n } else {\n result = await signup({\n email: email || undefined,\n phoneNumber: phoneNumber || undefined,\n name,\n password,\n tenantId: tenant!.id,\n lastName: lastName || undefined,\n });\n }\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: keyof typeof fieldErrors) => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading ? mergedStyles.buttonLoading : {}),\n ...(!name ||\n (!email && !phoneNumber) ||\n !password ||\n !confirmPassword ||\n loading ||\n (signupType === 'tenant' && !tenantName)\n ? mergedStyles.buttonDisabled\n : {}),\n });\n\n const isFormValid =\n name &&\n (email || phoneNumber) &&\n password &&\n confirmPassword &&\n (signupType === 'user' || tenantName);\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n\n <form onSubmit={handleSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.nameLabel}</label>\n <input\n id=\"name\"\n name=\"name\"\n type=\"text\"\n value={name}\n onChange={e => {\n setName(e.target.value);\n if (fieldErrors.name) {\n setFieldErrors(prev => ({ ...prev, name: false }));\n }\n }}\n placeholder={mergedCopy.namePlaceholder}\n style={getInputStyle('name')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.lastNameLabel}</label>\n <input\n id=\"lastName\"\n name=\"lastName\"\n type=\"text\"\n value={lastName}\n onChange={e => setLastName(e.target.value)}\n placeholder={mergedCopy.lastNamePlaceholder}\n style={mergedStyles.input}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.emailLabel}</label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={e => {\n setEmail(e.target.value);\n if (fieldErrors.email) {\n setFieldErrors(prev => ({ ...prev, email: false, phoneNumber: false }));\n }\n }}\n placeholder={mergedCopy.emailPlaceholder}\n style={getInputStyle('email')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.phoneNumberLabel}</label>\n <input\n id=\"phoneNumber\"\n name=\"phoneNumber\"\n type=\"tel\"\n value={phoneNumber}\n onChange={e => {\n setPhoneNumber(e.target.value);\n if (fieldErrors.phoneNumber) {\n setFieldErrors(prev => ({ ...prev, email: false, phoneNumber: false }));\n }\n }}\n placeholder={mergedCopy.phoneNumberPlaceholder}\n style={getInputStyle('phoneNumber')}\n disabled={loading}\n />\n </div>\n\n <div\n style={{\n fontSize: '0.875rem',\n color: '#6b7280',\n textAlign: 'center',\n margin: '0.5rem 0',\n }}\n >\n At least one contact method (email or phone) is required\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.passwordLabel}</label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n value={password}\n onChange={e => {\n setPassword(e.target.value);\n if (fieldErrors.password) {\n setFieldErrors(prev => ({ ...prev, password: false }));\n }\n }}\n placeholder={mergedCopy.passwordPlaceholder}\n style={getInputStyle('password')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.confirmPasswordLabel}</label>\n <input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n value={confirmPassword}\n onChange={e => {\n setConfirmPassword(e.target.value);\n if (fieldErrors.confirmPassword) {\n setFieldErrors(prev => ({ ...prev, confirmPassword: false }));\n }\n if (error === mergedCopy.passwordMismatchError) {\n setError('');\n }\n }}\n placeholder={mergedCopy.confirmPasswordPlaceholder}\n style={getInputStyle('confirmPassword')}\n disabled={loading}\n />\n </div>\n\n {signupType === 'tenant' && (\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.tenantNameLabel}</label>\n <input\n id=\"tenantName\"\n name=\"tenantName\"\n type=\"text\"\n value={tenantName}\n onChange={e => {\n setTenantName(e.target.value);\n if (fieldErrors.tenantName) {\n setFieldErrors(prev => ({ ...prev, tenantName: false }));\n }\n }}\n placeholder={mergedCopy.tenantNamePlaceholder}\n style={getInputStyle('tenantName')}\n disabled={loading}\n />\n </div>\n )}\n\n <button type=\"submit\" disabled={!isFormValid || loading} style={getButtonStyle()}>\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n </form>\n\n {(showLoginLink || showMagicLinkOption) && (\n <div style={mergedStyles.linkContainer}>\n {showMagicLinkOption && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.magicLinkText} </span>\n <a onClick={onMagicLinkClick} style={mergedStyles.link}>\n {mergedCopy.magicLinkLink}\n </a>\n </div>\n )}\n\n {showMagicLinkOption && showLoginLink && <div style={mergedStyles.divider}>•</div>}\n\n {showLoginLink && (\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.loginText} </span>\n <a onClick={onLoginClick} style={mergedStyles.link}>\n {mergedCopy.loginLink}\n </a>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface MagicLinkFormCopy {\n title?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n nameLabel?: string;\n namePlaceholder?: string;\n lastNameLabel?: string;\n lastNamePlaceholder?: string;\n submitButton?: string;\n loginLink?: string;\n signupLink?: string;\n loginText?: string;\n signupText?: string;\n successMessage?: string;\n errorMessage?: string;\n loadingText?: string;\n verifyingText?: string;\n description?: string;\n}\n\nexport interface MagicLinkFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n description?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n successText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n divider?: React.CSSProperties;\n}\n\nexport interface MagicLinkFormProps {\n copy?: MagicLinkFormCopy;\n styles?: MagicLinkFormStyles;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onLoginClick?: () => void;\n onSignupClick?: () => void;\n showTraditionalLinks?: boolean;\n className?: string;\n // Auto-verify magic link if token is provided (e.g., from URL params)\n verifyToken?: string;\n // Frontend URL for magic link callback (if not provided, will use window.location.origin)\n frontendUrl?: string;\n}\n\nconst defaultCopy: Required<MagicLinkFormCopy> = {\n title: 'Sign In with Magic Link',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n nameLabel: 'Name',\n namePlaceholder: 'Enter your name',\n lastNameLabel: 'Last Name',\n lastNamePlaceholder: 'Enter your last name',\n submitButton: 'Send Magic Link',\n loginLink: 'Sign in with password',\n signupLink: 'Sign up with password',\n loginText: 'Already have an account?',\n signupText: 'Prefer traditional signup?',\n successMessage: 'Magic link sent! Check your email and click the link to sign in.',\n errorMessage: 'Failed to send magic link. Please try again.',\n loadingText: 'Sending magic link...',\n verifyingText: 'Verifying magic link...',\n description:\n \"Enter your email to receive a magic link. If you don't have an account, we'll create one for you.\",\n};\n\nconst defaultStyles: Required<MagicLinkFormStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1rem',\n color: '#333333',\n },\n description: {\n fontSize: '0.875rem',\n color: '#6b7280',\n textAlign: 'center',\n marginBottom: '1.5rem',\n lineHeight: '1.5',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n width: '100%',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n successText: {\n color: '#10b981',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n padding: '0.75rem',\n backgroundColor: '#f0fdf4',\n borderRadius: '6px',\n border: '1px solid #bbf7d0',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n divider: {\n margin: '0.5rem 0',\n color: '#6b7280',\n fontSize: '0.875rem',\n },\n};\n\nexport function MagicLinkForm({\n copy = {},\n styles = {},\n onSuccess,\n onError,\n onLoginClick,\n onSignupClick,\n showTraditionalLinks = true,\n className,\n verifyToken,\n frontendUrl,\n}: MagicLinkFormProps) {\n const [email, setEmail] = useState('');\n const [name, setName] = useState('');\n const [lastName, setLastName] = useState('');\n const [loading, setLoading] = useState(false);\n const [verifying, setVerifying] = useState(false);\n const [error, setError] = useState('');\n const [success, setSuccess] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{ email?: boolean; name?: boolean }>({});\n const [showNameFields, setShowNameFields] = useState(false);\n\n const { sendMagicLink, verifyMagicLink } = useAuth();\n const { tenant } = useTenantInfo();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n\n // Auto-verify magic link if token is provided\n useEffect(() => {\n if (verifyToken) {\n handleVerifyMagicLink(verifyToken);\n }\n }, [verifyToken]);\n\n const handleVerifyMagicLink = async (token: string) => {\n if (!tenant || !email) {\n setError('Missing tenant or email');\n return;\n }\n\n setVerifying(true);\n setError('');\n\n try {\n const result = await verifyMagicLink({\n token,\n email,\n // tenantId inferred from context automatically\n });\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || 'Failed to verify magic link';\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setVerifying(false);\n }\n };\n\n const validateForm = () => {\n const errors: { email?: boolean; name?: boolean } = {};\n\n if (!email.trim()) errors.email = true;\n if (showNameFields && !name.trim()) errors.name = true;\n\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) return;\n if (!tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n setSuccess('');\n\n try {\n const finalFrontendUrl =\n frontendUrl || (typeof window !== 'undefined' ? window.location.origin : '');\n const result = await sendMagicLink({\n email,\n tenantId: tenant.id,\n frontendUrl: finalFrontendUrl,\n name: showNameFields ? name : undefined,\n lastName: showNameFields ? lastName : undefined,\n });\n setSuccess(mergedCopy.successMessage);\n onSuccess?.(result);\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: 'email' | 'name') => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading || verifying ? mergedStyles.buttonLoading : {}),\n ...(!email || loading || verifying ? mergedStyles.buttonDisabled : {}),\n });\n\n if (verifying) {\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.verifyingText}</h2>\n <div style={{ textAlign: 'center', padding: '2rem' }}>\n <div style={{ fontSize: '1rem', color: '#6b7280' }}>\n Please wait while we verify your magic link...\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n <p style={mergedStyles.description}>{mergedCopy.description}</p>\n\n <form onSubmit={handleSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.emailLabel}</label>\n <input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n value={email}\n onChange={e => {\n setEmail(e.target.value);\n if (fieldErrors.email) {\n setFieldErrors(prev => ({ ...prev, email: false }));\n }\n }}\n placeholder={mergedCopy.emailPlaceholder}\n style={getInputStyle('email')}\n disabled={loading || verifying}\n />\n </div>\n\n {/* Toggle to show name fields for new users */}\n {!showNameFields && (\n <div style={{ textAlign: 'center', marginTop: '0.5rem' }}>\n <button\n type=\"button\"\n onClick={() => setShowNameFields(true)}\n style={{\n background: 'none',\n border: 'none',\n color: '#3b82f6',\n fontSize: '0.875rem',\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n New user? Add your name\n </button>\n </div>\n )}\n\n {showNameFields && (\n <>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.nameLabel}</label>\n <input\n id=\"name\"\n name=\"name\"\n type=\"text\"\n value={name}\n onChange={e => {\n setName(e.target.value);\n if (fieldErrors.name) {\n setFieldErrors(prev => ({ ...prev, name: false }));\n }\n }}\n placeholder={mergedCopy.namePlaceholder}\n style={getInputStyle('name')}\n disabled={loading || verifying}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.lastNameLabel}</label>\n <input\n id=\"lastName\"\n name=\"lastName\"\n type=\"text\"\n value={lastName}\n onChange={e => setLastName(e.target.value)}\n placeholder={mergedCopy.lastNamePlaceholder}\n style={mergedStyles.input}\n disabled={loading || verifying}\n />\n </div>\n\n <div style={{ textAlign: 'center', marginTop: '0.5rem' }}>\n <button\n type=\"button\"\n onClick={() => {\n setShowNameFields(false);\n setName('');\n setLastName('');\n }}\n style={{\n background: 'none',\n border: 'none',\n color: '#6b7280',\n fontSize: '0.875rem',\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n Existing user? Hide name fields\n </button>\n </div>\n </>\n )}\n\n <button type=\"submit\" disabled={!email || loading || verifying} style={getButtonStyle()}>\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n {success && <div style={mergedStyles.successText}>{success}</div>}\n </form>\n\n {showTraditionalLinks && (\n <div style={mergedStyles.linkContainer}>\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.loginText} </span>\n <a onClick={onLoginClick} style={mergedStyles.link}>\n {mergedCopy.loginLink}\n </a>\n </div>\n\n <div style={mergedStyles.divider}>•</div>\n\n <div>\n <span style={mergedStyles.divider}>{mergedCopy.signupText} </span>\n <a onClick={onSignupClick} style={mergedStyles.link}>\n {mergedCopy.signupLink}\n </a>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\n\nexport interface MagicLinkVerifyCopy {\n title?: string;\n verifyingMessage?: string;\n successMessage?: string;\n errorMessage?: string;\n redirectingMessage?: string;\n retryButton?: string;\n backToLoginButton?: string;\n}\n\nexport interface MagicLinkVerifyStyles {\n container?: React.CSSProperties;\n card?: React.CSSProperties;\n title?: React.CSSProperties;\n message?: React.CSSProperties;\n successMessage?: React.CSSProperties;\n errorMessage?: React.CSSProperties;\n spinner?: React.CSSProperties;\n buttonContainer?: React.CSSProperties;\n retryButton?: React.CSSProperties;\n backButton?: React.CSSProperties;\n}\n\nexport interface MagicLinkVerifyIcons {\n loading?: React.ReactNode;\n success?: React.ReactNode;\n error?: React.ReactNode;\n}\n\nexport interface MagicLinkVerifyProps {\n copy?: MagicLinkVerifyCopy;\n styles?: MagicLinkVerifyStyles;\n icons?: MagicLinkVerifyIcons;\n onSuccess?: (data: any) => void;\n onError?: (error: string) => void;\n onRetry?: () => void;\n onBackToLogin?: () => void;\n className?: string;\n // Auto-extract from URL params if not provided\n token?: string;\n email?: string;\n appId?: string;\n tenantSlug?: string;\n // Auto-redirect after success (in milliseconds)\n autoRedirectDelay?: number;\n}\n\nconst defaultCopy: Required<MagicLinkVerifyCopy> = {\n title: 'Verifying Magic Link',\n verifyingMessage: 'Please wait while we verify your magic link...',\n successMessage: 'Magic link verified successfully! You are now logged in.',\n errorMessage: 'Failed to verify magic link. The link may be expired or invalid.',\n redirectingMessage: 'Redirecting you to the dashboard...',\n retryButton: 'Try Again',\n backToLoginButton: 'Back to Login',\n};\n\nconst defaultStyles: Required<MagicLinkVerifyStyles> = {\n container: {\n maxWidth: '400px',\n width: '100%',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n card: {\n // Not used in new design, keeping for compatibility\n backgroundColor: 'transparent',\n padding: '0',\n borderRadius: '0',\n boxShadow: 'none',\n maxWidth: '100%',\n width: '100%',\n textAlign: 'center',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#333333',\n },\n message: {\n fontSize: '1rem',\n color: '#6b7280',\n marginBottom: '1.5rem',\n lineHeight: '1.5',\n textAlign: 'center',\n },\n successMessage: {\n fontSize: '1rem',\n color: '#059669',\n marginBottom: '1.5rem',\n lineHeight: '1.5',\n textAlign: 'center',\n },\n errorMessage: {\n fontSize: '0.875rem',\n color: '#ef4444',\n textAlign: 'center',\n marginBottom: '1rem',\n lineHeight: '1.5',\n },\n spinner: {\n display: 'inline-block',\n width: '20px',\n height: '20px',\n border: '2px solid #e5e7eb',\n borderTop: '2px solid #3b82f6',\n borderRadius: '50%',\n animation: 'spin 1s linear infinite',\n marginRight: '0.5rem',\n },\n buttonContainer: {\n display: 'flex',\n gap: '0.75rem',\n justifyContent: 'center',\n flexWrap: 'wrap',\n marginTop: '1rem',\n },\n retryButton: {\n padding: '0.75rem 1rem',\n backgroundColor: '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n },\n backButton: {\n padding: '0.75rem 1rem',\n backgroundColor: '#f3f4f6',\n color: '#374151',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'all 0.15s ease-in-out',\n },\n};\n\n// Loading spinner icon\nconst LoadingIcon = () => <div style={defaultStyles.spinner} />;\n\n// Success icon\nconst SuccessIcon = () => (\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"#059669\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ margin: '0 auto 1rem auto', display: 'block' }}\n >\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\" />\n <polyline points=\"22,4 12,14.01 9,11.01\" />\n </svg>\n);\n\n// Error icon\nconst ErrorIcon = () => (\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"#ef4444\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{ margin: '0 auto 1rem auto', display: 'block' }}\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n);\n\nconst defaultIcons: Required<MagicLinkVerifyIcons> = {\n loading: <LoadingIcon />,\n success: <SuccessIcon />,\n error: <ErrorIcon />,\n};\n\ntype VerificationState = 'verifying' | 'success' | 'error' | 'redirecting';\n\nexport function MagicLinkVerify({\n copy = {},\n styles = {},\n icons = {},\n onSuccess,\n onError,\n onRetry,\n onBackToLogin,\n className,\n token: propToken,\n email: propEmail,\n appId: propAppId,\n tenantSlug: propTenantSlug,\n autoRedirectDelay = 3000,\n}: MagicLinkVerifyProps) {\n const [state, setState] = useState<VerificationState>('verifying');\n const [error, setError] = useState('');\n\n const { verifyMagicLink } = useAuth();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n const mergedIcons = { ...defaultIcons, ...icons };\n\n // Extract parameters from URL or use props\n const getUrlParams = () => {\n if (typeof window === 'undefined') return {};\n\n const urlParams = new URLSearchParams(window.location.search);\n return {\n token: propToken || urlParams.get('token') || '',\n email: propEmail || urlParams.get('email') || '',\n appId: propAppId || urlParams.get('appId') || '',\n tenantSlug: propTenantSlug || urlParams.get('tenantSlug') || undefined,\n };\n };\n\n const handleVerification = async () => {\n setState('verifying');\n setError('');\n\n try {\n const params = getUrlParams();\n\n if (!params.token || !params.email) {\n throw new Error('Missing required parameters: token or email');\n }\n\n const result = await verifyMagicLink({\n token: params.token,\n email: params.email,\n tenantSlug: params.tenantSlug,\n });\n\n setState('success');\n onSuccess?.(result);\n\n // Auto-redirect after success\n if (autoRedirectDelay > 0) {\n setTimeout(() => {\n setState('redirecting');\n }, autoRedirectDelay);\n }\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n setState('error');\n onError?.(errorMessage);\n }\n };\n\n const handleRetry = () => {\n onRetry?.();\n handleVerification();\n };\n\n const handleBackToLogin = () => {\n onBackToLogin?.();\n };\n\n // Auto-verify on mount\n useEffect(() => {\n handleVerification();\n }, []);\n\n const renderContent = () => {\n switch (state) {\n case 'verifying':\n return (\n <div style={mergedStyles.message}>\n {mergedIcons.loading}\n {mergedCopy.verifyingMessage}\n </div>\n );\n\n case 'success':\n return (\n <>\n {mergedIcons.success}\n <div style={mergedStyles.successMessage}>{mergedCopy.successMessage}</div>\n </>\n );\n\n case 'redirecting':\n return (\n <>\n {mergedIcons.loading}\n <div style={mergedStyles.message}>{mergedCopy.redirectingMessage}</div>\n </>\n );\n\n case 'error':\n return (\n <>\n {mergedIcons.error}\n <div style={mergedStyles.errorMessage}>{error || mergedCopy.errorMessage}</div>\n <div style={mergedStyles.buttonContainer}>\n <button\n onClick={handleRetry}\n style={mergedStyles.retryButton}\n onMouseOver={e => {\n e.currentTarget.style.backgroundColor = '#2563eb';\n }}\n onMouseOut={e => {\n e.currentTarget.style.backgroundColor = '#3b82f6';\n }}\n >\n {mergedCopy.retryButton}\n </button>\n <button\n onClick={handleBackToLogin}\n style={mergedStyles.backButton}\n onMouseOver={e => {\n e.currentTarget.style.backgroundColor = '#e5e7eb';\n }}\n onMouseOut={e => {\n e.currentTarget.style.backgroundColor = '#f3f4f6';\n }}\n >\n {mergedCopy.backToLoginButton}\n </button>\n </div>\n </>\n );\n\n default:\n return null;\n }\n };\n\n return (\n <div style={mergedStyles.container} className={className}>\n <style>\n {`\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `}\n </style>\n <h1 style={mergedStyles.title}>{mergedCopy.title}</h1>\n {renderContent()}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { useAuth } from '../providers/AuthProvider';\nimport { useTenantInfo } from '../providers/TenantProvider';\n\nexport interface PasswordRecoveryFormCopy {\n title?: string;\n subtitle?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n submitButton?: string;\n backToLoginLink?: string;\n successMessage?: string;\n errorMessage?: string;\n loadingText?: string;\n // Reset form copy\n resetTitle?: string;\n resetSubtitle?: string;\n tokenLabel?: string;\n tokenPlaceholder?: string;\n newPasswordLabel?: string;\n newPasswordPlaceholder?: string;\n confirmPasswordLabel?: string;\n confirmPasswordPlaceholder?: string;\n resetSubmitButton?: string;\n resetLoadingText?: string;\n resetSuccessMessage?: string;\n passwordMismatchError?: string;\n}\n\nexport interface PasswordRecoveryFormStyles {\n container?: React.CSSProperties;\n title?: React.CSSProperties;\n subtitle?: React.CSSProperties;\n form?: React.CSSProperties;\n fieldGroup?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n inputError?: React.CSSProperties;\n button?: React.CSSProperties;\n buttonDisabled?: React.CSSProperties;\n buttonLoading?: React.CSSProperties;\n errorText?: React.CSSProperties;\n successText?: React.CSSProperties;\n linkContainer?: React.CSSProperties;\n link?: React.CSSProperties;\n}\n\nexport interface PasswordRecoveryFormProps {\n copy?: PasswordRecoveryFormCopy;\n styles?: PasswordRecoveryFormStyles;\n mode?: 'request' | 'reset';\n token?: string;\n onSuccess?: (data?: any) => void;\n onError?: (error: string) => void;\n onBackToLogin?: () => void;\n onModeChange?: (mode: 'request' | 'reset') => void;\n className?: string;\n}\n\nconst defaultCopy: Required<PasswordRecoveryFormCopy> = {\n title: 'Reset Password',\n subtitle: \"Enter your email address and we'll send you a link to reset your password.\",\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n submitButton: 'Send Reset Link',\n backToLoginLink: 'Back to Sign In',\n successMessage: 'Password reset link sent! Check your email.',\n errorMessage: 'Failed to send reset link',\n loadingText: 'Sending...',\n resetTitle: 'Set New Password',\n resetSubtitle: 'Enter your reset token and new password.',\n tokenLabel: 'Reset Token',\n tokenPlaceholder: 'Enter reset token from email',\n newPasswordLabel: 'New Password',\n newPasswordPlaceholder: 'Enter new password',\n confirmPasswordLabel: 'Confirm Password',\n confirmPasswordPlaceholder: 'Confirm new password',\n resetSubmitButton: 'Reset Password',\n resetLoadingText: 'Resetting...',\n resetSuccessMessage: 'Password reset successfully!',\n passwordMismatchError: 'Passwords do not match',\n};\n\nconst defaultStyles: Required<PasswordRecoveryFormStyles> = {\n container: {\n maxWidth: '400px',\n margin: '0 auto',\n padding: '2rem',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',\n },\n title: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: '0.5rem',\n color: '#333333',\n },\n subtitle: {\n fontSize: '0.875rem',\n textAlign: 'center',\n marginBottom: '1.5rem',\n color: '#6b7280',\n lineHeight: '1.4',\n },\n form: {\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n },\n label: {\n fontSize: '0.875rem',\n fontWeight: '500',\n color: '#374151',\n },\n input: {\n padding: '0.75rem',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n fontSize: '1rem',\n transition: 'border-color 0.15s ease-in-out',\n outline: 'none',\n },\n inputError: {\n borderColor: '#ef4444',\n boxShadow: '0 0 0 3px rgba(239, 68, 68, 0.1)',\n },\n button: {\n padding: '0.75rem 1rem',\n backgroundColor: '#f59e0b',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '1rem',\n fontWeight: '500',\n cursor: 'pointer',\n transition: 'background-color 0.15s ease-in-out',\n marginTop: '0.5rem',\n },\n buttonDisabled: {\n backgroundColor: '#9ca3af',\n cursor: 'not-allowed',\n },\n buttonLoading: {\n backgroundColor: '#6b7280',\n },\n errorText: {\n color: '#ef4444',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n successText: {\n color: '#10b981',\n fontSize: '0.875rem',\n textAlign: 'center',\n marginTop: '0.5rem',\n },\n linkContainer: {\n textAlign: 'center',\n marginTop: '1rem',\n },\n link: {\n color: '#3b82f6',\n textDecoration: 'none',\n fontSize: '0.875rem',\n cursor: 'pointer',\n },\n};\n\nexport function PasswordRecoveryForm({\n copy = {},\n styles = {},\n mode = 'request',\n token: initialToken = '',\n onSuccess,\n onError,\n onBackToLogin,\n onModeChange,\n className,\n}: PasswordRecoveryFormProps) {\n const [email, setEmail] = useState('');\n const [token, setToken] = useState(initialToken);\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [success, setSuccess] = useState('');\n const [fieldErrors, setFieldErrors] = useState<{\n email?: boolean;\n token?: boolean;\n newPassword?: boolean;\n confirmPassword?: boolean;\n }>({});\n\n const { requestPasswordReset, confirmPasswordReset } = useAuth();\n const { tenant } = useTenantInfo();\n\n const mergedCopy = { ...defaultCopy, ...copy };\n const mergedStyles = { ...defaultStyles, ...styles };\n\n const validateRequestForm = () => {\n const errors: { email?: boolean } = {};\n if (!email.trim()) errors.email = true;\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const validateResetForm = () => {\n const errors: { token?: boolean; newPassword?: boolean; confirmPassword?: boolean } = {};\n if (!token.trim()) errors.token = true;\n if (!newPassword.trim()) errors.newPassword = true;\n if (!confirmPassword.trim()) errors.confirmPassword = true;\n setFieldErrors(errors);\n return Object.keys(errors).length === 0;\n };\n\n const handleRequestSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateRequestForm()) return;\n if (!tenant?.id) {\n setError('Tenant not found');\n return;\n }\n\n setLoading(true);\n setError('');\n setSuccess('');\n\n try {\n await requestPasswordReset({ email, tenantId: tenant.id });\n setSuccess(mergedCopy.successMessage);\n onSuccess?.();\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const handleResetSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateResetForm()) return;\n\n if (newPassword !== confirmPassword) {\n setError(mergedCopy.passwordMismatchError);\n setFieldErrors({ confirmPassword: true });\n return;\n }\n\n setLoading(true);\n setError('');\n setSuccess('');\n\n try {\n await confirmPasswordReset({ token, newPassword });\n setSuccess(mergedCopy.resetSuccessMessage);\n onSuccess?.();\n } catch (err: any) {\n const errorMessage = err.message || mergedCopy.errorMessage;\n setError(errorMessage);\n onError?.(errorMessage);\n } finally {\n setLoading(false);\n }\n };\n\n const getInputStyle = (field: keyof typeof fieldErrors) => ({\n ...mergedStyles.input,\n ...(fieldErrors[field] ? mergedStyles.inputError : {}),\n });\n\n const getButtonStyle = () => ({\n ...mergedStyles.button,\n ...(loading ? mergedStyles.buttonLoading : {}),\n });\n\n if (mode === 'reset') {\n const isFormValid = token && newPassword && confirmPassword;\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.resetTitle}</h2>\n <p style={mergedStyles.subtitle}>{mergedCopy.resetSubtitle}</p>\n\n <form onSubmit={handleResetSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.tokenLabel}</label>\n <input\n type=\"text\"\n value={token}\n onChange={e => {\n setToken(e.target.value);\n if (fieldErrors.token) {\n setFieldErrors(prev => ({ ...prev, token: false }));\n }\n }}\n placeholder={mergedCopy.tokenPlaceholder}\n style={getInputStyle('token')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.newPasswordLabel}</label>\n <input\n type=\"password\"\n value={newPassword}\n onChange={e => {\n setNewPassword(e.target.value);\n if (fieldErrors.newPassword) {\n setFieldErrors(prev => ({ ...prev, newPassword: false }));\n }\n }}\n placeholder={mergedCopy.newPasswordPlaceholder}\n style={getInputStyle('newPassword')}\n disabled={loading}\n />\n </div>\n\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.confirmPasswordLabel}</label>\n <input\n type=\"password\"\n value={confirmPassword}\n onChange={e => {\n setConfirmPassword(e.target.value);\n if (fieldErrors.confirmPassword) {\n setFieldErrors(prev => ({ ...prev, confirmPassword: false }));\n }\n if (error === mergedCopy.passwordMismatchError) {\n setError('');\n }\n }}\n placeholder={mergedCopy.confirmPasswordPlaceholder}\n style={getInputStyle('confirmPassword')}\n disabled={loading}\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={!isFormValid || loading}\n style={{\n ...getButtonStyle(),\n ...(!isFormValid || loading ? mergedStyles.buttonDisabled : {}),\n }}\n >\n {loading ? mergedCopy.resetLoadingText : mergedCopy.resetSubmitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n {success && <div style={mergedStyles.successText}>{success}</div>}\n </form>\n\n <div style={mergedStyles.linkContainer}>\n <a onClick={onBackToLogin} style={mergedStyles.link}>\n {mergedCopy.backToLoginLink}\n </a>\n {onModeChange && (\n <>\n <span style={{ margin: '0 0.5rem', color: '#6b7280' }}>•</span>\n <a onClick={() => onModeChange('request')} style={mergedStyles.link}>\n Request New Link\n </a>\n </>\n )}\n </div>\n </div>\n );\n }\n\n // Request mode\n const isFormValid = email;\n\n return (\n <div className={className} style={mergedStyles.container}>\n <h2 style={mergedStyles.title}>{mergedCopy.title}</h2>\n <p style={mergedStyles.subtitle}>{mergedCopy.subtitle}</p>\n\n <form onSubmit={handleRequestSubmit} style={mergedStyles.form}>\n <div style={mergedStyles.fieldGroup}>\n <label style={mergedStyles.label}>{mergedCopy.emailLabel}</label>\n <input\n type=\"email\"\n value={email}\n onChange={e => {\n setEmail(e.target.value);\n if (fieldErrors.email) {\n setFieldErrors(prev => ({ ...prev, email: false }));\n }\n }}\n placeholder={mergedCopy.emailPlaceholder}\n style={getInputStyle('email')}\n disabled={loading}\n />\n </div>\n\n <button\n type=\"submit\"\n disabled={!isFormValid || loading}\n style={{\n ...getButtonStyle(),\n ...(!isFormValid || loading ? mergedStyles.buttonDisabled : {}),\n }}\n >\n {loading ? mergedCopy.loadingText : mergedCopy.submitButton}\n </button>\n\n {error && <div style={mergedStyles.errorText}>{error}</div>}\n {success && <div style={mergedStyles.successText}>{success}</div>}\n </form>\n\n <div style={mergedStyles.linkContainer}>\n <a onClick={onBackToLogin} style={mergedStyles.link}>\n {mergedCopy.backToLoginLink}\n </a>\n {onModeChange && (\n <>\n <span style={{ margin: '0 0.5rem', color: '#6b7280' }}>•</span>\n <a onClick={() => onModeChange('reset')} style={mergedStyles.link}>\n I have a token\n </a>\n </>\n )}\n </div>\n </div>\n );\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n Permission,\n CreatePermissionRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class PermissionApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager?: SessionManager\n ) {}\n\n async createPermission(request: CreatePermissionRequest): Promise<Permission> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<Permission>>(\n '/permissions/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getPermissions(\n params?: PaginationParams\n ): Promise<{ permissions: Permission[]; meta: any }> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/permissions/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Permission[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n permissions: response.data,\n meta: response.meta,\n };\n }\n\n async getPermissionById(id: string): Promise<Permission> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<Permission>>(`/permissions/${id}`, {\n headers: authHeaders,\n });\n return response.data;\n }\n\n async updatePermission(\n id: string,\n request: Partial<CreatePermissionRequest>\n ): Promise<Permission> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<Permission>>(\n `/permissions/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async deletePermission(id: string): Promise<void> {\n if (!this.sessionManager) {\n throw new Error('SessionManager is required for private endpoints');\n }\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/permissions/${id}`, {\n headers: authHeaders,\n });\n }\n\n // Public endpoint - no auth required\n async getAppPermissions(\n appId: string,\n params?: PaginationParams\n ): Promise<{ permissions: Permission[]; meta: any }> {\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n\n const url = `/permissions/apps/${appId}${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<Permission[]>>(url);\n\n return {\n permissions: response.data,\n meta: response.meta,\n };\n }\n}\n","import { HttpService } from './HttpService';\nimport { SessionManager } from './SessionManager';\nimport type {\n SubscriptionPlan,\n CreateSubscriptionPlanRequest,\n ApiResponse,\n PaginationParams,\n} from '../types/api';\n\nexport class SubscriptionPlanApiService {\n constructor(\n private httpService: HttpService,\n private sessionManager: SessionManager\n ) {}\n\n async createSubscriptionPlan(request: CreateSubscriptionPlanRequest): Promise<SubscriptionPlan> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.post<ApiResponse<SubscriptionPlan>>(\n '/subscription-plans/',\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async getSubscriptionPlans(\n params?: PaginationParams & { appId?: string }\n ): Promise<{ plans: SubscriptionPlan[]; meta: any }> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const queryParams = new URLSearchParams();\n\n if (params?.page) queryParams.append('page', params.page.toString());\n if (params?.limit) queryParams.append('limit', params.limit.toString());\n if (params?.sortBy) queryParams.append('sortBy', params.sortBy);\n if (params?.sortOrder) queryParams.append('sortOrder', params.sortOrder);\n if (params?.appId) queryParams.append('appId', params.appId);\n\n const url = `/subscription-plans/${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;\n const response = await this.httpService.get<ApiResponse<SubscriptionPlan[]>>(url, {\n headers: authHeaders,\n });\n\n return {\n plans: response.data,\n meta: response.meta,\n };\n }\n\n async getSubscriptionPlanById(id: string): Promise<SubscriptionPlan> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.get<ApiResponse<SubscriptionPlan>>(\n `/subscription-plans/${id}`,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async updateSubscriptionPlan(\n id: string,\n request: Partial<CreateSubscriptionPlanRequest>\n ): Promise<SubscriptionPlan> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n const response = await this.httpService.put<ApiResponse<SubscriptionPlan>>(\n `/subscription-plans/${id}`,\n request,\n {\n headers: authHeaders,\n }\n );\n return response.data;\n }\n\n async deleteSubscriptionPlan(id: string): Promise<void> {\n const authHeaders = await this.sessionManager.getAuthHeaders();\n await this.httpService.delete<void>(`/subscription-plans/${id}`, {\n headers: authHeaders,\n });\n }\n}\n","import { HttpService } from './HttpService';\n\nexport class HealthApiService {\n constructor(private httpService: HttpService) {}\n\n // Public endpoint - no auth required\n async checkHealth(): Promise<{ status: string }> {\n return await this.httpService.get<{ status: string }>('/health');\n }\n}\n","// Data transformation utilities for API responses\n\nexport class ApiMappers {\n // Date string to Date object\n static toDate(dateString: string): Date {\n return new Date(dateString);\n }\n\n // Date object to ISO string\n static toISOString(date: Date): string {\n return date.toISOString();\n }\n\n // Transform API response pagination meta\n static transformPaginationMeta(meta: any) {\n return {\n total: meta.total || 0,\n page: meta.page || 1,\n limit: meta.limit || 100,\n totalPages: meta.totalPages || 1,\n hasNext: meta.hasNext || false,\n hasPrev: meta.hasPrev || false,\n };\n }\n\n // Transform user data for display\n static transformUser(user: any) {\n return {\n ...user,\n createdAt: this.toDate(user.createdAt),\n updatedAt: this.toDate(user.updatedAt),\n displayName: user.lastName ? `${user.name} ${user.lastName}` : user.name,\n isActiveUser: user.isActive,\n };\n }\n\n // Transform role data for display\n static transformRole(role: any) {\n return {\n ...role,\n createdAt: this.toDate(role.createdAt),\n updatedAt: this.toDate(role.updatedAt),\n permissionCount: role.permissions?.length || 0,\n };\n }\n\n // Transform tenant data for display\n static transformTenant(tenant: any) {\n return {\n ...tenant,\n createdAt: this.toDate(tenant.createdAt),\n updatedAt: this.toDate(tenant.updatedAt),\n displayName: tenant.name,\n hasCustomDomain: !!tenant.domain,\n };\n }\n\n // Transform subscription data for display\n static transformSubscription(subscription: any) {\n return {\n ...subscription,\n createdAt: this.toDate(subscription.createdAt),\n updatedAt: this.toDate(subscription.updatedAt),\n startDate: this.toDate(subscription.startDate),\n endDate: subscription.endDate ? this.toDate(subscription.endDate) : null,\n isActive: subscription.status === 'ACTIVE',\n isExpired: subscription.endDate ? new Date(subscription.endDate) < new Date() : false,\n };\n }\n\n // Transform app data for display\n static transformApp(app: any) {\n return {\n ...app,\n createdAt: this.toDate(app.createdAt),\n updatedAt: this.toDate(app.updatedAt),\n isAdminLevel: app.securityLevel === 'ADMIN',\n hasDefaultPlan: !!app.defaultSubscriptionPlanId,\n };\n }\n\n // Transform feature flag data for display\n static transformFeatureFlag(featureFlag: any) {\n return {\n ...featureFlag,\n createdAt: this.toDate(featureFlag.createdAt),\n updatedAt: this.toDate(featureFlag.updatedAt),\n isEnabled: featureFlag.isActive,\n };\n }\n\n // Transform permission data for display\n static transformPermission(permission: any) {\n return {\n ...permission,\n createdAt: this.toDate(permission.createdAt),\n updatedAt: this.toDate(permission.updatedAt),\n fullName: `${permission.resource}:${permission.action}`,\n isSystemLevel: !permission.appId,\n };\n }\n\n // Transform subscription plan data for display\n static transformSubscriptionPlan(plan: any) {\n return {\n ...plan,\n createdAt: this.toDate(plan.createdAt),\n updatedAt: this.toDate(plan.updatedAt),\n displayPrice: `${plan.currency} ${plan.price}`,\n isMonthly: plan.billingCycle === 'MONTHLY',\n featureCount: plan.features?.length || 0,\n };\n }\n\n // Transform error response\n static transformError(error: any) {\n return {\n code: error.error?.code || 'UNKNOWN_ERROR',\n message: error.message || 'An unexpected error occurred',\n type: error.type || 'SYSTEM',\n isAuthError: error.type === 'AUTH',\n isValidationError: error.type === 'VALIDATION',\n };\n }\n\n // Transform query parameters for API calls\n static transformQueryParams(params: any): URLSearchParams {\n const searchParams = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n searchParams.append(key, String(value));\n }\n });\n\n return searchParams;\n }\n}\n"],"names":["HttpService","baseUrl","timeout","sessionManager","method","endpoint","data","options","isRetry","url","requestTimeout","requestHeaders","authHeaders","error","controller","timeoutId","response","tokens","contentType","AppApiService","httpService","request","params","queryParams","id","appId","planId","schema","defaultSettings","AppContext","createContext","DefaultLoadingFallback","jsx","DefaultErrorFallback","retry","jsxs","AppProvider","config","children","cacheConfig","useMemo","_a","_b","_c","appInfo","setAppInfo","useState","cached","parsed","isAppLoading","setIsAppLoading","appError","setAppError","contextValue","retryApp","loadApp","useCallback","bypassCache","appData","cacheData","err","backgroundRefresh","useEffect","Fragment","ErrorComponent","useApp","context","useContext","useApi","SessionManager","storageKey","stored","tokenData","token","resolve","reject","newTokens","headers","refreshError","refreshToken","refreshResponse","user","currentData","parts","payload","decodedPayload","AuthApiService","RoleApiService","roleId","userId","UserApiService","TenantApiService","slug","TenantContext","TenantProvider","detectTenantSlug","tenantMode","subdomain","urlTenant","tenantSlug","setTenantSlug","tenant","setTenant","isTenantLoading","setIsTenantLoading","tenantError","setTenantError","settings","setSettings","isSettingsLoading","setIsSettingsLoading","settingsError","setSettingsError","detected","settingsSchema","loadTenant","tenantInfo","loadSettings","tenantSettings","refreshSettings","validateSettings","settingsToValidate","errors","key","fieldSchema","value","expectedType","actualType","switchTenant","targetTenantSlug","mode","currentHostname","newHostname","newUrl","urlParams","useTenant","useTenantSettings","useSettings","useTenantInfo","retryTenant","AuthContext","AuthProvider","availableRoles","setAvailableRoles","rolesLoading","setRolesLoading","currentUser","setCurrentUser","isUserLoading","setIsUserLoading","userError","setUserError","lastUserFetch","setLastUserFetch","authenticatedHttpService","service","authApiService","userApiService","roleApiService","userRole","role","userPermissions","isAuthenticated","USER_DATA_CACHE_TTL","loadUserData","forceRefresh","now","userData","refreshUser","login","username","password","targetSlug","resolvedTenantId","targetSessionManager","loginResponse","shouldSwitch","signup","email","phoneNumber","name","lastName","tenantId","signupTenantAdmin","tenantName","changePassword","currentPassword","newPassword","requestPasswordReset","confirmPasswordReset","sendMagicLink","frontendUrl","verifyMagicLink","verifyResponse","logout","setTokens","hasValidSession","clearSession","fetchRoles","roles","refreshRoles","hasPermission","permission","permissionString","permissions","internalHttpService","refreshInterval","useAuth","FeatureFlagApiService","flagKey","FeatureFlagContext","FeatureFlagProvider","featureFlags","setFeatureFlags","loading","setLoading","setError","featureFlagService","fetchFeatureFlags","errorMessage","interval","flag","f","useFeatureFlags","SubscriptionApiService","subscriptionId","paymentData","SubscriptionContext","SubscriptionProvider","subscription","setSubscription","subscriptionService","fetchSubscription","features","featureKey","feature","defaultValue","allowedPlans","useSubscription","UserType","DefaultFallback","InsufficientPermissionsFallback","userType","minUserType","missingPermissions","hasMinimumUserType","hierarchy","Protected","fallback","requiredPermissions","requireAllPermissions","hasAnyPermission","hasAllPermissions","redirectPath","ProtectedRoute","redirectTo","location","useLocation","Navigate","DefaultTenantRequiredFallback","TenantRoute","isLoading","DefaultTenantDetectedFallback","LandingRoute","SubscriptionGuard","requiredFeature","hasAllowedPlan","isFeatureEnabled","flagName","FeatureFlag","isEnabled","EyeIcon","EyeOffIcon","defaultIcons","defaultCopy","defaultStyles","LoginForm","copy","styles","icons","onSuccess","onError","onForgotPassword","onSignupClick","onMagicLinkClick","showForgotPassword","showSignupLink","showMagicLinkOption","className","setUsername","setPassword","showPassword","setShowPassword","fieldErrors","setFieldErrors","mergedCopy","mergedStyles","mergedIcons","validateForm","handleSubmit","e","result","getInputStyle","field","getButtonStyle","prev","SignupForm","signupType","onLoginClick","showLoginLink","setName","setLastName","setEmail","setPhoneNumber","confirmPassword","setConfirmPassword","setTenantName","isFormValid","MagicLinkForm","showTraditionalLinks","verifyToken","verifying","setVerifying","success","setSuccess","showNameFields","setShowNameFields","handleVerifyMagicLink","finalFrontendUrl","LoadingIcon","SuccessIcon","ErrorIcon","MagicLinkVerify","onRetry","onBackToLogin","propToken","propEmail","propAppId","propTenantSlug","autoRedirectDelay","state","setState","getUrlParams","handleVerification","handleRetry","handleBackToLogin","renderContent","PasswordRecoveryForm","initialToken","onModeChange","setToken","setNewPassword","validateRequestForm","validateResetForm","handleRequestSubmit","handleResetSubmit","PermissionApiService","SubscriptionPlanApiService","HealthApiService","ApiMappers","dateString","date","meta","app","featureFlag","plan","searchParams"],"mappings":"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"}
|